Index: include/clang/ASTMatchers/ASTMatchers.h =================================================================== --- include/clang/ASTMatchers/ASTMatchers.h +++ include/clang/ASTMatchers/ASTMatchers.h @@ -3159,12 +3159,10 @@ /// \endcode /// functionDecl(isInstantiated()) /// matches 'A(int) {...};' and 'A(unsigned) {...}'. -AST_MATCHER(Decl, isInstantiated) { +AST_MATCHER_FUNCTION(internal::Matcher, isInstantiated) { auto IsInstantiation = decl(anyOf(recordDecl(isTemplateInstantiation()), functionDecl(isTemplateInstantiation()))); - auto InnerMatcher = - decl(anyOf(IsInstantiation, hasAncestor(IsInstantiation))); - return InnerMatcher.matches(Node, Finder, Builder); + return decl(anyOf(IsInstantiation, hasAncestor(IsInstantiation))); } /// \brief Matches statements inside of a template instantiation. @@ -3181,11 +3179,10 @@ /// unless(stmt(isInTemplateInstantiation())) /// will NOT match j += 42; as it's shared between the template definition and /// instantiation. -AST_MATCHER(Stmt, isInTemplateInstantiation) { - auto InnerMatcher = - stmt(hasAncestor(decl(anyOf(recordDecl(isTemplateInstantiation()), - functionDecl(isTemplateInstantiation()))))); - return InnerMatcher.matches(Node, Finder, Builder); +AST_MATCHER_FUNCTION(internal::Matcher, isInTemplateInstantiation) { + return stmt( + hasAncestor(decl(anyOf(recordDecl(isTemplateInstantiation()), + functionDecl(isTemplateInstantiation()))))); } /// \brief Matches explicit template specializations of function, class, or Index: include/clang/ASTMatchers/ASTMatchersInternal.h =================================================================== --- include/clang/ASTMatchers/ASTMatchersInternal.h +++ include/clang/ASTMatchers/ASTMatchersInternal.h @@ -44,6 +44,7 @@ #include "clang/AST/Type.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/VariadicFunction.h" +#include "llvm/Support/ManagedStatic.h" #include #include #include @@ -1620,6 +1621,23 @@ const Matcher InnerMatcher; }; +/// \brief A simple memoizer of T(*)() functions. +/// +/// It will call the passed 'Func' template parameter at most once. +/// Used to support AST_MATCHER_FUNCTION() macro. +template class MemoizedMatcher { + struct Wrapper { + Wrapper() : M(Func()) {} + Matcher M; + }; + +public: + static const Matcher &getInstance() { + static llvm::ManagedStatic Instance; + return Instance->M; + } +}; + // Define the create() method out of line to silence a GCC warning about // the struct "Func" having greater visibility than its base, which comes from // using the flag -fvisibility-inlines-hidden. Index: include/clang/ASTMatchers/ASTMatchersMacros.h =================================================================== --- include/clang/ASTMatchers/ASTMatchersMacros.h +++ include/clang/ASTMatchers/ASTMatchersMacros.h @@ -37,6 +37,17 @@ #ifndef LLVM_CLANG_ASTMATCHERS_ASTMATCHERSMACROS_H #define LLVM_CLANG_ASTMATCHERS_ASTMATCHERSMACROS_H +/// \brief AST_MATCHER_FUNCTION(ReturnType, DefineMatcher) { +/// defines a zero parameter function named DefineMatcher() that returns a +/// ReturnType object. +#define AST_MATCHER_FUNCTION(ReturnType, DefineMatcher) \ + inline ReturnType DefineMatcher##_getInstance(); \ + inline ReturnType DefineMatcher() { \ + return internal::MemoizedMatcher< \ + ReturnType, DefineMatcher##_getInstance>::getInstance(); \ + } \ + inline ReturnType DefineMatcher##_getInstance() + /// \brief AST_MATCHER_FUNCTION_P(ReturnType, DefineMatcher, ParamType, Param) { /// defines a single-parameter function named DefineMatcher() that returns a /// ReturnType object.