001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2014 Oliver Burn 004// 005// This library is free software; you can redistribute it and/or 006// modify it under the terms of the GNU Lesser General Public 007// License as published by the Free Software Foundation; either 008// version 2.1 of the License, or (at your option) any later version. 009// 010// This library is distributed in the hope that it will be useful, 011// but WITHOUT ANY WARRANTY; without even the implied warranty of 012// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013// Lesser General Public License for more details. 014// 015// You should have received a copy of the GNU Lesser General Public 016// License along with this library; if not, write to the Free Software 017// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 018//////////////////////////////////////////////////////////////////////////////// 019package com.puppycrawl.tools.checkstyle.checks.imports; 020 021import com.puppycrawl.tools.checkstyle.api.Check; 022import com.puppycrawl.tools.checkstyle.api.DetailAST; 023import com.puppycrawl.tools.checkstyle.api.FullIdent; 024import com.puppycrawl.tools.checkstyle.api.TokenTypes; 025 026/** 027 * <p> 028 * Check that finds static imports. 029 * </p> 030 * <p> 031 * Rationale: Importing static members can lead to naming conflicts 032 * between class' members. It may lead to poor code readability since it 033 * may no longer be clear what class a member resides (without looking 034 * at the import statement). 035 * </p> 036 * <p> 037 * An example of how to configure the check is: 038 * </p> 039 * <pre> 040 * <module name="AvoidStaticImport"> 041 * <property name="excludes" 042 * value="java.lang.System.out,java.lang.Math.*"/> 043 * </module> 044 * </pre> 045 * 046 * The optional "excludes" property allows for certain classes via a star 047 * notation to be excluded such as java.lang.Math.* or specific 048 * static members to be excluded like java.lang.System.out for a variable 049 * or java.lang.Math.random for a method. 050 * 051 * <p> 052 * If you exclude a starred import on a class this automatically 053 * excludes each member individually. 054 * </p> 055 * 056 * <p> 057 * For example: 058 * Excluding java.lang.Math.* will allow the import of 059 * each static member in the Math class individually like 060 * java.lang.Math.PI 061 * </p> 062 * @author Travis Schneeberger 063 * @version 1.0 064 */ 065public class AvoidStaticImportCheck 066 extends Check 067{ 068 /** the classes/static members to exempt from this check. */ 069 private String[] excludes = new String[0]; 070 071 @Override 072 public int[] getDefaultTokens() 073 { 074 return new int[] {TokenTypes.STATIC_IMPORT}; 075 } 076 077 /** 078 * Sets the list of classes or static members to be exempt from the check. 079 * @param excludes a list of fully-qualified class names/specific 080 * static members where static imports are ok 081 */ 082 public void setExcludes(String[] excludes) 083 { 084 this.excludes = excludes.clone(); 085 } 086 087 @Override 088 public void visitToken(final DetailAST ast) 089 { 090 final DetailAST startingDot = 091 ast.getFirstChild().getNextSibling(); 092 final FullIdent name = FullIdent.createFullIdent(startingDot); 093 094 if ((null != name) && !isExempt(name.getText())) { 095 log(startingDot.getLineNo(), "import.avoidStatic", name.getText()); 096 } 097 } 098 099 /** 100 * Checks if a class or static member is exempt from known excludes. 101 * 102 * @param classOrStaticMember 103 * the class or static member 104 * @return true if except false if not 105 */ 106 private boolean isExempt(String classOrStaticMember) 107 { 108 for (String exclude : excludes) { 109 if (classOrStaticMember.equals(exclude)) { 110 return true; 111 } 112 else if (exclude.endsWith(".*")) { 113 //this section allows explicit imports 114 //to be exempt when configured using 115 //a starred import 116 final String excludeMinusDotStar = 117 exclude.substring(0, exclude.length() - 2); 118 if (classOrStaticMember.startsWith(excludeMinusDotStar)) { 119 final String member = 120 classOrStaticMember.substring( 121 excludeMinusDotStar.length() + 1); 122 //if it contains a dot then it is not a member but a package 123 if (member.indexOf('.') == -1) { 124 return true; 125 } 126 } 127 } 128 } 129 return false; 130 } 131}