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) 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 } 36 37 bool shouldWalkTypesOfTypeLocs() const { return false; } 38 39 bool VisitTypedefTypeLoc(TypedefTypeLoc TL) { 40 return IndexCtx.handleReference(TL.getTypedefNameDecl(), TL.getNameLoc(), 41 Parent, ParentDC, SymbolRoleSet(), 42 Relations); 43 } 44 45 #define TRY_TO(CALL_EXPR) \ 46 do { \ 47 if (!CALL_EXPR) \ 48 return false; \ 49 } while (0) 50 51 bool traverseParamVarHelper(ParmVarDecl *D) { 52 TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc())); 53 if (D->getTypeSourceInfo()) 54 TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc())); 55 return true; 56 } 57 58 bool TraverseParmVarDecl(ParmVarDecl *D) { 59 // Avoid visiting default arguments from the definition that were already 60 // visited in the declaration. 61 // FIXME: A free function definition can have default arguments. 62 // Avoiding double visitaiton of default arguments should be handled by the 63 // visitor probably with a bit in the AST to indicate if the attached 64 // default argument was 'inherited' or written in source. 65 if (auto FD = dyn_cast<FunctionDecl>(D->getDeclContext())) { 66 if (FD->isThisDeclarationADefinition()) { 67 return traverseParamVarHelper(D); 68 } 69 } 70 71 return base::TraverseParmVarDecl(D); 72 } 73 74 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) { 75 IndexCtx.indexNestedNameSpecifierLoc(NNS, Parent, ParentDC); 76 return true; 77 } 78 79 bool VisitTagTypeLoc(TagTypeLoc TL) { 80 TagDecl *D = TL.getDecl(); 81 if (D->getParentFunctionOrMethod()) 82 return true; 83 84 if (TL.isDefinition()) { 85 IndexCtx.indexTagDecl(D); 86 return true; 87 } 88 89 return IndexCtx.handleReference(D, TL.getNameLoc(), 90 Parent, ParentDC, SymbolRoleSet(), 91 Relations); 92 } 93 94 bool VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { 95 return IndexCtx.handleReference(TL.getIFaceDecl(), TL.getNameLoc(), 96 Parent, ParentDC, SymbolRoleSet()); 97 } 98 99 bool VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { 100 for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) { 101 IndexCtx.handleReference(TL.getProtocol(i), TL.getProtocolLoc(i), 102 Parent, ParentDC, SymbolRoleSet()); 103 } 104 return true; 105 } 106 107 bool VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) { 108 if (const TemplateSpecializationType *T = TL.getTypePtr()) { 109 if (IndexCtx.shouldIndexImplicitTemplateInsts()) { 110 if (CXXRecordDecl *RD = T->getAsCXXRecordDecl()) 111 IndexCtx.handleReference(RD, TL.getTemplateNameLoc(), 112 Parent, ParentDC, SymbolRoleSet(), Relations); 113 } else { 114 if (const TemplateDecl *D = T->getTemplateName().getAsTemplateDecl()) 115 IndexCtx.handleReference(D, TL.getTemplateNameLoc(), 116 Parent, ParentDC, SymbolRoleSet(), Relations); 117 } 118 } 119 return true; 120 } 121 122 bool TraverseStmt(Stmt *S) { 123 IndexCtx.indexBody(S, Parent, ParentDC); 124 return true; 125 } 126 }; 127 128 } // anonymous namespace 129 130 void IndexingContext::indexTypeSourceInfo(TypeSourceInfo *TInfo, 131 const NamedDecl *Parent, 132 const DeclContext *DC, 133 bool isBase) { 134 if (!TInfo || TInfo->getTypeLoc().isNull()) 135 return; 136 137 indexTypeLoc(TInfo->getTypeLoc(), Parent, DC, isBase); 138 } 139 140 void IndexingContext::indexTypeLoc(TypeLoc TL, 141 const NamedDecl *Parent, 142 const DeclContext *DC, 143 bool isBase) { 144 if (TL.isNull()) 145 return; 146 147 if (!DC) 148 DC = Parent->getLexicalDeclContext(); 149 TypeIndexer(*this, Parent, DC, isBase).TraverseTypeLoc(TL); 150 } 151 152 void IndexingContext::indexNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS, 153 const NamedDecl *Parent, 154 const DeclContext *DC) { 155 if (!NNS) 156 return; 157 158 if (NestedNameSpecifierLoc Prefix = NNS.getPrefix()) 159 indexNestedNameSpecifierLoc(Prefix, Parent, DC); 160 161 if (!DC) 162 DC = Parent->getLexicalDeclContext(); 163 SourceLocation Loc = NNS.getSourceRange().getBegin(); 164 165 switch (NNS.getNestedNameSpecifier()->getKind()) { 166 case NestedNameSpecifier::Identifier: 167 case NestedNameSpecifier::Global: 168 case NestedNameSpecifier::Super: 169 break; 170 171 case NestedNameSpecifier::Namespace: 172 handleReference(NNS.getNestedNameSpecifier()->getAsNamespace(), 173 Loc, Parent, DC, SymbolRoleSet()); 174 break; 175 case NestedNameSpecifier::NamespaceAlias: 176 handleReference(NNS.getNestedNameSpecifier()->getAsNamespaceAlias(), 177 Loc, Parent, DC, SymbolRoleSet()); 178 break; 179 180 case NestedNameSpecifier::TypeSpec: 181 case NestedNameSpecifier::TypeSpecWithTemplate: 182 indexTypeLoc(NNS.getTypeLoc(), Parent, DC); 183 break; 184 } 185 } 186 187 void IndexingContext::indexTagDecl(const TagDecl *D) { 188 if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalDecl(D)) 189 return; 190 191 if (handleDecl(D)) { 192 if (D->isThisDeclarationADefinition()) { 193 indexNestedNameSpecifierLoc(D->getQualifierLoc(), D); 194 if (auto CXXRD = dyn_cast<CXXRecordDecl>(D)) { 195 for (const auto &I : CXXRD->bases()) { 196 indexTypeSourceInfo(I.getTypeSourceInfo(), CXXRD, CXXRD, /*isBase=*/true); 197 } 198 } 199 indexDeclContext(D); 200 } 201 } 202 } 203