/*
* This file is part of JOP, the Java Optimized Processor
* see <http://www.jopdesign.com/>
*
* Copyright (C) 2010, Stefan Hepp (stefan@stefant.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.jopdesign.common.tools;
import com.jopdesign.common.ClassInfo;
import com.jopdesign.common.FieldInfo;
import com.jopdesign.common.MemberInfo;
import com.jopdesign.common.MethodCode;
import com.jopdesign.common.MethodInfo;
import com.jopdesign.common.bcel.Annotation;
import com.jopdesign.common.bcel.AnnotationAttribute;
import com.jopdesign.common.bcel.AnnotationElement;
import com.jopdesign.common.bcel.AnnotationElementValue;
import com.jopdesign.common.bcel.CustomAttribute;
import com.jopdesign.common.bcel.EnclosingMethod;
import com.jopdesign.common.bcel.ParameterAnnotationAttribute;
import com.jopdesign.common.bcel.StackMapTable;
import com.jopdesign.common.code.InvokeSite;
import com.jopdesign.common.graphutils.ClassElementVisitor;
import com.jopdesign.common.graphutils.DescendingClassTraverser;
import com.jopdesign.common.graphutils.EmptyClassElementVisitor;
import com.jopdesign.common.misc.JavaClassFormatError;
import com.jopdesign.common.type.ClassRef;
import com.jopdesign.common.type.ConstantFieldInfo;
import com.jopdesign.common.type.ConstantMethodInfo;
import com.jopdesign.common.type.ConstantNameAndTypeInfo;
import com.jopdesign.common.type.Descriptor;
import com.jopdesign.common.type.FieldRef;
import com.jopdesign.common.type.MethodRef;
import com.jopdesign.common.type.MemberID;
import org.apache.bcel.Constants;
import org.apache.bcel.classfile.Code;
import org.apache.bcel.classfile.CodeException;
import org.apache.bcel.classfile.Constant;
import org.apache.bcel.classfile.ConstantClass;
import org.apache.bcel.classfile.ConstantDouble;
import org.apache.bcel.classfile.ConstantFieldref;
import org.apache.bcel.classfile.ConstantFloat;
import org.apache.bcel.classfile.ConstantInteger;
import org.apache.bcel.classfile.ConstantInterfaceMethodref;
import org.apache.bcel.classfile.ConstantLong;
import org.apache.bcel.classfile.ConstantMethodref;
import org.apache.bcel.classfile.ConstantNameAndType;
import org.apache.bcel.classfile.ConstantPool;
import org.apache.bcel.classfile.ConstantString;
import org.apache.bcel.classfile.ConstantUtf8;
import org.apache.bcel.classfile.ConstantValue;
import org.apache.bcel.classfile.ExceptionTable;
import org.apache.bcel.classfile.Field;
import org.apache.bcel.classfile.InnerClass;
import org.apache.bcel.classfile.InnerClasses;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.LineNumberTable;
import org.apache.bcel.classfile.LocalVariableTable;
import org.apache.bcel.classfile.Method;
import org.apache.bcel.classfile.SourceFile;
import org.apache.bcel.classfile.StackMap;
import org.apache.bcel.classfile.StackMapEntry;
import org.apache.bcel.classfile.StackMapType;
import org.apache.bcel.classfile.Synthetic;
import org.apache.bcel.classfile.Unknown;
import org.apache.bcel.generic.ArrayType;
import org.apache.bcel.generic.CPInstruction;
import org.apache.bcel.generic.CodeExceptionGen;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.Instruction;
import org.apache.bcel.generic.InstructionHandle;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.LineNumberGen;
import org.apache.bcel.generic.LocalVariableGen;
import org.apache.bcel.generic.ObjectType;
import org.apache.bcel.generic.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* A helper class to perform various ClassInfo/MethodInfo/FieldInfo query tasks.
*
* @author Stefan Hepp (stefan@stefant.org)
*/
public class ConstantPoolReferenceFinder {
////////////////////////////////////////////////////////////////
// Helper classes to find something in a class
////////////////////////////////////////////////////////////////
/**
* Applying this visitor to a method, field, class or constantpool entries collects all
* found member references.
*/
public abstract static class ConstantPoolMemberVisitor extends EmptyClassElementVisitor {
@Override
public boolean visitMethod(MethodInfo methodInfo) {
processDescriptor(methodInfo.getDescriptor());
return true;
}
@Override
public boolean visitField(FieldInfo fieldInfo) {
processDescriptor(fieldInfo.getDescriptor());
return true;
}
@Override
public void visitConstantClass(ClassInfo classInfo, ConstantClass constant) {
processClassRef(classInfo.getConstantInfo(constant).getClassRef());
}
@Override
public void visitConstantField(ClassInfo classInfo, ConstantFieldref constant) {
ConstantFieldInfo field = (ConstantFieldInfo) classInfo.getConstantInfo(constant);
processFieldRef(field.getValue());
}
@Override
public void visitConstantMethod(ClassInfo classInfo, ConstantMethodref constant) {
ConstantMethodInfo method = (ConstantMethodInfo) classInfo.getConstantInfo(constant);
processMethodRef(method.getValue());
}
@Override
public void visitConstantInterfaceMethod(ClassInfo classInfo, ConstantInterfaceMethodref constant) {
ConstantMethodInfo method = (ConstantMethodInfo) classInfo.getConstantInfo(constant);
processMethodRef(method.getValue());
}
@Override
public void visitConstantNameAndType(ClassInfo classInfo, ConstantNameAndType constant) {
ConstantNameAndTypeInfo nat = (ConstantNameAndTypeInfo) classInfo.getConstantInfo(constant);
processDescriptor(nat.getValue().getDescriptor());
}
@Override
public void visitAnnotation(MemberInfo memberInfo, AnnotationAttribute obj) {
visitCustomAttribute(memberInfo, obj, true);
}
@Override
public void visitParameterAnnotation(MemberInfo memberInfo, ParameterAnnotationAttribute obj) {
visitCustomAttribute(memberInfo, obj, true);
}
@Override
public void visitCustomAttribute(MemberInfo memberInfo, CustomAttribute obj, boolean isCodeAttribute) {
String[] classes = obj.getReferencedClassNames();
if ( classes != null ) {
for (String cName : classes) {
processClassName(cName);
}
}
}
private void processClassRef(ClassRef ref) {
processType( ref.getType() );
}
private void processDescriptor(Descriptor d) {
Type ret = d.getType();
processType(ret);
if (d.isMethod()) {
for (Type t : d.getArgumentTypes()) {
processType(t);
}
}
}
private void processType(Type type) {
if ( type instanceof ArrayType) {
processType( ((ArrayType)type).getBasicType() );
} else if ( type instanceof ObjectType) {
processClassName( ((ObjectType)type).getClassName() );
}
}
public abstract void processClassName(String name);
public abstract void processFieldRef(FieldRef fieldRef);
public abstract void processMethodRef(MethodRef methodRef);
}
/**
* Collect only class names
*/
public static class ClassNameVisitor extends ConstantPoolMemberVisitor {
private Set<String> names;
public ClassNameVisitor(Set<String> names) {
this.names = names;
}
@Override
public void processClassName(String name) {
// also called for the classname part of field- and method-refs
names.add(name);
}
@Override
public void processFieldRef(FieldRef fieldRef) {
}
@Override
public void processMethodRef(MethodRef methodRef) {
}
}
/**
* Collect all member references, using a syntax which is always unambiguous
*/
public static class ClassMemberVisitor extends ConstantPoolMemberVisitor {
private Set<String> members;
public ClassMemberVisitor(Set<String> members) {
this.members = members;
}
@Override
public void processClassName(String name) {
members.add(name);
}
@Override
public void processFieldRef(FieldRef fieldRef) {
String className = fieldRef.getClassName();
members.add(className + MemberID.ALT_MEMBER_SEPARATOR + fieldRef.getName());
}
@Override
public void processMethodRef(MethodRef methodRef) {
String className = methodRef.getClassName();
members.add(className + MemberID.ALT_MEMBER_SEPARATOR + methodRef.getMethodSignature());
}
}
////////////////////////////////////////////////////////////////
// Find/replace references, member names, Pool entries
////////////////////////////////////////////////////////////////
public static Set<Integer> findPoolReferences(ClassInfo classInfo, boolean checkMembers) {
JavaClass javaClass = classInfo.compile();
Set<Integer> ids = findPoolReferences(classInfo, javaClass);
if (checkMembers) {
for (Field field : javaClass.getFields()) {
FieldInfo fieldInfo = classInfo.getFieldInfo(field.getName());
ids.addAll( findPoolReferences(fieldInfo, field) );
}
for (Method method : javaClass.getMethods()) {
MethodInfo methodInfo = classInfo.getMethodInfo(method.getName()+method.getSignature());
ids.addAll( findPoolReferences(methodInfo, method) );
}
}
return ids;
}
public static Set<Integer> findPoolReferences(MethodInfo methodInfo) {
return findPoolReferences(methodInfo, methodInfo.compile());
}
public static Set<Integer> findPoolReferences(FieldInfo fieldInfo) {
return findPoolReferences(fieldInfo, fieldInfo.getField());
}
/**
* Get a set of all referenced classes and class members for a method.
*
* @param methodInfo the method to search.
* @return a set of class names and class member IDs found in the method.
*/
public static Set<String> findReferencedMembers(MethodInfo methodInfo) {
Set<String> members = new HashSet<String>();
ClassMemberVisitor visitor = new ClassMemberVisitor(members);
Set<Integer> ids = findPoolReferences(methodInfo);
// fill the members list with info from the method descriptor
visitor.visitMethod(methodInfo);
// fill the members list with all found constantpool references
visitPoolReferences(methodInfo.getClassInfo(), visitor, ids);
return members;
}
/**
* Get a set of all referenced classes and class members for a field.
*
* @param fieldInfo the field to search.
* @return a set of class names and class member IDs found in the field.
*/
public static Set<String> findReferencedMembers(FieldInfo fieldInfo) {
Set<String> members = new HashSet<String>();
ClassMemberVisitor visitor = new ClassMemberVisitor(members);
Set<Integer> ids = findPoolReferences(fieldInfo);
// fill the members list with info from the type descriptor
visitor.visitField(fieldInfo);
// fill the members list with all found constantpool references
visitPoolReferences(fieldInfo.getClassInfo(), visitor, ids);
return members;
}
/**
* Find all referenced members in a class.
* @param classInfo the class to search.
* @param checkMembers if false, do not check fields and methods. Else check everything.
* @return a set of class names and class member signatures found in the class.
*/
public static Set<String> findReferencedMembers(ClassInfo classInfo, boolean checkMembers) {
// Else we need to go into details..
Set<String> members = new HashSet<String>();
ClassMemberVisitor visitor = new ClassMemberVisitor(members);
JavaClass javaClass = classInfo.compile();
Set<Integer> ids = findPoolReferences(classInfo, javaClass);
List<InvokeSite> invokes = new ArrayList<InvokeSite>();
if (checkMembers) {
for (Field field : javaClass.getFields()) {
FieldInfo fieldInfo = classInfo.getFieldInfo(field.getName());
// add members found in the field
visitor.visitField(fieldInfo);
// there are no invokesites in a field, only add found ids
ids.addAll( findPoolReferences(fieldInfo, field) );
}
for (Method method : javaClass.getMethods()) {
MethodInfo methodInfo = classInfo.getMethodInfo(method.getName()+method.getSignature());
// add members found in the method
visitor.visitMethod(methodInfo);
// add all ids for checking, add all invoke sites
ids.addAll( findPoolReferences(methodInfo, method) );
}
}
// fill the members list with all found constantpool references
visitor.visitClass(classInfo);
visitPoolReferences(classInfo, visitor, ids);
return members;
}
/**
* @param members a set of member names returned by a findReferencedMembers() method.
* @return a set of all classnames found in the given set.
*/
public static Set<String> getClassNames(Set<String> members) {
Set<String> classNames = new HashSet<String>();
for (String name : members) {
classNames.add( MemberID.getClassName(name, false) );
}
return classNames;
}
/**
* Get a set of all classes referenced by the given class, including superclasses, interfaces and
* references from the code, from parameters and from attributes.
*
* @param classInfo the classInfo to search
* @return a set of all fully qualified class names referenced by this class.
*/
public static Set<String> findReferencedClasses(ClassInfo classInfo) {
final Set<String> names = new HashSet<String>();
ClassNameVisitor visitor = new ClassNameVisitor(names);
new DescendingClassTraverser(visitor).visitClass(classInfo);
return names;
}
////////////////////////////////////////////////////////////////
// Private methods
////////////////////////////////////////////////////////////////
/**
* This is a helper visitor to find all constant pool references in classes / methods / fields.
*
* TODO this is nasty and 'fine-tuned' stuff, reduce number of indirections and make this code more robust
*
* This is supposed to work the following way:
* - findPoolReferences() applies this visitor to all indices found directly, then visits the attributes
* - IdFinderVisitor.visitConstant*(int) adds the index to the set, recurses down referenced constants using:
* - IdFinderVisitor.visitConstant*(Constant) visits all indices in the constant using above
* - A DescendingClassTraverser is used to
* - Visit various attributes
* - visitor-methods recurse down using visitConstant(int)
* - Visit referenced constants with unknown type, using the visitConstant(int) method
*/
private static class IdFinderVisitor implements ClassElementVisitor {
private final ClassInfo classInfo;
private final Set<Integer> ids;
private final ConstantPool cp;
private final ConstantPoolGen cpg;
private final DescendingClassTraverser classTraverser;
/**
* Create a new visitor.
*
* @param classInfo the classinfo which will be visited.
*/
public IdFinderVisitor(ClassInfo classInfo) {
this.classInfo = classInfo;
this.ids = new HashSet<Integer>();
this.cpg = classInfo.getConstantPoolGen();
this.cp = cpg.getConstantPool();
// A helper traverser to visit parts of classes/methods/..
this.classTraverser = new DescendingClassTraverser(this);
}
public Set<Integer> getIds() {
return ids;
}
@Override
public boolean visitMethod(MethodInfo methodInfo) {
// ignored, handled in findPoolReferences(Method)
return true;
}
@Override
public void finishMethod(MethodInfo methodInfo) {
// nothing to do
}
@Override
public void visitMethodCode(MethodCode methodCode) {
throw new AssertionError("Visited methodCode, but we visit only Method attributes");
}
@Override
public boolean visitField(FieldInfo fieldInfo) {
// ignored, handled in findPoolReferences(Field)
return true;
}
@Override
public void finishField(FieldInfo fieldInfo) {
// nothing to do
}
@Override
public boolean visitConstantPoolGen(ClassInfo classInfo, ConstantPoolGen cpg) {
// ignored
return true;
}
@Override
public void finishConstantPoolGen(ClassInfo classInfo, ConstantPoolGen cpg) {
// nothing to do
}
@Override
public void visitConstantClass(ClassInfo classInfo, ConstantClass constant) {
visitConstantUtf8(constant.getNameIndex());
}
@Override
public void visitConstantDouble(ClassInfo classInfo, ConstantDouble constant) {
// no indices here
}
@Override
public void visitConstantField(ClassInfo classInfo, ConstantFieldref constant) {
visitConstantClass(constant.getClassIndex());
visitConstantNameAndType(constant.getNameAndTypeIndex());
}
@Override
public void visitConstantFloat(ClassInfo classInfo, ConstantFloat constant) {
// no indices here
}
@Override
public void visitConstantInteger(ClassInfo classInfo, ConstantInteger constant) {
// no indices here
}
@Override
public void visitConstantLong(ClassInfo classInfo, ConstantLong constant) {
// no indices here
}
@Override
public void visitConstantMethod(ClassInfo classInfo, ConstantMethodref constant) {
visitConstantClass(constant.getClassIndex());
visitConstantNameAndType(constant.getNameAndTypeIndex());
}
@Override
public void visitConstantInterfaceMethod(ClassInfo classInfo, ConstantInterfaceMethodref constant) {
visitConstantClass(constant.getClassIndex());
visitConstantNameAndType(constant.getNameAndTypeIndex());
}
@Override
public void visitConstantNameAndType(ClassInfo classInfo, ConstantNameAndType constant) {
visitConstantUtf8(constant.getNameIndex());
visitConstantUtf8(constant.getSignatureIndex());
}
@Override
public void visitConstantString(ClassInfo classInfo, ConstantString constant) {
visitConstantUtf8(constant.getStringIndex());
}
@Override
public void visitConstantUtf8(ClassInfo classInfo, ConstantUtf8 constant) {
// no indices here
}
@Override
public void visitInnerClasses(ClassInfo classInfo, InnerClasses obj) {
visitConstantUtf8(obj.getNameIndex());
for (InnerClass ic : obj.getInnerClasses()) {
visitConstantClass(ic.getInnerClassIndex());
if (ic.getOuterClassIndex() != 0) {
visitConstantClass(ic.getOuterClassIndex());
}
if (ic.getInnerNameIndex() != 0) {
visitConstantUtf8(ic.getInnerNameIndex());
}
}
}
@Override
public void visitSourceFile(ClassInfo classInfo, SourceFile obj) {
visitConstantUtf8(obj.getNameIndex());
visitConstantUtf8(obj.getSourceFileIndex());
}
@Override
public void visitEnclosingMethod(ClassInfo classInfo, EnclosingMethod obj) {
visitConstantUtf8(obj.getNameIndex());
visitConstantClass(obj.getClassIndex());
int index = obj.getMethodIndex();
if (index != 0) {
visitConstantNameAndType(index);
}
}
@Override
public void visitConstantValue(FieldInfo fieldInfo, ConstantValue obj) {
visitConstantUtf8(obj.getNameIndex());
int index = obj.getConstantValueIndex();
Constant c = cp.getConstant(index);
if (c instanceof ConstantString) {
visitConstantString(index);
}
}
@Override
public void visitCodeException(MethodInfo methodInfo, CodeExceptionGen obj) {
ObjectType type = obj.getCatchType();
if (type != null) {
// we do not have an index here, we need to find it
visitConstantClass(cpg.addClass(type));
}
}
@Override
public void visitLineNumber(MethodInfo methodInfo, LineNumberGen obj) {
// is redundant, but we do it anyway: add the name of the linenr table attribute
visitConstantUtf8(cpg.addUtf8("LineNumberTable"));
// No other constantpool references here
}
@Override
public void visitLocalVariable(MethodInfo methodInfo, LocalVariableGen obj) {
// is redundant, but we do it anyway: add the name of the linenumber table attribute
visitConstantUtf8(cpg.addUtf8("LocalVariableTable"));
// we do not know the indices, so we need to find them
visitConstantUtf8(cpg.addUtf8(obj.getName()));
visitConstantUtf8(cpg.addUtf8(obj.getType().getSignature()));
}
@Override
public void visitStackMap(MethodInfo methodInfo, StackMap obj) {
visitConstantUtf8(obj.getNameIndex());
for (StackMapEntry e : obj.getStackMap()) {
for (StackMapType t : e.getTypesOfLocals()) {
visitStackType(t);
}
for (StackMapType t : e.getTypesOfStackItems()) {
visitStackType(t);
}
}
}
@Override
public void visitStackMapTable(MethodInfo methodInfo, StackMapTable obj) {
visitCustomAttribute(methodInfo, obj, true);
}
@Override
public void visitSignature(MemberInfo memberInfo, org.apache.bcel.classfile.Signature obj) {
visitConstantUtf8(obj.getNameIndex());
visitConstantUtf8(obj.getSignatureIndex());
}
@Override
public void visitDeprecated(MemberInfo memberInfo, org.apache.bcel.classfile.Deprecated obj) {
visitConstantUtf8(obj.getNameIndex());
}
@Override
public void visitSynthetic(MemberInfo memberInfo, Synthetic obj) {
visitConstantUtf8(obj.getNameIndex());
}
@Override
public void visitAnnotation(MemberInfo memberInfo, AnnotationAttribute obj) {
visitConstantUtf8(obj.getNameIndex());
for (Annotation a : obj.getAnnotations()) {
visitAnnotation(memberInfo.getClassInfo(), a);
}
}
@Override
public void visitParameterAnnotation(MemberInfo memberInfo, ParameterAnnotationAttribute obj) {
visitConstantUtf8(obj.getNameIndex());
for (int i = 0; i < obj.getNumParameters(); i++) {
for (Annotation a : obj.getAnnotations(i)) {
visitAnnotation(memberInfo.getClassInfo(), a);
}
}
}
@Override
public void visitUnknown(MemberInfo memberInfo, Unknown obj, boolean isCodeAttribute) {
if ("LocalVariableTypeTable".equals(obj.getName())) {
// TODO quick workaround, just ignore this attribute for now
return;
}
throw new JavaClassFormatError("Unknown Attribute "+obj.getName()+" in "+memberInfo+" found, not supported!");
}
@Override
public void visitCustomAttribute(MemberInfo memberInfo, CustomAttribute obj, boolean isCodeAttribute) {
Collection<Integer> ids = obj.getConstantPoolIDs();
if (ids == null) {
throw new JavaClassFormatError("CustomAttribute "+obj.getName()+" in "+memberInfo+" not supported!");
}
for (Integer i : ids) {
visitConstant(i);
}
}
@Override
public void visitCode(MethodInfo methodInfo, Code code) {
visitConstantUtf8(code.getNameIndex());
InstructionList il = new InstructionList(code.getCode());
visitInstructionList(methodInfo.getCode(), il);
il.dispose();
for (CodeException ce : code.getExceptionTable()) {
if (ce.getCatchType() != 0) {
visitConstantClass(ce.getCatchType());
}
}
new DescendingClassTraverser(this).visitAttributes(methodInfo, code.getAttributes());
}
@Override
public void visitExceptionTable(MethodInfo methodInfo, ExceptionTable table) {
visitConstantUtf8(table.getNameIndex());
for (int index : table.getExceptionIndexTable()) {
visitConstantClass(index);
}
}
@Override
public void visitLineNumberTable(MethodInfo methodInfo, LineNumberTable table) {
visitConstantUtf8(table.getNameIndex());
}
@Override
public void visitLocalVariableTable(MethodInfo methodInfo, LocalVariableTable table) {
visitConstantUtf8(table.getNameIndex());
}
@Override
public boolean visitClass(ClassInfo classInfo) {
// handled in findPoolReferences(JavaClass)
return true;
}
@Override
public void finishClass(ClassInfo classInfo) {
// nothing to do
}
//////// Instruction visitor /////////
private void visitInstructionList(MethodCode methodCode, InstructionList il) {
for (InstructionHandle ih : il.getInstructionHandles()) {
Instruction i = ih.getInstruction();
if (i instanceof CPInstruction) {
visitConstant(((CPInstruction)i).getIndex());
}
}
}
///////// End Instruction visitor /////////
private void visitStackType(StackMapType type) {
if (type.getType() == Constants.ITEM_Object && type.getIndex() != -1) {
visitConstantClass(type.getIndex());
}
}
private void visitAnnotation(ClassInfo classInfo, Annotation annotation) {
visitConstantUtf8(annotation.getTypeIndex());
for (AnnotationElement e : annotation.getElements()) {
visitConstantUtf8(e.getNameIndex());
AnnotationElementValue v = e.getValue();
if (v.isConstValue()) {
visitConstant(v.getConstValueIndex());
} else {
throw new JavaClassFormatError("Unsupported annotation type "+v.getTag());
}
}
}
private void visitConstant(int index) {
if (index == 0) return;
ids.add(index);
classTraverser.visitConstant(classInfo, index);
}
private void visitConstantClass(int index) {
if (index == 0) return;
ids.add(index);
ConstantClass c = (ConstantClass) cp.getConstant(index);
visitConstantClass(classInfo, c);
}
private void visitConstantNameAndType(int index) {
if (index == 0) return;
ids.add(index);
ConstantNameAndType c = (ConstantNameAndType) cp.getConstant(index);
visitConstantNameAndType(classInfo, c);
}
private void visitConstantString(int index) {
if (index == 0) return;
ids.add(index);
ConstantString c = (ConstantString) cp.getConstant(index);
visitConstantString(classInfo, c);
}
private void visitConstantUtf8(int index) {
if (index == 0) return;
ids.add(index);
}
}
/**
* Helper method which applies a visitor to all constants given by a set of ids.
* @param classInfo the class containing the constant pool
* @param visitor the visitor to apply
* @param ids a set of ids of pool entries to visit
*/
private static void visitPoolReferences(ClassInfo classInfo, ClassElementVisitor visitor, Set<Integer> ids) {
DescendingClassTraverser traverser = new DescendingClassTraverser(visitor);
ConstantPoolGen cpg = classInfo.getConstantPoolGen();
// iterate over the given pool entries, call the visitor
for (Integer id : ids) {
traverser.visitConstant(classInfo, cpg.getConstant(id));
}
}
private static Set<Integer> findPoolReferences(ClassInfo classInfo, JavaClass javaClass) {
// we do not need to handle invoke sites here specially, since we do not visit code here
IdFinderVisitor visitor = new IdFinderVisitor(classInfo);
// now, find *every* used constantpool index in the class, except for methods and fields
visitor.visitConstantClass(javaClass.getClassNameIndex());
visitor.visitConstantClass(javaClass.getSuperclassNameIndex());
for (int index : javaClass.getInterfaceIndices()) {
visitor.visitConstantClass(index);
}
DescendingClassTraverser traverser = new DescendingClassTraverser(visitor);
traverser.visitAttributes(classInfo, javaClass.getAttributes());
return visitor.getIds();
}
private static Set<Integer> findPoolReferences(MethodInfo methodInfo, Method method) {
ClassInfo classInfo = methodInfo.getClassInfo();
IdFinderVisitor visitor = new IdFinderVisitor(classInfo);
visitor.visitConstantUtf8(method.getNameIndex());
visitor.visitConstantUtf8(method.getSignatureIndex());
DescendingClassTraverser traverser = new DescendingClassTraverser(visitor);
// Code is an attribute, since we visit Method, not MethodGen
traverser.visitAttributes(methodInfo, method.getAttributes());
return visitor.getIds();
}
private static Set<Integer> findPoolReferences(FieldInfo fieldInfo, Field field) {
ClassInfo classInfo = fieldInfo.getClassInfo();
// we do not need to handle invoke sites here specially, since we do not visit code here
IdFinderVisitor visitor = new IdFinderVisitor(classInfo);
visitor.visitConstantUtf8(field.getNameIndex());
visitor.visitConstantUtf8(field.getSignatureIndex());
DescendingClassTraverser traverser = new DescendingClassTraverser(visitor);
traverser.visitAttributes(fieldInfo, field.getAttributes());
return visitor.getIds();
}
}