Path: blob/main/contrib/llvm-project/clang/lib/ASTMatchers/ASTMatchFinder.cpp
35262 views
//===--- ASTMatchFinder.cpp - Structural query framework ------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// Implements an algorithm to efficiently search for matches on AST nodes.9// Uses memoization to support recursive matches like HasDescendant.10//11// The general idea is to visit all AST nodes with a RecursiveASTVisitor,12// calling the Matches(...) method of each matcher we are running on each13// AST node. The matcher can recurse via the ASTMatchFinder interface.14//15//===----------------------------------------------------------------------===//1617#include "clang/ASTMatchers/ASTMatchFinder.h"18#include "clang/AST/ASTConsumer.h"19#include "clang/AST/ASTContext.h"20#include "clang/AST/DeclCXX.h"21#include "clang/AST/RecursiveASTVisitor.h"22#include "llvm/ADT/DenseMap.h"23#include "llvm/ADT/SmallPtrSet.h"24#include "llvm/ADT/StringMap.h"25#include "llvm/Support/PrettyStackTrace.h"26#include "llvm/Support/Timer.h"27#include <deque>28#include <memory>29#include <set>3031namespace clang {32namespace ast_matchers {33namespace internal {34namespace {3536typedef MatchFinder::MatchCallback MatchCallback;3738// The maximum number of memoization entries to store.39// 10k has been experimentally found to give a good trade-off40// of performance vs. memory consumption by running matcher41// that match on every statement over a very large codebase.42//43// FIXME: Do some performance optimization in general and44// revisit this number; also, put up micro-benchmarks that we can45// optimize this on.46static const unsigned MaxMemoizationEntries = 10000;4748enum class MatchType {49Ancestors,5051Descendants,52Child,53};5455// We use memoization to avoid running the same matcher on the same56// AST node twice. This struct is the key for looking up match57// result. It consists of an ID of the MatcherInterface (for58// identifying the matcher), a pointer to the AST node and the59// bound nodes before the matcher was executed.60//61// We currently only memoize on nodes whose pointers identify the62// nodes (\c Stmt and \c Decl, but not \c QualType or \c TypeLoc).63// For \c QualType and \c TypeLoc it is possible to implement64// generation of keys for each type.65// FIXME: Benchmark whether memoization of non-pointer typed nodes66// provides enough benefit for the additional amount of code.67struct MatchKey {68DynTypedMatcher::MatcherIDType MatcherID;69DynTypedNode Node;70BoundNodesTreeBuilder BoundNodes;71TraversalKind Traversal = TK_AsIs;72MatchType Type;7374bool operator<(const MatchKey &Other) const {75return std::tie(Traversal, Type, MatcherID, Node, BoundNodes) <76std::tie(Other.Traversal, Other.Type, Other.MatcherID, Other.Node,77Other.BoundNodes);78}79};8081// Used to store the result of a match and possibly bound nodes.82struct MemoizedMatchResult {83bool ResultOfMatch;84BoundNodesTreeBuilder Nodes;85};8687// A RecursiveASTVisitor that traverses all children or all descendants of88// a node.89class MatchChildASTVisitor90: public RecursiveASTVisitor<MatchChildASTVisitor> {91public:92typedef RecursiveASTVisitor<MatchChildASTVisitor> VisitorBase;9394// Creates an AST visitor that matches 'matcher' on all children or95// descendants of a traversed node. max_depth is the maximum depth96// to traverse: use 1 for matching the children and INT_MAX for97// matching the descendants.98MatchChildASTVisitor(const DynTypedMatcher *Matcher, ASTMatchFinder *Finder,99BoundNodesTreeBuilder *Builder, int MaxDepth,100bool IgnoreImplicitChildren,101ASTMatchFinder::BindKind Bind)102: Matcher(Matcher), Finder(Finder), Builder(Builder), CurrentDepth(0),103MaxDepth(MaxDepth), IgnoreImplicitChildren(IgnoreImplicitChildren),104Bind(Bind), Matches(false) {}105106// Returns true if a match is found in the subtree rooted at the107// given AST node. This is done via a set of mutually recursive108// functions. Here's how the recursion is done (the *wildcard can109// actually be Decl, Stmt, or Type):110//111// - Traverse(node) calls BaseTraverse(node) when it needs112// to visit the descendants of node.113// - BaseTraverse(node) then calls (via VisitorBase::Traverse*(node))114// Traverse*(c) for each child c of 'node'.115// - Traverse*(c) in turn calls Traverse(c), completing the116// recursion.117bool findMatch(const DynTypedNode &DynNode) {118reset();119if (const Decl *D = DynNode.get<Decl>())120traverse(*D);121else if (const Stmt *S = DynNode.get<Stmt>())122traverse(*S);123else if (const NestedNameSpecifier *NNS =124DynNode.get<NestedNameSpecifier>())125traverse(*NNS);126else if (const NestedNameSpecifierLoc *NNSLoc =127DynNode.get<NestedNameSpecifierLoc>())128traverse(*NNSLoc);129else if (const QualType *Q = DynNode.get<QualType>())130traverse(*Q);131else if (const TypeLoc *T = DynNode.get<TypeLoc>())132traverse(*T);133else if (const auto *C = DynNode.get<CXXCtorInitializer>())134traverse(*C);135else if (const TemplateArgumentLoc *TALoc =136DynNode.get<TemplateArgumentLoc>())137traverse(*TALoc);138else if (const Attr *A = DynNode.get<Attr>())139traverse(*A);140// FIXME: Add other base types after adding tests.141142// It's OK to always overwrite the bound nodes, as if there was143// no match in this recursive branch, the result set is empty144// anyway.145*Builder = ResultBindings;146147return Matches;148}149150// The following are overriding methods from the base visitor class.151// They are public only to allow CRTP to work. They are *not *part152// of the public API of this class.153bool TraverseDecl(Decl *DeclNode) {154155if (DeclNode && DeclNode->isImplicit() &&156Finder->isTraversalIgnoringImplicitNodes())157return baseTraverse(*DeclNode);158159ScopedIncrement ScopedDepth(&CurrentDepth);160return (DeclNode == nullptr) || traverse(*DeclNode);161}162163Stmt *getStmtToTraverse(Stmt *StmtNode) {164Stmt *StmtToTraverse = StmtNode;165if (auto *ExprNode = dyn_cast_or_null<Expr>(StmtNode)) {166auto *LambdaNode = dyn_cast_or_null<LambdaExpr>(StmtNode);167if (LambdaNode && Finder->isTraversalIgnoringImplicitNodes())168StmtToTraverse = LambdaNode;169else170StmtToTraverse =171Finder->getASTContext().getParentMapContext().traverseIgnored(172ExprNode);173}174return StmtToTraverse;175}176177bool TraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue = nullptr) {178// If we need to keep track of the depth, we can't perform data recursion.179if (CurrentDepth == 0 || (CurrentDepth <= MaxDepth && MaxDepth < INT_MAX))180Queue = nullptr;181182ScopedIncrement ScopedDepth(&CurrentDepth);183Stmt *StmtToTraverse = getStmtToTraverse(StmtNode);184if (!StmtToTraverse)185return true;186187if (IgnoreImplicitChildren && isa<CXXDefaultArgExpr>(StmtNode))188return true;189190if (!match(*StmtToTraverse))191return false;192return VisitorBase::TraverseStmt(StmtToTraverse, Queue);193}194// We assume that the QualType and the contained type are on the same195// hierarchy level. Thus, we try to match either of them.196bool TraverseType(QualType TypeNode) {197if (TypeNode.isNull())198return true;199ScopedIncrement ScopedDepth(&CurrentDepth);200// Match the Type.201if (!match(*TypeNode))202return false;203// The QualType is matched inside traverse.204return traverse(TypeNode);205}206// We assume that the TypeLoc, contained QualType and contained Type all are207// on the same hierarchy level. Thus, we try to match all of them.208bool TraverseTypeLoc(TypeLoc TypeLocNode) {209if (TypeLocNode.isNull())210return true;211ScopedIncrement ScopedDepth(&CurrentDepth);212// Match the Type.213if (!match(*TypeLocNode.getType()))214return false;215// Match the QualType.216if (!match(TypeLocNode.getType()))217return false;218// The TypeLoc is matched inside traverse.219return traverse(TypeLocNode);220}221bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) {222ScopedIncrement ScopedDepth(&CurrentDepth);223return (NNS == nullptr) || traverse(*NNS);224}225bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {226if (!NNS)227return true;228ScopedIncrement ScopedDepth(&CurrentDepth);229if (!match(*NNS.getNestedNameSpecifier()))230return false;231return traverse(NNS);232}233bool TraverseConstructorInitializer(CXXCtorInitializer *CtorInit) {234if (!CtorInit)235return true;236ScopedIncrement ScopedDepth(&CurrentDepth);237return traverse(*CtorInit);238}239bool TraverseTemplateArgumentLoc(TemplateArgumentLoc TAL) {240ScopedIncrement ScopedDepth(&CurrentDepth);241return traverse(TAL);242}243bool TraverseCXXForRangeStmt(CXXForRangeStmt *Node) {244if (!Finder->isTraversalIgnoringImplicitNodes())245return VisitorBase::TraverseCXXForRangeStmt(Node);246if (!Node)247return true;248ScopedIncrement ScopedDepth(&CurrentDepth);249if (auto *Init = Node->getInit())250if (!traverse(*Init))251return false;252if (!match(*Node->getLoopVariable()))253return false;254if (match(*Node->getRangeInit()))255if (!VisitorBase::TraverseStmt(Node->getRangeInit()))256return false;257if (!match(*Node->getBody()))258return false;259return VisitorBase::TraverseStmt(Node->getBody());260}261bool TraverseCXXRewrittenBinaryOperator(CXXRewrittenBinaryOperator *Node) {262if (!Finder->isTraversalIgnoringImplicitNodes())263return VisitorBase::TraverseCXXRewrittenBinaryOperator(Node);264if (!Node)265return true;266ScopedIncrement ScopedDepth(&CurrentDepth);267268return match(*Node->getLHS()) && match(*Node->getRHS());269}270bool TraverseAttr(Attr *A) {271if (A == nullptr ||272(A->isImplicit() &&273Finder->getASTContext().getParentMapContext().getTraversalKind() ==274TK_IgnoreUnlessSpelledInSource))275return true;276ScopedIncrement ScopedDepth(&CurrentDepth);277return traverse(*A);278}279bool TraverseLambdaExpr(LambdaExpr *Node) {280if (!Finder->isTraversalIgnoringImplicitNodes())281return VisitorBase::TraverseLambdaExpr(Node);282if (!Node)283return true;284ScopedIncrement ScopedDepth(&CurrentDepth);285286for (unsigned I = 0, N = Node->capture_size(); I != N; ++I) {287const auto *C = Node->capture_begin() + I;288if (!C->isExplicit())289continue;290if (Node->isInitCapture(C) && !match(*C->getCapturedVar()))291return false;292if (!match(*Node->capture_init_begin()[I]))293return false;294}295296if (const auto *TPL = Node->getTemplateParameterList()) {297for (const auto *TP : *TPL) {298if (!match(*TP))299return false;300}301}302303for (const auto *P : Node->getCallOperator()->parameters()) {304if (!match(*P))305return false;306}307308if (!match(*Node->getBody()))309return false;310311return VisitorBase::TraverseStmt(Node->getBody());312}313314bool shouldVisitTemplateInstantiations() const { return true; }315bool shouldVisitImplicitCode() const { return !IgnoreImplicitChildren; }316317private:318// Used for updating the depth during traversal.319struct ScopedIncrement {320explicit ScopedIncrement(int *Depth) : Depth(Depth) { ++(*Depth); }321~ScopedIncrement() { --(*Depth); }322323private:324int *Depth;325};326327// Resets the state of this object.328void reset() {329Matches = false;330CurrentDepth = 0;331}332333// Forwards the call to the corresponding Traverse*() method in the334// base visitor class.335bool baseTraverse(const Decl &DeclNode) {336return VisitorBase::TraverseDecl(const_cast<Decl*>(&DeclNode));337}338bool baseTraverse(const Stmt &StmtNode) {339return VisitorBase::TraverseStmt(const_cast<Stmt*>(&StmtNode));340}341bool baseTraverse(QualType TypeNode) {342return VisitorBase::TraverseType(TypeNode);343}344bool baseTraverse(TypeLoc TypeLocNode) {345return VisitorBase::TraverseTypeLoc(TypeLocNode);346}347bool baseTraverse(const NestedNameSpecifier &NNS) {348return VisitorBase::TraverseNestedNameSpecifier(349const_cast<NestedNameSpecifier*>(&NNS));350}351bool baseTraverse(NestedNameSpecifierLoc NNS) {352return VisitorBase::TraverseNestedNameSpecifierLoc(NNS);353}354bool baseTraverse(const CXXCtorInitializer &CtorInit) {355return VisitorBase::TraverseConstructorInitializer(356const_cast<CXXCtorInitializer *>(&CtorInit));357}358bool baseTraverse(TemplateArgumentLoc TAL) {359return VisitorBase::TraverseTemplateArgumentLoc(TAL);360}361bool baseTraverse(const Attr &AttrNode) {362return VisitorBase::TraverseAttr(const_cast<Attr *>(&AttrNode));363}364365// Sets 'Matched' to true if 'Matcher' matches 'Node' and:366// 0 < CurrentDepth <= MaxDepth.367//368// Returns 'true' if traversal should continue after this function369// returns, i.e. if no match is found or 'Bind' is 'BK_All'.370template <typename T>371bool match(const T &Node) {372if (CurrentDepth == 0 || CurrentDepth > MaxDepth) {373return true;374}375if (Bind != ASTMatchFinder::BK_All) {376BoundNodesTreeBuilder RecursiveBuilder(*Builder);377if (Matcher->matches(DynTypedNode::create(Node), Finder,378&RecursiveBuilder)) {379Matches = true;380ResultBindings.addMatch(RecursiveBuilder);381return false; // Abort as soon as a match is found.382}383} else {384BoundNodesTreeBuilder RecursiveBuilder(*Builder);385if (Matcher->matches(DynTypedNode::create(Node), Finder,386&RecursiveBuilder)) {387// After the first match the matcher succeeds.388Matches = true;389ResultBindings.addMatch(RecursiveBuilder);390}391}392return true;393}394395// Traverses the subtree rooted at 'Node'; returns true if the396// traversal should continue after this function returns.397template <typename T>398bool traverse(const T &Node) {399static_assert(IsBaseType<T>::value,400"traverse can only be instantiated with base type");401if (!match(Node))402return false;403return baseTraverse(Node);404}405406const DynTypedMatcher *const Matcher;407ASTMatchFinder *const Finder;408BoundNodesTreeBuilder *const Builder;409BoundNodesTreeBuilder ResultBindings;410int CurrentDepth;411const int MaxDepth;412const bool IgnoreImplicitChildren;413const ASTMatchFinder::BindKind Bind;414bool Matches;415};416417// Controls the outermost traversal of the AST and allows to match multiple418// matchers.419class MatchASTVisitor : public RecursiveASTVisitor<MatchASTVisitor>,420public ASTMatchFinder {421public:422MatchASTVisitor(const MatchFinder::MatchersByType *Matchers,423const MatchFinder::MatchFinderOptions &Options)424: Matchers(Matchers), Options(Options), ActiveASTContext(nullptr) {}425426~MatchASTVisitor() override {427if (Options.CheckProfiling) {428Options.CheckProfiling->Records = std::move(TimeByBucket);429}430}431432void onStartOfTranslationUnit() {433const bool EnableCheckProfiling = Options.CheckProfiling.has_value();434TimeBucketRegion Timer;435for (MatchCallback *MC : Matchers->AllCallbacks) {436if (EnableCheckProfiling)437Timer.setBucket(&TimeByBucket[MC->getID()]);438MC->onStartOfTranslationUnit();439}440}441442void onEndOfTranslationUnit() {443const bool EnableCheckProfiling = Options.CheckProfiling.has_value();444TimeBucketRegion Timer;445for (MatchCallback *MC : Matchers->AllCallbacks) {446if (EnableCheckProfiling)447Timer.setBucket(&TimeByBucket[MC->getID()]);448MC->onEndOfTranslationUnit();449}450}451452void set_active_ast_context(ASTContext *NewActiveASTContext) {453ActiveASTContext = NewActiveASTContext;454}455456// The following Visit*() and Traverse*() functions "override"457// methods in RecursiveASTVisitor.458459bool VisitTypedefNameDecl(TypedefNameDecl *DeclNode) {460// When we see 'typedef A B', we add name 'B' to the set of names461// A's canonical type maps to. This is necessary for implementing462// isDerivedFrom(x) properly, where x can be the name of the base463// class or any of its aliases.464//465// In general, the is-alias-of (as defined by typedefs) relation466// is tree-shaped, as you can typedef a type more than once. For467// example,468//469// typedef A B;470// typedef A C;471// typedef C D;472// typedef C E;473//474// gives you475//476// A477// |- B478// `- C479// |- D480// `- E481//482// It is wrong to assume that the relation is a chain. A correct483// implementation of isDerivedFrom() needs to recognize that B and484// E are aliases, even though neither is a typedef of the other.485// Therefore, we cannot simply walk through one typedef chain to486// find out whether the type name matches.487const Type *TypeNode = DeclNode->getUnderlyingType().getTypePtr();488const Type *CanonicalType = // root of the typedef tree489ActiveASTContext->getCanonicalType(TypeNode);490TypeAliases[CanonicalType].insert(DeclNode);491return true;492}493494bool VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *CAD) {495const ObjCInterfaceDecl *InterfaceDecl = CAD->getClassInterface();496CompatibleAliases[InterfaceDecl].insert(CAD);497return true;498}499500bool TraverseDecl(Decl *DeclNode);501bool TraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue = nullptr);502bool TraverseType(QualType TypeNode);503bool TraverseTypeLoc(TypeLoc TypeNode);504bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS);505bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS);506bool TraverseConstructorInitializer(CXXCtorInitializer *CtorInit);507bool TraverseTemplateArgumentLoc(TemplateArgumentLoc TAL);508bool TraverseAttr(Attr *AttrNode);509510bool dataTraverseNode(Stmt *S, DataRecursionQueue *Queue) {511if (auto *RF = dyn_cast<CXXForRangeStmt>(S)) {512{513ASTNodeNotAsIsSourceScope RAII(this, true);514TraverseStmt(RF->getInit());515// Don't traverse under the loop variable516match(*RF->getLoopVariable());517TraverseStmt(RF->getRangeInit());518}519{520ASTNodeNotSpelledInSourceScope RAII(this, true);521for (auto *SubStmt : RF->children()) {522if (SubStmt != RF->getBody())523TraverseStmt(SubStmt);524}525}526TraverseStmt(RF->getBody());527return true;528} else if (auto *RBO = dyn_cast<CXXRewrittenBinaryOperator>(S)) {529{530ASTNodeNotAsIsSourceScope RAII(this, true);531TraverseStmt(const_cast<Expr *>(RBO->getLHS()));532TraverseStmt(const_cast<Expr *>(RBO->getRHS()));533}534{535ASTNodeNotSpelledInSourceScope RAII(this, true);536for (auto *SubStmt : RBO->children()) {537TraverseStmt(SubStmt);538}539}540return true;541} else if (auto *LE = dyn_cast<LambdaExpr>(S)) {542for (auto I : llvm::zip(LE->captures(), LE->capture_inits())) {543auto C = std::get<0>(I);544ASTNodeNotSpelledInSourceScope RAII(545this, TraversingASTNodeNotSpelledInSource || !C.isExplicit());546TraverseLambdaCapture(LE, &C, std::get<1>(I));547}548549{550ASTNodeNotSpelledInSourceScope RAII(this, true);551TraverseDecl(LE->getLambdaClass());552}553{554ASTNodeNotAsIsSourceScope RAII(this, true);555556// We need to poke around to find the bits that might be explicitly557// written.558TypeLoc TL = LE->getCallOperator()->getTypeSourceInfo()->getTypeLoc();559FunctionProtoTypeLoc Proto = TL.getAsAdjusted<FunctionProtoTypeLoc>();560561if (auto *TPL = LE->getTemplateParameterList()) {562for (NamedDecl *D : *TPL) {563TraverseDecl(D);564}565if (Expr *RequiresClause = TPL->getRequiresClause()) {566TraverseStmt(RequiresClause);567}568}569570if (LE->hasExplicitParameters()) {571// Visit parameters.572for (ParmVarDecl *Param : Proto.getParams())573TraverseDecl(Param);574}575576const auto *T = Proto.getTypePtr();577for (const auto &E : T->exceptions())578TraverseType(E);579580if (Expr *NE = T->getNoexceptExpr())581TraverseStmt(NE, Queue);582583if (LE->hasExplicitResultType())584TraverseTypeLoc(Proto.getReturnLoc());585TraverseStmt(LE->getTrailingRequiresClause());586}587588TraverseStmt(LE->getBody());589return true;590}591return RecursiveASTVisitor<MatchASTVisitor>::dataTraverseNode(S, Queue);592}593594// Matches children or descendants of 'Node' with 'BaseMatcher'.595bool memoizedMatchesRecursively(const DynTypedNode &Node, ASTContext &Ctx,596const DynTypedMatcher &Matcher,597BoundNodesTreeBuilder *Builder, int MaxDepth,598BindKind Bind) {599// For AST-nodes that don't have an identity, we can't memoize.600if (!Node.getMemoizationData() || !Builder->isComparable())601return matchesRecursively(Node, Matcher, Builder, MaxDepth, Bind);602603MatchKey Key;604Key.MatcherID = Matcher.getID();605Key.Node = Node;606// Note that we key on the bindings *before* the match.607Key.BoundNodes = *Builder;608Key.Traversal = Ctx.getParentMapContext().getTraversalKind();609// Memoize result even doing a single-level match, it might be expensive.610Key.Type = MaxDepth == 1 ? MatchType::Child : MatchType::Descendants;611MemoizationMap::iterator I = ResultCache.find(Key);612if (I != ResultCache.end()) {613*Builder = I->second.Nodes;614return I->second.ResultOfMatch;615}616617MemoizedMatchResult Result;618Result.Nodes = *Builder;619Result.ResultOfMatch =620matchesRecursively(Node, Matcher, &Result.Nodes, MaxDepth, Bind);621622MemoizedMatchResult &CachedResult = ResultCache[Key];623CachedResult = std::move(Result);624625*Builder = CachedResult.Nodes;626return CachedResult.ResultOfMatch;627}628629// Matches children or descendants of 'Node' with 'BaseMatcher'.630bool matchesRecursively(const DynTypedNode &Node,631const DynTypedMatcher &Matcher,632BoundNodesTreeBuilder *Builder, int MaxDepth,633BindKind Bind) {634bool ScopedTraversal = TraversingASTNodeNotSpelledInSource ||635TraversingASTChildrenNotSpelledInSource;636637bool IgnoreImplicitChildren = false;638639if (isTraversalIgnoringImplicitNodes()) {640IgnoreImplicitChildren = true;641}642643ASTNodeNotSpelledInSourceScope RAII(this, ScopedTraversal);644645MatchChildASTVisitor Visitor(&Matcher, this, Builder, MaxDepth,646IgnoreImplicitChildren, Bind);647return Visitor.findMatch(Node);648}649650bool classIsDerivedFrom(const CXXRecordDecl *Declaration,651const Matcher<NamedDecl> &Base,652BoundNodesTreeBuilder *Builder,653bool Directly) override;654655private:656bool657classIsDerivedFromImpl(const CXXRecordDecl *Declaration,658const Matcher<NamedDecl> &Base,659BoundNodesTreeBuilder *Builder, bool Directly,660llvm::SmallPtrSetImpl<const CXXRecordDecl *> &Visited);661662public:663bool objcClassIsDerivedFrom(const ObjCInterfaceDecl *Declaration,664const Matcher<NamedDecl> &Base,665BoundNodesTreeBuilder *Builder,666bool Directly) override;667668public:669// Implements ASTMatchFinder::matchesChildOf.670bool matchesChildOf(const DynTypedNode &Node, ASTContext &Ctx,671const DynTypedMatcher &Matcher,672BoundNodesTreeBuilder *Builder, BindKind Bind) override {673if (ResultCache.size() > MaxMemoizationEntries)674ResultCache.clear();675return memoizedMatchesRecursively(Node, Ctx, Matcher, Builder, 1, Bind);676}677// Implements ASTMatchFinder::matchesDescendantOf.678bool matchesDescendantOf(const DynTypedNode &Node, ASTContext &Ctx,679const DynTypedMatcher &Matcher,680BoundNodesTreeBuilder *Builder,681BindKind Bind) override {682if (ResultCache.size() > MaxMemoizationEntries)683ResultCache.clear();684return memoizedMatchesRecursively(Node, Ctx, Matcher, Builder, INT_MAX,685Bind);686}687// Implements ASTMatchFinder::matchesAncestorOf.688bool matchesAncestorOf(const DynTypedNode &Node, ASTContext &Ctx,689const DynTypedMatcher &Matcher,690BoundNodesTreeBuilder *Builder,691AncestorMatchMode MatchMode) override {692// Reset the cache outside of the recursive call to make sure we693// don't invalidate any iterators.694if (ResultCache.size() > MaxMemoizationEntries)695ResultCache.clear();696if (MatchMode == AncestorMatchMode::AMM_ParentOnly)697return matchesParentOf(Node, Matcher, Builder);698return matchesAnyAncestorOf(Node, Ctx, Matcher, Builder);699}700701// Matches all registered matchers on the given node and calls the702// result callback for every node that matches.703void match(const DynTypedNode &Node) {704// FIXME: Improve this with a switch or a visitor pattern.705if (auto *N = Node.get<Decl>()) {706match(*N);707} else if (auto *N = Node.get<Stmt>()) {708match(*N);709} else if (auto *N = Node.get<Type>()) {710match(*N);711} else if (auto *N = Node.get<QualType>()) {712match(*N);713} else if (auto *N = Node.get<NestedNameSpecifier>()) {714match(*N);715} else if (auto *N = Node.get<NestedNameSpecifierLoc>()) {716match(*N);717} else if (auto *N = Node.get<TypeLoc>()) {718match(*N);719} else if (auto *N = Node.get<CXXCtorInitializer>()) {720match(*N);721} else if (auto *N = Node.get<TemplateArgumentLoc>()) {722match(*N);723} else if (auto *N = Node.get<Attr>()) {724match(*N);725}726}727728template <typename T> void match(const T &Node) {729matchDispatch(&Node);730}731732// Implements ASTMatchFinder::getASTContext.733ASTContext &getASTContext() const override { return *ActiveASTContext; }734735bool shouldVisitTemplateInstantiations() const { return true; }736bool shouldVisitImplicitCode() const { return true; }737738// We visit the lambda body explicitly, so instruct the RAV739// to not visit it on our behalf too.740bool shouldVisitLambdaBody() const { return false; }741742bool IsMatchingInASTNodeNotSpelledInSource() const override {743return TraversingASTNodeNotSpelledInSource;744}745bool isMatchingChildrenNotSpelledInSource() const override {746return TraversingASTChildrenNotSpelledInSource;747}748void setMatchingChildrenNotSpelledInSource(bool Set) override {749TraversingASTChildrenNotSpelledInSource = Set;750}751752bool IsMatchingInASTNodeNotAsIs() const override {753return TraversingASTNodeNotAsIs;754}755756bool TraverseTemplateInstantiations(ClassTemplateDecl *D) {757ASTNodeNotSpelledInSourceScope RAII(this, true);758return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateInstantiations(759D);760}761762bool TraverseTemplateInstantiations(VarTemplateDecl *D) {763ASTNodeNotSpelledInSourceScope RAII(this, true);764return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateInstantiations(765D);766}767768bool TraverseTemplateInstantiations(FunctionTemplateDecl *D) {769ASTNodeNotSpelledInSourceScope RAII(this, true);770return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateInstantiations(771D);772}773774private:775bool TraversingASTNodeNotSpelledInSource = false;776bool TraversingASTNodeNotAsIs = false;777bool TraversingASTChildrenNotSpelledInSource = false;778779class CurMatchData {780// We don't have enough free low bits in 32bit builds to discriminate 8 pointer781// types in PointerUnion. so split the union in 2 using a free bit from the782// callback pointer.783#define CMD_TYPES_0 \784const QualType *, const TypeLoc *, const NestedNameSpecifier *, \785const NestedNameSpecifierLoc *786#define CMD_TYPES_1 \787const CXXCtorInitializer *, const TemplateArgumentLoc *, const Attr *, \788const DynTypedNode *789790#define IMPL(Index) \791template <typename NodeType> \792std::enable_if_t< \793llvm::is_one_of<const NodeType *, CMD_TYPES_##Index>::value> \794SetCallbackAndRawNode(const MatchCallback *CB, const NodeType &N) { \795assertEmpty(); \796Callback.setPointerAndInt(CB, Index); \797Node##Index = &N; \798} \799\800template <typename T> \801std::enable_if_t<llvm::is_one_of<const T *, CMD_TYPES_##Index>::value, \802const T *> \803getNode() const { \804assertHoldsState(); \805return Callback.getInt() == (Index) ? Node##Index.dyn_cast<const T *>() \806: nullptr; \807}808809public:810CurMatchData() : Node0(nullptr) {}811812IMPL(0)813IMPL(1)814815const MatchCallback *getCallback() const { return Callback.getPointer(); }816817void SetBoundNodes(const BoundNodes &BN) {818assertHoldsState();819BNodes = &BN;820}821822void clearBoundNodes() {823assertHoldsState();824BNodes = nullptr;825}826827const BoundNodes *getBoundNodes() const {828assertHoldsState();829return BNodes;830}831832void reset() {833assertHoldsState();834Callback.setPointerAndInt(nullptr, 0);835Node0 = nullptr;836}837838private:839void assertHoldsState() const {840assert(Callback.getPointer() != nullptr && !Node0.isNull());841}842843void assertEmpty() const {844assert(Callback.getPointer() == nullptr && Node0.isNull() &&845BNodes == nullptr);846}847848llvm::PointerIntPair<const MatchCallback *, 1> Callback;849union {850llvm::PointerUnion<CMD_TYPES_0> Node0;851llvm::PointerUnion<CMD_TYPES_1> Node1;852};853const BoundNodes *BNodes = nullptr;854855#undef CMD_TYPES_0856#undef CMD_TYPES_1857#undef IMPL858} CurMatchState;859860struct CurMatchRAII {861template <typename NodeType>862CurMatchRAII(MatchASTVisitor &MV, const MatchCallback *CB,863const NodeType &NT)864: MV(MV) {865MV.CurMatchState.SetCallbackAndRawNode(CB, NT);866}867868~CurMatchRAII() { MV.CurMatchState.reset(); }869870private:871MatchASTVisitor &MV;872};873874public:875class TraceReporter : llvm::PrettyStackTraceEntry {876static void dumpNode(const ASTContext &Ctx, const DynTypedNode &Node,877raw_ostream &OS) {878if (const auto *D = Node.get<Decl>()) {879OS << D->getDeclKindName() << "Decl ";880if (const auto *ND = dyn_cast<NamedDecl>(D)) {881ND->printQualifiedName(OS);882OS << " : ";883} else884OS << ": ";885D->getSourceRange().print(OS, Ctx.getSourceManager());886} else if (const auto *S = Node.get<Stmt>()) {887OS << S->getStmtClassName() << " : ";888S->getSourceRange().print(OS, Ctx.getSourceManager());889} else if (const auto *T = Node.get<Type>()) {890OS << T->getTypeClassName() << "Type : ";891QualType(T, 0).print(OS, Ctx.getPrintingPolicy());892} else if (const auto *QT = Node.get<QualType>()) {893OS << "QualType : ";894QT->print(OS, Ctx.getPrintingPolicy());895} else {896OS << Node.getNodeKind().asStringRef() << " : ";897Node.getSourceRange().print(OS, Ctx.getSourceManager());898}899}900901static void dumpNodeFromState(const ASTContext &Ctx,902const CurMatchData &State, raw_ostream &OS) {903if (const DynTypedNode *MatchNode = State.getNode<DynTypedNode>()) {904dumpNode(Ctx, *MatchNode, OS);905} else if (const auto *QT = State.getNode<QualType>()) {906dumpNode(Ctx, DynTypedNode::create(*QT), OS);907} else if (const auto *TL = State.getNode<TypeLoc>()) {908dumpNode(Ctx, DynTypedNode::create(*TL), OS);909} else if (const auto *NNS = State.getNode<NestedNameSpecifier>()) {910dumpNode(Ctx, DynTypedNode::create(*NNS), OS);911} else if (const auto *NNSL = State.getNode<NestedNameSpecifierLoc>()) {912dumpNode(Ctx, DynTypedNode::create(*NNSL), OS);913} else if (const auto *CtorInit = State.getNode<CXXCtorInitializer>()) {914dumpNode(Ctx, DynTypedNode::create(*CtorInit), OS);915} else if (const auto *TAL = State.getNode<TemplateArgumentLoc>()) {916dumpNode(Ctx, DynTypedNode::create(*TAL), OS);917} else if (const auto *At = State.getNode<Attr>()) {918dumpNode(Ctx, DynTypedNode::create(*At), OS);919}920}921922public:923TraceReporter(const MatchASTVisitor &MV) : MV(MV) {}924void print(raw_ostream &OS) const override {925const CurMatchData &State = MV.CurMatchState;926const MatchCallback *CB = State.getCallback();927if (!CB) {928OS << "ASTMatcher: Not currently matching\n";929return;930}931932assert(MV.ActiveASTContext &&933"ActiveASTContext should be set if there is a matched callback");934935ASTContext &Ctx = MV.getASTContext();936937if (const BoundNodes *Nodes = State.getBoundNodes()) {938OS << "ASTMatcher: Processing '" << CB->getID() << "' against:\n\t";939dumpNodeFromState(Ctx, State, OS);940const BoundNodes::IDToNodeMap &Map = Nodes->getMap();941if (Map.empty()) {942OS << "\nNo bound nodes\n";943return;944}945OS << "\n--- Bound Nodes Begin ---\n";946for (const auto &Item : Map) {947OS << " " << Item.first << " - { ";948dumpNode(Ctx, Item.second, OS);949OS << " }\n";950}951OS << "--- Bound Nodes End ---\n";952} else {953OS << "ASTMatcher: Matching '" << CB->getID() << "' against:\n\t";954dumpNodeFromState(Ctx, State, OS);955OS << '\n';956}957}958959private:960const MatchASTVisitor &MV;961};962963private:964struct ASTNodeNotSpelledInSourceScope {965ASTNodeNotSpelledInSourceScope(MatchASTVisitor *V, bool B)966: MV(V), MB(V->TraversingASTNodeNotSpelledInSource) {967V->TraversingASTNodeNotSpelledInSource = B;968}969~ASTNodeNotSpelledInSourceScope() {970MV->TraversingASTNodeNotSpelledInSource = MB;971}972973private:974MatchASTVisitor *MV;975bool MB;976};977978struct ASTNodeNotAsIsSourceScope {979ASTNodeNotAsIsSourceScope(MatchASTVisitor *V, bool B)980: MV(V), MB(V->TraversingASTNodeNotAsIs) {981V->TraversingASTNodeNotAsIs = B;982}983~ASTNodeNotAsIsSourceScope() { MV->TraversingASTNodeNotAsIs = MB; }984985private:986MatchASTVisitor *MV;987bool MB;988};989990class TimeBucketRegion {991public:992TimeBucketRegion() = default;993~TimeBucketRegion() { setBucket(nullptr); }994995/// Start timing for \p NewBucket.996///997/// If there was a bucket already set, it will finish the timing for that998/// other bucket.999/// \p NewBucket will be timed until the next call to \c setBucket() or1000/// until the \c TimeBucketRegion is destroyed.1001/// If \p NewBucket is the same as the currently timed bucket, this call1002/// does nothing.1003void setBucket(llvm::TimeRecord *NewBucket) {1004if (Bucket != NewBucket) {1005auto Now = llvm::TimeRecord::getCurrentTime(true);1006if (Bucket)1007*Bucket += Now;1008if (NewBucket)1009*NewBucket -= Now;1010Bucket = NewBucket;1011}1012}10131014private:1015llvm::TimeRecord *Bucket = nullptr;1016};10171018/// Runs all the \p Matchers on \p Node.1019///1020/// Used by \c matchDispatch() below.1021template <typename T, typename MC>1022void matchWithoutFilter(const T &Node, const MC &Matchers) {1023const bool EnableCheckProfiling = Options.CheckProfiling.has_value();1024TimeBucketRegion Timer;1025for (const auto &MP : Matchers) {1026if (EnableCheckProfiling)1027Timer.setBucket(&TimeByBucket[MP.second->getID()]);1028BoundNodesTreeBuilder Builder;1029CurMatchRAII RAII(*this, MP.second, Node);1030if (MP.first.matches(Node, this, &Builder)) {1031MatchVisitor Visitor(*this, ActiveASTContext, MP.second);1032Builder.visitMatches(&Visitor);1033}1034}1035}10361037void matchWithFilter(const DynTypedNode &DynNode) {1038auto Kind = DynNode.getNodeKind();1039auto it = MatcherFiltersMap.find(Kind);1040const auto &Filter =1041it != MatcherFiltersMap.end() ? it->second : getFilterForKind(Kind);10421043if (Filter.empty())1044return;10451046const bool EnableCheckProfiling = Options.CheckProfiling.has_value();1047TimeBucketRegion Timer;1048auto &Matchers = this->Matchers->DeclOrStmt;1049for (unsigned short I : Filter) {1050auto &MP = Matchers[I];1051if (EnableCheckProfiling)1052Timer.setBucket(&TimeByBucket[MP.second->getID()]);1053BoundNodesTreeBuilder Builder;10541055{1056TraversalKindScope RAII(getASTContext(), MP.first.getTraversalKind());1057if (getASTContext().getParentMapContext().traverseIgnored(DynNode) !=1058DynNode)1059continue;1060}10611062CurMatchRAII RAII(*this, MP.second, DynNode);1063if (MP.first.matches(DynNode, this, &Builder)) {1064MatchVisitor Visitor(*this, ActiveASTContext, MP.second);1065Builder.visitMatches(&Visitor);1066}1067}1068}10691070const std::vector<unsigned short> &getFilterForKind(ASTNodeKind Kind) {1071auto &Filter = MatcherFiltersMap[Kind];1072auto &Matchers = this->Matchers->DeclOrStmt;1073assert((Matchers.size() < USHRT_MAX) && "Too many matchers.");1074for (unsigned I = 0, E = Matchers.size(); I != E; ++I) {1075if (Matchers[I].first.canMatchNodesOfKind(Kind)) {1076Filter.push_back(I);1077}1078}1079return Filter;1080}10811082/// @{1083/// Overloads to pair the different node types to their matchers.1084void matchDispatch(const Decl *Node) {1085return matchWithFilter(DynTypedNode::create(*Node));1086}1087void matchDispatch(const Stmt *Node) {1088return matchWithFilter(DynTypedNode::create(*Node));1089}10901091void matchDispatch(const Type *Node) {1092matchWithoutFilter(QualType(Node, 0), Matchers->Type);1093}1094void matchDispatch(const TypeLoc *Node) {1095matchWithoutFilter(*Node, Matchers->TypeLoc);1096}1097void matchDispatch(const QualType *Node) {1098matchWithoutFilter(*Node, Matchers->Type);1099}1100void matchDispatch(const NestedNameSpecifier *Node) {1101matchWithoutFilter(*Node, Matchers->NestedNameSpecifier);1102}1103void matchDispatch(const NestedNameSpecifierLoc *Node) {1104matchWithoutFilter(*Node, Matchers->NestedNameSpecifierLoc);1105}1106void matchDispatch(const CXXCtorInitializer *Node) {1107matchWithoutFilter(*Node, Matchers->CtorInit);1108}1109void matchDispatch(const TemplateArgumentLoc *Node) {1110matchWithoutFilter(*Node, Matchers->TemplateArgumentLoc);1111}1112void matchDispatch(const Attr *Node) {1113matchWithoutFilter(*Node, Matchers->Attr);1114}1115void matchDispatch(const void *) { /* Do nothing. */ }1116/// @}11171118// Returns whether a direct parent of \p Node matches \p Matcher.1119// Unlike matchesAnyAncestorOf there's no memoization: it doesn't save much.1120bool matchesParentOf(const DynTypedNode &Node, const DynTypedMatcher &Matcher,1121BoundNodesTreeBuilder *Builder) {1122for (const auto &Parent : ActiveASTContext->getParents(Node)) {1123BoundNodesTreeBuilder BuilderCopy = *Builder;1124if (Matcher.matches(Parent, this, &BuilderCopy)) {1125*Builder = std::move(BuilderCopy);1126return true;1127}1128}1129return false;1130}11311132// Returns whether an ancestor of \p Node matches \p Matcher.1133//1134// The order of matching (which can lead to different nodes being bound in1135// case there are multiple matches) is breadth first search.1136//1137// To allow memoization in the very common case of having deeply nested1138// expressions inside a template function, we first walk up the AST, memoizing1139// the result of the match along the way, as long as there is only a single1140// parent.1141//1142// Once there are multiple parents, the breadth first search order does not1143// allow simple memoization on the ancestors. Thus, we only memoize as long1144// as there is a single parent.1145//1146// We avoid a recursive implementation to prevent excessive stack use on1147// very deep ASTs (similarly to RecursiveASTVisitor's data recursion).1148bool matchesAnyAncestorOf(DynTypedNode Node, ASTContext &Ctx,1149const DynTypedMatcher &Matcher,1150BoundNodesTreeBuilder *Builder) {11511152// Memoization keys that can be updated with the result.1153// These are the memoizable nodes in the chain of unique parents, which1154// terminates when a node has multiple parents, or matches, or is the root.1155std::vector<MatchKey> Keys;1156// When returning, update the memoization cache.1157auto Finish = [&](bool Matched) {1158for (const auto &Key : Keys) {1159MemoizedMatchResult &CachedResult = ResultCache[Key];1160CachedResult.ResultOfMatch = Matched;1161CachedResult.Nodes = *Builder;1162}1163return Matched;1164};11651166// Loop while there's a single parent and we want to attempt memoization.1167DynTypedNodeList Parents{ArrayRef<DynTypedNode>()}; // after loop: size != 11168for (;;) {1169// A cache key only makes sense if memoization is possible.1170if (Builder->isComparable()) {1171Keys.emplace_back();1172Keys.back().MatcherID = Matcher.getID();1173Keys.back().Node = Node;1174Keys.back().BoundNodes = *Builder;1175Keys.back().Traversal = Ctx.getParentMapContext().getTraversalKind();1176Keys.back().Type = MatchType::Ancestors;11771178// Check the cache.1179MemoizationMap::iterator I = ResultCache.find(Keys.back());1180if (I != ResultCache.end()) {1181Keys.pop_back(); // Don't populate the cache for the matching node!1182*Builder = I->second.Nodes;1183return Finish(I->second.ResultOfMatch);1184}1185}11861187Parents = ActiveASTContext->getParents(Node);1188// Either no parents or multiple parents: leave chain+memoize mode and1189// enter bfs+forgetful mode.1190if (Parents.size() != 1)1191break;11921193// Check the next parent.1194Node = *Parents.begin();1195BoundNodesTreeBuilder BuilderCopy = *Builder;1196if (Matcher.matches(Node, this, &BuilderCopy)) {1197*Builder = std::move(BuilderCopy);1198return Finish(true);1199}1200}1201// We reached the end of the chain.12021203if (Parents.empty()) {1204// Nodes may have no parents if:1205// a) the node is the TranslationUnitDecl1206// b) we have a limited traversal scope that excludes the parent edges1207// c) there is a bug in the AST, and the node is not reachable1208// Usually the traversal scope is the whole AST, which precludes b.1209// Bugs are common enough that it's worthwhile asserting when we can.1210#ifndef NDEBUG1211if (!Node.get<TranslationUnitDecl>() &&1212/* Traversal scope is full AST if any of the bounds are the TU */1213llvm::any_of(ActiveASTContext->getTraversalScope(), [](Decl *D) {1214return D->getKind() == Decl::TranslationUnit;1215})) {1216llvm::errs() << "Tried to match orphan node:\n";1217Node.dump(llvm::errs(), *ActiveASTContext);1218llvm_unreachable("Parent map should be complete!");1219}1220#endif1221} else {1222assert(Parents.size() > 1);1223// BFS starting from the parents not yet considered.1224// Memoization of newly visited nodes is not possible (but we still update1225// results for the elements in the chain we found above).1226std::deque<DynTypedNode> Queue(Parents.begin(), Parents.end());1227llvm::DenseSet<const void *> Visited;1228while (!Queue.empty()) {1229BoundNodesTreeBuilder BuilderCopy = *Builder;1230if (Matcher.matches(Queue.front(), this, &BuilderCopy)) {1231*Builder = std::move(BuilderCopy);1232return Finish(true);1233}1234for (const auto &Parent : ActiveASTContext->getParents(Queue.front())) {1235// Make sure we do not visit the same node twice.1236// Otherwise, we'll visit the common ancestors as often as there1237// are splits on the way down.1238if (Visited.insert(Parent.getMemoizationData()).second)1239Queue.push_back(Parent);1240}1241Queue.pop_front();1242}1243}1244return Finish(false);1245}12461247// Implements a BoundNodesTree::Visitor that calls a MatchCallback with1248// the aggregated bound nodes for each match.1249class MatchVisitor : public BoundNodesTreeBuilder::Visitor {1250struct CurBoundScope {1251CurBoundScope(MatchASTVisitor::CurMatchData &State, const BoundNodes &BN)1252: State(State) {1253State.SetBoundNodes(BN);1254}12551256~CurBoundScope() { State.clearBoundNodes(); }12571258private:1259MatchASTVisitor::CurMatchData &State;1260};12611262public:1263MatchVisitor(MatchASTVisitor &MV, ASTContext *Context,1264MatchFinder::MatchCallback *Callback)1265: State(MV.CurMatchState), Context(Context), Callback(Callback) {}12661267void visitMatch(const BoundNodes& BoundNodesView) override {1268TraversalKindScope RAII(*Context, Callback->getCheckTraversalKind());1269CurBoundScope RAII2(State, BoundNodesView);1270Callback->run(MatchFinder::MatchResult(BoundNodesView, Context));1271}12721273private:1274MatchASTVisitor::CurMatchData &State;1275ASTContext* Context;1276MatchFinder::MatchCallback* Callback;1277};12781279// Returns true if 'TypeNode' has an alias that matches the given matcher.1280bool typeHasMatchingAlias(const Type *TypeNode,1281const Matcher<NamedDecl> &Matcher,1282BoundNodesTreeBuilder *Builder) {1283const Type *const CanonicalType =1284ActiveASTContext->getCanonicalType(TypeNode);1285auto Aliases = TypeAliases.find(CanonicalType);1286if (Aliases == TypeAliases.end())1287return false;1288for (const TypedefNameDecl *Alias : Aliases->second) {1289BoundNodesTreeBuilder Result(*Builder);1290if (Matcher.matches(*Alias, this, &Result)) {1291*Builder = std::move(Result);1292return true;1293}1294}1295return false;1296}12971298bool1299objcClassHasMatchingCompatibilityAlias(const ObjCInterfaceDecl *InterfaceDecl,1300const Matcher<NamedDecl> &Matcher,1301BoundNodesTreeBuilder *Builder) {1302auto Aliases = CompatibleAliases.find(InterfaceDecl);1303if (Aliases == CompatibleAliases.end())1304return false;1305for (const ObjCCompatibleAliasDecl *Alias : Aliases->second) {1306BoundNodesTreeBuilder Result(*Builder);1307if (Matcher.matches(*Alias, this, &Result)) {1308*Builder = std::move(Result);1309return true;1310}1311}1312return false;1313}13141315/// Bucket to record map.1316///1317/// Used to get the appropriate bucket for each matcher.1318llvm::StringMap<llvm::TimeRecord> TimeByBucket;13191320const MatchFinder::MatchersByType *Matchers;13211322/// Filtered list of matcher indices for each matcher kind.1323///1324/// \c Decl and \c Stmt toplevel matchers usually apply to a specific node1325/// kind (and derived kinds) so it is a waste to try every matcher on every1326/// node.1327/// We precalculate a list of matchers that pass the toplevel restrict check.1328llvm::DenseMap<ASTNodeKind, std::vector<unsigned short>> MatcherFiltersMap;13291330const MatchFinder::MatchFinderOptions &Options;1331ASTContext *ActiveASTContext;13321333// Maps a canonical type to its TypedefDecls.1334llvm::DenseMap<const Type*, std::set<const TypedefNameDecl*> > TypeAliases;13351336// Maps an Objective-C interface to its ObjCCompatibleAliasDecls.1337llvm::DenseMap<const ObjCInterfaceDecl *,1338llvm::SmallPtrSet<const ObjCCompatibleAliasDecl *, 2>>1339CompatibleAliases;13401341// Maps (matcher, node) -> the match result for memoization.1342typedef std::map<MatchKey, MemoizedMatchResult> MemoizationMap;1343MemoizationMap ResultCache;1344};13451346static CXXRecordDecl *1347getAsCXXRecordDeclOrPrimaryTemplate(const Type *TypeNode) {1348if (auto *RD = TypeNode->getAsCXXRecordDecl())1349return RD;13501351// Find the innermost TemplateSpecializationType that isn't an alias template.1352auto *TemplateType = TypeNode->getAs<TemplateSpecializationType>();1353while (TemplateType && TemplateType->isTypeAlias())1354TemplateType =1355TemplateType->getAliasedType()->getAs<TemplateSpecializationType>();13561357// If this is the name of a (dependent) template specialization, use the1358// definition of the template, even though it might be specialized later.1359if (TemplateType)1360if (auto *ClassTemplate = dyn_cast_or_null<ClassTemplateDecl>(1361TemplateType->getTemplateName().getAsTemplateDecl()))1362return ClassTemplate->getTemplatedDecl();13631364return nullptr;1365}13661367// Returns true if the given C++ class is directly or indirectly derived1368// from a base type with the given name. A class is not considered to be1369// derived from itself.1370bool MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration,1371const Matcher<NamedDecl> &Base,1372BoundNodesTreeBuilder *Builder,1373bool Directly) {1374llvm::SmallPtrSet<const CXXRecordDecl *, 8> Visited;1375return classIsDerivedFromImpl(Declaration, Base, Builder, Directly, Visited);1376}13771378bool MatchASTVisitor::classIsDerivedFromImpl(1379const CXXRecordDecl *Declaration, const Matcher<NamedDecl> &Base,1380BoundNodesTreeBuilder *Builder, bool Directly,1381llvm::SmallPtrSetImpl<const CXXRecordDecl *> &Visited) {1382if (!Declaration->hasDefinition())1383return false;1384if (!Visited.insert(Declaration).second)1385return false;1386for (const auto &It : Declaration->bases()) {1387const Type *TypeNode = It.getType().getTypePtr();13881389if (typeHasMatchingAlias(TypeNode, Base, Builder))1390return true;13911392// FIXME: Going to the primary template here isn't really correct, but1393// unfortunately we accept a Decl matcher for the base class not a Type1394// matcher, so it's the best thing we can do with our current interface.1395CXXRecordDecl *ClassDecl = getAsCXXRecordDeclOrPrimaryTemplate(TypeNode);1396if (!ClassDecl)1397continue;1398if (ClassDecl == Declaration) {1399// This can happen for recursive template definitions.1400continue;1401}1402BoundNodesTreeBuilder Result(*Builder);1403if (Base.matches(*ClassDecl, this, &Result)) {1404*Builder = std::move(Result);1405return true;1406}1407if (!Directly &&1408classIsDerivedFromImpl(ClassDecl, Base, Builder, Directly, Visited))1409return true;1410}1411return false;1412}14131414// Returns true if the given Objective-C class is directly or indirectly1415// derived from a matching base class. A class is not considered to be derived1416// from itself.1417bool MatchASTVisitor::objcClassIsDerivedFrom(1418const ObjCInterfaceDecl *Declaration, const Matcher<NamedDecl> &Base,1419BoundNodesTreeBuilder *Builder, bool Directly) {1420// Check if any of the superclasses of the class match.1421for (const ObjCInterfaceDecl *ClassDecl = Declaration->getSuperClass();1422ClassDecl != nullptr; ClassDecl = ClassDecl->getSuperClass()) {1423// Check if there are any matching compatibility aliases.1424if (objcClassHasMatchingCompatibilityAlias(ClassDecl, Base, Builder))1425return true;14261427// Check if there are any matching type aliases.1428const Type *TypeNode = ClassDecl->getTypeForDecl();1429if (typeHasMatchingAlias(TypeNode, Base, Builder))1430return true;14311432if (Base.matches(*ClassDecl, this, Builder))1433return true;14341435// Not `return false` as a temporary workaround for PR43879.1436if (Directly)1437break;1438}14391440return false;1441}14421443bool MatchASTVisitor::TraverseDecl(Decl *DeclNode) {1444if (!DeclNode) {1445return true;1446}14471448bool ScopedTraversal =1449TraversingASTNodeNotSpelledInSource || DeclNode->isImplicit();1450bool ScopedChildren = TraversingASTChildrenNotSpelledInSource;14511452if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(DeclNode)) {1453auto SK = CTSD->getSpecializationKind();1454if (SK == TSK_ExplicitInstantiationDeclaration ||1455SK == TSK_ExplicitInstantiationDefinition)1456ScopedChildren = true;1457} else if (const auto *FD = dyn_cast<FunctionDecl>(DeclNode)) {1458if (FD->isDefaulted())1459ScopedChildren = true;1460if (FD->isTemplateInstantiation())1461ScopedTraversal = true;1462} else if (isa<BindingDecl>(DeclNode)) {1463ScopedChildren = true;1464}14651466ASTNodeNotSpelledInSourceScope RAII1(this, ScopedTraversal);1467ASTChildrenNotSpelledInSourceScope RAII2(this, ScopedChildren);14681469match(*DeclNode);1470return RecursiveASTVisitor<MatchASTVisitor>::TraverseDecl(DeclNode);1471}14721473bool MatchASTVisitor::TraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue) {1474if (!StmtNode) {1475return true;1476}1477bool ScopedTraversal = TraversingASTNodeNotSpelledInSource ||1478TraversingASTChildrenNotSpelledInSource;14791480ASTNodeNotSpelledInSourceScope RAII(this, ScopedTraversal);1481match(*StmtNode);1482return RecursiveASTVisitor<MatchASTVisitor>::TraverseStmt(StmtNode, Queue);1483}14841485bool MatchASTVisitor::TraverseType(QualType TypeNode) {1486match(TypeNode);1487return RecursiveASTVisitor<MatchASTVisitor>::TraverseType(TypeNode);1488}14891490bool MatchASTVisitor::TraverseTypeLoc(TypeLoc TypeLocNode) {1491// The RecursiveASTVisitor only visits types if they're not within TypeLocs.1492// We still want to find those types via matchers, so we match them here. Note1493// that the TypeLocs are structurally a shadow-hierarchy to the expressed1494// type, so we visit all involved parts of a compound type when matching on1495// each TypeLoc.1496match(TypeLocNode);1497match(TypeLocNode.getType());1498return RecursiveASTVisitor<MatchASTVisitor>::TraverseTypeLoc(TypeLocNode);1499}15001501bool MatchASTVisitor::TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) {1502match(*NNS);1503return RecursiveASTVisitor<MatchASTVisitor>::TraverseNestedNameSpecifier(NNS);1504}15051506bool MatchASTVisitor::TraverseNestedNameSpecifierLoc(1507NestedNameSpecifierLoc NNS) {1508if (!NNS)1509return true;15101511match(NNS);15121513// We only match the nested name specifier here (as opposed to traversing it)1514// because the traversal is already done in the parallel "Loc"-hierarchy.1515if (NNS.hasQualifier())1516match(*NNS.getNestedNameSpecifier());1517return1518RecursiveASTVisitor<MatchASTVisitor>::TraverseNestedNameSpecifierLoc(NNS);1519}15201521bool MatchASTVisitor::TraverseConstructorInitializer(1522CXXCtorInitializer *CtorInit) {1523if (!CtorInit)1524return true;15251526bool ScopedTraversal = TraversingASTNodeNotSpelledInSource ||1527TraversingASTChildrenNotSpelledInSource;15281529if (!CtorInit->isWritten())1530ScopedTraversal = true;15311532ASTNodeNotSpelledInSourceScope RAII1(this, ScopedTraversal);15331534match(*CtorInit);15351536return RecursiveASTVisitor<MatchASTVisitor>::TraverseConstructorInitializer(1537CtorInit);1538}15391540bool MatchASTVisitor::TraverseTemplateArgumentLoc(TemplateArgumentLoc Loc) {1541match(Loc);1542return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateArgumentLoc(Loc);1543}15441545bool MatchASTVisitor::TraverseAttr(Attr *AttrNode) {1546match(*AttrNode);1547return RecursiveASTVisitor<MatchASTVisitor>::TraverseAttr(AttrNode);1548}15491550class MatchASTConsumer : public ASTConsumer {1551public:1552MatchASTConsumer(MatchFinder *Finder,1553MatchFinder::ParsingDoneTestCallback *ParsingDone)1554: Finder(Finder), ParsingDone(ParsingDone) {}15551556private:1557void HandleTranslationUnit(ASTContext &Context) override {1558if (ParsingDone != nullptr) {1559ParsingDone->run();1560}1561Finder->matchAST(Context);1562}15631564MatchFinder *Finder;1565MatchFinder::ParsingDoneTestCallback *ParsingDone;1566};15671568} // end namespace1569} // end namespace internal15701571MatchFinder::MatchResult::MatchResult(const BoundNodes &Nodes,1572ASTContext *Context)1573: Nodes(Nodes), Context(Context),1574SourceManager(&Context->getSourceManager()) {}15751576MatchFinder::MatchCallback::~MatchCallback() {}1577MatchFinder::ParsingDoneTestCallback::~ParsingDoneTestCallback() {}15781579MatchFinder::MatchFinder(MatchFinderOptions Options)1580: Options(std::move(Options)), ParsingDone(nullptr) {}15811582MatchFinder::~MatchFinder() {}15831584void MatchFinder::addMatcher(const DeclarationMatcher &NodeMatch,1585MatchCallback *Action) {1586std::optional<TraversalKind> TK;1587if (Action)1588TK = Action->getCheckTraversalKind();1589if (TK)1590Matchers.DeclOrStmt.emplace_back(traverse(*TK, NodeMatch), Action);1591else1592Matchers.DeclOrStmt.emplace_back(NodeMatch, Action);1593Matchers.AllCallbacks.insert(Action);1594}15951596void MatchFinder::addMatcher(const TypeMatcher &NodeMatch,1597MatchCallback *Action) {1598Matchers.Type.emplace_back(NodeMatch, Action);1599Matchers.AllCallbacks.insert(Action);1600}16011602void MatchFinder::addMatcher(const StatementMatcher &NodeMatch,1603MatchCallback *Action) {1604std::optional<TraversalKind> TK;1605if (Action)1606TK = Action->getCheckTraversalKind();1607if (TK)1608Matchers.DeclOrStmt.emplace_back(traverse(*TK, NodeMatch), Action);1609else1610Matchers.DeclOrStmt.emplace_back(NodeMatch, Action);1611Matchers.AllCallbacks.insert(Action);1612}16131614void MatchFinder::addMatcher(const NestedNameSpecifierMatcher &NodeMatch,1615MatchCallback *Action) {1616Matchers.NestedNameSpecifier.emplace_back(NodeMatch, Action);1617Matchers.AllCallbacks.insert(Action);1618}16191620void MatchFinder::addMatcher(const NestedNameSpecifierLocMatcher &NodeMatch,1621MatchCallback *Action) {1622Matchers.NestedNameSpecifierLoc.emplace_back(NodeMatch, Action);1623Matchers.AllCallbacks.insert(Action);1624}16251626void MatchFinder::addMatcher(const TypeLocMatcher &NodeMatch,1627MatchCallback *Action) {1628Matchers.TypeLoc.emplace_back(NodeMatch, Action);1629Matchers.AllCallbacks.insert(Action);1630}16311632void MatchFinder::addMatcher(const CXXCtorInitializerMatcher &NodeMatch,1633MatchCallback *Action) {1634Matchers.CtorInit.emplace_back(NodeMatch, Action);1635Matchers.AllCallbacks.insert(Action);1636}16371638void MatchFinder::addMatcher(const TemplateArgumentLocMatcher &NodeMatch,1639MatchCallback *Action) {1640Matchers.TemplateArgumentLoc.emplace_back(NodeMatch, Action);1641Matchers.AllCallbacks.insert(Action);1642}16431644void MatchFinder::addMatcher(const AttrMatcher &AttrMatch,1645MatchCallback *Action) {1646Matchers.Attr.emplace_back(AttrMatch, Action);1647Matchers.AllCallbacks.insert(Action);1648}16491650bool MatchFinder::addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch,1651MatchCallback *Action) {1652if (NodeMatch.canConvertTo<Decl>()) {1653addMatcher(NodeMatch.convertTo<Decl>(), Action);1654return true;1655} else if (NodeMatch.canConvertTo<QualType>()) {1656addMatcher(NodeMatch.convertTo<QualType>(), Action);1657return true;1658} else if (NodeMatch.canConvertTo<Stmt>()) {1659addMatcher(NodeMatch.convertTo<Stmt>(), Action);1660return true;1661} else if (NodeMatch.canConvertTo<NestedNameSpecifier>()) {1662addMatcher(NodeMatch.convertTo<NestedNameSpecifier>(), Action);1663return true;1664} else if (NodeMatch.canConvertTo<NestedNameSpecifierLoc>()) {1665addMatcher(NodeMatch.convertTo<NestedNameSpecifierLoc>(), Action);1666return true;1667} else if (NodeMatch.canConvertTo<TypeLoc>()) {1668addMatcher(NodeMatch.convertTo<TypeLoc>(), Action);1669return true;1670} else if (NodeMatch.canConvertTo<CXXCtorInitializer>()) {1671addMatcher(NodeMatch.convertTo<CXXCtorInitializer>(), Action);1672return true;1673} else if (NodeMatch.canConvertTo<TemplateArgumentLoc>()) {1674addMatcher(NodeMatch.convertTo<TemplateArgumentLoc>(), Action);1675return true;1676} else if (NodeMatch.canConvertTo<Attr>()) {1677addMatcher(NodeMatch.convertTo<Attr>(), Action);1678return true;1679}1680return false;1681}16821683std::unique_ptr<ASTConsumer> MatchFinder::newASTConsumer() {1684return std::make_unique<internal::MatchASTConsumer>(this, ParsingDone);1685}16861687void MatchFinder::match(const clang::DynTypedNode &Node, ASTContext &Context) {1688internal::MatchASTVisitor Visitor(&Matchers, Options);1689Visitor.set_active_ast_context(&Context);1690Visitor.match(Node);1691}16921693void MatchFinder::matchAST(ASTContext &Context) {1694internal::MatchASTVisitor Visitor(&Matchers, Options);1695internal::MatchASTVisitor::TraceReporter StackTrace(Visitor);1696Visitor.set_active_ast_context(&Context);1697Visitor.onStartOfTranslationUnit();1698Visitor.TraverseAST(Context);1699Visitor.onEndOfTranslationUnit();1700}17011702void MatchFinder::registerTestCallbackAfterParsing(1703MatchFinder::ParsingDoneTestCallback *NewParsingDone) {1704ParsingDone = NewParsingDone;1705}17061707StringRef MatchFinder::MatchCallback::getID() const { return "<unknown>"; }17081709std::optional<TraversalKind>1710MatchFinder::MatchCallback::getCheckTraversalKind() const {1711return std::nullopt;1712}17131714} // end namespace ast_matchers1715} // end namespace clang171617171718