CheckClassAdapterpublic class CheckClassAdapter extends ClassAdapter A {@link ClassAdapter ClassAdapter} that checks that its methods are properly
used. More precisely this class adapter checks each method call individually,
based only on its arguments, but does not check the
sequence of method calls. For example, the invalid sequence
visitField(ACC_PUBLIC, "i", "I", null) visitField(ACC_PUBLIC,
"i", "D", null) will not be detected by this class adapter. |
Fields Summary |
---|
private boolean | starttrue if the visit method has been called. | private boolean | endtrue if the visitEnd method has been called. |
Constructors Summary |
---|
public CheckClassAdapter(ClassVisitor cv)Constructs a new {@link CheckClassAdapter CheckClassAdapter} object.
super(cv);
|
Methods Summary |
---|
static void | checkAccess(int access, int possibleAccess)Checks that the given access flags do not contain invalid flags. This
method also checks that mutually incompatible flags are not set
simultaneously.
if ((access & ~possibleAccess) != 0) {
throw new IllegalArgumentException("Invalid access flags: " + access);
}
int pub = ((access & Constants.ACC_PUBLIC) != 0 ? 1 : 0);
int pri = ((access & Constants.ACC_PRIVATE) != 0 ? 1 : 0);
int pro = ((access & Constants.ACC_PROTECTED) != 0 ? 1 : 0);
if (pub + pri + pro > 1) {
throw new IllegalArgumentException(
"public private and protected are mutually exclusive: " + access);
}
int fin = ((access & Constants.ACC_FINAL) != 0 ? 1 : 0);
int abs = ((access & Constants.ACC_ABSTRACT) != 0 ? 1 : 0);
if (fin + abs > 1) {
throw new IllegalArgumentException(
"final and abstract are mutually exclusive: " + access);
}
| private void | checkState()Checks that the visit method has been called and that visitEnd has not been
called.
if (!start) {
throw new IllegalStateException(
"Cannot visit member before visit has been called.");
}
if (end) {
throw new IllegalStateException(
"Cannot visit member after visitEnd has been called.");
}
| public static void | main(java.lang.String[] args)Checks a given class.
Usage: CheckClassAdapter
<fully qualified class name or class file name>
if (args.length != 1) {
printUsage();
}
ClassReader cr;
if (args[0].endsWith(".class")) {
cr = new ClassReader(new FileInputStream(args[0]));
} else {
cr = new ClassReader(args[0]);
}
TreeClassAdapter ca = new TreeClassAdapter(null);
cr.accept(new CheckClassAdapter(ca), true);
List methods = ca.classNode.methods;
for (int i = 0; i < methods.size(); ++i) {
MethodNode method = (MethodNode)methods.get(i);
if (method.instructions.size() > 0) {
Analyzer a = new Analyzer(new SimpleVerifier());
try {
a.analyze(ca.classNode, method);
continue;
} catch (Exception e) {
e.printStackTrace();
}
final Frame[] frames = a.getFrames();
System.out.println(method.name + method.desc);
TraceCodeVisitor cv = new TraceCodeVisitor(null) {
public void visitMaxs (int maxStack, int maxLocals) {
for (int i = 0; i < text.size(); ++i) {
String s = frames[i] == null ? "null" : frames[i].toString();
while (s.length() < maxStack+maxLocals+1) {
s += " ";
}
System.out.print(
Integer.toString(i + 100000).substring(1) + " " + s + " : "
+ text.get(i));
}
System.out.println();
}
};
for (int j = 0; j < method.instructions.size(); ++j) {
Object insn = method.instructions.get(j);
if (insn instanceof AbstractInsnNode) {
((AbstractInsnNode)insn).accept(cv);
} else {
cv.visitLabel((Label)insn);
}
}
cv.visitMaxs(method.maxStack, method.maxLocals);
}
}
| private static void | printUsage()
System.err.println("TODO.");
System.err.println("Usage: CheckClassAdapter " +
"<fully qualified class name or class file name>");
System.exit(-1);
| public void | visit(int version, int access, java.lang.String name, java.lang.String superName, java.lang.String[] interfaces, java.lang.String sourceFile)
if (start) {
throw new IllegalStateException("visit must be called only once");
} else {
start = true;
}
checkState();
checkAccess(
access,
Constants.ACC_PUBLIC +
Constants.ACC_FINAL +
Constants.ACC_SUPER +
Constants.ACC_INTERFACE +
Constants.ACC_ABSTRACT +
Constants.ACC_SYNTHETIC +
Constants.ACC_ANNOTATION +
Constants.ACC_ENUM +
Constants.ACC_DEPRECATED);
CheckCodeAdapter.checkInternalName(name, "class name");
if (name.equals("java/lang/Object")) {
if (superName != null) {
throw new IllegalArgumentException(
"The super class name of the Object class must be 'null'");
}
} else {
CheckCodeAdapter.checkInternalName(superName, "super class name");
}
if ((access & Constants.ACC_INTERFACE) != 0) {
if (!superName.equals("java/lang/Object")) {
throw new IllegalArgumentException(
"The super class name of interfaces must be 'java/lang/Object'");
}
}
if (interfaces != null) {
for (int i = 0; i < interfaces.length; ++i) {
CheckCodeAdapter.checkInternalName(
interfaces[i], "interface name at index " + i);
}
}
cv.visit(version, access, name, superName, interfaces, sourceFile);
| public void | visitAttribute(oracle.toplink.libraries.asm.Attribute attr)
checkState();
if (attr == null) {
throw new IllegalArgumentException(
"Invalid attribute (must not be null)");
}
| public void | visitEnd()
checkState();
end = true;
cv.visitEnd();
| public void | visitField(int access, java.lang.String name, java.lang.String desc, java.lang.Object value, oracle.toplink.libraries.asm.Attribute attrs)
checkState();
checkAccess(
access,
Constants.ACC_PUBLIC +
Constants.ACC_PRIVATE +
Constants.ACC_PROTECTED +
Constants.ACC_STATIC +
Constants.ACC_FINAL +
Constants.ACC_VOLATILE +
Constants.ACC_TRANSIENT +
Constants.ACC_SYNTHETIC +
Constants.ACC_ENUM +
Constants.ACC_DEPRECATED);
CheckCodeAdapter.checkIdentifier(name, "field name");
CheckCodeAdapter.checkDesc(desc, false);
if (value != null) {
CheckCodeAdapter.checkConstant(value);
}
cv.visitField(access, name, desc, value, attrs);
| public void | visitInnerClass(java.lang.String name, java.lang.String outerName, java.lang.String innerName, int access)
checkState();
CheckCodeAdapter.checkInternalName(name, "class name");
if (outerName != null) {
CheckCodeAdapter.checkInternalName(outerName, "outer class name");
}
if (innerName != null) {
CheckCodeAdapter.checkIdentifier(innerName, "inner class name");
}
checkAccess(
access,
Constants.ACC_PUBLIC +
Constants.ACC_PRIVATE +
Constants.ACC_PROTECTED +
Constants.ACC_STATIC +
Constants.ACC_FINAL +
Constants.ACC_INTERFACE +
Constants.ACC_ABSTRACT +
Constants.ACC_SYNTHETIC +
Constants.ACC_ANNOTATION +
Constants.ACC_ENUM);
cv.visitInnerClass(name, outerName, innerName, access);
| public oracle.toplink.libraries.asm.CodeVisitor | visitMethod(int access, java.lang.String name, java.lang.String desc, java.lang.String[] exceptions, oracle.toplink.libraries.asm.Attribute attrs)
checkState();
checkAccess(
access,
Constants.ACC_PUBLIC +
Constants.ACC_PRIVATE +
Constants.ACC_PROTECTED +
Constants.ACC_STATIC +
Constants.ACC_FINAL +
Constants.ACC_SYNCHRONIZED +
Constants.ACC_BRIDGE +
Constants.ACC_VARARGS +
Constants.ACC_NATIVE +
Constants.ACC_ABSTRACT +
Constants.ACC_STRICT +
Constants.ACC_SYNTHETIC +
Constants.ACC_DEPRECATED);
CheckCodeAdapter.checkMethodIdentifier(name, "method name");
CheckCodeAdapter.checkMethodDesc(desc);
if (exceptions != null) {
for (int i = 0; i < exceptions.length; ++i) {
CheckCodeAdapter.checkInternalName(
exceptions[i], "exception name at index " + i);
}
}
return new CheckCodeAdapter(
cv.visitMethod(access, name, desc, exceptions, attrs));
|
|