12 #include "clang/AST/ASTTypeTraits.h" 13 #include "clang/AST/Decl.h" 14 #include "clang/AST/DeclCXX.h" 15 #include "clang/AST/DeclTemplate.h" 16 #include "clang/AST/DeclVisitor.h" 17 #include "clang/AST/DeclarationName.h" 18 #include "clang/AST/Expr.h" 19 #include "clang/AST/ExprCXX.h" 20 #include "clang/AST/ExprObjC.h" 21 #include "clang/AST/NestedNameSpecifier.h" 22 #include "clang/AST/PrettyPrinter.h" 23 #include "clang/AST/RecursiveASTVisitor.h" 24 #include "clang/AST/StmtVisitor.h" 25 #include "clang/AST/TemplateBase.h" 26 #include "clang/AST/Type.h" 27 #include "clang/AST/TypeLoc.h" 28 #include "clang/AST/TypeLocVisitor.h" 29 #include "clang/Basic/LangOptions.h" 30 #include "clang/Basic/OperatorKinds.h" 31 #include "clang/Basic/SourceLocation.h" 32 #include "llvm/ADT/STLExtras.h" 33 #include "llvm/ADT/SmallVector.h" 34 #include "llvm/Support/Casting.h" 35 #include "llvm/Support/Compiler.h" 36 #include "llvm/Support/raw_ostream.h" 42 using ast_type_traits::DynTypedNode;
44 LLVM_ATTRIBUTE_UNUSED std::string
45 nodeToString(
const ast_type_traits::DynTypedNode &N) {
46 std::string S = N.getNodeKind().asStringRef();
48 llvm::raw_string_ostream OS(S);
50 N.print(OS, PrintingPolicy(LangOptions()));
69 std::vector<const NamedDecl *> getMembersReferencedViaDependentName(
71 llvm::function_ref<DeclarationName(ASTContext &)> NameFactory,
72 bool IsNonstaticMember) {
75 if (
auto *ICNT = T->getAs<InjectedClassNameType>()) {
76 T = ICNT->getInjectedSpecializationType().getTypePtrOrNull();
78 auto *TST = T->getAs<TemplateSpecializationType>();
81 const ClassTemplateDecl *TD = dyn_cast_or_null<ClassTemplateDecl>(
82 TST->getTemplateName().getAsTemplateDecl());
85 CXXRecordDecl *RD = TD->getTemplatedDecl();
86 if (!RD->hasDefinition())
88 RD = RD->getDefinition();
89 DeclarationName
Name = NameFactory(RD->getASTContext());
90 return RD->lookupDependentName(Name, [=](
const NamedDecl *D) {
91 return IsNonstaticMember ? D->isCXXInstanceMember()
92 : !D->isCXXInstanceMember();
99 const Type *getPointeeType(
const Type *T) {
103 if (T->isPointerType()) {
104 return T->getAs<PointerType>()->getPointeeType().getTypePtrOrNull();
111 auto ArrowOps = getMembersReferencedViaDependentName(
113 [](ASTContext &
Ctx) {
114 return Ctx.DeclarationNames.getCXXOperatorName(OO_Arrow);
117 if (ArrowOps.empty())
126 auto *TST = T->getAs<TemplateSpecializationType>();
129 if (TST->getNumArgs() == 0)
131 const TemplateArgument &FirstArg = TST->getArg(0);
134 return FirstArg.getAsType().getTypePtrOrNull();
167 struct TargetFinder {
168 using RelSet = DeclRelationSet;
170 llvm::SmallDenseMap<const NamedDecl *, RelSet>
Decls;
173 static const NamedDecl *getTemplatePattern(
const NamedDecl *D) {
174 if (
const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(D)) {
175 return CRD->getTemplateInstantiationPattern();
176 }
else if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
177 return FD->getTemplateInstantiationPattern();
178 }
else if (
auto *VD = dyn_cast<VarDecl>(D)) {
180 VarDecl *T = VD->getTemplateInstantiationPattern();
181 return (T == D) ? nullptr : T;
182 }
else if (
const auto *ED = dyn_cast<EnumDecl>(D)) {
183 return ED->getInstantiatedFromMemberEnum();
184 }
else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D)) {
185 if (
const auto *
Parent = llvm::dyn_cast<NamedDecl>(D->getDeclContext()))
186 if (
const DeclContext *ParentPat =
187 dyn_cast_or_null<DeclContext>(getTemplatePattern(
Parent)))
188 for (
const NamedDecl *BaseND : ParentPat->lookup(D->getDeclName()))
189 if (!BaseND->isImplicit() && BaseND->getKind() == D->getKind())
191 }
else if (
const auto *ECD = dyn_cast<EnumConstantDecl>(D)) {
192 if (
const auto *ED = dyn_cast<EnumDecl>(ECD->getDeclContext())) {
193 if (
const EnumDecl *Pattern = ED->getInstantiatedFromMemberEnum()) {
194 for (
const NamedDecl *BaseECD : Pattern->lookup(ECD->getDeclName()))
202 template <
typename T>
void debug(T &Node, RelSet Flags) {
203 dlog(
"visit [{0}] {1}", Flags,
204 nodeToString(ast_type_traits::DynTypedNode::create(Node)));
207 void report(
const NamedDecl *D, RelSet Flags) {
208 dlog(
"--> [{0}] {1}", Flags,
209 nodeToString(ast_type_traits::DynTypedNode::create(*D)));
214 void add(
const Decl *Dcl, RelSet Flags) {
215 const NamedDecl *D = llvm::dyn_cast<NamedDecl>(Dcl);
219 if (
const UsingDirectiveDecl *UDD = llvm::dyn_cast<UsingDirectiveDecl>(D))
220 D = UDD->getNominatedNamespaceAsWritten();
222 if (
const TypedefNameDecl *TND = dyn_cast<TypedefNameDecl>(D)) {
225 }
else if (
const UsingDecl *UD = dyn_cast<UsingDecl>(D)) {
226 for (
const UsingShadowDecl *S : UD->shadows())
229 }
else if (
const auto *NAD = dyn_cast<NamespaceAliasDecl>(D)) {
232 }
else if (
const UsingShadowDecl *USD = dyn_cast<UsingShadowDecl>(D)) {
235 report(USD->getUsingDecl(), Flags |
Rel::Alias);
238 D = USD->getTargetDecl();
242 if (
const Decl *Pat = getTemplatePattern(D)) {
252 void add(
const Stmt *S, RelSet Flags) {
256 struct Visitor :
public ConstStmtVisitor<Visitor> {
259 Visitor(TargetFinder &Outer, RelSet Flags) : Outer(Outer),
Flags(Flags) {}
261 void VisitCallExpr(
const CallExpr *CE) {
262 Outer.add(CE->getCalleeDecl(),
Flags);
264 void VisitDeclRefExpr(
const DeclRefExpr *DRE) {
265 const Decl *D = DRE->getDecl();
268 if (
auto *USD = llvm::dyn_cast<UsingShadowDecl>(DRE->getFoundDecl()))
272 void VisitMemberExpr(
const MemberExpr *ME) {
273 const Decl *D = ME->getMemberDecl();
275 llvm::dyn_cast<UsingShadowDecl>(ME->getFoundDecl().getDecl()))
279 void VisitOverloadExpr(
const OverloadExpr *OE) {
280 for (
auto *D : OE->decls())
283 void VisitSizeOfPackExpr(
const SizeOfPackExpr *SE) {
284 Outer.add(SE->getPack(),
Flags);
286 void VisitCXXConstructExpr(
const CXXConstructExpr *CCE) {
287 Outer.add(CCE->getConstructor(),
Flags);
289 void VisitDesignatedInitExpr(
const DesignatedInitExpr *DIE) {
290 for (
const DesignatedInitExpr::Designator &D :
291 llvm::reverse(DIE->designators()))
292 if (D.isFieldDesignator()) {
293 Outer.add(D.getField(),
Flags);
299 VisitCXXDependentScopeMemberExpr(
const CXXDependentScopeMemberExpr *
E) {
300 const Type *BaseType = E->getBaseType().getTypePtrOrNull();
302 BaseType = getPointeeType(BaseType);
304 for (
const NamedDecl *D : getMembersReferencedViaDependentName(
305 BaseType, [E](ASTContext &) {
return E->getMember(); },
310 void VisitDependentScopeDeclRefExpr(
const DependentScopeDeclRefExpr *E) {
311 for (
const NamedDecl *D : getMembersReferencedViaDependentName(
312 E->getQualifier()->getAsType(),
313 [
E](ASTContext &) {
return E->getDeclName(); },
318 void VisitObjCIvarRefExpr(
const ObjCIvarRefExpr *OIRE) {
319 Outer.add(OIRE->getDecl(),
Flags);
321 void VisitObjCMessageExpr(
const ObjCMessageExpr *OME) {
322 Outer.add(OME->getMethodDecl(),
Flags);
324 void VisitObjCPropertyRefExpr(
const ObjCPropertyRefExpr *OPRE) {
325 if (OPRE->isExplicitProperty())
326 Outer.add(OPRE->getExplicitProperty(),
Flags);
328 if (OPRE->isMessagingGetter())
329 Outer.add(OPRE->getImplicitPropertyGetter(),
Flags);
330 if (OPRE->isMessagingSetter())
331 Outer.add(OPRE->getImplicitPropertySetter(),
Flags);
334 void VisitObjCProtocolExpr(
const ObjCProtocolExpr *OPE) {
335 Outer.add(OPE->getProtocol(),
Flags);
337 void VisitOpaqueValueExpr(
const OpaqueValueExpr *OVE) {
338 Outer.add(OVE->getSourceExpr(),
Flags);
340 void VisitPseudoObjectExpr(
const PseudoObjectExpr *POE) {
341 Outer.add(POE->getSyntacticForm(),
Flags);
344 Visitor(*
this, Flags).Visit(S);
347 void add(QualType T, RelSet Flags) {
351 struct Visitor :
public TypeVisitor<Visitor> {
354 Visitor(TargetFinder &Outer, RelSet Flags) : Outer(Outer),
Flags(Flags) {}
356 void VisitTagType(
const TagType *TT) {
357 Outer.add(TT->getAsTagDecl(),
Flags);
359 void VisitDecltypeType(
const DecltypeType *DTT) {
367 void VisitDeducedTemplateSpecializationType(
368 const DeducedTemplateSpecializationType *DTST) {
375 if (
auto *TD = DTST->getTemplateName().getAsTemplateDecl())
378 void VisitTypedefType(
const TypedefType *TT) {
379 Outer.add(TT->getDecl(),
Flags);
382 VisitTemplateSpecializationType(
const TemplateSpecializationType *TST) {
389 if (TST->isTypeAlias()) {
394 TST->getTemplateName().getAsTemplateDecl()->getTemplatedDecl(),
399 else if (
const auto *Parm =
400 llvm::dyn_cast_or_null<TemplateTemplateParmDecl>(
401 TST->getTemplateName().getAsTemplateDecl()))
402 Outer.add(Parm, Flags);
404 else if (
const CXXRecordDecl *RD = TST->getAsCXXRecordDecl())
405 Outer.add(RD, Flags);
408 if (
auto *TD = TST->getTemplateName().getAsTemplateDecl())
412 void VisitTemplateTypeParmType(
const TemplateTypeParmType *TTPT) {
413 Outer.add(TTPT->getDecl(),
Flags);
415 void VisitObjCInterfaceType(
const ObjCInterfaceType *OIT) {
416 Outer.add(OIT->getDecl(),
Flags);
418 void VisitObjCObjectType(
const ObjCObjectType *OOT) {
421 if (OOT->isObjCQualifiedId() && OOT->getNumProtocols() == 1)
422 Outer.add(OOT->getProtocol(0),
Flags);
425 Visitor(*
this, Flags).Visit(T.getTypePtr());
428 void add(
const NestedNameSpecifier *NNS, RelSet Flags) {
432 switch (NNS->getKind()) {
436 add(NNS->getAsNamespace(),
Flags);
438 case NestedNameSpecifier::NamespaceAlias:
439 add(NNS->getAsNamespaceAlias(),
Flags);
441 case NestedNameSpecifier::TypeSpec:
442 case NestedNameSpecifier::TypeSpecWithTemplate:
443 add(QualType(NNS->getAsType(), 0), Flags);
445 case NestedNameSpecifier::Global:
448 case NestedNameSpecifier::Super:
449 add(NNS->getAsRecordDecl(),
Flags);
452 llvm_unreachable(
"unhandled NestedNameSpecifier::SpecifierKind");
455 void add(
const CXXCtorInitializer *CCI, RelSet Flags) {
460 if (CCI->isAnyMemberInitializer())
461 add(CCI->getAnyMember(),
Flags);
468 llvm::SmallVector<std::pair<const NamedDecl *, DeclRelationSet>, 1>
470 dlog(
"allTargetDecls({0})", nodeToString(N));
474 Finder.add(D, Flags);
475 else if (
const Stmt *S = N.get<Stmt>())
476 Finder.add(S, Flags);
477 else if (
const NestedNameSpecifierLoc *NNSL = N.get<NestedNameSpecifierLoc>())
478 Finder.add(NNSL->getNestedNameSpecifier(),
Flags);
479 else if (
const NestedNameSpecifier *NNS = N.get<NestedNameSpecifier>())
480 Finder.add(NNS, Flags);
481 else if (
const TypeLoc *TL = N.get<TypeLoc>())
482 Finder.add(TL->getType(),
Flags);
483 else if (
const QualType *QT = N.get<QualType>())
484 Finder.add(*QT, Flags);
485 else if (
const CXXCtorInitializer *CCI = N.get<CXXCtorInitializer>())
486 Finder.add(CCI, Flags);
488 return {Finder.Decls.begin(), Finder.Decls.end()};
491 llvm::SmallVector<const NamedDecl *, 1>
493 llvm::SmallVector<const NamedDecl *, 1> Result;
495 if (!(
Entry.second & ~Mask))
496 Result.push_back(
Entry.first);
501 llvm::SmallVector<const NamedDecl *, 1>
505 "explicitRefenceTargets handles templates on its own");
512 llvm::SmallVector<const NamedDecl *, 1> TemplatePatterns;
513 llvm::SmallVector<const NamedDecl *, 1> Targets;
514 bool SeenTemplateInstantiations =
false;
515 for (
auto &D :
Decls) {
516 if (D.second & ~Mask)
519 TemplatePatterns.push_back(D.first);
523 SeenTemplateInstantiations =
true;
524 Targets.push_back(D.first);
526 if (!SeenTemplateInstantiations)
527 Targets.insert(Targets.end(), TemplatePatterns.begin(),
528 TemplatePatterns.end());
533 llvm::SmallVector<ReferenceLoc, 2> refInDecl(
const Decl *D) {
534 struct Visitor : ConstDeclVisitor<Visitor> {
535 llvm::SmallVector<ReferenceLoc, 2>
Refs;
537 void VisitUsingDirectiveDecl(
const UsingDirectiveDecl *D) {
541 D->getIdentLocation(),
543 {D->getNominatedNamespaceAsWritten()}});
546 void VisitUsingDecl(
const UsingDecl *D) {
549 ReferenceLoc{D->getQualifierLoc(), D->getLocation(),
false,
554 void VisitNamespaceAliasDecl(
const NamespaceAliasDecl *D) {
560 D->getTargetNameLoc(),
562 {D->getAliasedNamespace()}});
565 void VisitNamedDecl(
const NamedDecl *ND) {
567 if (llvm::isa<CXXDestructorDecl>(ND))
571 if (ND->getDeclName().isIdentifier() &&
572 !ND->getDeclName().getAsIdentifierInfo())
586 llvm::SmallVector<ReferenceLoc, 2> refInExpr(
const Expr *
E) {
587 struct Visitor : ConstStmtVisitor<Visitor> {
589 llvm::SmallVector<ReferenceLoc, 2>
Refs;
591 void VisitDeclRefExpr(
const DeclRefExpr *E) {
593 E->getNameInfo().getLoc(),
595 {E->getFoundDecl()}});
598 void VisitMemberExpr(
const MemberExpr *E) {
600 E->getMemberNameInfo().getLoc(),
602 {E->getFoundDecl()}});
605 void VisitOverloadExpr(
const OverloadExpr *E) {
607 E->getNameInfo().getLoc(),
609 llvm::SmallVector<const NamedDecl *, 1>(
610 E->decls().begin(), E->decls().end())});
613 void VisitSizeOfPackExpr(
const SizeOfPackExpr *E) {
626 llvm::SmallVector<ReferenceLoc, 2> refInTypeLoc(TypeLoc L) {
627 struct Visitor : TypeLocVisitor<Visitor> {
628 llvm::Optional<ReferenceLoc>
Ref;
630 void VisitElaboratedTypeLoc(ElaboratedTypeLoc L) {
632 Visit(L.getNamedTypeLoc().getUnqualifiedLoc());
636 assert(!Ref->Qualifier.hasQualifier() &&
"qualifier already set");
637 Ref->Qualifier = L.getQualifierLoc();
640 void VisitTagTypeLoc(TagTypeLoc L) {
647 void VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc L) {
654 void VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc L) {
664 NestedNameSpecifierLoc(), L.getTemplateNameLoc(),
false,
668 void VisitDeducedTemplateSpecializationTypeLoc(
669 DeducedTemplateSpecializationTypeLoc L) {
671 NestedNameSpecifierLoc(), L.getNameLoc(),
false,
676 void VisitDependentTemplateSpecializationTypeLoc(
677 DependentTemplateSpecializationTypeLoc L) {
679 L.getQualifierLoc(), L.getTemplateNameLoc(),
false,
683 void VisitDependentNameTypeLoc(DependentNameTypeLoc L) {
685 L.getQualifierLoc(), L.getNameLoc(),
false,
689 void VisitTypedefTypeLoc(TypedefTypeLoc L) {
693 {L.getTypedefNameDecl()}};
698 V.Visit(L.getUnqualifiedLoc());
704 class ExplicitReferenceCollector
705 :
public RecursiveASTVisitor<ExplicitReferenceCollector> {
707 ExplicitReferenceCollector(llvm::function_ref<
void(
ReferenceLoc)> Out)
712 bool VisitTypeLoc(TypeLoc TTL) {
713 if (TypeLocsToSkip.count(TTL.getBeginLoc().getRawEncoding()))
715 visitNode(DynTypedNode::create(TTL));
719 bool TraverseElaboratedTypeLoc(ElaboratedTypeLoc L) {
722 TypeLoc Inner = L.getNamedTypeLoc().getUnqualifiedLoc();
723 TypeLocsToSkip.insert(Inner.getBeginLoc().getRawEncoding());
724 return RecursiveASTVisitor::TraverseElaboratedTypeLoc(L);
727 bool VisitExpr(Expr *E) {
728 visitNode(DynTypedNode::create(*E));
735 bool TraverseTemplateArgumentLoc(TemplateArgumentLoc A) {
736 switch (A.getArgument().getKind()) {
737 case TemplateArgument::Template:
738 case TemplateArgument::TemplateExpansion:
739 reportReference(
ReferenceLoc{A.getTemplateQualifierLoc(),
740 A.getTemplateNameLoc(),
743 .getAsTemplateOrTemplatePattern()
744 .getAsTemplateDecl()}},
745 DynTypedNode::create(A.getArgument()));
749 case TemplateArgument::Integral:
751 case TemplateArgument::NullPtr:
753 case TemplateArgument::Pack:
755 case TemplateArgument::Expression:
758 return RecursiveASTVisitor::TraverseTemplateArgumentLoc(A);
761 bool VisitDecl(
Decl *D) {
762 visitNode(DynTypedNode::create(*D));
767 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc L) {
768 if (!L.getNestedNameSpecifier())
770 visitNode(DynTypedNode::create(L));
772 if (
auto TL = L.getTypeLoc())
773 TypeLocsToSkip.insert(TL.getBeginLoc().getRawEncoding());
774 return RecursiveASTVisitor::TraverseNestedNameSpecifierLoc(L);
777 bool TraverseConstructorInitializer(CXXCtorInitializer *Init) {
778 visitNode(DynTypedNode::create(*Init));
779 return RecursiveASTVisitor::TraverseConstructorInitializer(Init);
797 llvm::SmallVector<ReferenceLoc, 2> explicitReference(DynTypedNode N) {
798 if (
auto *D = N.get<
Decl>())
800 if (
auto *E = N.get<Expr>())
802 if (
auto *NNSL = N.get<NestedNameSpecifierLoc>()) {
805 NNSL->getPrefix(), NNSL->getLocalBeginLoc(),
false,
807 DynTypedNode::create(*NNSL->getNestedNameSpecifier()),
810 if (
const TypeLoc *TL = N.get<TypeLoc>())
811 return refInTypeLoc(*TL);
812 if (
const CXXCtorInitializer *CCI = N.get<CXXCtorInitializer>()) {
815 if (CCI->isAnyMemberInitializer()) {
817 CCI->getMemberLocation(),
819 {CCI->getAnyMember()}}};
826 void visitNode(DynTypedNode N) {
827 for (
const auto &R : explicitReference(N))
828 reportReference(R, N);
837 dlog(
"invalid location at node {0}", nodeToString(N));
843 llvm::function_ref<void(ReferenceLoc)> Out;
846 llvm::DenseSet<
unsigned> TypeLocsToSkip;
853 ExplicitReferenceCollector(Out).TraverseStmt(const_cast<Stmt *>(S));
858 ExplicitReferenceCollector(Out).TraverseDecl(const_cast<Decl *>(D));
862 ExplicitReferenceCollector(Out).TraverseAST(const_cast<ASTContext &>(AST));
867 #define REL_CASE(X) \ 868 case DeclRelation::X: \ 876 llvm_unreachable(
"Unhandled DeclRelation enum");
879 const char *Sep =
"";
880 for (
unsigned I = 0; I < RS.S.size(); ++I) {
882 OS << Sep << static_cast<DeclRelation>(I);
893 for (
const NamedDecl *T : R.
Targets) {
902 OS <<
", qualifier = '";
903 R.
Qualifier.getNestedNameSpecifier()->print(OS,
904 PrintingPolicy(LangOptions()));
const FunctionDecl * Decl
std::string printQualifiedName(const NamedDecl &ND)
Returns the qualified name of ND.
Information about a reference written in the source code, independent of the actual AST node that thi...
llvm::SmallVector< std::pair< const NamedDecl *, DeclRelationSet >, 1 > allTargetDecls(const ast_type_traits::DynTypedNode &N)
Similar to targetDecl(), however instead of applying a filter, all possible decls are returned along ...
This is the pattern the template specialization was instantiated from.
Represents a symbol occurrence in the source file.
NestedNameSpecifierLoc getQualifierLoc(const NamedDecl &ND)
Returns a nested name specifier loc of ND if it was present in the source, e.g.
std::string printTemplateSpecializationArgs(const NamedDecl &ND)
Prints template arguments of a decl as written in the source code, including enclosing '<' and '>'...
static std::string replace(llvm::StringRef Haystack, llvm::StringRef Needle, llvm::StringRef Repl)
This declaration is an alias that was referred to.
bool IsDecl
True if the reference is a declaration or definition;.
SourceLocation NameLoc
Start location of the last name part, i.e. 'foo' in 'ns::foo<int>'.
llvm::SmallVector< const NamedDecl *, 1 > explicitReferenceTargets(DynTypedNode N, DeclRelationSet Mask)
This is the template instantiation that was referred to.
static constexpr llvm::StringLiteral Name
llvm::SmallVector< const NamedDecl *, 1 > Targets
A list of targets referenced by this name.
llvm::SmallVector< const NamedDecl *, 1 > targetDecl(const ast_type_traits::DynTypedNode &N, DeclRelationSet Mask)
targetDecl() finds the declaration referred to by an AST node.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
void findExplicitReferences(const Stmt *S, llvm::function_ref< void(ReferenceLoc)> Out)
Recursively traverse S and report all references explicitly written in the code.
This is the underlying declaration for an alias, decltype etc.
llvm::SmallDenseMap< const NamedDecl *, RelSet > Decls
llvm::raw_ostream & operator<<(llvm::raw_ostream &OS, const CodeCompletion &C)
NestedNameSpecifierLoc Qualifier
Contains qualifier written in the code, if any, e.g. 'ns::' for 'ns::foo'.