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

How to determine line number for the method with java ASM?

我需要使用 ObjectWeb ASM 库确定 class 中特定方法的行号。
方法声明的行号或方法主体中的第一行同样被接受为正确答案(示例中为 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;
    }
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;

}

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

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