xref: /openbsd-src/gnu/llvm/clang/lib/Index/IndexingContext.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
1e5dd7070Spatrick //===- IndexingContext.cpp - Indexing context data ------------------------===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick 
9e5dd7070Spatrick #include "IndexingContext.h"
10e5dd7070Spatrick #include "clang/AST/ASTContext.h"
11e5dd7070Spatrick #include "clang/AST/Attr.h"
12e5dd7070Spatrick #include "clang/AST/DeclObjC.h"
13e5dd7070Spatrick #include "clang/AST/DeclTemplate.h"
14e5dd7070Spatrick #include "clang/Basic/SourceLocation.h"
15e5dd7070Spatrick #include "clang/Basic/SourceManager.h"
16e5dd7070Spatrick #include "clang/Index/IndexDataConsumer.h"
17e5dd7070Spatrick 
18e5dd7070Spatrick using namespace clang;
19e5dd7070Spatrick using namespace index;
20e5dd7070Spatrick 
isGeneratedDecl(const Decl * D)21e5dd7070Spatrick static bool isGeneratedDecl(const Decl *D) {
22e5dd7070Spatrick   if (auto *attr = D->getAttr<ExternalSourceSymbolAttr>()) {
23e5dd7070Spatrick     return attr->getGeneratedDeclaration();
24e5dd7070Spatrick   }
25e5dd7070Spatrick   return false;
26e5dd7070Spatrick }
27e5dd7070Spatrick 
shouldIndex(const Decl * D)28e5dd7070Spatrick bool IndexingContext::shouldIndex(const Decl *D) {
29e5dd7070Spatrick   return !isGeneratedDecl(D);
30e5dd7070Spatrick }
31e5dd7070Spatrick 
getLangOpts() const32e5dd7070Spatrick const LangOptions &IndexingContext::getLangOpts() const {
33e5dd7070Spatrick   return Ctx->getLangOpts();
34e5dd7070Spatrick }
35e5dd7070Spatrick 
shouldIndexFunctionLocalSymbols() const36e5dd7070Spatrick bool IndexingContext::shouldIndexFunctionLocalSymbols() const {
37e5dd7070Spatrick   return IndexOpts.IndexFunctionLocals;
38e5dd7070Spatrick }
39e5dd7070Spatrick 
shouldIndexImplicitInstantiation() const40e5dd7070Spatrick bool IndexingContext::shouldIndexImplicitInstantiation() const {
41e5dd7070Spatrick   return IndexOpts.IndexImplicitInstantiation;
42e5dd7070Spatrick }
43e5dd7070Spatrick 
shouldIndexParametersInDeclarations() const44e5dd7070Spatrick bool IndexingContext::shouldIndexParametersInDeclarations() const {
45e5dd7070Spatrick   return IndexOpts.IndexParametersInDeclarations;
46e5dd7070Spatrick }
47e5dd7070Spatrick 
shouldIndexTemplateParameters() const48e5dd7070Spatrick bool IndexingContext::shouldIndexTemplateParameters() const {
49e5dd7070Spatrick   return IndexOpts.IndexTemplateParameters;
50e5dd7070Spatrick }
51e5dd7070Spatrick 
handleDecl(const Decl * D,SymbolRoleSet Roles,ArrayRef<SymbolRelation> Relations)52e5dd7070Spatrick bool IndexingContext::handleDecl(const Decl *D,
53e5dd7070Spatrick                                  SymbolRoleSet Roles,
54e5dd7070Spatrick                                  ArrayRef<SymbolRelation> Relations) {
55e5dd7070Spatrick   return handleDecl(D, D->getLocation(), Roles, Relations);
56e5dd7070Spatrick }
57e5dd7070Spatrick 
handleDecl(const Decl * D,SourceLocation Loc,SymbolRoleSet Roles,ArrayRef<SymbolRelation> Relations,const DeclContext * DC)58e5dd7070Spatrick bool IndexingContext::handleDecl(const Decl *D, SourceLocation Loc,
59e5dd7070Spatrick                                  SymbolRoleSet Roles,
60e5dd7070Spatrick                                  ArrayRef<SymbolRelation> Relations,
61e5dd7070Spatrick                                  const DeclContext *DC) {
62e5dd7070Spatrick   if (!DC)
63e5dd7070Spatrick     DC = D->getDeclContext();
64e5dd7070Spatrick 
65e5dd7070Spatrick   const Decl *OrigD = D;
66e5dd7070Spatrick   if (isa<ObjCPropertyImplDecl>(D)) {
67e5dd7070Spatrick     D = cast<ObjCPropertyImplDecl>(D)->getPropertyDecl();
68e5dd7070Spatrick   }
69e5dd7070Spatrick   return handleDeclOccurrence(D, Loc, /*IsRef=*/false, cast<Decl>(DC),
70e5dd7070Spatrick                               Roles, Relations,
71e5dd7070Spatrick                               nullptr, OrigD, DC);
72e5dd7070Spatrick }
73e5dd7070Spatrick 
handleReference(const NamedDecl * D,SourceLocation Loc,const NamedDecl * Parent,const DeclContext * DC,SymbolRoleSet Roles,ArrayRef<SymbolRelation> Relations,const Expr * RefE,const Decl * RefD)74e5dd7070Spatrick bool IndexingContext::handleReference(const NamedDecl *D, SourceLocation Loc,
75e5dd7070Spatrick                                       const NamedDecl *Parent,
76e5dd7070Spatrick                                       const DeclContext *DC,
77e5dd7070Spatrick                                       SymbolRoleSet Roles,
78e5dd7070Spatrick                                       ArrayRef<SymbolRelation> Relations,
79e5dd7070Spatrick                                       const Expr *RefE,
80e5dd7070Spatrick                                       const Decl *RefD) {
81e5dd7070Spatrick   if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalSymbol(D))
82e5dd7070Spatrick     return true;
83e5dd7070Spatrick 
84e5dd7070Spatrick   if (!shouldIndexTemplateParameters() &&
85e5dd7070Spatrick       (isa<NonTypeTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
86e5dd7070Spatrick        isa<TemplateTemplateParmDecl>(D))) {
87e5dd7070Spatrick     return true;
88e5dd7070Spatrick   }
89e5dd7070Spatrick   return handleDeclOccurrence(D, Loc, /*IsRef=*/true, Parent, Roles, Relations,
90e5dd7070Spatrick                               RefE, RefD, DC);
91e5dd7070Spatrick }
92e5dd7070Spatrick 
reportModuleReferences(const Module * Mod,ArrayRef<SourceLocation> IdLocs,const ImportDecl * ImportD,IndexDataConsumer & DataConsumer)93e5dd7070Spatrick static void reportModuleReferences(const Module *Mod,
94e5dd7070Spatrick                                    ArrayRef<SourceLocation> IdLocs,
95e5dd7070Spatrick                                    const ImportDecl *ImportD,
96e5dd7070Spatrick                                    IndexDataConsumer &DataConsumer) {
97e5dd7070Spatrick   if (!Mod)
98e5dd7070Spatrick     return;
99e5dd7070Spatrick   reportModuleReferences(Mod->Parent, IdLocs.drop_back(), ImportD,
100e5dd7070Spatrick                          DataConsumer);
101e5dd7070Spatrick   DataConsumer.handleModuleOccurrence(
102e5dd7070Spatrick       ImportD, Mod, (SymbolRoleSet)SymbolRole::Reference, IdLocs.back());
103e5dd7070Spatrick }
104e5dd7070Spatrick 
importedModule(const ImportDecl * ImportD)105e5dd7070Spatrick bool IndexingContext::importedModule(const ImportDecl *ImportD) {
106e5dd7070Spatrick   if (ImportD->isInvalidDecl())
107e5dd7070Spatrick     return true;
108e5dd7070Spatrick 
109e5dd7070Spatrick   SourceLocation Loc;
110e5dd7070Spatrick   auto IdLocs = ImportD->getIdentifierLocs();
111e5dd7070Spatrick   if (!IdLocs.empty())
112e5dd7070Spatrick     Loc = IdLocs.back();
113e5dd7070Spatrick   else
114e5dd7070Spatrick     Loc = ImportD->getLocation();
115e5dd7070Spatrick 
116e5dd7070Spatrick   SourceManager &SM = Ctx->getSourceManager();
117e5dd7070Spatrick   FileID FID = SM.getFileID(SM.getFileLoc(Loc));
118e5dd7070Spatrick   if (FID.isInvalid())
119e5dd7070Spatrick     return true;
120e5dd7070Spatrick 
121e5dd7070Spatrick   bool Invalid = false;
122e5dd7070Spatrick   const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
123e5dd7070Spatrick   if (Invalid || !SEntry.isFile())
124e5dd7070Spatrick     return true;
125e5dd7070Spatrick 
126e5dd7070Spatrick   if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
127e5dd7070Spatrick     switch (IndexOpts.SystemSymbolFilter) {
128e5dd7070Spatrick     case IndexingOptions::SystemSymbolFilterKind::None:
129e5dd7070Spatrick       return true;
130e5dd7070Spatrick     case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
131e5dd7070Spatrick     case IndexingOptions::SystemSymbolFilterKind::All:
132e5dd7070Spatrick       break;
133e5dd7070Spatrick     }
134e5dd7070Spatrick   }
135e5dd7070Spatrick 
136e5dd7070Spatrick   const Module *Mod = ImportD->getImportedModule();
137e5dd7070Spatrick   if (!ImportD->isImplicit() && Mod->Parent && !IdLocs.empty()) {
138e5dd7070Spatrick     reportModuleReferences(Mod->Parent, IdLocs.drop_back(), ImportD,
139e5dd7070Spatrick                            DataConsumer);
140e5dd7070Spatrick   }
141e5dd7070Spatrick 
142e5dd7070Spatrick   SymbolRoleSet Roles = (unsigned)SymbolRole::Declaration;
143e5dd7070Spatrick   if (ImportD->isImplicit())
144e5dd7070Spatrick     Roles |= (unsigned)SymbolRole::Implicit;
145e5dd7070Spatrick 
146e5dd7070Spatrick   return DataConsumer.handleModuleOccurrence(ImportD, Mod, Roles, Loc);
147e5dd7070Spatrick }
148e5dd7070Spatrick 
isTemplateImplicitInstantiation(const Decl * D)149e5dd7070Spatrick bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) {
150e5dd7070Spatrick   TemplateSpecializationKind TKind = TSK_Undeclared;
151e5dd7070Spatrick   if (const ClassTemplateSpecializationDecl *
152e5dd7070Spatrick       SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
153e5dd7070Spatrick     TKind = SD->getSpecializationKind();
154e5dd7070Spatrick   } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
155e5dd7070Spatrick     TKind = FD->getTemplateSpecializationKind();
156e5dd7070Spatrick   } else if (auto *VD = dyn_cast<VarDecl>(D)) {
157e5dd7070Spatrick     TKind = VD->getTemplateSpecializationKind();
158e5dd7070Spatrick   } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
159e5dd7070Spatrick     if (RD->getInstantiatedFromMemberClass())
160e5dd7070Spatrick       TKind = RD->getTemplateSpecializationKind();
161e5dd7070Spatrick   } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
162e5dd7070Spatrick     if (ED->getInstantiatedFromMemberEnum())
163e5dd7070Spatrick       TKind = ED->getTemplateSpecializationKind();
164e5dd7070Spatrick   } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D) ||
165e5dd7070Spatrick              isa<EnumConstantDecl>(D)) {
166e5dd7070Spatrick     if (const auto *Parent = dyn_cast<Decl>(D->getDeclContext()))
167e5dd7070Spatrick       return isTemplateImplicitInstantiation(Parent);
168e5dd7070Spatrick   }
169e5dd7070Spatrick   switch (TKind) {
170e5dd7070Spatrick     case TSK_Undeclared:
171ec727ea7Spatrick       // Instantiation maybe not happen yet when we see a SpecializationDecl,
172ec727ea7Spatrick       // e.g. when the type doesn't need to be complete, we still treat it as an
173ec727ea7Spatrick       // instantiation as we'd like to keep the canonicalized result consistent.
174ec727ea7Spatrick       return isa<ClassTemplateSpecializationDecl>(D);
175e5dd7070Spatrick     case TSK_ExplicitSpecialization:
176e5dd7070Spatrick       return false;
177e5dd7070Spatrick     case TSK_ImplicitInstantiation:
178e5dd7070Spatrick     case TSK_ExplicitInstantiationDeclaration:
179e5dd7070Spatrick     case TSK_ExplicitInstantiationDefinition:
180e5dd7070Spatrick       return true;
181e5dd7070Spatrick   }
182e5dd7070Spatrick   llvm_unreachable("invalid TemplateSpecializationKind");
183e5dd7070Spatrick }
184e5dd7070Spatrick 
shouldIgnoreIfImplicit(const Decl * D)185e5dd7070Spatrick bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) {
186e5dd7070Spatrick   if (isa<ObjCInterfaceDecl>(D))
187e5dd7070Spatrick     return false;
188e5dd7070Spatrick   if (isa<ObjCCategoryDecl>(D))
189e5dd7070Spatrick     return false;
190e5dd7070Spatrick   if (isa<ObjCIvarDecl>(D))
191e5dd7070Spatrick     return false;
192e5dd7070Spatrick   if (isa<ObjCMethodDecl>(D))
193e5dd7070Spatrick     return false;
194e5dd7070Spatrick   if (isa<ImportDecl>(D))
195e5dd7070Spatrick     return false;
196e5dd7070Spatrick   return true;
197e5dd7070Spatrick }
198e5dd7070Spatrick 
199e5dd7070Spatrick static const CXXRecordDecl *
getDeclContextForTemplateInstationPattern(const Decl * D)200e5dd7070Spatrick getDeclContextForTemplateInstationPattern(const Decl *D) {
201e5dd7070Spatrick   if (const auto *CTSD =
202e5dd7070Spatrick           dyn_cast<ClassTemplateSpecializationDecl>(D->getDeclContext()))
203e5dd7070Spatrick     return CTSD->getTemplateInstantiationPattern();
204e5dd7070Spatrick   else if (const auto *RD = dyn_cast<CXXRecordDecl>(D->getDeclContext()))
205e5dd7070Spatrick     return RD->getInstantiatedFromMemberClass();
206e5dd7070Spatrick   return nullptr;
207e5dd7070Spatrick }
208e5dd7070Spatrick 
adjustTemplateImplicitInstantiation(const Decl * D)209e5dd7070Spatrick static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) {
210e5dd7070Spatrick   if (const ClassTemplateSpecializationDecl *
211e5dd7070Spatrick       SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
212ec727ea7Spatrick     const auto *Template = SD->getTemplateInstantiationPattern();
213ec727ea7Spatrick     if (Template)
214ec727ea7Spatrick       return Template;
215ec727ea7Spatrick     // Fallback to primary template if no instantiation is available yet (e.g.
216ec727ea7Spatrick     // the type doesn't need to be complete).
217ec727ea7Spatrick     return SD->getSpecializedTemplate()->getTemplatedDecl();
218e5dd7070Spatrick   } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
219e5dd7070Spatrick     return FD->getTemplateInstantiationPattern();
220e5dd7070Spatrick   } else if (auto *VD = dyn_cast<VarDecl>(D)) {
221e5dd7070Spatrick     return VD->getTemplateInstantiationPattern();
222e5dd7070Spatrick   } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
223e5dd7070Spatrick     return RD->getInstantiatedFromMemberClass();
224e5dd7070Spatrick   } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
225e5dd7070Spatrick     return ED->getInstantiatedFromMemberEnum();
226e5dd7070Spatrick   } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D)) {
227e5dd7070Spatrick     const auto *ND = cast<NamedDecl>(D);
228e5dd7070Spatrick     if (const CXXRecordDecl *Pattern =
229e5dd7070Spatrick             getDeclContextForTemplateInstationPattern(ND)) {
230e5dd7070Spatrick       for (const NamedDecl *BaseND : Pattern->lookup(ND->getDeclName())) {
231e5dd7070Spatrick         if (BaseND->isImplicit())
232e5dd7070Spatrick           continue;
233e5dd7070Spatrick         if (BaseND->getKind() == ND->getKind())
234e5dd7070Spatrick           return BaseND;
235e5dd7070Spatrick       }
236e5dd7070Spatrick     }
237e5dd7070Spatrick   } else if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) {
238e5dd7070Spatrick     if (const auto *ED = dyn_cast<EnumDecl>(ECD->getDeclContext())) {
239e5dd7070Spatrick       if (const EnumDecl *Pattern = ED->getInstantiatedFromMemberEnum()) {
240e5dd7070Spatrick         for (const NamedDecl *BaseECD : Pattern->lookup(ECD->getDeclName()))
241e5dd7070Spatrick           return BaseECD;
242e5dd7070Spatrick       }
243e5dd7070Spatrick     }
244e5dd7070Spatrick   }
245e5dd7070Spatrick   return nullptr;
246e5dd7070Spatrick }
247e5dd7070Spatrick 
isDeclADefinition(const Decl * D,const DeclContext * ContainerDC,ASTContext & Ctx)248e5dd7070Spatrick static bool isDeclADefinition(const Decl *D, const DeclContext *ContainerDC, ASTContext &Ctx) {
249e5dd7070Spatrick   if (auto VD = dyn_cast<VarDecl>(D))
250e5dd7070Spatrick     return VD->isThisDeclarationADefinition(Ctx);
251e5dd7070Spatrick 
252e5dd7070Spatrick   if (auto FD = dyn_cast<FunctionDecl>(D))
253e5dd7070Spatrick     return FD->isThisDeclarationADefinition();
254e5dd7070Spatrick 
255e5dd7070Spatrick   if (auto TD = dyn_cast<TagDecl>(D))
256e5dd7070Spatrick     return TD->isThisDeclarationADefinition();
257e5dd7070Spatrick 
258e5dd7070Spatrick   if (auto MD = dyn_cast<ObjCMethodDecl>(D))
259e5dd7070Spatrick     return MD->isThisDeclarationADefinition() || isa<ObjCImplDecl>(ContainerDC);
260e5dd7070Spatrick 
261*12c85518Srobert   if (isa<TypedefNameDecl>(D) || isa<EnumConstantDecl>(D) ||
262*12c85518Srobert       isa<FieldDecl>(D) || isa<MSPropertyDecl>(D) || isa<ObjCImplDecl>(D) ||
263*12c85518Srobert       isa<ObjCPropertyImplDecl>(D) || isa<ConceptDecl>(D))
264e5dd7070Spatrick     return true;
265e5dd7070Spatrick 
266e5dd7070Spatrick   return false;
267e5dd7070Spatrick }
268e5dd7070Spatrick 
269e5dd7070Spatrick /// Whether the given NamedDecl should be skipped because it has no name.
shouldSkipNamelessDecl(const NamedDecl * ND)270e5dd7070Spatrick static bool shouldSkipNamelessDecl(const NamedDecl *ND) {
271e5dd7070Spatrick   return (ND->getDeclName().isEmpty() && !isa<TagDecl>(ND) &&
272e5dd7070Spatrick           !isa<ObjCCategoryDecl>(ND)) || isa<CXXDeductionGuideDecl>(ND);
273e5dd7070Spatrick }
274e5dd7070Spatrick 
adjustParent(const Decl * Parent)275e5dd7070Spatrick static const Decl *adjustParent(const Decl *Parent) {
276e5dd7070Spatrick   if (!Parent)
277e5dd7070Spatrick     return nullptr;
278e5dd7070Spatrick   for (;; Parent = cast<Decl>(Parent->getDeclContext())) {
279e5dd7070Spatrick     if (isa<TranslationUnitDecl>(Parent))
280e5dd7070Spatrick       return nullptr;
281e5dd7070Spatrick     if (isa<LinkageSpecDecl>(Parent) || isa<BlockDecl>(Parent))
282e5dd7070Spatrick       continue;
283e5dd7070Spatrick     if (auto NS = dyn_cast<NamespaceDecl>(Parent)) {
284e5dd7070Spatrick       if (NS->isAnonymousNamespace())
285e5dd7070Spatrick         continue;
286e5dd7070Spatrick     } else if (auto RD = dyn_cast<RecordDecl>(Parent)) {
287e5dd7070Spatrick       if (RD->isAnonymousStructOrUnion())
288e5dd7070Spatrick         continue;
289e5dd7070Spatrick     } else if (auto ND = dyn_cast<NamedDecl>(Parent)) {
290e5dd7070Spatrick       if (shouldSkipNamelessDecl(ND))
291e5dd7070Spatrick         continue;
292e5dd7070Spatrick     }
293e5dd7070Spatrick     return Parent;
294e5dd7070Spatrick   }
295e5dd7070Spatrick }
296e5dd7070Spatrick 
getCanonicalDecl(const Decl * D)297e5dd7070Spatrick static const Decl *getCanonicalDecl(const Decl *D) {
298e5dd7070Spatrick   D = D->getCanonicalDecl();
299e5dd7070Spatrick   if (auto TD = dyn_cast<TemplateDecl>(D)) {
300e5dd7070Spatrick     if (auto TTD = TD->getTemplatedDecl()) {
301e5dd7070Spatrick       D = TTD;
302e5dd7070Spatrick       assert(D->isCanonicalDecl());
303e5dd7070Spatrick     }
304e5dd7070Spatrick   }
305e5dd7070Spatrick 
306e5dd7070Spatrick   return D;
307e5dd7070Spatrick }
308e5dd7070Spatrick 
shouldReportOccurrenceForSystemDeclOnlyMode(bool IsRef,SymbolRoleSet Roles,ArrayRef<SymbolRelation> Relations)309e5dd7070Spatrick static bool shouldReportOccurrenceForSystemDeclOnlyMode(
310e5dd7070Spatrick     bool IsRef, SymbolRoleSet Roles, ArrayRef<SymbolRelation> Relations) {
311e5dd7070Spatrick   if (!IsRef)
312e5dd7070Spatrick     return true;
313e5dd7070Spatrick 
314e5dd7070Spatrick   auto acceptForRelation = [](SymbolRoleSet roles) -> bool {
315e5dd7070Spatrick     bool accept = false;
316e5dd7070Spatrick     applyForEachSymbolRoleInterruptible(roles, [&accept](SymbolRole r) -> bool {
317e5dd7070Spatrick       switch (r) {
318e5dd7070Spatrick       case SymbolRole::RelationChildOf:
319e5dd7070Spatrick       case SymbolRole::RelationBaseOf:
320e5dd7070Spatrick       case SymbolRole::RelationOverrideOf:
321e5dd7070Spatrick       case SymbolRole::RelationExtendedBy:
322e5dd7070Spatrick       case SymbolRole::RelationAccessorOf:
323e5dd7070Spatrick       case SymbolRole::RelationIBTypeOf:
324e5dd7070Spatrick         accept = true;
325e5dd7070Spatrick         return false;
326e5dd7070Spatrick       case SymbolRole::Declaration:
327e5dd7070Spatrick       case SymbolRole::Definition:
328e5dd7070Spatrick       case SymbolRole::Reference:
329e5dd7070Spatrick       case SymbolRole::Read:
330e5dd7070Spatrick       case SymbolRole::Write:
331e5dd7070Spatrick       case SymbolRole::Call:
332e5dd7070Spatrick       case SymbolRole::Dynamic:
333e5dd7070Spatrick       case SymbolRole::AddressOf:
334e5dd7070Spatrick       case SymbolRole::Implicit:
335e5dd7070Spatrick       case SymbolRole::Undefinition:
336e5dd7070Spatrick       case SymbolRole::RelationReceivedBy:
337e5dd7070Spatrick       case SymbolRole::RelationCalledBy:
338e5dd7070Spatrick       case SymbolRole::RelationContainedBy:
339e5dd7070Spatrick       case SymbolRole::RelationSpecializationOf:
340e5dd7070Spatrick       case SymbolRole::NameReference:
341e5dd7070Spatrick         return true;
342e5dd7070Spatrick       }
343e5dd7070Spatrick       llvm_unreachable("Unsupported SymbolRole value!");
344e5dd7070Spatrick     });
345e5dd7070Spatrick     return accept;
346e5dd7070Spatrick   };
347e5dd7070Spatrick 
348e5dd7070Spatrick   for (auto &Rel : Relations) {
349e5dd7070Spatrick     if (acceptForRelation(Rel.Roles))
350e5dd7070Spatrick       return true;
351e5dd7070Spatrick   }
352e5dd7070Spatrick 
353e5dd7070Spatrick   return false;
354e5dd7070Spatrick }
355e5dd7070Spatrick 
handleDeclOccurrence(const Decl * D,SourceLocation Loc,bool IsRef,const Decl * Parent,SymbolRoleSet Roles,ArrayRef<SymbolRelation> Relations,const Expr * OrigE,const Decl * OrigD,const DeclContext * ContainerDC)356e5dd7070Spatrick bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc,
357e5dd7070Spatrick                                            bool IsRef, const Decl *Parent,
358e5dd7070Spatrick                                            SymbolRoleSet Roles,
359e5dd7070Spatrick                                            ArrayRef<SymbolRelation> Relations,
360e5dd7070Spatrick                                            const Expr *OrigE,
361e5dd7070Spatrick                                            const Decl *OrigD,
362e5dd7070Spatrick                                            const DeclContext *ContainerDC) {
363e5dd7070Spatrick   if (D->isImplicit() && !isa<ObjCMethodDecl>(D))
364e5dd7070Spatrick     return true;
365e5dd7070Spatrick   if (!isa<NamedDecl>(D) || shouldSkipNamelessDecl(cast<NamedDecl>(D)))
366e5dd7070Spatrick     return true;
367e5dd7070Spatrick 
368e5dd7070Spatrick   SourceManager &SM = Ctx->getSourceManager();
369e5dd7070Spatrick   FileID FID = SM.getFileID(SM.getFileLoc(Loc));
370e5dd7070Spatrick   if (FID.isInvalid())
371e5dd7070Spatrick     return true;
372e5dd7070Spatrick 
373e5dd7070Spatrick   bool Invalid = false;
374e5dd7070Spatrick   const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
375e5dd7070Spatrick   if (Invalid || !SEntry.isFile())
376e5dd7070Spatrick     return true;
377e5dd7070Spatrick 
378e5dd7070Spatrick   if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
379e5dd7070Spatrick     switch (IndexOpts.SystemSymbolFilter) {
380e5dd7070Spatrick     case IndexingOptions::SystemSymbolFilterKind::None:
381e5dd7070Spatrick       return true;
382e5dd7070Spatrick     case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
383e5dd7070Spatrick       if (!shouldReportOccurrenceForSystemDeclOnlyMode(IsRef, Roles, Relations))
384e5dd7070Spatrick         return true;
385e5dd7070Spatrick       break;
386e5dd7070Spatrick     case IndexingOptions::SystemSymbolFilterKind::All:
387e5dd7070Spatrick       break;
388e5dd7070Spatrick     }
389e5dd7070Spatrick   }
390e5dd7070Spatrick 
391e5dd7070Spatrick   if (!OrigD)
392e5dd7070Spatrick     OrigD = D;
393e5dd7070Spatrick 
394e5dd7070Spatrick   if (isTemplateImplicitInstantiation(D)) {
395e5dd7070Spatrick     if (!IsRef)
396e5dd7070Spatrick       return true;
397e5dd7070Spatrick     D = adjustTemplateImplicitInstantiation(D);
398e5dd7070Spatrick     if (!D)
399e5dd7070Spatrick       return true;
400e5dd7070Spatrick     assert(!isTemplateImplicitInstantiation(D));
401e5dd7070Spatrick   }
402e5dd7070Spatrick 
403e5dd7070Spatrick   if (IsRef)
404e5dd7070Spatrick     Roles |= (unsigned)SymbolRole::Reference;
405e5dd7070Spatrick   else if (isDeclADefinition(OrigD, ContainerDC, *Ctx))
406e5dd7070Spatrick     Roles |= (unsigned)SymbolRole::Definition;
407e5dd7070Spatrick   else
408e5dd7070Spatrick     Roles |= (unsigned)SymbolRole::Declaration;
409e5dd7070Spatrick 
410e5dd7070Spatrick   D = getCanonicalDecl(D);
411e5dd7070Spatrick   Parent = adjustParent(Parent);
412e5dd7070Spatrick   if (Parent)
413e5dd7070Spatrick     Parent = getCanonicalDecl(Parent);
414e5dd7070Spatrick 
415e5dd7070Spatrick   SmallVector<SymbolRelation, 6> FinalRelations;
416e5dd7070Spatrick   FinalRelations.reserve(Relations.size()+1);
417e5dd7070Spatrick 
418e5dd7070Spatrick   auto addRelation = [&](SymbolRelation Rel) {
419e5dd7070Spatrick     auto It = llvm::find_if(FinalRelations, [&](SymbolRelation Elem) -> bool {
420e5dd7070Spatrick       return Elem.RelatedSymbol == Rel.RelatedSymbol;
421e5dd7070Spatrick     });
422e5dd7070Spatrick     if (It != FinalRelations.end()) {
423e5dd7070Spatrick       It->Roles |= Rel.Roles;
424e5dd7070Spatrick     } else {
425e5dd7070Spatrick       FinalRelations.push_back(Rel);
426e5dd7070Spatrick     }
427e5dd7070Spatrick     Roles |= Rel.Roles;
428e5dd7070Spatrick   };
429e5dd7070Spatrick 
430e5dd7070Spatrick   if (Parent) {
431e5dd7070Spatrick     if (IsRef || (!isa<ParmVarDecl>(D) && isFunctionLocalSymbol(D))) {
432e5dd7070Spatrick       addRelation(SymbolRelation{
433e5dd7070Spatrick         (unsigned)SymbolRole::RelationContainedBy,
434e5dd7070Spatrick         Parent
435e5dd7070Spatrick       });
436e5dd7070Spatrick     } else {
437e5dd7070Spatrick       addRelation(SymbolRelation{
438e5dd7070Spatrick         (unsigned)SymbolRole::RelationChildOf,
439e5dd7070Spatrick         Parent
440e5dd7070Spatrick       });
441e5dd7070Spatrick     }
442e5dd7070Spatrick   }
443e5dd7070Spatrick 
444e5dd7070Spatrick   for (auto &Rel : Relations) {
445e5dd7070Spatrick     addRelation(SymbolRelation(Rel.Roles,
446e5dd7070Spatrick                                Rel.RelatedSymbol->getCanonicalDecl()));
447e5dd7070Spatrick   }
448e5dd7070Spatrick 
449e5dd7070Spatrick   IndexDataConsumer::ASTNodeInfo Node{OrigE, OrigD, Parent, ContainerDC};
450e5dd7070Spatrick   return DataConsumer.handleDeclOccurrence(D, Roles, FinalRelations, Loc, Node);
451e5dd7070Spatrick }
452e5dd7070Spatrick 
handleMacroDefined(const IdentifierInfo & Name,SourceLocation Loc,const MacroInfo & MI)453e5dd7070Spatrick void IndexingContext::handleMacroDefined(const IdentifierInfo &Name,
454e5dd7070Spatrick                                          SourceLocation Loc,
455e5dd7070Spatrick                                          const MacroInfo &MI) {
456a9ac8606Spatrick   if (!shouldIndexMacroOccurrence(/*IsRef=*/false, Loc))
457a9ac8606Spatrick     return;
458e5dd7070Spatrick   SymbolRoleSet Roles = (unsigned)SymbolRole::Definition;
459e5dd7070Spatrick   DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc);
460e5dd7070Spatrick }
461e5dd7070Spatrick 
handleMacroUndefined(const IdentifierInfo & Name,SourceLocation Loc,const MacroInfo & MI)462e5dd7070Spatrick void IndexingContext::handleMacroUndefined(const IdentifierInfo &Name,
463e5dd7070Spatrick                                            SourceLocation Loc,
464e5dd7070Spatrick                                            const MacroInfo &MI) {
465a9ac8606Spatrick   if (!shouldIndexMacroOccurrence(/*IsRef=*/false, Loc))
466a9ac8606Spatrick     return;
467e5dd7070Spatrick   SymbolRoleSet Roles = (unsigned)SymbolRole::Undefinition;
468e5dd7070Spatrick   DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc);
469e5dd7070Spatrick }
470e5dd7070Spatrick 
handleMacroReference(const IdentifierInfo & Name,SourceLocation Loc,const MacroInfo & MI)471e5dd7070Spatrick void IndexingContext::handleMacroReference(const IdentifierInfo &Name,
472e5dd7070Spatrick                                            SourceLocation Loc,
473e5dd7070Spatrick                                            const MacroInfo &MI) {
474a9ac8606Spatrick   if (!shouldIndexMacroOccurrence(/*IsRef=*/true, Loc))
475a9ac8606Spatrick     return;
476e5dd7070Spatrick   SymbolRoleSet Roles = (unsigned)SymbolRole::Reference;
477e5dd7070Spatrick   DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc);
478e5dd7070Spatrick }
479a9ac8606Spatrick 
shouldIndexMacroOccurrence(bool IsRef,SourceLocation Loc)480a9ac8606Spatrick bool IndexingContext::shouldIndexMacroOccurrence(bool IsRef,
481a9ac8606Spatrick                                                  SourceLocation Loc) {
482a9ac8606Spatrick   if (!IndexOpts.IndexMacros)
483a9ac8606Spatrick     return false;
484a9ac8606Spatrick 
485a9ac8606Spatrick   switch (IndexOpts.SystemSymbolFilter) {
486a9ac8606Spatrick   case IndexingOptions::SystemSymbolFilterKind::None:
487a9ac8606Spatrick     break;
488a9ac8606Spatrick   case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
489a9ac8606Spatrick     if (!IsRef)
490a9ac8606Spatrick       return true;
491a9ac8606Spatrick     break;
492a9ac8606Spatrick   case IndexingOptions::SystemSymbolFilterKind::All:
493a9ac8606Spatrick     return true;
494a9ac8606Spatrick   }
495a9ac8606Spatrick 
496a9ac8606Spatrick   SourceManager &SM = Ctx->getSourceManager();
497a9ac8606Spatrick   FileID FID = SM.getFileID(SM.getFileLoc(Loc));
498a9ac8606Spatrick   if (FID.isInvalid())
499a9ac8606Spatrick     return false;
500a9ac8606Spatrick 
501a9ac8606Spatrick   bool Invalid = false;
502a9ac8606Spatrick   const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
503a9ac8606Spatrick   if (Invalid || !SEntry.isFile())
504a9ac8606Spatrick     return false;
505a9ac8606Spatrick 
506a9ac8606Spatrick   return SEntry.getFile().getFileCharacteristic() == SrcMgr::C_User;
507a9ac8606Spatrick }
508