[clang] Handle __declspec() attributes in using
[llvm-project.git] / clang / lib / Index / IndexingContext.cpp
blobca8b144a431c0b9dcd2bd9933714aa8a9c0b7702
1 //===- IndexingContext.cpp - Indexing context data ------------------------===//
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 //===----------------------------------------------------------------------===//
9 #include "IndexingContext.h"
10 #include "clang/AST/ASTContext.h"
11 #include "clang/AST/Attr.h"
12 #include "clang/AST/DeclObjC.h"
13 #include "clang/AST/DeclTemplate.h"
14 #include "clang/Basic/SourceLocation.h"
15 #include "clang/Basic/SourceManager.h"
16 #include "clang/Index/IndexDataConsumer.h"
18 using namespace clang;
19 using namespace index;
21 static bool isGeneratedDecl(const Decl *D) {
22 if (auto *attr = D->getAttr<ExternalSourceSymbolAttr>()) {
23 return attr->getGeneratedDeclaration();
25 return false;
28 bool IndexingContext::shouldIndex(const Decl *D) {
29 return !isGeneratedDecl(D);
32 const LangOptions &IndexingContext::getLangOpts() const {
33 return Ctx->getLangOpts();
36 bool IndexingContext::shouldIndexFunctionLocalSymbols() const {
37 return IndexOpts.IndexFunctionLocals;
40 bool IndexingContext::shouldIndexImplicitInstantiation() const {
41 return IndexOpts.IndexImplicitInstantiation;
44 bool IndexingContext::shouldIndexParametersInDeclarations() const {
45 return IndexOpts.IndexParametersInDeclarations;
48 bool IndexingContext::shouldIndexTemplateParameters() const {
49 return IndexOpts.IndexTemplateParameters;
52 bool IndexingContext::handleDecl(const Decl *D,
53 SymbolRoleSet Roles,
54 ArrayRef<SymbolRelation> Relations) {
55 return handleDecl(D, D->getLocation(), Roles, Relations);
58 bool IndexingContext::handleDecl(const Decl *D, SourceLocation Loc,
59 SymbolRoleSet Roles,
60 ArrayRef<SymbolRelation> Relations,
61 const DeclContext *DC) {
62 if (!DC)
63 DC = D->getDeclContext();
65 const Decl *OrigD = D;
66 if (isa<ObjCPropertyImplDecl>(D)) {
67 D = cast<ObjCPropertyImplDecl>(D)->getPropertyDecl();
69 return handleDeclOccurrence(D, Loc, /*IsRef=*/false, cast<Decl>(DC),
70 Roles, Relations,
71 nullptr, OrigD, DC);
74 bool IndexingContext::handleReference(const NamedDecl *D, SourceLocation Loc,
75 const NamedDecl *Parent,
76 const DeclContext *DC,
77 SymbolRoleSet Roles,
78 ArrayRef<SymbolRelation> Relations,
79 const Expr *RefE,
80 const Decl *RefD) {
81 if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalSymbol(D))
82 return true;
84 if (!shouldIndexTemplateParameters() &&
85 (isa<NonTypeTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
86 isa<TemplateTemplateParmDecl>(D))) {
87 return true;
89 return handleDeclOccurrence(D, Loc, /*IsRef=*/true, Parent, Roles, Relations,
90 RefE, RefD, DC);
93 static void reportModuleReferences(const Module *Mod,
94 ArrayRef<SourceLocation> IdLocs,
95 const ImportDecl *ImportD,
96 IndexDataConsumer &DataConsumer) {
97 if (!Mod)
98 return;
99 reportModuleReferences(Mod->Parent, IdLocs.drop_back(), ImportD,
100 DataConsumer);
101 DataConsumer.handleModuleOccurrence(
102 ImportD, Mod, (SymbolRoleSet)SymbolRole::Reference, IdLocs.back());
105 bool IndexingContext::importedModule(const ImportDecl *ImportD) {
106 if (ImportD->isInvalidDecl())
107 return true;
109 SourceLocation Loc;
110 auto IdLocs = ImportD->getIdentifierLocs();
111 if (!IdLocs.empty())
112 Loc = IdLocs.back();
113 else
114 Loc = ImportD->getLocation();
116 SourceManager &SM = Ctx->getSourceManager();
117 FileID FID = SM.getFileID(SM.getFileLoc(Loc));
118 if (FID.isInvalid())
119 return true;
121 bool Invalid = false;
122 const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
123 if (Invalid || !SEntry.isFile())
124 return true;
126 if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
127 switch (IndexOpts.SystemSymbolFilter) {
128 case IndexingOptions::SystemSymbolFilterKind::None:
129 return true;
130 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
131 case IndexingOptions::SystemSymbolFilterKind::All:
132 break;
136 const Module *Mod = ImportD->getImportedModule();
137 if (!ImportD->isImplicit() && Mod->Parent && !IdLocs.empty()) {
138 reportModuleReferences(Mod->Parent, IdLocs.drop_back(), ImportD,
139 DataConsumer);
142 SymbolRoleSet Roles = (unsigned)SymbolRole::Declaration;
143 if (ImportD->isImplicit())
144 Roles |= (unsigned)SymbolRole::Implicit;
146 return DataConsumer.handleModuleOccurrence(ImportD, Mod, Roles, Loc);
149 bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) {
150 TemplateSpecializationKind TKind = TSK_Undeclared;
151 if (const ClassTemplateSpecializationDecl *
152 SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
153 TKind = SD->getSpecializationKind();
154 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
155 TKind = FD->getTemplateSpecializationKind();
156 } else if (auto *VD = dyn_cast<VarDecl>(D)) {
157 TKind = VD->getTemplateSpecializationKind();
158 } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
159 if (RD->getInstantiatedFromMemberClass())
160 TKind = RD->getTemplateSpecializationKind();
161 } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
162 if (ED->getInstantiatedFromMemberEnum())
163 TKind = ED->getTemplateSpecializationKind();
164 } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D) ||
165 isa<EnumConstantDecl>(D)) {
166 if (const auto *Parent = dyn_cast<Decl>(D->getDeclContext()))
167 return isTemplateImplicitInstantiation(Parent);
169 switch (TKind) {
170 case TSK_Undeclared:
171 // Instantiation maybe not happen yet when we see a SpecializationDecl,
172 // e.g. when the type doesn't need to be complete, we still treat it as an
173 // instantiation as we'd like to keep the canonicalized result consistent.
174 return isa<ClassTemplateSpecializationDecl>(D);
175 case TSK_ExplicitSpecialization:
176 return false;
177 case TSK_ImplicitInstantiation:
178 case TSK_ExplicitInstantiationDeclaration:
179 case TSK_ExplicitInstantiationDefinition:
180 return true;
182 llvm_unreachable("invalid TemplateSpecializationKind");
185 bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) {
186 if (isa<ObjCInterfaceDecl>(D))
187 return false;
188 if (isa<ObjCCategoryDecl>(D))
189 return false;
190 if (isa<ObjCIvarDecl>(D))
191 return false;
192 if (isa<ObjCMethodDecl>(D))
193 return false;
194 if (isa<ImportDecl>(D))
195 return false;
196 return true;
199 static const CXXRecordDecl *
200 getDeclContextForTemplateInstationPattern(const Decl *D) {
201 if (const auto *CTSD =
202 dyn_cast<ClassTemplateSpecializationDecl>(D->getDeclContext()))
203 return CTSD->getTemplateInstantiationPattern();
204 else if (const auto *RD = dyn_cast<CXXRecordDecl>(D->getDeclContext()))
205 return RD->getInstantiatedFromMemberClass();
206 return nullptr;
209 static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) {
210 if (const ClassTemplateSpecializationDecl *
211 SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
212 const auto *Template = SD->getTemplateInstantiationPattern();
213 if (Template)
214 return Template;
215 // Fallback to primary template if no instantiation is available yet (e.g.
216 // the type doesn't need to be complete).
217 return SD->getSpecializedTemplate()->getTemplatedDecl();
218 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
219 return FD->getTemplateInstantiationPattern();
220 } else if (auto *VD = dyn_cast<VarDecl>(D)) {
221 return VD->getTemplateInstantiationPattern();
222 } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
223 return RD->getInstantiatedFromMemberClass();
224 } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
225 return ED->getInstantiatedFromMemberEnum();
226 } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D)) {
227 const auto *ND = cast<NamedDecl>(D);
228 if (const CXXRecordDecl *Pattern =
229 getDeclContextForTemplateInstationPattern(ND)) {
230 for (const NamedDecl *BaseND : Pattern->lookup(ND->getDeclName())) {
231 if (BaseND->isImplicit())
232 continue;
233 if (BaseND->getKind() == ND->getKind())
234 return BaseND;
237 } else if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) {
238 if (const auto *ED = dyn_cast<EnumDecl>(ECD->getDeclContext())) {
239 if (const EnumDecl *Pattern = ED->getInstantiatedFromMemberEnum()) {
240 for (const NamedDecl *BaseECD : Pattern->lookup(ECD->getDeclName()))
241 return BaseECD;
245 return nullptr;
248 static bool isDeclADefinition(const Decl *D, const DeclContext *ContainerDC, ASTContext &Ctx) {
249 if (auto VD = dyn_cast<VarDecl>(D))
250 return VD->isThisDeclarationADefinition(Ctx);
252 if (auto FD = dyn_cast<FunctionDecl>(D))
253 return FD->isThisDeclarationADefinition();
255 if (auto TD = dyn_cast<TagDecl>(D))
256 return TD->isThisDeclarationADefinition();
258 if (auto MD = dyn_cast<ObjCMethodDecl>(D))
259 return MD->isThisDeclarationADefinition() || isa<ObjCImplDecl>(ContainerDC);
261 if (isa<TypedefNameDecl>(D) || isa<EnumConstantDecl>(D) ||
262 isa<FieldDecl>(D) || isa<MSPropertyDecl>(D) || isa<ObjCImplDecl>(D) ||
263 isa<ObjCPropertyImplDecl>(D) || isa<ConceptDecl>(D))
264 return true;
266 return false;
269 /// Whether the given NamedDecl should be skipped because it has no name.
270 static bool shouldSkipNamelessDecl(const NamedDecl *ND) {
271 return (ND->getDeclName().isEmpty() && !isa<TagDecl>(ND) &&
272 !isa<ObjCCategoryDecl>(ND)) || isa<CXXDeductionGuideDecl>(ND);
275 static const Decl *adjustParent(const Decl *Parent) {
276 if (!Parent)
277 return nullptr;
278 for (;; Parent = cast<Decl>(Parent->getDeclContext())) {
279 if (isa<TranslationUnitDecl>(Parent))
280 return nullptr;
281 if (isa<LinkageSpecDecl>(Parent) || isa<BlockDecl>(Parent))
282 continue;
283 if (auto NS = dyn_cast<NamespaceDecl>(Parent)) {
284 if (NS->isAnonymousNamespace())
285 continue;
286 } else if (auto RD = dyn_cast<RecordDecl>(Parent)) {
287 if (RD->isAnonymousStructOrUnion())
288 continue;
289 } else if (auto ND = dyn_cast<NamedDecl>(Parent)) {
290 if (shouldSkipNamelessDecl(ND))
291 continue;
293 return Parent;
297 static const Decl *getCanonicalDecl(const Decl *D) {
298 D = D->getCanonicalDecl();
299 if (auto TD = dyn_cast<TemplateDecl>(D)) {
300 if (auto TTD = TD->getTemplatedDecl()) {
301 D = TTD;
302 assert(D->isCanonicalDecl());
306 return D;
309 static bool shouldReportOccurrenceForSystemDeclOnlyMode(
310 bool IsRef, SymbolRoleSet Roles, ArrayRef<SymbolRelation> Relations) {
311 if (!IsRef)
312 return true;
314 auto acceptForRelation = [](SymbolRoleSet roles) -> bool {
315 bool accept = false;
316 applyForEachSymbolRoleInterruptible(roles, [&accept](SymbolRole r) -> bool {
317 switch (r) {
318 case SymbolRole::RelationChildOf:
319 case SymbolRole::RelationBaseOf:
320 case SymbolRole::RelationOverrideOf:
321 case SymbolRole::RelationExtendedBy:
322 case SymbolRole::RelationAccessorOf:
323 case SymbolRole::RelationIBTypeOf:
324 accept = true;
325 return false;
326 case SymbolRole::Declaration:
327 case SymbolRole::Definition:
328 case SymbolRole::Reference:
329 case SymbolRole::Read:
330 case SymbolRole::Write:
331 case SymbolRole::Call:
332 case SymbolRole::Dynamic:
333 case SymbolRole::AddressOf:
334 case SymbolRole::Implicit:
335 case SymbolRole::Undefinition:
336 case SymbolRole::RelationReceivedBy:
337 case SymbolRole::RelationCalledBy:
338 case SymbolRole::RelationContainedBy:
339 case SymbolRole::RelationSpecializationOf:
340 case SymbolRole::NameReference:
341 return true;
343 llvm_unreachable("Unsupported SymbolRole value!");
345 return accept;
348 for (auto &Rel : Relations) {
349 if (acceptForRelation(Rel.Roles))
350 return true;
353 return false;
356 bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc,
357 bool IsRef, const Decl *Parent,
358 SymbolRoleSet Roles,
359 ArrayRef<SymbolRelation> Relations,
360 const Expr *OrigE,
361 const Decl *OrigD,
362 const DeclContext *ContainerDC) {
363 if (D->isImplicit() && !isa<ObjCMethodDecl>(D))
364 return true;
365 if (!isa<NamedDecl>(D) || shouldSkipNamelessDecl(cast<NamedDecl>(D)))
366 return true;
368 SourceManager &SM = Ctx->getSourceManager();
369 FileID FID = SM.getFileID(SM.getFileLoc(Loc));
370 if (FID.isInvalid())
371 return true;
373 bool Invalid = false;
374 const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
375 if (Invalid || !SEntry.isFile())
376 return true;
378 if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
379 switch (IndexOpts.SystemSymbolFilter) {
380 case IndexingOptions::SystemSymbolFilterKind::None:
381 return true;
382 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
383 if (!shouldReportOccurrenceForSystemDeclOnlyMode(IsRef, Roles, Relations))
384 return true;
385 break;
386 case IndexingOptions::SystemSymbolFilterKind::All:
387 break;
391 if (!OrigD)
392 OrigD = D;
394 if (isTemplateImplicitInstantiation(D)) {
395 if (!IsRef)
396 return true;
397 D = adjustTemplateImplicitInstantiation(D);
398 if (!D)
399 return true;
400 assert(!isTemplateImplicitInstantiation(D));
403 if (IsRef)
404 Roles |= (unsigned)SymbolRole::Reference;
405 else if (isDeclADefinition(OrigD, ContainerDC, *Ctx))
406 Roles |= (unsigned)SymbolRole::Definition;
407 else
408 Roles |= (unsigned)SymbolRole::Declaration;
410 D = getCanonicalDecl(D);
411 Parent = adjustParent(Parent);
412 if (Parent)
413 Parent = getCanonicalDecl(Parent);
415 SmallVector<SymbolRelation, 6> FinalRelations;
416 FinalRelations.reserve(Relations.size()+1);
418 auto addRelation = [&](SymbolRelation Rel) {
419 auto It = llvm::find_if(FinalRelations, [&](SymbolRelation Elem) -> bool {
420 return Elem.RelatedSymbol == Rel.RelatedSymbol;
422 if (It != FinalRelations.end()) {
423 It->Roles |= Rel.Roles;
424 } else {
425 FinalRelations.push_back(Rel);
427 Roles |= Rel.Roles;
430 if (Parent) {
431 if (IsRef || (!isa<ParmVarDecl>(D) && isFunctionLocalSymbol(D))) {
432 addRelation(SymbolRelation{
433 (unsigned)SymbolRole::RelationContainedBy,
434 Parent
436 } else {
437 addRelation(SymbolRelation{
438 (unsigned)SymbolRole::RelationChildOf,
439 Parent
444 for (auto &Rel : Relations) {
445 addRelation(SymbolRelation(Rel.Roles,
446 Rel.RelatedSymbol->getCanonicalDecl()));
449 IndexDataConsumer::ASTNodeInfo Node{OrigE, OrigD, Parent, ContainerDC};
450 return DataConsumer.handleDeclOccurrence(D, Roles, FinalRelations, Loc, Node);
453 void IndexingContext::handleMacroDefined(const IdentifierInfo &Name,
454 SourceLocation Loc,
455 const MacroInfo &MI) {
456 if (!shouldIndexMacroOccurrence(/*IsRef=*/false, Loc))
457 return;
458 SymbolRoleSet Roles = (unsigned)SymbolRole::Definition;
459 DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc);
462 void IndexingContext::handleMacroUndefined(const IdentifierInfo &Name,
463 SourceLocation Loc,
464 const MacroInfo &MI) {
465 if (!shouldIndexMacroOccurrence(/*IsRef=*/false, Loc))
466 return;
467 SymbolRoleSet Roles = (unsigned)SymbolRole::Undefinition;
468 DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc);
471 void IndexingContext::handleMacroReference(const IdentifierInfo &Name,
472 SourceLocation Loc,
473 const MacroInfo &MI) {
474 if (!shouldIndexMacroOccurrence(/*IsRef=*/true, Loc))
475 return;
476 SymbolRoleSet Roles = (unsigned)SymbolRole::Reference;
477 DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc);
480 bool IndexingContext::shouldIndexMacroOccurrence(bool IsRef,
481 SourceLocation Loc) {
482 if (!IndexOpts.IndexMacros)
483 return false;
485 switch (IndexOpts.SystemSymbolFilter) {
486 case IndexingOptions::SystemSymbolFilterKind::None:
487 break;
488 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
489 if (!IsRef)
490 return true;
491 break;
492 case IndexingOptions::SystemSymbolFilterKind::All:
493 return true;
496 SourceManager &SM = Ctx->getSourceManager();
497 FileID FID = SM.getFileID(SM.getFileLoc(Loc));
498 if (FID.isInvalid())
499 return false;
501 bool Invalid = false;
502 const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
503 if (Invalid || !SEntry.isFile())
504 return false;
506 return SEntry.getFile().getFileCharacteristic() == SrcMgr::C_User;