ast_matchers {
37typedefMatchFinder::MatchCallback MatchCallback;
47static const unsignedMaxMemoizationEntries = 10000;
83structMemoizedMatchResult {
90classMatchChildASTVisitor
91:
publicRecursiveASTVisitor<MatchChildASTVisitor> {
93 typedefRecursiveASTVisitor<MatchChildASTVisitor> VisitorBase;
99MatchChildASTVisitor(
constDynTypedMatcher *Matcher, ASTMatchFinder *Finder,
100BoundNodesTreeBuilder *Builder,
intMaxDepth,
101 boolIgnoreImplicitChildren,
102ASTMatchFinder::BindKind Bind)
103: Matcher(Matcher), Finder(Finder), Builder(Builder), CurrentDepth(0),
104MaxDepth(MaxDepth), IgnoreImplicitChildren(IgnoreImplicitChildren),
105Bind(Bind), Matches(
false) {}
118 boolfindMatch(
constDynTypedNode &DynNode) {
120 if(
constDecl *
D= DynNode.get<Decl>())
122 else if(
constStmt *S = DynNode.get<Stmt>())
124 else if(
constNestedNameSpecifier *NNS =
125DynNode.get<NestedNameSpecifier>())
127 else if(
constNestedNameSpecifierLoc *NNSLoc =
128DynNode.get<NestedNameSpecifierLoc>())
130 else if(
constQualType *Q = DynNode.get<QualType>())
132 else if(
constTypeLoc *
T= DynNode.get<TypeLoc>())
134 else if(
const auto*
C= DynNode.get<CXXCtorInitializer>())
136 else if(
constTemplateArgumentLoc *TALoc =
137DynNode.get<TemplateArgumentLoc>())
139 else if(
constAttr *A = DynNode.get<Attr>())
146*Builder = ResultBindings;
154 boolTraverseDecl(Decl *DeclNode) {
156 if(DeclNode && DeclNode->isImplicit() &&
157Finder->isTraversalIgnoringImplicitNodes())
158 returnbaseTraverse(*DeclNode);
160ScopedIncrement ScopedDepth(&CurrentDepth);
161 return(DeclNode ==
nullptr) ||
traverse(*DeclNode);
164Stmt *getStmtToTraverse(Stmt *StmtNode) {
165Stmt *StmtToTraverse = StmtNode;
166 if(
auto*ExprNode = dyn_cast_or_null<Expr>(StmtNode)) {
167 auto*LambdaNode = dyn_cast_or_null<LambdaExpr>(StmtNode);
168 if(LambdaNode && Finder->isTraversalIgnoringImplicitNodes())
169StmtToTraverse = LambdaNode;
172Finder->getASTContext().getParentMapContext().traverseIgnored(
175 returnStmtToTraverse;
178 boolTraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue =
nullptr) {
180 if(CurrentDepth == 0 || (CurrentDepth <= MaxDepth && MaxDepth <
INT_MAX))
183ScopedIncrement ScopedDepth(&CurrentDepth);
184Stmt *StmtToTraverse = getStmtToTraverse(StmtNode);
188 if(IgnoreImplicitChildren && isa<CXXDefaultArgExpr>(StmtNode))
191 if(!
match(*StmtToTraverse))
197 boolTraverseType(QualType TypeNode) {
198 if(TypeNode.isNull())
200ScopedIncrement ScopedDepth(&CurrentDepth);
202 if(!
match(*TypeNode))
209 boolTraverseTypeLoc(TypeLoc TypeLocNode) {
210 if(TypeLocNode.isNull())
212ScopedIncrement ScopedDepth(&CurrentDepth);
214 if(!
match(*TypeLocNode.getType()))
217 if(!
match(TypeLocNode.getType()))
222 boolTraverseNestedNameSpecifier(NestedNameSpecifier *NNS) {
223ScopedIncrement ScopedDepth(&CurrentDepth);
224 return(NNS ==
nullptr) ||
traverse(*NNS);
226 boolTraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
229ScopedIncrement ScopedDepth(&CurrentDepth);
230 if(!
match(*NNS.getNestedNameSpecifier()))
234 boolTraverseConstructorInitializer(CXXCtorInitializer *CtorInit) {
237ScopedIncrement ScopedDepth(&CurrentDepth);
240 boolTraverseTemplateArgumentLoc(TemplateArgumentLoc TAL) {
241ScopedIncrement ScopedDepth(&CurrentDepth);
244 boolTraverseCXXForRangeStmt(CXXForRangeStmt *
Node) {
245 if(!Finder->isTraversalIgnoringImplicitNodes())
246 returnVisitorBase::TraverseCXXForRangeStmt(
Node);
249ScopedIncrement ScopedDepth(&CurrentDepth);
250 if(
auto*
Init=
Node->getInit())
253 if(!
match(*
Node->getLoopVariable()))
262 boolTraverseCXXRewrittenBinaryOperator(CXXRewrittenBinaryOperator *
Node) {
263 if(!Finder->isTraversalIgnoringImplicitNodes())
264 returnVisitorBase::TraverseCXXRewrittenBinaryOperator(
Node);
267ScopedIncrement ScopedDepth(&CurrentDepth);
271 boolTraverseAttr(Attr *A) {
274Finder->getASTContext().getParentMapContext().getTraversalKind() ==
277ScopedIncrement ScopedDepth(&CurrentDepth);
280 boolTraverseLambdaExpr(LambdaExpr *
Node) {
281 if(!Finder->isTraversalIgnoringImplicitNodes())
282 returnVisitorBase::TraverseLambdaExpr(
Node);
285ScopedIncrement ScopedDepth(&CurrentDepth);
287 for(
unsignedI = 0, N =
Node->capture_size(); I != N; ++I) {
288 constLambdaCapture *
C=
Node->capture_begin() + I;
289 if(!
C->isExplicit())
291 if(
Node->isInitCapture(
C) && !
match(*
C->getCapturedVar()))
293 constExpr *CIE =
Node->capture_init_begin()[I];
294 if(CIE !=
nullptr&& !
match(*CIE))
298 if(
const auto*TPL =
Node->getTemplateParameterList()) {
299 for(
const auto*TP : *TPL) {
305 for(
const auto*
P:
Node->getCallOperator()->parameters()) {
316 boolshouldVisitTemplateInstantiations()
const{
return true; }
317 boolshouldVisitImplicitCode()
const{
return!IgnoreImplicitChildren; }
321 structScopedIncrement {
322 explicitScopedIncrement(
int*Depth) : Depth(Depth) { ++(*Depth); }
323~ScopedIncrement() { --(*Depth); }
337 boolbaseTraverse(
constDecl &DeclNode) {
340 boolbaseTraverse(
constStmt &StmtNode) {
343 boolbaseTraverse(QualType TypeNode) {
346 boolbaseTraverse(TypeLoc TypeLocNode) {
349 boolbaseTraverse(
constNestedNameSpecifier &NNS) {
351 const_cast<NestedNameSpecifier*
>(&NNS));
353 boolbaseTraverse(NestedNameSpecifierLoc NNS) {
356 boolbaseTraverse(
constCXXCtorInitializer &CtorInit) {
358 const_cast<CXXCtorInitializer *
>(&CtorInit));
360 boolbaseTraverse(TemplateArgumentLoc TAL) {
363 boolbaseTraverse(
constAttr &AttrNode) {
372 template<
typenameT>
374 if(CurrentDepth == 0 || CurrentDepth > MaxDepth) {
377 if(Bind != ASTMatchFinder::BK_All) {
378BoundNodesTreeBuilder RecursiveBuilder(*Builder);
380&RecursiveBuilder)) {
382ResultBindings.addMatch(RecursiveBuilder);
386BoundNodesTreeBuilder RecursiveBuilder(*Builder);
388&RecursiveBuilder)) {
391ResultBindings.addMatch(RecursiveBuilder);
399 template<
typenameT>
401 static_assert(IsBaseType<T>::value,
402 "traverse can only be instantiated with base type");
405 returnbaseTraverse(
Node);
408 constDynTypedMatcher *
constMatcher;
409ASTMatchFinder *
constFinder;
410BoundNodesTreeBuilder *
constBuilder;
411BoundNodesTreeBuilder ResultBindings;
414 const boolIgnoreImplicitChildren;
415 constASTMatchFinder::BindKind Bind;
421classMatchASTVisitor :
publicRecursiveASTVisitor<MatchASTVisitor>,
422 publicASTMatchFinder {
424MatchASTVisitor(
constMatchFinder::MatchersByType *Matchers,
425 constMatchFinder::MatchFinderOptions &Options)
426: Matchers(Matchers), Options(Options), ActiveASTContext(nullptr) {}
428~MatchASTVisitor()
override{
429 if(Options.CheckProfiling) {
430Options.CheckProfiling->Records = std::move(TimeByBucket);
434 voidonStartOfTranslationUnit() {
435 const boolEnableCheckProfiling = Options.CheckProfiling.has_value();
436TimeBucketRegion Timer;
437 for(MatchCallback *MC : Matchers->AllCallbacks) {
438 if(EnableCheckProfiling)
439Timer.setBucket(&TimeByBucket[MC->getID()]);
440MC->onStartOfTranslationUnit();
444 voidonEndOfTranslationUnit() {
445 const boolEnableCheckProfiling = Options.CheckProfiling.has_value();
446TimeBucketRegion Timer;
447 for(MatchCallback *MC : Matchers->AllCallbacks) {
448 if(EnableCheckProfiling)
449Timer.setBucket(&TimeByBucket[MC->getID()]);
450MC->onEndOfTranslationUnit();
454 voidset_active_ast_context(ASTContext *NewActiveASTContext) {
455ActiveASTContext = NewActiveASTContext;
461 boolVisitTypedefNameDecl(TypedefNameDecl *DeclNode) {
489 const Type*TypeNode = DeclNode->getUnderlyingType().getTypePtr();
490 const Type*CanonicalType =
491ActiveASTContext->getCanonicalType(TypeNode);
492TypeAliases[CanonicalType].insert(DeclNode);
496 boolVisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *CAD) {
497 constObjCInterfaceDecl *InterfaceDecl = CAD->getClassInterface();
498CompatibleAliases[InterfaceDecl].insert(CAD);
502 boolTraverseDecl(Decl *DeclNode);
503 boolTraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue =
nullptr);
504 boolTraverseType(QualType TypeNode);
505 boolTraverseTypeLoc(TypeLoc TypeNode);
506 boolTraverseNestedNameSpecifier(NestedNameSpecifier *NNS);
507 boolTraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS);
508 boolTraverseConstructorInitializer(CXXCtorInitializer *CtorInit);
509 boolTraverseTemplateArgumentLoc(TemplateArgumentLoc TAL);
510 boolTraverseAttr(Attr *AttrNode);
512 booldataTraverseNode(Stmt *S, DataRecursionQueue *Queue) {
513 if(
auto*RF = dyn_cast<CXXForRangeStmt>(S)) {
515ASTNodeNotAsIsSourceScope RAII(
this,
true);
516TraverseStmt(RF->getInit());
518 match(*RF->getLoopVariable());
519TraverseStmt(RF->getRangeInit());
522ASTNodeNotSpelledInSourceScope RAII(
this,
true);
523 for(
auto*SubStmt : RF->children()) {
524 if(SubStmt != RF->getBody())
525TraverseStmt(SubStmt);
528TraverseStmt(RF->getBody());
530}
else if(
auto*RBO = dyn_cast<CXXRewrittenBinaryOperator>(S)) {
532ASTNodeNotAsIsSourceScope RAII(
this,
true);
533TraverseStmt(
const_cast<Expr *
>(RBO->getLHS()));
534TraverseStmt(
const_cast<Expr *
>(RBO->getRHS()));
537ASTNodeNotSpelledInSourceScope RAII(
this,
true);
538 for(
auto*SubStmt : RBO->children()) {
539TraverseStmt(SubStmt);
543}
else if(
auto*LE = dyn_cast<LambdaExpr>(S)) {
544 for(
autoI : llvm::zip(
LE->captures(),
LE->capture_inits())) {
545 auto C= std::get<0>(I);
546ASTNodeNotSpelledInSourceScope RAII(
547 this, TraversingASTNodeNotSpelledInSource || !
C.isExplicit());
548TraverseLambdaCapture(LE, &
C, std::get<1>(I));
552ASTNodeNotSpelledInSourceScope RAII(
this,
true);
553TraverseDecl(
LE->getLambdaClass());
556ASTNodeNotAsIsSourceScope RAII(
this,
true);
560TypeLoc TL =
LE->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
561FunctionProtoTypeLoc Proto = TL.getAsAdjusted<FunctionProtoTypeLoc>();
563 if(
auto*TPL =
LE->getTemplateParameterList()) {
564 for(NamedDecl *
D: *TPL) {
567 if(Expr *RequiresClause = TPL->getRequiresClause()) {
568TraverseStmt(RequiresClause);
572 if(
LE->hasExplicitParameters()) {
574 for(ParmVarDecl *Param : Proto.getParams())
578 const auto*
T= Proto.getTypePtr();
583TraverseStmt(NE, Queue);
585 if(
LE->hasExplicitResultType())
586TraverseTypeLoc(Proto.getReturnLoc());
587TraverseStmt(
LE->getTrailingRequiresClause());
590TraverseStmt(
LE->getBody());
597 boolmemoizedMatchesRecursively(
constDynTypedNode &
Node, ASTContext &Ctx,
598 constDynTypedMatcher &Matcher,
599BoundNodesTreeBuilder *Builder,
intMaxDepth,
602 if(!
Node.getMemoizationData() || !Builder->isComparable())
603 returnmatchesRecursively(
Node, Matcher, Builder, MaxDepth,
Bind);
606Key.MatcherID = Matcher.getID();
609Key.BoundNodes = *Builder;
610Key.Traversal = Ctx.getParentMapContext().getTraversalKind();
612Key.Type = MaxDepth == 1 ? MatchType::Child : MatchType::Descendants;
613MemoizationMap::iterator I = ResultCache.find(Key);
614 if(I != ResultCache.end()) {
615*Builder = I->second.Nodes;
616 returnI->second.ResultOfMatch;
619MemoizedMatchResult
Result;
622matchesRecursively(
Node, Matcher, &
Result.Nodes, MaxDepth,
Bind);
624MemoizedMatchResult &CachedResult = ResultCache[Key];
625CachedResult = std::move(
Result);
627*Builder = CachedResult.Nodes;
628 returnCachedResult.ResultOfMatch;
632 boolmatchesRecursively(
constDynTypedNode &
Node,
633 constDynTypedMatcher &Matcher,
634BoundNodesTreeBuilder *Builder,
intMaxDepth,
636 boolScopedTraversal = TraversingASTNodeNotSpelledInSource ||
637TraversingASTChildrenNotSpelledInSource;
639 boolIgnoreImplicitChildren =
false;
641 if(isTraversalIgnoringImplicitNodes()) {
642IgnoreImplicitChildren =
true;
645ASTNodeNotSpelledInSourceScope RAII(
this, ScopedTraversal);
647MatchChildASTVisitor Visitor(&Matcher,
this, Builder, MaxDepth,
648IgnoreImplicitChildren,
Bind);
649 returnVisitor.findMatch(
Node);
652 boolclassIsDerivedFrom(
constCXXRecordDecl *
Declaration,
653 constMatcher<NamedDecl> &
Base,
654BoundNodesTreeBuilder *Builder,
655 boolDirectly)
override;
659classIsDerivedFromImpl(
constCXXRecordDecl *
Declaration,
660 constMatcher<NamedDecl> &
Base,
661BoundNodesTreeBuilder *Builder,
boolDirectly,
662llvm::SmallPtrSetImpl<const CXXRecordDecl *> &
Visited);
665 boolobjcClassIsDerivedFrom(
constObjCInterfaceDecl *
Declaration,
666 constMatcher<NamedDecl> &
Base,
667BoundNodesTreeBuilder *Builder,
668 boolDirectly)
override;
672 boolmatchesChildOf(
constDynTypedNode &
Node, ASTContext &Ctx,
673 constDynTypedMatcher &Matcher,
674BoundNodesTreeBuilder *Builder, BindKind
Bind)
override{
675 if(ResultCache.size() > MaxMemoizationEntries)
677 returnmemoizedMatchesRecursively(
Node, Ctx, Matcher, Builder, 1,
Bind);
680 boolmatchesDescendantOf(
constDynTypedNode &
Node, ASTContext &Ctx,
681 constDynTypedMatcher &Matcher,
682BoundNodesTreeBuilder *Builder,
683BindKind
Bind)
override{
684 if(ResultCache.size() > MaxMemoizationEntries)
686 returnmemoizedMatchesRecursively(
Node, Ctx, Matcher, Builder,
INT_MAX,
690 boolmatchesAncestorOf(
constDynTypedNode &
Node, ASTContext &Ctx,
691 constDynTypedMatcher &Matcher,
692BoundNodesTreeBuilder *Builder,
693AncestorMatchMode MatchMode)
override{
696 if(ResultCache.size() > MaxMemoizationEntries)
698 if(MatchMode == AncestorMatchMode::AMM_ParentOnly)
699 returnmatchesParentOf(
Node, Matcher, Builder);
700 returnmatchesAnyAncestorOf(
Node, Ctx, Matcher, Builder);
705 void match(
constDynTypedNode &
Node) {
707 if(
auto*N =
Node.get<Decl>()) {
709}
else if(
auto*N =
Node.get<Stmt>()) {
711}
else if(
auto*N =
Node.get<Type>()) {
713}
else if(
auto*N =
Node.get<QualType>()) {
715}
else if(
auto*N =
Node.get<NestedNameSpecifier>()) {
717}
else if(
auto*N =
Node.get<NestedNameSpecifierLoc>()) {
719}
else if(
auto*N =
Node.get<TypeLoc>()) {
721}
else if(
auto*N =
Node.get<CXXCtorInitializer>()) {
723}
else if(
auto*N =
Node.get<TemplateArgumentLoc>()) {
725}
else if(
auto*N =
Node.get<Attr>()) {
730 template<
typenameT>
void match(
const T&
Node) {
731matchDispatch(&
Node);
735ASTContext &getASTContext()
const override{
return*ActiveASTContext; }
737 boolshouldVisitTemplateInstantiations()
const{
return true; }
738 boolshouldVisitImplicitCode()
const{
return true; }
742 boolshouldVisitLambdaBody()
const{
return false; }
744 boolIsMatchingInASTNodeNotSpelledInSource()
const override{
745 returnTraversingASTNodeNotSpelledInSource;
747 boolisMatchingChildrenNotSpelledInSource()
const override{
748 returnTraversingASTChildrenNotSpelledInSource;
750 voidsetMatchingChildrenNotSpelledInSource(
bool Set)
override{
751TraversingASTChildrenNotSpelledInSource =
Set;
754 boolIsMatchingInASTNodeNotAsIs()
const override{
755 returnTraversingASTNodeNotAsIs;
758 boolTraverseTemplateInstantiations(ClassTemplateDecl *
D) {
759ASTNodeNotSpelledInSourceScope RAII(
this,
true);
760 returnRecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateInstantiations(
764 boolTraverseTemplateInstantiations(VarTemplateDecl *
D) {
765ASTNodeNotSpelledInSourceScope RAII(
this,
true);
766 returnRecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateInstantiations(
770 boolTraverseTemplateInstantiations(FunctionTemplateDecl *
D) {
771ASTNodeNotSpelledInSourceScope RAII(
this,
true);
772 returnRecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateInstantiations(
777 boolTraversingASTNodeNotSpelledInSource =
false;
778 boolTraversingASTNodeNotAsIs =
false;
779 boolTraversingASTChildrenNotSpelledInSource =
false;
786 const QualType *, const TypeLoc *, const NestedNameSpecifier *, \ 787 const NestedNameSpecifierLoc * 789 const CXXCtorInitializer *, const TemplateArgumentLoc *, const Attr *, \ 793 template <typename NodeType> \ 795 llvm::is_one_of<const NodeType *, CMD_TYPES_##Index>::value> \ 796 SetCallbackAndRawNode(const MatchCallback *CB, const NodeType &N) { \ 798 Callback.setPointerAndInt(CB, Index); \ 802 template <typename T> \ 803 std::enable_if_t<llvm::is_one_of<const T *, CMD_TYPES_##Index>::value, \ 806 assertHoldsState(); \ 807 return Callback.getInt() == (Index) ? Node##Index.dyn_cast<const T *>() \ 812CurMatchData() :
Node0(nullptr) {}
817const MatchCallback *getCallback()
const{
returnCallback.getPointer(); }
819 voidSetBoundNodes(
constBoundNodes &BN) {
824 voidclearBoundNodes() {
836Callback.setPointerAndInt(
nullptr, 0);
841 voidassertHoldsState()
const{
842assert(Callback.getPointer() !=
nullptr&& !
Node0.isNull());
845 voidassertEmpty()
const{
846assert(Callback.getPointer() ==
nullptr&&
Node0.isNull() &&
850llvm::PointerIntPair<const MatchCallback *, 1> Callback;
852llvm::PointerUnion<CMD_TYPES_0>
Node0;
853llvm::PointerUnion<CMD_TYPES_1>
Node1;
862 structCurMatchRAII {
863 template<
typenameNodeType>
864CurMatchRAII(MatchASTVisitor &MV,
constMatchCallback *CB,
867MV.CurMatchState.SetCallbackAndRawNode(CB, NT);
870~CurMatchRAII() { MV.CurMatchState.reset(); }
877 classTraceReporter : llvm::PrettyStackTraceEntry {
878 static voiddumpNode(
constASTContext &Ctx,
constDynTypedNode &
Node,
880 if(
const auto*
D=
Node.get<Decl>()) {
881OS <<
D->getDeclKindName() <<
"Decl ";
882 if(
const auto*ND = dyn_cast<NamedDecl>(
D)) {
883ND->printQualifiedName(OS);
887 D->getSourceRange().print(OS, Ctx.getSourceManager());
888}
else if(
const auto*S =
Node.get<Stmt>()) {
889OS << S->getStmtClassName() <<
" : ";
890S->getSourceRange().print(OS, Ctx.getSourceManager());
891}
else if(
const auto*
T=
Node.get<Type>()) {
893QualType(
T, 0).print(OS, Ctx.getPrintingPolicy());
894}
else if(
const auto*QT =
Node.get<QualType>()) {
895OS <<
"QualType : ";
896QT->print(OS, Ctx.getPrintingPolicy());
898OS <<
Node.getNodeKind().asStringRef() <<
" : ";
899 Node.getSourceRange().print(OS, Ctx.getSourceManager());
903 static voiddumpNodeFromState(
constASTContext &Ctx,
904 constCurMatchData &State, raw_ostream &OS) {
905 if(
constDynTypedNode *MatchNode = State.getNode<DynTypedNode>()) {
906dumpNode(Ctx, *MatchNode, OS);
907}
else if(
const auto*QT = State.getNode<QualType>()) {
909}
else if(
const auto*TL = State.getNode<TypeLoc>()) {
911}
else if(
const auto*NNS = State.getNode<NestedNameSpecifier>()) {
913}
else if(
const auto*NNSL = State.getNode<NestedNameSpecifierLoc>()) {
915}
else if(
const auto*CtorInit = State.getNode<CXXCtorInitializer>()) {
917}
else if(
const auto*TAL = State.getNode<TemplateArgumentLoc>()) {
919}
else if(
const auto*At = State.getNode<Attr>()) {
925TraceReporter(
constMatchASTVisitor &MV) : MV(MV) {}
926 void print(raw_ostream &OS)
const override{
927 constCurMatchData &State = MV.CurMatchState;
928 constMatchCallback *CB = State.getCallback();
930OS <<
"ASTMatcher: Not currently matching\n";
934assert(MV.ActiveASTContext &&
935 "ActiveASTContext should be set if there is a matched callback");
937ASTContext &Ctx = MV.getASTContext();
939 if(
constBoundNodes *
Nodes= State.getBoundNodes()) {
940OS <<
"ASTMatcher: Processing '"<< CB->getID() <<
"' against:\n\t";
941dumpNodeFromState(Ctx, State, OS);
944OS <<
"\nNo bound nodes\n";
947OS <<
"\n--- Bound Nodes Begin ---\n";
948 for(
const auto&Item : Map) {
949OS <<
" "<< Item.first <<
" - { ";
950dumpNode(Ctx, Item.second, OS);
953OS <<
"--- Bound Nodes End ---\n";
955OS <<
"ASTMatcher: Matching '"<< CB->getID() <<
"' against:\n\t";
956dumpNodeFromState(Ctx, State, OS);
962 constMatchASTVisitor &MV;
966 structASTNodeNotSpelledInSourceScope {
967ASTNodeNotSpelledInSourceScope(MatchASTVisitor *
V,
boolB)
968: MV(
V), MB(
V->TraversingASTNodeNotSpelledInSource) {
969 V->TraversingASTNodeNotSpelledInSource = B;
971~ASTNodeNotSpelledInSourceScope() {
972MV->TraversingASTNodeNotSpelledInSource = MB;
980 structASTNodeNotAsIsSourceScope {
981ASTNodeNotAsIsSourceScope(MatchASTVisitor *
V,
boolB)
982: MV(
V), MB(
V->TraversingASTNodeNotAsIs) {
983 V->TraversingASTNodeNotAsIs = B;
985~ASTNodeNotAsIsSourceScope() { MV->TraversingASTNodeNotAsIs = MB; }
992 classTimeBucketRegion {
994TimeBucketRegion() =
default;
995~TimeBucketRegion() { setBucket(
nullptr); }
1005 voidsetBucket(llvm::TimeRecord *NewBucket) {
1006 if(Bucket != NewBucket) {
1007 autoNow = llvm::TimeRecord::getCurrentTime(
true);
1017llvm::TimeRecord *Bucket =
nullptr;
1023 template<
typenameT,
typenameMC>
1024 voidmatchWithoutFilter(
const T&
Node,
constMC &Matchers) {
1025 const boolEnableCheckProfiling = Options.CheckProfiling.has_value();
1026TimeBucketRegion Timer;
1027 for(
const auto&MP : Matchers) {
1028 if(EnableCheckProfiling)
1029Timer.setBucket(&TimeByBucket[MP.second->getID()]);
1030BoundNodesTreeBuilder Builder;
1031CurMatchRAII RAII(*
this, MP.second,
Node);
1032 if(MP.first.matches(
Node,
this, &Builder)) {
1033MatchVisitor Visitor(*
this, ActiveASTContext, MP.second);
1034Builder.visitMatches(&Visitor);
1039 voidmatchWithFilter(
constDynTypedNode &DynNode) {
1040 auto Kind= DynNode.getNodeKind();
1041 autoit = MatcherFiltersMap.find(
Kind);
1043it != MatcherFiltersMap.end() ? it->second : getFilterForKind(
Kind);
1048 const boolEnableCheckProfiling = Options.CheckProfiling.has_value();
1049TimeBucketRegion Timer;
1050 auto&Matchers = this->Matchers->DeclOrStmt;
1051 for(
unsigned shortI : Filter) {
1052 auto&MP = Matchers[I];
1053 if(EnableCheckProfiling)
1054Timer.setBucket(&TimeByBucket[MP.second->getID()]);
1055BoundNodesTreeBuilder Builder;
1058TraversalKindScope RAII(getASTContext(), MP.first.getTraversalKind());
1059 if(getASTContext().getParentMapContext().traverseIgnored(DynNode) !=
1064CurMatchRAII RAII(*
this, MP.second, DynNode);
1065 if(MP.first.matches(DynNode,
this, &Builder)) {
1066MatchVisitor Visitor(*
this, ActiveASTContext, MP.second);
1067Builder.visitMatches(&Visitor);
1072 conststd::vector<unsigned short> &getFilterForKind(ASTNodeKind
Kind) {
1074 auto&Matchers = this->Matchers->DeclOrStmt;
1075assert((Matchers.size() <
USHRT_MAX) &&
"Too many matchers.");
1076 for(
unsignedI = 0,
E= Matchers.size(); I !=
E; ++I) {
1077 if(Matchers[I].first.canMatchNodesOfKind(
Kind)) {
1086 voidmatchDispatch(
constDecl *
Node) {
1089 voidmatchDispatch(
constStmt *
Node) {
1093 voidmatchDispatch(
constType *
Node) {
1094matchWithoutFilter(QualType(
Node, 0), Matchers->Type);
1096 voidmatchDispatch(
constTypeLoc *
Node) {
1097matchWithoutFilter(*
Node, Matchers->TypeLoc);
1099 voidmatchDispatch(
constQualType *
Node) {
1100matchWithoutFilter(*
Node, Matchers->Type);
1102 voidmatchDispatch(
constNestedNameSpecifier *
Node) {
1103matchWithoutFilter(*
Node, Matchers->NestedNameSpecifier);
1105 voidmatchDispatch(
constNestedNameSpecifierLoc *
Node) {
1106matchWithoutFilter(*
Node, Matchers->NestedNameSpecifierLoc);
1108 voidmatchDispatch(
constCXXCtorInitializer *
Node) {
1109matchWithoutFilter(*
Node, Matchers->CtorInit);
1111 voidmatchDispatch(
constTemplateArgumentLoc *
Node) {
1112matchWithoutFilter(*
Node, Matchers->TemplateArgumentLoc);
1114 voidmatchDispatch(
constAttr *
Node) {
1115matchWithoutFilter(*
Node, Matchers->Attr);
1117 voidmatchDispatch(
const void*) {
}
1122 boolmatchesParentOf(
constDynTypedNode &
Node,
constDynTypedMatcher &Matcher,
1123BoundNodesTreeBuilder *Builder) {
1124 for(
const auto&
Parent: ActiveASTContext->getParents(
Node)) {
1125BoundNodesTreeBuilder BuilderCopy = *Builder;
1126 if(Matcher.matches(
Parent,
this, &BuilderCopy)) {
1127*Builder = std::move(BuilderCopy);
1150 boolmatchesAnyAncestorOf(DynTypedNode
Node, ASTContext &Ctx,
1151 constDynTypedMatcher &Matcher,
1152BoundNodesTreeBuilder *Builder) {
1157std::vector<MatchKey> Keys;
1159 autoFinish = [&](
boolMatched) {
1160 for(
const auto&Key : Keys) {
1161MemoizedMatchResult &CachedResult = ResultCache[Key];
1162CachedResult.ResultOfMatch = Matched;
1163CachedResult.Nodes = *Builder;
1169DynTypedNodeList Parents{ArrayRef<DynTypedNode>()};
1172 if(Builder->isComparable()) {
1173Keys.emplace_back();
1174Keys.back().MatcherID = Matcher.getID();
1175Keys.back().Node =
Node;
1176Keys.back().BoundNodes = *Builder;
1177Keys.back().Traversal = Ctx.getParentMapContext().getTraversalKind();
1178Keys.back().Type = MatchType::Ancestors;
1181MemoizationMap::iterator I = ResultCache.find(Keys.back());
1182 if(I != ResultCache.end()) {
1184*Builder = I->second.Nodes;
1185 returnFinish(I->second.ResultOfMatch);
1189Parents = ActiveASTContext->getParents(
Node);
1192 if(Parents.size() != 1)
1196 Node= *Parents.begin();
1197BoundNodesTreeBuilder BuilderCopy = *Builder;
1198 if(Matcher.matches(
Node,
this, &BuilderCopy)) {
1199*Builder = std::move(BuilderCopy);
1200 returnFinish(
true);
1205 if(Parents.empty()) {
1213 if(!
Node.get<TranslationUnitDecl>() &&
1215llvm::any_of(ActiveASTContext->getTraversalScope(), [](Decl *
D) {
1216return D->getKind() == Decl::TranslationUnit;
1218llvm::errs() <<
"Tried to match orphan node:\n";
1219 Node.dump(llvm::errs(), *ActiveASTContext);
1220llvm_unreachable(
"Parent map should be complete!");
1224assert(Parents.size() > 1);
1228std::deque<DynTypedNode> Queue(Parents.begin(), Parents.end());
1229llvm::DenseSet<const void *>
Visited;
1230 while(!Queue.empty()) {
1231BoundNodesTreeBuilder BuilderCopy = *Builder;
1232 if(Matcher.matches(Queue.front(),
this, &BuilderCopy)) {
1233*Builder = std::move(BuilderCopy);
1234 returnFinish(
true);
1236 for(
const auto&
Parent: ActiveASTContext->getParents(Queue.front())) {
1241Queue.push_back(
Parent);
1246 returnFinish(
false);
1251 classMatchVisitor :
publicBoundNodesTreeBuilder::Visitor {
1252 structCurBoundScope {
1253CurBoundScope(MatchASTVisitor::CurMatchData &State,
constBoundNodes &BN)
1255State.SetBoundNodes(BN);
1258~CurBoundScope() { State.clearBoundNodes(); }
1261MatchASTVisitor::CurMatchData &State;
1265MatchVisitor(MatchASTVisitor &MV, ASTContext *Context,
1266MatchFinder::MatchCallback *Callback)
1267: State(MV.CurMatchState), Context(Context), Callback(Callback) {}
1269 voidvisitMatch(
constBoundNodes& BoundNodesView)
override{
1270TraversalKindScope RAII(*Context, Callback->getCheckTraversalKind());
1271CurBoundScope RAII2(State, BoundNodesView);
1272Callback->run(MatchFinder::MatchResult(BoundNodesView, Context));
1276MatchASTVisitor::CurMatchData &State;
1277ASTContext* Context;
1278MatchFinder::MatchCallback* Callback;
1282 booltypeHasMatchingAlias(
constType *TypeNode,
1283 constMatcher<NamedDecl> &Matcher,
1284BoundNodesTreeBuilder *Builder) {
1285 const Type*
constCanonicalType =
1286ActiveASTContext->getCanonicalType(TypeNode);
1287 autoAliases = TypeAliases.find(CanonicalType);
1288 if(Aliases == TypeAliases.end())
1290 for(
constTypedefNameDecl *Alias : Aliases->second) {
1291BoundNodesTreeBuilder
Result(*Builder);
1292 if(Matcher.matches(*Alias,
this, &
Result)) {
1293*Builder = std::move(
Result);
1301objcClassHasMatchingCompatibilityAlias(
constObjCInterfaceDecl *InterfaceDecl,
1302 constMatcher<NamedDecl> &Matcher,
1303BoundNodesTreeBuilder *Builder) {
1304 autoAliases = CompatibleAliases.find(InterfaceDecl);
1305 if(Aliases == CompatibleAliases.end())
1307 for(
constObjCCompatibleAliasDecl *Alias : Aliases->second) {
1308BoundNodesTreeBuilder
Result(*Builder);
1309 if(Matcher.matches(*Alias,
this, &
Result)) {
1310*Builder = std::move(
Result);
1320llvm::StringMap<llvm::TimeRecord> TimeByBucket;
1322 constMatchFinder::MatchersByType *Matchers;
1330llvm::DenseMap<ASTNodeKind, std::vector<unsigned short>> MatcherFiltersMap;
1332 constMatchFinder::MatchFinderOptions &Options;
1333ASTContext *ActiveASTContext;
1336llvm::DenseMap<const Type*, std::set<const TypedefNameDecl*> > TypeAliases;
1339llvm::DenseMap<
constObjCInterfaceDecl *,
1344 typedefstd::map<MatchKey, MemoizedMatchResult> MemoizationMap;
1345MemoizationMap ResultCache;
1348staticCXXRecordDecl *
1349getAsCXXRecordDeclOrPrimaryTemplate(
constType *TypeNode) {
1350 if(
auto*RD = TypeNode->getAsCXXRecordDecl())
1354 auto*TemplateType = TypeNode->getAs<TemplateSpecializationType>();
1355 while(TemplateType && TemplateType->isTypeAlias())
1357TemplateType->getAliasedType()->getAs<TemplateSpecializationType>();
1362 if(
auto*ClassTemplate = dyn_cast_or_null<ClassTemplateDecl>(
1363TemplateType->getTemplateName().getAsTemplateDecl()))
1364 returnClassTemplate->getTemplatedDecl();
1372boolMatchASTVisitor::classIsDerivedFrom(
constCXXRecordDecl *
Declaration,
1373 constMatcher<NamedDecl> &
Base,
1374BoundNodesTreeBuilder *Builder,
1380boolMatchASTVisitor::classIsDerivedFromImpl(
1382BoundNodesTreeBuilder *Builder,
boolDirectly,
1383llvm::SmallPtrSetImpl<const CXXRecordDecl *> &
Visited) {
1389 const Type*TypeNode = It.getType().getTypePtr();
1391 if(typeHasMatchingAlias(TypeNode,
Base, Builder))
1397CXXRecordDecl *ClassDecl = getAsCXXRecordDeclOrPrimaryTemplate(TypeNode);
1404BoundNodesTreeBuilder
Result(*Builder);
1405 if(
Base.matches(*ClassDecl,
this, &
Result)) {
1406*Builder = std::move(
Result);
1410classIsDerivedFromImpl(ClassDecl,
Base, Builder, Directly,
Visited))
1419boolMatchASTVisitor::objcClassIsDerivedFrom(
1420 constObjCInterfaceDecl *
Declaration,
constMatcher<NamedDecl> &
Base,
1421BoundNodesTreeBuilder *Builder,
boolDirectly) {
1423 for(
constObjCInterfaceDecl *ClassDecl =
Declaration->getSuperClass();
1424ClassDecl !=
nullptr; ClassDecl = ClassDecl->getSuperClass()) {
1426 if(objcClassHasMatchingCompatibilityAlias(ClassDecl,
Base, Builder))
1430 const Type*TypeNode = ClassDecl->getTypeForDecl();
1431 if(typeHasMatchingAlias(TypeNode,
Base, Builder))
1434 if(
Base.matches(*ClassDecl,
this, Builder))
1445boolMatchASTVisitor::TraverseDecl(Decl *DeclNode) {
1450 boolScopedTraversal =
1451TraversingASTNodeNotSpelledInSource || DeclNode->isImplicit();
1452 boolScopedChildren = TraversingASTChildrenNotSpelledInSource;
1454 if(
const auto*CTSD = dyn_cast<ClassTemplateSpecializationDecl>(DeclNode)) {
1455 autoSK = CTSD->getSpecializationKind();
1458ScopedChildren =
true;
1459}
else if(
const auto*FD = dyn_cast<FunctionDecl>(DeclNode)) {
1460 if(FD->isDefaulted())
1461ScopedChildren =
true;
1462 if(FD->isTemplateInstantiation())
1463ScopedTraversal =
true;
1464}
else if(isa<BindingDecl>(DeclNode)) {
1465ScopedChildren =
true;
1468ASTNodeNotSpelledInSourceScope RAII1(
this, ScopedTraversal);
1469ASTChildrenNotSpelledInSourceScope RAII2(
this, ScopedChildren);
1475boolMatchASTVisitor::TraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue) {
1479 boolScopedTraversal = TraversingASTNodeNotSpelledInSource ||
1480TraversingASTChildrenNotSpelledInSource;
1482ASTNodeNotSpelledInSourceScope RAII(
this, ScopedTraversal);
1487boolMatchASTVisitor::TraverseType(QualType TypeNode) {
1492boolMatchASTVisitor::TraverseTypeLoc(TypeLoc TypeLocNode) {
1498 match(TypeLocNode);
1499 match(TypeLocNode.getType());
1503boolMatchASTVisitor::TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) {
1508boolMatchASTVisitor::TraverseNestedNameSpecifierLoc(
1509NestedNameSpecifierLoc NNS) {
1517 if(NNS.hasQualifier())
1518 match(*NNS.getNestedNameSpecifier());
1523boolMatchASTVisitor::TraverseConstructorInitializer(
1524CXXCtorInitializer *CtorInit) {
1528 boolScopedTraversal = TraversingASTNodeNotSpelledInSource ||
1529TraversingASTChildrenNotSpelledInSource;
1531 if(!CtorInit->isWritten())
1532ScopedTraversal =
true;
1534ASTNodeNotSpelledInSourceScope RAII1(
this, ScopedTraversal);
1542boolMatchASTVisitor::TraverseTemplateArgumentLoc(TemplateArgumentLoc
Loc) {
1547boolMatchASTVisitor::TraverseAttr(Attr *AttrNode) {
1552classMatchASTConsumer :
publicASTConsumer {
1554MatchASTConsumer(MatchFinder *Finder,
1555MatchFinder::ParsingDoneTestCallback *ParsingDone)
1556: Finder(Finder), ParsingDone(ParsingDone) {}
1559 voidHandleTranslationUnit(ASTContext &Context)
override{
1560 if(ParsingDone !=
nullptr) {
1563Finder->matchAST(Context);
1566MatchFinder *Finder;
1567MatchFinder::ParsingDoneTestCallback *ParsingDone;
1582: Options(
std::move(Options)), ParsingDone(nullptr) {}
1588std::optional<TraversalKind> TK;
1592Matchers.DeclOrStmt.emplace_back(
traverse(*TK, NodeMatch), Action);
1594Matchers.DeclOrStmt.emplace_back(NodeMatch, Action);
1595Matchers.AllCallbacks.insert(Action);
1600Matchers.Type.emplace_back(NodeMatch, Action);
1601Matchers.AllCallbacks.insert(Action);
1606std::optional<TraversalKind> TK;
1610Matchers.DeclOrStmt.emplace_back(
traverse(*TK, NodeMatch), Action);
1612Matchers.DeclOrStmt.emplace_back(NodeMatch, Action);
1613Matchers.AllCallbacks.insert(Action);
1618Matchers.NestedNameSpecifier.emplace_back(NodeMatch, Action);
1619Matchers.AllCallbacks.insert(Action);
1624Matchers.NestedNameSpecifierLoc.emplace_back(NodeMatch, Action);
1625Matchers.AllCallbacks.insert(Action);
1630Matchers.TypeLoc.emplace_back(NodeMatch, Action);
1631Matchers.AllCallbacks.insert(Action);
1636Matchers.CtorInit.emplace_back(NodeMatch, Action);
1637Matchers.AllCallbacks.insert(Action);
1642Matchers.TemplateArgumentLoc.emplace_back(NodeMatch, Action);
1643Matchers.AllCallbacks.insert(Action);
1648Matchers.Attr.emplace_back(AttrMatch, Action);
1649Matchers.AllCallbacks.insert(Action);
1654 if(NodeMatch.canConvertTo<
Decl>()) {
1657}
else if(NodeMatch.canConvertTo<
QualType>()) {
1660}
else if(NodeMatch.canConvertTo<
Stmt>()) {
1669}
else if(NodeMatch.canConvertTo<
TypeLoc>()) {
1678}
else if(NodeMatch.canConvertTo<
Attr>()) {
1686 returnstd::make_unique<internal::MatchASTConsumer>(
this, ParsingDone);
1690internal::MatchASTVisitor Visitor(&Matchers, Options);
1691Visitor.set_active_ast_context(&Context);
1692Visitor.match(
Node);
1696internal::MatchASTVisitor Visitor(&Matchers, Options);
1697internal::MatchASTVisitor::TraceReporter StackTrace(Visitor);
1698Visitor.set_active_ast_context(&Context);
1699Visitor.onStartOfTranslationUnit();
1700Visitor.TraverseAST(Context);
1701Visitor.onEndOfTranslationUnit();
1706ParsingDone = NewParsingDone;
1711std::optional<TraversalKind>
1713 returnstd::nullopt;
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::@1704::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<int>::".
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)
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4