Clang Project

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