1 //===- IndexingContext.cpp - Indexing context data ------------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "IndexingContext.h"
11 #include "clang/Index/IndexDataConsumer.h"
12 #include "clang/AST/ASTContext.h"
13 #include "clang/AST/DeclTemplate.h"
14 #include "clang/AST/DeclObjC.h"
15 #include "clang/Basic/SourceManager.h"
16
17 using namespace clang;
18 using namespace index;
19
shouldIndexFunctionLocalSymbols() const20 bool IndexingContext::shouldIndexFunctionLocalSymbols() const {
21 return IndexOpts.IndexFunctionLocals;
22 }
23
handleDecl(const Decl * D,SymbolRoleSet Roles,ArrayRef<SymbolRelation> Relations)24 bool IndexingContext::handleDecl(const Decl *D,
25 SymbolRoleSet Roles,
26 ArrayRef<SymbolRelation> Relations) {
27 return handleDeclOccurrence(D, D->getLocation(), /*IsRef=*/false,
28 cast<Decl>(D->getDeclContext()), Roles, Relations,
29 nullptr, nullptr, D->getDeclContext());
30 }
31
handleDecl(const Decl * D,SourceLocation Loc,SymbolRoleSet Roles,ArrayRef<SymbolRelation> Relations,const DeclContext * DC)32 bool IndexingContext::handleDecl(const Decl *D, SourceLocation Loc,
33 SymbolRoleSet Roles,
34 ArrayRef<SymbolRelation> Relations,
35 const DeclContext *DC) {
36 if (!DC)
37 DC = D->getDeclContext();
38 return handleDeclOccurrence(D, Loc, /*IsRef=*/false, cast<Decl>(DC),
39 Roles, Relations,
40 nullptr, nullptr, DC);
41 }
42
handleReference(const NamedDecl * D,SourceLocation Loc,const NamedDecl * Parent,const DeclContext * DC,SymbolRoleSet Roles,ArrayRef<SymbolRelation> Relations,const Expr * RefE,const Decl * RefD)43 bool IndexingContext::handleReference(const NamedDecl *D, SourceLocation Loc,
44 const NamedDecl *Parent,
45 const DeclContext *DC,
46 SymbolRoleSet Roles,
47 ArrayRef<SymbolRelation> Relations,
48 const Expr *RefE,
49 const Decl *RefD) {
50 if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalDecl(D))
51 return true;
52
53 if (isa<NonTypeTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D))
54 return true;
55
56 return handleDeclOccurrence(D, Loc, /*IsRef=*/true, Parent, Roles, Relations,
57 RefE, RefD, DC);
58 }
59
importedModule(const ImportDecl * ImportD)60 bool IndexingContext::importedModule(const ImportDecl *ImportD) {
61 SourceLocation Loc;
62 auto IdLocs = ImportD->getIdentifierLocs();
63 if (!IdLocs.empty())
64 Loc = IdLocs.front();
65 else
66 Loc = ImportD->getLocation();
67 SourceManager &SM = Ctx->getSourceManager();
68 Loc = SM.getFileLoc(Loc);
69 if (Loc.isInvalid())
70 return true;
71
72 FileID FID;
73 unsigned Offset;
74 std::tie(FID, Offset) = SM.getDecomposedLoc(Loc);
75 if (FID.isInvalid())
76 return true;
77
78 bool Invalid = false;
79 const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
80 if (Invalid || !SEntry.isFile())
81 return true;
82
83 if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
84 switch (IndexOpts.SystemSymbolFilter) {
85 case IndexingOptions::SystemSymbolFilterKind::None:
86 return true;
87 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
88 case IndexingOptions::SystemSymbolFilterKind::All:
89 break;
90 }
91 }
92
93 SymbolRoleSet Roles = (unsigned)SymbolRole::Declaration;
94 if (ImportD->isImplicit())
95 Roles |= (unsigned)SymbolRole::Implicit;
96
97 return DataConsumer.handleModuleOccurence(ImportD, Roles, FID, Offset);
98 }
99
isFunctionLocalDecl(const Decl * D)100 bool IndexingContext::isFunctionLocalDecl(const Decl *D) {
101 assert(D);
102
103 if (isa<TemplateTemplateParmDecl>(D))
104 return true;
105
106 if (isa<ObjCTypeParamDecl>(D))
107 return true;
108
109 if (!D->getParentFunctionOrMethod())
110 return false;
111
112 if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
113 switch (ND->getFormalLinkage()) {
114 case NoLinkage:
115 case VisibleNoLinkage:
116 case InternalLinkage:
117 return true;
118 case UniqueExternalLinkage:
119 llvm_unreachable("Not a sema linkage");
120 case ExternalLinkage:
121 return false;
122 }
123 }
124
125 return true;
126 }
127
isTemplateImplicitInstantiation(const Decl * D)128 bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) {
129 TemplateSpecializationKind TKind = TSK_Undeclared;
130 if (const ClassTemplateSpecializationDecl *
131 SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
132 TKind = SD->getSpecializationKind();
133 }
134 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
135 TKind = FD->getTemplateSpecializationKind();
136 }
137 switch (TKind) {
138 case TSK_Undeclared:
139 case TSK_ExplicitSpecialization:
140 return false;
141 case TSK_ImplicitInstantiation:
142 case TSK_ExplicitInstantiationDeclaration:
143 case TSK_ExplicitInstantiationDefinition:
144 return true;
145 }
146 llvm_unreachable("invalid TemplateSpecializationKind");
147 }
148
shouldIgnoreIfImplicit(const Decl * D)149 bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) {
150 if (isa<ObjCInterfaceDecl>(D))
151 return false;
152 if (isa<ObjCCategoryDecl>(D))
153 return false;
154 if (isa<ObjCIvarDecl>(D))
155 return false;
156 if (isa<ObjCMethodDecl>(D))
157 return false;
158 if (isa<ImportDecl>(D))
159 return false;
160 return true;
161 }
162
adjustTemplateImplicitInstantiation(const Decl * D)163 static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) {
164 if (const ClassTemplateSpecializationDecl *
165 SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
166 return SD->getTemplateInstantiationPattern();
167 }
168 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
169 return FD->getTemplateInstantiationPattern();
170 }
171 return nullptr;
172 }
173
isDeclADefinition(const Decl * D,const DeclContext * ContainerDC,ASTContext & Ctx)174 static bool isDeclADefinition(const Decl *D, const DeclContext *ContainerDC, ASTContext &Ctx) {
175 if (auto VD = dyn_cast<VarDecl>(D))
176 return VD->isThisDeclarationADefinition(Ctx);
177
178 if (auto FD = dyn_cast<FunctionDecl>(D))
179 return FD->isThisDeclarationADefinition();
180
181 if (auto TD = dyn_cast<TagDecl>(D))
182 return TD->isThisDeclarationADefinition();
183
184 if (auto MD = dyn_cast<ObjCMethodDecl>(D))
185 return MD->isThisDeclarationADefinition() || isa<ObjCImplDecl>(ContainerDC);
186
187 if (isa<TypedefNameDecl>(D) ||
188 isa<EnumConstantDecl>(D) ||
189 isa<FieldDecl>(D) ||
190 isa<MSPropertyDecl>(D) ||
191 isa<ObjCImplDecl>(D) ||
192 isa<ObjCPropertyImplDecl>(D))
193 return true;
194
195 return false;
196 }
197
adjustParent(const Decl * Parent)198 static const Decl *adjustParent(const Decl *Parent) {
199 if (!Parent)
200 return nullptr;
201 for (;; Parent = cast<Decl>(Parent->getDeclContext())) {
202 if (isa<TranslationUnitDecl>(Parent))
203 return nullptr;
204 if (isa<LinkageSpecDecl>(Parent) || isa<BlockDecl>(Parent))
205 continue;
206 if (auto NS = dyn_cast<NamespaceDecl>(Parent)) {
207 if (NS->isAnonymousNamespace())
208 continue;
209 } else if (auto RD = dyn_cast<RecordDecl>(Parent)) {
210 if (RD->isAnonymousStructOrUnion())
211 continue;
212 } else if (auto FD = dyn_cast<FieldDecl>(Parent)) {
213 if (FD->getDeclName().isEmpty())
214 continue;
215 }
216 return Parent;
217 }
218 }
219
getCanonicalDecl(const Decl * D)220 static const Decl *getCanonicalDecl(const Decl *D) {
221 D = D->getCanonicalDecl();
222 if (auto TD = dyn_cast<TemplateDecl>(D)) {
223 D = TD->getTemplatedDecl();
224 assert(D->isCanonicalDecl());
225 }
226
227 return D;
228 }
229
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)230 bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc,
231 bool IsRef, const Decl *Parent,
232 SymbolRoleSet Roles,
233 ArrayRef<SymbolRelation> Relations,
234 const Expr *OrigE,
235 const Decl *OrigD,
236 const DeclContext *ContainerDC) {
237 if (D->isImplicit() && !isa<ObjCMethodDecl>(D))
238 return true;
239 if (!isa<NamedDecl>(D) ||
240 (cast<NamedDecl>(D)->getDeclName().isEmpty() &&
241 !isa<TagDecl>(D) && !isa<ObjCCategoryDecl>(D)))
242 return true;
243
244 SourceManager &SM = Ctx->getSourceManager();
245 Loc = SM.getFileLoc(Loc);
246 if (Loc.isInvalid())
247 return true;
248
249 FileID FID;
250 unsigned Offset;
251 std::tie(FID, Offset) = SM.getDecomposedLoc(Loc);
252 if (FID.isInvalid())
253 return true;
254
255 bool Invalid = false;
256 const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
257 if (Invalid || !SEntry.isFile())
258 return true;
259
260 if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
261 switch (IndexOpts.SystemSymbolFilter) {
262 case IndexingOptions::SystemSymbolFilterKind::None:
263 return true;
264 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
265 if (IsRef)
266 return true;
267 break;
268 case IndexingOptions::SystemSymbolFilterKind::All:
269 break;
270 }
271 }
272
273 if (isTemplateImplicitInstantiation(D)) {
274 if (!IsRef)
275 return true;
276 D = adjustTemplateImplicitInstantiation(D);
277 if (!D)
278 return true;
279 assert(!isTemplateImplicitInstantiation(D));
280 }
281
282 if (!OrigD)
283 OrigD = D;
284
285 if (IsRef)
286 Roles |= (unsigned)SymbolRole::Reference;
287 else if (isDeclADefinition(D, ContainerDC, *Ctx))
288 Roles |= (unsigned)SymbolRole::Definition;
289 else
290 Roles |= (unsigned)SymbolRole::Declaration;
291
292 D = getCanonicalDecl(D);
293 if (D->isImplicit() && !isa<ObjCMethodDecl>(D) &&
294 !(isa<FunctionDecl>(D) && cast<FunctionDecl>(D)->getBuiltinID())) {
295 // operator new declarations will link to the implicit one as canonical.
296 return true;
297 }
298 Parent = adjustParent(Parent);
299 if (Parent)
300 Parent = getCanonicalDecl(Parent);
301 assert((!Parent || !Parent->isImplicit() ||
302 (isa<FunctionDecl>(Parent) &&
303 cast<FunctionDecl>(Parent)->getBuiltinID()) ||
304 isa<ObjCInterfaceDecl>(Parent) || isa<ObjCMethodDecl>(Parent)) &&
305 "unexpected implicit parent!");
306
307 SmallVector<SymbolRelation, 6> FinalRelations;
308 FinalRelations.reserve(Relations.size()+1);
309
310 auto addRelation = [&](SymbolRelation Rel) {
311 auto It = std::find_if(FinalRelations.begin(), FinalRelations.end(),
312 [&](SymbolRelation Elem)->bool {
313 return Elem.RelatedSymbol == Rel.RelatedSymbol;
314 });
315 if (It != FinalRelations.end()) {
316 It->Roles |= Rel.Roles;
317 } else {
318 FinalRelations.push_back(Rel);
319 }
320 Roles |= Rel.Roles;
321 };
322
323 if (!IsRef && Parent && !cast<DeclContext>(Parent)->isFunctionOrMethod()) {
324 addRelation(SymbolRelation{(unsigned)SymbolRole::RelationChildOf, Parent});
325 }
326 for (auto &Rel : Relations) {
327 addRelation(SymbolRelation(Rel.Roles,
328 Rel.RelatedSymbol->getCanonicalDecl()));
329 }
330
331 IndexDataConsumer::ASTNodeInfo Node{ OrigE, OrigD, Parent, ContainerDC };
332 return DataConsumer.handleDeclOccurence(D, Roles, FinalRelations, FID, Offset,
333 Node);
334 }
335