spyros
spyros

Reputation: 59

Getting Method Call Information from AST

How can I get the names of the methods invoked in each method declaration of a program using AST (Abstract Syntax Tree) parser? So far, I have managed to get all the names of the methods' declaration and all the names of the methods being invoked, but I want to know which method call which methods. For example, I want to see that method m1 calls methods mA and mB, while method m2 calls methods mC and mD, etc.

[EDIT 11/9/2011 IDB, transcribing newbie's extended comment back in the body of the original question. I hope I have transcribed it correctly. I hope the author comes back and revises as necessary]:

My problem seems to be that (Eclipse's) MethodDeclaration api doesn't have a GetInvokedMethodName function to call. Here is my code:

 public class MethodVisitor extends ASTVisitor { 

         List<MethodDeclaration> methods = new ArrayList<MethodDeclaration>();

         @Override public boolean visit(MethodDeclaration node) { 
             methods.add(node); 
             return super.visit(node); } 

         public List<MethodDeclaration> getMethods() 
             { return methods; }

         List<MethodInvocation> methods1 = new ArrayList<MethodInvocation>();

         @Override public boolean visit(MethodInvocation node)
             { methods1.add(node); 
               return super.visit(node); } 

        public List<MethodInvocation> getMethods1() 
             { return methods1; } 
        } 

    ...

    for (MethodDeclaration method : visitor .getMethods()) 
        { System.out.println("Method name: " + method.getName() 
                            + " Return type: " + method.getReturnType2() 
                            + " Is constructor: " + method.isConstructor()
                            + " Method invoked: " + ASTNode.METHOD_INVOCATION );
           ); }

    for (MethodInvocation method1 : visitor .getMethods1())
           { System.out.println("Method name invoked: " + method1.getName() ); }

Upvotes: 4

Views: 5013

Answers (2)

J3lly
J3lly

Reputation: 148

I had the same problem. This was my solution to it:

final HashMap<MethodDeclaration, ArrayList<MethodInvocation>> invocationsForMethods =
    new HashMap<MethodDeclaration, ArrayList<MethodInvocation>>();

        CompilationUnit cu = (CompilationUnit) ap.createAST(null);
        cu.accept(new ASTVisitor() {

            private MethodDeclaration activeMethod;

            @Override
            public boolean visit(MethodDeclaration node) {
                activeMethod = node;
                return super.visit(node);
            }

            @Override
            public boolean visit(MethodInvocation node) {
                if (invocationsForMethods.get(activeMethod) == null) {
                    invocationsForMethods.put(activeMethod, new ArrayList<MethodInvocation>());
                }
                invocationsForMethods.get(activeMethod).add(node);
                return super.visit(node);
            }

        });

Now, one can ask the invocationsForMethods.keySet() to get all the method declarations for the used AST and invocationsForMethods.get(key) returns all method invocations for the declaration given as a key.

Upvotes: 3

Ira Baxter
Ira Baxter

Reputation: 95334

If you want to know which specific method mB (of all the ones named "mB" throughout your vast array of classes) is invoked by m1, you need more than just the AST. You need a full symbol table, that binds each symbol use to the possible definitions that match it.

The process of computing such a symbol table is difficult for many languages and very hard for Java (but not nearly as bad as it is for C++). Somebody has to encode the rules of how an identifier is looked up in the face of (local) scopes, inheritance, overloads, implied casts, etc, and the Java reference manual devotes a significant portion of its content trying to explain that. You don't want to have to do this yourself.

What you really need is a full Java front end, that has both ASTs and the corresponding symbol tables, for each method you want to inspect. You can get this, I think, from interfaces to the (Sun?) Java compiler (I don't personally know how to do this), from the Jikes compiler, from the Eclipse Java AST (?) module, and from tools such as our Java Front End. Another approach is to process class files, which contain the method calls in JVM form, with the advavntage that the JVM instructions all have built with the benefit of a symbol table.

If you want to compute m1 calls mA calls mQ calls .... mZ, you need a tool that is willing to read in the entire source code base at once. The compilers won't do that for you, but you can use Eclipse or our front end to do that.

Upvotes: 2

Related Questions