Java 从AST获取方法调用信息

Java 从AST获取方法调用信息,java,eclipse,abstract-syntax-tree,Java,Eclipse,Abstract Syntax Tree,如何使用AST(抽象语法树)解析器获取程序的每个方法声明中调用的方法的名称?到目前为止,我已经获得了方法声明的所有名称和被调用方法的所有名称,但是我想知道哪个方法调用哪个方法。例如,我想看到方法m1调用方法mA和mB,而方法m2调用方法mC和mD,等等 [编辑2011年11月9日IDB,将新手的扩展评论抄写回原始问题正文。我希望我抄写正确。我希望作者回来并根据需要进行修改]: 我的问题似乎是(Eclipse的)MethodDeclaration api没有要调用的GetInvokedMethod

如何使用AST(抽象语法树)解析器获取程序的每个方法声明中调用的方法的名称?到目前为止,我已经获得了方法声明的所有名称和被调用方法的所有名称,但是我想知道哪个方法调用哪个方法。例如,我想看到方法
m1
调用方法
mA
mB
,而方法
m2
调用方法
mC
mD
,等等

[编辑2011年11月9日IDB,将新手的扩展评论抄写回原始问题正文。我希望我抄写正确。我希望作者回来并根据需要进行修改]:

我的问题似乎是(Eclipse的)MethodDeclaration api没有要调用的GetInvokedMethodName函数。这是我的密码:

 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() ); }
公共类MethodVisitor扩展ASTVisitor{
列表方法=新的ArrayList();
@重写公共布尔访问(MethodDeclaration节点){
方法:添加(节点);
return super.visit(node);}
公共列表getMethods()
{返回方法;}
List methods1=新的ArrayList();
@覆盖公共布尔访问(MethodInvocation节点)
{methods1.add(节点);
return super.visit(node);}
公共列表getMethods1()
{返回方法1;}
} 
...
for(MethodDeclaration方法:visitor.getMethods())
{System.out.println(“方法名:”+Method.getName()
+“返回类型:”+method.getReturnType2()
+是构造函数:“+method.isConstructor()
+“调用的方法:”+ASTNode.Method\u调用);
); }
for(MethodInvocation method1:visitor.getMethods1())
{System.out.println(“调用的方法名:+method1.getName());}

如果您想知道m1调用了哪一个特定的方法mB(在您庞大的类数组中所有名为“mB”的方法中),您需要的不仅仅是AST。您需要一个完整的符号表,该表将每个符号的使用绑定到与之匹配的可能定义

计算这样一个符号表的过程对于许多语言来说都很困难,对于Java来说也很困难(但没有C++那么糟糕)。必须有人对如何在(本地)作用域、继承、重载、隐含强制转换等方面查找标识符的规则进行编码,Java参考手册的大部分内容都试图解释这一点。你不想自己做这件事

对于要检查的每个方法,您真正需要的是一个完整的Java前端,它同时具有AST和相应的符号表。我认为,您可以从(Sun?)Java编译器的接口(我个人不知道如何做到这一点)、Jikes编译器、EclipseJavaAST(?)模块以及诸如我们的。另一种方法是使用JVM指令都使用符号表构建的advantage处理类文件,这些类文件包含JVM形式的方法调用


如果要计算m1调用,请调用mA调用mQ调用。。。。mZ,您需要一个能够同时读入整个源代码库的工具。编译器不会为您这样做,但您可以使用Eclipse或我们的前端来实现这一点。

我也遇到了同样的问题。这是我的解决方案:

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);
            }

        });
最终HashMap调用格式方法=
新的HashMap();
CompilationUnit cu=(CompilationUnit)ap.createAST(null);
cu.接受(新的ASTVisitor(){
私有方法;
@凌驾
公共布尔访问(MethodDeclaration节点){
activeMethod=node;
返回超级访问(节点);
}
@凌驾
公共布尔访问(MethodInvocation节点){
if(invocationsForMethods.get(activeMethod)==null){
put(activeMethod,newArrayList());
}
获取(activeMethod).add(node);
返回超级访问(节点);
}
});

现在,您可以要求
invocationsForMethods.keySet()
获取所使用的
AST
invocationsForMethods.get(key)
为作为键给出的声明返回所有方法调用。

Spyros:您作为问题背景提供的附加信息,应该真正添加到问题本身。在将代码块分解成注释大小的片段之后,应该很明显,它基本上是不可读的。很可能其他阅读我答案的人会跳过这些评论,而错过额外的评论。你可以编辑你的问题;请参见问题下方的**编辑**“按钮”。我冒昧地将您添加的评论移动到您的问题中(排名很高,用户可以这样做),以帮助您。要完成此清理,可以删除这些注释。