restrict field and method reference recording to configured reference check scopes

This commit is contained in:
Rick Giles 2003-06-24 10:06:32 +00:00
parent ed7fc0e632
commit 3da302031b
7 changed files with 186 additions and 62 deletions

View File

@ -3,6 +3,7 @@
package com.puppycrawl.tools.checkstyle.bcel;
import java.util.HashSet;
import java.util.Set;
import org.apache.bcel.classfile.ConstantPool;
@ -16,6 +17,7 @@ import org.apache.bcel.generic.INVOKEVIRTUAL;
import org.apache.bcel.generic.PUTFIELD;
import org.apache.bcel.generic.PUTSTATIC;
import com.puppycrawl.tools.checkstyle.api.Scope;
import com.puppycrawl.tools.checkstyle.bcel.classfile.JavaClassDefinition;
import com.puppycrawl.tools.checkstyle.bcel.classfile.ReferenceDAO;
import com.puppycrawl.tools.checkstyle.bcel.generic.FieldReference;
@ -29,10 +31,17 @@ 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 {
public final class ReferenceVisitor extends EmptyDeepVisitor
{
/** singleton */
private static ReferenceVisitor sInstance = new ReferenceVisitor();
/** scope for checking field references */
private Set mFieldScopes = new HashSet();
/** scope for checking method references */
private Set mMethodScopes = new HashSet();
/** maps a JavaClass to a JavaClassDefinition */
private ReferenceDAO mReferenceDAO;
@ -45,60 +54,71 @@ public final class ReferenceVisitor extends EmptyDeepVisitor {
* @author Rick Giles
* @version 18-Jun-2003
*/
private class GenericVisitor extends org.apache.bcel.generic.EmptyVisitor {
private class GenericVisitor extends org.apache.bcel.generic.EmptyVisitor
{
/** @see org.apache.bcel.generic.Visitor */
public void visitINVOKESPECIAL(INVOKESPECIAL aINVOKESPECIAL) {
public void visitINVOKESPECIAL(INVOKESPECIAL aINVOKESPECIAL)
{
addInvokeReference(
new InvokeReference(aINVOKESPECIAL, mCurrentPoolGen));
}
/** @see org.apache.bcel.generic.Visitor */
public void visitINVOKESTATIC(INVOKESTATIC aINVOKESTATIC) {
public void visitINVOKESTATIC(INVOKESTATIC aINVOKESTATIC)
{
addInvokeReference(
new InvokeReference(aINVOKESTATIC, mCurrentPoolGen));
}
/** @see org.apache.bcel.generic.Visitor */
public void visitINVOKEVIRTUAL(INVOKEVIRTUAL aINVOKEVIRTUAL) {
public void visitINVOKEVIRTUAL(INVOKEVIRTUAL aINVOKEVIRTUAL)
{
addInvokeReference(
new InvokeReference(aINVOKEVIRTUAL, mCurrentPoolGen));
}
/** @see org.apache.bcel.generic.Visitor */
public void visitGETSTATIC(GETSTATIC aGETSTATIC) {
public void visitGETSTATIC(GETSTATIC aGETSTATIC)
{
addFieldReference(
new GETSTATICReference(aGETSTATIC, mCurrentPoolGen));
}
/** @see org.apache.bcel.generic.Visitor */
public void visitGETFIELD(GETFIELD aGETFIELD) {
public void visitGETFIELD(GETFIELD aGETFIELD)
{
addFieldReference(
new GETFIELDReference(aGETFIELD, mCurrentPoolGen));
}
/** @see org.apache.bcel.generic.Visitor */
public void visitPUTSTATIC(PUTSTATIC aPUTSTATIC) {
public void visitPUTSTATIC(PUTSTATIC aPUTSTATIC)
{
addFieldReference(
new PUTSTATICReference(aPUTSTATIC, mCurrentPoolGen));
}
/** @see org.apache.bcel.generic.Visitor */
public void visitPUTFIELD(PUTFIELD aPUTFIELD) {
public void visitPUTFIELD(PUTFIELD aPUTFIELD)
{
addFieldReference(
new PUTFIELDReference(aPUTFIELD, mCurrentPoolGen));
}
}
/** prevent client construction */
private ReferenceVisitor() {
private ReferenceVisitor()
{
setGenericVisitor(new GenericVisitor());
addFieldScope(Scope.PRIVATE);
}
/**
* Returns the singleton ReferencesVisitor
* @return the singleton
*/
public static ReferenceVisitor getInstance() {
public static ReferenceVisitor getInstance()
{
return sInstance;
}
@ -106,7 +126,8 @@ public final class ReferenceVisitor extends EmptyDeepVisitor {
* Adds an invoke reference to the reference DAO.
* @param aReference the reference.
*/
private void addInvokeReference(InvokeReference aReference) {
private void addInvokeReference(InvokeReference aReference)
{
getReferenceDAO().addInvokeReference(aReference);
}
@ -114,25 +135,30 @@ public final class ReferenceVisitor extends EmptyDeepVisitor {
* Adds an field reference to the reference DAO.
* @param aReference the reference.
*/
private void addFieldReference(FieldReference aReference) {
private void addFieldReference(FieldReference aReference)
{
getReferenceDAO().addFieldReference(aReference);
}
/** @see com.puppycrawl.tools.checkstyle.bcel.IDeepVisitor */
public void visitSet(Set aJavaClasses) {
mReferenceDAO = new ReferenceDAO(aJavaClasses);
public void visitSet(Set aJavaClasses)
{
mReferenceDAO =
new ReferenceDAO(aJavaClasses, mFieldScopes, mMethodScopes);
}
/**
* Gets the reference DAO.
* @return the reference DAO.
*/
public ReferenceDAO getReferenceDAO() {
public ReferenceDAO getReferenceDAO()
{
return mReferenceDAO;
}
/** @see com.puppycrawl.tools.checkstyle.bcel.IDeepVisitor */
public void visitObject(Object aObject) {
public void visitObject(Object aObject)
{
final JavaClass javaClass = (JavaClass) aObject;
final ConstantPool pool = javaClass.getConstantPool();
mCurrentPoolGen = new ConstantPoolGen(pool);
@ -143,7 +169,26 @@ public final class ReferenceVisitor extends EmptyDeepVisitor {
* @param aJavaClass the JavaClass.
* @return the JavaClassDefinition for aJavaClass.
*/
public JavaClassDefinition findJavaClassDef(JavaClass aJavaClass) {
public JavaClassDefinition findJavaClassDef(JavaClass aJavaClass)
{
return getReferenceDAO().findJavaClassDef(aJavaClass);
}
/**
* Includes a scope in the scope for checking field references.
* @param aScope the scope to include.
*/
public void addFieldScope(Scope aScope)
{
mFieldScopes.add(aScope);
}
/**
* Includes a scope in the scope for checking method references.
* @param aScope the scope to include.
*/
public void addMethodScope(Scope aScope)
{
mMethodScopes.add(aScope);
}
}

View File

@ -51,12 +51,12 @@ public abstract class AbstractReferenceCheck
{
mScope = Scope.getInstance(aScopeName);
}
/**
* Determines whether a class name and field or method should be ignored.
* @param aClassName the class name.
* @param aName the name.
* @return true if aClassName and aName should be ignored.
* Determines whether a class name, and field or method should be ignored.
* @param aClassName the class name to consider.
* @param aFieldOrMethod the field or method to consider.
* @return true if aClassName, and field or method should be ignored.
*/
protected boolean ignore(String aClassName, FieldOrMethod aFieldOrMethod)
{
@ -65,7 +65,7 @@ public abstract class AbstractReferenceCheck
|| mIgnoreClassNameRegexp.match(aClassName)
|| mIgnoreNameRegexp.match(fieldOrMethodName));
}
/**
* Tests whether the scope of a field or method is compatible
* with the scope of this check. References for compatible

View File

@ -9,6 +9,8 @@ import java.util.Set;
import org.apache.bcel.classfile.Field;
import org.apache.bcel.classfile.JavaClass;
import com.puppycrawl.tools.checkstyle.api.Scope;
import com.puppycrawl.tools.checkstyle.bcel.ReferenceVisitor;
import com.puppycrawl.tools.checkstyle.bcel.classfile.FieldDefinition;
import com.puppycrawl.tools.checkstyle.bcel.classfile.JavaClassDefinition;
@ -19,6 +21,14 @@ import com.puppycrawl.tools.checkstyle.bcel.classfile.JavaClassDefinition;
public class UnreadFieldCheck
extends AbstractReferenceCheck
{
/** @see AbstractReferenceCheck */
public void setScope(String aFrom)
{
super.setScope(aFrom);
((ReferenceVisitor) getVisitor()).addFieldScope(
Scope.getInstance(aFrom));
}
/** @see com.puppycrawl.tools.checkstyle.bcel.IObjectSetVisitor */
public void leaveSet(Set aJavaClasses)
{

View File

@ -9,6 +9,8 @@ import java.util.Set;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.Method;
import com.puppycrawl.tools.checkstyle.api.Scope;
import com.puppycrawl.tools.checkstyle.bcel.ReferenceVisitor;
import com.puppycrawl.tools.checkstyle.bcel.classfile.JavaClassDefinition;
import com.puppycrawl.tools.checkstyle.bcel.classfile.MethodDefinition;
@ -19,6 +21,14 @@ import com.puppycrawl.tools.checkstyle.bcel.classfile.MethodDefinition;
public class UnusedMethodCheck
extends AbstractReferenceCheck
{
/** @see AbstractReferenceCheck */
public void setScope(String aScopeName)
{
super.setScope(aScopeName);
((ReferenceVisitor) getVisitor()).addMethodScope(
Scope.getInstance(aScopeName));
}
/** @see com.puppycrawl.tools.checkstyle.bcel.IObjectSetVisitor */
public void leaveSet(Set aJavaClasses)
{
@ -32,8 +42,7 @@ public class UnusedMethodCheck
if (!classDef.hasReference(methodDefs[i], getReferenceDAO())) {
final String methodName = methodDefs[i].getName();
final Method method = methodDefs[i].getMethod();
if (!ignore(className, method))
{
if (!ignore(className, method)) {
log(
0,
"unused.method",

View File

@ -4,7 +4,9 @@
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;
@ -30,29 +32,46 @@ public class JavaClassDefinition
private Map mFieldDefs;
/**
* Creates a JavaClassDefinition from a JavaClass.
* 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)
public JavaClassDefinition(
JavaClass aJavaClass,
Set aFieldScopes,
Set aMethodScopes)
{
mJavaClass = aJavaClass;
// store method definitions
// 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++) {
mMethodDefs[i] = new MethodDefinition(methods[i]);
if (Utils.inScope(methods[i], aMethodScopes)) {
methodSet.add(new MethodDefinition(methods[i]));
}
}
mMethodDefs =
(MethodDefinition[]) methodSet.toArray(
new MethodDefinition[methodSet.size()]);
// store field definitions
// create field definitions, restricted by scope
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]));
if (Utils.inScope(fields[i], aFieldScopes)) {
mFieldDefs.put(
fields[i].getName(),
new FieldDefinition(fields[i]));
}
}
}
/**
/**
* Gets the JavaClass for this definition.
* @return the JavaClass
*/
@ -135,31 +154,31 @@ public class JavaClassDefinition
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)
{
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;
}
{
return true;
}
}
currentJavaClass = currentJavaClass.getSuperClass();
}
return false;
}
/** @see java.lang.Object#toString() */
public String toString()

View File

@ -21,25 +21,27 @@ import com.puppycrawl.tools.checkstyle.bcel.generic.InvokeReference;
*/
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.
* @param aFieldScopes the scopes for field references.
* @param aMethodScopes the scopes for method references.
*/
public ReferenceDAO(Set aJavaClasses)
public ReferenceDAO(Set aJavaClasses, Set aFieldScopes, Set aMethodScopes)
{
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);
new JavaClassDefinition(javaClass, aFieldScopes, aMethodScopes);
mJavaClasses.put(javaClass, javaClassDef);
}
}
/** maps a JavaClass to a JavaClassDefinition */
private Map mJavaClasses = null;
/**
* Finds the JavaClassDefinition for a given JavaClass.
* @param aJavaClass the JavaClass.

View File

@ -0,0 +1,39 @@
package com.puppycrawl.tools.checkstyle.bcel.classfile;
import java.util.Set;
import org.apache.bcel.classfile.FieldOrMethod;
import com.puppycrawl.tools.checkstyle.api.Scope;
/**
* Utility methods for BCEL classfile package
* @author Rick Giles
*/
public class Utils
{
/**
* Determines whether the declared scope of a field or method is in
* a set of scopes.
* @param aFieldOrMethod the field or method to test.
* @param aScopes the set of scopes to test against.
* @return true if the declared scope of aFieldOrMethod is in aScopes.
*/
public static boolean inScope(FieldOrMethod aFieldOrMethod, Set aScopes)
{
if (aFieldOrMethod.isPrivate()) {
return (aScopes.contains(Scope.PRIVATE));
}
else if (aFieldOrMethod.isProtected()) {
return (aScopes.contains(Scope.PROTECTED));
}
else if (aFieldOrMethod.isPublic()) {
return (aScopes.contains(Scope.PUBLIC));
}
else {
return (aScopes.contains(Scope.PACKAGE));
}
}
}