[clang][extract-api][NFC] Use dedicated API to check for macro equality
[llvm-project.git] / clang / lib / Index / IndexingContext.cpp
blob8a962a055bac9ec660bca94daad64373c2b2f708
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;
90 return handleDeclOccurrence(D, Loc, /*IsRef=*/true, Parent, Roles, Relations,
91 RefE, RefD, DC);
94 static void reportModuleReferences(const Module *Mod,
95 ArrayRef<SourceLocation> IdLocs,
96 const ImportDecl *ImportD,
97 IndexDataConsumer &DataConsumer) {
98 if (!Mod)
99 return;
100 reportModuleReferences(Mod->Parent, IdLocs.drop_back(), ImportD,
101 DataConsumer);
102 DataConsumer.handleModuleOccurrence(
103 ImportD, Mod, (SymbolRoleSet)SymbolRole::Reference, IdLocs.back());
106 bool IndexingContext::importedModule(const ImportDecl *ImportD) {
107 if (ImportD->isInvalidDecl())
108 return true;
110 SourceLocation Loc;
111 auto IdLocs = ImportD->getIdentifierLocs();
112 if (!IdLocs.empty())
113 Loc = IdLocs.back();
114 else
115 Loc = ImportD->getLocation();
117 SourceManager &SM = Ctx->getSourceManager();
118 FileID FID = SM.getFileID(SM.getFileLoc(Loc));
119 if (FID.isInvalid())
120 return true;
122 bool Invalid = false;
123 const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
124 if (Invalid || !SEntry.isFile())
125 return true;
127 if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
128 switch (IndexOpts.SystemSymbolFilter) {
129 case IndexingOptions::SystemSymbolFilterKind::None:
130 return true;
131 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
132 case IndexingOptions::SystemSymbolFilterKind::All:
133 break;
137 const Module *Mod = ImportD->getImportedModule();
138 if (!ImportD->isImplicit() && Mod->Parent && !IdLocs.empty()) {
139 reportModuleReferences(Mod->Parent, IdLocs.drop_back(), ImportD,
140 DataConsumer);
143 SymbolRoleSet Roles = (unsigned)SymbolRole::Declaration;
144 if (ImportD->isImplicit())
145 Roles |= (unsigned)SymbolRole::Implicit;
147 return DataConsumer.handleModuleOccurrence(ImportD, Mod, Roles, Loc);
150 bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) {
151 TemplateSpecializationKind TKind = TSK_Undeclared;
152 if (const ClassTemplateSpecializationDecl *
153 SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
154 TKind = SD->getSpecializationKind();
155 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
156 TKind = FD->getTemplateSpecializationKind();
157 } else if (auto *VD = dyn_cast<VarDecl>(D)) {
158 TKind = VD->getTemplateSpecializationKind();
159 } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
160 if (RD->getInstantiatedFromMemberClass())
161 TKind = RD->getTemplateSpecializationKind();
162 } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
163 if (ED->getInstantiatedFromMemberEnum())
164 TKind = ED->getTemplateSpecializationKind();
165 } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D) ||
166 isa<EnumConstantDecl>(D)) {
167 if (const auto *Parent = dyn_cast<Decl>(D->getDeclContext()))
168 return isTemplateImplicitInstantiation(Parent);
170 switch (TKind) {
171 case TSK_Undeclared:
172 // Instantiation maybe not happen yet when we see a SpecializationDecl,
173 // e.g. when the type doesn't need to be complete, we still treat it as an
174 // instantiation as we'd like to keep the canonicalized result consistent.
175 return isa<ClassTemplateSpecializationDecl>(D);
176 case TSK_ExplicitSpecialization:
177 return false;
178 case TSK_ImplicitInstantiation:
179 case TSK_ExplicitInstantiationDeclaration:
180 case TSK_ExplicitInstantiationDefinition:
181 return true;
183 llvm_unreachable("invalid TemplateSpecializationKind");
186 bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) {
187 if (isa<ObjCInterfaceDecl>(D))
188 return false;
189 if (isa<ObjCCategoryDecl>(D))
190 return false;
191 if (isa<ObjCIvarDecl>(D))
192 return false;
193 if (isa<ObjCMethodDecl>(D))
194 return false;
195 if (isa<ImportDecl>(D))
196 return false;
197 return true;
200 static const CXXRecordDecl *
201 getDeclContextForTemplateInstationPattern(const Decl *D) {
202 if (const auto *CTSD =
203 dyn_cast<ClassTemplateSpecializationDecl>(D->getDeclContext()))
204 return CTSD->getTemplateInstantiationPattern();
205 else if (const auto *RD = dyn_cast<CXXRecordDecl>(D->getDeclContext()))
206 return RD->getInstantiatedFromMemberClass();
207 return nullptr;
210 static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) {
211 if (const ClassTemplateSpecializationDecl *
212 SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
213 const auto *Template = SD->getTemplateInstantiationPattern();
214 if (Template)
215 return Template;
216 // Fallback to primary template if no instantiation is available yet (e.g.
217 // the type doesn't need to be complete).
218 return SD->getSpecializedTemplate()->getTemplatedDecl();
219 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
220 return FD->getTemplateInstantiationPattern();
221 } else if (auto *VD = dyn_cast<VarDecl>(D)) {
222 return VD->getTemplateInstantiationPattern();
223 } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
224 return RD->getInstantiatedFromMemberClass();
225 } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
226 return ED->getInstantiatedFromMemberEnum();
227 } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D)) {
228 const auto *ND = cast<NamedDecl>(D);
229 if (const CXXRecordDecl *Pattern =
230 getDeclContextForTemplateInstationPattern(ND)) {
231 for (const NamedDecl *BaseND : Pattern->lookup(ND->getDeclName())) {
232 if (BaseND->isImplicit())
233 continue;
234 if (BaseND->getKind() == ND->getKind())
235 return BaseND;
238 } else if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) {
239 if (const auto *ED = dyn_cast<EnumDecl>(ECD->getDeclContext())) {
240 if (const EnumDecl *Pattern = ED->getInstantiatedFromMemberEnum()) {
241 for (const NamedDecl *BaseECD : Pattern->lookup(ECD->getDeclName()))
242 return BaseECD;
246 return nullptr;
249 static bool isDeclADefinition(const Decl *D, const DeclContext *ContainerDC, ASTContext &Ctx) {
250 if (auto VD = dyn_cast<VarDecl>(D))
251 return VD->isThisDeclarationADefinition(Ctx);
253 if (auto FD = dyn_cast<FunctionDecl>(D))
254 return FD->isThisDeclarationADefinition();
256 if (auto TD = dyn_cast<TagDecl>(D))
257 return TD->isThisDeclarationADefinition();
259 if (auto MD = dyn_cast<ObjCMethodDecl>(D))
260 return MD->isThisDeclarationADefinition() || isa<ObjCImplDecl>(ContainerDC);
262 if (isa<TypedefNameDecl>(D) ||
263 isa<EnumConstantDecl>(D) ||
264 isa<FieldDecl>(D) ||
265 isa<MSPropertyDecl>(D) ||
266 isa<ObjCImplDecl>(D) ||
267 isa<ObjCPropertyImplDecl>(D))
268 return true;
270 return false;
273 /// Whether the given NamedDecl should be skipped because it has no name.
274 static bool shouldSkipNamelessDecl(const NamedDecl *ND) {
275 return (ND->getDeclName().isEmpty() && !isa<TagDecl>(ND) &&
276 !isa<ObjCCategoryDecl>(ND)) || isa<CXXDeductionGuideDecl>(ND);
279 static const Decl *adjustParent(const Decl *Parent) {
280 if (!Parent)
281 return nullptr;
282 for (;; Parent = cast<Decl>(Parent->getDeclContext())) {
283 if (isa<TranslationUnitDecl>(Parent))
284 return nullptr;
285 if (isa<LinkageSpecDecl>(Parent) || isa<BlockDecl>(Parent))
286 continue;
287 if (auto NS = dyn_cast<NamespaceDecl>(Parent)) {
288 if (NS->isAnonymousNamespace())
289 continue;
290 } else if (auto RD = dyn_cast<RecordDecl>(Parent)) {
291 if (RD->isAnonymousStructOrUnion())
292 continue;
293 } else if (auto ND = dyn_cast<NamedDecl>(Parent)) {
294 if (shouldSkipNamelessDecl(ND))
295 continue;
297 return Parent;
301 static const Decl *getCanonicalDecl(const Decl *D) {
302 D = D->getCanonicalDecl();
303 if (auto TD = dyn_cast<TemplateDecl>(D)) {
304 if (auto TTD = TD->getTemplatedDecl()) {
305 D = TTD;
306 assert(D->isCanonicalDecl());
310 return D;
313 static bool shouldReportOccurrenceForSystemDeclOnlyMode(
314 bool IsRef, SymbolRoleSet Roles, ArrayRef<SymbolRelation> Relations) {
315 if (!IsRef)
316 return true;
318 auto acceptForRelation = [](SymbolRoleSet roles) -> bool {
319 bool accept = false;
320 applyForEachSymbolRoleInterruptible(roles, [&accept](SymbolRole r) -> bool {
321 switch (r) {
322 case SymbolRole::RelationChildOf:
323 case SymbolRole::RelationBaseOf:
324 case SymbolRole::RelationOverrideOf:
325 case SymbolRole::RelationExtendedBy:
326 case SymbolRole::RelationAccessorOf:
327 case SymbolRole::RelationIBTypeOf:
328 accept = true;
329 return false;
330 case SymbolRole::Declaration:
331 case SymbolRole::Definition:
332 case SymbolRole::Reference:
333 case SymbolRole::Read:
334 case SymbolRole::Write:
335 case SymbolRole::Call:
336 case SymbolRole::Dynamic:
337 case SymbolRole::AddressOf:
338 case SymbolRole::Implicit:
339 case SymbolRole::Undefinition:
340 case SymbolRole::RelationReceivedBy:
341 case SymbolRole::RelationCalledBy:
342 case SymbolRole::RelationContainedBy:
343 case SymbolRole::RelationSpecializationOf:
344 case SymbolRole::NameReference:
345 return true;
347 llvm_unreachable("Unsupported SymbolRole value!");
349 return accept;
352 for (auto &Rel : Relations) {
353 if (acceptForRelation(Rel.Roles))
354 return true;
357 return false;
360 bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc,
361 bool IsRef, const Decl *Parent,
362 SymbolRoleSet Roles,
363 ArrayRef<SymbolRelation> Relations,
364 const Expr *OrigE,
365 const Decl *OrigD,
366 const DeclContext *ContainerDC) {
367 if (D->isImplicit() && !isa<ObjCMethodDecl>(D))
368 return true;
369 if (!isa<NamedDecl>(D) || shouldSkipNamelessDecl(cast<NamedDecl>(D)))
370 return true;
372 SourceManager &SM = Ctx->getSourceManager();
373 FileID FID = SM.getFileID(SM.getFileLoc(Loc));
374 if (FID.isInvalid())
375 return true;
377 bool Invalid = false;
378 const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
379 if (Invalid || !SEntry.isFile())
380 return true;
382 if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
383 switch (IndexOpts.SystemSymbolFilter) {
384 case IndexingOptions::SystemSymbolFilterKind::None:
385 return true;
386 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
387 if (!shouldReportOccurrenceForSystemDeclOnlyMode(IsRef, Roles, Relations))
388 return true;
389 break;
390 case IndexingOptions::SystemSymbolFilterKind::All:
391 break;
395 if (!OrigD)
396 OrigD = D;
398 if (isTemplateImplicitInstantiation(D)) {
399 if (!IsRef)
400 return true;
401 D = adjustTemplateImplicitInstantiation(D);
402 if (!D)
403 return true;
404 assert(!isTemplateImplicitInstantiation(D));
407 if (IsRef)
408 Roles |= (unsigned)SymbolRole::Reference;
409 else if (isDeclADefinition(OrigD, ContainerDC, *Ctx))
410 Roles |= (unsigned)SymbolRole::Definition;
411 else
412 Roles |= (unsigned)SymbolRole::Declaration;
414 D = getCanonicalDecl(D);
415 Parent = adjustParent(Parent);
416 if (Parent)
417 Parent = getCanonicalDecl(Parent);
419 SmallVector<SymbolRelation, 6> FinalRelations;
420 FinalRelations.reserve(Relations.size()+1);
422 auto addRelation = [&](SymbolRelation Rel) {
423 auto It = llvm::find_if(FinalRelations, [&](SymbolRelation Elem) -> bool {
424 return Elem.RelatedSymbol == Rel.RelatedSymbol;
426 if (It != FinalRelations.end()) {
427 It->Roles |= Rel.Roles;
428 } else {
429 FinalRelations.push_back(Rel);
431 Roles |= Rel.Roles;
434 if (Parent) {
435 if (IsRef || (!isa<ParmVarDecl>(D) && isFunctionLocalSymbol(D))) {
436 addRelation(SymbolRelation{
437 (unsigned)SymbolRole::RelationContainedBy,
438 Parent
440 } else {
441 addRelation(SymbolRelation{
442 (unsigned)SymbolRole::RelationChildOf,
443 Parent
448 for (auto &Rel : Relations) {
449 addRelation(SymbolRelation(Rel.Roles,
450 Rel.RelatedSymbol->getCanonicalDecl()));
453 IndexDataConsumer::ASTNodeInfo Node{OrigE, OrigD, Parent, ContainerDC};
454 return DataConsumer.handleDeclOccurrence(D, Roles, FinalRelations, Loc, Node);
457 void IndexingContext::handleMacroDefined(const IdentifierInfo &Name,
458 SourceLocation Loc,
459 const MacroInfo &MI) {
460 if (!shouldIndexMacroOccurrence(/*IsRef=*/false, Loc))
461 return;
462 SymbolRoleSet Roles = (unsigned)SymbolRole::Definition;
463 DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc);
466 void IndexingContext::handleMacroUndefined(const IdentifierInfo &Name,
467 SourceLocation Loc,
468 const MacroInfo &MI) {
469 if (!shouldIndexMacroOccurrence(/*IsRef=*/false, Loc))
470 return;
471 SymbolRoleSet Roles = (unsigned)SymbolRole::Undefinition;
472 DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc);
475 void IndexingContext::handleMacroReference(const IdentifierInfo &Name,
476 SourceLocation Loc,
477 const MacroInfo &MI) {
478 if (!shouldIndexMacroOccurrence(/*IsRef=*/true, Loc))
479 return;
480 SymbolRoleSet Roles = (unsigned)SymbolRole::Reference;
481 DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc);
484 bool IndexingContext::shouldIndexMacroOccurrence(bool IsRef,
485 SourceLocation Loc) {
486 if (!IndexOpts.IndexMacros)
487 return false;
489 switch (IndexOpts.SystemSymbolFilter) {
490 case IndexingOptions::SystemSymbolFilterKind::None:
491 break;
492 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
493 if (!IsRef)
494 return true;
495 break;
496 case IndexingOptions::SystemSymbolFilterKind::All:
497 return true;
500 SourceManager &SM = Ctx->getSourceManager();
501 FileID FID = SM.getFileID(SM.getFileLoc(Loc));
502 if (FID.isInvalid())
503 return false;
505 bool Invalid = false;
506 const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
507 if (Invalid || !SEntry.isFile())
508 return false;
510 return SEntry.getFile().getFileCharacteristic() == SrcMgr::C_User;