clang: lib/ASTMatchers/ASTMatchFinder.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

23#include "llvm/ADT/DenseMap.h"

24#include "llvm/ADT/SmallPtrSet.h"

25#include "llvm/ADT/StringMap.h"

26#include "llvm/Support/PrettyStackTrace.h"

27#include "llvm/Support/Timer.h"

28#include

29#include

30#include

31

33namespace ast_matchers {

34namespace internal {

35namespace {

36

37typedef MatchFinder::MatchCallback MatchCallback;

38

39

40

41

42

43

44

45

46

47static const unsigned MaxMemoizationEntries = 10000;

48

49enum class MatchType {

50 Ancestors,

51

52 Descendants,

53 Child,

54};

55

56

57

58

59

60

61

62

63

64

65

66

67

68struct MatchKey {

74

78 Other.BoundNodes);

79 }

80};

81

82

83struct MemoizedMatchResult {

85 BoundNodesTreeBuilder Nodes;

86};

87

88

89

90class MatchChildASTVisitor

91 : public RecursiveASTVisitor {

92public:

93 typedef RecursiveASTVisitor VisitorBase;

94

95

96

97

98

99 MatchChildASTVisitor(const DynTypedMatcher *Matcher, ASTMatchFinder *Finder,

100 BoundNodesTreeBuilder *Builder, int MaxDepth,

101 bool IgnoreImplicitChildren,

102 ASTMatchFinder::BindKind Bind)

103 : Matcher(Matcher), Finder(Finder), Builder(Builder), CurrentDepth(0),

104 MaxDepth(MaxDepth), IgnoreImplicitChildren(IgnoreImplicitChildren),

105 Bind(Bind), Matches(false) {}

106

107

108

109

110

111

112

113

114

115

116

117

118 bool findMatch(const DynTypedNode &DynNode) {

119 reset();

120 if (const Decl *D = DynNode.get())

122 else if (const Stmt *S = DynNode.get())

124 else if (const NestedNameSpecifier *NNS =

125 DynNode.get())

127 else if (const NestedNameSpecifierLoc *NNSLoc =

128 DynNode.get())

130 else if (const QualType *Q = DynNode.get())

132 else if (const TypeLoc *T = DynNode.get())

134 else if (const auto *C = DynNode.get())

136 else if (const TemplateArgumentLoc *TALoc =

137 DynNode.get())

139 else if (const Attr *A = DynNode.get())

141

142

143

144

145

146 *Builder = ResultBindings;

147

148 return Matches;

149 }

150

151

152

153

154 bool TraverseDecl(Decl *DeclNode) {

155

156 if (DeclNode && DeclNode->isImplicit() &&

157 Finder->isTraversalIgnoringImplicitNodes())

158 return baseTraverse(*DeclNode);

159

160 ScopedIncrement ScopedDepth(&CurrentDepth);

161 return (DeclNode == nullptr) || traverse(*DeclNode);

162 }

163

164 Stmt *getStmtToTraverse(Stmt *StmtNode) {

165 Stmt *StmtToTraverse = StmtNode;

166 if (auto *ExprNode = dyn_cast_or_null(StmtNode)) {

167 auto *LambdaNode = dyn_cast_or_null(StmtNode);

168 if (LambdaNode && Finder->isTraversalIgnoringImplicitNodes())

169 StmtToTraverse = LambdaNode;

170 else

171 StmtToTraverse =

172 Finder->getASTContext().getParentMapContext().traverseIgnored(

173 ExprNode);

174 }

175 return StmtToTraverse;

176 }

177

178 bool TraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue = nullptr) {

179

180 if (CurrentDepth == 0 || (CurrentDepth <= MaxDepth && MaxDepth < INT_MAX))

181 Queue = nullptr;

182

183 ScopedIncrement ScopedDepth(&CurrentDepth);

184 Stmt *StmtToTraverse = getStmtToTraverse(StmtNode);

185 if (!StmtToTraverse)

186 return true;

187

188 if (IgnoreImplicitChildren && isa(StmtNode))

189 return true;

190

191 if (match(*StmtToTraverse))

192 return false;

194 }

195

196

197 bool TraverseType(QualType TypeNode) {

198 if (TypeNode.isNull())

199 return true;

200 ScopedIncrement ScopedDepth(&CurrentDepth);

201

202 if (match(*TypeNode))

203 return false;

204

206 }

207

208

209 bool TraverseTypeLoc(TypeLoc TypeLocNode) {

210 if (TypeLocNode.isNull())

211 return true;

212 ScopedIncrement ScopedDepth(&CurrentDepth);

213

214 if (match(*TypeLocNode.getType()))

215 return false;

216

217 if (match(TypeLocNode.getType()))

218 return false;

219

220 return traverse(TypeLocNode);

221 }

222 bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) {

223 ScopedIncrement ScopedDepth(&CurrentDepth);

224 return (NNS == nullptr) || traverse(*NNS);

225 }

226 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {

227 if (!NNS)

228 return true;

229 ScopedIncrement ScopedDepth(&CurrentDepth);

230 if (match(*NNS.getNestedNameSpecifier()))

231 return false;

233 }

234 bool TraverseConstructorInitializer(CXXCtorInitializer *CtorInit) {

235 if (!CtorInit)

236 return true;

237 ScopedIncrement ScopedDepth(&CurrentDepth);

239 }

240 bool TraverseTemplateArgumentLoc(TemplateArgumentLoc TAL) {

241 ScopedIncrement ScopedDepth(&CurrentDepth);

243 }

244 bool TraverseCXXForRangeStmt(CXXForRangeStmt *Node) {

245 if (!Finder->isTraversalIgnoringImplicitNodes())

246 return VisitorBase::TraverseCXXForRangeStmt(Node);

248 return true;

249 ScopedIncrement ScopedDepth(&CurrentDepth);

250 if (auto *Init = Node->getInit())

252 return false;

253 if (match(*Node->getLoopVariable()))

254 return false;

255 if (match(*Node->getRangeInit()))

257 return false;

259 return false;

261 }

262 bool TraverseCXXRewrittenBinaryOperator(CXXRewrittenBinaryOperator *Node) {

263 if (!Finder->isTraversalIgnoringImplicitNodes())

264 return VisitorBase::TraverseCXXRewrittenBinaryOperator(Node);

266 return true;

267 ScopedIncrement ScopedDepth(&CurrentDepth);

268

270 }

