//===- ASTMatchersInternal.cpp - Structural query framework ---------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // Implements the base layer of the matcher framework. // //===----------------------------------------------------------------------===// #include "clang/ASTMatchers/ASTMatchersInternal.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTTypeTraits.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/ParentMapContext.h" #include "clang/AST/PrettyPrinter.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Basic/LLVM.h" #include "clang/Lex/Lexer.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/None.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Regex.h" #include "llvm/Support/WithColor.h" #include "llvm/Support/raw_ostream.h" #include #include #include #include #include #include namespace clang { namespace ast_matchers { AST_MATCHER_P(ObjCMessageExpr, hasAnySelectorMatcher, std::vector, Matches) { return llvm::is_contained(Matches, Node.getSelector().getAsString()); } namespace internal { bool NotUnaryOperator(const DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef InnerMatchers); bool AllOfVariadicOperator(const DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef InnerMatchers); bool EachOfVariadicOperator(const DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef InnerMatchers); bool AnyOfVariadicOperator(const DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef InnerMatchers); bool OptionallyVariadicOperator(const DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef InnerMatchers); bool matchesAnyBase(const CXXRecordDecl &Node, const Matcher &BaseSpecMatcher, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) { if (!Node.hasDefinition()) return false; CXXBasePaths Paths; Paths.setOrigin(&Node); const auto basePredicate = [Finder, Builder, &BaseSpecMatcher](const CXXBaseSpecifier *BaseSpec, CXXBasePath &IgnoredParam) { BoundNodesTreeBuilder Result(*Builder); if (BaseSpecMatcher.matches(*BaseSpec, Finder, Builder)) { *Builder = std::move(Result); return true; } return false; }; return Node.lookupInBases(basePredicate, Paths, /*LookupInDependent =*/true); } void BoundNodesTreeBuilder::visitMatches(Visitor *ResultVisitor) { if (Bindings.empty()) Bindings.push_back(BoundNodesMap()); for (BoundNodesMap &Binding : Bindings) { ResultVisitor->visitMatch(BoundNodes(Binding)); } } namespace { using VariadicOperatorFunction = bool (*)( const DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef InnerMatchers); template class VariadicMatcher : public DynMatcherInterface { public: VariadicMatcher(std::vector InnerMatchers) : InnerMatchers(std::move(InnerMatchers)) {} bool dynMatches(const DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const override { return Func(DynNode, Finder, Builder, InnerMatchers); } private: std::vector InnerMatchers; }; class IdDynMatcher : public DynMatcherInterface { public: IdDynMatcher(StringRef ID, IntrusiveRefCntPtr InnerMatcher) : ID(ID), InnerMatcher(std::move(InnerMatcher)) {} bool dynMatches(const DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const override { bool Result = InnerMatcher->dynMatches(DynNode, Finder, Builder); if (Result) Builder->setBinding(ID, DynNode); return Result; } llvm::Optional TraversalKind() const override { return InnerMatcher->TraversalKind(); } private: const std::string ID; const IntrusiveRefCntPtr InnerMatcher; }; /// A matcher that always returns true. /// /// We only ever need one instance of this matcher, so we create a global one /// and reuse it to reduce the overhead of the matcher and increase the chance /// of cache hits. class TrueMatcherImpl : public DynMatcherInterface { public: TrueMatcherImpl() { Retain(); // Reference count will never become zero. } bool dynMatches(const DynTypedNode &, ASTMatchFinder *, BoundNodesTreeBuilder *) const override { return true; } }; /// A matcher that specifies a particular \c TraversalKind. /// /// The kind provided to the constructor overrides any kind that may be /// specified by the `InnerMatcher`. class DynTraversalMatcherImpl : public DynMatcherInterface { public: explicit DynTraversalMatcherImpl( clang::TraversalKind TK, IntrusiveRefCntPtr InnerMatcher) : TK(TK), InnerMatcher(std::move(InnerMatcher)) {} bool dynMatches(const DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const override { return this->InnerMatcher->dynMatches(DynNode, Finder, Builder); } llvm::Optional TraversalKind() const override { return TK; } private: clang::TraversalKind TK; IntrusiveRefCntPtr InnerMatcher; }; } // namespace static llvm::ManagedStatic TrueMatcherInstance; DynTypedMatcher DynTypedMatcher::constructVariadic(DynTypedMatcher::VariadicOperator Op, ASTNodeKind SupportedKind, std::vector InnerMatchers) { assert(!InnerMatchers.empty() && "Array must not be empty."); assert(llvm::all_of(InnerMatchers, [SupportedKind](const DynTypedMatcher &M) { return M.canConvertTo(SupportedKind); }) && "InnerMatchers must be convertible to SupportedKind!"); // We must relax the restrict kind here. // The different operators might deal differently with a mismatch. // Make it the same as SupportedKind, since that is the broadest type we are // allowed to accept. auto RestrictKind = SupportedKind; switch (Op) { case VO_AllOf: // In the case of allOf() we must pass all the checks, so making // RestrictKind the most restrictive can save us time. This way we reject // invalid types earlier and we can elide the kind checks inside the // matcher. for (auto &IM : InnerMatchers) { RestrictKind = ASTNodeKind::getMostDerivedType(RestrictKind, IM.RestrictKind); } return DynTypedMatcher( SupportedKind, RestrictKind, new VariadicMatcher(std::move(InnerMatchers))); case VO_AnyOf: return DynTypedMatcher( SupportedKind, RestrictKind, new VariadicMatcher(std::move(InnerMatchers))); case VO_EachOf: return DynTypedMatcher( SupportedKind, RestrictKind, new VariadicMatcher(std::move(InnerMatchers))); case VO_Optionally: return DynTypedMatcher(SupportedKind, RestrictKind, new VariadicMatcher( std::move(InnerMatchers))); case VO_UnaryNot: // FIXME: Implement the Not operator to take a single matcher instead of a // vector. return DynTypedMatcher( SupportedKind, RestrictKind, new VariadicMatcher(std::move(InnerMatchers))); } llvm_unreachable("Invalid Op value."); } DynTypedMatcher DynTypedMatcher::constructRestrictedWrapper(const DynTypedMatcher &InnerMatcher, ASTNodeKind RestrictKind) { DynTypedMatcher Copy = InnerMatcher; Copy.RestrictKind = RestrictKind; return Copy; } DynTypedMatcher DynTypedMatcher::withTraversalKind(ast_type_traits::TraversalKind TK) { auto Copy = *this; Copy.Implementation = new DynTraversalMatcherImpl(TK, std::move(Copy.Implementation)); return Copy; } DynTypedMatcher DynTypedMatcher::trueMatcher(ASTNodeKind NodeKind) { return DynTypedMatcher(NodeKind, NodeKind, &*TrueMatcherInstance); } bool DynTypedMatcher::canMatchNodesOfKind(ASTNodeKind Kind) const { return RestrictKind.isBaseOf(Kind); } DynTypedMatcher DynTypedMatcher::dynCastTo(const ASTNodeKind Kind) const { auto Copy = *this; Copy.SupportedKind = Kind; Copy.RestrictKind = ASTNodeKind::getMostDerivedType(Kind, RestrictKind); return Copy; } bool DynTypedMatcher::matches(const DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const { TraversalKindScope RAII(Finder->getASTContext(), Implementation->TraversalKind()); auto N = Finder->getASTContext().getParentMapContext().traverseIgnored(DynNode); if (RestrictKind.isBaseOf(N.getNodeKind()) && Implementation->dynMatches(N, Finder, Builder)) { return true; } // Delete all bindings when a matcher does not match. // This prevents unexpected exposure of bound nodes in unmatches // branches of the match tree. Builder->removeBindings([](const BoundNodesMap &) { return true; }); return false; } bool DynTypedMatcher::matchesNoKindCheck(const DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const { TraversalKindScope raii(Finder->getASTContext(), Implementation->TraversalKind()); auto N = Finder->getASTContext().getParentMapContext().traverseIgnored(DynNode); assert(RestrictKind.isBaseOf(N.getNodeKind())); if (Implementation->dynMatches(N, Finder, Builder)) { return true; } // Delete all bindings when a matcher does not match. // This prevents unexpected exposure of bound nodes in unmatches // branches of the match tree. Builder->removeBindings([](const BoundNodesMap &) { return true; }); return false; } llvm::Optional DynTypedMatcher::tryBind(StringRef ID) const { if (!AllowBind) return llvm::None; auto Result = *this; Result.Implementation = new IdDynMatcher(ID, std::move(Result.Implementation)); return std::move(Result); } bool DynTypedMatcher::canConvertTo(ASTNodeKind To) const { const auto From = getSupportedKind(); auto QualKind = ASTNodeKind::getFromNodeKind(); auto TypeKind = ASTNodeKind::getFromNodeKind(); /// Mimic the implicit conversions of Matcher<>. /// - From Matcher to Matcher if (From.isSame(TypeKind) && To.isSame(QualKind)) return true; /// - From Matcher to Matcher return From.isBaseOf(To); } void BoundNodesTreeBuilder::addMatch(const BoundNodesTreeBuilder &Other) { Bindings.append(Other.Bindings.begin(), Other.Bindings.end()); } bool NotUnaryOperator(const DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef InnerMatchers) { if (InnerMatchers.size() != 1) return false; // The 'unless' matcher will always discard the result: // If the inner matcher doesn't match, unless returns true, // but the inner matcher cannot have bound anything. // If the inner matcher matches, the result is false, and // any possible binding will be discarded. // We still need to hand in all the bound nodes up to this // point so the inner matcher can depend on bound nodes, // and we need to actively discard the bound nodes, otherwise // the inner matcher will reset the bound nodes if it doesn't // match, but this would be inversed by 'unless'. BoundNodesTreeBuilder Discard(*Builder); return !InnerMatchers[0].matches(DynNode, Finder, &Discard); } bool AllOfVariadicOperator(const DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef InnerMatchers) { // allOf leads to one matcher for each alternative in the first // matcher combined with each alternative in the second matcher. // Thus, we can reuse the same Builder. return llvm::all_of(InnerMatchers, [&](const DynTypedMatcher &InnerMatcher) { return InnerMatcher.matchesNoKindCheck(DynNode, Finder, Builder); }); } bool EachOfVariadicOperator(const DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef InnerMatchers) { BoundNodesTreeBuilder Result; bool Matched = false; for (const DynTypedMatcher &InnerMatcher : InnerMatchers) { BoundNodesTreeBuilder BuilderInner(*Builder); if (InnerMatcher.matches(DynNode, Finder, &BuilderInner)) { Matched = true; Result.addMatch(BuilderInner); } } *Builder = std::move(Result); return Matched; } bool AnyOfVariadicOperator(const DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef InnerMatchers) { for (const DynTypedMatcher &InnerMatcher : InnerMatchers) { BoundNodesTreeBuilder Result = *Builder; if (InnerMatcher.matches(DynNode, Finder, &Result)) { *Builder = std::move(Result); return true; } } return false; } bool OptionallyVariadicOperator(const DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef InnerMatchers) { if (InnerMatchers.size() != 1) return false; BoundNodesTreeBuilder Result(*Builder); if (InnerMatchers[0].matches(DynNode, Finder, &Result)) *Builder = std::move(Result); return true; } inline static std::vector vectorFromRefs(ArrayRef NameRefs) { std::vector Names; Names.reserve(NameRefs.size()); for (auto *Name : NameRefs) Names.emplace_back(*Name); return Names; } Matcher hasAnyNameFunc(ArrayRef NameRefs) { return internal::Matcher( new internal::HasNameMatcher(vectorFromRefs(NameRefs))); } Matcher hasAnySelectorFunc( ArrayRef NameRefs) { return hasAnySelectorMatcher(vectorFromRefs(NameRefs)); } HasOpNameMatcher hasAnyOperatorNameFunc(ArrayRef NameRefs) { return HasOpNameMatcher(vectorFromRefs(NameRefs)); } HasOverloadOpNameMatcher hasAnyOverloadedOperatorNameFunc(ArrayRef NameRefs) { return HasOverloadOpNameMatcher(vectorFromRefs(NameRefs)); } HasNameMatcher::HasNameMatcher(std::vector N) : UseUnqualifiedMatch(llvm::all_of( N, [](StringRef Name) { return Name.find("::") == Name.npos; })), Names(std::move(N)) { #ifndef NDEBUG for (StringRef Name : Names) assert(!Name.empty()); #endif } static bool consumeNameSuffix(StringRef &FullName, StringRef Suffix) { StringRef Name = FullName; if (!Name.endswith(Suffix)) return false; Name = Name.drop_back(Suffix.size()); if (!Name.empty()) { if (!Name.endswith("::")) return false; Name = Name.drop_back(2); } FullName = Name; return true; } static StringRef getNodeName(const NamedDecl &Node, llvm::SmallString<128> &Scratch) { // Simple name. if (Node.getIdentifier()) return Node.getName(); if (Node.getDeclName()) { // Name needs to be constructed. Scratch.clear(); llvm::raw_svector_ostream OS(Scratch); Node.printName(OS); return OS.str(); } return "(anonymous)"; } static StringRef getNodeName(const RecordDecl &Node, llvm::SmallString<128> &Scratch) { if (Node.getIdentifier()) { return Node.getName(); } Scratch.clear(); return ("(anonymous " + Node.getKindName() + ")").toStringRef(Scratch); } static StringRef getNodeName(const NamespaceDecl &Node, llvm::SmallString<128> &Scratch) { return Node.isAnonymousNamespace() ? "(anonymous namespace)" : Node.getName(); } namespace { class PatternSet { public: PatternSet(ArrayRef Names) { Patterns.reserve(Names.size()); for (StringRef Name : Names) Patterns.push_back({Name, Name.startswith("::")}); } /// Consumes the name suffix from each pattern in the set and removes the ones /// that didn't match. /// Return true if there are still any patterns left. bool consumeNameSuffix(StringRef NodeName, bool CanSkip) { for (size_t I = 0; I < Patterns.size();) { if (::clang::ast_matchers::internal::consumeNameSuffix(Patterns[I].P, NodeName) || CanSkip) { ++I; } else { Patterns.erase(Patterns.begin() + I); } } return !Patterns.empty(); } /// Check if any of the patterns are a match. /// A match will be a pattern that was fully consumed, that also matches the /// 'fully qualified' requirement. bool foundMatch(bool AllowFullyQualified) const { return llvm::any_of(Patterns, [&](const Pattern &Pattern) { return Pattern.P.empty() && (AllowFullyQualified || !Pattern.IsFullyQualified); }); } private: struct Pattern { StringRef P; bool IsFullyQualified; }; llvm::SmallVector Patterns; }; } // namespace bool HasNameMatcher::matchesNodeUnqualified(const NamedDecl &Node) const { assert(UseUnqualifiedMatch); llvm::SmallString<128> Scratch; StringRef NodeName = getNodeName(Node, Scratch); return llvm::any_of(Names, [&](StringRef Name) { return consumeNameSuffix(Name, NodeName) && Name.empty(); }); } bool HasNameMatcher::matchesNodeFullFast(const NamedDecl &Node) const { PatternSet Patterns(Names); llvm::SmallString<128> Scratch; // This function is copied and adapted from NamedDecl::printQualifiedName() // By matching each part individually we optimize in a couple of ways: // - We can exit early on the first failure. // - We can skip inline/anonymous namespaces without another pass. // - We print one name at a time, reducing the chance of overflowing the // inlined space of the SmallString. // First, match the name. if (!Patterns.consumeNameSuffix(getNodeName(Node, Scratch), /*CanSkip=*/false)) return false; // Try to match each declaration context. // We are allowed to skip anonymous and inline namespaces if they don't match. const DeclContext *Ctx = Node.getDeclContext(); if (Ctx->isFunctionOrMethod()) return Patterns.foundMatch(/*AllowFullyQualified=*/false); for (; Ctx; Ctx = Ctx->getParent()) { // Linkage Spec can just be ignored // FIXME: Any other DeclContext kinds that can be safely disregarded if (isa(Ctx)) continue; if (!isa(Ctx)) break; if (Patterns.foundMatch(/*AllowFullyQualified=*/false)) return true; if (const auto *ND = dyn_cast(Ctx)) { // If it matches (or we can skip it), continue. if (Patterns.consumeNameSuffix(getNodeName(*ND, Scratch), /*CanSkip=*/ND->isAnonymousNamespace() || ND->isInline())) continue; return false; } if (const auto *RD = dyn_cast(Ctx)) { if (!isa(Ctx)) { if (Patterns.consumeNameSuffix(getNodeName(*RD, Scratch), /*CanSkip=*/false)) continue; return false; } } // We don't know how to deal with this DeclContext. // Fallback to the slow version of the code. return matchesNodeFullSlow(Node); } return Patterns.foundMatch(/*AllowFullyQualified=*/true); } bool HasNameMatcher::matchesNodeFullSlow(const NamedDecl &Node) const { const bool SkipUnwrittenCases[] = {false, true}; for (bool SkipUnwritten : SkipUnwrittenCases) { llvm::SmallString<128> NodeName = StringRef("::"); llvm::raw_svector_ostream OS(NodeName); if (SkipUnwritten) { PrintingPolicy Policy = Node.getASTContext().getPrintingPolicy(); Policy.SuppressUnwrittenScope = true; Node.printQualifiedName(OS, Policy); } else { Node.printQualifiedName(OS); } const StringRef FullName = OS.str(); for (const StringRef Pattern : Names) { if (Pattern.startswith("::")) { if (FullName == Pattern) return true; } else if (FullName.endswith(Pattern) && FullName.drop_back(Pattern.size()).endswith("::")) { return true; } } } return false; } bool HasNameMatcher::matchesNode(const NamedDecl &Node) const { assert(matchesNodeFullFast(Node) == matchesNodeFullSlow(Node)); if (UseUnqualifiedMatch) { assert(matchesNodeUnqualified(Node) == matchesNodeFullFast(Node)); return matchesNodeUnqualified(Node); } return matchesNodeFullFast(Node); } // Checks whether \p Loc points to a token with source text of \p TokenText. static bool isTokenAtLoc(const SourceManager &SM, const LangOptions &LangOpts, StringRef Text, SourceLocation Loc) { llvm::SmallString<16> Buffer; bool Invalid = false; // Since `Loc` may point into an expansion buffer, which has no corresponding // source, we need to look at the spelling location to read the actual source. StringRef TokenText = Lexer::getSpelling(SM.getSpellingLoc(Loc), Buffer, SM, LangOpts, &Invalid); return !Invalid && Text == TokenText; } llvm::Optional getExpansionLocOfMacro(StringRef MacroName, SourceLocation Loc, const ASTContext &Context) { auto &SM = Context.getSourceManager(); const LangOptions &LangOpts = Context.getLangOpts(); while (Loc.isMacroID()) { SrcMgr::ExpansionInfo Expansion = SM.getSLocEntry(SM.getFileID(Loc)).getExpansion(); if (Expansion.isMacroArgExpansion()) // Check macro argument for an expansion of the given macro. For example, // `F(G(3))`, where `MacroName` is `G`. if (llvm::Optional ArgLoc = getExpansionLocOfMacro( MacroName, Expansion.getSpellingLoc(), Context)) return ArgLoc; Loc = Expansion.getExpansionLocStart(); if (isTokenAtLoc(SM, LangOpts, MacroName, Loc)) return Loc; } return llvm::None; } std::shared_ptr createAndVerifyRegex(StringRef Regex, llvm::Regex::RegexFlags Flags, StringRef MatcherID) { assert(!Regex.empty() && "Empty regex string"); auto SharedRegex = std::make_shared(Regex, Flags); std::string Error; if (!SharedRegex->isValid(Error)) { llvm::WithColor::error() << "building matcher '" << MatcherID << "': " << Error << "\n"; llvm::WithColor::note() << " input was '" << Regex << "'\n"; } return SharedRegex; } } // end namespace internal const internal::VariadicDynCastAllOfMatcher autoreleasePoolStmt; const internal::VariadicDynCastAllOfMatcher translationUnitDecl; const internal::VariadicDynCastAllOfMatcher typedefDecl; const internal::VariadicDynCastAllOfMatcher typedefNameDecl; const internal::VariadicDynCastAllOfMatcher typeAliasDecl; const internal::VariadicDynCastAllOfMatcher typeAliasTemplateDecl; const internal::VariadicAllOfMatcher decl; const internal::VariadicDynCastAllOfMatcher linkageSpecDecl; const internal::VariadicDynCastAllOfMatcher namedDecl; const internal::VariadicDynCastAllOfMatcher labelDecl; const internal::VariadicDynCastAllOfMatcher namespaceDecl; const internal::VariadicDynCastAllOfMatcher namespaceAliasDecl; const internal::VariadicDynCastAllOfMatcher recordDecl; const internal::VariadicDynCastAllOfMatcher cxxRecordDecl; const internal::VariadicDynCastAllOfMatcher classTemplateDecl; const internal::VariadicDynCastAllOfMatcher classTemplateSpecializationDecl; const internal::VariadicDynCastAllOfMatcher< Decl, ClassTemplatePartialSpecializationDecl> classTemplatePartialSpecializationDecl; const internal::VariadicDynCastAllOfMatcher declaratorDecl; const internal::VariadicDynCastAllOfMatcher parmVarDecl; const internal::VariadicDynCastAllOfMatcher accessSpecDecl; const internal::VariadicAllOfMatcher cxxCtorInitializer; const internal::VariadicAllOfMatcher templateArgument; const internal::VariadicAllOfMatcher templateName; const internal::VariadicDynCastAllOfMatcher nonTypeTemplateParmDecl; const internal::VariadicDynCastAllOfMatcher templateTypeParmDecl; const internal::VariadicAllOfMatcher qualType; const internal::VariadicAllOfMatcher type; const internal::VariadicAllOfMatcher typeLoc; const internal::VariadicDynCastAllOfMatcher unaryExprOrTypeTraitExpr; const internal::VariadicDynCastAllOfMatcher valueDecl; const internal::VariadicDynCastAllOfMatcher cxxConstructorDecl; const internal::VariadicDynCastAllOfMatcher cxxDestructorDecl; const internal::VariadicDynCastAllOfMatcher enumDecl; const internal::VariadicDynCastAllOfMatcher enumConstantDecl; const internal::VariadicDynCastAllOfMatcher tagDecl; const internal::VariadicDynCastAllOfMatcher cxxMethodDecl; const internal::VariadicDynCastAllOfMatcher cxxConversionDecl; const internal::VariadicDynCastAllOfMatcher varDecl; const internal::VariadicDynCastAllOfMatcher fieldDecl; const internal::VariadicDynCastAllOfMatcher indirectFieldDecl; const internal::VariadicDynCastAllOfMatcher functionDecl; const internal::VariadicDynCastAllOfMatcher functionTemplateDecl; const internal::VariadicDynCastAllOfMatcher friendDecl; const internal::VariadicAllOfMatcher stmt; const internal::VariadicDynCastAllOfMatcher declStmt; const internal::VariadicDynCastAllOfMatcher memberExpr; const internal::VariadicDynCastAllOfMatcher unresolvedMemberExpr; const internal::VariadicDynCastAllOfMatcher cxxDependentScopeMemberExpr; const internal::VariadicDynCastAllOfMatcher callExpr; const internal::VariadicDynCastAllOfMatcher lambdaExpr; const internal::VariadicDynCastAllOfMatcher cxxMemberCallExpr; const internal::VariadicDynCastAllOfMatcher objcMessageExpr; const internal::VariadicDynCastAllOfMatcher objcInterfaceDecl; const internal::VariadicDynCastAllOfMatcher objcImplementationDecl; const internal::VariadicDynCastAllOfMatcher objcProtocolDecl; const internal::VariadicDynCastAllOfMatcher objcCategoryDecl; const internal::VariadicDynCastAllOfMatcher objcCategoryImplDecl; const internal::VariadicDynCastAllOfMatcher objcMethodDecl; const internal::VariadicDynCastAllOfMatcher blockDecl; const internal::VariadicDynCastAllOfMatcher objcIvarDecl; const internal::VariadicDynCastAllOfMatcher objcPropertyDecl; const internal::VariadicDynCastAllOfMatcher objcThrowStmt; const internal::VariadicDynCastAllOfMatcher objcTryStmt; const internal::VariadicDynCastAllOfMatcher objcCatchStmt; const internal::VariadicDynCastAllOfMatcher objcFinallyStmt; const internal::VariadicDynCastAllOfMatcher exprWithCleanups; const internal::VariadicDynCastAllOfMatcher initListExpr; const internal::VariadicDynCastAllOfMatcher cxxStdInitializerListExpr; const internal::VariadicDynCastAllOfMatcher implicitValueInitExpr; const internal::VariadicDynCastAllOfMatcher parenListExpr; const internal::VariadicDynCastAllOfMatcher substNonTypeTemplateParmExpr; const internal::VariadicDynCastAllOfMatcher usingDecl; const internal::VariadicDynCastAllOfMatcher usingDirectiveDecl; const internal::VariadicDynCastAllOfMatcher unresolvedLookupExpr; const internal::VariadicDynCastAllOfMatcher unresolvedUsingValueDecl; const internal::VariadicDynCastAllOfMatcher unresolvedUsingTypenameDecl; const internal::VariadicDynCastAllOfMatcher constantExpr; const internal::VariadicDynCastAllOfMatcher parenExpr; const internal::VariadicDynCastAllOfMatcher cxxConstructExpr; const internal::VariadicDynCastAllOfMatcher cxxUnresolvedConstructExpr; const internal::VariadicDynCastAllOfMatcher cxxThisExpr; const internal::VariadicDynCastAllOfMatcher cxxBindTemporaryExpr; const internal::VariadicDynCastAllOfMatcher materializeTemporaryExpr; const internal::VariadicDynCastAllOfMatcher cxxNewExpr; const internal::VariadicDynCastAllOfMatcher cxxDeleteExpr; const internal::VariadicDynCastAllOfMatcher cxxNoexceptExpr; const internal::VariadicDynCastAllOfMatcher arraySubscriptExpr; const internal::VariadicDynCastAllOfMatcher cxxDefaultArgExpr; const internal::VariadicDynCastAllOfMatcher cxxOperatorCallExpr; const internal::VariadicDynCastAllOfMatcher expr; const internal::VariadicDynCastAllOfMatcher declRefExpr; const internal::VariadicDynCastAllOfMatcher objcIvarRefExpr; const internal::VariadicDynCastAllOfMatcher blockExpr; const internal::VariadicDynCastAllOfMatcher ifStmt; const internal::VariadicDynCastAllOfMatcher forStmt; const internal::VariadicDynCastAllOfMatcher cxxForRangeStmt; const internal::VariadicDynCastAllOfMatcher whileStmt; const internal::VariadicDynCastAllOfMatcher doStmt; const internal::VariadicDynCastAllOfMatcher breakStmt; const internal::VariadicDynCastAllOfMatcher continueStmt; const internal::VariadicDynCastAllOfMatcher returnStmt; const internal::VariadicDynCastAllOfMatcher gotoStmt; const internal::VariadicDynCastAllOfMatcher labelStmt; const internal::VariadicDynCastAllOfMatcher addrLabelExpr; const internal::VariadicDynCastAllOfMatcher switchStmt; const internal::VariadicDynCastAllOfMatcher switchCase; const internal::VariadicDynCastAllOfMatcher caseStmt; const internal::VariadicDynCastAllOfMatcher defaultStmt; const internal::VariadicDynCastAllOfMatcher compoundStmt; const internal::VariadicDynCastAllOfMatcher cxxCatchStmt; const internal::VariadicDynCastAllOfMatcher cxxTryStmt; const internal::VariadicDynCastAllOfMatcher cxxThrowExpr; const internal::VariadicDynCastAllOfMatcher nullStmt; const internal::VariadicDynCastAllOfMatcher asmStmt; const internal::VariadicDynCastAllOfMatcher cxxBoolLiteral; const internal::VariadicDynCastAllOfMatcher stringLiteral; const internal::VariadicDynCastAllOfMatcher characterLiteral; const internal::VariadicDynCastAllOfMatcher integerLiteral; const internal::VariadicDynCastAllOfMatcher floatLiteral; const internal::VariadicDynCastAllOfMatcher imaginaryLiteral; const internal::VariadicDynCastAllOfMatcher fixedPointLiteral; const internal::VariadicDynCastAllOfMatcher userDefinedLiteral; const internal::VariadicDynCastAllOfMatcher compoundLiteralExpr; const internal::VariadicDynCastAllOfMatcher cxxNullPtrLiteralExpr; const internal::VariadicDynCastAllOfMatcher chooseExpr; const internal::VariadicDynCastAllOfMatcher gnuNullExpr; const internal::VariadicDynCastAllOfMatcher atomicExpr; const internal::VariadicDynCastAllOfMatcher stmtExpr; const internal::VariadicDynCastAllOfMatcher binaryOperator; const internal::VariadicDynCastAllOfMatcher unaryOperator; const internal::VariadicDynCastAllOfMatcher conditionalOperator; const internal::VariadicDynCastAllOfMatcher binaryConditionalOperator; const internal::VariadicDynCastAllOfMatcher opaqueValueExpr; const internal::VariadicDynCastAllOfMatcher staticAssertDecl; const internal::VariadicDynCastAllOfMatcher cxxReinterpretCastExpr; const internal::VariadicDynCastAllOfMatcher cxxStaticCastExpr; const internal::VariadicDynCastAllOfMatcher cxxDynamicCastExpr; const internal::VariadicDynCastAllOfMatcher cxxConstCastExpr; const internal::VariadicDynCastAllOfMatcher cStyleCastExpr; const internal::VariadicDynCastAllOfMatcher explicitCastExpr; const internal::VariadicDynCastAllOfMatcher implicitCastExpr; const internal::VariadicDynCastAllOfMatcher castExpr; const internal::VariadicDynCastAllOfMatcher cxxFunctionalCastExpr; const internal::VariadicDynCastAllOfMatcher cxxTemporaryObjectExpr; const internal::VariadicDynCastAllOfMatcher predefinedExpr; const internal::VariadicDynCastAllOfMatcher designatedInitExpr; const internal::VariadicOperatorMatcherFunc< 2, std::numeric_limits::max()> eachOf = {internal::DynTypedMatcher::VO_EachOf}; const internal::VariadicOperatorMatcherFunc< 2, std::numeric_limits::max()> anyOf = {internal::DynTypedMatcher::VO_AnyOf}; const internal::VariadicOperatorMatcherFunc< 2, std::numeric_limits::max()> allOf = {internal::DynTypedMatcher::VO_AllOf}; const internal::VariadicOperatorMatcherFunc<1, 1> optionally = { internal::DynTypedMatcher::VO_Optionally}; const internal::VariadicFunction, StringRef, internal::hasAnyNameFunc> hasAnyName = {}; const internal::VariadicFunction hasAnyOperatorName = {}; const internal::VariadicFunction hasAnyOverloadedOperatorName = {}; const internal::VariadicFunction, StringRef, internal::hasAnySelectorFunc> hasAnySelector = {}; const internal::ArgumentAdaptingMatcherFunc has = {}; const internal::ArgumentAdaptingMatcherFunc hasDescendant = {}; const internal::ArgumentAdaptingMatcherFunc forEach = {}; const internal::ArgumentAdaptingMatcherFunc forEachDescendant = {}; const internal::ArgumentAdaptingMatcherFunc< internal::HasParentMatcher, internal::TypeList, internal::TypeList> hasParent = {}; const internal::ArgumentAdaptingMatcherFunc< internal::HasAncestorMatcher, internal::TypeList, internal::TypeList> hasAncestor = {}; const internal::VariadicOperatorMatcherFunc<1, 1> unless = { internal::DynTypedMatcher::VO_UnaryNot}; const internal::VariadicAllOfMatcher nestedNameSpecifier; const internal::VariadicAllOfMatcher nestedNameSpecifierLoc; const internal::VariadicDynCastAllOfMatcher cudaKernelCallExpr; const AstTypeMatcher builtinType; const AstTypeMatcher arrayType; const AstTypeMatcher complexType; const AstTypeMatcher constantArrayType; const AstTypeMatcher deducedTemplateSpecializationType; const AstTypeMatcher dependentSizedArrayType; const AstTypeMatcher incompleteArrayType; const AstTypeMatcher variableArrayType; const AstTypeMatcher atomicType; const AstTypeMatcher autoType; const AstTypeMatcher decltypeType; const AstTypeMatcher functionType; const AstTypeMatcher functionProtoType; const AstTypeMatcher parenType; const AstTypeMatcher blockPointerType; const AstTypeMatcher memberPointerType; const AstTypeMatcher pointerType; const AstTypeMatcher objcObjectPointerType; const AstTypeMatcher referenceType; const AstTypeMatcher lValueReferenceType; const AstTypeMatcher rValueReferenceType; const AstTypeMatcher typedefType; const AstTypeMatcher enumType; const AstTypeMatcher templateSpecializationType; const AstTypeMatcher unaryTransformType; const AstTypeMatcher recordType; const AstTypeMatcher tagType; const AstTypeMatcher elaboratedType; const AstTypeMatcher substTemplateTypeParmType; const AstTypeMatcher templateTypeParmType; const AstTypeMatcher injectedClassNameType; const AstTypeMatcher decayedType; AST_TYPELOC_TRAVERSE_MATCHER_DEF(hasElementType, AST_POLYMORPHIC_SUPPORTED_TYPES(ArrayType, ComplexType)); AST_TYPELOC_TRAVERSE_MATCHER_DEF(hasValueType, AST_POLYMORPHIC_SUPPORTED_TYPES(AtomicType)); AST_TYPELOC_TRAVERSE_MATCHER_DEF( pointee, AST_POLYMORPHIC_SUPPORTED_TYPES(BlockPointerType, MemberPointerType, PointerType, ReferenceType)); const internal::VariadicDynCastAllOfMatcher ompExecutableDirective; const internal::VariadicDynCastAllOfMatcher ompDefaultClause; const internal::VariadicDynCastAllOfMatcher cxxDeductionGuideDecl; } // end namespace ast_matchers } // end namespace clang