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