clangllvmclang-ast-matchers

Clang AST matching method call on class, derived class or typedef to either


I have a matcher that works perfectly for matching operator() calls on instances of a class or classes derived from that class. For example, it matches the final line of:

class MyBase { void operator()(...) {} };
MyBase b;
b(parameters);

using a matcher like:

const auto MyBaseExpr =                                                                                                                                                                                
  expr(hasType(cxxRecordDecl(isSameOrDerivedFrom("::MyBase"))));                                                                                                                                        
Finder->addMatcher(traverse(
                   TK_AsIs, cxxOperatorCallExpr(
                    hasOverloadedOperatorName("()"),
                    hasArgument(0, anyOf(MyBaseExpr, MyOtherBaseExpr)),
                    hasAnyArgument(...),
                  this);

But I'd also like to be able to match such calls on instances of typedefs for the base or derived types like in the last line below:

typedef MyBase MyTypedef;
MyTypedef t;
t(parameters);

and I can't seem to fathom the correct way to specify this match. Attempting to use hasUnqualifiedDesugaredType rather than hasType doesn't work since it works on a type rather than a Decl and if I try to do more matching with the type then I can't use isSameOrDerived which returns a Matcher<CXXRecordDecl>. A similar problem occurs when trying to use hasCanonicalType:

.../RedundantStringCStrCheck.cpp:193:40: error: invalid initialization of reference of type ‘const clang::ast_matchers:
:internal::Matcher<clang::QualType>&’ from expression of type ‘clang::ast_matchers::internal::BindableMatcher<clang::Decl>’
  193 |     expr(hasCanonicalType(cxxRecordDecl(isSameOrDerivedFrom("::MyBase"))));

Solution

  • Thien Tran provided the pointer which led me to the right answer. Here's my original expression

    const auto MyBaseExpr =
      expr(hasType(cxxRecordDecl(isSameOrDerivedFrom("::MyBase"))));
    

    I was trying to use:

    const auto MyBaseExpr =
      expr(hasCanonicalType(cxxRecordDecl(isSameOrDerivedFrom("::MyBase"))));
    

    but the description of hasCanonicalType in LibASTMatchersReference shows that it takes and returns Matcher<QualType> yet cxxRecordDecl has type Matcher<Decl>, so this did not compile.

    The mismatch of types can be corrected by inserting a call to hasDeclaration. It's then also necessary to keep the call to hasType in order to turn the Matcher<QualType> result of hasCanonicalType back into something that can be passed to expr.

    After all that I ended up with:

    const auto MyBaseExpr =                                                                                                                                                                                
      expr(hasType(hasCanonicalType(hasDeclaration(cxxRecordDecl(isSameOrDerivedFrom("::MyBase"))))));
    

    which seems to work perfectly.