C++ 使用clang AST Matcher匹配私有类成员

C++ 使用clang AST Matcher匹配私有类成员,c++,clang,static-analysis,abstract-syntax-tree,C++,Clang,Static Analysis,Abstract Syntax Tree,我正在编写一个Clang工具来静态分析源文件,并匹配和重命名类的所有私有成员 举个例子: class AClass{//问题:我的匹配器也在这里修改AST节点 私人: int a;//a=1;//正如您所观察到的,问题是由隐式定义的副本引起的 构造函数。这是AST的转储 % clang-check -ast-dump -ast-dump-filter=AClass s.cpp -- Dumping AClass: CXXRecordDecl 0x2cb3700 </tmp/s.cpp:1:

我正在编写一个Clang工具来静态分析源文件,并匹配和重命名类的所有私有成员

举个例子:

class AClass{//问题:我的匹配器也在这里修改AST节点
私人:

int a;//a=1;//正如您所观察到的,问题是由隐式定义的副本引起的 构造函数。这是AST的转储

% clang-check -ast-dump -ast-dump-filter=AClass s.cpp --
Dumping AClass:
CXXRecordDecl 0x2cb3700 </tmp/s.cpp:1:1, line:10:1> line:1:7 referenced class AClass definition
|-CXXRecordDecl 0x2cb3810 <col:1, col:7> col:7 implicit referenced class AClass
|-AccessSpecDecl 0x2cb38a0 <line:2:1, col:8> col:1 private
|-FieldDecl 0x2cb38e0 <line:3:3, col:7> col:7 referenced a 'int'
|-AccessSpecDecl 0x2cb3930 <line:4:1, col:7> col:1 public
|-CXXConstructorDecl 0x2cfaee0 <line:5:3, line:9:3> line:5:3 used AClass 'void (void)'
| `-CompoundStmt 0x2cfb440 <col:12, line:9:3>
|   |-DeclStmt 0x2cfb240 <line:6:5, col:14>
|   | `-VarDecl 0x2cfafe0 <col:5, col:12> col:12 used cl 'class AClass' callinit
|   |   `-CXXConstructExpr 0x2cfb210 <col:12> 'class AClass' 'void (void)'
|   |-BinaryOperator 0x2cfb2c0 <line:7:5, col:15> 'int' lvalue '='
|   | |-MemberExpr 0x2cfb270 <col:5, col:11> 'int' lvalue ->a 0x2cb38e0
|   | | `-CXXThisExpr 0x2cfb258 <col:5> 'class AClass *' this
|   | `-IntegerLiteral 0x2cfb2a0 <col:15> 'int' 1
|   `-BinaryOperator 0x2cfb360 <line:8:5, col:12> 'int' lvalue '='
|     |-MemberExpr 0x2cfb310 <col:5, col:8> 'int' lvalue .a 0x2cb38e0
|     | `-DeclRefExpr 0x2cfb2e8 <col:5> 'class AClass' lvalue Var 0x2cfafe0 'cl' 'class AClass'
|     `-IntegerLiteral 0x2cfb340 <col:12> 'int' 2
|-CXXConstructorDecl 0x2cfb070 <line:1:7> col:7 implicit used AClass 'void (const class AClass &) throw()' inline
| |-ParmVarDecl 0x2cfb1b0 <col:7> col:7 used 'const class AClass &'
| |-CXXCtorInitializer Field 0x2cb38e0 'a' 'int'
| | `-ImplicitCastExpr 0x2cfb9e0 <col:7> 'int' <LValueToRValue>
| |   `-MemberExpr 0x2cfb998 <col:7> 'const int' lvalue .a 0x2cb38e0
| |     `-DeclRefExpr 0x2cfb970 <col:7> 'const class AClass' lvalue ParmVar 0x2cfb1b0 '' 'const class AClass &'
| `-CompoundStmt 0x2cfba28 <col:7>
`-CXXDestructorDecl 0x2cfb770 <col:7> col:7 implicit used ~AClass 'void (void) throw()' inline
  `-CompoundStmt 0x2cfb890 <col:7>
这就给你留下了你想要的火柴

Match #1:

/tmp/s.cpp:7:5: note: "root" binds here
    this->a = 1; // <- rename this 'a'
    ^~~~~~~

Match #2:

/tmp/s.cpp:8:5: note: "root" binds here
    cl.a = 2;    // <- rename this 'a'
    ^~~~
2 matches.
匹配#1:
/tmp/s.cpp:7:5:注意:“根”绑定在这里

this->a=1;//这可能是clang提供给隐式定义的复制构造函数的位置吗?我不熟悉clang是如何实现的,但我熟悉类似的工具。一种常见的方法是让隐式声明/定义的函数占据构造函数的位置。也许你可以在封闭函数n上添加一个过滤器是否隐式定义?@RichardCorden,我尝试使用
memberExpr(hasddeclaration(namedDecl(isPrivate(),除非(isImplicit()))
匹配表达式,它没有任何影响。我对Clang API一点也不熟悉。你不想问
a
是否是隐式的,你想问包含表达式的函数是否是隐式定义的。你能得到这些信息吗?测试我理论的一种方法是显式定义复制构造函数。如果你不再r在源文件的第1行找到一个匹配项,然后显示它一直是复制构造函数的位置。你是对的。如果复制构造函数被显式定义,第三个匹配项将消失。嘿,我目前正在尝试做类似的事情,我对llvm/clang是完全陌生的-你能为我提供一个到你的项目的链接吗,或者告诉我告诉我你一开始是如何匹配成员的?我目前正在匹配fieldDecl(hasConsentor(cxRecordDecl()),但不知道这在所有情况下是否都是安全的。。。
% clang-check -ast-dump -ast-dump-filter=AClass s.cpp --
Dumping AClass:
CXXRecordDecl 0x2cb3700 </tmp/s.cpp:1:1, line:10:1> line:1:7 referenced class AClass definition
|-CXXRecordDecl 0x2cb3810 <col:1, col:7> col:7 implicit referenced class AClass
|-AccessSpecDecl 0x2cb38a0 <line:2:1, col:8> col:1 private
|-FieldDecl 0x2cb38e0 <line:3:3, col:7> col:7 referenced a 'int'
|-AccessSpecDecl 0x2cb3930 <line:4:1, col:7> col:1 public
|-CXXConstructorDecl 0x2cfaee0 <line:5:3, line:9:3> line:5:3 used AClass 'void (void)'
| `-CompoundStmt 0x2cfb440 <col:12, line:9:3>
|   |-DeclStmt 0x2cfb240 <line:6:5, col:14>
|   | `-VarDecl 0x2cfafe0 <col:5, col:12> col:12 used cl 'class AClass' callinit
|   |   `-CXXConstructExpr 0x2cfb210 <col:12> 'class AClass' 'void (void)'
|   |-BinaryOperator 0x2cfb2c0 <line:7:5, col:15> 'int' lvalue '='
|   | |-MemberExpr 0x2cfb270 <col:5, col:11> 'int' lvalue ->a 0x2cb38e0
|   | | `-CXXThisExpr 0x2cfb258 <col:5> 'class AClass *' this
|   | `-IntegerLiteral 0x2cfb2a0 <col:15> 'int' 1
|   `-BinaryOperator 0x2cfb360 <line:8:5, col:12> 'int' lvalue '='
|     |-MemberExpr 0x2cfb310 <col:5, col:8> 'int' lvalue .a 0x2cb38e0
|     | `-DeclRefExpr 0x2cfb2e8 <col:5> 'class AClass' lvalue Var 0x2cfafe0 'cl' 'class AClass'
|     `-IntegerLiteral 0x2cfb340 <col:12> 'int' 2
|-CXXConstructorDecl 0x2cfb070 <line:1:7> col:7 implicit used AClass 'void (const class AClass &) throw()' inline
| |-ParmVarDecl 0x2cfb1b0 <col:7> col:7 used 'const class AClass &'
| |-CXXCtorInitializer Field 0x2cb38e0 'a' 'int'
| | `-ImplicitCastExpr 0x2cfb9e0 <col:7> 'int' <LValueToRValue>
| |   `-MemberExpr 0x2cfb998 <col:7> 'const int' lvalue .a 0x2cb38e0
| |     `-DeclRefExpr 0x2cfb970 <col:7> 'const class AClass' lvalue ParmVar 0x2cfb1b0 '' 'const class AClass &'
| `-CompoundStmt 0x2cfba28 <col:7>
`-CXXDestructorDecl 0x2cfb770 <col:7> col:7 implicit used ~AClass 'void (void) throw()' inline
  `-CompoundStmt 0x2cfb890 <col:7>
match memberExpr(hasDeclaration(namedDecl(isPrivate())),
                 unless(hasAncestor(isImplicit())))
Match #1:

/tmp/s.cpp:7:5: note: "root" binds here
    this->a = 1; // <- rename this 'a'
    ^~~~~~~

Match #2:

/tmp/s.cpp:8:5: note: "root" binds here
    cl.a = 2;    // <- rename this 'a'
    ^~~~
2 matches.