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#include "llvm/ADT/ScopeExit.h"
12
13using namespace clang;
14using namespace index;
15
16namespace {
17
18class 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
27public:
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 VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TTPL) {
50    SourceLocation Loc = TTPL.getNameLoc();
51    TemplateTypeParmDecl *TTPD = TTPL.getDecl();
52    return IndexCtx.handleReference(TTPD, Loc, Parent, ParentDC,
53                                    SymbolRoleSet());
54  }
55
56  bool VisitTypedefTypeLoc(TypedefTypeLoc TL) {
57    SourceLocation Loc = TL.getNameLoc();
58    TypedefNameDecl *ND = TL.getTypedefNameDecl();
59    if (ND->isTransparentTag()) {
60      TagDecl *Underlying = ND->getUnderlyingType()->getAsTagDecl();
61      return IndexCtx.handleReference(Underlying, Loc, Parent,
62                                      ParentDC, SymbolRoleSet(), Relations);
63    }
64    if (IsBase) {
65      TRY_TO(IndexCtx.handleReference(ND, Loc,
66                                      Parent, ParentDC, SymbolRoleSet()));
67      if (auto *CD = TL.getType()->getAsCXXRecordDecl()) {
68        TRY_TO(IndexCtx.handleReference(CD, Loc, Parent, ParentDC,
69                                        (unsigned)SymbolRole::Implicit,
70                                        Relations));
71      }
72    } else {
73      TRY_TO(IndexCtx.handleReference(ND, Loc,
74                                      Parent, ParentDC, SymbolRoleSet(),
75                                      Relations));
76    }
77    return true;
78  }
79
80  bool traverseParamVarHelper(ParmVarDecl *D) {
81    TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc()));
82    if (D->getTypeSourceInfo())
83      TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));
84    return true;
85  }
86
87  bool TraverseParmVarDecl(ParmVarDecl *D) {
88    // Avoid visiting default arguments from the definition that were already
89    // visited in the declaration.
90    // FIXME: A free function definition can have default arguments.
91    // Avoiding double visitaiton of default arguments should be handled by the
92    // visitor probably with a bit in the AST to indicate if the attached
93    // default argument was 'inherited' or written in source.
94    if (auto FD = dyn_cast<FunctionDecl>(D->getDeclContext())) {
95      if (FD->isThisDeclarationADefinition()) {
96        return traverseParamVarHelper(D);
97      }
98    }
99
100    return base::TraverseParmVarDecl(D);
101  }
102
103  bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
104    IndexCtx.indexNestedNameSpecifierLoc(NNS, Parent, ParentDC);
105    return true;
106  }
107
108  bool VisitTagTypeLoc(TagTypeLoc TL) {
109    TagDecl *D = TL.getDecl();
110    if (!IndexCtx.shouldIndexFunctionLocalSymbols() &&
111        D->getParentFunctionOrMethod())
112      return true;
113
114    if (TL.isDefinition()) {
115      IndexCtx.indexTagDecl(D);
116      return true;
117    }
118
119    return IndexCtx.handleReference(D, TL.getNameLoc(),
120                                    Parent, ParentDC, SymbolRoleSet(),
121                                    Relations);
122  }
123
124  bool VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
125    return IndexCtx.handleReference(TL.getIFaceDecl(), TL.getNameLoc(),
126                                    Parent, ParentDC, SymbolRoleSet(), Relations);
127  }
128
129  bool VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) {
130    for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) {
131      IndexCtx.handleReference(TL.getProtocol(i), TL.getProtocolLoc(i),
132                               Parent, ParentDC, SymbolRoleSet(), Relations);
133    }
134    return true;
135  }
136
137  void HandleTemplateSpecializationTypeLoc(TemplateName TemplName,
138                                           SourceLocation TemplNameLoc,
139                                           CXXRecordDecl *ResolvedClass,
140                                           bool IsTypeAlias) {
141    // In presence of type aliases, the resolved class was never written in
142    // the code so don't report it.
143    if (!IsTypeAlias && ResolvedClass &&
144        (!ResolvedClass->isImplicit() ||
145         IndexCtx.shouldIndexImplicitInstantiation())) {
146      IndexCtx.handleReference(ResolvedClass, TemplNameLoc, Parent, ParentDC,
147                               SymbolRoleSet(), Relations);
148    } else if (const TemplateDecl *D = TemplName.getAsTemplateDecl()) {
149      IndexCtx.handleReference(D, TemplNameLoc, Parent, ParentDC,
150                               SymbolRoleSet(), Relations);
151    }
152  }
153
154  bool VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) {
155    auto *T = TL.getTypePtr();
156    if (!T)
157      return true;
158    HandleTemplateSpecializationTypeLoc(
159        T->getTemplateName(), TL.getTemplateNameLoc(), T->getAsCXXRecordDecl(),
160        T->isTypeAlias());
161    return true;
162  }
163
164  bool TraverseTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) {
165    if (!WalkUpFromTemplateSpecializationTypeLoc(TL))
166      return false;
167    if (!TraverseTemplateName(TL.getTypePtr()->getTemplateName()))
168      return false;
169
170    // The relations we have to `Parent` do not apply to our template arguments,
171    // so clear them while visiting the args.
172    SmallVector<SymbolRelation, 3> SavedRelations = Relations;
173    Relations.clear();
174    auto ResetSavedRelations =
175        llvm::make_scope_exit([&] { this->Relations = SavedRelations; });
176    for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) {
177      if (!TraverseTemplateArgumentLoc(TL.getArgLoc(I)))
178        return false;
179    }
180
181    return true;
182  }
183
184  bool VisitDeducedTemplateSpecializationTypeLoc(DeducedTemplateSpecializationTypeLoc TL) {
185    auto *T = TL.getTypePtr();
186    if (!T)
187      return true;
188    HandleTemplateSpecializationTypeLoc(
189        T->getTemplateName(), TL.getTemplateNameLoc(), T->getAsCXXRecordDecl(),
190        /*IsTypeAlias=*/false);
191    return true;
192  }
193
194  bool VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) {
195    return IndexCtx.handleReference(TL.getDecl(), TL.getNameLoc(), Parent,
196                                    ParentDC, SymbolRoleSet(), Relations);
197  }
198
199  bool VisitDependentNameTypeLoc(DependentNameTypeLoc TL) {
200    const DependentNameType *DNT = TL.getTypePtr();
201    const NestedNameSpecifier *NNS = DNT->getQualifier();
202    const Type *T = NNS->getAsType();
203    if (!T)
204      return true;
205    const TemplateSpecializationType *TST =
206        T->getAs<TemplateSpecializationType>();
207    if (!TST)
208      return true;
209    TemplateName TN = TST->getTemplateName();
210    const ClassTemplateDecl *TD =
211        dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl());
212    if (!TD)
213      return true;
214    CXXRecordDecl *RD = TD->getTemplatedDecl();
215    if (!RD->hasDefinition())
216      return true;
217    RD = RD->getDefinition();
218    DeclarationName Name(DNT->getIdentifier());
219    std::vector<const NamedDecl *> Symbols = RD->lookupDependentName(
220        Name, [](const NamedDecl *ND) { return isa<TypeDecl>(ND); });
221    if (Symbols.size() != 1)
222      return true;
223    return IndexCtx.handleReference(Symbols[0], TL.getNameLoc(), Parent,
224                                    ParentDC, SymbolRoleSet(), Relations);
225  }
226
227  bool TraverseStmt(Stmt *S) {
228    IndexCtx.indexBody(S, Parent, ParentDC);
229    return true;
230  }
231};
232
233} // anonymous namespace
234
235void IndexingContext::indexTypeSourceInfo(TypeSourceInfo *TInfo,
236                                          const NamedDecl *Parent,
237                                          const DeclContext *DC,
238                                          bool isBase,
239                                          bool isIBType) {
240  if (!TInfo || TInfo->getTypeLoc().isNull())
241    return;
242
243  indexTypeLoc(TInfo->getTypeLoc(), Parent, DC, isBase, isIBType);
244}
245
246void IndexingContext::indexTypeLoc(TypeLoc TL,
247                                   const NamedDecl *Parent,
248                                   const DeclContext *DC,
249                                   bool isBase,
250                                   bool isIBType) {
251  if (TL.isNull())
252    return;
253
254  if (!DC)
255    DC = Parent->getLexicalDeclContext();
256  TypeIndexer(*this, Parent, DC, isBase, isIBType).TraverseTypeLoc(TL);
257}
258
259void IndexingContext::indexNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS,
260                                                  const NamedDecl *Parent,
261                                                  const DeclContext *DC) {
262  if (!NNS)
263    return;
264
265  if (NestedNameSpecifierLoc Prefix = NNS.getPrefix())
266    indexNestedNameSpecifierLoc(Prefix, Parent, DC);
267
268  if (!DC)
269    DC = Parent->getLexicalDeclContext();
270  SourceLocation Loc = NNS.getLocalBeginLoc();
271
272  switch (NNS.getNestedNameSpecifier()->getKind()) {
273  case NestedNameSpecifier::Identifier:
274  case NestedNameSpecifier::Global:
275  case NestedNameSpecifier::Super:
276    break;
277
278  case NestedNameSpecifier::Namespace:
279    handleReference(NNS.getNestedNameSpecifier()->getAsNamespace(),
280                    Loc, Parent, DC, SymbolRoleSet());
281    break;
282  case NestedNameSpecifier::NamespaceAlias:
283    handleReference(NNS.getNestedNameSpecifier()->getAsNamespaceAlias(),
284                    Loc, Parent, DC, SymbolRoleSet());
285    break;
286
287  case NestedNameSpecifier::TypeSpec:
288  case NestedNameSpecifier::TypeSpecWithTemplate:
289    indexTypeLoc(NNS.getTypeLoc(), Parent, DC);
290    break;
291  }
292}
293
294void IndexingContext::indexTagDecl(const TagDecl *D,
295                                   ArrayRef<SymbolRelation> Relations) {
296  if (!shouldIndex(D))
297    return;
298  if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalSymbol(D))
299    return;
300
301  if (handleDecl(D, /*Roles=*/SymbolRoleSet(), Relations)) {
302    if (D->isThisDeclarationADefinition()) {
303      indexNestedNameSpecifierLoc(D->getQualifierLoc(), D);
304      if (auto CXXRD = dyn_cast<CXXRecordDecl>(D)) {
305        for (const auto &I : CXXRD->bases()) {
306          indexTypeSourceInfo(I.getTypeSourceInfo(), CXXRD, CXXRD, /*isBase=*/true);
307        }
308      }
309      indexDeclContext(D);
310    }
311  }
312}
313