271 bool TraverseAttr(Attr *A) {

272 if (A == nullptr ||

273 (A->isImplicit() &&

274 Finder->getASTContext().getParentMapContext().getTraversalKind() ==

276 return true;

277 ScopedIncrement ScopedDepth(&CurrentDepth);

279 }

280 bool TraverseLambdaExpr(LambdaExpr *Node) {

281 if (!Finder->isTraversalIgnoringImplicitNodes())

282 return VisitorBase::TraverseLambdaExpr(Node);

284 return true;

285 ScopedIncrement ScopedDepth(&CurrentDepth);

286

287 for (unsigned I = 0, N = Node->capture_size(); I != N; ++I) {

288 const LambdaCapture *C = Node->capture_begin() + I;

289 if (C->isExplicit())

290 continue;

291 if (Node->isInitCapture(C) && match(*C->getCapturedVar()))

292 return false;

293 const Expr *CIE = Node->capture_init_begin()[I];

294 if (CIE != nullptr && match(*CIE))

295 return false;

296 }

297

298 if (const auto *TPL = Node->getTemplateParameterList()) {

299 for (const auto *TP : *TPL) {

301 return false;

302 }

303 }

304

305 for (const auto *P : Node->getCallOperator()->parameters()) {

307 return false;

308 }

309

311 return false;

312

314 }

315

316 bool shouldVisitTemplateInstantiations() const { return true; }

317 bool shouldVisitImplicitCode() const { return !IgnoreImplicitChildren; }

318

319private:

320

321 struct ScopedIncrement {

322 explicit ScopedIncrement(int *Depth) : Depth(Depth) { ++(*Depth); }

323 ~ScopedIncrement() { --(*Depth); }

324

325 private:

326 int *Depth;

327 };

328

329

330 void reset() {

331 Matches = false;

332 CurrentDepth = 0;

333 }

334

335

336

337 bool baseTraverse(const Decl &DeclNode) {

339 }

340 bool baseTraverse(const Stmt &StmtNode) {

342 }

343 bool baseTraverse(QualType TypeNode) {

345 }

346 bool baseTraverse(TypeLoc TypeLocNode) {

348 }

349 bool baseTraverse(const NestedNameSpecifier &NNS) {

351 const_cast<NestedNameSpecifier*>(&NNS));

352 }

353 bool baseTraverse(NestedNameSpecifierLoc NNS) {

355 }

356 bool baseTraverse(const CXXCtorInitializer &CtorInit) {

358 const_cast<CXXCtorInitializer *>(&CtorInit));

359 }

360 bool baseTraverse(TemplateArgumentLoc TAL) {

362 }

363 bool baseTraverse(const Attr &AttrNode) {

365 }

366

367

368

369

370

371

372 template

374 if (CurrentDepth == 0 || CurrentDepth > MaxDepth) {

375 return true;

376 }

377 if (Bind != ASTMatchFinder::BK_All) {

378 BoundNodesTreeBuilder RecursiveBuilder(*Builder);

380 &RecursiveBuilder)) {

381 Matches = true;

382 ResultBindings.addMatch(RecursiveBuilder);

383 return false;

384 }

385 } else {

386 BoundNodesTreeBuilder RecursiveBuilder(*Builder);

388 &RecursiveBuilder)) {

389

390 Matches = true;

391 ResultBindings.addMatch(RecursiveBuilder);

392 }

393 }

394 return true;

395 }

396

397

398

399 template

401 static_assert(IsBaseType::value,

402 "traverse can only be instantiated with base type");

404 return false;

405 return baseTraverse(Node);

406 }

407

408 const DynTypedMatcher *const Matcher;

409 ASTMatchFinder *const Finder;

410 BoundNodesTreeBuilder *const Builder;

411 BoundNodesTreeBuilder ResultBindings;

412 int CurrentDepth;

413 const int MaxDepth;

414 const bool IgnoreImplicitChildren;

415 const ASTMatchFinder::BindKind Bind;

416 bool Matches;

417};

418

419

420

421class MatchASTVisitor : public RecursiveASTVisitor,

422 public ASTMatchFinder {

423public:

424 MatchASTVisitor(const MatchFinder::MatchersByType *Matchers,

425 const MatchFinder::MatchFinderOptions &Options)

426 : Matchers(Matchers), Options(Options), ActiveASTContext(nullptr) {}

427

428 ~MatchASTVisitor() override {

429 if (Options.CheckProfiling) {

430 Options.CheckProfiling->Records = std::move(TimeByBucket);

431 }

432 }

433

434 void onStartOfTranslationUnit() {

435 const bool EnableCheckProfiling = Options.CheckProfiling.has_value();

436 TimeBucketRegion Timer;

437 for (MatchCallback *MC : Matchers->AllCallbacks) {

438 if (EnableCheckProfiling)

439 Timer.setBucket(&TimeByBucket[MC->getID()]);

440 MC->onStartOfTranslationUnit();

441 }

442 }

443

444 void onEndOfTranslationUnit() {

445 const bool EnableCheckProfiling = Options.CheckProfiling.has_value();

446 TimeBucketRegion Timer;

447 for (MatchCallback *MC : Matchers->AllCallbacks) {

448 if (EnableCheckProfiling)

449 Timer.setBucket(&TimeByBucket[MC->getID()]);

450 MC->onEndOfTranslationUnit();

451 }

452 }

453

454 void set_active_ast_context(ASTContext *NewActiveASTContext) {

455 ActiveASTContext = NewActiveASTContext;

456 }

457

458

459

460

461 bool VisitTypedefNameDecl(TypedefNameDecl *DeclNode) {

462

463

464

465

466

467

468

469

470

471

472

473

474

475

476

477

478

479

480

481

482

483

484

485

486

487

488

489 const Type *TypeNode = DeclNode->getUnderlyingType().getTypePtr();

490 const Type *CanonicalType =

491 ActiveASTContext->getCanonicalType(TypeNode);

492 TypeAliases[CanonicalType].insert(DeclNode);

493 return true;

494 }

495

496 bool VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *CAD) {

497 const ObjCInterfaceDecl *InterfaceDecl = CAD->getClassInterface();

498 CompatibleAliases[InterfaceDecl].insert(CAD);

499 return true;

500 }

501

502 bool TraverseDecl(Decl *DeclNode);

503 bool TraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue = nullptr);

504 bool TraverseType(QualType TypeNode);

505 bool TraverseTypeLoc(TypeLoc TypeNode);

506 bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS);

507 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS);

508 bool TraverseConstructorInitializer(CXXCtorInitializer *CtorInit);

509 bool TraverseTemplateArgumentLoc(TemplateArgumentLoc TAL);

510 bool TraverseAttr(Attr *AttrNode);

511

512 bool dataTraverseNode(Stmt *S, DataRecursionQueue *Queue) {

513 if (auto *RF = dyn_cast(S)) {

514 {

515 ASTNodeNotAsIsSourceScope RAII(this, true);

516 TraverseStmt(RF->getInit());

517

518 match(*RF->getLoopVariable());

519 TraverseStmt(RF->getRangeInit());

520 }

521 {

522 ASTNodeNotSpelledInSourceScope RAII(this, true);

523 for (auto *SubStmt : RF->children()) {

524 if (SubStmt != RF->getBody())

525 TraverseStmt(SubStmt);

526 }

527 }

528 TraverseStmt(RF->getBody());

529 return true;

530 } else if (auto *RBO = dyn_cast(S)) {

531 {

532 ASTNodeNotAsIsSourceScope RAII(this, true);

533 TraverseStmt(const_cast<Expr *>(RBO->getLHS()));

534 TraverseStmt(const_cast<Expr *>(RBO->getRHS()));

535 }

536 {

537 ASTNodeNotSpelledInSourceScope RAII(this, true);

538 for (auto *SubStmt : RBO->children()) {

539 TraverseStmt(SubStmt);

540 }

541 }

542 return true;

543 } else if (auto *LE = dyn_cast(S)) {

544 for (auto I : llvm::zip(LE->captures(), LE->capture_inits())) {

545 auto C = std::get<0>(I);

546 ASTNodeNotSpelledInSourceScope RAII(

547 this, TraversingASTNodeNotSpelledInSource || C.isExplicit());

548 TraverseLambdaCapture(LE, &C, std::get<1>(I));

549 }

550

551 {

552 ASTNodeNotSpelledInSourceScope RAII(this, true);

553 TraverseDecl(LE->getLambdaClass());

554 }

555 {

556 ASTNodeNotAsIsSourceScope RAII(this, true);

557

558

559

560 TypeLoc TL = LE->getCallOperator()->getTypeSourceInfo()->getTypeLoc();

561 FunctionProtoTypeLoc Proto = TL.getAsAdjusted();

562

563 if (auto *TPL = LE->getTemplateParameterList()) {

564 for (NamedDecl *D : *TPL) {

565 TraverseDecl(D);

566 }

567 if (Expr *RequiresClause = TPL->getRequiresClause()) {

568 TraverseStmt(RequiresClause);

569 }

570 }

571

572 if (LE->hasExplicitParameters()) {

573

574 for (ParmVarDecl *Param : Proto.getParams())

575 TraverseDecl(Param);

576 }

577

578 const auto *T = Proto.getTypePtr();

580 TraverseType(E);

581

583 TraverseStmt(NE, Queue);

584

585 if (LE->hasExplicitResultType())

586 TraverseTypeLoc(Proto.getReturnLoc());

587 TraverseStmt(LE->getTrailingRequiresClause());

588 }

589

590 TraverseStmt(LE->getBody());

591 return true;

592 }

594 }

