0

I would like to list all methods called by a method.

void create() throws MyException {
    System.out.println("TEST");
    of("String").map(String::valueOf).get();
}

In this method i would like to list

  • System.out.println
  • of
  • map
  • String::valueOf
  • get();

I have used to following code , from how to find all methods called in a method?

public class MethodFinder {

  public static void main(String[] args) throws Throwable {
    ClassPool cp = ClassPool.getDefault();
    CtClass ctClass = cp.get("MyClass");
    CtMethod method = ctClass.getDeclaredMethod("getItem1");
    method.instrument(
        new ExprEditor() {
            public void edit(MethodCall m)
                          throws CannotCompileException
            {
                System.out.println(m.getClassName() + "." + m.getMethodName() + " " + m.getSignature());
            }
        });
  }
}

And get all methods except the String::valueOf

It dosn't matter if this is solved by any other framework.

Trind
  • 1,583
  • 4
  • 18
  • 38
  • 2
    Note that this is correct since your method `create` does not call the method `String.valueOf`, but only gets a reference to the method and passes it to the map method. Strictly speaking your method does not know wether or not the passed method actually does ever get called. – luk2302 Nov 02 '17 at 12:17
  • is there any way to figure it out :)? – Trind Nov 02 '17 at 12:22
  • and i only need the reference to the method that is passed in – Trind Nov 02 '17 at 12:25
  • Your code doesn’t list `System.out.println`, as that’s not the method call. The method call is `println`, applied on a `PrintStream` instance. Besides that, you should not `import static` a method like `of`. There are more than sixty methods of that name just in the JRE API and you’re forcing the reader to guess about the actual method, especially in this question where we can’t scroll up to your `import` statements. – Holger Nov 03 '17 at 08:57

1 Answers1

5

Since String.valueOf is not actually invoked by the method, I’d use a broader term, e.g. talk about referenced methods which includes invoked methods. One way to gather all of them using ASM() is:

import java.io.IOException;
import java.util.Optional;
import org.objectweb.asm.*;

public class FindAllReferencedMethods {
    class Example {
        void create() {
            System.out.println("TEST");
            Optional.of("String").map(String::valueOf).get();
        }
    }
    public static void main(String[] args) throws IOException {
        ClassReader r = new ClassReader(Example.class.getName());
        r.accept(new ClassVisitor(Opcodes.ASM5) {
            @Override
            public MethodVisitor visitMethod(
                   int access, String name, String desc, String sig, String[] ex) {
                return name.equals("create")? new MethodRefCollector(): null;
            }

        }, ClassReader.SKIP_DEBUG|ClassReader.SKIP_FRAMES);
    }

    static void referencedMethod(String owner, String name, String desc) {
        System.out.println(
            Type.getObjectType(owner).getClassName() + "." + name + " " + desc);
    }

    static class MethodRefCollector extends MethodVisitor {
        public MethodRefCollector() {
            super(Opcodes.ASM5);
        }

        @Override
        public void visitMethodInsn(
                    int opcode, String owner, String name, String desc, boolean itf) {
            referencedMethod(owner, name, desc);
        }

        @Override
        public void visitInvokeDynamicInsn(
                    String name, String desc, Handle bsm, Object... bsmArgs) {
            if(bsm.getOwner().equals("java/lang/invoke/LambdaMetafactory")
            && bsm.getDesc().equals(bsm.getName().equals("altMetafactory")?
                                    ALT_SIG: MF_SIG)) {
                Handle target = (Handle)bsmArgs[1];
                referencedMethod(target.getOwner(), target.getName(), target.getDesc());
            }
        }
    }
    static String MF_SIG = "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;"
        +"Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/"
        +"MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;";
    static String ALT_SIG = "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;"
        +"Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;";
}
Holger
  • 285,553
  • 42
  • 434
  • 765