使用 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