0

我有一段代码:

typedef struct S1{
 int a;
 int b; 
} S, *PS;

我可以通过 clang-check 获得以下 AST:

| |-CXRecordDecl 0x3dfde48 col:16 隐式结构 S1 | |-FieldDecl 0x3dfdef8 col:9 'int' | -FieldDecl 0x3dfdf58 <line:4:5, col:9> col:9 b 'int' |-TypedefDecl 0x3dfe010 <line:1:1, line:5:3> col:3 S 'struct S1':'struct S1' |-ElaboratedType 0x3dfdfc0 'struct S1' 糖 | -RecordType 0x3dfddc0 'struct S1' |-CXRecord 0x3dfdd28 'S1' -TypedefDecl 0x3dfe0f0 <line:1:1, line:5:7> col:7 PS 'struct S1 *' -PointerType 0x3dfe0a0 'struct S1 *' -ElaboratedType 0x3dfdfc0 'struct S1' sugar -RecordType 0x3dfddc0 'struct S1' `-CXRecord 0x3dfdd28 'S1'

如果我使用 typedefDecl(),我可以匹配 S 和 PS,但是我怎样才能得到底层的 cxxRecordDecl() 呢?

4

1 回答 1

1

typedefDecl一种方法是使用遍历匹配器来限定。第一跳是到 typedef 的类型,第二跳是到该类型的声明。这在您正在寻找的 cxxRecordDecl 中终止。

typedefDecl(
  hasType(
    hasDeclaration(
      cxxRecordDecl().bind("the_struct")
))).bind("the_typedef")

这可行,但它(至少)有两个问题。首先,它还匹配您可能不想匹配的内容,其次,它无法匹配代码中的指针 typedef 声明。要查看第一个问题,请在clang-query. 将您的片段放入 test_input_struct_type.cpp:

$ clang-query test_input_struct_type.cpp --
clang-query> let m1 typedefDecl( hasType( hasDeclaration(cxxRecordDecl().bind("the_struct"))))
clang-query> m m1

Match #1:


Match #2:

test_input_struct_type.cpp:1:1: note: "root" binds here
typedef struct S1{
^~~~~~~~~~~~~~~~~~
test_input_struct_type.cpp:1:9: note: "the_struct" binds here
typedef struct S1{
        ^~~~~~~~~~
test_input_struct_type.cpp:1:1: note: "the_typedef" binds here
typedef struct S1{
^~~~~~~~~~~~~~~~~~
2 matches.

第 2 场比赛看起来不错,但第 1 场比赛是什么?我怀疑 matcher 正在命中一些 typedef 节点,这些节点似乎是由编译器在翻译单元的 AST 开头插入的。

解决第一个问题的一种方法是添加更多特异性:

typedefDecl(
  hasType(
    elaboratedType(
      namesType(
        recordType(
          hasDeclaration(
            cxxRecordDecl().bind("the_struct")
))))).bind("the_typedef")

回到clang-query

clang-query> let m2  typedefDecl(hasType(elaboratedType( namesType( recordType( hasDeclaration(cxxRecordDecl().bind("the_struct")))) ))).bind("the_typedef")
clang-query> m m2

Match #1:

test_input_struct_type.cpp:1:1: note: "root" binds here
typedef struct S1{
^~~~~~~~~~~~~~~~~~
test_input_struct_type.cpp:1:9: note: "the_struct" binds here
typedef struct S1{
        ^~~~~~~~~~
test_input_struct_type.cpp:1:1: note: "the_typedef" binds here
typedef struct S1{
^~~~~~~~~~~~~~~~~~
1 match.

第二个问题——找到指针 typedef 呢?这需要一个稍微不同的匹配器:

typedefDecl(
  hasType(
    pointerType(
      pointee(
        hasDeclaration(
          cxxRecordDecl().bind("pointee_struct")
))))).bind("the_typedef")   

然后可以使用 组合这两个匹配器anyOf。回到clang-query

clang-query> let m2a hasType(elaboratedType( namesType( recordType( hasDeclaration(cxxRecordDecl().bind("the_struct"))))))
clang-query> let m3a hasType(pointerType( pointee( hasDeclaration(cxxRecordDecl().bind("pointee_struct")))))
clang-query> let m4 typedefDecl( anyOf(m2a,m3a)).bind("the_typedef")
clang-query> m m4

Match #1:

test_input_struct_type.cpp:1:1: note: "root" binds here
typedef struct S1{
^~~~~~~~~~~~~~~~~~
test_input_struct_type.cpp:1:9: note: "the_struct" binds here
typedef struct S1{
        ^~~~~~~~~~
test_input_struct_type.cpp:1:1: note: "the_typedef" binds here
typedef struct S1{
^~~~~~~~~~~~~~~~~~

Match #2:

test_input_struct_type.cpp:1:9: note: "pointee_struct" binds here
typedef struct S1{
        ^~~~~~~~~~
test_input_struct_type.cpp:1:1: note: "root" binds here
typedef struct S1{
^~~~~~~~~~~~~~~~~~
test_input_struct_type.cpp:1:1: note: "the_typedef" binds here
typedef struct S1{
^~~~~~~~~~~~~~~~~~
2 matches.
于 2017-12-07T14:17:30.557 回答