//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.HashSet; import java.util.Map; import java.util.Set; 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. The fields and * methods of the JavaClassDefinition are those whose scopes are * in restricted sets of Scopes. * @param aJavaClass the JavaClass for the definition. * @param aFieldScopes the restricted set of field scopes. * @param aMethodScopes the restriced set of method scopes. */ public JavaClassDefinition( JavaClass aJavaClass, Set aFieldScopes, Set aMethodScopes) { mJavaClass = aJavaClass; // create method definitions, restricted by scope final Method[] methods = aJavaClass.getMethods(); final Set methodSet = new HashSet(); mMethodDefs = new MethodDefinition[methods.length]; for (int i = 0; i < methods.length; i++) { if (Utils.inScope(methods[i], aMethodScopes)) { methodSet.add(new MethodDefinition(methods[i])); } } mMethodDefs = (MethodDefinition[]) methodSet.toArray( new MethodDefinition[methodSet.size()]); // create field definitions, restricted by scope final Field[] fields = aJavaClass.getFields(); mFieldDefs = new HashMap(fields.length); for (int i = 0; i < fields.length; i++) { if (Utils.inScope(fields[i], aFieldScopes)) { 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 java.lang.Object#toString() */ public String toString() { return getJavaClass().toString(); } }