595

596

597 bool memoizedMatchesRecursively(const DynTypedNode &Node, ASTContext &Ctx,

598 const DynTypedMatcher &Matcher,

599 BoundNodesTreeBuilder *Builder, int MaxDepth,

600 BindKind Bind) {

601

602 if (Node.getMemoizationData() || !Builder->isComparable())

603 return matchesRecursively(Node, Matcher, Builder, MaxDepth, Bind);

604

605 MatchKey Key;

606 Key.MatcherID = Matcher.getID();

607 Key.Node = Node;

608

609 Key.BoundNodes = *Builder;

610 Key.Traversal = Ctx.getParentMapContext().getTraversalKind();

611

612 Key.Type = MaxDepth == 1 ? MatchType::Child : MatchType::Descendants;

613 MemoizationMap::iterator I = ResultCache.find(Key);

614 if (I != ResultCache.end()) {

615 *Builder = I->second.Nodes;

616 return I->second.ResultOfMatch;

617 }

618

619 MemoizedMatchResult Result;

620 Result.Nodes = *Builder;

621 Result.ResultOfMatch =

622 matchesRecursively(Node, Matcher, &Result.Nodes, MaxDepth, Bind);

623

624 MemoizedMatchResult &CachedResult = ResultCache[Key];

625 CachedResult = std::move(Result);

626

627 *Builder = CachedResult.Nodes;

628 return CachedResult.ResultOfMatch;

629 }

630

631

632 bool matchesRecursively(const DynTypedNode &Node,

633 const DynTypedMatcher &Matcher,

634 BoundNodesTreeBuilder *Builder, int MaxDepth,

635 BindKind Bind) {

636 bool ScopedTraversal = TraversingASTNodeNotSpelledInSource ||

637 TraversingASTChildrenNotSpelledInSource;

638

639 bool IgnoreImplicitChildren = false;

640

641 if (isTraversalIgnoringImplicitNodes()) {

642 IgnoreImplicitChildren = true;

643 }

644

645 ASTNodeNotSpelledInSourceScope RAII(this, ScopedTraversal);

646

647 MatchChildASTVisitor Visitor(&Matcher, this, Builder, MaxDepth,

648 IgnoreImplicitChildren, Bind);

649 return Visitor.findMatch(Node);

650 }

651

652 bool classIsDerivedFrom(const CXXRecordDecl *Declaration,

653 const Matcher &Base,

654 BoundNodesTreeBuilder *Builder,

655 bool Directly) override;

656

657private:

658 bool

659 classIsDerivedFromImpl(const CXXRecordDecl *Declaration,

660 const Matcher &Base,

661 BoundNodesTreeBuilder *Builder, bool Directly,

662 llvm::SmallPtrSetImpl<const CXXRecordDecl *> &Visited);

663

664public:

665 bool objcClassIsDerivedFrom(const ObjCInterfaceDecl *Declaration,

666 const Matcher &Base,

667 BoundNodesTreeBuilder *Builder,

668 bool Directly) override;

669

670public:

671

672 bool matchesChildOf(const DynTypedNode &Node, ASTContext &Ctx,

673 const DynTypedMatcher &Matcher,

674 BoundNodesTreeBuilder *Builder, BindKind Bind) override {

675 if (ResultCache.size() > MaxMemoizationEntries)

676 ResultCache.clear();

677 return memoizedMatchesRecursively(Node, Ctx, Matcher, Builder, 1, Bind);

678 }

679

