如何使用 Clang AST 匹配器查找 setter 和 getter 方法? [已关闭]

问题描述 投票:0回答:1

我想使用以下方法在代码库中查找 setter 和 getter 方法 Clang AST 匹配器 表达。 例如,这段代码有一个 getter 和一个 setter 报告:

struct S {
  int m_x;

  int getX()                 // getter
  {
    return m_x;
  }

  void setX(int x)           // setter
  {
    m_x = x;
  }
};

对于这两种方法,我想检查主体是否有一个 陈述。 getter 主体应该是带有 return 的 return 语句 班级成员的价值。 setter 主体应该是一个赋值 将传递的参数分配给类成员的语句。 (这 在实践中可能不是一套足够宽容的标准,但我会 对此作为第一个近似值感到满意。)

我发现我可以使用

cxxMethodDecl
匹配器来查找所有方法, 但目前尚不清楚如何挖掘尸体或检查各种 特性。 文档中的示例(上面链接)都没有 这;最接近的似乎是例子:

cxxConstructorDecl(
  isCopyConstructor()
  ).bind("prepend_explicit")

但这似乎依赖于原始匹配器的存在

isCopyConstructor
对方法体进行分类(或者可能只是它的 签名?该文档没有说明它们实际上做了什么), 并且没有
isSetter
或类似的。

如何编写匹配表达式来查找所有 setter 和 getter 在翻译单位?

c++ clang abstract-syntax-tree clang-ast-matchers
1个回答
0
投票

我将这个问题解释为 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),而对于其他人,我必须在 匹配器参考,以及反复试验,以找到正确的 组合。

© www.soinside.com 2019 - 2024. All rights reserved.