确定 CXXMethodDecl 是否被实例化

Determine if a CXXMethodDecl is instantiated or not

我正在编写一个遍历 clang AST 并以特定格式打印出来的工具,但我不想打印函数模板,只是打印它们的(完整)专业化。我想知道如何确定 const CXXMethodDecl* 是否代表完全实例化的方法(它不是模板化的或者它是模板化方法的完整实例化)或未完全实例化的方法。这是我使用我的工具看到的示例:

template <typename Z>
class P
{
    int lookup ();
};

template <typename Z>
int P<Z>::lookup ()
{
    return Z::f();
}

struct X {
    static int f();
};

template class P<X>;

构造以下 AST。我不想看到第一个 CXXRecordDecl,因为它没有完全实例化,但我确实想看到第二个(已完全实例化)。

|-ClassTemplateDecl 0x3eff5b8 <minimal.cpp:1:1, line:5:1> line:2:7 Pte
| |-TemplateTypeParmDecl 0x3eff480 <line:1:11, col:20> col:20 typename depth 0 index 0 PTT
| |-CXXRecordDecl 0x3eff530 <line:2:1, line:5:1> line:2:7 class Pte definition
| | |-DefinitionData empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init
| | | |-DefaultConstructor exists trivial constexpr needs_implicit defaulted_is_constexpr
| | | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param
| | | |-MoveConstructor exists simple trivial needs_implicit
| | | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param
| | | |-MoveAssignment exists simple trivial needs_implicit
| | | `-Destructor simple irrelevant trivial needs_implicit
| | |-CXXRecordDecl 0x3eff800 <col:1, col:7> col:7 implicit class Pte
| | `-CXXMethodDecl 0x3eff910 <line:4:5, col:17> col:9 lookup 'int ()'
| `-ClassTemplateSpecialization 0x3f00010 'Pte'
|-CXXMethodDecl 0x3effbb0 parent 0x3eff530 prev 0x3eff910 <line:7:1, line:11:1> line:8:15 lookup 'int ()'
  ^^^^^^^^^^^^^^^^^^^^^^^^^^ I DO NOT WANT TO SEE THIS
| `-CompoundStmt 0x3effd50 <line:9:1, line:11:1>
|   `-ReturnStmt 0x3effd40 <line:10:5, col:19>
|     `-CallExpr 0x3effd20 <col:12, col:19> '<dependent type>'
|       `-CXXDependentScopeMemberExpr 0x3effcd8 <col:12, col:17> '<dependent type>' lvalue ->f
|-CXXRecordDecl 0x3effd68 <line:13:1, line:15:1> line:13:8 referenced struct X definition
| |-DefinitionData pass_in_registers empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init
| | |-DefaultConstructor exists trivial constexpr needs_implicit defaulted_is_constexpr
| | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param
| | |-MoveConstructor exists simple trivial needs_implicit
| | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param
| | |-MoveAssignment exists simple trivial needs_implicit
| | `-Destructor simple irrelevant trivial needs_implicit
| |-CXXRecordDecl 0x3effe78 <col:1, col:8> col:8 implicit struct X
| `-CXXMethodDecl 0x3efff50 <line:14:5, col:18> col:16 used f 'int ()' static
`-ClassTemplateSpecializationDecl 0x3f00010 <line:17:1, col:21> col:16 class Pte definition
  |-DefinitionData pass_in_registers empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init
  | |-DefaultConstructor exists trivial constexpr needs_implicit defaulted_is_constexpr
  | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param
  | |-MoveConstructor exists simple trivial needs_implicit
  | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param
  | |-MoveAssignment exists simple trivial needs_implicit
  | `-Destructor simple irrelevant trivial needs_implicit
  |-TemplateArgument type 'X'
  |-CXXRecordDecl 0x3f001f8 prev 0x3f00010 <line:2:1, col:7> col:7 implicit class Pte
  `-CXXMethodDecl 0x3f00280 <line:8:1, line:11:1> line:4:9 lookup 'int ()'
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ I want to see this
    `-CompoundStmt 0x3f2e1b0 <line:9:1, line:11:1>
      `-ReturnStmt 0x3f2e1a0 <line:10:5, col:19>
        `-CallExpr 0x3f2e180 <col:12, col:19> 'int'
          `-ImplicitCastExpr 0x3f2e168 <col:12, col:17> 'int (*)()' <FunctionToPointerDecay>
            `-DeclRefExpr 0x3f2e110 <col:12, col:17> 'int ()' lvalue CXXMethod 0x3efff50 'f' 'int ()'

每当在模板中声明 type/function/variable 或者是模板时,clang 将其称为 依赖上下文 。您可能已经在模板中的 AST 节点周围看到 dependent 这个词。

我已经修改了您的原始测试用例以在非模板类型中包含模板化方法:

template <typename Z>
class P
{
    int lookup ();
};

template <typename Z>
int P<Z>::lookup ()
{
    return Z::f();
}

struct X {
    static int f() { return 42; }
};

struct Y {
    template <typename Z>
    int foo() { return Z::f(); }
};

template class P<X>;

这是一个非常简单的递归 AST 访问器,它只打印出您感兴趣的函数:

class NonDependentMethodVisitor
    : public clang::ASTConsumer,
      public clang::RecursiveASTVisitor<NonDependentMethodVisitor> {
public:
  void HandleTranslationUnit(clang::ASTContext &Context) {
    this->TraverseTranslationUnitDecl(Context.getTranslationUnitDecl());
  }

  bool shouldVisitTemplateInstantiations() const { return true; }

  bool VisitCXXMethodDecl(clang::CXXMethodDecl *MD) {
    if (!MD->isDependentContext()) {
      MD->dump();
    }

    return true;
  }
};

这会为测试片段生成以下输出:

CXXMethodDecl 0x384eda0 <$TEST_DIR/test.cpp:14:5, col:33> col:16 used f 'int ()' static
`-CompoundStmt 0x384ee80 <col:20, col:33>
  `-ReturnStmt 0x384ee70 <col:22, col:29>
    `-IntegerLiteral 0x384ee50 <col:29> 'int' 42
CXXMethodDecl 0x387e170 <$TEST_DIR/test.cpp:8:1, line:11:1> line:4:9 lookup 'int ()'
`-CompoundStmt 0x387e450 <line:9:1, line:11:1>
  `-ReturnStmt 0x387e440 <line:10:5, col:17>
    `-CallExpr 0x387e420 <col:12, col:17> 'int'
      `-ImplicitCastExpr 0x387e408 <col:12, col:15> 'int (*)()' <FunctionToPointerDecay>
        `-DeclRefExpr 0x387e3b0 <col:12, col:15> 'int ()' lvalue CXXMethod 0x384eda0 'f' 'int ()'

希望这能回答您的问题!