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