Java 理论与实践: 平衡测试,第 2 部分:编写和优化 bug 检测器
2010-01-11 00:00:00 来源:WEB开发网标识抛出的异常
此时,您已获得了您需要的一半信息:在何处捕获哪些异常。现在必须找出哪些异常被抛出。为此,您需要重写 BytecodeScanningDetector 的 sawOpcode() 方法,并处理与方法调用和异常抛出相对应的字节码。可以根据 athrow JVM 指令抛出异常。三个 JVM 指令分别用于调用以下方法:invokestatic、invokevirtual 和 invokespecial。就像使用 visit(CodeException) 一样,在调用超类 visit(Code) 时可以调用 sawOpcode,这样,如果在 sawOpcode() 中收集信息,那么在 super.visit(Code) 返回时,您将获得您需要的、有关捕获和抛出异常的所有信息。
清单 5 显示了 sawOpcode() 的实现,它将处理上述 JVM 指令。对于 athrow 指令,可以使用 FindBugs 的 OpcodeStack 帮助器类来了解 athrow 操作数的类型。对于方法调用指令,可以使用 Bytecode Engineering Library (BCEL) 类来提取方法声明抛出的已检查异常的类型。在任何一种情况下,都可以积累关于哪些异常在方法中的哪个字节码偏移量被抛出的信息,这样,在完成整个方法的处理后,可以将它们进行匹配。
清单 5. 标识受访问代码中抛出异常的位置public void sawOpcode(int seen) {
stack.mergeJumps(this);
try {
switch (seen) {
case ATHROW:
if (stack.getStackDepth() > 0) {
OpcodeStack.Item item = stack.getStackItem(0);
String signature = item.getSignature();
if (signature != null && signature.length() > 0) {
if (signature.startsWith("L"))
signature = SignatureConverter.convert(signature);
else
signature = signature.replace('/', '.');
throwList.add(new ExceptionThrown(signature, getPC()));
}
}
break;
case INVOKEVIRTUAL:
case INVOKESPECIAL:
case INVOKESTATIC:
String className = getDottedClassConstantOperand();
try {
if (!className.startsWith("[")) {
JavaClass clazz = Repository.lookupClass(className);
Method[] methods = clazz.getMethods();
for (Method method : methods) {
if (method.getName().equals(getNameConstantOperand())
&& method.getSignature().equals(getSigConstantOperand())) {
ExceptionTable et = method.getExceptionTable();
if (et != null) {
String[] names = et.getExceptionNames();
for (String name : names)
throwList.add(new ExceptionThrown(name, getPC()));
}
break;
}
}
}
} catch (ClassNotFoundException e) {
bugReporter.reportMissingClass(e);
}
break;
default:
break;
}
} finally {
stack.sawOpcode(this, seen);
}
}
更多精彩
赞助商链接