//===- IndexTypeSourceInfo.cpp - Indexing types ---------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "IndexingContext.h" #include "clang/AST/RecursiveASTVisitor.h" using namespace clang; using namespace index; namespace { class TypeIndexer : public RecursiveASTVisitor { IndexingContext &IndexCtx; const NamedDecl *Parent; const DeclContext *ParentDC; bool IsBase; SmallVector Relations; typedef RecursiveASTVisitor base; public: TypeIndexer(IndexingContext &indexCtx, const NamedDecl *parent, const DeclContext *DC, bool isBase, bool isIBType) : IndexCtx(indexCtx), Parent(parent), ParentDC(DC), IsBase(isBase) { if (IsBase) { assert(Parent); Relations.emplace_back((unsigned)SymbolRole::RelationBaseOf, Parent); } if (isIBType) { assert(Parent); Relations.emplace_back((unsigned)SymbolRole::RelationIBTypeOf, Parent); } } bool shouldWalkTypesOfTypeLocs() const { return false; } #define TRY_TO(CALL_EXPR) \ do { \ if (!CALL_EXPR) \ return false; \ } while (0) bool VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TTPL) { SourceLocation Loc = TTPL.getNameLoc(); TemplateTypeParmDecl *TTPD = TTPL.getDecl(); return IndexCtx.handleReference(TTPD, Loc, Parent, ParentDC, SymbolRoleSet()); } bool VisitTypedefTypeLoc(TypedefTypeLoc TL) { SourceLocation Loc = TL.getNameLoc(); TypedefNameDecl *ND = TL.getTypedefNameDecl(); if (ND->isTransparentTag()) { TagDecl *Underlying = ND->getUnderlyingType()->getAsTagDecl(); return IndexCtx.handleReference(Underlying, Loc, Parent, ParentDC, SymbolRoleSet(), Relations); } if (IsBase) { TRY_TO(IndexCtx.handleReference(ND, Loc, Parent, ParentDC, SymbolRoleSet())); if (auto *CD = TL.getType()->getAsCXXRecordDecl()) { TRY_TO(IndexCtx.handleReference(CD, Loc, Parent, ParentDC, (unsigned)SymbolRole::Implicit, Relations)); } } else { TRY_TO(IndexCtx.handleReference(ND, Loc, Parent, ParentDC, SymbolRoleSet(), Relations)); } return true; } bool traverseParamVarHelper(ParmVarDecl *D) { TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc())); if (D->getTypeSourceInfo()) TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc())); return true; } bool TraverseParmVarDecl(ParmVarDecl *D) { // Avoid visiting default arguments from the definition that were already // visited in the declaration. // FIXME: A free function definition can have default arguments. // Avoiding double visitaiton of default arguments should be handled by the // visitor probably with a bit in the AST to indicate if the attached // default argument was 'inherited' or written in source. if (auto FD = dyn_cast(D->getDeclContext())) { if (FD->isThisDeclarationADefinition()) { return traverseParamVarHelper(D); } } return base::TraverseParmVarDecl(D); } bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) { IndexCtx.indexNestedNameSpecifierLoc(NNS, Parent, ParentDC); return true; } bool VisitTagTypeLoc(TagTypeLoc TL) { TagDecl *D = TL.getDecl(); if (!IndexCtx.shouldIndexFunctionLocalSymbols() && D->getParentFunctionOrMethod()) return true; if (TL.isDefinition()) { IndexCtx.indexTagDecl(D); return true; } return IndexCtx.handleReference(D, TL.getNameLoc(), Parent, ParentDC, SymbolRoleSet(), Relations); } bool VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { return IndexCtx.handleReference(TL.getIFaceDecl(), TL.getNameLoc(), Parent, ParentDC, SymbolRoleSet(), Relations); } bool VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) { IndexCtx.handleReference(TL.getProtocol(i), TL.getProtocolLoc(i), Parent, ParentDC, SymbolRoleSet(), Relations); } return true; } void HandleTemplateSpecializationTypeLoc(TemplateName TemplName, SourceLocation TemplNameLoc, CXXRecordDecl *ResolvedClass, bool IsTypeAlias) { // In presence of type aliases, the resolved class was never written in // the code so don't report it. if (!IsTypeAlias && ResolvedClass && (!ResolvedClass->isImplicit() || IndexCtx.shouldIndexImplicitInstantiation())) { IndexCtx.handleReference(ResolvedClass, TemplNameLoc, Parent, ParentDC, SymbolRoleSet(), Relations); } else if (const TemplateDecl *D = TemplName.getAsTemplateDecl()) { IndexCtx.handleReference(D, TemplNameLoc, Parent, ParentDC, SymbolRoleSet(), Relations); } } bool VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) { auto *T = TL.getTypePtr(); if (!T) return true; HandleTemplateSpecializationTypeLoc( T->getTemplateName(), TL.getTemplateNameLoc(), T->getAsCXXRecordDecl(), T->isTypeAlias()); return true; } bool VisitDeducedTemplateSpecializationTypeLoc(DeducedTemplateSpecializationTypeLoc TL) { auto *T = TL.getTypePtr(); if (!T) return true; HandleTemplateSpecializationTypeLoc( T->getTemplateName(), TL.getTemplateNameLoc(), T->getAsCXXRecordDecl(), /*IsTypeAlias=*/false); return true; } bool VisitDependentNameTypeLoc(DependentNameTypeLoc TL) { const DependentNameType *DNT = TL.getTypePtr(); const NestedNameSpecifier *NNS = DNT->getQualifier(); const Type *T = NNS->getAsType(); if (!T) return true; const TemplateSpecializationType *TST = T->getAs(); if (!TST) return true; TemplateName TN = TST->getTemplateName(); const ClassTemplateDecl *TD = dyn_cast_or_null(TN.getAsTemplateDecl()); if (!TD) return true; CXXRecordDecl *RD = TD->getTemplatedDecl(); if (!RD->hasDefinition()) return true; RD = RD->getDefinition(); DeclarationName Name(DNT->getIdentifier()); std::vector Symbols = RD->lookupDependentName( Name, [](const NamedDecl *ND) { return isa(ND); }); if (Symbols.size() != 1) return true; return IndexCtx.handleReference(Symbols[0], TL.getNameLoc(), Parent, ParentDC, SymbolRoleSet(), Relations); } bool TraverseStmt(Stmt *S) { IndexCtx.indexBody(S, Parent, ParentDC); return true; } }; } // anonymous namespace void IndexingContext::indexTypeSourceInfo(TypeSourceInfo *TInfo, const NamedDecl *Parent, const DeclContext *DC, bool isBase, bool isIBType) { if (!TInfo || TInfo->getTypeLoc().isNull()) return; indexTypeLoc(TInfo->getTypeLoc(), Parent, DC, isBase, isIBType); } void IndexingContext::indexTypeLoc(TypeLoc TL, const NamedDecl *Parent, const DeclContext *DC, bool isBase, bool isIBType) { if (TL.isNull()) return; if (!DC) DC = Parent->getLexicalDeclContext(); TypeIndexer(*this, Parent, DC, isBase, isIBType).TraverseTypeLoc(TL); } void IndexingContext::indexNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS, const NamedDecl *Parent, const DeclContext *DC) { if (!NNS) return; if (NestedNameSpecifierLoc Prefix = NNS.getPrefix()) indexNestedNameSpecifierLoc(Prefix, Parent, DC); if (!DC) DC = Parent->getLexicalDeclContext(); SourceLocation Loc = NNS.getLocalBeginLoc(); switch (NNS.getNestedNameSpecifier()->getKind()) { case NestedNameSpecifier::Identifier: case NestedNameSpecifier::Global: case NestedNameSpecifier::Super: break; case NestedNameSpecifier::Namespace: handleReference(NNS.getNestedNameSpecifier()->getAsNamespace(), Loc, Parent, DC, SymbolRoleSet()); break; case NestedNameSpecifier::NamespaceAlias: handleReference(NNS.getNestedNameSpecifier()->getAsNamespaceAlias(), Loc, Parent, DC, SymbolRoleSet()); break; case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: indexTypeLoc(NNS.getTypeLoc(), Parent, DC); break; } } void IndexingContext::indexTagDecl(const TagDecl *D, ArrayRef Relations) { if (!shouldIndex(D)) return; if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalSymbol(D)) return; if (handleDecl(D, /*Roles=*/SymbolRoleSet(), Relations)) { if (D->isThisDeclarationADefinition()) { indexNestedNameSpecifierLoc(D->getQualifierLoc(), D); if (auto CXXRD = dyn_cast(D)) { for (const auto &I : CXXRD->bases()) { indexTypeSourceInfo(I.getTypeSourceInfo(), CXXRD, CXXRD, /*isBase=*/true); } } indexDeclContext(D); } } }