/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Index/IndexDecl.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===- IndexDecl.cpp - Indexing declarations ------------------------------===// |
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/Attr.h" |
12 | | #include "clang/AST/Decl.h" |
13 | | #include "clang/AST/DeclTemplate.h" |
14 | | #include "clang/AST/DeclVisitor.h" |
15 | | #include "clang/Index/IndexDataConsumer.h" |
16 | | #include "clang/Index/IndexSymbol.h" |
17 | | |
18 | | using namespace clang; |
19 | | using namespace index; |
20 | | |
21 | | #define TRY_DECL(D,CALL_EXPR) \ |
22 | 982 | do { \ |
23 | 982 | if (!IndexCtx.shouldIndex(D)) return true4 ; \ |
24 | 982 | if (978 !CALL_EXPR978 ) \ |
25 | 978 | return false0 ; \ |
26 | 978 | } while (0) |
27 | | |
28 | | #define TRY_TO(CALL_EXPR) \ |
29 | 260 | do { \ |
30 | 260 | if (!CALL_EXPR) \ |
31 | 260 | return false0 ; \ |
32 | 260 | } while (0) |
33 | | |
34 | | namespace { |
35 | | |
36 | | class IndexingDeclVisitor : public ConstDeclVisitor<IndexingDeclVisitor, bool> { |
37 | | IndexingContext &IndexCtx; |
38 | | |
39 | | public: |
40 | | explicit IndexingDeclVisitor(IndexingContext &indexCtx) |
41 | 1.38k | : IndexCtx(indexCtx) { } |
42 | | |
43 | | bool Handled = true; |
44 | | |
45 | 23 | bool VisitDecl(const Decl *D) { |
46 | 23 | Handled = false; |
47 | 23 | return true; |
48 | 23 | } |
49 | | |
50 | | void handleTemplateArgumentLoc(const TemplateArgumentLoc &TALoc, |
51 | | const NamedDecl *Parent, |
52 | 25 | const DeclContext *DC) { |
53 | 25 | const TemplateArgumentLocInfo &LocInfo = TALoc.getLocInfo(); |
54 | 25 | switch (TALoc.getArgument().getKind()) { |
55 | 6 | case TemplateArgument::Expression: |
56 | 6 | IndexCtx.indexBody(LocInfo.getAsExpr(), Parent, DC); |
57 | 6 | break; |
58 | 16 | case TemplateArgument::Type: |
59 | 16 | IndexCtx.indexTypeSourceInfo(LocInfo.getAsTypeSourceInfo(), Parent, DC); |
60 | 16 | break; |
61 | 3 | case TemplateArgument::Template: |
62 | 3 | case TemplateArgument::TemplateExpansion: |
63 | 3 | IndexCtx.indexNestedNameSpecifierLoc(TALoc.getTemplateQualifierLoc(), |
64 | 3 | Parent, DC); |
65 | 3 | if (const TemplateDecl *TD = TALoc.getArgument() |
66 | 3 | .getAsTemplateOrTemplatePattern() |
67 | 3 | .getAsTemplateDecl()) { |
68 | 3 | if (const NamedDecl *TTD = TD->getTemplatedDecl()) |
69 | 3 | IndexCtx.handleReference(TTD, TALoc.getTemplateNameLoc(), Parent, DC); |
70 | 3 | } |
71 | 3 | break; |
72 | 0 | default: |
73 | 0 | break; |
74 | 25 | } |
75 | 25 | } |
76 | | |
77 | | /// Returns true if the given method has been defined explicitly by the |
78 | | /// user. |
79 | | static bool hasUserDefined(const ObjCMethodDecl *D, |
80 | 44 | const ObjCImplDecl *Container) { |
81 | 44 | const ObjCMethodDecl *MD = Container->getMethod(D->getSelector(), |
82 | 44 | D->isInstanceMethod()); |
83 | 44 | return MD && !MD->isImplicit() && MD->isThisDeclarationADefinition()9 && |
84 | 44 | !MD->isSynthesizedAccessorStub()2 ; |
85 | 44 | } |
86 | | |
87 | | |
88 | | void handleDeclarator(const DeclaratorDecl *D, |
89 | | const NamedDecl *Parent = nullptr, |
90 | 537 | bool isIBType = false) { |
91 | 537 | if (!Parent) Parent = D457 ; |
92 | | |
93 | 537 | IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), Parent, |
94 | 537 | Parent->getLexicalDeclContext(), |
95 | 537 | /*isBase=*/false, isIBType); |
96 | 537 | IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent); |
97 | 537 | auto IndexDefaultParmeterArgument = [&](const ParmVarDecl *Parm, |
98 | 537 | const NamedDecl *Parent) { |
99 | 52 | if (Parm->hasDefaultArg() && !Parm->hasUninstantiatedDefaultArg()7 && |
100 | 52 | !Parm->hasUnparsedDefaultArg()7 ) |
101 | 7 | IndexCtx.indexBody(Parm->getDefaultArg(), Parent); |
102 | 52 | }; |
103 | 537 | if (IndexCtx.shouldIndexFunctionLocalSymbols()) { |
104 | 133 | if (const ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D)) { |
105 | 27 | auto *DC = Parm->getDeclContext(); |
106 | 27 | if (auto *FD = dyn_cast<FunctionDecl>(DC)) { |
107 | 0 | if (IndexCtx.shouldIndexParametersInDeclarations() || |
108 | 0 | FD->isThisDeclarationADefinition()) |
109 | 0 | IndexCtx.handleDecl(Parm); |
110 | 27 | } else if (auto *MD = dyn_cast<ObjCMethodDecl>(DC)) { |
111 | 27 | if (MD->isThisDeclarationADefinition()) |
112 | 8 | IndexCtx.handleDecl(Parm); |
113 | 27 | } else { |
114 | 0 | IndexCtx.handleDecl(Parm); |
115 | 0 | } |
116 | 106 | } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { |
117 | 58 | if (IndexCtx.shouldIndexParametersInDeclarations() || |
118 | 58 | FD->isThisDeclarationADefinition()56 ) { |
119 | 37 | for (const auto *PI : FD->parameters()) { |
120 | 13 | IndexDefaultParmeterArgument(PI, D); |
121 | 13 | IndexCtx.handleDecl(PI); |
122 | 13 | } |
123 | 37 | } |
124 | 58 | } |
125 | 404 | } else { |
126 | | // Index the default parameter value for function definitions. |
127 | 404 | if (const auto *FD = dyn_cast<FunctionDecl>(D)) { |
128 | 236 | if (FD->isThisDeclarationADefinition()) { |
129 | 118 | for (const auto *PV : FD->parameters()) { |
130 | 39 | IndexDefaultParmeterArgument(PV, D); |
131 | 39 | } |
132 | 118 | } |
133 | 236 | } |
134 | 404 | } |
135 | 537 | if (auto *C = D->getTrailingRequiresClause()) |
136 | 0 | IndexCtx.indexBody(C, Parent); |
137 | 537 | } |
138 | | |
139 | | bool handleObjCMethod(const ObjCMethodDecl *D, |
140 | 143 | const ObjCPropertyDecl *AssociatedProp = nullptr) { |
141 | 143 | SmallVector<SymbolRelation, 4> Relations; |
142 | 143 | SmallVector<const ObjCMethodDecl*, 4> Overriden; |
143 | | |
144 | 143 | D->getOverriddenMethods(Overriden); |
145 | 143 | for(auto overridden: Overriden) { |
146 | 1 | Relations.emplace_back((unsigned) SymbolRole::RelationOverrideOf, |
147 | 1 | overridden); |
148 | 1 | } |
149 | 143 | if (AssociatedProp) |
150 | 61 | Relations.emplace_back((unsigned)SymbolRole::RelationAccessorOf, |
151 | 61 | AssociatedProp); |
152 | | |
153 | | // getLocation() returns beginning token of a method declaration, but for |
154 | | // indexing purposes we want to point to the base name. |
155 | 143 | SourceLocation MethodLoc = D->getSelectorStartLoc(); |
156 | 143 | if (MethodLoc.isInvalid()) |
157 | 0 | MethodLoc = D->getLocation(); |
158 | | |
159 | 143 | SourceLocation AttrLoc; |
160 | | |
161 | | // check for (getter=/setter=) |
162 | 143 | if (AssociatedProp) { |
163 | 61 | bool isGetter = !D->param_size(); |
164 | 61 | AttrLoc = isGetter ? |
165 | 32 | AssociatedProp->getGetterNameLoc(): |
166 | 61 | AssociatedProp->getSetterNameLoc()29 ; |
167 | 61 | } |
168 | | |
169 | 143 | SymbolRoleSet Roles = (SymbolRoleSet)SymbolRole::Dynamic; |
170 | 143 | if (D->isImplicit()) { |
171 | 50 | if (AttrLoc.isValid()) { |
172 | 4 | MethodLoc = AttrLoc; |
173 | 46 | } else { |
174 | 46 | Roles |= (SymbolRoleSet)SymbolRole::Implicit; |
175 | 46 | } |
176 | 93 | } else if (AttrLoc.isValid()) { |
177 | 2 | IndexCtx.handleReference(D, AttrLoc, cast<NamedDecl>(D->getDeclContext()), |
178 | 2 | D->getDeclContext(), 0); |
179 | 2 | } |
180 | | |
181 | 143 | TRY_DECL(D, IndexCtx.handleDecl(D, MethodLoc, Roles, Relations)); |
182 | 143 | IndexCtx.indexTypeSourceInfo(D->getReturnTypeSourceInfo(), D); |
183 | 143 | bool hasIBActionAndFirst = D->hasAttr<IBActionAttr>(); |
184 | 143 | for (const auto *I : D->parameters()) { |
185 | 80 | handleDeclarator(I, D, /*isIBType=*/hasIBActionAndFirst); |
186 | 80 | hasIBActionAndFirst = false; |
187 | 80 | } |
188 | | |
189 | 143 | if (D->isThisDeclarationADefinition()) { |
190 | 24 | const Stmt *Body = D->getBody(); |
191 | 24 | if (Body) { |
192 | 24 | IndexCtx.indexBody(Body, D, D); |
193 | 24 | } |
194 | 24 | } |
195 | 143 | return true; |
196 | 143 | } |
197 | | |
198 | | /// Gather the declarations which the given declaration \D overrides in a |
199 | | /// pseudo-override manner. |
200 | | /// |
201 | | /// Pseudo-overrides occur when a class template specialization declares |
202 | | /// a declaration that has the same name as a similar declaration in the |
203 | | /// non-specialized template. |
204 | | void |
205 | | gatherTemplatePseudoOverrides(const NamedDecl *D, |
206 | 781 | SmallVectorImpl<SymbolRelation> &Relations) { |
207 | 781 | if (!IndexCtx.getLangOpts().CPlusPlus) |
208 | 144 | return; |
209 | 637 | const auto *CTSD = |
210 | 637 | dyn_cast<ClassTemplateSpecializationDecl>(D->getLexicalDeclContext()); |
211 | 637 | if (!CTSD) |
212 | 596 | return; |
213 | 41 | llvm::PointerUnion<ClassTemplateDecl *, |
214 | 41 | ClassTemplatePartialSpecializationDecl *> |
215 | 41 | Template = CTSD->getSpecializedTemplateOrPartial(); |
216 | 41 | if (const auto *CTD = Template.dyn_cast<ClassTemplateDecl *>()) { |
217 | 41 | const CXXRecordDecl *Pattern = CTD->getTemplatedDecl(); |
218 | 41 | bool TypeOverride = isa<TypeDecl>(D); |
219 | 41 | for (const NamedDecl *ND : Pattern->lookup(D->getDeclName())) { |
220 | 40 | if (const auto *CTD = dyn_cast<ClassTemplateDecl>(ND)) |
221 | 4 | ND = CTD->getTemplatedDecl(); |
222 | 40 | if (ND->isImplicit()) |
223 | 0 | continue; |
224 | | // Types can override other types. |
225 | 40 | if (!TypeOverride) { |
226 | 17 | if (ND->getKind() != D->getKind()) |
227 | 0 | continue; |
228 | 23 | } else if (!isa<TypeDecl>(ND)) |
229 | 0 | continue; |
230 | 40 | if (const auto *FD = dyn_cast<FunctionDecl>(ND)) { |
231 | 13 | const auto *DFD = cast<FunctionDecl>(D); |
232 | | // Function overrides are approximated using the number of parameters. |
233 | 13 | if (FD->getStorageClass() != DFD->getStorageClass() || |
234 | 13 | FD->getNumParams() != DFD->getNumParams()11 ) |
235 | 4 | continue; |
236 | 13 | } |
237 | 36 | Relations.emplace_back( |
238 | 36 | SymbolRoleSet(SymbolRole::RelationSpecializationOf), ND); |
239 | 36 | } |
240 | 41 | } |
241 | 41 | } |
242 | | |
243 | 295 | bool VisitFunctionDecl(const FunctionDecl *D) { |
244 | 295 | SymbolRoleSet Roles{}; |
245 | 295 | SmallVector<SymbolRelation, 4> Relations; |
246 | 295 | if (auto *CXXMD = dyn_cast<CXXMethodDecl>(D)) { |
247 | 113 | if (CXXMD->isVirtual()) |
248 | 2 | Roles |= (unsigned)SymbolRole::Dynamic; |
249 | 113 | for (const CXXMethodDecl *O : CXXMD->overridden_methods()) { |
250 | 1 | Relations.emplace_back((unsigned)SymbolRole::RelationOverrideOf, O); |
251 | 1 | } |
252 | 113 | } |
253 | 295 | gatherTemplatePseudoOverrides(D, Relations); |
254 | 295 | if (const auto *Base = D->getPrimaryTemplate()) |
255 | 12 | Relations.push_back( |
256 | 12 | SymbolRelation(SymbolRoleSet(SymbolRole::RelationSpecializationOf), |
257 | 12 | Base->getTemplatedDecl())); |
258 | | |
259 | 295 | TRY_DECL(D, IndexCtx.handleDecl(D, Roles, Relations)); |
260 | 294 | handleDeclarator(D); |
261 | | |
262 | 294 | if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) { |
263 | 25 | IndexCtx.handleReference(Ctor->getParent(), Ctor->getLocation(), |
264 | 25 | Ctor->getParent(), Ctor->getDeclContext(), |
265 | 25 | (unsigned)SymbolRole::NameReference); |
266 | | |
267 | | // Constructor initializers. |
268 | 25 | for (const auto *Init : Ctor->inits()) { |
269 | 4 | if (Init->isWritten()) { |
270 | 4 | IndexCtx.indexTypeSourceInfo(Init->getTypeSourceInfo(), D); |
271 | 4 | if (const FieldDecl *Member = Init->getAnyMember()) |
272 | 4 | IndexCtx.handleReference(Member, Init->getMemberLocation(), D, D, |
273 | 4 | (unsigned)SymbolRole::Write); |
274 | 4 | IndexCtx.indexBody(Init->getInit(), D, D); |
275 | 4 | } |
276 | 4 | } |
277 | 269 | } else if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(D)) { |
278 | 8 | if (auto TypeNameInfo = Dtor->getNameInfo().getNamedTypeInfo()) { |
279 | 8 | IndexCtx.handleReference(Dtor->getParent(), |
280 | 8 | TypeNameInfo->getTypeLoc().getBeginLoc(), |
281 | 8 | Dtor->getParent(), Dtor->getDeclContext(), |
282 | 8 | (unsigned)SymbolRole::NameReference); |
283 | 8 | } |
284 | 261 | } else if (const auto *Guide = dyn_cast<CXXDeductionGuideDecl>(D)) { |
285 | 2 | IndexCtx.handleReference(Guide->getDeducedTemplate()->getTemplatedDecl(), |
286 | 2 | Guide->getLocation(), Guide, |
287 | 2 | Guide->getDeclContext()); |
288 | 2 | } |
289 | | // Template specialization arguments. |
290 | 294 | if (const ASTTemplateArgumentListInfo *TemplateArgInfo = |
291 | 294 | D->getTemplateSpecializationArgsAsWritten()) { |
292 | 12 | for (const auto &Arg : TemplateArgInfo->arguments()) |
293 | 22 | handleTemplateArgumentLoc(Arg, D, D->getLexicalDeclContext()); |
294 | 12 | } |
295 | | |
296 | 294 | if (D->isThisDeclarationADefinition()) { |
297 | 154 | const Stmt *Body = D->getBody(); |
298 | 154 | if (Body) { |
299 | 135 | IndexCtx.indexBody(Body, D, D); |
300 | 135 | } |
301 | 154 | } |
302 | 294 | return true; |
303 | 295 | } |
304 | | |
305 | 109 | bool VisitVarDecl(const VarDecl *D) { |
306 | 109 | SmallVector<SymbolRelation, 4> Relations; |
307 | 109 | gatherTemplatePseudoOverrides(D, Relations); |
308 | 109 | TRY_DECL(D, IndexCtx.handleDecl(D, SymbolRoleSet(), Relations)); |
309 | 109 | handleDeclarator(D); |
310 | 109 | IndexCtx.indexBody(D->getInit(), D); |
311 | 109 | return true; |
312 | 109 | } |
313 | | |
314 | 4 | bool VisitDecompositionDecl(const DecompositionDecl *D) { |
315 | 4 | for (const auto *Binding : D->bindings()) |
316 | 6 | TRY_DECL(Binding, IndexCtx.handleDecl(Binding)); |
317 | 4 | return Base::VisitDecompositionDecl(D); |
318 | 4 | } |
319 | | |
320 | 51 | bool VisitFieldDecl(const FieldDecl *D) { |
321 | 51 | SmallVector<SymbolRelation, 4> Relations; |
322 | 51 | gatherTemplatePseudoOverrides(D, Relations); |
323 | 51 | TRY_DECL(D, IndexCtx.handleDecl(D, SymbolRoleSet(), Relations)); |
324 | 51 | handleDeclarator(D); |
325 | 51 | if (D->isBitField()) |
326 | 0 | IndexCtx.indexBody(D->getBitWidth(), D); |
327 | 51 | else if (D->hasInClassInitializer()) |
328 | 8 | IndexCtx.indexBody(D->getInClassInitializer(), D); |
329 | 51 | return true; |
330 | 51 | } |
331 | | |
332 | 22 | bool VisitObjCIvarDecl(const ObjCIvarDecl *D) { |
333 | 22 | if (D->getSynthesize()) { |
334 | | // handled in VisitObjCPropertyImplDecl |
335 | 20 | return true; |
336 | 20 | } |
337 | 2 | TRY_DECL(D, IndexCtx.handleDecl(D)); |
338 | 2 | handleDeclarator(D); |
339 | 2 | return true; |
340 | 2 | } |
341 | | |
342 | 1 | bool VisitMSPropertyDecl(const MSPropertyDecl *D) { |
343 | 1 | TRY_DECL(D, IndexCtx.handleDecl(D)); |
344 | 1 | handleDeclarator(D); |
345 | 1 | return true; |
346 | 1 | } |
347 | | |
348 | 28 | bool VisitEnumConstantDecl(const EnumConstantDecl *D) { |
349 | 28 | TRY_DECL(D, IndexCtx.handleDecl(D)); |
350 | 28 | IndexCtx.indexBody(D->getInitExpr(), D); |
351 | 28 | return true; |
352 | 28 | } |
353 | | |
354 | 135 | bool VisitTypedefNameDecl(const TypedefNameDecl *D) { |
355 | 135 | if (!D->isTransparentTag()) { |
356 | 130 | SmallVector<SymbolRelation, 4> Relations; |
357 | 130 | gatherTemplatePseudoOverrides(D, Relations); |
358 | 130 | TRY_DECL(D, IndexCtx.handleDecl(D, SymbolRoleSet(), Relations)); |
359 | 130 | IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D); |
360 | 130 | } |
361 | 135 | return true; |
362 | 135 | } |
363 | | |
364 | 207 | bool VisitTagDecl(const TagDecl *D) { |
365 | | // Non-free standing tags are handled in indexTypeSourceInfo. |
366 | 207 | if (D->isFreeStanding()) { |
367 | 196 | if (D->isThisDeclarationADefinition()) { |
368 | 183 | SmallVector<SymbolRelation, 4> Relations; |
369 | 183 | gatherTemplatePseudoOverrides(D, Relations); |
370 | 183 | IndexCtx.indexTagDecl(D, Relations); |
371 | 183 | } else { |
372 | 13 | SmallVector<SymbolRelation, 1> Relations; |
373 | 13 | gatherTemplatePseudoOverrides(D, Relations); |
374 | 13 | return IndexCtx.handleDecl(D, D->getLocation(), SymbolRoleSet(), |
375 | 13 | Relations, D->getLexicalDeclContext()); |
376 | 13 | } |
377 | 196 | } |
378 | 194 | return true; |
379 | 207 | } |
380 | | |
381 | 24 | bool VisitEnumDecl(const EnumDecl *ED) { |
382 | 24 | TRY_TO(VisitTagDecl(ED)); |
383 | | // Indexing for enumdecl itself is handled inside TagDecl, we just want to |
384 | | // visit integer-base here, which is different than other TagDecl bases. |
385 | 24 | if (auto *TSI = ED->getIntegerTypeSourceInfo()) |
386 | 8 | IndexCtx.indexTypeSourceInfo(TSI, ED, ED, /*isBase=*/true); |
387 | 24 | return true; |
388 | 24 | } |
389 | | |
390 | | bool handleReferencedProtocols(const ObjCProtocolList &ProtList, |
391 | | const ObjCContainerDecl *ContD, |
392 | 87 | SourceLocation SuperLoc) { |
393 | 87 | ObjCInterfaceDecl::protocol_loc_iterator LI = ProtList.loc_begin(); |
394 | 87 | for (ObjCInterfaceDecl::protocol_iterator |
395 | 106 | I = ProtList.begin(), E = ProtList.end(); I != E; ++I, ++LI19 ) { |
396 | 19 | SourceLocation Loc = *LI; |
397 | 19 | ObjCProtocolDecl *PD = *I; |
398 | 19 | SymbolRoleSet roles{}; |
399 | 19 | if (Loc == SuperLoc) |
400 | 4 | roles |= (SymbolRoleSet)SymbolRole::Implicit; |
401 | 19 | TRY_TO(IndexCtx.handleReference(PD, Loc, ContD, ContD, roles, |
402 | 19 | SymbolRelation{(unsigned)SymbolRole::RelationBaseOf, ContD})); |
403 | 19 | } |
404 | 87 | return true; |
405 | 87 | } |
406 | | |
407 | 75 | bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) { |
408 | 75 | if (D->isThisDeclarationADefinition()) { |
409 | 64 | TRY_DECL(D, IndexCtx.handleDecl(D)); |
410 | 62 | SourceLocation SuperLoc = D->getSuperClassLoc(); |
411 | 62 | if (auto *SuperD = D->getSuperClass()) { |
412 | 16 | bool hasSuperTypedef = false; |
413 | 16 | if (auto *TInfo = D->getSuperClassTInfo()) { |
414 | 16 | if (auto *TT = TInfo->getType()->getAs<TypedefType>()) { |
415 | 4 | if (auto *TD = TT->getDecl()) { |
416 | 4 | hasSuperTypedef = true; |
417 | 4 | TRY_TO(IndexCtx.handleReference(TD, SuperLoc, D, D, |
418 | 4 | SymbolRoleSet())); |
419 | 4 | } |
420 | 4 | } |
421 | 16 | } |
422 | 16 | SymbolRoleSet superRoles{}; |
423 | 16 | if (hasSuperTypedef) |
424 | 4 | superRoles |= (SymbolRoleSet)SymbolRole::Implicit; |
425 | 16 | TRY_TO(IndexCtx.handleReference(SuperD, SuperLoc, D, D, superRoles, |
426 | 16 | SymbolRelation{(unsigned)SymbolRole::RelationBaseOf, D})); |
427 | 16 | } |
428 | 62 | TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D, |
429 | 62 | SuperLoc)); |
430 | 62 | TRY_TO(IndexCtx.indexDeclContext(D)); |
431 | 62 | } else { |
432 | 11 | return IndexCtx.handleReference(D, D->getLocation(), nullptr, |
433 | 11 | D->getDeclContext(), SymbolRoleSet()); |
434 | 11 | } |
435 | 62 | return true; |
436 | 75 | } |
437 | | |
438 | 19 | bool VisitObjCProtocolDecl(const ObjCProtocolDecl *D) { |
439 | 19 | if (D->isThisDeclarationADefinition()) { |
440 | 16 | TRY_DECL(D, IndexCtx.handleDecl(D)); |
441 | 15 | TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D, |
442 | 15 | /*SuperLoc=*/SourceLocation())); |
443 | 15 | TRY_TO(IndexCtx.indexDeclContext(D)); |
444 | 15 | } else { |
445 | 3 | return IndexCtx.handleReference(D, D->getLocation(), nullptr, |
446 | 3 | D->getDeclContext(), SymbolRoleSet()); |
447 | 3 | } |
448 | 15 | return true; |
449 | 19 | } |
450 | | |
451 | 20 | bool VisitObjCImplementationDecl(const ObjCImplementationDecl *D) { |
452 | 20 | const ObjCInterfaceDecl *Class = D->getClassInterface(); |
453 | 20 | if (!Class) |
454 | 0 | return true; |
455 | | |
456 | 20 | if (Class->isImplicitInterfaceDecl()) |
457 | 0 | IndexCtx.handleDecl(Class); |
458 | | |
459 | 20 | TRY_DECL(D, IndexCtx.handleDecl(D)); |
460 | | |
461 | | // Visit implicit @synthesize property implementations first as their |
462 | | // location is reported at the name of the @implementation block. This |
463 | | // serves no purpose other than to simplify the FileCheck-based tests. |
464 | 22 | for (const auto *I : D->property_impls())20 { |
465 | 22 | if (I->getLocation().isInvalid()) |
466 | 10 | IndexCtx.indexDecl(I); |
467 | 22 | } |
468 | 109 | for (const auto *I : D->decls()) { |
469 | 109 | if (!isa<ObjCPropertyImplDecl>(I) || |
470 | 109 | cast<ObjCPropertyImplDecl>(I)->getLocation().isValid()22 ) |
471 | 99 | IndexCtx.indexDecl(I); |
472 | 109 | } |
473 | | |
474 | 20 | return true; |
475 | 20 | } |
476 | | |
477 | 14 | bool VisitObjCCategoryDecl(const ObjCCategoryDecl *D) { |
478 | 14 | if (!IndexCtx.shouldIndex(D)) |
479 | 2 | return true; |
480 | 12 | const ObjCInterfaceDecl *C = D->getClassInterface(); |
481 | 12 | if (!C) |
482 | 2 | return true; |
483 | 10 | TRY_TO(IndexCtx.handleReference(C, D->getLocation(), D, D, SymbolRoleSet(), |
484 | 10 | SymbolRelation{ |
485 | 10 | (unsigned)SymbolRole::RelationExtendedBy, D |
486 | 10 | })); |
487 | 10 | SourceLocation CategoryLoc = D->getCategoryNameLoc(); |
488 | 10 | if (!CategoryLoc.isValid()) |
489 | 1 | CategoryLoc = D->getLocation(); |
490 | 10 | TRY_TO(IndexCtx.handleDecl(D, CategoryLoc)); |
491 | 10 | TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D, |
492 | 10 | /*SuperLoc=*/SourceLocation())); |
493 | 10 | TRY_TO(IndexCtx.indexDeclContext(D)); |
494 | 10 | return true; |
495 | 10 | } |
496 | | |
497 | 3 | bool VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D) { |
498 | 3 | const ObjCCategoryDecl *Cat = D->getCategoryDecl(); |
499 | 3 | if (!Cat) |
500 | 0 | return true; |
501 | 3 | const ObjCInterfaceDecl *C = D->getClassInterface(); |
502 | 3 | if (C) |
503 | 3 | TRY_TO(IndexCtx.handleReference(C, D->getLocation(), D, D, |
504 | 3 | SymbolRoleSet())); |
505 | 3 | SourceLocation CategoryLoc = D->getCategoryNameLoc(); |
506 | 3 | if (!CategoryLoc.isValid()) |
507 | 0 | CategoryLoc = D->getLocation(); |
508 | 3 | TRY_DECL(D, IndexCtx.handleDecl(D, CategoryLoc)); |
509 | 3 | IndexCtx.indexDeclContext(D); |
510 | 3 | return true; |
511 | 3 | } |
512 | | |
513 | 185 | bool VisitObjCMethodDecl(const ObjCMethodDecl *D) { |
514 | | // Methods associated with a property, even user-declared ones, are |
515 | | // handled when we handle the property. |
516 | 185 | if (D->isPropertyAccessor()) |
517 | 103 | return true; |
518 | | |
519 | 82 | handleObjCMethod(D); |
520 | 82 | return true; |
521 | 185 | } |
522 | | |
523 | 33 | bool VisitObjCPropertyDecl(const ObjCPropertyDecl *D) { |
524 | 33 | if (ObjCMethodDecl *MD = D->getGetterMethodDecl()) |
525 | 33 | if (MD->getLexicalDeclContext() == D->getLexicalDeclContext()) |
526 | 32 | handleObjCMethod(MD, D); |
527 | 33 | if (ObjCMethodDecl *MD = D->getSetterMethodDecl()) |
528 | 29 | if (MD->getLexicalDeclContext() == D->getLexicalDeclContext()) |
529 | 29 | handleObjCMethod(MD, D); |
530 | 33 | TRY_DECL(D, IndexCtx.handleDecl(D)); |
531 | 33 | if (IBOutletCollectionAttr *attr = D->getAttr<IBOutletCollectionAttr>()) |
532 | 4 | IndexCtx.indexTypeSourceInfo(attr->getInterfaceLoc(), D, |
533 | 4 | D->getLexicalDeclContext(), false, true); |
534 | 33 | IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D); |
535 | 33 | return true; |
536 | 33 | } |
537 | | |
538 | 22 | bool VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) { |
539 | 22 | ObjCPropertyDecl *PD = D->getPropertyDecl(); |
540 | 22 | auto *Container = cast<ObjCImplDecl>(D->getDeclContext()); |
541 | 22 | SourceLocation Loc = D->getLocation(); |
542 | 22 | SymbolRoleSet Roles = 0; |
543 | 22 | SmallVector<SymbolRelation, 1> Relations; |
544 | | |
545 | 22 | if (ObjCIvarDecl *ID = D->getPropertyIvarDecl()) |
546 | 22 | Relations.push_back({(SymbolRoleSet)SymbolRole::RelationAccessorOf, ID}); |
547 | 22 | if (Loc.isInvalid()) { |
548 | 10 | Loc = Container->getLocation(); |
549 | 10 | Roles |= (SymbolRoleSet)SymbolRole::Implicit; |
550 | 10 | } |
551 | 22 | TRY_DECL(D, IndexCtx.handleDecl(D, Loc, Roles, Relations)); |
552 | | |
553 | 22 | if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) |
554 | 0 | return true; |
555 | | |
556 | 22 | assert(D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize); |
557 | 22 | SymbolRoleSet AccessorMethodRoles = |
558 | 22 | SymbolRoleSet(SymbolRole::Dynamic) | SymbolRoleSet(SymbolRole::Implicit); |
559 | 22 | if (ObjCMethodDecl *MD = PD->getGetterMethodDecl()) { |
560 | 22 | if (MD->isPropertyAccessor() && !hasUserDefined(MD, Container)) |
561 | 21 | IndexCtx.handleDecl(MD, Loc, AccessorMethodRoles, {}, Container); |
562 | 22 | } |
563 | 22 | if (ObjCMethodDecl *MD = PD->getSetterMethodDecl()) { |
564 | 22 | if (MD->isPropertyAccessor() && !hasUserDefined(MD, Container)) |
565 | 21 | IndexCtx.handleDecl(MD, Loc, AccessorMethodRoles, {}, Container); |
566 | 22 | } |
567 | 22 | if (ObjCIvarDecl *IvarD = D->getPropertyIvarDecl()) { |
568 | 22 | if (IvarD->getSynthesize()) { |
569 | | // For synthesized ivars, use the location of its name in the |
570 | | // corresponding @synthesize. If there isn't one, use the containing |
571 | | // @implementation's location, rather than the property's location, |
572 | | // otherwise the header file containing the @interface will have different |
573 | | // indexing contents based on whether the @implementation was present or |
574 | | // not in the translation unit. |
575 | 20 | SymbolRoleSet IvarRoles = 0; |
576 | 20 | SourceLocation IvarLoc = D->getPropertyIvarDeclLoc(); |
577 | 20 | if (D->getLocation().isInvalid()) { |
578 | 10 | IvarLoc = Container->getLocation(); |
579 | 10 | IvarRoles = (SymbolRoleSet)SymbolRole::Implicit; |
580 | 10 | } else if (D->getLocation() == IvarLoc) { |
581 | 2 | IvarRoles = (SymbolRoleSet)SymbolRole::Implicit; |
582 | 2 | } |
583 | 20 | TRY_DECL(IvarD, IndexCtx.handleDecl(IvarD, IvarLoc, IvarRoles)); |
584 | 20 | } else { |
585 | 2 | IndexCtx.handleReference(IvarD, D->getPropertyIvarDeclLoc(), nullptr, |
586 | 2 | D->getDeclContext(), SymbolRoleSet()); |
587 | 2 | } |
588 | 22 | } |
589 | 22 | return true; |
590 | 22 | } |
591 | | |
592 | 29 | bool VisitNamespaceDecl(const NamespaceDecl *D) { |
593 | 29 | TRY_DECL(D, IndexCtx.handleDecl(D)); |
594 | 29 | IndexCtx.indexDeclContext(D); |
595 | 29 | return true; |
596 | 29 | } |
597 | | |
598 | 4 | bool VisitNamespaceAliasDecl(const NamespaceAliasDecl *D) { |
599 | 4 | TRY_DECL(D, IndexCtx.handleDecl(D)); |
600 | 4 | IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), D); |
601 | 4 | IndexCtx.handleReference(D->getAliasedNamespace(), D->getTargetNameLoc(), D, |
602 | 4 | D->getLexicalDeclContext()); |
603 | 4 | return true; |
604 | 4 | } |
605 | | |
606 | 3 | bool VisitUsingDecl(const UsingDecl *D) { |
607 | 3 | IndexCtx.handleDecl(D); |
608 | | |
609 | 3 | const DeclContext *DC = D->getDeclContext()->getRedeclContext(); |
610 | 3 | const NamedDecl *Parent = dyn_cast<NamedDecl>(DC); |
611 | 3 | IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent, |
612 | 3 | D->getLexicalDeclContext()); |
613 | 3 | for (const auto *I : D->shadows()) { |
614 | | // Skip unresolved using decls - we already have a decl for the using |
615 | | // itself, so there's not much point adding another decl or reference to |
616 | | // refer to the same location. |
617 | 3 | if (isa<UnresolvedUsingIfExistsDecl>(I->getUnderlyingDecl())) |
618 | 1 | continue; |
619 | | |
620 | 2 | IndexCtx.handleReference(I->getUnderlyingDecl(), D->getLocation(), Parent, |
621 | 2 | D->getLexicalDeclContext(), SymbolRoleSet()); |
622 | 2 | } |
623 | 3 | return true; |
624 | 3 | } |
625 | | |
626 | 6 | bool VisitUsingDirectiveDecl(const UsingDirectiveDecl *D) { |
627 | 6 | const DeclContext *DC = D->getDeclContext()->getRedeclContext(); |
628 | 6 | const NamedDecl *Parent = dyn_cast<NamedDecl>(DC); |
629 | | |
630 | | // NNS for the local 'using namespace' directives is visited by the body |
631 | | // visitor. |
632 | 6 | if (!D->getParentFunctionOrMethod()) |
633 | 2 | IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent, |
634 | 2 | D->getLexicalDeclContext()); |
635 | | |
636 | 6 | return IndexCtx.handleReference(D->getNominatedNamespaceAsWritten(), |
637 | 6 | D->getLocation(), Parent, |
638 | 6 | D->getLexicalDeclContext(), |
639 | 6 | SymbolRoleSet()); |
640 | 6 | } |
641 | | |
642 | 5 | bool VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D) { |
643 | 5 | TRY_DECL(D, IndexCtx.handleDecl(D)); |
644 | 5 | const DeclContext *DC = D->getDeclContext()->getRedeclContext(); |
645 | 5 | const NamedDecl *Parent = dyn_cast<NamedDecl>(DC); |
646 | 5 | IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent, |
647 | 5 | D->getLexicalDeclContext()); |
648 | 5 | return true; |
649 | 5 | } |
650 | | |
651 | 1 | bool VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenameDecl *D) { |
652 | 1 | TRY_DECL(D, IndexCtx.handleDecl(D)); |
653 | 1 | const DeclContext *DC = D->getDeclContext()->getRedeclContext(); |
654 | 1 | const NamedDecl *Parent = dyn_cast<NamedDecl>(DC); |
655 | 1 | IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent, |
656 | 1 | D->getLexicalDeclContext()); |
657 | 1 | return true; |
658 | 1 | } |
659 | | |
660 | | bool VisitClassTemplateSpecializationDecl(const |
661 | 41 | ClassTemplateSpecializationDecl *D) { |
662 | | // FIXME: Notify subsequent callbacks if info comes from implicit |
663 | | // instantiation. |
664 | 41 | llvm::PointerUnion<ClassTemplateDecl *, |
665 | 41 | ClassTemplatePartialSpecializationDecl *> |
666 | 41 | Template = D->getSpecializedTemplateOrPartial(); |
667 | 41 | const Decl *SpecializationOf = |
668 | 41 | Template.is<ClassTemplateDecl *>() |
669 | 41 | ? (Decl *)Template.get<ClassTemplateDecl *>() |
670 | 41 | : Template.get<ClassTemplatePartialSpecializationDecl *>()0 ; |
671 | 41 | if (!D->isThisDeclarationADefinition()) |
672 | 7 | IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), D); |
673 | 41 | IndexCtx.indexTagDecl( |
674 | 41 | D, SymbolRelation(SymbolRoleSet(SymbolRole::RelationSpecializationOf), |
675 | 41 | SpecializationOf)); |
676 | 41 | if (TypeSourceInfo *TSI = D->getTypeAsWritten()) |
677 | 41 | IndexCtx.indexTypeSourceInfo(TSI, /*Parent=*/nullptr, |
678 | 41 | D->getLexicalDeclContext()); |
679 | 41 | return true; |
680 | 41 | } |
681 | | |
682 | 126 | static bool shouldIndexTemplateParameterDefaultValue(const NamedDecl *D) { |
683 | | // We want to index the template parameters only once when indexing the |
684 | | // canonical declaration. |
685 | 126 | if (!D) |
686 | 0 | return false; |
687 | 126 | if (const auto *FD = dyn_cast<FunctionDecl>(D)) |
688 | 30 | return FD->getCanonicalDecl() == FD; |
689 | 96 | else if (const auto *TD = dyn_cast<TagDecl>(D)) |
690 | 86 | return TD->getCanonicalDecl() == TD; |
691 | 10 | else if (const auto *VD = dyn_cast<VarDecl>(D)) |
692 | 6 | return VD->getCanonicalDecl() == VD; |
693 | 4 | return true; |
694 | 126 | } |
695 | | |
696 | | void indexTemplateParameters(TemplateParameterList *Params, |
697 | 110 | const NamedDecl *Parent) { |
698 | 153 | for (const NamedDecl *TP : *Params) { |
699 | 153 | if (IndexCtx.shouldIndexTemplateParameters()) |
700 | 4 | IndexCtx.handleDecl(TP); |
701 | 153 | if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(TP)) { |
702 | 127 | if (TTP->hasDefaultArgument()) |
703 | 12 | IndexCtx.indexTypeSourceInfo(TTP->getDefaultArgumentInfo(), Parent); |
704 | 127 | if (auto *C = TTP->getTypeConstraint()) |
705 | 1 | IndexCtx.handleReference(C->getNamedConcept(), C->getConceptNameLoc(), |
706 | 1 | Parent, TTP->getLexicalDeclContext()); |
707 | 127 | } else if (const auto *26 NTTP26 = dyn_cast<NonTypeTemplateParmDecl>(TP)) { |
708 | 14 | IndexCtx.indexTypeSourceInfo(NTTP->getTypeSourceInfo(), Parent); |
709 | 14 | if (NTTP->hasDefaultArgument()) |
710 | 5 | IndexCtx.indexBody(NTTP->getDefaultArgument(), Parent); |
711 | 14 | } else if (const auto *12 TTPD12 = dyn_cast<TemplateTemplateParmDecl>(TP)) { |
712 | 12 | if (TTPD->hasDefaultArgument()) |
713 | 3 | handleTemplateArgumentLoc(TTPD->getDefaultArgument(), Parent, |
714 | 3 | TP->getLexicalDeclContext()); |
715 | 12 | } |
716 | 153 | } |
717 | 110 | if (auto *R = Params->getRequiresClause()) |
718 | 0 | IndexCtx.indexBody(R, Parent); |
719 | 110 | } |
720 | | |
721 | 126 | bool VisitTemplateDecl(const TemplateDecl *D) { |
722 | 126 | const NamedDecl *Parent = D->getTemplatedDecl(); |
723 | 126 | if (!Parent) |
724 | 0 | return true; |
725 | | |
726 | | // Index the default values for the template parameters. |
727 | 126 | auto *Params = D->getTemplateParameters(); |
728 | 126 | if (Params && shouldIndexTemplateParameterDefaultValue(Parent)) { |
729 | 109 | indexTemplateParameters(Params, Parent); |
730 | 109 | } |
731 | | |
732 | 126 | return Visit(Parent); |
733 | 126 | } |
734 | | |
735 | 1 | bool VisitConceptDecl(const ConceptDecl *D) { |
736 | 1 | if (auto *Params = D->getTemplateParameters()) |
737 | 1 | indexTemplateParameters(Params, D); |
738 | 1 | if (auto *E = D->getConstraintExpr()) |
739 | 1 | IndexCtx.indexBody(E, D); |
740 | 1 | return IndexCtx.handleDecl(D); |
741 | 1 | } |
742 | | |
743 | 0 | bool VisitFriendDecl(const FriendDecl *D) { |
744 | 0 | if (auto ND = D->getFriendDecl()) { |
745 | | // FIXME: Ignore a class template in a dependent context, these are not |
746 | | // linked properly with their redeclarations, ending up with duplicate |
747 | | // USRs. |
748 | | // See comment "Friend templates are visible in fairly strange ways." in |
749 | | // SemaTemplate.cpp which precedes code that prevents the friend template |
750 | | // from becoming visible from the enclosing context. |
751 | 0 | if (isa<ClassTemplateDecl>(ND) && D->getDeclContext()->isDependentContext()) |
752 | 0 | return true; |
753 | 0 | return Visit(ND); |
754 | 0 | } |
755 | 0 | if (auto Ty = D->getFriendType()) { |
756 | 0 | IndexCtx.indexTypeSourceInfo(Ty, cast<NamedDecl>(D->getDeclContext())); |
757 | 0 | } |
758 | 0 | return true; |
759 | 0 | } |
760 | | |
761 | 50 | bool VisitImportDecl(const ImportDecl *D) { |
762 | 50 | return IndexCtx.importedModule(D); |
763 | 50 | } |
764 | | |
765 | 3 | bool VisitStaticAssertDecl(const StaticAssertDecl *D) { |
766 | 3 | IndexCtx.indexBody(D->getAssertExpr(), |
767 | 3 | dyn_cast<NamedDecl>(D->getDeclContext()), |
768 | 3 | D->getLexicalDeclContext()); |
769 | 3 | return true; |
770 | 3 | } |
771 | | }; |
772 | | |
773 | | } // anonymous namespace |
774 | | |
775 | 1.64k | bool IndexingContext::indexDecl(const Decl *D) { |
776 | 1.64k | if (D->isImplicit() && shouldIgnoreIfImplicit(D)383 ) |
777 | 258 | return true; |
778 | | |
779 | 1.39k | if (isTemplateImplicitInstantiation(D) && !shouldIndexImplicitInstantiation()7 ) |
780 | 6 | return true; |
781 | | |
782 | 1.38k | IndexingDeclVisitor Visitor(*this); |
783 | 1.38k | bool ShouldContinue = Visitor.Visit(D); |
784 | 1.38k | if (!ShouldContinue) |
785 | 0 | return false; |
786 | | |
787 | 1.38k | if (!Visitor.Handled && isa<DeclContext>(D)23 ) |
788 | 5 | return indexDeclContext(cast<DeclContext>(D)); |
789 | | |
790 | 1.38k | return true; |
791 | 1.38k | } |
792 | | |
793 | 342 | bool IndexingContext::indexDeclContext(const DeclContext *DC) { |
794 | 342 | for (const auto *I : DC->decls()) |
795 | 771 | if (!indexDecl(I)) |
796 | 0 | return false; |
797 | 342 | return true; |
798 | 342 | } |
799 | | |
800 | 883 | bool IndexingContext::indexTopLevelDecl(const Decl *D) { |
801 | 883 | if (!D || D->getLocation().isInvalid()) |
802 | 90 | return true; |
803 | | |
804 | 793 | if (isa<ObjCMethodDecl>(D)) |
805 | 24 | return true; // Wait for the objc container. |
806 | | |
807 | 769 | if (IndexOpts.ShouldTraverseDecl && !IndexOpts.ShouldTraverseDecl(D)0 ) |
808 | 0 | return true; // skip |
809 | | |
810 | 769 | return indexDecl(D); |
811 | 769 | } |
812 | | |
813 | 651 | bool IndexingContext::indexDeclGroupRef(DeclGroupRef DG) { |
814 | 1.34k | for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I689 ) |
815 | 689 | if (!indexTopLevelDecl(*I)) |
816 | 0 | return false; |
817 | 651 | return true; |
818 | 651 | } |