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: package com.puppycrawl.tools.checkstyle.checks.imports;
020:
021: import com.puppycrawl.tools.checkstyle.api.DetailAST;
022: import com.puppycrawl.tools.checkstyle.api.FullIdent;
023: import com.puppycrawl.tools.checkstyle.api.TokenTypes;
024: import com.puppycrawl.tools.checkstyle.api.Utils;
025: import com.puppycrawl.tools.checkstyle.checks.DeclarationCollector;
026:
027: import java.util.HashSet;
028: import java.util.Iterator;
029: import java.util.Set;
030:
031: /**
032: * <p>
033: * Checks for unused import statements.
034: * </p>
035: * <p>
036: * An example of how to configure the check is:
037: * </p>
038: * <pre>
039: * <module name="UnusedImports"/>
040: * </pre>
041: *
042: * Compatible with Java 1.5 source.
043: *
044: * @author Oliver Burn
045: * @version 1.1
046: */
047: public class UnusedImportsCheck extends DeclarationCollector {
048: /** flag to indicate when time to start collecting references */
049: private boolean mCollect;
050:
051: /** set of the imports */
052: private final Set mImports = new HashSet();
053:
054: /** set of references - possibly to imports or other things */
055: private final Set mReferenced = new HashSet();
056:
057: /** Default constructor. */
058: public UnusedImportsCheck() {
059: }
060:
061: /** {@inheritDoc} */
062: public void beginTree(DetailAST aRootAST) {
063: super .beginTree(aRootAST);
064: mCollect = false;
065: mImports.clear();
066: mReferenced.clear();
067: }
068:
069: /** {@inheritDoc} */
070: public void finishTree(DetailAST aRootAST) {
071: // loop over all the imports to see if referenced.
072: final Iterator it = mImports.iterator();
073: while (it.hasNext()) {
074: final FullIdent imp = (FullIdent) it.next();
075:
076: if (!mReferenced.contains(Utils
077: .baseClassname(imp.getText()))) {
078: log(imp.getLineNo(), imp.getColumnNo(),
079: "import.unused", imp.getText());
080: }
081: }
082: }
083:
084: /** {@inheritDoc} */
085: public int[] getDefaultTokens() {
086: return new int[] { TokenTypes.PACKAGE_DEF,
087: TokenTypes.ANNOTATION_DEF, TokenTypes.CLASS_DEF,
088: TokenTypes.CTOR_DEF, TokenTypes.ENUM_DEF,
089: TokenTypes.IDENT, TokenTypes.IMPORT,
090: TokenTypes.INTERFACE_DEF, TokenTypes.METHOD_DEF,
091: TokenTypes.PARAMETER_DEF, TokenTypes.SLIST,
092: TokenTypes.STATIC_IMPORT, TokenTypes.VARIABLE_DEF, };
093: }
094:
095: /** {@inheritDoc} */
096: public int[] getRequiredTokens() {
097: return getDefaultTokens();
098: }
099:
100: /** {@inheritDoc} */
101: public void visitToken(DetailAST aAST) {
102: super .visitToken(aAST);
103: if (aAST.getType() == TokenTypes.IDENT) {
104: if (mCollect) {
105: processIdent(aAST);
106: }
107: } else if (aAST.getType() == TokenTypes.IMPORT) {
108: processImport(aAST);
109: } else if (aAST.getType() == TokenTypes.STATIC_IMPORT) {
110: processStaticImport(aAST);
111: } else if ((aAST.getType() == TokenTypes.CLASS_DEF)
112: || (aAST.getType() == TokenTypes.INTERFACE_DEF)
113: || (aAST.getType() == TokenTypes.ENUM_DEF)
114: || (aAST.getType() == TokenTypes.ANNOTATION_DEF)
115: || (aAST.getType() == TokenTypes.PACKAGE_DEF)) {
116: mCollect = true;
117: }
118: }
119:
120: /**
121: * Collects references made by IDENT.
122: * @param aAST the IDENT node to process
123: */
124: private void processIdent(DetailAST aAST) {
125: final DetailAST parent = aAST.getParent();
126: final int parentType = parent.getType();
127: if (((parentType != TokenTypes.DOT) && (parentType != TokenTypes.METHOD_DEF))
128: || ((parentType == TokenTypes.DOT) && (aAST
129: .getNextSibling() != null))) {
130: if (!isDeclared(aAST.getText())) {
131: mReferenced.add(aAST.getText());
132: }
133: }
134: }
135:
136: /**
137: * Collects the details of imports.
138: * @param aAST node containing the import details
139: */
140: private void processImport(DetailAST aAST) {
141: final FullIdent name = FullIdent.createFullIdentBelow(aAST);
142: if ((name != null) && !name.getText().endsWith(".*")) {
143: mImports.add(name);
144: }
145: }
146:
147: /**
148: * Collects the details of static imports.
149: * @param aAST node containing the static import details
150: */
151: private void processStaticImport(DetailAST aAST) {
152: final FullIdent name = FullIdent
153: .createFullIdent((DetailAST) aAST.getFirstChild()
154: .getNextSibling());
155: if ((name != null) && !name.getText().endsWith(".*")) {
156: mImports.add(name);
157: }
158: }
159: }
|