diff --git a/contrib/bcel/docs/BCELConfig.xml b/contrib/bcel/docs/BCELConfig.xml new file mode 100644 index 000000000..14c034513 --- /dev/null +++ b/contrib/bcel/docs/BCELConfig.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + diff --git a/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/AbstractCheckVisitor.java b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/AbstractCheckVisitor.java new file mode 100644 index 000000000..368c8521f --- /dev/null +++ b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/AbstractCheckVisitor.java @@ -0,0 +1,115 @@ +//Tested with BCEL-5.1 +//http://jakarta.apache.org/builds/jakarta-bcel/release/v5.1/ + +package com.puppycrawl.tools.checkstyle.bcel; + +import java.util.Set; + +import com.puppycrawl.tools.checkstyle.api.AbstractViolationReporter; +import com.puppycrawl.tools.checkstyle.api.LocalizedMessage; +import com.puppycrawl.tools.checkstyle.api.LocalizedMessages; + +/** + * Abstract class for checks with visitors. + * @author Rick Giles + */ +//TODO: Refactor with class Check +public abstract class AbstractCheckVisitor + extends AbstractViolationReporter + implements IObjectSetVisitor +{ + /** the object for collecting messages. */ + private LocalizedMessages mMessages; + + /** @see com.puppycrawl.tools.checkstyle.bcel.IParserCheck */ + public org.apache.bcel.classfile.Visitor getClassFileVisitor() + { + return new EmptyClassFileVisitor(); + } + + /** + * @see com.puppycrawl.tools.checkstyle.bcel.IParserCheck + */ + public org.apache.bcel.generic.Visitor getGenericVisitor() + { + return new EmptyGenericVisitor(); + } + + /** + * Initialse the check. This is the time to verify that the check has + * everything required to perform it job. + */ + public void init() + { + } + + /** + * Destroy the check. It is being retired from service. + */ + public void destroy() + { + } + + /** + * Set the global object used to collect messages. + * @param aMessages the messages to log with + */ + public final void setMessages(LocalizedMessages aMessages) + { + mMessages = aMessages; + } + + /** + * Log an error message. + * + * @param aLine the line number where the error was found + * @param aKey the message that describes the error + * @param aArgs the details of the message + * + * @see java.text.MessageFormat + */ + protected final void log(int aLine, String aKey, Object aArgs[]) + { + mMessages.add( + new LocalizedMessage( + aLine, + getMessageBundle(), + aKey, + aArgs, + getSeverityLevel(), + this.getClass().getName())); + } + + /** + * @see com.puppycrawl.tools.checkstyle.api.AbstractViolationReporter + */ + protected void log(int aLine, int aCol, String aKey, Object[] aArgs) + { + } + + /** @see com.puppycrawl.tools.checkstyle.bcel.IObjectSetVisitor */ + public void visitObject(Object aObject) + { + } + + /** @see com.puppycrawl.tools.checkstyle.bcel.IObjectSetVisitor */ + public void leaveObject(Object aObject) + { + } + + /** @see com.puppycrawl.tools.checkstyle.bcel.IObjectSetVisitor */ + public void visitSet(Set aJavaClassDefs) + { + } + + /** @see com.puppycrawl.tools.checkstyle.bcel.IObjectSetVisitor */ + public void leaveSet(Set aJavaClassDefs) + { + } + + /** + * Gets the deep BCEL visitor. + * @return the deep BCEL visitor for this check. + */ + public abstract IDeepVisitor getVisitor(); +} diff --git a/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/ClassFileSetCheck.java b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/ClassFileSetCheck.java new file mode 100644 index 000000000..3c6c95f6c --- /dev/null +++ b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/ClassFileSetCheck.java @@ -0,0 +1,304 @@ +//Tested with BCEL-5.1 +//http://jakarta.apache.org/builds/jakarta-bcel/release/v5.1/ + +package com.puppycrawl.tools.checkstyle.bcel; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import org.apache.bcel.Repository; +import org.apache.bcel.classfile.ClassParser; +import org.apache.bcel.classfile.JavaClass; +import org.apache.bcel.classfile.Visitor; +import org.apache.bcel.util.ClassLoaderRepository; + +import com.puppycrawl.tools.checkstyle.DefaultContext; +import com.puppycrawl.tools.checkstyle.ModuleFactory; +import com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck; +import com.puppycrawl.tools.checkstyle.api.CheckstyleException; +import com.puppycrawl.tools.checkstyle.api.Configuration; +import com.puppycrawl.tools.checkstyle.api.Context; +import com.puppycrawl.tools.checkstyle.api.LocalizedMessage; + +/** + * Checks a set of class files using BCEL + * @author Rick Giles + */ +//TODO: Refactor with AbstractFileSetCheck and TreeWalker +public class ClassFileSetCheck + extends AbstractFileSetCheck + implements IObjectSetVisitor +{ + /** visitors for BCEL parse tree walk */ + private final Set mTreeVisitors = new HashSet(); + + /** all the registered checks */ + private final Set mAllChecks = new HashSet(); + + /** all visitors for IObjectSetVisitor visits */ + private final Set mObjectSetVisitors = new HashSet(); + + /** class loader to resolve classes with. **/ + private ClassLoader mClassLoader; + + /** context of child components */ + private Context mChildContext; + + /** a factory for creating submodules (i.e. the Checks) */ + private ModuleFactory mModuleFactory; + + /** + * Creates a new ClassFileSetCheck instance. + * Initializes the acceptable file extensions. + */ + public ClassFileSetCheck() + { + setFileExtensions(new String[]{"class", "jar", "zip"}); + } + + /** + * Stores the class loader and makes it the Repository's class loader. + * @param aClassLoader class loader to resolve classes with. + */ + public void setClassLoader(ClassLoader aClassLoader) + { + Repository.setRepository(new ClassLoaderRepository(aClassLoader)); + mClassLoader = aClassLoader; + } + + /** + * Sets the module factory for creating child modules (Checks). + * @param aModuleFactory the factory + */ + public void setModuleFactory(ModuleFactory aModuleFactory) + { + mModuleFactory = aModuleFactory; + } + + /** + * Instantiates, configures and registers a Check that is specified + * in the provided configuration. + * @see com.puppycrawl.tools.checkstyle.api.AutomaticBean + */ + public void setupChild(Configuration aChildConf) + throws CheckstyleException + { + // TODO: improve the error handing + final String name = aChildConf.getName(); + final Object module = mModuleFactory.createModule(name); + if (!(module instanceof AbstractCheckVisitor)) { + throw new CheckstyleException( + "ClassFileSet is not allowed as a parent of " + name); + } + final AbstractCheckVisitor c = (AbstractCheckVisitor) module; + c.contextualize(mChildContext); + c.configure(aChildConf); + c.init(); + + registerCheck(c); + } + + /** @see com.puppycrawl.tools.checkstyle.api.Configurable */ + public void finishLocalSetup() + { + DefaultContext checkContext = new DefaultContext(); + checkContext.add("classLoader", mClassLoader); + checkContext.add("messages", getMessageCollector()); + checkContext.add("severity", getSeverity()); + + mChildContext = checkContext; + } + + /** + * Register a check. + * @param aCheck the check to register + */ + private void registerCheck(AbstractCheckVisitor aCheck) + { + mAllChecks.add(aCheck); + } + + /** + * @see com.puppycrawl.tools.checkstyle.api.FileSetCheck + */ + public void process(File[] aFiles) + { + registerVisitors(); + + // get all the JavaClasses in the files + final Set javaClasses = extractJavaClasses(aFiles); + + visitSet(javaClasses); + + // walk each Java class parse tree + final JavaClassWalker walker = JavaClassWalker.getInstance(); + walker.setVisitor(getTreeVisitor()); + final Iterator it = javaClasses.iterator(); + while (it.hasNext()) { + final JavaClass clazz = (JavaClass) it.next(); + visitObject(clazz); + walker.walk(clazz); + leaveObject(clazz); + } + + leaveSet(javaClasses); + fireErrors(); + } + + /** + * Gets the visitor for a parse tree walk. + * @return the visitor for a parse tree walk. + */ + private Visitor getTreeVisitor() + { + return new VisitorSet(mTreeVisitors); + } + + /** + * Registers all the visitors for IObjectSetVisitor visits, and for + * tree walk visits. + */ + private void registerVisitors() + { + mObjectSetVisitors.addAll(mAllChecks); + final Iterator it = mAllChecks.iterator(); + while (it.hasNext()) { + final AbstractCheckVisitor check = (AbstractCheckVisitor) it.next(); + final IDeepVisitor visitor = check.getVisitor(); + mObjectSetVisitors.add(visitor); + mTreeVisitors.add(visitor); + } + } + + /** + * Gets the set of all visitors for all the checks. + * @return the set of all visitors for all the checks. + */ + private Set getObjectSetVisitors() + { + return mObjectSetVisitors; + } + + /** + * Gets the set of all JavaClasses within a set of Files. + * @param aFiles the set of files to extract from. + * @return the set of all JavaClasses within aFiles. + */ + private Set extractJavaClasses(File[] aFiles) + { + final Set result = new HashSet(); + final File[] classFiles = filter(aFiles); + // get Java classes from each filtered file + for (int i = 0; i < classFiles.length; i++) { + try { + final Set extracted = extractJavaClasses(classFiles[i]); + result.addAll(extracted); + } + catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + return result; + } + + /** @see com.puppycrawl.tools.checkstyle.bcel.IObjectSetVisitor */ + public void visitSet(Set aSet) + { + // register the JavaClasses in the Repository + Repository.clearCache(); + Iterator it = aSet.iterator(); + while (it.hasNext()) { + final JavaClass javaClass = (JavaClass) it.next(); + Repository.addClass(javaClass); + } + + // visit the visitors + it = getObjectSetVisitors().iterator(); + while (it.hasNext()) { + final IObjectSetVisitor visitor = (IObjectSetVisitor) it.next(); + visitor.visitSet(aSet); + } + } + + /** @see com.puppycrawl.tools.checkstyle.bcel.IObjectSetVisitor */ + public void visitObject(Object aObject) + { + final Iterator it = getObjectSetVisitors().iterator(); + while (it.hasNext()) { + final IObjectSetVisitor visitor = (IObjectSetVisitor) it.next(); + visitor.visitObject(aObject); + } + } + + /** @see com.puppycrawl.tools.checkstyle.bcel.IObjectSetVisitor */ + public void leaveObject(Object aObject) + { + final Iterator it = getObjectSetVisitors().iterator(); + while (it.hasNext()) { + final IObjectSetVisitor visitor = (IObjectSetVisitor) it.next(); + visitor.leaveObject(aObject); + } + } + + /** @see com.puppycrawl.tools.checkstyle.bcel.IObjectSetVisitor */ + public void leaveSet(Set aSet) + { + final Iterator it = getObjectSetVisitors().iterator(); + while (it.hasNext()) { + final IObjectSetVisitor visitor = (IObjectSetVisitor) it.next(); + visitor.leaveSet(aSet); + } + } + + /** + * Extracts the JavaClasses from .class, .zip, and .jar files. + * @param aFile the file to extract from. + * @return the set of JavaClasses from aFile. + * @throws IOException if there is an error. + */ + private Set extractJavaClasses(File aFile) + throws IOException + { + final Set result = new HashSet(); + final String fileName = aFile.getPath(); + if (fileName.endsWith(".jar") || fileName.endsWith(".zip")) { + final ZipFile zipFile = new ZipFile(fileName); + final Enumeration entries = zipFile.entries(); + while (entries.hasMoreElements()) { + final ZipEntry entry = (ZipEntry) entries.nextElement(); + final String entryName = entry.getName(); + if (entryName.endsWith(".class")) { + final InputStream in = zipFile.getInputStream(entry); + final JavaClass javaClass = + new ClassParser(in, entryName).parse(); + result.add(javaClass); + } + } + } + else { + final JavaClass javaClass = new ClassParser(fileName).parse(); + result.add(javaClass); + } + return result; + } + + /** + * Notify all listeners about the errors in a file. + * Calls MessageDispatcher.fireErrors() with + * all logged errors and than clears errors' list. + */ + private void fireErrors() + { + final LocalizedMessage[] errors = getMessageCollector().getMessages(); + getMessageCollector().reset(); + getMessageDispatcher().fireErrors("", errors); + } +} diff --git a/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/EmptyClassFileVisitor.java b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/EmptyClassFileVisitor.java new file mode 100644 index 000000000..8a89c5df7 --- /dev/null +++ b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/EmptyClassFileVisitor.java @@ -0,0 +1,17 @@ +//Tested with BCEL-5.1 +//http://jakarta.apache.org/builds/jakarta-bcel/release/v5.1/ + +package com.puppycrawl.tools.checkstyle.bcel; + +/** + * Default classfile visitor. + * @author Rick Giles + */ +public class EmptyClassFileVisitor + extends org.apache.bcel.classfile.EmptyVisitor +{ + /** restrict client creation */ + protected EmptyClassFileVisitor() + { + } +} \ No newline at end of file diff --git a/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/EmptyDeepVisitor.java b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/EmptyDeepVisitor.java new file mode 100644 index 000000000..cbb7121d5 --- /dev/null +++ b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/EmptyDeepVisitor.java @@ -0,0 +1,86 @@ +//Tested with BCEL-5.1 +//http://jakarta.apache.org/builds/jakarta-bcel/release/v5.1/ + +package com.puppycrawl.tools.checkstyle.bcel; + +import java.util.Set; + + +/** + * Default deep visitor + * @author Rick Giles + * @version 17-Jun-2003 + */ +public class EmptyDeepVisitor + implements IDeepVisitor +{ + /** the classfile visitor */ + private org.apache.bcel.classfile.Visitor mClassFileVisitor = + new EmptyClassFileVisitor(); + + /** the generic visitor */ + private org.apache.bcel.generic.Visitor mGenericVisitor = + new EmptyGenericVisitor(); + + /** + * @see com.puppycrawl.tools.checkstyle.bcel.IDeepVisitor + */ + public org.apache.bcel.classfile.Visitor getClassFileVisitor() + { + return mClassFileVisitor; + } + + /** + * @see com.puppycrawl.tools.checkstyle.bcel.IDeepVisitor + */ + public org.apache.bcel.generic.Visitor getGenericVisitor() + { + return mGenericVisitor; + } + + /** + * Sets the classfile visitor. + * @param aVisitor the classfile visitor. + */ + public void setClassFileVisitor(org.apache.bcel.classfile.Visitor aVisitor) + { + mClassFileVisitor = aVisitor; + } + + /** + * Sets the generic visitor. + * @param aVisitor the generic visitor. + */ + public void setGenericVisitor(org.apache.bcel.generic.Visitor aVisitor) + { + mGenericVisitor = aVisitor; + } + + /** + * @see com.puppycrawl.tools.checkstyle.bcel.IObjectSetVisitor + */ + public void visitObject(Object aObject) + { + } + + /** + * @see com.puppycrawl.tools.checkstyle.bcel.IObjectSetVisitor + */ + public void leaveObject(Object aObject) + { + } + + /** + * @see com.puppycrawl.tools.checkstyle.bcel.IObjectSetVisitor + */ + public void visitSet(Set aSet) + { + } + + /** + * @see com.puppycrawl.tools.checkstyle.bcel.IObjectSetVisitor + */ + public void leaveSet(Set aSet) + { + } +} diff --git a/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/EmptyGenericVisitor.java b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/EmptyGenericVisitor.java new file mode 100644 index 000000000..71be8c6af --- /dev/null +++ b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/EmptyGenericVisitor.java @@ -0,0 +1,18 @@ +//Tested with BCEL-5.1 +//http://jakarta.apache.org/builds/jakarta-bcel/release/v5.1/ + +package com.puppycrawl.tools.checkstyle.bcel; + +/** + * Default generic visitor + * @author Rick Giles + */ +public class EmptyGenericVisitor + extends org.apache.bcel.generic.EmptyVisitor +{ + /** Restrict client creation */ + protected EmptyGenericVisitor() + { + } +} + diff --git a/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/IDeepVisitor.java b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/IDeepVisitor.java new file mode 100644 index 000000000..71c725190 --- /dev/null +++ b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/IDeepVisitor.java @@ -0,0 +1,25 @@ +//Tested with BCEL-5.1 +//http://jakarta.apache.org/builds/jakarta-bcel/release/v5.1/ + +package com.puppycrawl.tools.checkstyle.bcel; + +/** + * Deep visitor for classfile and generic traversals. A ClassFile traversal + * visits all classfile and all generic nodes. + * @author Rick Giles + */ +public interface IDeepVisitor + extends IObjectSetVisitor +{ + /** + * Returns the classfile visitor. + * @return the classfile visitor. + */ + org.apache.bcel.classfile.Visitor getClassFileVisitor(); + + /** + * Returns the generic visitor. + * @return the generic visitor. + */ + org.apache.bcel.generic.Visitor getGenericVisitor(); +} diff --git a/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/IObjectSetVisitor.java b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/IObjectSetVisitor.java new file mode 100644 index 000000000..1e492ef11 --- /dev/null +++ b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/IObjectSetVisitor.java @@ -0,0 +1,37 @@ +//Tested with BCEL-5.1 +//http://jakarta.apache.org/builds/jakarta-bcel/release/v5.1/ + +package com.puppycrawl.tools.checkstyle.bcel; + +import java.util.Set; + +/** + * Object set visitor for a general set. + * @author Rick Giles + */ +public interface IObjectSetVisitor +{ + /** + * Visit a set itself. + * @param aSet the set. + */ + void visitSet(Set aSet); + + /** + * Finish the visit of a set. + * @param aSet the set. + */ + void leaveSet(Set aSet); + + /** + * Visit an object. Normally this is an object of the set. + * @param aObject the object. + */ + void visitObject(Object aObject); + + /** + * Finish the visit an object. Normally this is an object of the set. + * @param aObject the object. + */ + void leaveObject(Object aObject); +} diff --git a/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/JavaClassWalker.java b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/JavaClassWalker.java new file mode 100644 index 000000000..3c28cb7d9 --- /dev/null +++ b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/JavaClassWalker.java @@ -0,0 +1,57 @@ +//Tested with BCEL-5.1 +//http://jakarta.apache.org/builds/jakarta-bcel/release/v5.1/ + +package com.puppycrawl.tools.checkstyle.bcel; + +import org.apache.bcel.classfile.DescendingVisitor; +import org.apache.bcel.classfile.JavaClass; +import org.apache.bcel.classfile.Visitor; + +/** + * Walks a JavaClass parse tree. + * @author Rick Giles + * @version 15-Jun-2003 + */ +public final class JavaClassWalker +{ + /** singleton */ + private static JavaClassWalker sInstance = new JavaClassWalker(); + + /** visitor to be accepted during a traversal */ + private Visitor mVisitor = new EmptyClassFileVisitor(); + + /** prevent client creation */ + private JavaClassWalker() + { + } + + /** + * Accesses the singleton JavaClassWalker. + * @return the singleton JavaClassWalker. + */ + public static JavaClassWalker getInstance() + { + return sInstance; + } + + /** + * Sets a visitor to be accepted during a traversal. + * @param aVisitor the visitor to be accepted during a traversal. + */ + public void setVisitor(Visitor aVisitor) + { + mVisitor = aVisitor; + } + + /** + * Traverses a JavaClass parse tree and accepts all registered + * visitors. + * @param aJavaClass the root of the tree. + */ + public void walk(JavaClass aJavaClass) + { + DescendingVisitor visitor = + new DescendingVisitor(aJavaClass, mVisitor); + aJavaClass.accept(visitor); + } +} diff --git a/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/ReferenceVisitor.java b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/ReferenceVisitor.java new file mode 100644 index 000000000..ab6f11401 --- /dev/null +++ b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/ReferenceVisitor.java @@ -0,0 +1,149 @@ +//Tested with BCEL-5.1 +//http://jakarta.apache.org/builds/jakarta-bcel/release/v5.1/ + +package com.puppycrawl.tools.checkstyle.bcel; + +import java.util.Set; + +import org.apache.bcel.classfile.ConstantPool; +import org.apache.bcel.classfile.JavaClass; +import org.apache.bcel.generic.ConstantPoolGen; +import org.apache.bcel.generic.GETFIELD; +import org.apache.bcel.generic.GETSTATIC; +import org.apache.bcel.generic.INVOKESPECIAL; +import org.apache.bcel.generic.INVOKESTATIC; +import org.apache.bcel.generic.INVOKEVIRTUAL; +import org.apache.bcel.generic.PUTFIELD; +import org.apache.bcel.generic.PUTSTATIC; + +import com.puppycrawl.tools.checkstyle.bcel.classfile.JavaClassDefinition; +import com.puppycrawl.tools.checkstyle.bcel.classfile.ReferenceDAO; +import com.puppycrawl.tools.checkstyle.bcel.generic.FieldReference; +import com.puppycrawl.tools.checkstyle.bcel.generic.GETFIELDReference; +import com.puppycrawl.tools.checkstyle.bcel.generic.GETSTATICReference; +import com.puppycrawl.tools.checkstyle.bcel.generic.InvokeReference; +import com.puppycrawl.tools.checkstyle.bcel.generic.PUTFIELDReference; +import com.puppycrawl.tools.checkstyle.bcel.generic.PUTSTATICReference; + +/** + * Records references during a deep parse tree traversal. + * @author Rick Giles + */ +public final class ReferenceVisitor extends EmptyDeepVisitor { + /** singleton */ + private static ReferenceVisitor sInstance = new ReferenceVisitor(); + + /** maps a JavaClass to a JavaClassDefinition */ + private ReferenceDAO mReferenceDAO; + + /** access to current constant pool */ + private ConstantPoolGen mCurrentPoolGen; + + /** + * Adds a reference when it visits an instruction that invokes + * a method or references a field. + * @author Rick Giles + * @version 18-Jun-2003 + */ + private class GenericVisitor extends org.apache.bcel.generic.EmptyVisitor { + /** @see org.apache.bcel.generic.Visitor */ + public void visitINVOKESPECIAL(INVOKESPECIAL aINVOKESPECIAL) { + addInvokeReference( + new InvokeReference(aINVOKESPECIAL, mCurrentPoolGen)); + } + + /** @see org.apache.bcel.generic.Visitor */ + public void visitINVOKESTATIC(INVOKESTATIC aINVOKESTATIC) { + addInvokeReference( + new InvokeReference(aINVOKESTATIC, mCurrentPoolGen)); + } + + /** @see org.apache.bcel.generic.Visitor */ + public void visitINVOKEVIRTUAL(INVOKEVIRTUAL aINVOKEVIRTUAL) { + addInvokeReference( + new InvokeReference(aINVOKEVIRTUAL, mCurrentPoolGen)); + } + + /** @see org.apache.bcel.generic.Visitor */ + public void visitGETSTATIC(GETSTATIC aGETSTATIC) { + addFieldReference( + new GETSTATICReference(aGETSTATIC, mCurrentPoolGen)); + } + + /** @see org.apache.bcel.generic.Visitor */ + public void visitGETFIELD(GETFIELD aGETFIELD) { + addFieldReference( + new GETFIELDReference(aGETFIELD, mCurrentPoolGen)); + } + + /** @see org.apache.bcel.generic.Visitor */ + public void visitPUTSTATIC(PUTSTATIC aPUTSTATIC) { + addFieldReference( + new PUTSTATICReference(aPUTSTATIC, mCurrentPoolGen)); + } + + /** @see org.apache.bcel.generic.Visitor */ + public void visitPUTFIELD(PUTFIELD aPUTFIELD) { + addFieldReference( + new PUTFIELDReference(aPUTFIELD, mCurrentPoolGen)); + } + } + + /** prevent client construction */ + private ReferenceVisitor() { + setGenericVisitor(new GenericVisitor()); + } + + /** + * Returns the singleton ReferencesVisitor + * @return the singleton + */ + public static ReferenceVisitor getInstance() { + return sInstance; + } + + /** + * Adds an invoke reference to the reference DAO. + * @param aReference the reference. + */ + private void addInvokeReference(InvokeReference aReference) { + getReferenceDAO().addInvokeReference(aReference); + } + + /** + * Adds an field reference to the reference DAO. + * @param aReference the reference. + */ + private void addFieldReference(FieldReference aReference) { + getReferenceDAO().addFieldReference(aReference); + } + + /** @see com.puppycrawl.tools.checkstyle.bcel.IDeepVisitor */ + public void visitSet(Set aJavaClasses) { + mReferenceDAO = new ReferenceDAO(aJavaClasses); + } + + /** + * Gets the reference DAO. + * @return the reference DAO. + */ + public ReferenceDAO getReferenceDAO() { + return mReferenceDAO; + } + + /** @see com.puppycrawl.tools.checkstyle.bcel.IDeepVisitor */ + public void visitObject(Object aObject) { + final JavaClass javaClass = (JavaClass) aObject; + final ConstantPool pool = javaClass.getConstantPool(); + mCurrentPoolGen = new ConstantPoolGen(pool); + } + + /** + * Finds the JavaClassDefinition for a given JavaClass. + * @param aJavaClass the JavaClass. + * @return the JavaClassDefinition for aJavaClass. + */ + public JavaClassDefinition findJavaClassDef(JavaClass aJavaClass) { + return getReferenceDAO().findJavaClassDef(aJavaClass); + } +} diff --git a/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/VisitorSet.java b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/VisitorSet.java new file mode 100644 index 000000000..81227a2fd --- /dev/null +++ b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/VisitorSet.java @@ -0,0 +1,130 @@ +//Tested with BCEL-5.1 +//http://jakarta.apache.org/builds/jakarta-bcel/release/v5.1/ + +package com.puppycrawl.tools.checkstyle.bcel; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.apache.bcel.classfile.Code; +import org.apache.bcel.classfile.ConstantPool; +import org.apache.bcel.classfile.EmptyVisitor; +import org.apache.bcel.classfile.Field; +import org.apache.bcel.classfile.JavaClass; +import org.apache.bcel.classfile.LocalVariable; +import org.apache.bcel.classfile.Method; +import org.apache.bcel.classfile.Visitor; +import org.apache.bcel.generic.InstructionHandle; +import org.apache.bcel.generic.InstructionList; + +/** + * Manages a set of visitors that are accepted by nodes visited by + * a VisitorSet. Any visit to this object is passed on to its managed + * visitors. + * @author Rick Giles + */ +// TODO: review visitXXX +public class VisitorSet + extends EmptyVisitor +{ + /** the managed visitors */ + private Set mVisitors = new HashSet(); + + /** Creates a VisitorSet for a set of visitors. + * @param aVisitors the set of managed visitors. + */ + public VisitorSet(Set aVisitors) + { + mVisitors = aVisitors; + } + + /** + * @see org.apache.bcel.classfile.Visitor#visitCode + */ + public void visitCode(Code aCode) + { + // perform a deep visit + final byte[] code = aCode.getCode(); + final InstructionList list = new InstructionList(code); + final Iterator it = list.iterator(); + for (Iterator iter = list.iterator(); iter.hasNext();) { + InstructionHandle instruction = (InstructionHandle) iter.next(); + visitInstructionHandle(instruction); + } + } + + /** + * Deep visit of an InstructionHandle + * @param aInstruction the InstructionHandle + */ + private void visitInstructionHandle(InstructionHandle aInstruction) + { + for (Iterator iter = mVisitors.iterator(); iter.hasNext();) { + final IDeepVisitor visitor = (IDeepVisitor) iter.next(); + org.apache.bcel.generic.Visitor v = + visitor.getGenericVisitor(); + aInstruction.accept(v); + } + } + + /** + * @see org.apache.bcel.classfile.Visitor + */ + public void visitConstantPool(ConstantPool aConstantPool) + { + for (Iterator iter = mVisitors.iterator(); iter.hasNext();) { + IDeepVisitor visitor = (IDeepVisitor) iter.next(); + Visitor v = visitor.getClassFileVisitor(); + aConstantPool.accept(v); + } + } + + /** + * @see org.apache.bcel.classfile.Visitor + */ + public void visitField(Field aField) + { + for (Iterator iter = mVisitors.iterator(); iter.hasNext();) { + IDeepVisitor visitor = (IDeepVisitor) iter.next(); + Visitor v = visitor.getClassFileVisitor(); + aField.accept(v); + } + } + + /** + * @see org.apache.bcel.classfile.Visitor + */ + public void visitJavaClass(JavaClass aJavaClass) + { + for (Iterator iter = mVisitors.iterator(); iter.hasNext();) { + IDeepVisitor visitor = (IDeepVisitor) iter.next(); + Visitor v = visitor.getClassFileVisitor(); + aJavaClass.accept(v); + } + } + + /** + * @see org.apache.bcel.classfile.Visitor + */ + public void visitLocalVariable(LocalVariable aLocalVariable) + { + for (Iterator iter = mVisitors.iterator(); iter.hasNext();) { + IDeepVisitor visitor = (IDeepVisitor) iter.next(); + Visitor v = visitor.getClassFileVisitor(); + aLocalVariable.accept(v); + } + } + + /** + * @see org.apache.bcel.classfile.Visitor + */ + public void visitMethod(Method aMethod) + { + for (Iterator iter = mVisitors.iterator(); iter.hasNext();) { + IDeepVisitor visitor = (IDeepVisitor) iter.next(); + Visitor v = visitor.getClassFileVisitor(); + aMethod.accept(v); + } + } +} diff --git a/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/checks/AbstractReferenceCheck.java b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/checks/AbstractReferenceCheck.java new file mode 100644 index 000000000..a8566c922 --- /dev/null +++ b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/checks/AbstractReferenceCheck.java @@ -0,0 +1,109 @@ +//Tested with BCEL-5.1 +//http://jakarta.apache.org/builds/jakarta-bcel/release/v5.1/ + +package com.puppycrawl.tools.checkstyle.bcel.checks; + +import org.apache.bcel.classfile.JavaClass; +import org.apache.commons.beanutils.ConversionException; +import org.apache.regexp.RE; +import org.apache.regexp.RESyntaxException; + +import com.puppycrawl.tools.checkstyle.api.Utils; +import com.puppycrawl.tools.checkstyle.bcel.AbstractCheckVisitor; +import com.puppycrawl.tools.checkstyle.bcel.IDeepVisitor; +import com.puppycrawl.tools.checkstyle.bcel.ReferenceVisitor; +import com.puppycrawl.tools.checkstyle.bcel.classfile.JavaClassDefinition; +import com.puppycrawl.tools.checkstyle.bcel.classfile.ReferenceDAO; + +/** + * Abstract class for checks that require reference information. + * @author Rick Giles + */ +public abstract class AbstractReferenceCheck + extends AbstractCheckVisitor +{ + /** the regexp to match class names against */ + private RE mIgnoreClassNameRegexp; + + /** the regexp to match names against */ + private RE mIgnoreNameRegexp; + + /** + * Creates a AbstractReferenceCheck. + * + */ + public AbstractReferenceCheck() + { + setIgnoreClassName("^$"); + setIgnoreName("^$"); + } + + /** + * Determines whether a class name and name should be ignored. + * @param aClassName the class name. + * @param aName the name. + * @return true if aClassName and aName should be ignored. + */ + protected boolean ignore(String aClassName, String aName) + { + return (mIgnoreClassNameRegexp.match(aClassName) + || mIgnoreNameRegexp.match(aName)); + } + + /** + * Set the ignore class name to the specified regular expression. + * @param aFormat a String value + * @throws ConversionException unable to parse aFormat + */ + public void setIgnoreClassName(String aFormat) + throws ConversionException + { + try { + mIgnoreClassNameRegexp = Utils.getRE(aFormat); + } + catch (RESyntaxException e) { + throw new ConversionException("unable to parse " + aFormat, e); + } + } + + /** + * Set the ignore name format to the specified regular expression. + * @param aFormat a String value + * @throws ConversionException unable to parse aFormat + */ + public void setIgnoreName(String aFormat) + throws ConversionException + { + try { + mIgnoreNameRegexp = Utils.getRE(aFormat); + } + catch (RESyntaxException e) { + throw new ConversionException("unable to parse " + aFormat, e); + } + } + + /** @see com.puppycrawl.tools.checkstyle.bcel.AbstractCheckVisitor */ + public IDeepVisitor getVisitor() + { + return ReferenceVisitor.getInstance(); + } + + /** + * Gets the DAO that manages references for this check. + * @return the the DAO that manages references for this check. + */ + public ReferenceDAO getReferenceDAO() + { + return ((ReferenceVisitor) getVisitor()).getReferenceDAO(); + } + + /** + * Finds a JavaClassDefinition for a JavaClass. + * @param aJavaClass the JavaClass. + * @return the JavaClassDefinition for aJavaClass. + */ + protected JavaClassDefinition findJavaClassDef(JavaClass aJavaClass) + { + return getReferenceDAO().findJavaClassDef(aJavaClass); + } +} diff --git a/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/checks/UnreadFieldCheck.java b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/checks/UnreadFieldCheck.java new file mode 100644 index 000000000..f589749c6 --- /dev/null +++ b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/checks/UnreadFieldCheck.java @@ -0,0 +1,58 @@ +//Tested with BCEL-5.1 +//http://jakarta.apache.org/builds/jakarta-bcel/release/v5.1/ + +package com.puppycrawl.tools.checkstyle.bcel.checks; + +import java.util.Iterator; +import java.util.Set; + +import org.apache.bcel.classfile.Field; +import org.apache.bcel.classfile.JavaClass; + +import com.puppycrawl.tools.checkstyle.bcel.classfile.FieldDefinition; +import com.puppycrawl.tools.checkstyle.bcel.classfile.JavaClassDefinition; + +/** + * Checks for unread, non-final fields + * @author Rick Giles + */ +public class UnreadFieldCheck + extends AbstractReferenceCheck +{ + /** @see com.puppycrawl.tools.checkstyle.bcel.IObjectSetVisitor */ + public void leaveSet(Set aJavaClasses) + { + final Iterator it = aJavaClasses.iterator(); + while (it.hasNext()) { + final JavaClass javaClass = (JavaClass) it.next(); + final String className = javaClass.getClassName(); + final JavaClassDefinition classDef = findJavaClassDef(javaClass); + final FieldDefinition[] fieldDefs = classDef.getFieldDefs(); + for (int i = 0; i < fieldDefs.length; i++) { + if (fieldDefs[i].getReadReferenceCount() == 0) { + final Field field = fieldDefs[i].getField(); + if (!field.isFinal() + && (!ignore(className, field))) + { + log( + 0, + "unread.field", + new Object[] {className, fieldDefs[i]}); + } + } + } + } + } + + /** + * Determines whether a class name and Field should be ignored. + * Normally the Field is a Field of the named class. + * @param aClassName the class name. + * @param aField the Field. + * @return true if aClassName and aField should be ignored. + */ + protected boolean ignore(String aClassName, Field aField) + { + return ignore(aClassName, aField.getName()); + } +} \ No newline at end of file diff --git a/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/checks/UnreadPrivateFieldCheck.java b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/checks/UnreadPrivateFieldCheck.java new file mode 100644 index 000000000..2045cc0b1 --- /dev/null +++ b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/checks/UnreadPrivateFieldCheck.java @@ -0,0 +1,20 @@ +//Tested with BCEL-5.1 +//http://jakarta.apache.org/builds/jakarta-bcel/release/v5.1/ + +package com.puppycrawl.tools.checkstyle.bcel.checks; + +import org.apache.bcel.classfile.Field; + +/** + * Checks for unread, non-final private fields + * @author Rick Giles + */ +public class UnreadPrivateFieldCheck + extends UnreadFieldCheck +{ + /** @see UnreadFieldCheck */ + protected boolean ignore(String aClassName, Field aField) + { + return (!aField.isPrivate() || super.ignore(aClassName, aField)); + } +} \ No newline at end of file diff --git a/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/checks/UnusedMethodCheck.java b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/checks/UnusedMethodCheck.java new file mode 100644 index 000000000..cc0f2f464 --- /dev/null +++ b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/checks/UnusedMethodCheck.java @@ -0,0 +1,66 @@ +//Tested with BCEL-5.1 +//http://jakarta.apache.org/builds/jakarta-bcel/release/v5.1/ + +package com.puppycrawl.tools.checkstyle.bcel.checks; + +import java.util.Iterator; +import java.util.Set; + +import org.apache.bcel.classfile.JavaClass; +import org.apache.bcel.classfile.Method; + +import com.puppycrawl.tools.checkstyle.bcel.classfile.JavaClassDefinition; +import com.puppycrawl.tools.checkstyle.bcel.classfile.MethodDefinition; + +/** + * Checks for unused methods + * @author Rick Giles + */ +public class UnusedMethodCheck + extends AbstractReferenceCheck +{ + /** @see com.puppycrawl.tools.checkstyle.bcel.IObjectSetVisitor */ + public void leaveSet(Set aJavaClasses) + { + final Iterator it = aJavaClasses.iterator(); + while (it.hasNext()) { + final JavaClass javaClass = (JavaClass) it.next(); + final String className = javaClass.getClassName(); + final JavaClassDefinition classDef = findJavaClassDef(javaClass); + final MethodDefinition[] methodDefs = classDef.getMethodDefs(); + for (int i = 0; i < methodDefs.length; i++) { + if (!classDef.hasReference(methodDefs[i], getReferenceDAO())) { + final String methodName = methodDefs[i].getName(); + final Method method = methodDefs[i].getMethod(); + if (!ignore(className, method)) + { + log( + 0, + "unused.method", + new Object[] {className, methodDefs[i]}); + } + } + } + } + } + + /** + * Determines whether a class name and Method should be ignored. + * Normally the Method is a Method of the named class. + * @param aClassName the class name. + * @param aMethod the Method. + * @return true if aClassName and aMethod should be ignored. + */ + protected boolean ignore(String aClassName, Method aMethod) + { + return ignore(aClassName, aMethod.getName()); + } + + /** @see AbstractReferenceCheck */ + public boolean ignore(String aClassName, String aMethodName) + { + return (super.ignore(aClassName, aMethodName) + || aMethodName.equals("") + || aMethodName.equals("")); + } +} \ No newline at end of file diff --git a/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/checks/UnusedPrivateMethodCheck.java b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/checks/UnusedPrivateMethodCheck.java new file mode 100644 index 000000000..ac1209f3b --- /dev/null +++ b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/checks/UnusedPrivateMethodCheck.java @@ -0,0 +1,20 @@ +//Tested with BCEL-5.1 +//http://jakarta.apache.org/builds/jakarta-bcel/release/v5.1/ + +package com.puppycrawl.tools.checkstyle.bcel.checks; + +import org.apache.bcel.classfile.Method; + +/** + * Checks for unused private methods + * @author Rick Giles + */ +public class UnusedPrivateMethodCheck + extends UnusedMethodCheck +{ + /** @see UnusedMethodCheck */ + protected boolean ignore(String aClassName, Method aMethod) + { + return (!aMethod.isPrivate() || super.ignore(aClassName, aMethod)); + } +} \ No newline at end of file diff --git a/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/checks/messages.properties b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/checks/messages.properties new file mode 100644 index 000000000..986e34efc --- /dev/null +++ b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/checks/messages.properties @@ -0,0 +1,2 @@ +unread.field=Class ''{0}'', unread field ''{1}''. +unused.method=Class ''{0}'', unused method ''{1}''. \ No newline at end of file diff --git a/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/classfile/FieldDefinition.java b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/classfile/FieldDefinition.java new file mode 100644 index 000000000..bf102a8f5 --- /dev/null +++ b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/classfile/FieldDefinition.java @@ -0,0 +1,89 @@ +//Tested with BCEL-5.1 +//http://jakarta.apache.org/builds/jakarta-bcel/release/v5.1/ + +package com.puppycrawl.tools.checkstyle.bcel.classfile; + +import java.util.HashSet; +import java.util.Set; + +import org.apache.bcel.classfile.Field; + +import com.puppycrawl.tools.checkstyle.bcel.generic.FieldReference; +import com.puppycrawl.tools.checkstyle.bcel.generic.PUTFIELDReference; +import com.puppycrawl.tools.checkstyle.bcel.generic.PUTSTATICReference; + +/** + * Contains the definition of a Field and its references. + * @author Rick Giles + */ +public class FieldDefinition + extends FieldOrMethodDefinition +{ + /** the GET references for the Field */ + private final Set mGetReferences = new HashSet(); + + /** the PUT references for the FSield */ + private final Set mPutReferences = new HashSet(); + + /** + * Creates a FieldDefinition for a Field. + * @param aField the Field. + */ + public FieldDefinition(Field aField) + { + super(aField); + } + + /** + * Returns the Field for this definition. + * @return the Field for this definition. + */ + public Field getField() + { + return (Field) getFieldOrMethod(); + } + + /** + * Determines the number of read, or GET, references to the Field. + * @return the number of read references to the Field. + */ + public int getReadReferenceCount() + { + return mGetReferences.size(); + } + + /** + * Determines the number of write, or PUT, references to the Field. + * @return the number of write references to the Field. + */ + public int getWriteReferenceCount() + { + return mPutReferences.size(); + } + + /** + * Determines the total number of references to the Field. + * @return the number of references to the Field. + */ + public int getReferenceCount() + { + return getReadReferenceCount() + getWriteReferenceCount(); + } + + /** + * Adds a reference to the Field. + * @param aFieldRef the reference. + */ + public void addReference(FieldReference aFieldRef) + { + // TODO Polymorphize + if ((aFieldRef instanceof PUTFIELDReference) + || (aFieldRef instanceof PUTSTATICReference)) + { + mPutReferences.add(aFieldRef); + } + else { + mGetReferences.add(aFieldRef); + } + } +} diff --git a/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/classfile/FieldOrMethodDefinition.java b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/classfile/FieldOrMethodDefinition.java new file mode 100644 index 000000000..68e538df9 --- /dev/null +++ b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/classfile/FieldOrMethodDefinition.java @@ -0,0 +1,50 @@ +//Tested with BCEL-5.1 +//http://jakarta.apache.org/builds/jakarta-bcel/release/v5.1/ + +package com.puppycrawl.tools.checkstyle.bcel.classfile; + +import org.apache.bcel.classfile.FieldOrMethod; + +/** + * Contains the definition of a Field or a Method. + * @author Rick Giles + */ +public class FieldOrMethodDefinition +{ + /** the Field or Method */ + private FieldOrMethod mFieldOrMethod; + + /** + * Constructs a FieldOrMethodDefinition for a Field + * or a Method. + * @param aFieldOrMethod the Field or Method + */ + protected FieldOrMethodDefinition(FieldOrMethod aFieldOrMethod) + { + mFieldOrMethod = aFieldOrMethod; + } + + /** + * Returns the FieldOrMethod. + * @return the FieldOrMethod. + */ + protected FieldOrMethod getFieldOrMethod() + { + return mFieldOrMethod; + } + + /** + * Returns the name of the Field or Method. + * @return the name of the Field or Method. + */ + public String getName() + { + return mFieldOrMethod.getName(); + } + + /** @see java.lang.Object#toString() */ + public String toString() + { + return mFieldOrMethod.toString(); + } +} diff --git a/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/classfile/JavaClassDefinition.java b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/classfile/JavaClassDefinition.java new file mode 100644 index 000000000..5c6a0e432 --- /dev/null +++ b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/classfile/JavaClassDefinition.java @@ -0,0 +1,168 @@ +//Tested with BCEL-5.1 +//http://jakarta.apache.org/builds/jakarta-bcel/release/v5.1/ + +package com.puppycrawl.tools.checkstyle.bcel.classfile; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.bcel.Repository; +import org.apache.bcel.classfile.Field; +import org.apache.bcel.classfile.JavaClass; +import org.apache.bcel.classfile.Method; +import org.apache.bcel.generic.Type; + + +/** + * Contains the definition of a org.apache.bcel.classfile.JavaClass and + * the definitions of Methods and Fields of the JavaClass + * @author Rick Giles + */ +public class JavaClassDefinition +{ + /** the JavaClass */ + private JavaClass mJavaClass; + + /** the method definitions */ + private MethodDefinition[] mMethodDefs; + + /** field definitions, keyed on field name */ + private Map mFieldDefs; + + /** + * Creates a JavaClassDefinition from a JavaClass. + * @param aJavaClass the JavaClass for the definition. + */ + public JavaClassDefinition(JavaClass aJavaClass) + { + mJavaClass = aJavaClass; + + // store method definitions + final Method[] methods = aJavaClass.getMethods(); + mMethodDefs = new MethodDefinition[methods.length]; + for (int i = 0; i < methods.length; i++) { + mMethodDefs[i] = new MethodDefinition(methods[i]); + } + + // store field definitions + final Field[] fields = aJavaClass.getFields(); + mFieldDefs = new HashMap(fields.length); + for (int i = 0; i < fields.length; i++) { + mFieldDefs.put(fields[i].getName(), new FieldDefinition(fields[i])); + } + } + + /** + * Gets the JavaClass for this definition. + * @return the JavaClass + */ + public JavaClass getJavaClass() + { + return mJavaClass; + } + + /** + * Gets the method definitions for Methods of the JavaClass. + * @return the method definitions for Methods of the JavaClass. + */ + public MethodDefinition[] getMethodDefs() + { + return mMethodDefs; + } + + /** + * Gets the field definitions for Fields of the JavaClass. + * @return the method definitions for Fields of the JavaClass. + */ + public FieldDefinition[] getFieldDefs() + { + return (FieldDefinition[]) mFieldDefs.values().toArray( + new FieldDefinition[mFieldDefs.size()]); + } + + /** + * Finds the narrowest method that is compatible with a method. + * An invocation of the given method can be resolved as an invocation + * of the narrowest method. + * @param aClassName the class for the method. + * @param aMethodName the name of the method. + * @param aArgTypes the types for the method. + * @return the narrowest compatible method. + */ + public MethodDefinition findNarrowestMethod( + String aClassName, + String aMethodName, + Type[] aArgTypes) + { + MethodDefinition result = null; + final String javaClassName = mJavaClass.getClassName(); + if (Repository.instanceOf(aClassName, javaClassName)) { + // check all + for (int i = 0; i < mMethodDefs.length; i++) { + // TODO: check access privileges + if (mMethodDefs[i].isCompatible(aMethodName, aArgTypes)) { + if (result == null) { + result = mMethodDefs[i]; + } + //else if (mMethodDefs[i].isAsNarrow(result)) { + else if (result.isCompatible(mMethodDefs[i])) { + result = mMethodDefs[i]; + } + } + } + } + return result; + } + + /** + * Finds a field definition. + * @param aFieldName the name of the field. + * @return the field definition named aFieldName. + */ + public FieldDefinition findFieldDef(String aFieldName) + { + return (FieldDefinition) mFieldDefs.get(aFieldName); + } + + /** + * Determines whether there is reference to a given Method in this JavaClass + * definition or a definition in a superclass. + * @param aMethodDef the Method to check. + * @param aReferenceDAO reference DAO. + * @return true if there is a reference to the method of aMethodDef in + * this JavaClass or a superclass. + */ + public boolean hasReference( + MethodDefinition aMethodDef, + ReferenceDAO aReferenceDAO) + { + final String methodName = aMethodDef.getName(); + final Type[] argTypes = aMethodDef.getArgumentTypes(); + + // search the inheritance hierarchy + JavaClass currentJavaClass = getJavaClass(); + while (currentJavaClass != null) { + final JavaClassDefinition javaClassDef = + aReferenceDAO.findJavaClassDef(currentJavaClass); + if (javaClassDef != null) { + final MethodDefinition methodDef = + javaClassDef.findNarrowestMethod( + getJavaClass().getClassName(), + methodName, + argTypes); + if ((methodDef != null) + && (methodDef.hasReference(getJavaClass()))) + { + return true; + } + } + currentJavaClass = currentJavaClass.getSuperClass(); + } + return false; + } + /** @see comp.lang.Object#toString() */ + public String toString() + { + return getJavaClass().toString(); + } +} diff --git a/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/classfile/MethodDefinition.java b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/classfile/MethodDefinition.java new file mode 100644 index 000000000..3bf99a818 --- /dev/null +++ b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/classfile/MethodDefinition.java @@ -0,0 +1,175 @@ +//Tested with BCEL-5.1 +//http://jakarta.apache.org/builds/jakarta-bcel/release/v5.1/ + +package com.puppycrawl.tools.checkstyle.bcel.classfile; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.apache.bcel.Repository; +import org.apache.bcel.classfile.JavaClass; +import org.apache.bcel.classfile.Method; +import org.apache.bcel.generic.Type; + +import com.puppycrawl.tools.checkstyle.bcel.generic.InvokeReference; +import com.puppycrawl.tools.checkstyle.bcel.generic.Utils; + +/** + * Contains the definition of a Method and its references. + * @author Rick Giles + */ +public class MethodDefinition + extends FieldOrMethodDefinition +{ + /** the references to the Method */ + private Set mReferences = new HashSet(); + + /** + * Creates a MethodDefinition for a Method. + * @param aMethod the Method. + */ + public MethodDefinition(Method aMethod) + { + super(aMethod); + } + + /** + * Gets the references to the Method. + * @return the references to the Method. + */ + public Set getReferences() + { + return mReferences; + } + + /** + * Determines the number of references to the Method. + * @return the number of references to the Method. + */ + public int getReferenceCount() + { + return mReferences.size(); + } + + /** + * Returns the Method for this definition. + * @return the Method for this definition. + */ + public Method getMethod() + { + return (Method) getFieldOrMethod(); + } + + /** + * Adds a reference to the Method. + * @param aRef the reference. + */ + + public void addReference(InvokeReference aRef) + { + mReferences.add(aRef); + } + + /** + * Gets the Types of the Method's arguments. + * @return the argument Types. + */ + public Type[] getArgumentTypes() + { + return getMethod().getArgumentTypes(); + } + + /** + * Determines whether a Method is compatible with the + * Method of this definition. + * @param aMethod the Method to check. + * @return true if aMethod is compatible with the Method + * of this definition. + */ + public boolean isCompatible(Method aMethod) + { + return isCompatible(aMethod.getName(), aMethod.getArgumentTypes()); + } + + /** + * Determines whether a MethodDefinition is compatible with the + * Method of this definition. + * @param aMethodDef the Method definition to check. + * @return true if aMethod is compatible with the Method + * of this definition. + */ + public boolean isCompatible(MethodDefinition aMethodDef) + { + return isCompatible(aMethodDef.getMethod()); + } + + /** + * Determines whether the Method of a MethodDefinition is as narrow + * as the method for this definition. + * Precondition: the method for this has the same name and the same + * number of arguments as the Method for the given MethodDefinition. + * @param aMethodDef the MethodDefinition to check. + * @return true if the Method of aMethodDef is as narrow + * as the method for this definition. + */ + public boolean isAsNarrow(MethodDefinition aMethodDef) + { + return aMethodDef.isCompatible(this); +// final Type[] types1 = getArgumentTypes(); +// final Type[] types2 = aMethodDef.getArgumentTypes(); +// for (int i = 0; i < types2.length; i++) { +// if (!Utils.isCompatible(types1[i], types2[i])) { +// return false; +// } +// } +// return true; + } + + /** + * Determines whether a method is compatible with the Method of + * this definition. + * @param aMethodName the name of the method to check. + * @param aArgTypes the method argument types. + * @return true if the method is compatible with the Method of + * this definition. + */ + public boolean isCompatible(String aMethodName, Type[] aArgTypes) + { + // same name? + if (!getName().equals(aMethodName)) { + return false; + } + // compatible argument types? + final Type[] methodTypes = getArgumentTypes(); + if (methodTypes.length != aArgTypes.length) { + return false; + } + for (int i = 0; i < aArgTypes.length; i++) { + if (!Utils.isCompatible(aArgTypes[i], methodTypes[i])) { + return false; + } + } + return true; + } + + /** + * Determine whether this method definition has a reference from a class or + * a superclass. + * @param aJavaClass the JavaClass to check against. + * @return true if there is a reference to this method definition from a + * aJavaClass or a superclass of aJavaClass. + */ + public boolean hasReference(JavaClass aJavaClass) + { + final Iterator it = getReferences().iterator(); + while (it.hasNext()) { + final InvokeReference invokeRef = (InvokeReference) it.next(); + final String invokeClassName = invokeRef.getClassName(); + if (Repository.instanceOf(aJavaClass, invokeClassName)) { + return true; + } + } + return false; + } +} diff --git a/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/classfile/ReferenceDAO.java b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/classfile/ReferenceDAO.java new file mode 100644 index 000000000..8db06dd37 --- /dev/null +++ b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/classfile/ReferenceDAO.java @@ -0,0 +1,138 @@ +//Tested with BCEL-5.1 +//http://jakarta.apache.org/builds/jakarta-bcel/release/v5.1/ + +package com.puppycrawl.tools.checkstyle.bcel.classfile; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import org.apache.bcel.Repository; +import org.apache.bcel.classfile.JavaClass; +import org.apache.bcel.generic.Type; + +import com.puppycrawl.tools.checkstyle.bcel.generic.FieldReference; +import com.puppycrawl.tools.checkstyle.bcel.generic.InvokeReference; + +/** + * Accesses Method and Field references for a set of JavaClasses. + * @author Rick Giles + */ +public class ReferenceDAO +{ + /** maps a JavaClass to a JavaClassDefinition */ + private Map mJavaClasses = null; + + /** + * Creates a ReferenceDAO from a set of JavaClasses. + * @param aJavaClasses the set of JavaClasses for this DAO. + */ + public ReferenceDAO(Set aJavaClasses) + { + mJavaClasses = new HashMap(aJavaClasses.size()); + final Iterator it = aJavaClasses.iterator(); + while (it.hasNext()) { + final JavaClass javaClass = (JavaClass) it.next(); + final JavaClassDefinition javaClassDef = + new JavaClassDefinition(javaClass); + mJavaClasses.put(javaClass, javaClassDef); + } + } + + /** + * Finds the JavaClassDefinition for a given JavaClass. + * @param aJavaClass the JavaClass. + * @return the JavaClassDefinition keyed on aJavaClass. + */ + public JavaClassDefinition findJavaClassDef(JavaClass aJavaClass) + { + return (JavaClassDefinition) mJavaClasses.get(aJavaClass); + } + + /** + * Adds a reference for an invocation in the invoked method definition. + * The invocation is of the form class.method(args). + * @param aInvokeRef the invocation reference. + */ + public void addInvokeReference(InvokeReference aInvokeRef) + { + // find the class for the instruction + final String className = aInvokeRef.getClassName(); + JavaClass javaClass = Repository.lookupClass(className); + final String methodName = aInvokeRef.getName(); + final Type[] argTypes = aInvokeRef.getArgTypes(); + + // search up the class hierarchy for the class containing the + // method definition. + MethodDefinition narrowest = null; + while ((javaClass != null) && (narrowest == null)) { + final JavaClassDefinition javaClassDef = + (JavaClassDefinition) mJavaClasses.get(javaClass); + if (javaClassDef != null) { + // find narrowest compatible in the current class + narrowest = + javaClassDef.findNarrowestMethod( + className, + methodName, + argTypes); + if (narrowest != null) { + narrowest.addReference(aInvokeRef); + } + } + // search the parent + javaClass = javaClass.getSuperClass(); + } + } + + /** + * Adds a reference to a field. + * @param aFieldRef the field reference. + */ + public void addFieldReference(FieldReference aFieldRef) + { + final String className = aFieldRef.getClassName(); + JavaClass javaClass = Repository.lookupClass(className); + final String fieldName = aFieldRef.getName(); + // search up the class hierarchy for the class containing the + // method definition. + FieldDefinition fieldDef = null; + while ((javaClass != null) && (fieldDef == null)) { + final JavaClassDefinition javaClassDef = + (JavaClassDefinition) mJavaClasses.get(javaClass); + if (javaClassDef != null) { + fieldDef = javaClassDef.findFieldDef(fieldName); + if (fieldDef != null) { + fieldDef.addReference(aFieldRef); + } + } + //search the parent + javaClass = javaClass.getSuperClass(); + } + } + + /** + * Finds the definition of the field of a field reference. + * @param aFieldRef the reference to a field. + * @return the definition of the field for aFieldRef. + */ + public FieldDefinition findFieldDef(FieldReference aFieldRef) + { + final String className = aFieldRef.getClassName(); + JavaClass javaClass = Repository.lookupClass(className); + final String fieldName = aFieldRef.getName(); + // search up the class hierarchy for the class containing the + // method definition. + FieldDefinition result = null; + while ((javaClass != null) && (result == null)) { + final JavaClassDefinition javaClassDef = + (JavaClassDefinition) mJavaClasses.get(javaClass); + if (javaClassDef != null) { + result = javaClassDef.findFieldDef(fieldName); + } + //search the parent + javaClass = javaClass.getSuperClass(); + } + return result; + } +} diff --git a/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/generic/FieldOrMethodReference.java b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/generic/FieldOrMethodReference.java new file mode 100644 index 000000000..7aa0e4be7 --- /dev/null +++ b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/generic/FieldOrMethodReference.java @@ -0,0 +1,61 @@ +//Tested with BCEL-5.1 +//http://jakarta.apache.org/builds/jakarta-bcel/release/v5.1/ + +package com.puppycrawl.tools.checkstyle.bcel.generic; + +import org.apache.bcel.generic.ConstantPoolGen; +import org.apache.bcel.generic.FieldOrMethod; +import org.apache.bcel.generic.ObjectType; + +/** + * Describe class InstructionReference + * @author Rick Giles + * @version 18-Jun-2003 + */ +public class FieldOrMethodReference +{ + protected FieldOrMethod mInstruction; + + protected ConstantPoolGen mPoolGen; + + protected FieldOrMethodReference( + FieldOrMethod aInstruction, + ConstantPoolGen aPoolGen) + { + mInstruction = aInstruction; + mPoolGen = aPoolGen; + } + + /** + * @return + */ + public FieldOrMethod getInstruction() + { + return mInstruction; + } + + public String getClassName() + { + return mInstruction.getClassName(mPoolGen); + } + + public ObjectType getClassType() + { + return mInstruction.getClassType(mPoolGen); + } + + public ObjectType getLoadClassType() + { + return mInstruction.getLoadClassType(mPoolGen); + } + + public String getName() + { + return mInstruction.getName(mPoolGen); + } + + public String toString() + { + return mInstruction.toString(mPoolGen.getConstantPool()); + } +} diff --git a/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/generic/FieldReference.java b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/generic/FieldReference.java new file mode 100644 index 000000000..cda5f907e --- /dev/null +++ b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/generic/FieldReference.java @@ -0,0 +1,22 @@ +//Tested with BCEL-5.1 +//http://jakarta.apache.org/builds/jakarta-bcel/release/v5.1/ + +package com.puppycrawl.tools.checkstyle.bcel.generic; + +import org.apache.bcel.generic.ConstantPoolGen; +import org.apache.bcel.generic.FieldInstruction; + +/** + * Describe class FieldReference + * @author Rick Giles + * @version 18-Jun-2003 + */ +public class FieldReference extends FieldOrMethodReference +{ + protected FieldReference( + FieldInstruction aInstruction, + ConstantPoolGen aPoolGen) + { + super(aInstruction, aPoolGen); + } +} diff --git a/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/generic/GETFIELDReference.java b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/generic/GETFIELDReference.java new file mode 100644 index 000000000..b0cd399b1 --- /dev/null +++ b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/generic/GETFIELDReference.java @@ -0,0 +1,28 @@ +//Tested with BCEL-5.1 +//http://jakarta.apache.org/builds/jakarta-bcel/release/v5.1/ + +package com.puppycrawl.tools.checkstyle.bcel.generic; + +import org.apache.bcel.generic.ConstantPoolGen; +import org.apache.bcel.generic.GETFIELD; + +/** + * Describe class GETFIELDReference + * @author Rick Giles + * @version 18-Jun-2003 + */ +public class GETFIELDReference + extends FieldReference +{ + + /** + * @param aInstruction + * @param aPoolGen + */ + public GETFIELDReference( + GETFIELD aInstruction, + ConstantPoolGen aPoolGen) + { + super(aInstruction, aPoolGen); + } +} diff --git a/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/generic/GETSTATICReference.java b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/generic/GETSTATICReference.java new file mode 100644 index 000000000..a3e46deb9 --- /dev/null +++ b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/generic/GETSTATICReference.java @@ -0,0 +1,28 @@ +//Tested with BCEL-5.1 +//http://jakarta.apache.org/builds/jakarta-bcel/release/v5.1/ + +package com.puppycrawl.tools.checkstyle.bcel.generic; + +import org.apache.bcel.generic.ConstantPoolGen; +import org.apache.bcel.generic.GETSTATIC; + +/** + * Describe class GETSTATICReference + * @author Rick Giles + * @version 18-Jun-2003 + */ +public class GETSTATICReference + extends FieldReference +{ + + /** + * @param aInstruction + * @param aPoolGen + */ + public GETSTATICReference( + GETSTATIC aInstruction, + ConstantPoolGen aPoolGen) + { + super(aInstruction, aPoolGen); + } +} diff --git a/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/generic/InvokeReference.java b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/generic/InvokeReference.java new file mode 100644 index 000000000..6eb5e68e3 --- /dev/null +++ b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/generic/InvokeReference.java @@ -0,0 +1,38 @@ +//Tested with BCEL-5.1 +//http://jakarta.apache.org/builds/jakarta-bcel/release/v5.1/ + +package com.puppycrawl.tools.checkstyle.bcel.generic; + +import org.apache.bcel.generic.ConstantPoolGen; +import org.apache.bcel.generic.InvokeInstruction; +import org.apache.bcel.generic.Type; + + +/** + * Describe class MethodReference + * @author Rick Giles + * @version 18-Jun-2003 + */ +public class InvokeReference + extends FieldOrMethodReference +{ + + /** + * @param aInstruction + * @param aPoolGen + */ + public InvokeReference( + InvokeInstruction aInstruction, + ConstantPoolGen aPoolGen) + { + super(aInstruction, aPoolGen); + } + + /** + * @return + */ + public Type[] getArgTypes() + { + return ((InvokeInstruction) mInstruction).getArgumentTypes(mPoolGen); + } +} diff --git a/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/generic/PUTFIELDReference.java b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/generic/PUTFIELDReference.java new file mode 100644 index 000000000..81dcdb824 --- /dev/null +++ b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/generic/PUTFIELDReference.java @@ -0,0 +1,28 @@ +//Tested with BCEL-5.1 +//http://jakarta.apache.org/builds/jakarta-bcel/release/v5.1/ + +package com.puppycrawl.tools.checkstyle.bcel.generic; + +import org.apache.bcel.generic.ConstantPoolGen; +import org.apache.bcel.generic.PUTFIELD; + +/** + * Describe class GETFIELDReference + * @author Rick Giles + * @version 18-Jun-2003 + */ +public class PUTFIELDReference + extends FieldReference +{ + + /** + * @param aInstruction + * @param aPoolGen + */ + public PUTFIELDReference( + PUTFIELD aInstruction, + ConstantPoolGen aPoolGen) + { + super(aInstruction, aPoolGen); + } +} diff --git a/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/generic/PUTSTATICReference.java b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/generic/PUTSTATICReference.java new file mode 100644 index 000000000..bda78fba1 --- /dev/null +++ b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/generic/PUTSTATICReference.java @@ -0,0 +1,28 @@ +//Tested with BCEL-5.1 +//http://jakarta.apache.org/builds/jakarta-bcel/release/v5.1/ + +package com.puppycrawl.tools.checkstyle.bcel.generic; + +import org.apache.bcel.generic.ConstantPoolGen; +import org.apache.bcel.generic.PUTSTATIC; + +/** + * Describe class GETSTATICReference + * @author Rick Giles + * @version 18-Jun-2003 + */ +public class PUTSTATICReference + extends FieldReference +{ + + /** + * @param aInstruction + * @param aPoolGen + */ + public PUTSTATICReference( + PUTSTATIC aInstruction, + ConstantPoolGen aPoolGen) + { + super(aInstruction, aPoolGen); + } +} diff --git a/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/generic/Utils.java b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/generic/Utils.java new file mode 100644 index 000000000..4e0a108c0 --- /dev/null +++ b/contrib/bcel/src/checkstyle/com/puppycrawl/tools/checkstyle/bcel/generic/Utils.java @@ -0,0 +1,71 @@ +//Tested with BCEL-5.1 +//http://jakarta.apache.org/builds/jakarta-bcel/release/v5.1/ + +package com.puppycrawl.tools.checkstyle.bcel.generic; + +import org.apache.bcel.generic.ReferenceType; +import org.apache.bcel.generic.Type; + +/** + * Utility methods. + * @author Rick Giles + * @version 17-Jun-2003 + */ +public class Utils +{ + /** + * Tests whether one type is compatible with another for method + * invocation conversion. This includes assignment conversion, + * except the implicit narrowing of integer constants. + * JLS Section 5.2 + * @param aSubType the type to be converted. + * @param aSuperType the converted type. + * @return true if aSubType can be converted to aSuperType. + */ + public static boolean isCompatible(Type aSubType, Type aSuperType) + { + boolean result = false; + + if (aSubType.equals(aSuperType)) { + // identity conversion + result = true; + } + else if ((aSubType instanceof ReferenceType) + && (aSuperType instanceof ReferenceType)) + { + // widening reference conversion? + final ReferenceType aSubRefType = (ReferenceType) aSubType; + result = aSubRefType.isAssignmentCompatibleWith(aSuperType); + } + // widening primitive conversion? + else if (aSubType.equals(Type.BYTE)) { + result = + aSuperType.equals(Type.SHORT) + || aSuperType.equals(Type.INT) + || aSuperType.equals(Type.LONG) + || aSuperType.equals(Type.FLOAT) + || aSuperType.equals(Type.DOUBLE); + } + else if (aSubType.equals(Type.SHORT)) { + result = + aSuperType.equals(Type.INT) + || aSuperType.equals(Type.LONG) + || aSuperType.equals(Type.FLOAT) + || aSuperType.equals(Type.DOUBLE); + } + else if (aSubType.equals(Type.INT)) { + result = + aSuperType.equals(Type.LONG) + || aSuperType.equals(Type.FLOAT) + || aSuperType.equals(Type.DOUBLE); + } + else if (aSubType.equals(Type.LONG)) { + result = + aSuperType.equals(Type.FLOAT) || aSuperType.equals(Type.DOUBLE); + } + else if (aSubType.equals(Type.DOUBLE)) { + result = aSuperType.equals(Type.DOUBLE); + } + return result; + } +}