001: ////////////////////////////////////////////////////////////////////////////////
002: // checkstyle: Checks Java source code for adherence to a set of rules.
003: // Copyright (C) 2001-2007 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: ////////////////////////////////////////////////////////////////////////////////
019:
020: package com.puppycrawl.tools.checkstyle.checks.imports;
021:
022: import com.puppycrawl.tools.checkstyle.api.Check;
023: import com.puppycrawl.tools.checkstyle.api.DetailAST;
024: import com.puppycrawl.tools.checkstyle.api.FullIdent;
025: import com.puppycrawl.tools.checkstyle.api.TokenTypes;
026:
027: import java.util.HashSet;
028: import java.util.Iterator;
029: import java.util.Set;
030:
031: /**
032: * <p>
033: * Checks for imports that are redundant. An import statement is
034: * considered redundant if:
035: * </p>
036: *<ul>
037: * <li>It is a duplicate of another import. This is, when a class is imported
038: * more than once.</li>
039: * <li>The class non-statically imported is from the <code>java.lang</code>
040: * package. For example importing <code>java.lang.String</code>.</li>
041: * <li>The class non-statically imported is from the same package as the
042: * current package.</li>
043: *</ul>
044: * <p>
045: * An example of how to configure the check is:
046: * </p>
047: * <pre>
048: * <module name="RedundantImport"/>
049: * </pre>
050: *
051: * Compatible with Java 1.5 source.
052: *
053: * @author Oliver Burn
054: * @version 1.0
055: */
056: public class RedundantImportCheck extends Check {
057: /** name of package in file */
058: private String mPkgName;
059: /** set of the imports */
060: private final Set mImports = new HashSet();
061: /** set of static imports */
062: private final Set mStaticImports = new HashSet();
063:
064: /** {@inheritDoc} */
065: public void beginTree(DetailAST aRootAST) {
066: mPkgName = null;
067: mImports.clear();
068: mStaticImports.clear();
069: }
070:
071: /** {@inheritDoc} */
072: public int[] getDefaultTokens() {
073: return new int[] { TokenTypes.IMPORT, TokenTypes.STATIC_IMPORT,
074: TokenTypes.PACKAGE_DEF, };
075: }
076:
077: /** {@inheritDoc} */
078: public void visitToken(DetailAST aAST) {
079: if (aAST.getType() == TokenTypes.PACKAGE_DEF) {
080: mPkgName = FullIdent.createFullIdent(
081: aAST.getLastChild().getPreviousSibling()).getText();
082: } else if (aAST.getType() == TokenTypes.IMPORT) {
083: final FullIdent imp = FullIdent.createFullIdentBelow(aAST);
084: if (fromPackage(imp.getText(), "java.lang")) {
085: log(aAST.getLineNo(), aAST.getColumnNo(),
086: "import.lang", imp.getText());
087: } else if (fromPackage(imp.getText(), mPkgName)) {
088: log(aAST.getLineNo(), aAST.getColumnNo(),
089: "import.same", imp.getText());
090: }
091: // Check for a duplicate import
092: final Iterator it = mImports.iterator();
093: while (it.hasNext()) {
094: final FullIdent full = (FullIdent) it.next();
095: if (imp.getText().equals(full.getText())) {
096: log(aAST.getLineNo(), aAST.getColumnNo(),
097: "import.duplicate", new Integer(full
098: .getLineNo()), imp.getText());
099: }
100: }
101:
102: mImports.add(imp);
103: } else {
104: // Check for a duplicate static import
105: final FullIdent imp = FullIdent.createFullIdent(aAST
106: .getLastChild().getPreviousSibling());
107: final Iterator it = mStaticImports.iterator();
108: while (it.hasNext()) {
109: final FullIdent full = (FullIdent) it.next();
110: if (imp.getText().equals(full.getText())) {
111: log(aAST.getLineNo(), aAST.getColumnNo(),
112: "import.duplicate", new Integer(full
113: .getLineNo()), imp.getText());
114: }
115: }
116:
117: mStaticImports.add(imp);
118: }
119: }
120:
121: /**
122: * Determines if an import statement is for types from a specified package.
123: * @param aImport the import name
124: * @param aPkg the package name
125: * @return whether from the package
126: */
127: private static boolean fromPackage(String aImport, String aPkg) {
128: boolean retVal = false;
129: if (aPkg == null) {
130: // If not package, then check for no package in the import.
131: retVal = (aImport.indexOf('.') == -1);
132: } else {
133: final int index = aImport.lastIndexOf('.');
134: if (index != -1) {
135: final String front = aImport.substring(0, index);
136: retVal = front.equals(aPkg);
137: }
138: }
139: return retVal;
140: }
141: }
|