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