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