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