分析方法内部的变量。JavaParser/ANTLR还是其他什么?

分析方法内部的变量。JavaParser/ANTLR还是其他什么?,java,parsing,variables,reflection,antlr,Java,Parsing,Variables,Reflection,Antlr,我正在编写一个java代码分析片段,它将找出方法中变量的用法。(具体来说,在一个方法中读取和写入全局类变量的次数)。这可以使用JavaParser完成吗?有人有其他建议吗?有人知道类度量是如何计算的吗?它们可能处理类似的事情。要完成查找变量用法的任务,带有ANTLR的解析器buld也应该生成AST。我几乎肯定你能找到现成的AST生成器,但不知道在哪里 另一种方法是使用或其他类文件分析器分析类文件。我认为这更容易,而且会更快。此外,它还适用于其他jvm语言(如Scala)。要询问变量读取是否为“全

我正在编写一个java代码分析片段,它将找出方法中变量的用法。(具体来说,在一个方法中读取和写入全局类变量的次数)。这可以使用JavaParser完成吗?有人有其他建议吗?有人知道类度量是如何计算的吗?它们可能处理类似的事情。

要完成查找变量用法的任务,带有ANTLR的解析器buld也应该生成AST。我几乎肯定你能找到现成的AST生成器,但不知道在哪里


另一种方法是使用或其他类文件分析器分析类文件。我认为这更容易,而且会更快。此外,它还适用于其他jvm语言(如Scala)。

要询问变量读取是否为“全局”,您需要一个完整的Java编译器前端,用于解析代码、构建符号表和相关类型信息

如果编译器已经在类文件中实际记录了这些信息,那么您可以执行“反射”操作来获取这些信息。如果此类信息存在于.class文件中,则可以使用类文件字节码处理器(如Kaigorodov的回答中所述)访问它

ANTLR有一个Java语法,但我不相信对符号表构造有任何支持。 你自己不能假装这一点;Java的规则太复杂了。您可能可以扩展ANTLR解析器来实现这一点,但这需要大量的工作;“Java的规则太复杂了”

我知道Java编译器提供了对其内部结构的某种名称/类型准确的访问;你也许可以用这个


我们的DMS软件再工程工具包具有完整的Java解析器,具有名称和类型解析,可用于此目的。

谢谢各位。您的两个答案都引导我使用JAVAPARSER中的AST实现来解决这个问题。这里有一段代码片段可以帮助其他人

class CatchNameExpr extends VoidVisitorAdapter {
    HashMap<String, ArrayList<Integer>> variableLineNumMap;``
    ArrayList<String> variableList;
    boolean functionParsing = false;
    public CatchNameExpr(ArrayList<String> classVariables) {
        variableList=classVariables;
    }
    public void visit(MethodDeclaration method, Object arg) {
        System.out.println("---------------");
        System.out.println(method.getName());
        System.out.println("---------------");
        variableLineNumMap = new HashMap<String, ArrayList<Integer>>();
        System.out.println();
        functionParsing = true;
        visit(method.getBody(),arg);
        // Analyze lines for variable usage. Add to list of vars after checking if its read or written or unknown.

        functionParsing = false;
    }

    public void visit(NameExpr n, Object arg) {

        if(!functionParsing)
            return;
        //TODO: check if this var was declared above it, as a local var to the func. if yes, return
        ArrayList<Integer> setOfLineNum;

        System.out.println(n.getBeginLine()+" NameExpr " + n.getName());

        if(!variableList.contains(n.getName()) || n.getName().length()==0)
            return;
        if (!variableLineNumMap.containsKey(n.getName()))
        {
            setOfLineNum =   new ArrayList<Integer>();
            setOfLineNum.add(n.getBeginLine());
            variableLineNumMap.put(n.getName(), setOfLineNum);
        }
        else
        {
            setOfLineNum = variableLineNumMap.get(n.getName());
            setOfLineNum.add(n.getBeginLine());
            variableLineNumMap.put(n.getName(), setOfLineNum);

        }
    }
}
以类似的方式,您可以访问AST以获取以下表达式、语句、条件等

我很清楚字节码处理器将更加高效,并且将比我所希望的做得更好。但考虑到时间限制,这个选项最适合我

谢谢各位,
Jasmete

现在您已经使用它了,您能告诉我您是否有权访问某种类型的
表达式
CatchNameExpr nameExp = new CatchNameExpr(classVariables);
        nameExp.visit(classCompilationUnit, null);