FuzzyLogic
FuzzyLogic

Reputation: 33

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

I need to determine line number of specific method in class using ObjectWeb ASM library.
Line number of method declaration or first line in method's body are equally accepted as right answers (6 or 7 in example).

Example:

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

I try to use MethodVisitor's visitLineNumber method, but it visit only first executable line (line 9 in example).
I found solution for this problem on JavaAssist library (link).
But is there a way to solve this with ASM?

EDIT:

Following snippet gave same result, line 9 instead of 6 or 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;
    }

Upvotes: 3

Views: 3395

Answers (2)

Holger
Holger

Reputation: 298509

The line numbers provided by any bytecode processing library are based on the LineNumberTable attribute which maps executable instructions of the method to line numbers. So it’s a fundamental limitation that you can not find source code lines in the class file which do not cause the generation of executable byte code.

Sometimes it even depends on the compiler, which source code line a construct spanning multiple lines gets assigned to.

Upvotes: 3

Ankur
Ankur

Reputation: 61

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;

}

Upvotes: 0

Related Questions