[Clirr-devel] CVS: clirr/core/src/java/net/sf/clirr/core/internal/bcel BcelMethod.java,NONE,1.1 Bcel
Status: Alpha
Brought to you by:
lkuehne
Update of /cvsroot/clirr/clirr/core/src/java/net/sf/clirr/core/internal/bcel In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8230/src/java/net/sf/clirr/core/internal/bcel Added Files: BcelMethod.java BcelField.java BcelJavaType.java BcelScopeHelper.java Log Message: added bcel implementation for SPI --- NEW FILE --- package net.sf.clirr.core.internal.bcel; import org.apache.bcel.classfile.Attribute; import org.apache.bcel.classfile.JavaClass; import org.apache.bcel.classfile.Method; import org.apache.bcel.generic.Type; import net.sf.clirr.core.spi.JavaType; import net.sf.clirr.core.spi.Scope; final class BcelMethod implements net.sf.clirr.core.spi.Method { private Method method; private JavaClass owningClass; public BcelMethod(JavaClass owningClass, Method method) { this.owningClass = owningClass; this.method = method; } public JavaType getReturnType() { return convertType(method.getReturnType()); } public String getName() { return method.getName(); } public boolean isFinal() { return method.isFinal(); } public boolean isStatic() { return method.isStatic(); } public boolean isAbstract() { return method.isAbstract(); } public boolean isDeprecated() { Attribute[] attrs = method.getAttributes(); for (int i = 0; i < attrs.length; ++i) { if (attrs[i] instanceof org.apache.bcel.classfile.Deprecated) { return true; } } return false; } public Scope getDeclaredScope() { return BcelScopeHelper.getScope(method.getAccessFlags()); } public Scope getEffectiveScope() { // TODO: real impl return getDeclaredScope(); } public JavaType[] getArgumentTypes() { final Type[] types = method.getArgumentTypes(); return convertTypes(types); } private JavaType convertType(Type bcelType) { return new BcelJavaType(bcelType, owningClass.getRepository()); } /** * @param types * @return */ private JavaType[] convertTypes(final Type[] types) { JavaType[] retval = new JavaType[types.length]; for (int i = 0; i < retval.length; i++) { retval[i] = convertType(types[i]); } return retval; } } --- NEW FILE --- package net.sf.clirr.core.internal.bcel; import org.apache.bcel.classfile.Attribute; import org.apache.bcel.classfile.Field; import org.apache.bcel.classfile.JavaClass; import net.sf.clirr.core.spi.JavaType; import net.sf.clirr.core.spi.Scope; final class BcelField implements net.sf.clirr.core.spi.Field { private final Field field; private final JavaClass owningClass; BcelField(JavaClass owningClass, Field field) { this.owningClass = owningClass; this.field = field; } public String getName() { return field.getName(); } public JavaType getType() { return new BcelJavaType(field.getType(), owningClass.getRepository()); } public boolean isFinal() { return field.isFinal(); } public boolean isStatic() { return field.isStatic(); } public boolean isDeprecated() { Attribute[] attrs = field.getAttributes(); for (int i = 0; i < attrs.length; ++i) { if (attrs[i] instanceof org.apache.bcel.classfile.Deprecated) { return true; } } return false; } public Object getConstantValue() { return field.getConstantValue(); } public Scope getDeclaredScope() { return BcelScopeHelper.getScope(field.getAccessFlags()); } public Scope getEffectiveScope() { return getDeclaredScope(); // FIXME } public String toString() { return field.toString(); } } --- NEW FILE --- package net.sf.clirr.core.internal.bcel; import net.sf.clirr.core.spi.Field; import net.sf.clirr.core.spi.JavaType; import net.sf.clirr.core.spi.Method; import net.sf.clirr.core.spi.Scope; import org.apache.bcel.classfile.JavaClass; import org.apache.bcel.generic.ObjectType; import org.apache.bcel.generic.Type; import org.apache.bcel.util.Repository; /** * */ public final class BcelJavaType implements JavaType { private Type type; private JavaClass clazz; private Repository repository; public BcelJavaType(Type bcelType, Repository repository) { this.type = bcelType; this.repository = repository; this.clazz = findJavaClass(type); } public BcelJavaType(JavaClass clazz) { this.type = null; // TODO: how can I convert a JavaClass to the corresponding Type? this.repository = clazz.getRepository(); this.clazz = clazz; } public String getName() { if (clazz != null) { return clazz.getClassName(); } else { return type.toString(); } } public JavaType getContainingClass() { // TODO: move code from ScopeHelper here return null; } private JavaClass findJavaClass(Type type) { if (!(type instanceof ObjectType)) { return null; } ObjectType ot = (ObjectType) type; return repository.findClass(ot.getClassName()); } public JavaType[] getSuperClasses() { if (clazz == null) { return new JavaType[0]; } final JavaClass[] superClasses = clazz.getSuperClasses(); return convertToJavaTypeArray(superClasses); } public JavaType[] getAllInterfaces() { if (clazz == null) { return new JavaType[0]; } final JavaClass[] interfaces = clazz.getAllInterfaces(); return convertToJavaTypeArray(interfaces); } public JavaType[] getInnerClasses() { return new JavaType[0]; } public Method[] getMethods() { if (clazz == null) { return new Method[0]; } final org.apache.bcel.classfile.Method[] methods = clazz.getMethods(); Method[] ret = new Method[methods.length]; for (int i = 0; i < ret.length; i++) { ret[i] = new BcelMethod(clazz, methods[i]); } return ret; } public Field[] getFields() { if (clazz == null) { return new Field[0]; } final org.apache.bcel.classfile.Field[] fields = clazz.getFields(); Field[] ret = new Field[fields.length]; for (int i = 0; i < ret.length; i++) { ret[i] = new BcelField(clazz, fields[i]); } return ret; } public boolean isPrimitive() { return clazz == null; } public boolean isArray() { return false; } public boolean isFinal() { if (clazz == null) { return false; } return clazz.isFinal(); } public boolean isAbstract() { if (clazz == null) { return false; } return clazz.isAbstract(); } public boolean isInterface() { return clazz.isInterface(); } public Scope getDeclaredScope() { return BcelScopeHelper.getClassScope(clazz); } public Scope getEffectiveScope() { return getDeclaredScope(); // FIXME } public String toString() { return getName(); } /** * @param bcelClasses * @return */ private JavaType[] convertToJavaTypeArray(final JavaClass[] bcelClasses) { JavaType[] ret = new JavaType[bcelClasses.length]; for (int i = 0; i < ret.length; i++) { ret[i] = new BcelJavaType(bcelClasses[i]); } return ret; } } --- NEW FILE --- package net.sf.clirr.core.internal.bcel; import net.sf.clirr.core.CheckerException; import net.sf.clirr.core.spi.Scope; import org.apache.bcel.Constants; import org.apache.bcel.classfile.Attribute; import org.apache.bcel.classfile.ConstantClass; import org.apache.bcel.classfile.ConstantPool; import org.apache.bcel.classfile.ConstantUtf8; import org.apache.bcel.classfile.InnerClass; import org.apache.bcel.classfile.InnerClasses; import org.apache.bcel.classfile.JavaClass; import org.apache.bcel.util.Repository; final class BcelScopeHelper { /** * * */ private BcelScopeHelper() { } /** * Get a Scope object representing the accessibility of the specified * object. * <p> * Note that this method gives the wrong results for JavaClass objects * which are nested classes. Use getClassScope(jclass) instead. */ public static Scope getScope(int accessFlags) { if ((accessFlags & Constants.ACC_PUBLIC) > 0) { return Scope.PUBLIC; } if ((accessFlags & Constants.ACC_PROTECTED) > 0) { return Scope.PROTECTED; } if ((accessFlags & Constants.ACC_PRIVATE) > 0) { return Scope.PRIVATE; } return Scope.PACKAGE; } /** * Java class files only ever contain scope specifiers of "public" or * "package". For top-level classes, this is expected: it is not possible * to have a top-level protected or private class. * <p> * However nested classes <i>can</i> be declared as protected or private. The * way to tell the real scope of a nested class is to ignore the scope in * the actual class file itself, and instead look in the "InnerClasses" * attribute stored on the enclosing class. This is exactly what the java * compiler does when compiling, and what the jvm does when verifying class * linkage at runtime. * <p> * For a "top-level" class, this method just returns the access scope for * the class itself. For nested classes, the enclosing class of the * specified class is retrieved and its InnerClasses attribute checked to * find the true scope for the specified class. * <p> * @throws CheckerException if the specified class is a nested class and * the enclosing class could not be found, or if the supposedly enclosing * class has no reference to the nested class. This exception is not * expected to occur in practice, unless a truly screwed-up jar file is * passed to clirr for inspection. */ public static Scope getClassScope(JavaClass jclass) throws CheckerException { int dollarPos = jclass.getClassName().lastIndexOf('$'); if (dollarPos == -1) { // not a nested class return getScope(jclass.getAccessFlags()); } // ok this is a nested class String jclassName = jclass.getClassName(); String enclosingClassName = jclassName.substring(0, dollarPos); Repository repo = jclass.getRepository(); JavaClass enclosingClass = repo.findClass(enclosingClassName); if (enclosingClass == null) { throw new CheckerException( "Unable to locate enclosing class " + enclosingClassName + " for nested class " + jclassName); } ConstantPool pool = enclosingClass.getConstantPool(); Attribute[] attrs = enclosingClass.getAttributes(); for (int i = 0; i < attrs.length; ++i) { if (attrs[i] instanceof InnerClasses) { InnerClasses ics = (InnerClasses) attrs[i]; InnerClass[] icarray = ics.getInnerClasses(); for (int j = 0; j < icarray.length; ++j) { // in the code below, instanceof checks should not be necessary // before casting Constants because the classfile format ensures // that instanceof would always be true InnerClass ic = icarray[j]; int classIndex = ic.getInnerClassIndex(); ConstantClass constClass = (ConstantClass) pool.getConstant(classIndex); int nameIndex = constClass.getNameIndex(); ConstantUtf8 nameconst = (ConstantUtf8) pool.getConstant(nameIndex); String classname = nameconst.getBytes().replace('/', '.'); if (jclassName.equals(classname)) { return getScope(ic.getInnerAccessFlags()); } } } } // weird; no nested class info found throw new CheckerException( "Unable to find information in class " + enclosingClass.getClassName() + " referring back to nested class " + jclassName); } } |