1

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"))));
Mike Crowe
  • 642
  • 6
  • 18

2 Answers2

2

MyTypedef is defined from MyBase so its Canonical Type should be MyBase. More information about canonical type: https://clang.llvm.org/docs/InternalsManual.html#canonical-types

This is the example from LibASTMatchersReference , it uses hasType().

enter image description here

Thien Tran
  • 306
  • 1
  • 10
  • Thanks for the suggestion. I'm still having trouble. I think that my problem is that I'm currently using the `hasType(Matcher)` overload and no such overload exists for `hasCanonicalType` and I can't work out how to convert my match expression so it can be passed as a `Matcher` rather than a `Matcher`. – Mike Crowe Oct 04 '22 at 07:49
  • @MikeCrowe: Please have a look on LibASTMatchersReference. – Thien Tran Oct 04 '22 at 15:42
  • 1
    I've been using https://clang.llvm.org/docs/LibASTMatchersReference.html heavily as the source of my information so far. I've just gone back and read the text of it again, along with skimming through the list of matchers. It became a bit clearer to me that if I wrap my `cxxRecordDecl` with `hasDeclaration` then I can call `hasCanonicalType` on it. I then need to call `hasType` again on the result to get something I can turn back into an `Expr`. The result seems to work. I'll provide it in a separate answer. – Mike Crowe Oct 05 '22 at 20:39
2

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.

Mike Crowe
  • 642
  • 6
  • 18