如何从typedefDecl获取cxxRecordDecl

时间:2017-12-06 15:08:17

标签: clang-ast-matchers

我有一段代码:

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

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

| | -CXXRecordDecl 0x3dfde48 col:16隐式struct S1 | | -FieldDecl 0x3dfdef8 col:9 a&#39; int&#39; | -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&#39; struct S1&#39;糖 | -RecordType 0x3dfddc0 'struct S1' | - CXXRecord 0x3dfdd28&#39; S1&#39; -TypedefDecl 0x3dfe0f0 <line:1:1, line:5:7> col:7 PS 'struct S1 *' - PointerType 0x3dfe0a0&#39; struct S1 *&#39;     -ElaboratedType 0x3dfdfc0 'struct S1' sugar - RecordType 0x3dfddc0&#39; struct S1&#39;         `-CXXRecord 0x3dfdd28&#39; S1&#39;

如果我使用typedefDecl(),我可以匹配S和PS,但是如何获得底层cxxRecordDecl()?

1 个答案:

答案 0 :(得分:0)

一种方法是使用遍历匹配器限定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.