680 bool matchesDescendantOf(const DynTypedNode &Node, ASTContext &Ctx,

681 const DynTypedMatcher &Matcher,

682 BoundNodesTreeBuilder *Builder,

683 BindKind Bind) override {

684 if (ResultCache.size() > MaxMemoizationEntries)

685 ResultCache.clear();

686 return memoizedMatchesRecursively(Node, Ctx, Matcher, Builder, INT_MAX,

688 }

689

690 bool matchesAncestorOf(const DynTypedNode &Node, ASTContext &Ctx,

691 const DynTypedMatcher &Matcher,

692 BoundNodesTreeBuilder *Builder,

693 AncestorMatchMode MatchMode) override {

694

695

696 if (ResultCache.size() > MaxMemoizationEntries)

697 ResultCache.clear();

698 if (MatchMode == AncestorMatchMode::AMM_ParentOnly)

699 return matchesParentOf(Node, Matcher, Builder);

700 return matchesAnyAncestorOf(Node, Ctx, Matcher, Builder);

701 }

702

703

704

705 void match(const DynTypedNode &Node) {

706

707 if (auto *N = Node.get()) {

709 } else if (auto *N = Node.get()) {

711 } else if (auto *N = Node.get()) {

713 } else if (auto *N = Node.get()) {

715 } else if (auto *N = Node.get()) {

717 } else if (auto *N = Node.get()) {

719 } else if (auto *N = Node.get()) {

721 } else if (auto *N = Node.get()) {

723 } else if (auto *N = Node.get()) {

725 } else if (auto *N = Node.get()) {

727 }

728 }

729

730 template void match(const T &Node) {

731 matchDispatch(&Node);

732 }

733

734

735 ASTContext &getASTContext() const override { return *ActiveASTContext; }

736

737 bool shouldVisitTemplateInstantiations() const { return true; }

738 bool shouldVisitImplicitCode() const { return true; }

739

740

741

742 bool shouldVisitLambdaBody() const { return false; }

743

744 bool IsMatchingInASTNodeNotSpelledInSource() const override {

745 return TraversingASTNodeNotSpelledInSource;

746 }

747 bool isMatchingChildrenNotSpelledInSource() const override {

748 return TraversingASTChildrenNotSpelledInSource;

749 }

750 void setMatchingChildrenNotSpelledInSource(bool Set) override {

751 TraversingASTChildrenNotSpelledInSource = Set;

752 }

753

754 bool IsMatchingInASTNodeNotAsIs() const override {

755 return TraversingASTNodeNotAsIs;

756 }

757

758 bool TraverseTemplateInstantiations(ClassTemplateDecl *D) {

759 ASTNodeNotSpelledInSourceScope RAII(this, true);

760 return RecursiveASTVisitor::TraverseTemplateInstantiations(

761 D);

762 }

763

764 bool TraverseTemplateInstantiations(VarTemplateDecl *D) {

765 ASTNodeNotSpelledInSourceScope RAII(this, true);

766 return RecursiveASTVisitor::TraverseTemplateInstantiations(

767 D);

768 }

769

770 bool TraverseTemplateInstantiations(FunctionTemplateDecl *D) {

771 ASTNodeNotSpelledInSourceScope RAII(this, true);

772 return RecursiveASTVisitor::TraverseTemplateInstantiations(

773 D);

774 }

775

776private:

777 bool TraversingASTNodeNotSpelledInSource = false;

778 bool TraversingASTNodeNotAsIs = false;

779 bool TraversingASTChildrenNotSpelledInSource = false;

780

781 class CurMatchData {

782

783

784

785#define CMD_TYPES_0 \

786 const QualType *, const TypeLoc *, const NestedNameSpecifier *, \

787 const NestedNameSpecifierLoc *

788#define CMD_TYPES_1 \

789 const CXXCtorInitializer *, const TemplateArgumentLoc *, const Attr *, \

790 const DynTypedNode *

791

792#define IMPL(Index) \

793 template \

794 std::enable_if_t< \

795 llvm::is_one_of<const NodeType *, CMD_TYPES_##Index>::value> \

796 SetCallbackAndRawNode(const MatchCallback *CB, const NodeType &N) { \

797 assertEmpty(); \

798 Callback.setPointerAndInt(CB, Index); \

799 Node##Index = &N; \

800 } \

801 \

802 template \

803 std::enable_if_t<llvm::is_one_of<const T *, CMD_TYPES_##Index>::value, \

804 const T *> \

805 getNode() const { \

806 assertHoldsState(); \

807 return Callback.getInt() == (Index) ? Node##Index.dyn_cast<const T *>() \

808 : nullptr; \

809 }

810

811 public:

812 CurMatchData() : Node0(nullptr) {}

813

816

817 const MatchCallback *getCallback() const { return Callback.getPointer(); }

818

819 void SetBoundNodes(const BoundNodes &BN) {

820 assertHoldsState();

821 BNodes = &BN;

822 }

823

824 void clearBoundNodes() {

825 assertHoldsState();

826 BNodes = nullptr;

827 }

828

829 const BoundNodes *getBoundNodes() const {

830 assertHoldsState();

831 return BNodes;

832 }

833

834 void reset() {

835 assertHoldsState();

836 Callback.setPointerAndInt(nullptr, 0);

838 }

839

840 private:

841 void assertHoldsState() const {

842 assert(Callback.getPointer() != nullptr && Node0.isNull());

843 }

844

845 void assertEmpty() const {

846 assert(Callback.getPointer() == nullptr && Node0.isNull() &&

847 BNodes == nullptr);

848 }

849

850 llvm::PointerIntPair<const MatchCallback *, 1> Callback;

851 union {

852 llvm::PointerUnion<CMD_TYPES_0> Node0;

853 llvm::PointerUnion<CMD_TYPES_1> Node1;

854 };

856

857#undef CMD_TYPES_0

858#undef CMD_TYPES_1

859#undef IMPL

860 } CurMatchState;

861

862 struct CurMatchRAII {

863 template

864 CurMatchRAII(MatchASTVisitor &MV, const MatchCallback *CB,

865 const NodeType &NT)

866 : MV(MV) {

867 MV.CurMatchState.SetCallbackAndRawNode(CB, NT);

868 }

869

870 ~CurMatchRAII() { MV.CurMatchState.reset(); }

871

872 private:

873 MatchASTVisitor &MV;

874 };

875

876public:

877 class TraceReporter : llvm::PrettyStackTraceEntry {

878 static void dumpNode(const ASTContext &Ctx, const DynTypedNode &Node,

879 raw_ostream &OS) {

880 if (const auto *D = Node.get()) {

881 OS << D->getDeclKindName() << "Decl ";

882 if (const auto *ND = dyn_cast(D)) {

883 ND->printQualifiedName(OS);

884 OS << " : ";

885 } else

886 OS << ": ";

887 D->getSourceRange().print(OS, Ctx.getSourceManager());

888 } else if (const auto *S = Node.get()) {

889 OS << S->getStmtClassName() << " : ";

890 S->getSourceRange().print(OS, Ctx.getSourceManager());

891 } else if (const auto *T = Node.get()) {

893 QualType(T, 0).print(OS, Ctx.getPrintingPolicy());

894 } else if (const auto *QT = Node.get()) {

895 OS << "QualType : ";

896 QT->print(OS, Ctx.getPrintingPolicy());

897 } else {

898 OS << Node.getNodeKind().asStringRef() << " : ";

899 Node.getSourceRange().print(OS, Ctx.getSourceManager());

900 }

901 }

902

903 static void dumpNodeFromState(const ASTContext &Ctx,

904 const CurMatchData &State, raw_ostream &OS) {

905 if (const DynTypedNode *MatchNode = State.getNode()) {

906 dumpNode(Ctx, *MatchNode, OS);

907 } else if (const auto *QT = State.getNode()) {

909 } else if (const auto *TL = State.getNode()) {

911 } else if (const auto *NNS = State.getNode()) {

913 } else if (const auto *NNSL = State.getNode()) {

915 } else if (const auto *CtorInit = State.getNode()) {

917 } else if (const auto *TAL = State.getNode()) {

919 } else if (const auto *At = State.getNode()) {

921 }

922 }

923

924 public:

925 TraceReporter(const MatchASTVisitor &MV) : MV(MV) {}

926 void print(raw_ostream &OS) const override {

927 const CurMatchData &State = MV.CurMatchState;

928 const MatchCallback *CB = State.getCallback();

929 if (!CB) {

930 OS << "ASTMatcher: Not currently matching\n";

931 return;

932 }

933

934 assert(MV.ActiveASTContext &&

935 "ActiveASTContext should be set if there is a matched callback");

936

937 ASTContext &Ctx = MV.getASTContext();

938

939 if (const BoundNodes *Nodes = State.getBoundNodes()) {

940 OS << "ASTMatcher: Processing '" << CB->getID() << "' against:\n\t";

941 dumpNodeFromState(Ctx, State, OS);

943 if (Map.empty()) {

944 OS << "\nNo bound nodes\n";

945 return;

946 }

947 OS << "\n--- Bound Nodes Begin ---\n";

948 for (const auto &Item : Map) {

949 OS << " " << Item.first << " - { ";

950 dumpNode(Ctx, Item.second, OS);

951 OS << " }\n";

952 }

953 OS << "--- Bound Nodes End ---\n";

954 } else {

955 OS << "ASTMatcher: Matching '" << CB->getID() << "' against:\n\t";

956 dumpNodeFromState(Ctx, State, OS);

957 OS << '\n';

958 }

959 }

960

961 private:

962 const MatchASTVisitor &MV;

963 };

964

965private:

966 struct ASTNodeNotSpelledInSourceScope {

967 ASTNodeNotSpelledInSourceScope(MatchASTVisitor *V, bool B)

968 : MV(V), MB(V->TraversingASTNodeNotSpelledInSource) {

969 V->TraversingASTNodeNotSpelledInSource = B;

970 }

971 ~ASTNodeNotSpelledInSourceScope() {

972 MV->TraversingASTNodeNotSpelledInSource = MB;

973 }

974

975 private:

976 MatchASTVisitor *MV;

977 bool MB;

978 };

979

980 struct ASTNodeNotAsIsSourceScope {

981 ASTNodeNotAsIsSourceScope(MatchASTVisitor *V, bool B)

982 : MV(V), MB(V->TraversingASTNodeNotAsIs) {

983 V->TraversingASTNodeNotAsIs = B;

984 }

985 ~ASTNodeNotAsIsSourceScope() { MV->TraversingASTNodeNotAsIs = MB; }

986

987 private:

988 MatchASTVisitor *MV;

989 bool MB;

990 };

991

992 class TimeBucketRegion {

993 public:

994 TimeBucketRegion() = default;

995 ~TimeBucketRegion() { setBucket(nullptr); }

996

997

998

999

1000

1001

1002

1003

1004

1005 void setBucket(llvm::TimeRecord *NewBucket) {

1006 if (Bucket != NewBucket) {

1007 auto Now = llvm::TimeRecord::getCurrentTime(true);

1008 if (Bucket)

1009 *Bucket += Now;

1010 if (NewBucket)

1011 *NewBucket -= Now;

1012 Bucket = NewBucket;

1013 }

1014 }

1015

1016 private:

1017 llvm::TimeRecord *Bucket = nullptr;

1018 };

1019

1020

1021

1022

1023 template <typename T, typename MC>

1024 void matchWithoutFilter(const T &Node, const MC &Matchers) {

1025 const bool EnableCheckProfiling = Options.CheckProfiling.has_value();

1026 TimeBucketRegion Timer;

1027 for (const auto &MP : Matchers) {

1028 if (EnableCheckProfiling)

1029 Timer.setBucket(&TimeByBucket[MP.second->getID()]);

1030 BoundNodesTreeBuilder Builder;

1031 CurMatchRAII RAII(*this, MP.second, Node);

1032 if (MP.first.matches(Node, this, &Builder)) {

1033 MatchVisitor Visitor(*this, ActiveASTContext, MP.second);

1034 Builder.visitMatches(&Visitor);

1035 }

1036 }

1037 }

1038

1039 void matchWithFilter(const DynTypedNode &DynNode) {

1040 auto Kind = DynNode.getNodeKind();

1041 auto it = MatcherFiltersMap.find(Kind);

1042 const auto &Filter =

1043 it != MatcherFiltersMap.end() ? it->second : getFilterForKind(Kind);

1044

1046 return;

1047

1048 const bool EnableCheckProfiling = Options.CheckProfiling.has_value();

1049 TimeBucketRegion Timer;

1050 auto &Matchers = this->Matchers->DeclOrStmt;

1051 for (unsigned short I : Filter) {

1052 auto &MP = Matchers[I];

1053 if (EnableCheckProfiling)

1054 Timer.setBucket(&TimeByBucket[MP.second->getID()]);

1055 BoundNodesTreeBuilder Builder;

1056

1057 {

1058 TraversalKindScope RAII(getASTContext(), MP.first.getTraversalKind());

1059 if (getASTContext().getParentMapContext().traverseIgnored(DynNode) !=

1060 DynNode)

1061 continue;

1062 }

1063

1064 CurMatchRAII RAII(*this, MP.second, DynNode);

1065 if (MP.first.matches(DynNode, this, &Builder)) {

1066 MatchVisitor Visitor(*this, ActiveASTContext, MP.second);

1067 Builder.visitMatches(&Visitor);

1068 }

1069 }

1070 }

1071

1072 const std::vector &getFilterForKind(ASTNodeKind Kind) {

1073 auto &Filter = MatcherFiltersMap[Kind];

1074 auto &Matchers = this->Matchers->DeclOrStmt;

1075 assert((Matchers.size() < USHRT_MAX) && "Too many matchers.");

1076 for (unsigned I = 0, E = Matchers.size(); I != E; ++I) {

1077 if (Matchers[I].first.canMatchNodesOfKind(Kind)) {

1078 Filter.push_back(I);

1079 }

1080 }

1082 }

1083

1084

1085

1086 void matchDispatch(const Decl *Node) {

1088 }

1089 void matchDispatch(const Stmt *Node) {

1091 }

1092

1093 void matchDispatch(const Type *Node) {

1094 matchWithoutFilter(QualType(Node, 0), Matchers->Type);

1095 }

1096 void matchDispatch(const TypeLoc *Node) {

1097 matchWithoutFilter(*Node, Matchers->TypeLoc);

1098 }

1099 void matchDispatch(const QualType *Node) {

1100 matchWithoutFilter(*Node, Matchers->Type);

1101 }

1102 void matchDispatch(const NestedNameSpecifier *Node) {

1103 matchWithoutFilter(*Node, Matchers->NestedNameSpecifier);

1104 }

1105 void matchDispatch(const NestedNameSpecifierLoc *Node) {

1106 matchWithoutFilter(*Node, Matchers->NestedNameSpecifierLoc);

1107 }

1108 void matchDispatch(const CXXCtorInitializer *Node) {

1109 matchWithoutFilter(*Node, Matchers->CtorInit);

1110 }

1111 void matchDispatch(const TemplateArgumentLoc *Node) {

1112 matchWithoutFilter(*Node, Matchers->TemplateArgumentLoc);

1113 }

1114 void matchDispatch(const Attr *Node) {

1115 matchWithoutFilter(*Node, Matchers->Attr);

1116 }

1117 void matchDispatch(const void *) { }

1118

1119

1120

1121

1122 bool matchesParentOf(const DynTypedNode &Node, const DynTypedMatcher &Matcher,

1123 BoundNodesTreeBuilder *Builder) {

1124 for (const auto &Parent : ActiveASTContext->getParents(Node)) {

1125 BoundNodesTreeBuilder BuilderCopy = *Builder;

1126 if (Matcher.matches(Parent, this, &BuilderCopy)) {

1127 *Builder = std::move(BuilderCopy);

1128 return true;

1129 }

1130 }

1131 return false;

1132 }

1133

1134

1135

1136

1137

1138

1139

1140

1141

1142

1143

1144

1145

1146

1147

1148

1149

1150 bool matchesAnyAncestorOf(DynTypedNode Node, ASTContext &Ctx,

1151 const DynTypedMatcher &Matcher,

1152 BoundNodesTreeBuilder *Builder) {

1153

1154

1155

1156

1157 std::vector Keys;

1158

1159 auto Finish = [&](bool Matched) {

1160 for (const auto &Key : Keys) {

1161 MemoizedMatchResult &CachedResult = ResultCache[Key];

1162 CachedResult.ResultOfMatch = Matched;

1163 CachedResult.Nodes = *Builder;

1164 }

1165 return Matched;

1166 };

1167

1168

1169 DynTypedNodeList Parents{ArrayRef()};

1170 for (;;) {

1171

1172 if (Builder->isComparable()) {

1173 Keys.emplace_back();

1174 Keys.back().MatcherID = Matcher.getID();

1175 Keys.back().Node = Node;

1176 Keys.back().BoundNodes = *Builder;

1177 Keys.back().Traversal = Ctx.getParentMapContext().getTraversalKind();

1178 Keys.back().Type = MatchType::Ancestors;

1179

1180

1181 MemoizationMap::iterator I = ResultCache.find(Keys.back());

1182 if (I != ResultCache.end()) {

1183 Keys.pop_back();

1184 *Builder = I->second.Nodes;

1185 return Finish(I->second.ResultOfMatch);

1186 }

1187 }

1188

1189 Parents = ActiveASTContext->getParents(Node);

1190

1191

1192 if (Parents.size() != 1)

1193 break;

1194

1195

1196 Node = *Parents.begin();

1197 BoundNodesTreeBuilder BuilderCopy = *Builder;

1198 if (Matcher.matches(Node, this, &BuilderCopy)) {

1199 *Builder = std::move(BuilderCopy);

1200 return Finish(true);

1201 }

1202 }

1203

1204

1205 if (Parents.empty()) {

1206

1207

1208

1209

1210

1211

1212#ifndef NDEBUG

1213 if (Node.get() &&

1214

1215 llvm::any_of(ActiveASTContext->getTraversalScope(), [](Decl *D) {

1216 return D->getKind() == Decl::TranslationUnit;

1217 })) {

1218 llvm::errs() << "Tried to match orphan node:\n";

1219 Node.dump(llvm::errs(), *ActiveASTContext);

1220 llvm_unreachable("Parent map should be complete!");

1221 }

1222#endif

1223 } else {

1224 assert(Parents.size() > 1);

1225

1226

1227

1228 std::deque Queue(Parents.begin(), Parents.end());

1229 llvm::DenseSet<const void *> Visited;

1230 while (!Queue.empty()) {

1231 BoundNodesTreeBuilder BuilderCopy = *Builder;

1232 if (Matcher.matches(Queue.front(), this, &BuilderCopy)) {

1233 *Builder = std::move(BuilderCopy);

1234 return Finish(true);

1235 }

1236 for (const auto &Parent : ActiveASTContext->getParents(Queue.front())) {

1237

1238

1239

1240 if (Visited.insert(Parent.getMemoizationData()).second)

1241 Queue.push_back(Parent);

1242 }

1243 Queue.pop_front();

1244 }

1245 }

1246 return Finish(false);

1247 }

1248

1249

1250

1251 class MatchVisitor : public BoundNodesTreeBuilder::Visitor {

1252 struct CurBoundScope {

1253 CurBoundScope(MatchASTVisitor::CurMatchData &State, const BoundNodes &BN)

1254 : State(State) {

1255 State.SetBoundNodes(BN);

1256 }

1257

1258 ~CurBoundScope() { State.clearBoundNodes(); }

1259

1260 private:

1261 MatchASTVisitor::CurMatchData &State;

1262 };

1263

1264 public:

1265 MatchVisitor(MatchASTVisitor &MV, ASTContext *Context,

1266 MatchFinder::MatchCallback *Callback)

1267 : State(MV.CurMatchState), Context(Context), Callback(Callback) {}

1268

1269 void visitMatch(const BoundNodes& BoundNodesView) override {

1270 TraversalKindScope RAII(*Context, Callback->getCheckTraversalKind());

1271 CurBoundScope RAII2(State, BoundNodesView);

1272 Callback->run(MatchFinder::MatchResult(BoundNodesView, Context));

1273 }

1274

1275 private:

1276 MatchASTVisitor::CurMatchData &State;

1277 ASTContext* Context;

1278 MatchFinder::MatchCallback* Callback;

1279 };

1280

1281

1282 bool typeHasMatchingAlias(const Type *TypeNode,

1283 const Matcher &Matcher,

1284 BoundNodesTreeBuilder *Builder) {

1285 const Type *const CanonicalType =

1286 ActiveASTContext->getCanonicalType(TypeNode);

1287 auto Aliases = TypeAliases.find(CanonicalType);

1288 if (Aliases == TypeAliases.end())

1289 return false;

1290 for (const TypedefNameDecl *Alias : Aliases->second) {

1291 BoundNodesTreeBuilder Result(*Builder);

1292 if (Matcher.matches(*Alias, this, &Result)) {

1293 *Builder = std::move(Result);

1294 return true;

1295 }

1296 }

1297 return false;

1298 }

1299

1300 bool

1301 objcClassHasMatchingCompatibilityAlias(const ObjCInterfaceDecl *InterfaceDecl,

1302 const Matcher &Matcher,

1303 BoundNodesTreeBuilder *Builder) {

1304 auto Aliases = CompatibleAliases.find(InterfaceDecl);

1305 if (Aliases == CompatibleAliases.end())

1306 return false;

1307 for (const ObjCCompatibleAliasDecl *Alias : Aliases->second) {

1308 BoundNodesTreeBuilder Result(*Builder);

1309 if (Matcher.matches(*Alias, this, &Result)) {

1310 *Builder = std::move(Result);

1311 return true;

1312 }

1313 }

1314 return false;

1315 }

1316

1317

1318

1319

1320 llvm::StringMapllvm::TimeRecord TimeByBucket;

1321

1322 const MatchFinder::MatchersByType *Matchers;

1323

1324

1325

1326

1327

1328

1329

1330 llvm::DenseMap<ASTNodeKind, std::vector> MatcherFiltersMap;

1331

1332 const MatchFinder::MatchFinderOptions &Options;

1333 ASTContext *ActiveASTContext;

1334

1335

1336 llvm::DenseMap<const Type*, std::set<const TypedefNameDecl*> > TypeAliases;

1337

1338

1339 llvm::DenseMap<const ObjCInterfaceDecl *,

1341 CompatibleAliases;

1342

1343

1344 typedef std::map<MatchKey, MemoizedMatchResult> MemoizationMap;

1345 MemoizationMap ResultCache;

1346};

