I'm trying to match arguments passed to a templated member function invocation using clang-query as a precursor to writing a clang-tidy check. Whilst I can get non-templated member functions to match, I'm unable to get templated member functions to. I'm using clang-14.0.0.
Consider:
#include <string>
class BaseTrace {
public:
template <typename... Args>
void Templated(const char *fmt, Args &&...args) {
}
void NotTemplated(const char *fmt, const char *s1, const char *s2) {
}
};
BaseTrace TRACE;
void trace1(const std::string &s1, const std::string &s2)
{
TRACE.Templated("One:{} Two:{}\n", s1.c_str(), s2.c_str());
}
void trace2(const std::string &s1, const std::string &s2)
{
TRACE.NotTemplated("One:{} Two:{}\n", s1.c_str(), s2.c_str());
}
Querying for normal member invocation function matches as expected:
clang-query> match match cxxMemberCallExpr(callee(functionDecl(hasName("NotTemplated"))), on(expr(hasType(cxxRecordDecl(hasName("::BaseTrace"))))), hasAnyArgument(cxxMemberCallExpr()))
Match #1:
/home/mac/git/llvm-project/build/../clang-tools-extra/test/clang-tidy/checkers/minimal-cstr.cpp:23:3: note: "root" binds here
TRACE.NotTemplated("One:{} Two:{}\n", s1.c_str(), s2.c_str());
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 match.
But querying for a templated member function invocation does not:
clang-query> match match cxxMemberCallExpr(callee(functionDecl(hasName("Templated"), isTemplateInstantiation())), on(expr(hasType(cxxRecordDecl(hasName("::BaseTrace"))))), hasAnyArgument(cxxMemberCallExpr()))
0 matches.
The answer to this question implies that this ought to work. If I don't try to match the arguments then I am able to get a match:
clang-query> match cxxMemberCallExpr(callee(functionDecl(hasName("Templated"), isTemplateInstantiation())), on(anyOf(expr(hasType(cxxRecordDecl(hasName("::BaseTrace")))), expr(hasType(cxxRecordDecl(isDerivedFrom("::BaseTrace")))))))
Match #1:
/home/mac/git/llvm-project/build/../clang-tools-extra/test/clang-tidy/checkers/minimal-cstr.cpp:16:3: note: "root" binds here
TRACE.Templated("One:{} Two:{}\n", s1.c_str(), s2.c_str());
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 match.
I don't seem to have the same problem when matching non-member functions.
Am I missing something, or is this potentially a clang limitation.