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