1347

1348static CXXRecordDecl *

1349getAsCXXRecordDeclOrPrimaryTemplate(const Type *TypeNode) {

1350 if (auto *RD = TypeNode->getAsCXXRecordDecl())

1351 return RD;

1352

1353

1354 auto *TemplateType = TypeNode->getAs();

1355 while (TemplateType && TemplateType->isTypeAlias())

1356 TemplateType =

1357 TemplateType->getAliasedType()->getAs();

1358

1359

1360

1361 if (TemplateType)

1362 if (auto *ClassTemplate = dyn_cast_or_null(

1363 TemplateType->getTemplateName().getAsTemplateDecl()))

1364 return ClassTemplate->getTemplatedDecl();

1365

1366 return nullptr;

1367}

1368

1369

1370

1371

1372bool MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration,

1373 const Matcher &Base,

1374 BoundNodesTreeBuilder *Builder,

1375 bool Directly) {

1378}

1379

1380bool MatchASTVisitor::classIsDerivedFromImpl(

1381 const CXXRecordDecl *Declaration, const Matcher &Base,

1382 BoundNodesTreeBuilder *Builder, bool Directly,

1383 llvm::SmallPtrSetImpl<const CXXRecordDecl *> &Visited) {

1385 return false;

1387 return false;

1388 for (const auto &It : Declaration->bases()) {

1389 const Type *TypeNode = It.getType().getTypePtr();

1390

1391 if (typeHasMatchingAlias(TypeNode, Base, Builder))

1392 return true;

1393

1394

1395

1396

1397 CXXRecordDecl *ClassDecl = getAsCXXRecordDeclOrPrimaryTemplate(TypeNode);

1398 if (!ClassDecl)

1399 continue;

1401

1402 continue;

1403 }

1404 BoundNodesTreeBuilder Result(*Builder);

1405 if (Base.matches(*ClassDecl, this, &Result)) {

1406 *Builder = std::move(Result);

1407 return true;

1408 }

1409 if (!Directly &&

1410 classIsDerivedFromImpl(ClassDecl, Base, Builder, Directly, Visited))

1411 return true;

1412 }

