12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694 |
- //===--- ASTMatchFinder.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 an algorithm to efficiently search for matches on AST nodes.
- // Uses memoization to support recursive matches like HasDescendant.
- //
- // The general idea is to visit all AST nodes with a RecursiveASTVisitor,
- // calling the Matches(...) method of each matcher we are running on each
- // AST node. The matcher can recurse via the ASTMatchFinder interface.
- //
- //===----------------------------------------------------------------------===//
- #include "clang/ASTMatchers/ASTMatchFinder.h"
- #include "clang/AST/ASTConsumer.h"
- #include "clang/AST/ASTContext.h"
- #include "clang/AST/RecursiveASTVisitor.h"
- #include "llvm/ADT/DenseMap.h"
- #include "llvm/ADT/StringMap.h"
- #include "llvm/Support/PrettyStackTrace.h"
- #include "llvm/Support/Timer.h"
- #include <deque>
- #include <memory>
- #include <set>
- namespace clang {
- namespace ast_matchers {
- namespace internal {
- namespace {
- typedef MatchFinder::MatchCallback MatchCallback;
- // The maximum number of memoization entries to store.
- // 10k has been experimentally found to give a good trade-off
- // of performance vs. memory consumption by running matcher
- // that match on every statement over a very large codebase.
- //
- // FIXME: Do some performance optimization in general and
- // revisit this number; also, put up micro-benchmarks that we can
- // optimize this on.
- static const unsigned MaxMemoizationEntries = 10000;
- enum class MatchType {
- Ancestors,
- Descendants,
- Child,
- };
- // We use memoization to avoid running the same matcher on the same
- // AST node twice. This struct is the key for looking up match
- // result. It consists of an ID of the MatcherInterface (for
- // identifying the matcher), a pointer to the AST node and the
- // bound nodes before the matcher was executed.
- //
- // We currently only memoize on nodes whose pointers identify the
- // nodes (\c Stmt and \c Decl, but not \c QualType or \c TypeLoc).
- // For \c QualType and \c TypeLoc it is possible to implement
- // generation of keys for each type.
- // FIXME: Benchmark whether memoization of non-pointer typed nodes
- // provides enough benefit for the additional amount of code.
- struct MatchKey {
- DynTypedMatcher::MatcherIDType MatcherID;
- DynTypedNode Node;
- BoundNodesTreeBuilder BoundNodes;
- TraversalKind Traversal = TK_AsIs;
- MatchType Type;
- bool operator<(const MatchKey &Other) const {
- return std::tie(Traversal, Type, MatcherID, Node, BoundNodes) <
- std::tie(Other.Traversal, Other.Type, Other.MatcherID, Other.Node,
- Other.BoundNodes);
- }
- };
- // Used to store the result of a match and possibly bound nodes.
- struct MemoizedMatchResult {
- bool ResultOfMatch;
- BoundNodesTreeBuilder Nodes;
- };
- // A RecursiveASTVisitor that traverses all children or all descendants of
- // a node.
- class MatchChildASTVisitor
- : public RecursiveASTVisitor<MatchChildASTVisitor> {
- public:
- typedef RecursiveASTVisitor<MatchChildASTVisitor> VisitorBase;
- // Creates an AST visitor that matches 'matcher' on all children or
- // descendants of a traversed node. max_depth is the maximum depth
- // to traverse: use 1 for matching the children and INT_MAX for
- // matching the descendants.
- MatchChildASTVisitor(const DynTypedMatcher *Matcher, ASTMatchFinder *Finder,
- BoundNodesTreeBuilder *Builder, int MaxDepth,
- bool IgnoreImplicitChildren,
- ASTMatchFinder::BindKind Bind)
- : Matcher(Matcher), Finder(Finder), Builder(Builder), CurrentDepth(0),
- MaxDepth(MaxDepth), IgnoreImplicitChildren(IgnoreImplicitChildren),
- Bind(Bind), Matches(false) {}
- // Returns true if a match is found in the subtree rooted at the
- // given AST node. This is done via a set of mutually recursive
- // functions. Here's how the recursion is done (the *wildcard can
- // actually be Decl, Stmt, or Type):
- //
- // - Traverse(node) calls BaseTraverse(node) when it needs
- // to visit the descendants of node.
- // - BaseTraverse(node) then calls (via VisitorBase::Traverse*(node))
- // Traverse*(c) for each child c of 'node'.
- // - Traverse*(c) in turn calls Traverse(c), completing the
- // recursion.
- bool findMatch(const DynTypedNode &DynNode) {
- reset();
- if (const Decl *D = DynNode.get<Decl>())
- traverse(*D);
- else if (const Stmt *S = DynNode.get<Stmt>())
- traverse(*S);
- else if (const NestedNameSpecifier *NNS =
- DynNode.get<NestedNameSpecifier>())
- traverse(*NNS);
- else if (const NestedNameSpecifierLoc *NNSLoc =
- DynNode.get<NestedNameSpecifierLoc>())
- traverse(*NNSLoc);
- else if (const QualType *Q = DynNode.get<QualType>())
- traverse(*Q);
- else if (const TypeLoc *T = DynNode.get<TypeLoc>())
- traverse(*T);
- else if (const auto *C = DynNode.get<CXXCtorInitializer>())
- traverse(*C);
- else if (const TemplateArgumentLoc *TALoc =
- DynNode.get<TemplateArgumentLoc>())
- traverse(*TALoc);
- else if (const Attr *A = DynNode.get<Attr>())
- traverse(*A);
- // FIXME: Add other base types after adding tests.
- // It's OK to always overwrite the bound nodes, as if there was
- // no match in this recursive branch, the result set is empty
- // anyway.
- *Builder = ResultBindings;
- return Matches;
- }
- // The following are overriding methods from the base visitor class.
- // They are public only to allow CRTP to work. They are *not *part
- // of the public API of this class.
- bool TraverseDecl(Decl *DeclNode) {
- if (DeclNode && DeclNode->isImplicit() &&
- Finder->isTraversalIgnoringImplicitNodes())
- return baseTraverse(*DeclNode);
- ScopedIncrement ScopedDepth(&CurrentDepth);
- return (DeclNode == nullptr) || traverse(*DeclNode);
- }
- Stmt *getStmtToTraverse(Stmt *StmtNode) {
- Stmt *StmtToTraverse = StmtNode;
- if (auto *ExprNode = dyn_cast_or_null<Expr>(StmtNode)) {
- auto *LambdaNode = dyn_cast_or_null<LambdaExpr>(StmtNode);
- if (LambdaNode && Finder->isTraversalIgnoringImplicitNodes())
- StmtToTraverse = LambdaNode;
- else
- StmtToTraverse =
- Finder->getASTContext().getParentMapContext().traverseIgnored(
- ExprNode);
- }
- return StmtToTraverse;
- }
- bool TraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue = nullptr) {
- // If we need to keep track of the depth, we can't perform data recursion.
- if (CurrentDepth == 0 || (CurrentDepth <= MaxDepth && MaxDepth < INT_MAX))
- Queue = nullptr;
- ScopedIncrement ScopedDepth(&CurrentDepth);
- Stmt *StmtToTraverse = getStmtToTraverse(StmtNode);
- if (!StmtToTraverse)
- return true;
- if (IgnoreImplicitChildren && isa<CXXDefaultArgExpr>(StmtNode))
- return true;
- if (!match(*StmtToTraverse))
- return false;
- return VisitorBase::TraverseStmt(StmtToTraverse, Queue);
- }
- // We assume that the QualType and the contained type are on the same
- // hierarchy level. Thus, we try to match either of them.
- bool TraverseType(QualType TypeNode) {
- if (TypeNode.isNull())
- return true;
- ScopedIncrement ScopedDepth(&CurrentDepth);
- // Match the Type.
- if (!match(*TypeNode))
- return false;
- // The QualType is matched inside traverse.
- return traverse(TypeNode);
- }
- // We assume that the TypeLoc, contained QualType and contained Type all are
- // on the same hierarchy level. Thus, we try to match all of them.
- bool TraverseTypeLoc(TypeLoc TypeLocNode) {
- if (TypeLocNode.isNull())
- return true;
- ScopedIncrement ScopedDepth(&CurrentDepth);
- // Match the Type.
- if (!match(*TypeLocNode.getType()))
- return false;
- // Match the QualType.
- if (!match(TypeLocNode.getType()))
- return false;
- // The TypeLoc is matched inside traverse.
- return traverse(TypeLocNode);
- }
- bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) {
- ScopedIncrement ScopedDepth(&CurrentDepth);
- return (NNS == nullptr) || traverse(*NNS);
- }
- bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
- if (!NNS)
- return true;
- ScopedIncrement ScopedDepth(&CurrentDepth);
- if (!match(*NNS.getNestedNameSpecifier()))
- return false;
- return traverse(NNS);
- }
- bool TraverseConstructorInitializer(CXXCtorInitializer *CtorInit) {
- if (!CtorInit)
- return true;
- ScopedIncrement ScopedDepth(&CurrentDepth);
- return traverse(*CtorInit);
- }
- bool TraverseTemplateArgumentLoc(TemplateArgumentLoc TAL) {
- ScopedIncrement ScopedDepth(&CurrentDepth);
- return traverse(TAL);
- }
- bool TraverseCXXForRangeStmt(CXXForRangeStmt *Node) {
- if (!Finder->isTraversalIgnoringImplicitNodes())
- return VisitorBase::TraverseCXXForRangeStmt(Node);
- if (!Node)
- return true;
- ScopedIncrement ScopedDepth(&CurrentDepth);
- if (auto *Init = Node->getInit())
- if (!traverse(*Init))
- return false;
- if (!match(*Node->getLoopVariable()))
- return false;
- if (match(*Node->getRangeInit()))
- if (!VisitorBase::TraverseStmt(Node->getRangeInit()))
- return false;
- if (!match(*Node->getBody()))
- return false;
- return VisitorBase::TraverseStmt(Node->getBody());
- }
- bool TraverseCXXRewrittenBinaryOperator(CXXRewrittenBinaryOperator *Node) {
- if (!Finder->isTraversalIgnoringImplicitNodes())
- return VisitorBase::TraverseCXXRewrittenBinaryOperator(Node);
- if (!Node)
- return true;
- ScopedIncrement ScopedDepth(&CurrentDepth);
- return match(*Node->getLHS()) && match(*Node->getRHS());
- }
- bool TraverseAttr(Attr *A) {
- if (A == nullptr ||
- (A->isImplicit() &&
- Finder->getASTContext().getParentMapContext().getTraversalKind() ==
- TK_IgnoreUnlessSpelledInSource))
- return true;
- ScopedIncrement ScopedDepth(&CurrentDepth);
- return traverse(*A);
- }
- bool TraverseLambdaExpr(LambdaExpr *Node) {
- if (!Finder->isTraversalIgnoringImplicitNodes())
- return VisitorBase::TraverseLambdaExpr(Node);
- if (!Node)
- return true;
- ScopedIncrement ScopedDepth(&CurrentDepth);
- for (unsigned I = 0, N = Node->capture_size(); I != N; ++I) {
- const auto *C = Node->capture_begin() + I;
- if (!C->isExplicit())
- continue;
- if (Node->isInitCapture(C) && !match(*C->getCapturedVar()))
- return false;
- if (!match(*Node->capture_init_begin()[I]))
- return false;
- }
- if (const auto *TPL = Node->getTemplateParameterList()) {
- for (const auto *TP : *TPL) {
- if (!match(*TP))
- return false;
- }
- }
- for (const auto *P : Node->getCallOperator()->parameters()) {
- if (!match(*P))
- return false;
- }
- if (!match(*Node->getBody()))
- return false;
- return VisitorBase::TraverseStmt(Node->getBody());
- }
- bool shouldVisitTemplateInstantiations() const { return true; }
- bool shouldVisitImplicitCode() const { return !IgnoreImplicitChildren; }
- private:
- // Used for updating the depth during traversal.
- struct ScopedIncrement {
- explicit ScopedIncrement(int *Depth) : Depth(Depth) { ++(*Depth); }
- ~ScopedIncrement() { --(*Depth); }
- private:
- int *Depth;
- };
- // Resets the state of this object.
- void reset() {
- Matches = false;
- CurrentDepth = 0;
- }
- // Forwards the call to the corresponding Traverse*() method in the
- // base visitor class.
- bool baseTraverse(const Decl &DeclNode) {
- return VisitorBase::TraverseDecl(const_cast<Decl*>(&DeclNode));
- }
- bool baseTraverse(const Stmt &StmtNode) {
- return VisitorBase::TraverseStmt(const_cast<Stmt*>(&StmtNode));
- }
- bool baseTraverse(QualType TypeNode) {
- return VisitorBase::TraverseType(TypeNode);
- }
- bool baseTraverse(TypeLoc TypeLocNode) {
- return VisitorBase::TraverseTypeLoc(TypeLocNode);
- }
- bool baseTraverse(const NestedNameSpecifier &NNS) {
- return VisitorBase::TraverseNestedNameSpecifier(
- const_cast<NestedNameSpecifier*>(&NNS));
- }
- bool baseTraverse(NestedNameSpecifierLoc NNS) {
- return VisitorBase::TraverseNestedNameSpecifierLoc(NNS);
- }
- bool baseTraverse(const CXXCtorInitializer &CtorInit) {
- return VisitorBase::TraverseConstructorInitializer(
- const_cast<CXXCtorInitializer *>(&CtorInit));
- }
- bool baseTraverse(TemplateArgumentLoc TAL) {
- return VisitorBase::TraverseTemplateArgumentLoc(TAL);
- }
- bool baseTraverse(const Attr &AttrNode) {
- return VisitorBase::TraverseAttr(const_cast<Attr *>(&AttrNode));
- }
- // Sets 'Matched' to true if 'Matcher' matches 'Node' and:
- // 0 < CurrentDepth <= MaxDepth.
- //
- // Returns 'true' if traversal should continue after this function
- // returns, i.e. if no match is found or 'Bind' is 'BK_All'.
- template <typename T>
- bool match(const T &Node) {
- if (CurrentDepth == 0 || CurrentDepth > MaxDepth) {
- return true;
- }
- if (Bind != ASTMatchFinder::BK_All) {
- BoundNodesTreeBuilder RecursiveBuilder(*Builder);
- if (Matcher->matches(DynTypedNode::create(Node), Finder,
- &RecursiveBuilder)) {
- Matches = true;
- ResultBindings.addMatch(RecursiveBuilder);
- return false; // Abort as soon as a match is found.
- }
- } else {
- BoundNodesTreeBuilder RecursiveBuilder(*Builder);
- if (Matcher->matches(DynTypedNode::create(Node), Finder,
- &RecursiveBuilder)) {
- // After the first match the matcher succeeds.
- Matches = true;
- ResultBindings.addMatch(RecursiveBuilder);
- }
- }
- return true;
- }
- // Traverses the subtree rooted at 'Node'; returns true if the
- // traversal should continue after this function returns.
- template <typename T>
- bool traverse(const T &Node) {
- static_assert(IsBaseType<T>::value,
- "traverse can only be instantiated with base type");
- if (!match(Node))
- return false;
- return baseTraverse(Node);
- }
- const DynTypedMatcher *const Matcher;
- ASTMatchFinder *const Finder;
- BoundNodesTreeBuilder *const Builder;
- BoundNodesTreeBuilder ResultBindings;
- int CurrentDepth;
- const int MaxDepth;
- const bool IgnoreImplicitChildren;
- const ASTMatchFinder::BindKind Bind;
- bool Matches;
- };
- // Controls the outermost traversal of the AST and allows to match multiple
- // matchers.
- class MatchASTVisitor : public RecursiveASTVisitor<MatchASTVisitor>,
- public ASTMatchFinder {
- public:
- MatchASTVisitor(const MatchFinder::MatchersByType *Matchers,
- const MatchFinder::MatchFinderOptions &Options)
- : Matchers(Matchers), Options(Options), ActiveASTContext(nullptr) {}
- ~MatchASTVisitor() override {
- if (Options.CheckProfiling) {
- Options.CheckProfiling->Records = std::move(TimeByBucket);
- }
- }
- void onStartOfTranslationUnit() {
- const bool EnableCheckProfiling = Options.CheckProfiling.has_value();
- TimeBucketRegion Timer;
- for (MatchCallback *MC : Matchers->AllCallbacks) {
- if (EnableCheckProfiling)
- Timer.setBucket(&TimeByBucket[MC->getID()]);
- MC->onStartOfTranslationUnit();
- }
- }
- void onEndOfTranslationUnit() {
- const bool EnableCheckProfiling = Options.CheckProfiling.has_value();
- TimeBucketRegion Timer;
- for (MatchCallback *MC : Matchers->AllCallbacks) {
- if (EnableCheckProfiling)
- Timer.setBucket(&TimeByBucket[MC->getID()]);
- MC->onEndOfTranslationUnit();
- }
- }
- void set_active_ast_context(ASTContext *NewActiveASTContext) {
- ActiveASTContext = NewActiveASTContext;
- }
- // The following Visit*() and Traverse*() functions "override"
- // methods in RecursiveASTVisitor.
- bool VisitTypedefNameDecl(TypedefNameDecl *DeclNode) {
- // When we see 'typedef A B', we add name 'B' to the set of names
- // A's canonical type maps to. This is necessary for implementing
- // isDerivedFrom(x) properly, where x can be the name of the base
- // class or any of its aliases.
- //
- // In general, the is-alias-of (as defined by typedefs) relation
- // is tree-shaped, as you can typedef a type more than once. For
- // example,
- //
- // typedef A B;
- // typedef A C;
- // typedef C D;
- // typedef C E;
- //
- // gives you
- //
- // A
- // |- B
- // `- C
- // |- D
- // `- E
- //
- // It is wrong to assume that the relation is a chain. A correct
- // implementation of isDerivedFrom() needs to recognize that B and
- // E are aliases, even though neither is a typedef of the other.
- // Therefore, we cannot simply walk through one typedef chain to
- // find out whether the type name matches.
- const Type *TypeNode = DeclNode->getUnderlyingType().getTypePtr();
- const Type *CanonicalType = // root of the typedef tree
- ActiveASTContext->getCanonicalType(TypeNode);
- TypeAliases[CanonicalType].insert(DeclNode);
- return true;
- }
- bool VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *CAD) {
- const ObjCInterfaceDecl *InterfaceDecl = CAD->getClassInterface();
- CompatibleAliases[InterfaceDecl].insert(CAD);
- return true;
- }
- bool TraverseDecl(Decl *DeclNode);
- bool TraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue = nullptr);
- bool TraverseType(QualType TypeNode);
- bool TraverseTypeLoc(TypeLoc TypeNode);
- bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS);
- bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS);
- bool TraverseConstructorInitializer(CXXCtorInitializer *CtorInit);
- bool TraverseTemplateArgumentLoc(TemplateArgumentLoc TAL);
- bool TraverseAttr(Attr *AttrNode);
- bool dataTraverseNode(Stmt *S, DataRecursionQueue *Queue) {
- if (auto *RF = dyn_cast<CXXForRangeStmt>(S)) {
- {
- ASTNodeNotAsIsSourceScope RAII(this, true);
- TraverseStmt(RF->getInit());
- // Don't traverse under the loop variable
- match(*RF->getLoopVariable());
- TraverseStmt(RF->getRangeInit());
- }
- {
- ASTNodeNotSpelledInSourceScope RAII(this, true);
- for (auto *SubStmt : RF->children()) {
- if (SubStmt != RF->getBody())
- TraverseStmt(SubStmt);
- }
- }
- TraverseStmt(RF->getBody());
- return true;
- } else if (auto *RBO = dyn_cast<CXXRewrittenBinaryOperator>(S)) {
- {
- ASTNodeNotAsIsSourceScope RAII(this, true);
- TraverseStmt(const_cast<Expr *>(RBO->getLHS()));
- TraverseStmt(const_cast<Expr *>(RBO->getRHS()));
- }
- {
- ASTNodeNotSpelledInSourceScope RAII(this, true);
- for (auto *SubStmt : RBO->children()) {
- TraverseStmt(SubStmt);
- }
- }
- return true;
- } else if (auto *LE = dyn_cast<LambdaExpr>(S)) {
- for (auto I : llvm::zip(LE->captures(), LE->capture_inits())) {
- auto C = std::get<0>(I);
- ASTNodeNotSpelledInSourceScope RAII(
- this, TraversingASTNodeNotSpelledInSource || !C.isExplicit());
- TraverseLambdaCapture(LE, &C, std::get<1>(I));
- }
- {
- ASTNodeNotSpelledInSourceScope RAII(this, true);
- TraverseDecl(LE->getLambdaClass());
- }
- {
- ASTNodeNotAsIsSourceScope RAII(this, true);
- // We need to poke around to find the bits that might be explicitly
- // written.
- TypeLoc TL = LE->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
- FunctionProtoTypeLoc Proto = TL.getAsAdjusted<FunctionProtoTypeLoc>();
- if (auto *TPL = LE->getTemplateParameterList()) {
- for (NamedDecl *D : *TPL) {
- TraverseDecl(D);
- }
- if (Expr *RequiresClause = TPL->getRequiresClause()) {
- TraverseStmt(RequiresClause);
- }
- }
- if (LE->hasExplicitParameters()) {
- // Visit parameters.
- for (ParmVarDecl *Param : Proto.getParams())
- TraverseDecl(Param);
- }
- const auto *T = Proto.getTypePtr();
- for (const auto &E : T->exceptions())
- TraverseType(E);
- if (Expr *NE = T->getNoexceptExpr())
- TraverseStmt(NE, Queue);
- if (LE->hasExplicitResultType())
- TraverseTypeLoc(Proto.getReturnLoc());
- TraverseStmt(LE->getTrailingRequiresClause());
- }
- TraverseStmt(LE->getBody());
- return true;
- }
- return RecursiveASTVisitor<MatchASTVisitor>::dataTraverseNode(S, Queue);
- }
- // Matches children or descendants of 'Node' with 'BaseMatcher'.
- bool memoizedMatchesRecursively(const DynTypedNode &Node, ASTContext &Ctx,
- const DynTypedMatcher &Matcher,
- BoundNodesTreeBuilder *Builder, int MaxDepth,
- BindKind Bind) {
- // For AST-nodes that don't have an identity, we can't memoize.
- if (!Node.getMemoizationData() || !Builder->isComparable())
- return matchesRecursively(Node, Matcher, Builder, MaxDepth, Bind);
- MatchKey Key;
- Key.MatcherID = Matcher.getID();
- Key.Node = Node;
- // Note that we key on the bindings *before* the match.
- Key.BoundNodes = *Builder;
- Key.Traversal = Ctx.getParentMapContext().getTraversalKind();
- // Memoize result even doing a single-level match, it might be expensive.
- Key.Type = MaxDepth == 1 ? MatchType::Child : MatchType::Descendants;
- MemoizationMap::iterator I = ResultCache.find(Key);
- if (I != ResultCache.end()) {
- *Builder = I->second.Nodes;
- return I->second.ResultOfMatch;
- }
- MemoizedMatchResult Result;
- Result.Nodes = *Builder;
- Result.ResultOfMatch =
- matchesRecursively(Node, Matcher, &Result.Nodes, MaxDepth, Bind);
- MemoizedMatchResult &CachedResult = ResultCache[Key];
- CachedResult = std::move(Result);
- *Builder = CachedResult.Nodes;
- return CachedResult.ResultOfMatch;
- }
- // Matches children or descendants of 'Node' with 'BaseMatcher'.
- bool matchesRecursively(const DynTypedNode &Node,
- const DynTypedMatcher &Matcher,
- BoundNodesTreeBuilder *Builder, int MaxDepth,
- BindKind Bind) {
- bool ScopedTraversal = TraversingASTNodeNotSpelledInSource ||
- TraversingASTChildrenNotSpelledInSource;
- bool IgnoreImplicitChildren = false;
- if (isTraversalIgnoringImplicitNodes()) {
- IgnoreImplicitChildren = true;
- }
- ASTNodeNotSpelledInSourceScope RAII(this, ScopedTraversal);
- MatchChildASTVisitor Visitor(&Matcher, this, Builder, MaxDepth,
- IgnoreImplicitChildren, Bind);
- return Visitor.findMatch(Node);
- }
- bool classIsDerivedFrom(const CXXRecordDecl *Declaration,
- const Matcher<NamedDecl> &Base,
- BoundNodesTreeBuilder *Builder,
- bool Directly) override;
- bool objcClassIsDerivedFrom(const ObjCInterfaceDecl *Declaration,
- const Matcher<NamedDecl> &Base,
- BoundNodesTreeBuilder *Builder,
- bool Directly) override;
- // Implements ASTMatchFinder::matchesChildOf.
- bool matchesChildOf(const DynTypedNode &Node, ASTContext &Ctx,
- const DynTypedMatcher &Matcher,
- BoundNodesTreeBuilder *Builder, BindKind Bind) override {
- if (ResultCache.size() > MaxMemoizationEntries)
- ResultCache.clear();
- return memoizedMatchesRecursively(Node, Ctx, Matcher, Builder, 1, Bind);
- }
- // Implements ASTMatchFinder::matchesDescendantOf.
- bool matchesDescendantOf(const DynTypedNode &Node, ASTContext &Ctx,
- const DynTypedMatcher &Matcher,
- BoundNodesTreeBuilder *Builder,
- BindKind Bind) override {
- if (ResultCache.size() > MaxMemoizationEntries)
- ResultCache.clear();
- return memoizedMatchesRecursively(Node, Ctx, Matcher, Builder, INT_MAX,
- Bind);
- }
- // Implements ASTMatchFinder::matchesAncestorOf.
- bool matchesAncestorOf(const DynTypedNode &Node, ASTContext &Ctx,
- const DynTypedMatcher &Matcher,
- BoundNodesTreeBuilder *Builder,
- AncestorMatchMode MatchMode) override {
- // Reset the cache outside of the recursive call to make sure we
- // don't invalidate any iterators.
- if (ResultCache.size() > MaxMemoizationEntries)
- ResultCache.clear();
- if (MatchMode == AncestorMatchMode::AMM_ParentOnly)
- return matchesParentOf(Node, Matcher, Builder);
- return matchesAnyAncestorOf(Node, Ctx, Matcher, Builder);
- }
- // Matches all registered matchers on the given node and calls the
- // result callback for every node that matches.
- void match(const DynTypedNode &Node) {
- // FIXME: Improve this with a switch or a visitor pattern.
- if (auto *N = Node.get<Decl>()) {
- match(*N);
- } else if (auto *N = Node.get<Stmt>()) {
- match(*N);
- } else if (auto *N = Node.get<Type>()) {
- match(*N);
- } else if (auto *N = Node.get<QualType>()) {
- match(*N);
- } else if (auto *N = Node.get<NestedNameSpecifier>()) {
- match(*N);
- } else if (auto *N = Node.get<NestedNameSpecifierLoc>()) {
- match(*N);
- } else if (auto *N = Node.get<TypeLoc>()) {
- match(*N);
- } else if (auto *N = Node.get<CXXCtorInitializer>()) {
- match(*N);
- } else if (auto *N = Node.get<TemplateArgumentLoc>()) {
- match(*N);
- } else if (auto *N = Node.get<Attr>()) {
- match(*N);
- }
- }
- template <typename T> void match(const T &Node) {
- matchDispatch(&Node);
- }
- // Implements ASTMatchFinder::getASTContext.
- ASTContext &getASTContext() const override { return *ActiveASTContext; }
- bool shouldVisitTemplateInstantiations() const { return true; }
- bool shouldVisitImplicitCode() const { return true; }
- // We visit the lambda body explicitly, so instruct the RAV
- // to not visit it on our behalf too.
- bool shouldVisitLambdaBody() const { return false; }
- bool IsMatchingInASTNodeNotSpelledInSource() const override {
- return TraversingASTNodeNotSpelledInSource;
- }
- bool isMatchingChildrenNotSpelledInSource() const override {
- return TraversingASTChildrenNotSpelledInSource;
- }
- void setMatchingChildrenNotSpelledInSource(bool Set) override {
- TraversingASTChildrenNotSpelledInSource = Set;
- }
- bool IsMatchingInASTNodeNotAsIs() const override {
- return TraversingASTNodeNotAsIs;
- }
- bool TraverseTemplateInstantiations(ClassTemplateDecl *D) {
- ASTNodeNotSpelledInSourceScope RAII(this, true);
- return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateInstantiations(
- D);
- }
- bool TraverseTemplateInstantiations(VarTemplateDecl *D) {
- ASTNodeNotSpelledInSourceScope RAII(this, true);
- return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateInstantiations(
- D);
- }
- bool TraverseTemplateInstantiations(FunctionTemplateDecl *D) {
- ASTNodeNotSpelledInSourceScope RAII(this, true);
- return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateInstantiations(
- D);
- }
- private:
- bool TraversingASTNodeNotSpelledInSource = false;
- bool TraversingASTNodeNotAsIs = false;
- bool TraversingASTChildrenNotSpelledInSource = false;
- class CurMatchData {
- // We don't have enough free low bits in 32bit builds to discriminate 8 pointer
- // types in PointerUnion. so split the union in 2 using a free bit from the
- // callback pointer.
- #define CMD_TYPES_0 \
- const QualType *, const TypeLoc *, const NestedNameSpecifier *, \
- const NestedNameSpecifierLoc *
- #define CMD_TYPES_1 \
- const CXXCtorInitializer *, const TemplateArgumentLoc *, const Attr *, \
- const DynTypedNode *
- #define IMPL(Index) \
- template <typename NodeType> \
- std::enable_if_t< \
- llvm::is_one_of<const NodeType *, CMD_TYPES_##Index>::value> \
- SetCallbackAndRawNode(const MatchCallback *CB, const NodeType &N) { \
- assertEmpty(); \
- Callback.setPointerAndInt(CB, Index); \
- Node##Index = &N; \
- } \
- \
- template <typename T> \
- std::enable_if_t<llvm::is_one_of<const T *, CMD_TYPES_##Index>::value, \
- const T *> \
- getNode() const { \
- assertHoldsState(); \
- return Callback.getInt() == (Index) ? Node##Index.dyn_cast<const T *>() \
- : nullptr; \
- }
- public:
- CurMatchData() : Node0(nullptr) {}
- IMPL(0)
- IMPL(1)
- const MatchCallback *getCallback() const { return Callback.getPointer(); }
- void SetBoundNodes(const BoundNodes &BN) {
- assertHoldsState();
- BNodes = &BN;
- }
- void clearBoundNodes() {
- assertHoldsState();
- BNodes = nullptr;
- }
- const BoundNodes *getBoundNodes() const {
- assertHoldsState();
- return BNodes;
- }
- void reset() {
- assertHoldsState();
- Callback.setPointerAndInt(nullptr, 0);
- Node0 = nullptr;
- }
- private:
- void assertHoldsState() const {
- assert(Callback.getPointer() != nullptr && !Node0.isNull());
- }
- void assertEmpty() const {
- assert(Callback.getPointer() == nullptr && Node0.isNull() &&
- BNodes == nullptr);
- }
- llvm::PointerIntPair<const MatchCallback *, 1> Callback;
- union {
- llvm::PointerUnion<CMD_TYPES_0> Node0;
- llvm::PointerUnion<CMD_TYPES_1> Node1;
- };
- const BoundNodes *BNodes = nullptr;
- #undef CMD_TYPES_0
- #undef CMD_TYPES_1
- #undef IMPL
- } CurMatchState;
- struct CurMatchRAII {
- template <typename NodeType>
- CurMatchRAII(MatchASTVisitor &MV, const MatchCallback *CB,
- const NodeType &NT)
- : MV(MV) {
- MV.CurMatchState.SetCallbackAndRawNode(CB, NT);
- }
- ~CurMatchRAII() { MV.CurMatchState.reset(); }
- private:
- MatchASTVisitor &MV;
- };
- public:
- class TraceReporter : llvm::PrettyStackTraceEntry {
- static void dumpNode(const ASTContext &Ctx, const DynTypedNode &Node,
- raw_ostream &OS) {
- if (const auto *D = Node.get<Decl>()) {
- OS << D->getDeclKindName() << "Decl ";
- if (const auto *ND = dyn_cast<NamedDecl>(D)) {
- ND->printQualifiedName(OS);
- OS << " : ";
- } else
- OS << ": ";
- D->getSourceRange().print(OS, Ctx.getSourceManager());
- } else if (const auto *S = Node.get<Stmt>()) {
- OS << S->getStmtClassName() << " : ";
- S->getSourceRange().print(OS, Ctx.getSourceManager());
- } else if (const auto *T = Node.get<Type>()) {
- OS << T->getTypeClassName() << "Type : ";
- QualType(T, 0).print(OS, Ctx.getPrintingPolicy());
- } else if (const auto *QT = Node.get<QualType>()) {
- OS << "QualType : ";
- QT->print(OS, Ctx.getPrintingPolicy());
- } else {
- OS << Node.getNodeKind().asStringRef() << " : ";
- Node.getSourceRange().print(OS, Ctx.getSourceManager());
- }
- }
- static void dumpNodeFromState(const ASTContext &Ctx,
- const CurMatchData &State, raw_ostream &OS) {
- if (const DynTypedNode *MatchNode = State.getNode<DynTypedNode>()) {
- dumpNode(Ctx, *MatchNode, OS);
- } else if (const auto *QT = State.getNode<QualType>()) {
- dumpNode(Ctx, DynTypedNode::create(*QT), OS);
- } else if (const auto *TL = State.getNode<TypeLoc>()) {
- dumpNode(Ctx, DynTypedNode::create(*TL), OS);
- } else if (const auto *NNS = State.getNode<NestedNameSpecifier>()) {
- dumpNode(Ctx, DynTypedNode::create(*NNS), OS);
- } else if (const auto *NNSL = State.getNode<NestedNameSpecifierLoc>()) {
- dumpNode(Ctx, DynTypedNode::create(*NNSL), OS);
- } else if (const auto *CtorInit = State.getNode<CXXCtorInitializer>()) {
- dumpNode(Ctx, DynTypedNode::create(*CtorInit), OS);
- } else if (const auto *TAL = State.getNode<TemplateArgumentLoc>()) {
- dumpNode(Ctx, DynTypedNode::create(*TAL), OS);
- } else if (const auto *At = State.getNode<Attr>()) {
- dumpNode(Ctx, DynTypedNode::create(*At), OS);
- }
- }
- public:
- TraceReporter(const MatchASTVisitor &MV) : MV(MV) {}
- void print(raw_ostream &OS) const override {
- const CurMatchData &State = MV.CurMatchState;
- const MatchCallback *CB = State.getCallback();
- if (!CB) {
- OS << "ASTMatcher: Not currently matching\n";
- return;
- }
- assert(MV.ActiveASTContext &&
- "ActiveASTContext should be set if there is a matched callback");
- ASTContext &Ctx = MV.getASTContext();
- if (const BoundNodes *Nodes = State.getBoundNodes()) {
- OS << "ASTMatcher: Processing '" << CB->getID() << "' against:\n\t";
- dumpNodeFromState(Ctx, State, OS);
- const BoundNodes::IDToNodeMap &Map = Nodes->getMap();
- if (Map.empty()) {
- OS << "\nNo bound nodes\n";
- return;
- }
- OS << "\n--- Bound Nodes Begin ---\n";
- for (const auto &Item : Map) {
- OS << " " << Item.first << " - { ";
- dumpNode(Ctx, Item.second, OS);
- OS << " }\n";
- }
- OS << "--- Bound Nodes End ---\n";
- } else {
- OS << "ASTMatcher: Matching '" << CB->getID() << "' against:\n\t";
- dumpNodeFromState(Ctx, State, OS);
- OS << '\n';
- }
- }
- private:
- const MatchASTVisitor &MV;
- };
- private:
- struct ASTNodeNotSpelledInSourceScope {
- ASTNodeNotSpelledInSourceScope(MatchASTVisitor *V, bool B)
- : MV(V), MB(V->TraversingASTNodeNotSpelledInSource) {
- V->TraversingASTNodeNotSpelledInSource = B;
- }
- ~ASTNodeNotSpelledInSourceScope() {
- MV->TraversingASTNodeNotSpelledInSource = MB;
- }
- private:
- MatchASTVisitor *MV;
- bool MB;
- };
- struct ASTNodeNotAsIsSourceScope {
- ASTNodeNotAsIsSourceScope(MatchASTVisitor *V, bool B)
- : MV(V), MB(V->TraversingASTNodeNotAsIs) {
- V->TraversingASTNodeNotAsIs = B;
- }
- ~ASTNodeNotAsIsSourceScope() { MV->TraversingASTNodeNotAsIs = MB; }
- private:
- MatchASTVisitor *MV;
- bool MB;
- };
- class TimeBucketRegion {
- public:
- TimeBucketRegion() : Bucket(nullptr) {}
- ~TimeBucketRegion() { setBucket(nullptr); }
- /// Start timing for \p NewBucket.
- ///
- /// If there was a bucket already set, it will finish the timing for that
- /// other bucket.
- /// \p NewBucket will be timed until the next call to \c setBucket() or
- /// until the \c TimeBucketRegion is destroyed.
- /// If \p NewBucket is the same as the currently timed bucket, this call
- /// does nothing.
- void setBucket(llvm::TimeRecord *NewBucket) {
- if (Bucket != NewBucket) {
- auto Now = llvm::TimeRecord::getCurrentTime(true);
- if (Bucket)
- *Bucket += Now;
- if (NewBucket)
- *NewBucket -= Now;
- Bucket = NewBucket;
- }
- }
- private:
- llvm::TimeRecord *Bucket;
- };
- /// Runs all the \p Matchers on \p Node.
- ///
- /// Used by \c matchDispatch() below.
- template <typename T, typename MC>
- void matchWithoutFilter(const T &Node, const MC &Matchers) {
- const bool EnableCheckProfiling = Options.CheckProfiling.has_value();
- TimeBucketRegion Timer;
- for (const auto &MP : Matchers) {
- if (EnableCheckProfiling)
- Timer.setBucket(&TimeByBucket[MP.second->getID()]);
- BoundNodesTreeBuilder Builder;
- CurMatchRAII RAII(*this, MP.second, Node);
- if (MP.first.matches(Node, this, &Builder)) {
- MatchVisitor Visitor(*this, ActiveASTContext, MP.second);
- Builder.visitMatches(&Visitor);
- }
- }
- }
- void matchWithFilter(const DynTypedNode &DynNode) {
- auto Kind = DynNode.getNodeKind();
- auto it = MatcherFiltersMap.find(Kind);
- const auto &Filter =
- it != MatcherFiltersMap.end() ? it->second : getFilterForKind(Kind);
- if (Filter.empty())
- return;
- const bool EnableCheckProfiling = Options.CheckProfiling.has_value();
- TimeBucketRegion Timer;
- auto &Matchers = this->Matchers->DeclOrStmt;
- for (unsigned short I : Filter) {
- auto &MP = Matchers[I];
- if (EnableCheckProfiling)
- Timer.setBucket(&TimeByBucket[MP.second->getID()]);
- BoundNodesTreeBuilder Builder;
- {
- TraversalKindScope RAII(getASTContext(), MP.first.getTraversalKind());
- if (getASTContext().getParentMapContext().traverseIgnored(DynNode) !=
- DynNode)
- continue;
- }
- CurMatchRAII RAII(*this, MP.second, DynNode);
- if (MP.first.matches(DynNode, this, &Builder)) {
- MatchVisitor Visitor(*this, ActiveASTContext, MP.second);
- Builder.visitMatches(&Visitor);
- }
- }
- }
- const std::vector<unsigned short> &getFilterForKind(ASTNodeKind Kind) {
- auto &Filter = MatcherFiltersMap[Kind];
- auto &Matchers = this->Matchers->DeclOrStmt;
- assert((Matchers.size() < USHRT_MAX) && "Too many matchers.");
- for (unsigned I = 0, E = Matchers.size(); I != E; ++I) {
- if (Matchers[I].first.canMatchNodesOfKind(Kind)) {
- Filter.push_back(I);
- }
- }
- return Filter;
- }
- /// @{
- /// Overloads to pair the different node types to their matchers.
- void matchDispatch(const Decl *Node) {
- return matchWithFilter(DynTypedNode::create(*Node));
- }
- void matchDispatch(const Stmt *Node) {
- return matchWithFilter(DynTypedNode::create(*Node));
- }
- void matchDispatch(const Type *Node) {
- matchWithoutFilter(QualType(Node, 0), Matchers->Type);
- }
- void matchDispatch(const TypeLoc *Node) {
- matchWithoutFilter(*Node, Matchers->TypeLoc);
- }
- void matchDispatch(const QualType *Node) {
- matchWithoutFilter(*Node, Matchers->Type);
- }
- void matchDispatch(const NestedNameSpecifier *Node) {
- matchWithoutFilter(*Node, Matchers->NestedNameSpecifier);
- }
- void matchDispatch(const NestedNameSpecifierLoc *Node) {
- matchWithoutFilter(*Node, Matchers->NestedNameSpecifierLoc);
- }
- void matchDispatch(const CXXCtorInitializer *Node) {
- matchWithoutFilter(*Node, Matchers->CtorInit);
- }
- void matchDispatch(const TemplateArgumentLoc *Node) {
- matchWithoutFilter(*Node, Matchers->TemplateArgumentLoc);
- }
- void matchDispatch(const Attr *Node) {
- matchWithoutFilter(*Node, Matchers->Attr);
- }
- void matchDispatch(const void *) { /* Do nothing. */ }
- /// @}
- // Returns whether a direct parent of \p Node matches \p Matcher.
- // Unlike matchesAnyAncestorOf there's no memoization: it doesn't save much.
- bool matchesParentOf(const DynTypedNode &Node, const DynTypedMatcher &Matcher,
- BoundNodesTreeBuilder *Builder) {
- for (const auto &Parent : ActiveASTContext->getParents(Node)) {
- BoundNodesTreeBuilder BuilderCopy = *Builder;
- if (Matcher.matches(Parent, this, &BuilderCopy)) {
- *Builder = std::move(BuilderCopy);
- return true;
- }
- }
- return false;
- }
- // Returns whether an ancestor of \p Node matches \p Matcher.
- //
- // The order of matching (which can lead to different nodes being bound in
- // case there are multiple matches) is breadth first search.
- //
- // To allow memoization in the very common case of having deeply nested
- // expressions inside a template function, we first walk up the AST, memoizing
- // the result of the match along the way, as long as there is only a single
- // parent.
- //
- // Once there are multiple parents, the breadth first search order does not
- // allow simple memoization on the ancestors. Thus, we only memoize as long
- // as there is a single parent.
- //
- // We avoid a recursive implementation to prevent excessive stack use on
- // very deep ASTs (similarly to RecursiveASTVisitor's data recursion).
- bool matchesAnyAncestorOf(DynTypedNode Node, ASTContext &Ctx,
- const DynTypedMatcher &Matcher,
- BoundNodesTreeBuilder *Builder) {
- // Memoization keys that can be updated with the result.
- // These are the memoizable nodes in the chain of unique parents, which
- // terminates when a node has multiple parents, or matches, or is the root.
- std::vector<MatchKey> Keys;
- // When returning, update the memoization cache.
- auto Finish = [&](bool Matched) {
- for (const auto &Key : Keys) {
- MemoizedMatchResult &CachedResult = ResultCache[Key];
- CachedResult.ResultOfMatch = Matched;
- CachedResult.Nodes = *Builder;
- }
- return Matched;
- };
- // Loop while there's a single parent and we want to attempt memoization.
- DynTypedNodeList Parents{ArrayRef<DynTypedNode>()}; // after loop: size != 1
- for (;;) {
- // A cache key only makes sense if memoization is possible.
- if (Builder->isComparable()) {
- Keys.emplace_back();
- Keys.back().MatcherID = Matcher.getID();
- Keys.back().Node = Node;
- Keys.back().BoundNodes = *Builder;
- Keys.back().Traversal = Ctx.getParentMapContext().getTraversalKind();
- Keys.back().Type = MatchType::Ancestors;
- // Check the cache.
- MemoizationMap::iterator I = ResultCache.find(Keys.back());
- if (I != ResultCache.end()) {
- Keys.pop_back(); // Don't populate the cache for the matching node!
- *Builder = I->second.Nodes;
- return Finish(I->second.ResultOfMatch);
- }
- }
- Parents = ActiveASTContext->getParents(Node);
- // Either no parents or multiple parents: leave chain+memoize mode and
- // enter bfs+forgetful mode.
- if (Parents.size() != 1)
- break;
- // Check the next parent.
- Node = *Parents.begin();
- BoundNodesTreeBuilder BuilderCopy = *Builder;
- if (Matcher.matches(Node, this, &BuilderCopy)) {
- *Builder = std::move(BuilderCopy);
- return Finish(true);
- }
- }
- // We reached the end of the chain.
- if (Parents.empty()) {
- // Nodes may have no parents if:
- // a) the node is the TranslationUnitDecl
- // b) we have a limited traversal scope that excludes the parent edges
- // c) there is a bug in the AST, and the node is not reachable
- // Usually the traversal scope is the whole AST, which precludes b.
- // Bugs are common enough that it's worthwhile asserting when we can.
- #ifndef NDEBUG
- if (!Node.get<TranslationUnitDecl>() &&
- /* Traversal scope is full AST if any of the bounds are the TU */
- llvm::any_of(ActiveASTContext->getTraversalScope(), [](Decl *D) {
- return D->getKind() == Decl::TranslationUnit;
- })) {
- llvm::errs() << "Tried to match orphan node:\n";
- Node.dump(llvm::errs(), *ActiveASTContext);
- llvm_unreachable("Parent map should be complete!");
- }
- #endif
- } else {
- assert(Parents.size() > 1);
- // BFS starting from the parents not yet considered.
- // Memoization of newly visited nodes is not possible (but we still update
- // results for the elements in the chain we found above).
- std::deque<DynTypedNode> Queue(Parents.begin(), Parents.end());
- llvm::DenseSet<const void *> Visited;
- while (!Queue.empty()) {
- BoundNodesTreeBuilder BuilderCopy = *Builder;
- if (Matcher.matches(Queue.front(), this, &BuilderCopy)) {
- *Builder = std::move(BuilderCopy);
- return Finish(true);
- }
- for (const auto &Parent : ActiveASTContext->getParents(Queue.front())) {
- // Make sure we do not visit the same node twice.
- // Otherwise, we'll visit the common ancestors as often as there
- // are splits on the way down.
- if (Visited.insert(Parent.getMemoizationData()).second)
- Queue.push_back(Parent);
- }
- Queue.pop_front();
- }
- }
- return Finish(false);
- }
- // Implements a BoundNodesTree::Visitor that calls a MatchCallback with
- // the aggregated bound nodes for each match.
- class MatchVisitor : public BoundNodesTreeBuilder::Visitor {
- struct CurBoundScope {
- CurBoundScope(MatchASTVisitor::CurMatchData &State, const BoundNodes &BN)
- : State(State) {
- State.SetBoundNodes(BN);
- }
- ~CurBoundScope() { State.clearBoundNodes(); }
- private:
- MatchASTVisitor::CurMatchData &State;
- };
- public:
- MatchVisitor(MatchASTVisitor &MV, ASTContext *Context,
- MatchFinder::MatchCallback *Callback)
- : State(MV.CurMatchState), Context(Context), Callback(Callback) {}
- void visitMatch(const BoundNodes& BoundNodesView) override {
- TraversalKindScope RAII(*Context, Callback->getCheckTraversalKind());
- CurBoundScope RAII2(State, BoundNodesView);
- Callback->run(MatchFinder::MatchResult(BoundNodesView, Context));
- }
- private:
- MatchASTVisitor::CurMatchData &State;
- ASTContext* Context;
- MatchFinder::MatchCallback* Callback;
- };
- // Returns true if 'TypeNode' has an alias that matches the given matcher.
- bool typeHasMatchingAlias(const Type *TypeNode,
- const Matcher<NamedDecl> &Matcher,
- BoundNodesTreeBuilder *Builder) {
- const Type *const CanonicalType =
- ActiveASTContext->getCanonicalType(TypeNode);
- auto Aliases = TypeAliases.find(CanonicalType);
- if (Aliases == TypeAliases.end())
- return false;
- for (const TypedefNameDecl *Alias : Aliases->second) {
- BoundNodesTreeBuilder Result(*Builder);
- if (Matcher.matches(*Alias, this, &Result)) {
- *Builder = std::move(Result);
- return true;
- }
- }
- return false;
- }
- bool
- objcClassHasMatchingCompatibilityAlias(const ObjCInterfaceDecl *InterfaceDecl,
- const Matcher<NamedDecl> &Matcher,
- BoundNodesTreeBuilder *Builder) {
- auto Aliases = CompatibleAliases.find(InterfaceDecl);
- if (Aliases == CompatibleAliases.end())
- return false;
- for (const ObjCCompatibleAliasDecl *Alias : Aliases->second) {
- BoundNodesTreeBuilder Result(*Builder);
- if (Matcher.matches(*Alias, this, &Result)) {
- *Builder = std::move(Result);
- return true;
- }
- }
- return false;
- }
- /// Bucket to record map.
- ///
- /// Used to get the appropriate bucket for each matcher.
- llvm::StringMap<llvm::TimeRecord> TimeByBucket;
- const MatchFinder::MatchersByType *Matchers;
- /// Filtered list of matcher indices for each matcher kind.
- ///
- /// \c Decl and \c Stmt toplevel matchers usually apply to a specific node
- /// kind (and derived kinds) so it is a waste to try every matcher on every
- /// node.
- /// We precalculate a list of matchers that pass the toplevel restrict check.
- llvm::DenseMap<ASTNodeKind, std::vector<unsigned short>> MatcherFiltersMap;
- const MatchFinder::MatchFinderOptions &Options;
- ASTContext *ActiveASTContext;
- // Maps a canonical type to its TypedefDecls.
- llvm::DenseMap<const Type*, std::set<const TypedefNameDecl*> > TypeAliases;
- // Maps an Objective-C interface to its ObjCCompatibleAliasDecls.
- llvm::DenseMap<const ObjCInterfaceDecl *,
- llvm::SmallPtrSet<const ObjCCompatibleAliasDecl *, 2>>
- CompatibleAliases;
- // Maps (matcher, node) -> the match result for memoization.
- typedef std::map<MatchKey, MemoizedMatchResult> MemoizationMap;
- MemoizationMap ResultCache;
- };
- static CXXRecordDecl *
- getAsCXXRecordDeclOrPrimaryTemplate(const Type *TypeNode) {
- if (auto *RD = TypeNode->getAsCXXRecordDecl())
- return RD;
- // Find the innermost TemplateSpecializationType that isn't an alias template.
- auto *TemplateType = TypeNode->getAs<TemplateSpecializationType>();
- while (TemplateType && TemplateType->isTypeAlias())
- TemplateType =
- TemplateType->getAliasedType()->getAs<TemplateSpecializationType>();
- // If this is the name of a (dependent) template specialization, use the
- // definition of the template, even though it might be specialized later.
- if (TemplateType)
- if (auto *ClassTemplate = dyn_cast_or_null<ClassTemplateDecl>(
- TemplateType->getTemplateName().getAsTemplateDecl()))
- return ClassTemplate->getTemplatedDecl();
- return nullptr;
- }
- // Returns true if the given C++ class is directly or indirectly derived
- // from a base type with the given name. A class is not considered to be
- // derived from itself.
- bool MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration,
- const Matcher<NamedDecl> &Base,
- BoundNodesTreeBuilder *Builder,
- bool Directly) {
- if (!Declaration->hasDefinition())
- return false;
- for (const auto &It : Declaration->bases()) {
- const Type *TypeNode = It.getType().getTypePtr();
- if (typeHasMatchingAlias(TypeNode, Base, Builder))
- return true;
- // FIXME: Going to the primary template here isn't really correct, but
- // unfortunately we accept a Decl matcher for the base class not a Type
- // matcher, so it's the best thing we can do with our current interface.
- CXXRecordDecl *ClassDecl = getAsCXXRecordDeclOrPrimaryTemplate(TypeNode);
- if (!ClassDecl)
- continue;
- if (ClassDecl == Declaration) {
- // This can happen for recursive template definitions.
- continue;
- }
- BoundNodesTreeBuilder Result(*Builder);
- if (Base.matches(*ClassDecl, this, &Result)) {
- *Builder = std::move(Result);
- return true;
- }
- if (!Directly && classIsDerivedFrom(ClassDecl, Base, Builder, Directly))
- return true;
- }
- return false;
- }
- // Returns true if the given Objective-C class is directly or indirectly
- // derived from a matching base class. A class is not considered to be derived
- // from itself.
- bool MatchASTVisitor::objcClassIsDerivedFrom(
- const ObjCInterfaceDecl *Declaration, const Matcher<NamedDecl> &Base,
- BoundNodesTreeBuilder *Builder, bool Directly) {
- // Check if any of the superclasses of the class match.
- for (const ObjCInterfaceDecl *ClassDecl = Declaration->getSuperClass();
- ClassDecl != nullptr; ClassDecl = ClassDecl->getSuperClass()) {
- // Check if there are any matching compatibility aliases.
- if (objcClassHasMatchingCompatibilityAlias(ClassDecl, Base, Builder))
- return true;
- // Check if there are any matching type aliases.
- const Type *TypeNode = ClassDecl->getTypeForDecl();
- if (typeHasMatchingAlias(TypeNode, Base, Builder))
- return true;
- if (Base.matches(*ClassDecl, this, Builder))
- return true;
- // Not `return false` as a temporary workaround for PR43879.
- if (Directly)
- break;
- }
- return false;
- }
- bool MatchASTVisitor::TraverseDecl(Decl *DeclNode) {
- if (!DeclNode) {
- return true;
- }
- bool ScopedTraversal =
- TraversingASTNodeNotSpelledInSource || DeclNode->isImplicit();
- bool ScopedChildren = TraversingASTChildrenNotSpelledInSource;
- if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(DeclNode)) {
- auto SK = CTSD->getSpecializationKind();
- if (SK == TSK_ExplicitInstantiationDeclaration ||
- SK == TSK_ExplicitInstantiationDefinition)
- ScopedChildren = true;
- } else if (const auto *FD = dyn_cast<FunctionDecl>(DeclNode)) {
- if (FD->isDefaulted())
- ScopedChildren = true;
- if (FD->isTemplateInstantiation())
- ScopedTraversal = true;
- } else if (isa<BindingDecl>(DeclNode)) {
- ScopedChildren = true;
- }
- ASTNodeNotSpelledInSourceScope RAII1(this, ScopedTraversal);
- ASTChildrenNotSpelledInSourceScope RAII2(this, ScopedChildren);
- match(*DeclNode);
- return RecursiveASTVisitor<MatchASTVisitor>::TraverseDecl(DeclNode);
- }
- bool MatchASTVisitor::TraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue) {
- if (!StmtNode) {
- return true;
- }
- bool ScopedTraversal = TraversingASTNodeNotSpelledInSource ||
- TraversingASTChildrenNotSpelledInSource;
- ASTNodeNotSpelledInSourceScope RAII(this, ScopedTraversal);
- match(*StmtNode);
- return RecursiveASTVisitor<MatchASTVisitor>::TraverseStmt(StmtNode, Queue);
- }
- bool MatchASTVisitor::TraverseType(QualType TypeNode) {
- match(TypeNode);
- return RecursiveASTVisitor<MatchASTVisitor>::TraverseType(TypeNode);
- }
- bool MatchASTVisitor::TraverseTypeLoc(TypeLoc TypeLocNode) {
- // The RecursiveASTVisitor only visits types if they're not within TypeLocs.
- // We still want to find those types via matchers, so we match them here. Note
- // that the TypeLocs are structurally a shadow-hierarchy to the expressed
- // type, so we visit all involved parts of a compound type when matching on
- // each TypeLoc.
- match(TypeLocNode);
- match(TypeLocNode.getType());
- return RecursiveASTVisitor<MatchASTVisitor>::TraverseTypeLoc(TypeLocNode);
- }
- bool MatchASTVisitor::TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) {
- match(*NNS);
- return RecursiveASTVisitor<MatchASTVisitor>::TraverseNestedNameSpecifier(NNS);
- }
- bool MatchASTVisitor::TraverseNestedNameSpecifierLoc(
- NestedNameSpecifierLoc NNS) {
- if (!NNS)
- return true;
- match(NNS);
- // We only match the nested name specifier here (as opposed to traversing it)
- // because the traversal is already done in the parallel "Loc"-hierarchy.
- if (NNS.hasQualifier())
- match(*NNS.getNestedNameSpecifier());
- return
- RecursiveASTVisitor<MatchASTVisitor>::TraverseNestedNameSpecifierLoc(NNS);
- }
- bool MatchASTVisitor::TraverseConstructorInitializer(
- CXXCtorInitializer *CtorInit) {
- if (!CtorInit)
- return true;
- bool ScopedTraversal = TraversingASTNodeNotSpelledInSource ||
- TraversingASTChildrenNotSpelledInSource;
- if (!CtorInit->isWritten())
- ScopedTraversal = true;
- ASTNodeNotSpelledInSourceScope RAII1(this, ScopedTraversal);
- match(*CtorInit);
- return RecursiveASTVisitor<MatchASTVisitor>::TraverseConstructorInitializer(
- CtorInit);
- }
- bool MatchASTVisitor::TraverseTemplateArgumentLoc(TemplateArgumentLoc Loc) {
- match(Loc);
- return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateArgumentLoc(Loc);
- }
- bool MatchASTVisitor::TraverseAttr(Attr *AttrNode) {
- match(*AttrNode);
- return RecursiveASTVisitor<MatchASTVisitor>::TraverseAttr(AttrNode);
- }
- class MatchASTConsumer : public ASTConsumer {
- public:
- MatchASTConsumer(MatchFinder *Finder,
- MatchFinder::ParsingDoneTestCallback *ParsingDone)
- : Finder(Finder), ParsingDone(ParsingDone) {}
- private:
- void HandleTranslationUnit(ASTContext &Context) override {
- if (ParsingDone != nullptr) {
- ParsingDone->run();
- }
- Finder->matchAST(Context);
- }
- MatchFinder *Finder;
- MatchFinder::ParsingDoneTestCallback *ParsingDone;
- };
- } // end namespace
- } // end namespace internal
- MatchFinder::MatchResult::MatchResult(const BoundNodes &Nodes,
- ASTContext *Context)
- : Nodes(Nodes), Context(Context),
- SourceManager(&Context->getSourceManager()) {}
- MatchFinder::MatchCallback::~MatchCallback() {}
- MatchFinder::ParsingDoneTestCallback::~ParsingDoneTestCallback() {}
- MatchFinder::MatchFinder(MatchFinderOptions Options)
- : Options(std::move(Options)), ParsingDone(nullptr) {}
- MatchFinder::~MatchFinder() {}
- void MatchFinder::addMatcher(const DeclarationMatcher &NodeMatch,
- MatchCallback *Action) {
- std::optional<TraversalKind> TK;
- if (Action)
- TK = Action->getCheckTraversalKind();
- if (TK)
- Matchers.DeclOrStmt.emplace_back(traverse(*TK, NodeMatch), Action);
- else
- Matchers.DeclOrStmt.emplace_back(NodeMatch, Action);
- Matchers.AllCallbacks.insert(Action);
- }
- void MatchFinder::addMatcher(const TypeMatcher &NodeMatch,
- MatchCallback *Action) {
- Matchers.Type.emplace_back(NodeMatch, Action);
- Matchers.AllCallbacks.insert(Action);
- }
- void MatchFinder::addMatcher(const StatementMatcher &NodeMatch,
- MatchCallback *Action) {
- std::optional<TraversalKind> TK;
- if (Action)
- TK = Action->getCheckTraversalKind();
- if (TK)
- Matchers.DeclOrStmt.emplace_back(traverse(*TK, NodeMatch), Action);
- else
- Matchers.DeclOrStmt.emplace_back(NodeMatch, Action);
- Matchers.AllCallbacks.insert(Action);
- }
- void MatchFinder::addMatcher(const NestedNameSpecifierMatcher &NodeMatch,
- MatchCallback *Action) {
- Matchers.NestedNameSpecifier.emplace_back(NodeMatch, Action);
- Matchers.AllCallbacks.insert(Action);
- }
- void MatchFinder::addMatcher(const NestedNameSpecifierLocMatcher &NodeMatch,
- MatchCallback *Action) {
- Matchers.NestedNameSpecifierLoc.emplace_back(NodeMatch, Action);
- Matchers.AllCallbacks.insert(Action);
- }
- void MatchFinder::addMatcher(const TypeLocMatcher &NodeMatch,
- MatchCallback *Action) {
- Matchers.TypeLoc.emplace_back(NodeMatch, Action);
- Matchers.AllCallbacks.insert(Action);
- }
- void MatchFinder::addMatcher(const CXXCtorInitializerMatcher &NodeMatch,
- MatchCallback *Action) {
- Matchers.CtorInit.emplace_back(NodeMatch, Action);
- Matchers.AllCallbacks.insert(Action);
- }
- void MatchFinder::addMatcher(const TemplateArgumentLocMatcher &NodeMatch,
- MatchCallback *Action) {
- Matchers.TemplateArgumentLoc.emplace_back(NodeMatch, Action);
- Matchers.AllCallbacks.insert(Action);
- }
- void MatchFinder::addMatcher(const AttrMatcher &AttrMatch,
- MatchCallback *Action) {
- Matchers.Attr.emplace_back(AttrMatch, Action);
- Matchers.AllCallbacks.insert(Action);
- }
- bool MatchFinder::addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch,
- MatchCallback *Action) {
- if (NodeMatch.canConvertTo<Decl>()) {
- addMatcher(NodeMatch.convertTo<Decl>(), Action);
- return true;
- } else if (NodeMatch.canConvertTo<QualType>()) {
- addMatcher(NodeMatch.convertTo<QualType>(), Action);
- return true;
- } else if (NodeMatch.canConvertTo<Stmt>()) {
- addMatcher(NodeMatch.convertTo<Stmt>(), Action);
- return true;
- } else if (NodeMatch.canConvertTo<NestedNameSpecifier>()) {
- addMatcher(NodeMatch.convertTo<NestedNameSpecifier>(), Action);
- return true;
- } else if (NodeMatch.canConvertTo<NestedNameSpecifierLoc>()) {
- addMatcher(NodeMatch.convertTo<NestedNameSpecifierLoc>(), Action);
- return true;
- } else if (NodeMatch.canConvertTo<TypeLoc>()) {
- addMatcher(NodeMatch.convertTo<TypeLoc>(), Action);
- return true;
- } else if (NodeMatch.canConvertTo<CXXCtorInitializer>()) {
- addMatcher(NodeMatch.convertTo<CXXCtorInitializer>(), Action);
- return true;
- } else if (NodeMatch.canConvertTo<TemplateArgumentLoc>()) {
- addMatcher(NodeMatch.convertTo<TemplateArgumentLoc>(), Action);
- return true;
- } else if (NodeMatch.canConvertTo<Attr>()) {
- addMatcher(NodeMatch.convertTo<Attr>(), Action);
- return true;
- }
- return false;
- }
- std::unique_ptr<ASTConsumer> MatchFinder::newASTConsumer() {
- return std::make_unique<internal::MatchASTConsumer>(this, ParsingDone);
- }
- void MatchFinder::match(const clang::DynTypedNode &Node, ASTContext &Context) {
- internal::MatchASTVisitor Visitor(&Matchers, Options);
- Visitor.set_active_ast_context(&Context);
- Visitor.match(Node);
- }
- void MatchFinder::matchAST(ASTContext &Context) {
- internal::MatchASTVisitor Visitor(&Matchers, Options);
- internal::MatchASTVisitor::TraceReporter StackTrace(Visitor);
- Visitor.set_active_ast_context(&Context);
- Visitor.onStartOfTranslationUnit();
- Visitor.TraverseAST(Context);
- Visitor.onEndOfTranslationUnit();
- }
- void MatchFinder::registerTestCallbackAfterParsing(
- MatchFinder::ParsingDoneTestCallback *NewParsingDone) {
- ParsingDone = NewParsingDone;
- }
- StringRef MatchFinder::MatchCallback::getID() const { return "<unknown>"; }
- std::optional<TraversalKind>
- MatchFinder::MatchCallback::getCheckTraversalKind() const {
- return std::nullopt;
- }
- } // end namespace ast_matchers
- } // end namespace clang
|