IndexTypeSourceInfo.cpp 10 KB

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