1413 return false;

1414}

1415

1416

1417

1418

1419bool MatchASTVisitor::objcClassIsDerivedFrom(

1420 const ObjCInterfaceDecl *Declaration, const Matcher &Base,

1421 BoundNodesTreeBuilder *Builder, bool Directly) {

1422

1423 for (const ObjCInterfaceDecl *ClassDecl = Declaration->getSuperClass();

1424 ClassDecl != nullptr; ClassDecl = ClassDecl->getSuperClass()) {

1425

1426 if (objcClassHasMatchingCompatibilityAlias(ClassDecl, Base, Builder))

1427 return true;

1428

1429

1430 const Type *TypeNode = ClassDecl->getTypeForDecl();

1431 if (typeHasMatchingAlias(TypeNode, Base, Builder))

1432 return true;

1433

1434 if (Base.matches(*ClassDecl, this, Builder))

1435 return true;

1436

1437

1438 if (Directly)

1439 break;

1440 }

1441

1442 return false;

1443}

1444

1445bool MatchASTVisitor::TraverseDecl(Decl *DeclNode) {

1446 if (!DeclNode) {

1447 return true;

1448 }

1449

1450 bool ScopedTraversal =

1451 TraversingASTNodeNotSpelledInSource || DeclNode->isImplicit();

1452 bool ScopedChildren = TraversingASTChildrenNotSpelledInSource;

1453

1454 if (const auto *CTSD = dyn_cast(DeclNode)) {

1455 auto SK = CTSD->getSpecializationKind();

1458 ScopedChildren = true;

1459 } else if (const auto *FD = dyn_cast(DeclNode)) {

1460 if (FD->isDefaulted())

1461 ScopedChildren = true;

1462 if (FD->isTemplateInstantiation())

1463 ScopedTraversal = true;

1464 } else if (isa(DeclNode)) {

1465 ScopedChildren = true;

1466 }

1467

1468 ASTNodeNotSpelledInSourceScope RAII1(this, ScopedTraversal);

1469 ASTChildrenNotSpelledInSourceScope RAII2(this, ScopedChildren);

1470

1471 match(*DeclNode);

1473}

