使用 ast-grep 精准匹配指定类的方法调用(以 Java 为例)
使用 ast-grep 精准匹配指定类的方法调用(以 Java 为例)
在代码重构、安全审计或静态分析的场景中,我们常常需要匹配某个特定类中定义的方法调用。而 ast-grep 作为一款基于语法树的代码搜索工具,提供了强大的模式匹配功能,可以帮助我们高效实现这一目标。
本文将以 Java 为例,介绍如何使用 ast-grep
匹配一个给定类的实例所调用的特定方法。我们的问题是:如何只匹配 Class_A
类型对象上调用的 add()
方法,而不误匹配其它类的 add()
方法?
问题示例
考虑下面的 Java 代码片段:
class Class_A {public Class_A(int a, int b) {}public int add() {return this.a + this.b;}
}Class_A aaaa = new Class_A(foo, bar);
Object bbbb = new Object();print(aaaa.add());
bbbb.add();
我们的目标是仅匹配 print(aaaa.add());
,而不匹配 bbbb.add();
,因为后者并非调用 Class_A
的方法。
ast-grep 基础规则回顾
在 ast-grep 中,我们可以使用 YAML 编写规则,对语法结构进行匹配。例如:
rule:pattern: $VARNAME.add()
但这会匹配所有调用 add()
的代码行,无论对象是哪个类的实例。
加入上下文约束:inside
+ has
为了解决这个问题,我们需要添加上下文限制:
- 目标调用必须出现在一个作用域中
- 该作用域中要有对象是由
Class_A
创建的
完整规则如下:
rule:pattern: $VARNAME.add()inside:pattern: $DBstopBy: endhas:pattern: $TY $VARNAME = new Class_A($$$CARGS)
解释:
pattern: $VARNAME.add()
:匹配任何调用add()
方法的表达式,并将调用对象赋值给$VARNAME
inside: pattern: $DB
:该调用要出现在某个作用域(例如代码块)中has: pattern: $TY $VARNAME = new Class_A(...)
:这个作用域中,必须有$VARNAME
是通过new Class_A(...)
初始化的stopBy: end
:防止向上搜索超出当前代码块
实际效果
应用该规则后:
- ✅ 匹配到:
print(aaaa.add());
- ❌ 不匹配:
bbbb.add();
(因为bbbb
是Object
类型)
小结与提示
通过 ast-grep 的 YAML 配置语言,我们可以实现复杂的语法结构匹配,而不仅仅是文本替换。
如果你也有类似的需求,比如:
- 只匹配某个类的构造函数
- 检查 API 使用是否符合约定
- 对某一类实例调用方法进行重构或审计
那么不妨尝试用 pattern + inside + has
的组合方式,实现精确的匹配。
延伸阅读
- 官方文档:https://ast-grep.github.io/
- 规则配置指南:https://ast-grep.github.io/guide/rule-config.html
欢迎在评论区分享你对 ast-grep 的使用经验和问题,一起交流更高效的代码分析技巧!
想要深入讨论?我正在「不宽也不深」和朋友们讨论有趣的话题,你⼀起来吧?
https://t.zsxq.com/oFMwJ