BCEL .class file checks

This commit is contained in:
Rick Giles 2003-06-19 23:51:44 +00:00
parent db5ec5f654
commit 54f09ae36c
30 changed files with 2152 additions and 0 deletions

View File

@ -0,0 +1,15 @@
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
"-//Puppy Crawl//DTD Check Configuration 1.1//EN"
"http://www.puppycrawl.com/dtds/configuration_1_1.dtd">
<module name="Checker">
<metadata name="com.atlas-sw.eclipse" value="I like Sydney"/>
<property name="severity" value="error"/>
<module name="bcel.ClassFileSet">
<module name="bcel.checks.UnusedMethod">
</module>
<module name="bcel.checks.UnreadPrivateField">
</module>
</module>
</module>

View File

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

View File

@ -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 <code>ClassFileSetCheck</code> 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 <code>MessageDispatcher.fireErrors()</code> with
* all logged errors and than clears errors' list.
*/
private void fireErrors()
{
final LocalizedMessage[] errors = getMessageCollector().getMessages();
getMessageCollector().reset();
getMessageDispatcher().fireErrors("", errors);
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 <code>VisitorSet</code> 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);
}
}
}

View File

@ -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 <code>AbstractReferenceCheck</code>.
*
*/
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 <code>String</code> 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 <code>String</code> 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);
}
}

View File

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

View File

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

View File

@ -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("<init>")
|| aMethodName.equals("<clinit>"));
}
}

View File

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

View File

@ -0,0 +1,2 @@
unread.field=Class ''{0}'', unread field ''{1}''.
unused.method=Class ''{0}'', unused method ''{1}''.

View File

@ -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 <code>FieldDefinition</code> 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);
}
}
}

View File

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

View File

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

View File

@ -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 <code>MethodDefinition</code> 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;
}
}

View File

@ -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 <code>ReferenceDAO</code> 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;
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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