1474

1475bool MatchASTVisitor::TraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue) {

1476 if (!StmtNode) {

1477 return true;

1478 }

1479 bool ScopedTraversal = TraversingASTNodeNotSpelledInSource ||

1480 TraversingASTChildrenNotSpelledInSource;

1481

1482 ASTNodeNotSpelledInSourceScope RAII(this, ScopedTraversal);

1483 match(*StmtNode);

1485}

1486

1487bool MatchASTVisitor::TraverseType(QualType TypeNode) {

1488 match(TypeNode);

1490}

1491

1492bool MatchASTVisitor::TraverseTypeLoc(TypeLoc TypeLocNode) {

1493

1494

1495

1496

1497

1498 match(TypeLocNode);

1499 match(TypeLocNode.getType());

1501}

1502

1503bool MatchASTVisitor::TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) {

1506}

1507

1508bool MatchASTVisitor::TraverseNestedNameSpecifierLoc(

1509 NestedNameSpecifierLoc NNS) {

1510 if (!NNS)

1511 return true;

1512

1514

1515

1516

1517 if (NNS.hasQualifier())

1518 match(*NNS.getNestedNameSpecifier());

1519 return

1521}

1522

1523bool MatchASTVisitor::TraverseConstructorInitializer(

1524 CXXCtorInitializer *CtorInit) {

1525 if (!CtorInit)

1526 return true;

1527

1528 bool ScopedTraversal = TraversingASTNodeNotSpelledInSource ||

1529 TraversingASTChildrenNotSpelledInSource;

1530

1531 if (!CtorInit->isWritten())

1532 ScopedTraversal = true;

1533

1534 ASTNodeNotSpelledInSourceScope RAII1(this, ScopedTraversal);

1535

1536 match(*CtorInit);

1537

1539 CtorInit);

1540}

1541

1542bool MatchASTVisitor::TraverseTemplateArgumentLoc(TemplateArgumentLoc Loc) {

1545}

1546

1547bool MatchASTVisitor::TraverseAttr(Attr *AttrNode) {

1548 match(*AttrNode);

1550}

1551

1552class MatchASTConsumer : public ASTConsumer {

1553public:

1554 MatchASTConsumer(MatchFinder *Finder,

1555 MatchFinder::ParsingDoneTestCallback *ParsingDone)

1556 : Finder(Finder), ParsingDone(ParsingDone) {}

1557

1558private:

1559 void HandleTranslationUnit(ASTContext &Context) override {

1560 if (ParsingDone != nullptr) {

1561 ParsingDone->run();

1562 }

1563 Finder->matchAST(Context);

1564 }

1565

1566 MatchFinder *Finder;

1567 MatchFinder::ParsingDoneTestCallback *ParsingDone;

1568};

1569

1570}

1571}

1572

1577

1580

1582 : Options(std::move(Options)), ParsingDone(nullptr) {}

1583

1585

1588 std::optional TK;

1589 if (Action)

1591 if (TK)

1592 Matchers.DeclOrStmt.emplace_back(traverse(*TK, NodeMatch), Action);

1593 else

1594 Matchers.DeclOrStmt.emplace_back(NodeMatch, Action);

1595 Matchers.AllCallbacks.insert(Action);

1596}

1597

1600 Matchers.Type.emplace_back(NodeMatch, Action);

1601 Matchers.AllCallbacks.insert(Action);

1602}

1603

1606 std::optional TK;

1607 if (Action)

1609 if (TK)

1610 Matchers.DeclOrStmt.emplace_back(traverse(*TK, NodeMatch), Action);

1611 else

1612 Matchers.DeclOrStmt.emplace_back(NodeMatch, Action);

1613 Matchers.AllCallbacks.insert(Action);

1614}

1615

1618 Matchers.NestedNameSpecifier.emplace_back(NodeMatch, Action);

1619 Matchers.AllCallbacks.insert(Action);

1620}

1621

1624 Matchers.NestedNameSpecifierLoc.emplace_back(NodeMatch, Action);

1625 Matchers.AllCallbacks.insert(Action);

1626}

1627

1630 Matchers.TypeLoc.emplace_back(NodeMatch, Action);

1631 Matchers.AllCallbacks.insert(Action);

1632}

1633

1636 Matchers.CtorInit.emplace_back(NodeMatch, Action);

1637 Matchers.AllCallbacks.insert(Action);

1638}

1639

1642 Matchers.TemplateArgumentLoc.emplace_back(NodeMatch, Action);

