我有很多代码,其中包含带有访问器和修改器函数(getter 和 setter)的类。我想确定给定的 CXXMemberDecl 是否是其中之一。我不确定是否有好的方法。我想我是否可以验证该方法是否有一个语句,并且它是否是带有类成员(访问器)返回值的 return 语句,或者是带有将传递的参数分配给类成员(变异器)的分配语句,这会起作用。谁能建议一些可以做到这一点的代码?
我将这个问题解释为 Clang AST 匹配器 它将报告 setter 和 getter。 这样的匹配器可以在以下位置进行测试 命令行使用
clang-query
。
以下 shell 脚本包含一个匹配表达式,该表达式将在 至少有一些此类功能的情况(取决于它们的具体情况) 书面)。 注释解释了每个部分的作用,所以应该是 可根据需要调整:
#!/bin/sh
PATH=/d/opt/clang+llvm-18.1.8-msvc/bin:$PATH
matcher='
cxxMethodDecl( # Report C++ method declarations
hasBody( # where the body
compoundStmt( # is a compound statement
statementCountIs(1), # with one contained statement
hasAnySubstatement( # that
anyOf( # is either:
returnStmt( # (1) a return statement
hasReturnValue( # whose return value
implicitCastExpr( # is an implicit conversion
hasSourceExpression( # of
memberExpr( # a class member
hasObjectExpression( # of the object
cxxThisExpr() # `*this`, or
)
)
)
)
)
),
binaryOperator( # (2) is a binary expression
isAssignmentOperator(), # using the assignment operator
hasLHS( # where the left-hand side
memberExpr( # is a class member
hasObjectExpression( # of the object
cxxThisExpr() # `*this`, and
)
)
),
hasRHS( # where the right-hand side
implicitCastExpr( # is an implicit conversion
hasSourceExpression( # of
declRefExpr( # a reference to a declaration
hasDeclaration( # of
parmVarDecl() # a parameter.
)
)
)
)
)
)
)
)
)
)
)
'
clang-query \
-c "m $matcher" \
test.cc --
# EOF
为了测试这个匹配器,我使用了这个测试用例:
// test.cc
// Testcases for a matcher to find accessor methods.
struct S {
int m_x;
int getX()
{
return m_x;
}
void setX(int x)
{
m_x = x;
}
};
// EOF
有这个 AST:
$ clang -fsyntax-only -Xclang -ast-dump test.cc
TranslationUnitDecl 0x23df46300a0 <<invalid sloc>> <invalid sloc>
|-CXXRecordDecl 0x23df4630900 <<invalid sloc>> <invalid sloc> implicit struct _GUID
| `-TypeVisibilityAttr 0x23df46309b0 <<invalid sloc>> Implicit Default
|-TypedefDecl 0x23df4630a28 <<invalid sloc>> <invalid sloc> implicit __int128_t '__int128'
| `-BuiltinType 0x23df4630670 '__int128'
|-TypedefDecl 0x23df4630a98 <<invalid sloc>> <invalid sloc> implicit __uint128_t 'unsigned __int128'
| `-BuiltinType 0x23df4630690 'unsigned __int128'
|-TypedefDecl 0x23df4630e40 <<invalid sloc>> <invalid sloc> implicit __NSConstantString '__NSConstantString_tag'
| `-RecordType 0x23df4630b80 '__NSConstantString_tag'
| `-CXXRecord 0x23df4630af0 '__NSConstantString_tag'
|-CXXRecordDecl 0x23df4630e98 <<invalid sloc>> <invalid sloc> implicit class type_info
| `-TypeVisibilityAttr 0x23df4630f50 <<invalid sloc>> Implicit Default
|-TypedefDecl 0x23df4630fc8 <<invalid sloc>> <invalid sloc> implicit size_t 'unsigned long long'
| `-BuiltinType 0x23df4630290 'unsigned long long'
|-TypedefDecl 0x23df466b568 <<invalid sloc>> <invalid sloc> implicit __builtin_ms_va_list 'char *'
| `-PointerType 0x23df4631020 'char *'
| `-BuiltinType 0x23df4630150 'char'
|-TypedefDecl 0x23df466b5d8 <<invalid sloc>> <invalid sloc> implicit __builtin_va_list 'char *'
| `-PointerType 0x23df4631020 'char *'
| `-BuiltinType 0x23df4630150 'char'
`-CXXRecordDecl 0x23df466b630 <test.cc:4:1, line:16:1> line:4:8 struct S definition
|-DefinitionData pass_in_registers aggregate standard_layout trivially_copyable pod trivial literal
| |-DefaultConstructor exists trivial needs_implicit
| |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param
| |-MoveConstructor exists simple trivial needs_implicit
| |-CopyAssignment simple trivial has_const_param needs_implicit implicit_has_const_param
| |-MoveAssignment exists simple trivial needs_implicit
| `-Destructor simple irrelevant trivial needs_implicit
|-CXXRecordDecl 0x23df466b748 <col:1, col:8> col:8 implicit struct S
|-FieldDecl 0x23df466b7f0 <line:5:3, col:7> col:7 referenced m_x 'int'
|-CXXMethodDecl 0x23df466b8d8 <line:7:3, line:10:3> line:7:7 getX 'int ()' implicit-inline
| `-CompoundStmt 0x23df466bba0 <line:8:3, line:10:3>
| `-ReturnStmt 0x23df466bb90 <line:9:5, col:12>
| `-ImplicitCastExpr 0x23df466bb78 <col:12> 'int' <LValueToRValue>
| `-MemberExpr 0x23df466bb48 <col:12> 'int' lvalue ->m_x 0x23df466b7f0
| `-CXXThisExpr 0x23df466bb38 <col:12> 'S *' implicit this
`-CXXMethodDecl 0x23df466ba70 <line:12:3, line:15:3> line:12:8 setX 'void (int)' implicit-inline
|-ParmVarDecl 0x23df466b998 <col:13, col:17> col:17 used x 'int'
`-CompoundStmt 0x23df466bc98 <line:13:3, line:15:3>
`-BinaryOperator 0x23df466bc78 <line:14:5, col:11> 'int' lvalue '='
|-MemberExpr 0x23df466bc10 <col:5> 'int' lvalue ->m_x 0x23df466b7f0
| `-CXXThisExpr 0x23df466bc00 <col:5> 'S *' implicit this
`-ImplicitCastExpr 0x23df466bc60 <col:11> 'int' <LValueToRValue>
`-DeclRefExpr 0x23df466bc40 <col:11> 'int' lvalue ParmVar 0x23df466b998 'x' 'int'
脚本产生以下输出:
Match #1:
$PWD\test.cc:7:3: note: "root"
binds here
7 | int getX()
| ^~~~~~~~~~
8 | {
| ~
9 | return m_x;
| ~~~~~~~~~~~
10 | }
| ~
Match #2:
$PWD\test.cc:12:3: note: "root"
binds here
12 | void setX(int x)
| ^~~~~~~~~~~~~~~~
13 | {
| ~
14 | m_x = x;
| ~~~~~~~~
15 | }
| ~
2 matches.
创建匹配器的过程基本上遵循 AST 逐行转储,将每个我想要匹配的元素变成它的 对应的匹配器。 在某些情况下,这很简单(对于 例如,
CXXMethodDecl
AST 节点与 cxxMethodDecl
匹配
matcher),而对于其他人,我必须在
匹配器参考,以及反复试验,以找到正确的
组合。