diff --git a/docs/checkstyle_checks.xml b/docs/checkstyle_checks.xml index 4f12c5c63..840315221 100644 --- a/docs/checkstyle_checks.xml +++ b/docs/checkstyle_checks.xml @@ -17,11 +17,11 @@ - + - + - + diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/Checker.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/Checker.java index 9cfe07a8a..3eae11b8f 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/Checker.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/Checker.java @@ -398,7 +398,7 @@ public class Checker final String[] lines = Utils.getLines(aFileName); final FileContents contents = new FileContents(aFileName, lines); final DetailAST rootAST = parse(contents); - mWalker.walk(rootAST, contents); + mWalker.walk(rootAST, contents, mConfig.getClassLoader()); } catch (FileNotFoundException fnfe) { mMessages.add(new LocalizedMessage(0, Defn.CHECKSTYLE_BUNDLE, diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/ClassResolver.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/ClassResolver.java deleted file mode 100644 index d80d8b9f0..000000000 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/ClassResolver.java +++ /dev/null @@ -1,144 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2002 Oliver Burn -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//////////////////////////////////////////////////////////////////////////////// -package com.puppycrawl.tools.checkstyle; - -import java.util.Set; -import java.util.Iterator; - -/** - * Utility class to resolve a class name to an actual class. Note that loaded - * classes are not initialized. - *

Limitations: this does not handle inner classes very well.

- * - * @author Oliver Burn - * @version 1.0 - */ -class ClassResolver -{ - /** name of the package to check if the class belongs to **/ - private final String mPkg; - /** set of imports to check against **/ - private final Set mImports; - /** use to load classes **/ - private final ClassLoader mLoader; - - /** - * Creates a new ClassResolver instance. - * - * @param aLoader the ClassLoader to load classes with. - * @param aPkg the name of the package the class may belong to - * @param aImports set of imports to check if the class belongs to - */ - ClassResolver(ClassLoader aLoader, String aPkg, Set aImports) - { - mLoader = aLoader; - mPkg = aPkg; - mImports = aImports; - } - - /** - * Attempts to resolve the Class for a specified name. The algorithm is - * to check: - * - fully qualified name - * - explicit imports - * - enclosing package - * - star imports - * @param aName name of the class to resolve - * @return the resolved class - * @throws ClassNotFoundException if unable to resolve the class - */ - Class resolve(String aName) throws ClassNotFoundException - { - // See if the class is full qualified - if (isLoadable(aName)) { - return safeLoad(aName); - } - - // try matching explicit imports - Iterator it = mImports.iterator(); - while (it.hasNext()) { - final String imp = ((LineText) it.next()).getText(); - if (imp.endsWith(aName) && isLoadable(imp)) { - return safeLoad(imp); - } - } - - // See if in the package - if (mPkg != null) { - final String fqn = mPkg + "." + aName; - if (isLoadable(fqn)) { - return safeLoad(fqn); - } - } - - // try "java.lang." - final String langClass = "java.lang." + aName; - if (isLoadable(langClass)) { - return safeLoad(langClass); - } - - // try star imports - it = mImports.iterator(); - while (it.hasNext()) { - final String imp = ((LineText) it.next()).getText(); - if (imp.endsWith(".*")) { - final String fqn = imp.substring(0, imp.lastIndexOf('.') + 1) - + aName; - if (isLoadable(fqn)) { - return safeLoad(fqn); - } - } - } - - // Giving up, the type is unknown, so load the class to generate an - // exception - return safeLoad(aName); - } - - /** - * @return whether a specified class is loadable with safeLoad(). - * @param aName name of the class to check - */ - boolean isLoadable(String aName) - { - try { - safeLoad(aName); - return true; - } - catch (ClassNotFoundException e) { - return false; - } - } - - /** - * Will load a specified class is such a way that it will NOT be - * initialised. - * @param aName name of the class to load - * @return the Class for the specified class - * @throws ClassNotFoundException if an error occurs - */ - Class safeLoad(String aName) - throws ClassNotFoundException - { - // The next line will load the class using the specified class - // loader. The magic is having the "false" parameter. This means the - // class will not be initialised. Very, very important. - return Class.forName(aName, false, mLoader); - } -} diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/TreeWalker.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/TreeWalker.java index f2b391865..5e8710f21 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/TreeWalker.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/TreeWalker.java @@ -125,11 +125,12 @@ class TreeWalker * Initiates the walk of an AST. * @param aAST the root AST * @param aContents the contents of the file the AST was generated from + * @param aLoader the class loader for resolving classes */ - void walk(DetailAST aAST, FileContents aContents) + void walk(DetailAST aAST, FileContents aContents, ClassLoader aLoader) { mMessages.reset(); - notifyBegin(aContents); + notifyBegin(aContents, aLoader); // empty files are not flagged by javac, will yield aAST == null if (aAST != null) { @@ -143,8 +144,9 @@ class TreeWalker /** * Notify interested checks that about to begin walking a tree. * @param aContents the contents of the file the AST was generated from + * @param aLoader the class loader for resolving classes */ - private void notifyBegin(FileContents aContents) + private void notifyBegin(FileContents aContents, ClassLoader aLoader) { // TODO: do not track Context properly for token final Iterator it = mAllChecks.iterator(); @@ -153,6 +155,7 @@ class TreeWalker final HashMap treeContext = new HashMap(); check.setTreeContext(treeContext); check.setFileContents(aContents); + check.setClassLoader(aLoader); check.beginTree(); } } diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/api/Check.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/api/Check.java index 1ca3e777d..ebd1e3b21 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/api/Check.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/api/Check.java @@ -33,6 +33,8 @@ public abstract class Check /** name to store file contents under */ private static final String FILE_CONTENTS_ATTRIBUTE = "fILEcONTENTS"; + /** name to store class loader under */ + private static final String CLASS_LOADER_ATTRIBUTE = "cLaSsLoAdEr"; /** the global context for the check */ private Map mGlobalContext; @@ -224,6 +226,24 @@ public abstract class Check return (FileContents) getTreeContext().get(FILE_CONTENTS_ATTRIBUTE); } + /** + * Set the class loader associated with the tree. + * @param aLoader the class loader + */ + public final void setClassLoader(ClassLoader aLoader) + { + getTreeContext().put(CLASS_LOADER_ATTRIBUTE, aLoader); + } + + /** + * Returns the class loader associated with the tree. + * @return the class loader + */ + public final ClassLoader getClassLoader() + { + return (ClassLoader) getTreeContext().get(CLASS_LOADER_ATTRIBUTE); + } + /** @return the tab width to report errors with */ protected final int getTabWidth() { diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/ClassResolver.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/ClassResolver.java index d5c7420a3..3ad213f6b 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/ClassResolver.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/ClassResolver.java @@ -21,8 +21,6 @@ package com.puppycrawl.tools.checkstyle.checks; import java.util.Set; import java.util.Iterator; -import com.puppycrawl.tools.checkstyle.api.DetailAST; - /** * Utility class to resolve a class name to an actual class. Note that loaded * classes are not initialized. @@ -75,7 +73,7 @@ class ClassResolver // try matching explicit imports Iterator it = mImports.iterator(); while (it.hasNext()) { - final String imp = ((DetailAST) it.next()).getText(); + final String imp = (String) it.next(); if (imp.endsWith(aName) && isLoadable(imp)) { return safeLoad(imp); } @@ -98,7 +96,7 @@ class ClassResolver // try star imports it = mImports.iterator(); while (it.hasNext()) { - final String imp = ((DetailAST) it.next()).getText(); + final String imp = (String) it.next(); if (imp.endsWith(".*")) { final String fqn = imp.substring(0, imp.lastIndexOf('.') + 1) + aName; diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/JavadocMethodCheck.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/JavadocMethodCheck.java index a0d0108b5..fb54c195d 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/JavadocMethodCheck.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/JavadocMethodCheck.java @@ -179,7 +179,7 @@ public class JavadocMethodCheck { final FullIdent name = getImportText(aAST); if (name != null) { - mImports.add(name); + mImports.add(name.getText()); } } @@ -473,13 +473,16 @@ public class JavadocMethodCheck if (!found) { boolean reqd = true; if (mCheckUnusedThrows) { - final ClassResolver cr = new ClassResolver( - Thread.currentThread().getContextClassLoader(), - mPackageFullIdent.getText(), mImports); + final ClassResolver cr = + new ClassResolver( + getClassLoader(), + mPackageFullIdent.getText(), + mImports); try { final Class clazz = cr.resolve(tag.getArg1()); - reqd = !RuntimeException.class.isAssignableFrom(clazz) - && !Error.class.isAssignableFrom(clazz); + reqd = + !RuntimeException.class.isAssignableFrom(clazz) + && !Error.class.isAssignableFrom(clazz); } catch (ClassNotFoundException e) { log(tag.getLineNo(), "javadoc.classInfo", diff --git a/src/tests/com/puppycrawl/tools/checkstyle/ClassResolverTest.java b/src/tests/com/puppycrawl/tools/checkstyle/checks/ClassResolverTest.java similarity index 82% rename from src/tests/com/puppycrawl/tools/checkstyle/ClassResolverTest.java rename to src/tests/com/puppycrawl/tools/checkstyle/checks/ClassResolverTest.java index be5339767..88eaaf834 100644 --- a/src/tests/com/puppycrawl/tools/checkstyle/ClassResolverTest.java +++ b/src/tests/com/puppycrawl/tools/checkstyle/checks/ClassResolverTest.java @@ -1,4 +1,4 @@ -package com.puppycrawl.tools.checkstyle; +package com.puppycrawl.tools.checkstyle.checks; import junit.framework.TestCase; @@ -16,9 +16,9 @@ public class ClassResolverTest public void testMisc() throws ClassNotFoundException { final Set imps = new HashSet(); - imps.add(new LineText(666, "java.io.File")); - imps.add(new LineText(666, "nothing.will.match.*")); - imps.add(new LineText(666, "java.applet.*")); + imps.add("java.io.File"); + imps.add("nothing.will.match.*"); + imps.add("java.applet.*"); ClassResolver cr = new ClassResolver(Thread.currentThread().getContextClassLoader(), null, imps); @@ -40,7 +40,7 @@ public class ClassResolverTest catch (ClassNotFoundException e) { } - imps.add(new LineText(324, "java.text.ChoiceFormat")); + imps.add("java.text.ChoiceFormat"); cr.resolve("ChoiceFormat"); cr = new ClassResolver(Thread.currentThread().getContextClassLoader(),