1643 Matchers.AllCallbacks.insert(Action);

1644}

1645

1648 Matchers.Attr.emplace_back(AttrMatch, Action);

1649 Matchers.AllCallbacks.insert(Action);

1650}

1651

1654 if (NodeMatch.canConvertTo<Decl>()) {

1656 return true;

1657 } else if (NodeMatch.canConvertTo<QualType>()) {

1659 return true;

1660 } else if (NodeMatch.canConvertTo<Stmt>()) {

1662 return true;

1665 return true;

1668 return true;

1669 } else if (NodeMatch.canConvertTo<TypeLoc>()) {

1671 return true;

1674 return true;

1677 return true;

1678 } else if (NodeMatch.canConvertTo<Attr>()) {

1680 return true;

1681 }

1682 return false;

1683}

1684

1686 return std::make_uniqueinternal::MatchASTConsumer(this, ParsingDone);

1687}

1688

1690 internal::MatchASTVisitor Visitor(&Matchers, Options);

1691 Visitor.set_active_ast_context(&Context);

1692 Visitor.match(Node);

1693}

1694

1696 internal::MatchASTVisitor Visitor(&Matchers, Options);

1697 internal::MatchASTVisitor::TraceReporter StackTrace(Visitor);

1698 Visitor.set_active_ast_context(&Context);

1699 Visitor.onStartOfTranslationUnit();

1700 Visitor.TraverseAST(Context);

1701 Visitor.onEndOfTranslationUnit();

1702}

1703

1706 ParsingDone = NewParsingDone;

1707}

1708

1710

1711std::optional

1713 return std::nullopt;

1714}

1715

1716}

1717}

Defines the clang::ASTContext interface.

BoundNodesTreeBuilder BoundNodes

BoundNodesTreeBuilder Nodes

DynTypedMatcher::MatcherIDType MatcherID

llvm::PointerUnion< CMD_TYPES_1 > Node1

llvm::PointerUnion< CMD_TYPES_0 > Node0

enum clang::sema::@1725::IndirectLocalPathEntry::EntryKind Kind

Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....

llvm::DenseSet< const void * > Visited

static void print(llvm::raw_ostream &OS, const T &V, ASTContext &ASTCtx, QualType Ty)

Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...

Attr - This represents one attribute.

Represents a C++ base or member initializer.

Decl - This represents one declaration (or definition), e.g.

A dynamically typed AST node container.

static DynTypedNode create(const T &Node)

Creates a DynTypedNode from Node.

Expr * getNoexceptExpr() const

Return the expression inside noexcept(expression), or a null pointer if there is none (because the ex...

ArrayRef< QualType > exceptions() const

A C++ nested-name-specifier augmented with source location information.

Represents a C++ nested name specifier, such as "\::std::vector::".

A (possibly-)qualified type.

bool TraverseStmt(Stmt *S, DataRecursionQueue *Queue=nullptr)

Recursively visit a statement or expression, by dispatching to Traverse*() based on the argument's dy...

bool TraverseType(QualType T)

Recursively visit a type, by dispatching to Traverse*Type() based on the argument's getTypeClass() pr...

bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc)

Recursively visit a template argument location and dispatch to the appropriate method for the argumen...

bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS)

Recursively visit a C++ nested-name-specifier with location information.

bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS)

Recursively visit a C++ nested-name-specifier.

bool dataTraverseNode(Stmt *S, DataRecursionQueue *Queue)

bool TraverseDecl(Decl *D)

Recursively visit a declaration, by dispatching to Traverse*Decl() based on the argument's dynamic ty...

bool TraverseTypeLoc(TypeLoc TL)

Recursively visit a type with location, by dispatching to Traverse*TypeLoc() based on the argument ty...

bool TraverseAttr(Attr *At)

Recursively visit an attribute, by dispatching to Traverse*Attr() based on the argument's dynamic typ...

bool TraverseConstructorInitializer(CXXCtorInitializer *Init)

Recursively visit a constructor initializer.

This class handles loading and caching of source files into memory.

Stmt - This represents one statement.

Location wrapper for a TemplateArgument.

Base wrapper for a particular "section" of type source info.

const char * getTypeClassName() const

Maps string IDs to AST nodes matched by parts of a matcher.

internal::BoundNodesMap::IDToNodeMap IDToNodeMap

Type of mapping from binding identifiers to bound nodes.

Called when the Match registered for it was successfully found in the AST.

virtual std::optional< TraversalKind > getCheckTraversalKind() const

TraversalKind to use while matching and processing the result nodes.

virtual StringRef getID() const

An id used to group the matchers.

Called when parsing is finished. Intended for testing only.

virtual ~ParsingDoneTestCallback()

MatchFinder(MatchFinderOptions Options=MatchFinderOptions())

bool addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch, MatchCallback *Action)

Adds a matcher to execute when running over the AST.

void addMatcher(const DeclarationMatcher &NodeMatch, MatchCallback *Action)

Adds a matcher to execute when running over the AST.

void match(const T &Node, ASTContext &Context)

Calls the registered callbacks on all matches on the given Node.

void registerTestCallbackAfterParsing(ParsingDoneTestCallback *ParsingDone)

Registers a callback to notify the end of parsing.

std::unique_ptr< clang::ASTConsumer > newASTConsumer()

Creates a clang ASTConsumer that finds all matches.

void matchAST(ASTContext &Context)

Finds all matches in the given AST.

@ Decl

The l-value was an access to a declared entity or something equivalently strong, like the address of ...

internal::Matcher< QualType > TypeMatcher

internal::Matcher< Decl > DeclarationMatcher

Types of matchers for the top-level classes in the AST class hierarchy.

internal::Matcher< NestedNameSpecifier > NestedNameSpecifierMatcher

SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)

Returns the results of matching Matcher on Node.

internal::Matcher< CXXCtorInitializer > CXXCtorInitializerMatcher

internal::Matcher< Stmt > StatementMatcher

internal::Matcher< TypeLoc > TypeLocMatcher

internal::Matcher< TemplateArgumentLoc > TemplateArgumentLocMatcher

internal::Matcher< T > traverse(TraversalKind TK, const internal::Matcher< T > &InnerMatcher)

Causes all nested matchers to be matched with the specified traversal kind.

internal::Matcher< Attr > AttrMatcher

internal::Matcher< NestedNameSpecifierLoc > NestedNameSpecifierLocMatcher

bool LE(InterpState &S, CodePtr OpPC)

The JSON file list parser is used to communicate input to InstallAPI.

@ Bind

'bind' clause, allowed on routine constructs.

bool operator<(DeclarationName LHS, DeclarationName RHS)

Ordering on two declaration names.

TraversalKind

Defines how we descend a level in the AST when we pass through expressions.

@ TK_AsIs

Will traverse all child nodes.

@ TK_IgnoreUnlessSpelledInSource

Ignore AST nodes not written in the source.

@ Result

The result type of a method or function.

const FunctionProtoType * T

@ TSK_ExplicitInstantiationDefinition

This template specialization was instantiated from a template due to an explicit instantiation defini...

@ TSK_ExplicitInstantiationDeclaration

This template specialization was instantiated from a template due to an explicit instantiation declar...

@ Other

Other implicit parameter.

MatchResult(const BoundNodes &Nodes, clang::ASTContext *Context)