我正在编写一个简单的程序,用于分析方法体(用Java 7编写)并列出它所具有的所有方法调用。
对于初学者,我希望能够检测对静态方法的调用,对局部变量和类成员变量的调用:
class TestSubject {
String m;
void alpha() {
String l;
l.charAt(0); // local
m.contains(""); // member
String.valueOf(0); // static
bravo().valueOf(0); // local on method
}
String bravo() {
return "";
}
}
方法调用通常看起来像foo.bar()。我目前正在努力匹配这种模式。这是语法的(相关)部分,应该用来描述以下内容:
expression
: primary
| expression '.' Identifier
| expression '(' expressionList? ')'
- 这个语法如何生成看起来像'foo.bar()'的东西?毕竟,唯一被允许的事情之后的'。'是标识符。语法的哪一部分描述了'.'后面的'bar()' ?关键是:匹配方法调用的最佳方式是什么?
目前我有一些东西:
@Override
public void enterExpression(@NotNull JavaParser.ExpressionContext ctx) {
if(ctx.expression() != null && ctx.expression().size() == 1 && right(ctx) != null){
// This is something that may be a method invocation
}
}
捕获静态调用,但这显然是弱的…
我已经有了一个符号表(类成员变量、方法局部变量和方法参数的哈希)。我的问题是匹配方法调用。我很难理解Java是如何。g4语法生成方法+获得形式为x.y()
的表达式的最佳方式是什么(稍后我将进行必要的解释)
是的,表达式规则应该是正确的规则,但很难看出它如何匹配。
最好的建议是将print语句/断点添加到enterEveryRule &exitEveryRule方法,并解析和遍历一个最小的源代码示例。这将显示匹配的确切路径。
查看github.com/antlr/antlr4/tree/master/tool/test/org/antlr/v4/test获取如何快速测试运行的示例——BaseTest.java使测试代码片段变得容易。
不幸的是,您不能仅仅根据语法/解析树来区分静态方法调用和实例方法调用。例如,给定以下声明:
public class MyClass {
public static void method(){};
}
则以下两个调用都是静态方法调用:
MyClass.method(); // static method call
MyClass m = new MyClass();
m.method(); // static method call!!
要可靠地区分静态和实例方法调用,需要:
分析正在调用其方法的类,找出哪些方法是静态的,哪些不是。
分析调用以确定在
.
之前是否有表达式或类型名称。如果您有类型名称,那么方法必须是
static
。如果你有一个表达式你需要确定表达式的类型
给定表达式类型,并且给定该类型是类,您需要执行方法签名匹配以确定最佳匹配
最后,查看匹配的方法是否为
static
。
这里有Antlr4语法的参考实现:https://github.com/antlr/grammars-v4/tree/master/java
-
这个语法如何生成看起来像'foo.bar()'的东西?毕竟,唯一被允许的事情之后的'。'是标识符。语法的哪一部分描述了'.'后面的'bar()' ?
如果你看这行:
expression : primary | expression '.' Identifier // ... | expression '(' expressionList? ')' #FunctionInvocation // <-- this is the line that catches all function invocations
你会看到
foo.bar
是一个expression
。foo.bar
(
)
也是一个表达式 -
切中要害:匹配方法调用的最佳方式是什么?