292 lines · cpp
1//===- IndexTypeSourceInfo.cpp - Indexing types ---------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "IndexingContext.h"10#include "clang/AST/ASTConcept.h"11#include "clang/AST/PrettyPrinter.h"12#include "clang/AST/RecursiveASTVisitor.h"13#include "clang/AST/TypeLoc.h"14#include "clang/Sema/HeuristicResolver.h"15#include "llvm/ADT/ScopeExit.h"16 17using namespace clang;18using namespace index;19 20namespace {21 22class TypeIndexer : public RecursiveASTVisitor<TypeIndexer> {23 IndexingContext &IndexCtx;24 const NamedDecl *Parent;25 const DeclContext *ParentDC;26 bool IsBase;27 SmallVector<SymbolRelation, 3> Relations;28 29 typedef RecursiveASTVisitor<TypeIndexer> base;30 31public:32 TypeIndexer(IndexingContext &indexCtx, const NamedDecl *parent,33 const DeclContext *DC, bool isBase, bool isIBType)34 : IndexCtx(indexCtx), Parent(parent), ParentDC(DC), IsBase(isBase) {35 if (IsBase) {36 assert(Parent);37 Relations.emplace_back((unsigned)SymbolRole::RelationBaseOf, Parent);38 }39 if (isIBType) {40 assert(Parent);41 Relations.emplace_back((unsigned)SymbolRole::RelationIBTypeOf, Parent);42 }43 }44 45 bool shouldWalkTypesOfTypeLocs() const { return false; }46 47#define TRY_TO(CALL_EXPR) \48 do { \49 if (!CALL_EXPR) \50 return false; \51 } while (0)52 53 bool VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TTPL) {54 SourceLocation Loc = TTPL.getNameLoc();55 TemplateTypeParmDecl *TTPD = TTPL.getDecl();56 return IndexCtx.handleReference(TTPD, Loc, Parent, ParentDC,57 SymbolRoleSet());58 }59 60 bool VisitTypedefTypeLoc(TypedefTypeLoc TL) {61 SourceLocation Loc = TL.getNameLoc();62 TypedefNameDecl *ND = TL.getDecl();63 if (ND->isTransparentTag()) {64 auto *Underlying = ND->getUnderlyingType()->castAsTagDecl();65 return IndexCtx.handleReference(Underlying, Loc, Parent,66 ParentDC, SymbolRoleSet(), Relations);67 }68 if (IsBase) {69 TRY_TO(IndexCtx.handleReference(ND, Loc,70 Parent, ParentDC, SymbolRoleSet()));71 if (auto *CD = TL.getType()->getAsCXXRecordDecl()) {72 TRY_TO(IndexCtx.handleReference(CD, Loc, Parent, ParentDC,73 (unsigned)SymbolRole::Implicit,74 Relations));75 }76 } else {77 TRY_TO(IndexCtx.handleReference(ND, Loc,78 Parent, ParentDC, SymbolRoleSet(),79 Relations));80 }81 return true;82 }83 84 bool VisitAutoTypeLoc(AutoTypeLoc TL) {85 if (auto *C = TL.getNamedConcept())86 return IndexCtx.handleReference(C, TL.getConceptNameLoc(), Parent,87 ParentDC);88 return true;89 }90 91 bool traverseParamVarHelper(ParmVarDecl *D) {92 TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc()));93 if (D->getTypeSourceInfo())94 TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));95 return true;96 }97 98 bool TraverseParmVarDecl(ParmVarDecl *D) {99 // Avoid visiting default arguments from the definition that were already100 // visited in the declaration.101 // FIXME: A free function definition can have default arguments.102 // Avoiding double visitaiton of default arguments should be handled by the103 // visitor probably with a bit in the AST to indicate if the attached104 // default argument was 'inherited' or written in source.105 if (auto FD = dyn_cast<FunctionDecl>(D->getDeclContext())) {106 if (FD->isThisDeclarationADefinition()) {107 return traverseParamVarHelper(D);108 }109 }110 111 return base::TraverseParmVarDecl(D);112 }113 114 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {115 IndexCtx.indexNestedNameSpecifierLoc(NNS, Parent, ParentDC);116 return true;117 }118 119 bool VisitTagTypeLoc(TagTypeLoc TL) {120 TagDecl *D = TL.getDecl();121 if (!IndexCtx.shouldIndexFunctionLocalSymbols() &&122 D->getParentFunctionOrMethod())123 return true;124 125 if (TL.isDefinition()) {126 IndexCtx.indexTagDecl(D);127 return true;128 }129 130 return IndexCtx.handleReference(D, TL.getNameLoc(),131 Parent, ParentDC, SymbolRoleSet(),132 Relations);133 }134 135 bool VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {136 return IndexCtx.handleReference(TL.getIFaceDecl(), TL.getNameLoc(),137 Parent, ParentDC, SymbolRoleSet(), Relations);138 }139 140 bool VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) {141 for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) {142 IndexCtx.handleReference(TL.getProtocol(i), TL.getProtocolLoc(i),143 Parent, ParentDC, SymbolRoleSet(), Relations);144 }145 return true;146 }147 148 void HandleTemplateSpecializationTypeLoc(TemplateName TemplName,149 SourceLocation TemplNameLoc,150 CXXRecordDecl *ResolvedClass,151 bool IsTypeAlias) {152 // In presence of type aliases, the resolved class was never written in153 // the code so don't report it.154 if (!IsTypeAlias && ResolvedClass &&155 (!ResolvedClass->isImplicit() ||156 IndexCtx.shouldIndexImplicitInstantiation())) {157 IndexCtx.handleReference(ResolvedClass, TemplNameLoc, Parent, ParentDC,158 SymbolRoleSet(), Relations);159 } else if (const TemplateDecl *D = TemplName.getAsTemplateDecl()) {160 IndexCtx.handleReference(D, TemplNameLoc, Parent, ParentDC,161 SymbolRoleSet(), Relations);162 }163 }164 165 bool VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) {166 auto *T = TL.getTypePtr();167 if (!T)168 return true;169 HandleTemplateSpecializationTypeLoc(170 T->getTemplateName(), TL.getTemplateNameLoc(), T->getAsCXXRecordDecl(),171 T->isTypeAlias());172 return true;173 }174 175 bool TraverseTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL,176 bool TraverseQualifier) {177 if (!WalkUpFromTemplateSpecializationTypeLoc(TL))178 return false;179 if (!TraverseTemplateName(TL.getTypePtr()->getTemplateName()))180 return false;181 182 // The relations we have to `Parent` do not apply to our template arguments,183 // so clear them while visiting the args.184 SmallVector<SymbolRelation, 3> SavedRelations = Relations;185 Relations.clear();186 auto ResetSavedRelations =187 llvm::make_scope_exit([&] { this->Relations = SavedRelations; });188 for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) {189 if (!TraverseTemplateArgumentLoc(TL.getArgLoc(I)))190 return false;191 }192 193 return true;194 }195 196 bool VisitDeducedTemplateSpecializationTypeLoc(DeducedTemplateSpecializationTypeLoc TL) {197 auto *T = TL.getTypePtr();198 if (!T)199 return true;200 HandleTemplateSpecializationTypeLoc(201 T->getTemplateName(), TL.getTemplateNameLoc(), T->getAsCXXRecordDecl(),202 /*IsTypeAlias=*/false);203 return true;204 }205 206 bool VisitDependentNameTypeLoc(DependentNameTypeLoc TL) {207 std::vector<const NamedDecl *> Symbols =208 IndexCtx.getResolver()->resolveDependentNameType(TL.getTypePtr());209 if (Symbols.size() != 1)210 return true;211 return IndexCtx.handleReference(Symbols[0], TL.getNameLoc(), Parent,212 ParentDC, SymbolRoleSet(), Relations);213 }214 215 bool TraverseStmt(Stmt *S) {216 IndexCtx.indexBody(S, Parent, ParentDC);217 return true;218 }219};220 221} // anonymous namespace222 223void IndexingContext::indexTypeSourceInfo(TypeSourceInfo *TInfo,224 const NamedDecl *Parent,225 const DeclContext *DC,226 bool isBase,227 bool isIBType) {228 if (!TInfo || TInfo->getTypeLoc().isNull())229 return;230 231 indexTypeLoc(TInfo->getTypeLoc(), Parent, DC, isBase, isIBType);232}233 234void IndexingContext::indexTypeLoc(TypeLoc TL,235 const NamedDecl *Parent,236 const DeclContext *DC,237 bool isBase,238 bool isIBType) {239 if (TL.isNull())240 return;241 242 if (!DC)243 DC = Parent->getLexicalDeclContext();244 TypeIndexer(*this, Parent, DC, isBase, isIBType).TraverseTypeLoc(TL);245}246 247void IndexingContext::indexNestedNameSpecifierLoc(248 NestedNameSpecifierLoc QualifierLoc, const NamedDecl *Parent,249 const DeclContext *DC) {250 if (!DC)251 DC = Parent->getLexicalDeclContext();252 switch (NestedNameSpecifier Qualifier = QualifierLoc.getNestedNameSpecifier();253 Qualifier.getKind()) {254 case NestedNameSpecifier::Kind::Null:255 case NestedNameSpecifier::Kind::Global:256 case NestedNameSpecifier::Kind::MicrosoftSuper:257 break;258 259 case NestedNameSpecifier::Kind::Namespace: {260 auto [Namespace, Prefix] = QualifierLoc.castAsNamespaceAndPrefix();261 indexNestedNameSpecifierLoc(Prefix, Parent, DC);262 handleReference(Namespace, QualifierLoc.getLocalBeginLoc(), Parent, DC,263 SymbolRoleSet());264 break;265 }266 267 case NestedNameSpecifier::Kind::Type:268 indexTypeLoc(QualifierLoc.castAsTypeLoc(), Parent, DC);269 break;270 }271}272 273void IndexingContext::indexTagDecl(const TagDecl *D,274 ArrayRef<SymbolRelation> Relations) {275 if (!shouldIndex(D))276 return;277 if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalSymbol(D))278 return;279 280 if (handleDecl(D, /*Roles=*/SymbolRoleSet(), Relations)) {281 if (D->isThisDeclarationADefinition()) {282 indexNestedNameSpecifierLoc(D->getQualifierLoc(), D);283 if (auto CXXRD = dyn_cast<CXXRecordDecl>(D)) {284 for (const auto &I : CXXRD->bases()) {285 indexTypeSourceInfo(I.getTypeSourceInfo(), CXXRD, CXXRD, /*isBase=*/true);286 }287 }288 indexDeclContext(D);289 }290 }291}292