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