【发布时间】:2015-03-16 21:27:09
【问题描述】:
我正在编写一个 Clang 工具来静态分析源文件,并匹配和重命名类的所有私有成员。
考虑一个例子:
class AClass { // problem: my matcher modifies AST node here too
private:
int a; // <- I know how to rename this 'a' using other matcher
public:
AClass() {
AClass cl;
this->a = 1; // <- rename this 'a'
cl.a = 2; // <- rename this 'a'
}
};
void bar(AClass);
void foo() {
//bar(AClass());
}
我使用以下匹配器来访问我想要修改的 AST 节点。它按我的预期工作。
clang-query> match memberExpr(hasDeclaration(namedDecl(isPrivate())))
Match #1:
sum.cpp:7:9: note: "root" binds here
this->a = 1;
^~~~~~~
Match #2:
sum.cpp:8:9: note: "root" binds here
cl.a = 2;
^~~~
2 matches.
如果在示例中我取消注释带有bar(AClass()); 的行,就会出现问题。正好有一个额外的匹配项
Match #3:
sum.cpp:1:7: note: "root" binds here
class AClass {
^~~~~~
3 matches.
这会导致以一种奇怪的方式重写 class AClass 声明。我想摆脱这场比赛。
匹配器返回一个指向MemberExpr 对象的指针。我试图通过检查 isArrow() 谓词来过滤第三个匹配项,它有所帮助,但是我无法匹配带有点的表达式,例如 cl.a。
我正在寻找其他 AST 匹配器表达式或一些对 MemberExpr 对象进行操作的代码,并访问源文件中的所有私有变量,仅此而已。
【问题讨论】:
-
这可能是 clang 给隐式定义的复制构造函数的位置吗?我不熟悉 clang 是如何做到的,但我熟悉类似的工具。一种常见的方法是让隐式声明/定义的函数获取构造函数的位置。也许您可以在未隐式定义的封闭函数上添加过滤器?
-
@RichardCorden,我尝试使用
memberExpr(hasDeclaration(namedDecl(isPrivate(), unless(isImplicit()))))匹配表达式,但没有任何影响。 -
我对 Clang API 一点也不熟悉。你不想问
a是否是隐式的,你想问包含表达式的函数是否是隐式定义的。你能得到那个信息吗?检验我的理论的一种方法是显式定义复制构造函数。如果您不再在源文件的第 1 行获得匹配项,则表明它一直是复制构造函数的位置。 -
你是对的。如果显式定义了复制构造函数,则第三个匹配项将消失。
-
嘿,我目前正在尝试做一些类似的事情,并且对 llvm/clang 来说是全新的 - 你能为我提供一个你的项目的链接,或者告诉我你是如何匹配第一名?我目前正在匹配 fieldDecl(hasAncestor(cxxRecordDecl())) 但不知道这在所有情况下是否都安全......
标签: c++ clang static-analysis abstract-syntax-tree