【发布时间】:2021-12-19 13:19:16
【问题描述】:
我正在开发一个程序,该程序使用来自 ANTLRs github 的 Java9 词法分析器和语法来解析 Java 文件。解析文件时,我想将每个方法名称以及在该方法中调用的所有方法的名称保存在 HashMap<String, Set<String>> 中。
我使用侦听器模式,其中我使用方法 exitMethodDeclaration 来获取方法名称和 exitMethodInvocation 来获取方法调用。问题是这两种方法是在解析树的不同节点上调用的,因此它们将不同的上下文作为参数。因此,据我所知,我无法调用该方法来获取 exitMethodDeclaration 中的调用。我尝试构建自己的递归,这样我就可以通过将 methodDeclarationContext 作为参数传递给 exitMethodInvocation 来解决类型问题。不过这会很复杂,我想使用 ANTLRs 功能。
使用下面的代码,每个方法的 hashSet 包含整个文件的所有方法调用,而不仅仅是特定方法。
private HashMap<String, HashSet<String>> methodCalls = new HashMap<>();
private HashSet<String> methodCallNames = new HashSet<>();
public void exitMethodDeclaration(Java9Parser.MethodDeclarationContext ctx) {
String methodName = ctx.methodHeader().methodDeclarator().identifier().getText();
methodCalls.put(methodName, methodCallNames);
}
public void exitMethodInvocation(Java9Parser.MethodInvocationContext ctx) {
try {
String m = ctx.methodName().identifier().getText();
methodCallNames.add(m);
} catch (Exception e) {
}
}
欢迎任何关于如何在同一方法中收集不同上下文类型的节点、访问侦听器/访问者方法中的子树或其他想法的想法!
【问题讨论】:
-
如果在方法
foo中有一个匿名类,并且在该匿名类中有一个调用baz的方法bar。您是否也将baz视为foo调用的方法之一? -
@Sweeper 这不是我考虑过的事情,但感谢您提出!理想情况下,我会将
baz视为foo调用的方法之一,但任何关于如何在不考虑这一点的情况下解决问题的想法也将不胜感激。 -
最容易写的是
methodInvocation_lfno_primary和methodInvocation的访问者,只要遍历父链,直到得到methodDeclarator,然后将调用的方法与方法关联起来。现在,您还需要收集没有调用的方法,因此您必须为所有methodDeclarator创建一个空的方法列表(如果不存在)。编写此代码需要 3 分钟——非常简单。效率不高,但更大的问题是你会发现 java/java9 没有优化——解析慢。 -
我不会默默地接受这样的异常:
catch (Exception e) {}。如果事情出错,你永远不知道。至少记录,或将错误打印到控制台:catch(Exception e) { e.printStackTrace(); }
标签: java parsing listener antlr4 method-invocation