如何使用java ASM确定方法的行号?

时间:2018-04-23 17:33:20

标签: java bytecode java-bytecode-asm line-numbers

我需要使用ObjectWeb ASM库确定类中特定方法的行号。
方法声明的行号或方法体中的第一行同样被接受为正确的答案(例如6或7)。

实施例

1. public class Foo {
  ...
6.     public void bar() {
7.           try {
8.                try {
9.                     System.out.println(); //first executable line

我尝试使用MethodVisitor的visitLineNumber方法,但它只访问第一个可执行行(例子中的第9行)。
我在JavaAssist库(link)上找到了解决此问题的方法。
但是有没有办法用ASM来解决这个问题?

编辑:

以下代码段给出了相同的结果,第9行而不是6或7。

public static int getLineNumber(String path) throws IOException {
        final File f = new File(path);
        try (FileInputStream fis = new FileInputStream(f)) {
            ClassReader reader = new ClassReader(fis);
            ClassNode clNode = new ClassNode(Opcodes.ASM5);
            reader.accept(clNode, Opcodes.ASM5);
            for (MethodNode mNode : (List<MethodNode>) clNode.methods) {
                if (mNode.name.equals("bar")) {
                    ListIterator<AbstractInsnNode> it = mNode.instructions.iterator();
                    while (it.hasNext()) {
                        AbstractInsnNode inNode = it.next();
                        if (inNode instanceof LineNumberNode) {
                            return ((LineNumberNode) inNode).line;
                        }
                    }
                }
            }
        }
        return -1;
    }

2 个答案:

答案 0 :(得分:1)

任何字节码处理库提供的行号都基于LineNumberTable attribute,它将方法的可执行指令映射到行号。所以这是一个基本的限制,你不能在类文件中找到不会导致生成可执行字节代码的源代码行。

有时甚至取决于编译器,跨越多行的构造的源代码行被分配给。

答案 1 :(得分:0)

public static LineNumberNode findLineNumberForInstruction(InsnList 
insnList, AbstractInsnNode insnNode) {
    Validate.notNull(insnList);
    Validate.notNull(insnNode);

    int idx = insnList.indexOf(insnNode);
    Validate.isTrue(idx != -1);

    // Get index of labels and insnNode within method
    ListIterator<AbstractInsnNode> insnIt = insnList.iterator(idx);
    while (insnIt.hasPrevious()) {
        AbstractInsnNode node = insnIt.previous();

        if (node instanceof LineNumberNode) {
            return (LineNumberNode) node;
        }
    }

    return null;

}