Please ensure you thoroughly test code before committing it. As a sanity test,

ensure that the target "checkstyle.checkstyle" will run! If in doubt, do not
commit, but instead said a patch to the devel mailing list for a review.

Finished the port of the ClassResolver code. Even though it compiled, it had
no chance of working due to class casting problems. They have not been
fixed. Also needed to ensure the correct class loader is being used.
This commit is contained in:
Oliver Burn 2002-11-06 03:57:58 +00:00
parent e7556f4af6
commit 5fc3ff2bfb
8 changed files with 46 additions and 166 deletions

View File

@ -17,11 +17,11 @@
<check classname="com.puppycrawl.tools.checkstyle.checks.InnerAssignmentCheck"/>
<check classname="com.puppycrawl.tools.checkstyle.checks.JavadocTypeCheck"/>
<check classname="com.puppycrawl.tools.checkstyle.checks.JavadocMethodCheck">
<set-property name="checkUnusedThrows" value="false"/>
<set-property name="checkUnusedThrows" value="true"/>
</check>
<check classname="com.puppycrawl.tools.checkstyle.checks.JavadocVariableCheck"/>
<check classname="com.puppycrawl.tools.checkstyle.checks.LineLengthCheck"/>

View File

@ -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,

View File

@ -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.
* <p>Limitations: this does not handle inner classes very well.</p>
*
* @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
* @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 <code>ClassResolver</code> 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 <code>Class</code> 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);
}
}

View File

@ -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();
}
}

View File

@ -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()
{

View File

@ -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;

View File

@ -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",

View File

@ -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(),