如何从 typedefDecl 获取底层 cxxRecordDecl

How to get underly cxxRecordDecl from typedefDecl

我有一段代码:

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

我可以通过 clang-check 来跟踪 AST:

| |-CXXRecordDecl 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' |-CXXRecord 0x3dfdd28 'S1' -TypedefDecl 0x3dfe0f0 <line:1:1, line:5:7> col:7 PS 'struct S1 *' -指针类型 0x3dfe0a0 'struct S1 *' -ElaboratedType 0x3dfdfc0 'struct S1' sugar -记录类型 0x3dfddc0 'struct S1' `-CXXRecord 0x3dfdd28 'S1'

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

一种方法是使用遍历匹配器来限定 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 场比赛是什么?我怀疑匹配器正在命中一些 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.