1 | //===- CXIndexDataConsumer.cpp - Index data consumer for libclang----------===// |
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 "CXIndexDataConsumer.h" |
10 | #include "CIndexDiagnostic.h" |
11 | #include "CXFile.h" |
12 | #include "CXTranslationUnit.h" |
13 | #include "clang/AST/Attr.h" |
14 | #include "clang/AST/DeclCXX.h" |
15 | #include "clang/AST/DeclTemplate.h" |
16 | #include "clang/AST/DeclVisitor.h" |
17 | #include "clang/Frontend/ASTUnit.h" |
18 | |
19 | using namespace clang; |
20 | using namespace clang::index; |
21 | using namespace cxindex; |
22 | using namespace cxcursor; |
23 | |
24 | namespace { |
25 | class IndexingDeclVisitor : public ConstDeclVisitor<IndexingDeclVisitor, bool> { |
26 | CXIndexDataConsumer &DataConsumer; |
27 | SourceLocation DeclLoc; |
28 | const DeclContext *LexicalDC; |
29 | |
30 | public: |
31 | IndexingDeclVisitor(CXIndexDataConsumer &dataConsumer, SourceLocation Loc, |
32 | const DeclContext *lexicalDC) |
33 | : DataConsumer(dataConsumer), DeclLoc(Loc), LexicalDC(lexicalDC) { } |
34 | |
35 | bool VisitFunctionDecl(const FunctionDecl *D) { |
36 | DataConsumer.handleFunction(FD: D); |
37 | return true; |
38 | } |
39 | |
40 | bool VisitVarDecl(const VarDecl *D) { |
41 | DataConsumer.handleVar(D); |
42 | return true; |
43 | } |
44 | |
45 | bool VisitFieldDecl(const FieldDecl *D) { |
46 | DataConsumer.handleField(D); |
47 | return true; |
48 | } |
49 | |
50 | bool VisitMSPropertyDecl(const MSPropertyDecl *D) { |
51 | return true; |
52 | } |
53 | |
54 | bool VisitEnumConstantDecl(const EnumConstantDecl *D) { |
55 | DataConsumer.handleEnumerator(D); |
56 | return true; |
57 | } |
58 | |
59 | bool VisitTypedefNameDecl(const TypedefNameDecl *D) { |
60 | DataConsumer.handleTypedefName(D); |
61 | return true; |
62 | } |
63 | |
64 | bool VisitTagDecl(const TagDecl *D) { |
65 | DataConsumer.handleTagDecl(D); |
66 | return true; |
67 | } |
68 | |
69 | bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) { |
70 | DataConsumer.handleObjCInterface(D); |
71 | return true; |
72 | } |
73 | |
74 | bool VisitObjCProtocolDecl(const ObjCProtocolDecl *D) { |
75 | DataConsumer.handleObjCProtocol(D); |
76 | return true; |
77 | } |
78 | |
79 | bool VisitObjCImplementationDecl(const ObjCImplementationDecl *D) { |
80 | DataConsumer.handleObjCImplementation(D); |
81 | return true; |
82 | } |
83 | |
84 | bool VisitObjCCategoryDecl(const ObjCCategoryDecl *D) { |
85 | DataConsumer.handleObjCCategory(D); |
86 | return true; |
87 | } |
88 | |
89 | bool VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D) { |
90 | DataConsumer.handleObjCCategoryImpl(D); |
91 | return true; |
92 | } |
93 | |
94 | bool VisitObjCMethodDecl(const ObjCMethodDecl *D) { |
95 | if (isa<ObjCImplDecl>(Val: LexicalDC) && !D->isThisDeclarationADefinition()) |
96 | DataConsumer.handleSynthesizedObjCMethod(D, Loc: DeclLoc, LexicalDC); |
97 | else |
98 | DataConsumer.handleObjCMethod(D, Loc: DeclLoc); |
99 | return true; |
100 | } |
101 | |
102 | bool VisitObjCPropertyDecl(const ObjCPropertyDecl *D) { |
103 | DataConsumer.handleObjCProperty(D); |
104 | return true; |
105 | } |
106 | |
107 | bool VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) { |
108 | DataConsumer.handleSynthesizedObjCProperty(D); |
109 | return true; |
110 | } |
111 | |
112 | bool VisitNamespaceDecl(const NamespaceDecl *D) { |
113 | DataConsumer.handleNamespace(D); |
114 | return true; |
115 | } |
116 | |
117 | bool VisitUsingDecl(const UsingDecl *D) { |
118 | return true; |
119 | } |
120 | |
121 | bool VisitUsingDirectiveDecl(const UsingDirectiveDecl *D) { |
122 | return true; |
123 | } |
124 | |
125 | bool VisitClassTemplateDecl(const ClassTemplateDecl *D) { |
126 | DataConsumer.handleClassTemplate(D); |
127 | return true; |
128 | } |
129 | |
130 | bool VisitClassTemplateSpecializationDecl(const |
131 | ClassTemplateSpecializationDecl *D) { |
132 | DataConsumer.handleTagDecl(D); |
133 | return true; |
134 | } |
135 | |
136 | bool VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) { |
137 | DataConsumer.handleFunctionTemplate(D); |
138 | return true; |
139 | } |
140 | |
141 | bool VisitTypeAliasTemplateDecl(const TypeAliasTemplateDecl *D) { |
142 | DataConsumer.handleTypeAliasTemplate(D); |
143 | return true; |
144 | } |
145 | |
146 | bool VisitImportDecl(const ImportDecl *D) { |
147 | DataConsumer.importedModule(ImportD: D); |
148 | return true; |
149 | } |
150 | |
151 | bool VisitConceptDecl(const ConceptDecl *D) { |
152 | DataConsumer.handleConcept(D); |
153 | return true; |
154 | } |
155 | }; |
156 | |
157 | CXSymbolRole getSymbolRole(SymbolRoleSet Role) { |
158 | // CXSymbolRole mirrors low 9 bits of clang::index::SymbolRole. |
159 | return CXSymbolRole(static_cast<uint32_t>(Role) & ((1 << 9) - 1)); |
160 | } |
161 | } |
162 | |
163 | bool CXIndexDataConsumer::handleDeclOccurrence( |
164 | const Decl *D, SymbolRoleSet Roles, ArrayRef<SymbolRelation> Relations, |
165 | SourceLocation Loc, ASTNodeInfo ASTNode) { |
166 | Loc = getASTContext().getSourceManager().getFileLoc(Loc); |
167 | |
168 | if (Roles & (unsigned)SymbolRole::Reference) { |
169 | const NamedDecl *ND = dyn_cast<NamedDecl>(Val: D); |
170 | if (!ND) |
171 | return true; |
172 | |
173 | if (auto *ObjCID = dyn_cast_or_null<ObjCInterfaceDecl>(Val: ASTNode.OrigD)) { |
174 | if (!ObjCID->isThisDeclarationADefinition() && |
175 | ObjCID->getLocation() == Loc) { |
176 | // The libclang API treats this as ObjCClassRef declaration. |
177 | IndexingDeclVisitor(*this, Loc, nullptr).Visit(ObjCID); |
178 | return true; |
179 | } |
180 | } |
181 | if (auto *ObjCPD = dyn_cast_or_null<ObjCProtocolDecl>(Val: ASTNode.OrigD)) { |
182 | if (!ObjCPD->isThisDeclarationADefinition() && |
183 | ObjCPD->getLocation() == Loc) { |
184 | // The libclang API treats this as ObjCProtocolRef declaration. |
185 | IndexingDeclVisitor(*this, Loc, nullptr).Visit(ObjCPD); |
186 | return true; |
187 | } |
188 | } |
189 | |
190 | CXIdxEntityRefKind Kind = CXIdxEntityRef_Direct; |
191 | if (Roles & (unsigned)SymbolRole::Implicit) { |
192 | Kind = CXIdxEntityRef_Implicit; |
193 | } |
194 | CXSymbolRole CXRole = getSymbolRole(Role: Roles); |
195 | |
196 | CXCursor Cursor; |
197 | if (ASTNode.OrigE) { |
198 | Cursor = cxcursor::MakeCXCursor(ASTNode.OrigE, |
199 | cast<Decl>(Val: ASTNode.ContainerDC), |
200 | getCXTU()); |
201 | } else { |
202 | if (ASTNode.OrigD) { |
203 | if (auto *OrigND = dyn_cast<NamedDecl>(Val: ASTNode.OrigD)) |
204 | Cursor = getRefCursor(D: OrigND, Loc); |
205 | else |
206 | Cursor = MakeCXCursor(D: ASTNode.OrigD, TU: CXTU); |
207 | } else { |
208 | Cursor = getRefCursor(D: ND, Loc); |
209 | } |
210 | } |
211 | handleReference(D: ND, Loc, Cursor, |
212 | Parent: dyn_cast_or_null<NamedDecl>(Val: ASTNode.Parent), |
213 | DC: ASTNode.ContainerDC, E: ASTNode.OrigE, Kind, Role: CXRole); |
214 | |
215 | } else { |
216 | const DeclContext *LexicalDC = ASTNode.ContainerDC; |
217 | if (!LexicalDC) { |
218 | for (const auto &SymRel : Relations) { |
219 | if (SymRel.Roles & (unsigned)SymbolRole::RelationChildOf) |
220 | LexicalDC = dyn_cast<DeclContext>(Val: SymRel.RelatedSymbol); |
221 | } |
222 | } |
223 | IndexingDeclVisitor(*this, Loc, LexicalDC).Visit(ASTNode.OrigD); |
224 | } |
225 | |
226 | return !shouldAbort(); |
227 | } |
228 | |
229 | bool CXIndexDataConsumer::handleModuleOccurrence(const ImportDecl *ImportD, |
230 | const Module *Mod, |
231 | SymbolRoleSet Roles, |
232 | SourceLocation Loc) { |
233 | if (Roles & (SymbolRoleSet)SymbolRole::Declaration) |
234 | IndexingDeclVisitor(*this, SourceLocation(), nullptr).Visit(ImportD); |
235 | return !shouldAbort(); |
236 | } |
237 | |
238 | void CXIndexDataConsumer::finish() { |
239 | indexDiagnostics(); |
240 | } |
241 | |
242 | |
243 | CXIndexDataConsumer::ObjCProtocolListInfo::ObjCProtocolListInfo( |
244 | const ObjCProtocolList &ProtList, |
245 | CXIndexDataConsumer &IdxCtx, |
246 | ScratchAlloc &SA) { |
247 | ObjCInterfaceDecl::protocol_loc_iterator LI = ProtList.loc_begin(); |
248 | for (ObjCInterfaceDecl::protocol_iterator |
249 | I = ProtList.begin(), E = ProtList.end(); I != E; ++I, ++LI) { |
250 | SourceLocation Loc = *LI; |
251 | ObjCProtocolDecl *PD = *I; |
252 | ProtEntities.push_back(Elt: EntityInfo()); |
253 | IdxCtx.getEntityInfo(PD, ProtEntities.back(), SA); |
254 | CXIdxObjCProtocolRefInfo ProtInfo = { .protocol: nullptr, |
255 | .cursor: MakeCursorObjCProtocolRef(Proto: PD, Loc, TU: IdxCtx.CXTU), |
256 | .loc: IdxCtx.getIndexLoc(Loc) }; |
257 | ProtInfos.push_back(Elt: ProtInfo); |
258 | |
259 | if (IdxCtx.shouldSuppressRefs()) |
260 | IdxCtx.markEntityOccurrenceInFile(PD, Loc); |
261 | } |
262 | |
263 | for (unsigned i = 0, e = ProtInfos.size(); i != e; ++i) |
264 | ProtInfos[i].protocol = &ProtEntities[i]; |
265 | |
266 | for (unsigned i = 0, e = ProtInfos.size(); i != e; ++i) |
267 | Prots.push_back(Elt: &ProtInfos[i]); |
268 | } |
269 | |
270 | |
271 | IBOutletCollectionInfo::IBOutletCollectionInfo( |
272 | const IBOutletCollectionInfo &other) |
273 | : AttrInfo(CXIdxAttr_IBOutletCollection, other.cursor, other.loc, other.A) { |
274 | |
275 | IBCollInfo.attrInfo = this; |
276 | IBCollInfo.classCursor = other.IBCollInfo.classCursor; |
277 | IBCollInfo.classLoc = other.IBCollInfo.classLoc; |
278 | if (other.IBCollInfo.objcClass) { |
279 | ClassInfo = other.ClassInfo; |
280 | IBCollInfo.objcClass = &ClassInfo; |
281 | } else |
282 | IBCollInfo.objcClass = nullptr; |
283 | } |
284 | |
285 | AttrListInfo::AttrListInfo(const Decl *D, CXIndexDataConsumer &IdxCtx) |
286 | : SA(IdxCtx), ref_cnt(0) { |
287 | |
288 | if (!D->hasAttrs()) |
289 | return; |
290 | |
291 | for (const auto *A : D->attrs()) { |
292 | CXCursor C = MakeCXCursor(A, D, IdxCtx.CXTU); |
293 | CXIdxLoc Loc = IdxCtx.getIndexLoc(A->getLocation()); |
294 | switch (C.kind) { |
295 | default: |
296 | Attrs.push_back(AttrInfo(CXIdxAttr_Unexposed, C, Loc, A)); |
297 | break; |
298 | case CXCursor_IBActionAttr: |
299 | Attrs.push_back(AttrInfo(CXIdxAttr_IBAction, C, Loc, A)); |
300 | break; |
301 | case CXCursor_IBOutletAttr: |
302 | Attrs.push_back(AttrInfo(CXIdxAttr_IBOutlet, C, Loc, A)); |
303 | break; |
304 | case CXCursor_IBOutletCollectionAttr: |
305 | IBCollAttrs.push_back(IBOutletCollectionInfo(C, Loc, A)); |
306 | break; |
307 | } |
308 | } |
309 | |
310 | for (unsigned i = 0, e = IBCollAttrs.size(); i != e; ++i) { |
311 | IBOutletCollectionInfo &IBInfo = IBCollAttrs[i]; |
312 | CXAttrs.push_back(Elt: &IBInfo); |
313 | |
314 | const IBOutletCollectionAttr * |
315 | IBAttr = cast<IBOutletCollectionAttr>(IBInfo.A); |
316 | SourceLocation InterfaceLocStart = |
317 | IBAttr->getInterfaceLoc()->getTypeLoc().getBeginLoc(); |
318 | IBInfo.IBCollInfo.attrInfo = &IBInfo; |
319 | IBInfo.IBCollInfo.classLoc = IdxCtx.getIndexLoc(Loc: InterfaceLocStart); |
320 | IBInfo.IBCollInfo.objcClass = nullptr; |
321 | IBInfo.IBCollInfo.classCursor = clang_getNullCursor(); |
322 | QualType Ty = IBAttr->getInterface(); |
323 | if (const ObjCObjectType *ObjectTy = Ty->getAs<ObjCObjectType>()) { |
324 | if (const ObjCInterfaceDecl *InterD = ObjectTy->getInterface()) { |
325 | IdxCtx.getEntityInfo(InterD, IBInfo.ClassInfo, SA); |
326 | IBInfo.IBCollInfo.objcClass = &IBInfo.ClassInfo; |
327 | IBInfo.IBCollInfo.classCursor = |
328 | MakeCursorObjCClassRef(Class: InterD, Loc: InterfaceLocStart, TU: IdxCtx.CXTU); |
329 | } |
330 | } |
331 | } |
332 | |
333 | for (unsigned i = 0, e = Attrs.size(); i != e; ++i) |
334 | CXAttrs.push_back(Elt: &Attrs[i]); |
335 | } |
336 | |
337 | IntrusiveRefCntPtr<AttrListInfo> |
338 | AttrListInfo::create(const Decl *D, CXIndexDataConsumer &IdxCtx) { |
339 | ScratchAlloc SA(IdxCtx); |
340 | AttrListInfo *attrs = SA.allocate<AttrListInfo>(); |
341 | return new (attrs) AttrListInfo(D, IdxCtx); |
342 | } |
343 | |
344 | CXIndexDataConsumer::CXXBasesListInfo::CXXBasesListInfo(const CXXRecordDecl *D, |
345 | CXIndexDataConsumer &IdxCtx, |
346 | ScratchAlloc &SA) { |
347 | for (const auto &Base : D->bases()) { |
348 | BaseEntities.push_back(Elt: EntityInfo()); |
349 | const NamedDecl *BaseD = nullptr; |
350 | QualType T = Base.getType(); |
351 | SourceLocation Loc = getBaseLoc(Base); |
352 | |
353 | if (const TypedefType *TDT = T->getAs<TypedefType>()) { |
354 | BaseD = TDT->getDecl(); |
355 | } else if (const TemplateSpecializationType * |
356 | TST = T->getAs<TemplateSpecializationType>()) { |
357 | BaseD = TST->getTemplateName().getAsTemplateDecl(); |
358 | } else if (const RecordType *RT = T->getAs<RecordType>()) { |
359 | BaseD = RT->getDecl(); |
360 | } |
361 | |
362 | if (BaseD) |
363 | IdxCtx.getEntityInfo(D: BaseD, EntityInfo&: BaseEntities.back(), SA); |
364 | CXIdxBaseClassInfo BaseInfo = { .base: nullptr, |
365 | .cursor: MakeCursorCXXBaseSpecifier(B: &Base, TU: IdxCtx.CXTU), |
366 | .loc: IdxCtx.getIndexLoc(Loc) }; |
367 | BaseInfos.push_back(Elt: BaseInfo); |
368 | } |
369 | |
370 | for (unsigned i = 0, e = BaseInfos.size(); i != e; ++i) { |
371 | if (BaseEntities[i].name && BaseEntities[i].USR) |
372 | BaseInfos[i].base = &BaseEntities[i]; |
373 | } |
374 | |
375 | for (unsigned i = 0, e = BaseInfos.size(); i != e; ++i) |
376 | CXBases.push_back(Elt: &BaseInfos[i]); |
377 | } |
378 | |
379 | SourceLocation CXIndexDataConsumer::CXXBasesListInfo::getBaseLoc( |
380 | const CXXBaseSpecifier &Base) const { |
381 | SourceLocation Loc = Base.getSourceRange().getBegin(); |
382 | TypeLoc TL; |
383 | if (Base.getTypeSourceInfo()) |
384 | TL = Base.getTypeSourceInfo()->getTypeLoc(); |
385 | if (TL.isNull()) |
386 | return Loc; |
387 | |
388 | if (QualifiedTypeLoc QL = TL.getAs<QualifiedTypeLoc>()) |
389 | TL = QL.getUnqualifiedLoc(); |
390 | |
391 | if (ElaboratedTypeLoc EL = TL.getAs<ElaboratedTypeLoc>()) |
392 | return EL.getNamedTypeLoc().getBeginLoc(); |
393 | if (DependentNameTypeLoc DL = TL.getAs<DependentNameTypeLoc>()) |
394 | return DL.getNameLoc(); |
395 | if (DependentTemplateSpecializationTypeLoc DTL = |
396 | TL.getAs<DependentTemplateSpecializationTypeLoc>()) |
397 | return DTL.getTemplateNameLoc(); |
398 | |
399 | return Loc; |
400 | } |
401 | |
402 | const char *ScratchAlloc::toCStr(StringRef Str) { |
403 | if (Str.empty()) |
404 | return "" ; |
405 | if (Str.data()[Str.size()] == '\0') |
406 | return Str.data(); |
407 | return copyCStr(Str); |
408 | } |
409 | |
410 | const char *ScratchAlloc::copyCStr(StringRef Str) { |
411 | char *buf = IdxCtx.StrScratch.Allocate<char>(Num: Str.size() + 1); |
412 | std::uninitialized_copy(first: Str.begin(), last: Str.end(), result: buf); |
413 | buf[Str.size()] = '\0'; |
414 | return buf; |
415 | } |
416 | |
417 | void CXIndexDataConsumer::setASTContext(ASTContext &ctx) { |
418 | Ctx = &ctx; |
419 | cxtu::getASTUnit(TU: CXTU)->setASTContext(&ctx); |
420 | } |
421 | |
422 | void CXIndexDataConsumer::setPreprocessor(std::shared_ptr<Preprocessor> PP) { |
423 | cxtu::getASTUnit(TU: CXTU)->setPreprocessor(std::move(PP)); |
424 | } |
425 | |
426 | bool CXIndexDataConsumer::isFunctionLocalDecl(const Decl *D) { |
427 | assert(D); |
428 | |
429 | if (!D->getParentFunctionOrMethod()) |
430 | return false; |
431 | |
432 | if (const NamedDecl *ND = dyn_cast<NamedDecl>(Val: D)) { |
433 | switch (ND->getFormalLinkage()) { |
434 | case Linkage::Invalid: |
435 | llvm_unreachable("Linkage hasn't been computed!" ); |
436 | case Linkage::None: |
437 | case Linkage::Internal: |
438 | return true; |
439 | case Linkage::VisibleNone: |
440 | case Linkage::UniqueExternal: |
441 | llvm_unreachable("Not a sema linkage" ); |
442 | case Linkage::Module: |
443 | case Linkage::External: |
444 | return false; |
445 | } |
446 | } |
447 | |
448 | return true; |
449 | } |
450 | |
451 | bool CXIndexDataConsumer::shouldAbort() { |
452 | if (!CB.abortQuery) |
453 | return false; |
454 | return CB.abortQuery(ClientData, nullptr); |
455 | } |
456 | |
457 | void CXIndexDataConsumer::enteredMainFile(OptionalFileEntryRef File) { |
458 | if (File && CB.enteredMainFile) { |
459 | CXIdxClientFile idxFile = |
460 | CB.enteredMainFile(ClientData, cxfile::makeCXFile(FE: *File), nullptr); |
461 | FileMap[*File] = idxFile; |
462 | } |
463 | } |
464 | |
465 | void CXIndexDataConsumer::ppIncludedFile(SourceLocation hashLoc, |
466 | StringRef filename, |
467 | OptionalFileEntryRef File, |
468 | bool isImport, bool isAngled, |
469 | bool isModuleImport) { |
470 | if (!CB.ppIncludedFile) |
471 | return; |
472 | |
473 | const FileEntry *FE = File ? &File->getFileEntry() : nullptr; |
474 | |
475 | ScratchAlloc SA(*this); |
476 | CXIdxIncludedFileInfo Info = { .hashLoc: getIndexLoc(Loc: hashLoc), |
477 | .filename: SA.toCStr(Str: filename), |
478 | .file: cxfile::makeCXFile(FE: File), |
479 | .isImport: isImport, .isAngled: isAngled, .isModuleImport: isModuleImport }; |
480 | CXIdxClientFile idxFile = CB.ppIncludedFile(ClientData, &Info); |
481 | FileMap[FE] = idxFile; |
482 | } |
483 | |
484 | void CXIndexDataConsumer::importedModule(const ImportDecl *ImportD) { |
485 | if (!CB.importedASTFile) |
486 | return; |
487 | |
488 | Module *Mod = ImportD->getImportedModule(); |
489 | if (!Mod) |
490 | return; |
491 | |
492 | // If the imported module is part of the top-level module that we're |
493 | // indexing, it doesn't correspond to an imported AST file. |
494 | // FIXME: This assumes that AST files and top-level modules directly |
495 | // correspond, which is unlikely to remain true forever. |
496 | if (Module *SrcMod = ImportD->getImportedOwningModule()) |
497 | if (SrcMod->getTopLevelModule() == Mod->getTopLevelModule()) |
498 | return; |
499 | |
500 | OptionalFileEntryRef FE = Mod->getASTFile(); |
501 | CXIdxImportedASTFileInfo Info = {cxfile::makeCXFile(FE), Mod, |
502 | getIndexLoc(Loc: ImportD->getLocation()), |
503 | ImportD->isImplicit()}; |
504 | CXIdxClientASTFile astFile = CB.importedASTFile(ClientData, &Info); |
505 | (void)astFile; |
506 | } |
507 | |
508 | void CXIndexDataConsumer::importedPCH(FileEntryRef File) { |
509 | if (!CB.importedASTFile) |
510 | return; |
511 | |
512 | CXIdxImportedASTFileInfo Info = { |
513 | .file: cxfile::makeCXFile(FE: File), |
514 | /*module=*/nullptr, |
515 | .loc: getIndexLoc(Loc: SourceLocation()), |
516 | /*isImplicit=*/false |
517 | }; |
518 | CXIdxClientASTFile astFile = CB.importedASTFile(ClientData, &Info); |
519 | (void)astFile; |
520 | } |
521 | |
522 | void CXIndexDataConsumer::startedTranslationUnit() { |
523 | CXIdxClientContainer idxCont = nullptr; |
524 | if (CB.startedTranslationUnit) |
525 | idxCont = CB.startedTranslationUnit(ClientData, nullptr); |
526 | addContainerInMap(Ctx->getTranslationUnitDecl(), idxCont); |
527 | } |
528 | |
529 | void CXIndexDataConsumer::indexDiagnostics() { |
530 | if (!hasDiagnosticCallback()) |
531 | return; |
532 | |
533 | CXDiagnosticSetImpl *DiagSet = cxdiag::lazyCreateDiags(TU: getCXTU()); |
534 | handleDiagnosticSet(CXDiagSet: DiagSet); |
535 | } |
536 | |
537 | void CXIndexDataConsumer::handleDiagnosticSet(CXDiagnostic CXDiagSet) { |
538 | if (!CB.diagnostic) |
539 | return; |
540 | |
541 | CB.diagnostic(ClientData, CXDiagSet, nullptr); |
542 | } |
543 | |
544 | bool CXIndexDataConsumer::handleDecl(const NamedDecl *D, |
545 | SourceLocation Loc, CXCursor Cursor, |
546 | DeclInfo &DInfo, |
547 | const DeclContext *LexicalDC, |
548 | const DeclContext *SemaDC) { |
549 | if (!CB.indexDeclaration || !D) |
550 | return false; |
551 | if (D->isImplicit() && shouldIgnoreIfImplicit(D)) |
552 | return false; |
553 | |
554 | ScratchAlloc SA(*this); |
555 | getEntityInfo(D, EntityInfo&: DInfo.EntInfo, SA); |
556 | if ((!shouldIndexFunctionLocalSymbols() && !DInfo.EntInfo.USR) |
557 | || Loc.isInvalid()) |
558 | return false; |
559 | |
560 | if (!LexicalDC) |
561 | LexicalDC = D->getLexicalDeclContext(); |
562 | |
563 | if (shouldSuppressRefs()) |
564 | markEntityOccurrenceInFile(D, Loc); |
565 | |
566 | DInfo.entityInfo = &DInfo.EntInfo; |
567 | DInfo.cursor = Cursor; |
568 | DInfo.loc = getIndexLoc(Loc); |
569 | DInfo.isImplicit = D->isImplicit(); |
570 | |
571 | DInfo.attributes = DInfo.EntInfo.attributes; |
572 | DInfo.numAttributes = DInfo.EntInfo.numAttributes; |
573 | |
574 | if (!SemaDC) |
575 | SemaDC = D->getDeclContext(); |
576 | getContainerInfo(DC: SemaDC, ContInfo&: DInfo.SemanticContainer); |
577 | DInfo.semanticContainer = &DInfo.SemanticContainer; |
578 | |
579 | if (LexicalDC == SemaDC) { |
580 | DInfo.lexicalContainer = &DInfo.SemanticContainer; |
581 | } else if (isTemplateImplicitInstantiation(D)) { |
582 | // Implicit instantiations have the lexical context of where they were |
583 | // instantiated first. We choose instead the semantic context because: |
584 | // 1) at the time that we see the instantiation we have not seen the |
585 | // function where it occurred yet. |
586 | // 2) the lexical context of the first instantiation is not useful |
587 | // information anyway. |
588 | DInfo.lexicalContainer = &DInfo.SemanticContainer; |
589 | } else { |
590 | getContainerInfo(DC: LexicalDC, ContInfo&: DInfo.LexicalContainer); |
591 | DInfo.lexicalContainer = &DInfo.LexicalContainer; |
592 | } |
593 | |
594 | if (DInfo.isContainer) { |
595 | getContainerInfo(DC: getEntityContainer(D), ContInfo&: DInfo.DeclAsContainer); |
596 | DInfo.declAsContainer = &DInfo.DeclAsContainer; |
597 | } |
598 | |
599 | CB.indexDeclaration(ClientData, &DInfo); |
600 | return true; |
601 | } |
602 | |
603 | bool CXIndexDataConsumer::handleObjCContainer(const ObjCContainerDecl *D, |
604 | SourceLocation Loc, CXCursor Cursor, |
605 | ObjCContainerDeclInfo &ContDInfo) { |
606 | ContDInfo.ObjCContDeclInfo.declInfo = &ContDInfo; |
607 | return handleDecl(D, Loc, Cursor, ContDInfo); |
608 | } |
609 | |
610 | bool CXIndexDataConsumer::handleFunction(const FunctionDecl *D) { |
611 | bool isDef = D->isThisDeclarationADefinition(); |
612 | bool isContainer = isDef; |
613 | bool isSkipped = false; |
614 | if (D->hasSkippedBody()) { |
615 | isSkipped = true; |
616 | isDef = true; |
617 | isContainer = false; |
618 | } |
619 | |
620 | DeclInfo DInfo(!D->isFirstDecl(), isDef, isContainer); |
621 | if (isSkipped) |
622 | DInfo.flags |= CXIdxDeclFlag_Skipped; |
623 | return handleDecl(D, Loc: D->getLocation(), Cursor: getCursor(D), DInfo); |
624 | } |
625 | |
626 | bool CXIndexDataConsumer::handleVar(const VarDecl *D) { |
627 | DeclInfo DInfo(!D->isFirstDecl(), D->isThisDeclarationADefinition(), |
628 | /*isContainer=*/false); |
629 | return handleDecl(D, Loc: D->getLocation(), Cursor: getCursor(D), DInfo); |
630 | } |
631 | |
632 | bool CXIndexDataConsumer::handleField(const FieldDecl *D) { |
633 | DeclInfo DInfo(/*isRedeclaration=*/false, /*isDefinition=*/true, |
634 | /*isContainer=*/false); |
635 | return handleDecl(D, Loc: D->getLocation(), Cursor: getCursor(D), DInfo); |
636 | } |
637 | |
638 | bool CXIndexDataConsumer::handleEnumerator(const EnumConstantDecl *D) { |
639 | DeclInfo DInfo(/*isRedeclaration=*/false, /*isDefinition=*/true, |
640 | /*isContainer=*/false); |
641 | return handleDecl(D, Loc: D->getLocation(), Cursor: getCursor(D), DInfo); |
642 | } |
643 | |
644 | bool CXIndexDataConsumer::handleTagDecl(const TagDecl *D) { |
645 | if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(Val: D)) |
646 | return handleCXXRecordDecl(CXXRD, D); |
647 | |
648 | DeclInfo DInfo(!D->isFirstDecl(), D->isThisDeclarationADefinition(), |
649 | D->isThisDeclarationADefinition()); |
650 | return handleDecl(D, Loc: D->getLocation(), Cursor: getCursor(D), DInfo); |
651 | } |
652 | |
653 | bool CXIndexDataConsumer::handleTypedefName(const TypedefNameDecl *D) { |
654 | DeclInfo DInfo(!D->isFirstDecl(), /*isDefinition=*/true, |
655 | /*isContainer=*/false); |
656 | return handleDecl(D, Loc: D->getLocation(), Cursor: getCursor(D), DInfo); |
657 | } |
658 | |
659 | bool CXIndexDataConsumer::handleObjCInterface(const ObjCInterfaceDecl *D) { |
660 | // For @class forward declarations, suppress them the same way as references. |
661 | if (!D->isThisDeclarationADefinition()) { |
662 | if (shouldSuppressRefs() && markEntityOccurrenceInFile(D, Loc: D->getLocation())) |
663 | return false; // already occurred. |
664 | |
665 | // FIXME: This seems like the wrong definition for redeclaration. |
666 | bool isRedeclaration = D->hasDefinition() || D->getPreviousDecl(); |
667 | ObjCContainerDeclInfo ContDInfo(/*isForwardRef=*/true, isRedeclaration, |
668 | /*isImplementation=*/false); |
669 | return handleObjCContainer(D, Loc: D->getLocation(), |
670 | Cursor: MakeCursorObjCClassRef(D, D->getLocation(), |
671 | CXTU), |
672 | ContDInfo); |
673 | } |
674 | |
675 | ScratchAlloc SA(*this); |
676 | |
677 | CXIdxBaseClassInfo BaseClass; |
678 | EntityInfo BaseEntity; |
679 | BaseClass.cursor = clang_getNullCursor(); |
680 | if (ObjCInterfaceDecl *SuperD = D->getSuperClass()) { |
681 | getEntityInfo(SuperD, BaseEntity, SA); |
682 | SourceLocation SuperLoc = D->getSuperClassLoc(); |
683 | BaseClass.base = &BaseEntity; |
684 | BaseClass.cursor = MakeCursorObjCSuperClassRef(Super: SuperD, Loc: SuperLoc, TU: CXTU); |
685 | BaseClass.loc = getIndexLoc(Loc: SuperLoc); |
686 | |
687 | if (shouldSuppressRefs()) |
688 | markEntityOccurrenceInFile(SuperD, SuperLoc); |
689 | } |
690 | |
691 | ObjCProtocolList EmptyProtoList; |
692 | ObjCProtocolListInfo ProtInfo(D->isThisDeclarationADefinition() |
693 | ? D->getReferencedProtocols() |
694 | : EmptyProtoList, |
695 | *this, SA); |
696 | |
697 | ObjCInterfaceDeclInfo InterInfo(D); |
698 | InterInfo.ObjCProtoListInfo = ProtInfo.getListInfo(); |
699 | InterInfo.ObjCInterDeclInfo.containerInfo = &InterInfo.ObjCContDeclInfo; |
700 | InterInfo.ObjCInterDeclInfo.superInfo = D->getSuperClass() ? &BaseClass |
701 | : nullptr; |
702 | InterInfo.ObjCInterDeclInfo.protocols = &InterInfo.ObjCProtoListInfo; |
703 | |
704 | return handleObjCContainer(D, Loc: D->getLocation(), Cursor: getCursor(D), ContDInfo&: InterInfo); |
705 | } |
706 | |
707 | bool CXIndexDataConsumer::handleObjCImplementation( |
708 | const ObjCImplementationDecl *D) { |
709 | ObjCContainerDeclInfo ContDInfo(/*isForwardRef=*/false, |
710 | /*isRedeclaration=*/true, |
711 | /*isImplementation=*/true); |
712 | return handleObjCContainer(D, Loc: D->getLocation(), Cursor: getCursor(D), ContDInfo); |
713 | } |
714 | |
715 | bool CXIndexDataConsumer::handleObjCProtocol(const ObjCProtocolDecl *D) { |
716 | if (!D->isThisDeclarationADefinition()) { |
717 | if (shouldSuppressRefs() && markEntityOccurrenceInFile(D, Loc: D->getLocation())) |
718 | return false; // already occurred. |
719 | |
720 | // FIXME: This seems like the wrong definition for redeclaration. |
721 | bool isRedeclaration = D->hasDefinition() || D->getPreviousDecl(); |
722 | ObjCContainerDeclInfo ContDInfo(/*isForwardRef=*/true, |
723 | isRedeclaration, |
724 | /*isImplementation=*/false); |
725 | return handleObjCContainer(D, Loc: D->getLocation(), |
726 | Cursor: MakeCursorObjCProtocolRef(D, D->getLocation(), |
727 | CXTU), |
728 | ContDInfo); |
729 | } |
730 | |
731 | ScratchAlloc SA(*this); |
732 | ObjCProtocolList EmptyProtoList; |
733 | ObjCProtocolListInfo ProtListInfo(D->isThisDeclarationADefinition() |
734 | ? D->getReferencedProtocols() |
735 | : EmptyProtoList, |
736 | *this, SA); |
737 | |
738 | ObjCProtocolDeclInfo ProtInfo(D); |
739 | ProtInfo.ObjCProtoRefListInfo = ProtListInfo.getListInfo(); |
740 | |
741 | return handleObjCContainer(D, Loc: D->getLocation(), Cursor: getCursor(D), ContDInfo&: ProtInfo); |
742 | } |
743 | |
744 | bool CXIndexDataConsumer::handleObjCCategory(const ObjCCategoryDecl *D) { |
745 | ScratchAlloc SA(*this); |
746 | |
747 | ObjCCategoryDeclInfo CatDInfo(/*isImplementation=*/false); |
748 | EntityInfo ClassEntity; |
749 | const ObjCInterfaceDecl *IFaceD = D->getClassInterface(); |
750 | SourceLocation ClassLoc = D->getLocation(); |
751 | SourceLocation CategoryLoc = D->IsClassExtension() ? ClassLoc |
752 | : D->getCategoryNameLoc(); |
753 | getEntityInfo(IFaceD, ClassEntity, SA); |
754 | |
755 | if (shouldSuppressRefs()) |
756 | markEntityOccurrenceInFile(IFaceD, ClassLoc); |
757 | |
758 | ObjCProtocolListInfo ProtInfo(D->getReferencedProtocols(), *this, SA); |
759 | |
760 | CatDInfo.ObjCCatDeclInfo.containerInfo = &CatDInfo.ObjCContDeclInfo; |
761 | if (IFaceD) { |
762 | CatDInfo.ObjCCatDeclInfo.objcClass = &ClassEntity; |
763 | CatDInfo.ObjCCatDeclInfo.classCursor = |
764 | MakeCursorObjCClassRef(Class: IFaceD, Loc: ClassLoc, TU: CXTU); |
765 | } else { |
766 | CatDInfo.ObjCCatDeclInfo.objcClass = nullptr; |
767 | CatDInfo.ObjCCatDeclInfo.classCursor = clang_getNullCursor(); |
768 | } |
769 | CatDInfo.ObjCCatDeclInfo.classLoc = getIndexLoc(Loc: ClassLoc); |
770 | CatDInfo.ObjCProtoListInfo = ProtInfo.getListInfo(); |
771 | CatDInfo.ObjCCatDeclInfo.protocols = &CatDInfo.ObjCProtoListInfo; |
772 | |
773 | return handleObjCContainer(D, CategoryLoc, getCursor(D), CatDInfo); |
774 | } |
775 | |
776 | bool CXIndexDataConsumer::handleObjCCategoryImpl(const ObjCCategoryImplDecl *D) { |
777 | ScratchAlloc SA(*this); |
778 | |
779 | const ObjCCategoryDecl *CatD = D->getCategoryDecl(); |
780 | ObjCCategoryDeclInfo CatDInfo(/*isImplementation=*/true); |
781 | EntityInfo ClassEntity; |
782 | const ObjCInterfaceDecl *IFaceD = CatD->getClassInterface(); |
783 | SourceLocation ClassLoc = D->getLocation(); |
784 | SourceLocation CategoryLoc = D->getCategoryNameLoc(); |
785 | getEntityInfo(IFaceD, ClassEntity, SA); |
786 | |
787 | if (shouldSuppressRefs()) |
788 | markEntityOccurrenceInFile(IFaceD, ClassLoc); |
789 | |
790 | CatDInfo.ObjCCatDeclInfo.containerInfo = &CatDInfo.ObjCContDeclInfo; |
791 | if (IFaceD) { |
792 | CatDInfo.ObjCCatDeclInfo.objcClass = &ClassEntity; |
793 | CatDInfo.ObjCCatDeclInfo.classCursor = |
794 | MakeCursorObjCClassRef(Class: IFaceD, Loc: ClassLoc, TU: CXTU); |
795 | } else { |
796 | CatDInfo.ObjCCatDeclInfo.objcClass = nullptr; |
797 | CatDInfo.ObjCCatDeclInfo.classCursor = clang_getNullCursor(); |
798 | } |
799 | CatDInfo.ObjCCatDeclInfo.classLoc = getIndexLoc(Loc: ClassLoc); |
800 | CatDInfo.ObjCCatDeclInfo.protocols = nullptr; |
801 | |
802 | return handleObjCContainer(D, CategoryLoc, getCursor(D), CatDInfo); |
803 | } |
804 | |
805 | bool CXIndexDataConsumer::handleObjCMethod(const ObjCMethodDecl *D, |
806 | SourceLocation Loc) { |
807 | bool isDef = D->isThisDeclarationADefinition(); |
808 | bool isContainer = isDef; |
809 | bool isSkipped = false; |
810 | if (D->hasSkippedBody()) { |
811 | isSkipped = true; |
812 | isDef = true; |
813 | isContainer = false; |
814 | } |
815 | |
816 | DeclInfo DInfo(!D->isCanonicalDecl(), isDef, isContainer); |
817 | if (isSkipped) |
818 | DInfo.flags |= CXIdxDeclFlag_Skipped; |
819 | return handleDecl(D, Loc, getCursor(D), DInfo); |
820 | } |
821 | |
822 | bool CXIndexDataConsumer::handleSynthesizedObjCProperty( |
823 | const ObjCPropertyImplDecl *D) { |
824 | ObjCPropertyDecl *PD = D->getPropertyDecl(); |
825 | auto *DC = D->getDeclContext(); |
826 | return handleReference(D: PD, Loc: D->getLocation(), Cursor: getCursor(D), |
827 | Parent: dyn_cast<NamedDecl>(DC), DC: DC); |
828 | } |
829 | |
830 | bool CXIndexDataConsumer::handleSynthesizedObjCMethod(const ObjCMethodDecl *D, |
831 | SourceLocation Loc, |
832 | const DeclContext *LexicalDC) { |
833 | DeclInfo DInfo(/*isRedeclaration=*/true, /*isDefinition=*/true, |
834 | /*isContainer=*/false); |
835 | return handleDecl(D, Loc, Cursor: getCursor(D), DInfo, LexicalDC, SemaDC: D->getDeclContext()); |
836 | } |
837 | |
838 | bool CXIndexDataConsumer::handleObjCProperty(const ObjCPropertyDecl *D) { |
839 | ScratchAlloc SA(*this); |
840 | |
841 | ObjCPropertyDeclInfo DInfo; |
842 | EntityInfo GetterEntity; |
843 | EntityInfo SetterEntity; |
844 | |
845 | DInfo.ObjCPropDeclInfo.declInfo = &DInfo; |
846 | |
847 | if (ObjCMethodDecl *Getter = D->getGetterMethodDecl()) { |
848 | getEntityInfo(Getter, GetterEntity, SA); |
849 | DInfo.ObjCPropDeclInfo.getter = &GetterEntity; |
850 | } else { |
851 | DInfo.ObjCPropDeclInfo.getter = nullptr; |
852 | } |
853 | if (ObjCMethodDecl *Setter = D->getSetterMethodDecl()) { |
854 | getEntityInfo(Setter, SetterEntity, SA); |
855 | DInfo.ObjCPropDeclInfo.setter = &SetterEntity; |
856 | } else { |
857 | DInfo.ObjCPropDeclInfo.setter = nullptr; |
858 | } |
859 | |
860 | return handleDecl(D, Loc: D->getLocation(), Cursor: getCursor(D), DInfo); |
861 | } |
862 | |
863 | bool CXIndexDataConsumer::handleNamespace(const NamespaceDecl *D) { |
864 | DeclInfo DInfo(/*isRedeclaration=*/!D->isOriginalNamespace(), |
865 | /*isDefinition=*/true, |
866 | /*isContainer=*/true); |
867 | return handleDecl(D, Loc: D->getLocation(), Cursor: getCursor(D), DInfo); |
868 | } |
869 | |
870 | bool CXIndexDataConsumer::handleClassTemplate(const ClassTemplateDecl *D) { |
871 | return handleCXXRecordDecl(D->getTemplatedDecl(), D); |
872 | } |
873 | |
874 | bool CXIndexDataConsumer::handleFunctionTemplate(const FunctionTemplateDecl *D) { |
875 | DeclInfo DInfo(/*isRedeclaration=*/!D->isCanonicalDecl(), |
876 | /*isDefinition=*/D->isThisDeclarationADefinition(), |
877 | /*isContainer=*/D->isThisDeclarationADefinition()); |
878 | return handleDecl(D, Loc: D->getLocation(), Cursor: getCursor(D), DInfo); |
879 | } |
880 | |
881 | bool CXIndexDataConsumer::handleTypeAliasTemplate(const TypeAliasTemplateDecl *D) { |
882 | DeclInfo DInfo(/*isRedeclaration=*/!D->isCanonicalDecl(), |
883 | /*isDefinition=*/true, /*isContainer=*/false); |
884 | return handleDecl(D, Loc: D->getLocation(), Cursor: getCursor(D), DInfo); |
885 | } |
886 | |
887 | bool CXIndexDataConsumer::handleConcept(const ConceptDecl *D) { |
888 | DeclInfo DInfo(/*isRedeclaration=*/!D->isCanonicalDecl(), |
889 | /*isDefinition=*/true, /*isContainer=*/false); |
890 | return handleDecl(D, Loc: D->getLocation(), Cursor: getCursor(D), DInfo); |
891 | } |
892 | |
893 | bool CXIndexDataConsumer::handleReference(const NamedDecl *D, SourceLocation Loc, |
894 | CXCursor Cursor, |
895 | const NamedDecl *Parent, |
896 | const DeclContext *DC, |
897 | const Expr *E, |
898 | CXIdxEntityRefKind Kind, |
899 | CXSymbolRole Role) { |
900 | if (!CB.indexEntityReference) |
901 | return false; |
902 | |
903 | if (!D || !DC) |
904 | return false; |
905 | if (Loc.isInvalid()) |
906 | return false; |
907 | if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalDecl(D)) |
908 | return false; |
909 | if (isNotFromSourceFile(Loc: D->getLocation())) |
910 | return false; |
911 | if (D->isImplicit() && shouldIgnoreIfImplicit(D)) |
912 | return false; |
913 | |
914 | if (shouldSuppressRefs()) { |
915 | if (markEntityOccurrenceInFile(D, Loc)) |
916 | return false; // already occurred. |
917 | } |
918 | |
919 | ScratchAlloc SA(*this); |
920 | EntityInfo RefEntity, ParentEntity; |
921 | getEntityInfo(D, EntityInfo&: RefEntity, SA); |
922 | if (!RefEntity.USR) |
923 | return false; |
924 | |
925 | getEntityInfo(D: Parent, EntityInfo&: ParentEntity, SA); |
926 | |
927 | ContainerInfo Container; |
928 | getContainerInfo(DC, ContInfo&: Container); |
929 | |
930 | CXIdxEntityRefInfo Info = { .kind: Kind, |
931 | .cursor: Cursor, |
932 | .loc: getIndexLoc(Loc), |
933 | .referencedEntity: &RefEntity, |
934 | .parentEntity: Parent ? &ParentEntity : nullptr, |
935 | .container: &Container, |
936 | .role: Role }; |
937 | CB.indexEntityReference(ClientData, &Info); |
938 | return true; |
939 | } |
940 | |
941 | bool CXIndexDataConsumer::isNotFromSourceFile(SourceLocation Loc) const { |
942 | if (Loc.isInvalid()) |
943 | return true; |
944 | SourceManager &SM = Ctx->getSourceManager(); |
945 | SourceLocation FileLoc = SM.getFileLoc(Loc); |
946 | FileID FID = SM.getFileID(SpellingLoc: FileLoc); |
947 | return SM.getFileEntryForID(FID) == nullptr; |
948 | } |
949 | |
950 | void CXIndexDataConsumer::addContainerInMap(const DeclContext *DC, |
951 | CXIdxClientContainer container) { |
952 | if (!DC) |
953 | return; |
954 | |
955 | ContainerMapTy::iterator I = ContainerMap.find(Val: DC); |
956 | if (I == ContainerMap.end()) { |
957 | if (container) |
958 | ContainerMap[DC] = container; |
959 | return; |
960 | } |
961 | // Allow changing the container of a previously seen DeclContext so we |
962 | // can handle invalid user code, like a function re-definition. |
963 | if (container) |
964 | I->second = container; |
965 | else |
966 | ContainerMap.erase(I); |
967 | } |
968 | |
969 | CXIdxClientEntity CXIndexDataConsumer::getClientEntity(const Decl *D) const { |
970 | return D ? EntityMap.lookup(Val: D) : nullptr; |
971 | } |
972 | |
973 | void CXIndexDataConsumer::setClientEntity(const Decl *D, CXIdxClientEntity client) { |
974 | if (!D) |
975 | return; |
976 | EntityMap[D] = client; |
977 | } |
978 | |
979 | bool CXIndexDataConsumer::handleCXXRecordDecl(const CXXRecordDecl *RD, |
980 | const NamedDecl *OrigD) { |
981 | if (RD->isThisDeclarationADefinition()) { |
982 | ScratchAlloc SA(*this); |
983 | CXXClassDeclInfo CXXDInfo(/*isRedeclaration=*/!OrigD->isCanonicalDecl(), |
984 | /*isDefinition=*/RD->isThisDeclarationADefinition()); |
985 | CXXBasesListInfo BaseList(RD, *this, SA); |
986 | CXXDInfo.CXXClassInfo.declInfo = &CXXDInfo; |
987 | CXXDInfo.CXXClassInfo.bases = BaseList.getBases(); |
988 | CXXDInfo.CXXClassInfo.numBases = BaseList.getNumBases(); |
989 | |
990 | if (shouldSuppressRefs()) { |
991 | // Go through bases and mark them as referenced. |
992 | for (unsigned i = 0, e = BaseList.getNumBases(); i != e; ++i) { |
993 | const CXIdxBaseClassInfo *baseInfo = BaseList.getBases()[i]; |
994 | if (baseInfo->base) { |
995 | const NamedDecl *BaseD = BaseList.BaseEntities[i].Dcl; |
996 | SourceLocation |
997 | Loc = SourceLocation::getFromRawEncoding(Encoding: baseInfo->loc.int_data); |
998 | markEntityOccurrenceInFile(D: BaseD, Loc); |
999 | } |
1000 | } |
1001 | } |
1002 | |
1003 | return handleDecl(D: OrigD, Loc: OrigD->getLocation(), Cursor: getCursor(OrigD), DInfo&: CXXDInfo); |
1004 | } |
1005 | |
1006 | DeclInfo DInfo(/*isRedeclaration=*/!OrigD->isCanonicalDecl(), |
1007 | /*isDefinition=*/RD->isThisDeclarationADefinition(), |
1008 | /*isContainer=*/RD->isThisDeclarationADefinition()); |
1009 | return handleDecl(D: OrigD, Loc: OrigD->getLocation(), Cursor: getCursor(OrigD), DInfo); |
1010 | } |
1011 | |
1012 | bool CXIndexDataConsumer::markEntityOccurrenceInFile(const NamedDecl *D, |
1013 | SourceLocation Loc) { |
1014 | if (!D || Loc.isInvalid()) |
1015 | return true; |
1016 | |
1017 | SourceManager &SM = Ctx->getSourceManager(); |
1018 | D = getEntityDecl(D); |
1019 | |
1020 | std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc: SM.getFileLoc(Loc)); |
1021 | FileID FID = LocInfo.first; |
1022 | if (FID.isInvalid()) |
1023 | return true; |
1024 | |
1025 | const FileEntry *FE = SM.getFileEntryForID(FID); |
1026 | if (!FE) |
1027 | return true; |
1028 | RefFileOccurrence RefOccur(FE, D); |
1029 | std::pair<llvm::DenseSet<RefFileOccurrence>::iterator, bool> |
1030 | res = RefFileOccurrences.insert(V: RefOccur); |
1031 | return !res.second; // already in map |
1032 | } |
1033 | |
1034 | const NamedDecl *CXIndexDataConsumer::getEntityDecl(const NamedDecl *D) const { |
1035 | assert(D); |
1036 | D = cast<NamedDecl>(D->getCanonicalDecl()); |
1037 | |
1038 | if (const ObjCImplementationDecl * |
1039 | ImplD = dyn_cast<ObjCImplementationDecl>(Val: D)) { |
1040 | return getEntityDecl(D: ImplD->getClassInterface()); |
1041 | |
1042 | } else if (const ObjCCategoryImplDecl * |
1043 | CatImplD = dyn_cast<ObjCCategoryImplDecl>(Val: D)) { |
1044 | return getEntityDecl(CatImplD->getCategoryDecl()); |
1045 | } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Val: D)) { |
1046 | if (FunctionTemplateDecl *TemplD = FD->getDescribedFunctionTemplate()) |
1047 | return getEntityDecl(TemplD); |
1048 | } else if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Val: D)) { |
1049 | if (ClassTemplateDecl *TemplD = RD->getDescribedClassTemplate()) |
1050 | return getEntityDecl(TemplD); |
1051 | } |
1052 | |
1053 | return D; |
1054 | } |
1055 | |
1056 | const DeclContext * |
1057 | CXIndexDataConsumer::getEntityContainer(const Decl *D) const { |
1058 | const DeclContext *DC = dyn_cast<DeclContext>(Val: D); |
1059 | if (DC) |
1060 | return DC; |
1061 | |
1062 | if (const ClassTemplateDecl *ClassTempl = dyn_cast<ClassTemplateDecl>(Val: D)) { |
1063 | DC = ClassTempl->getTemplatedDecl(); |
1064 | } else if (const FunctionTemplateDecl * |
1065 | FuncTempl = dyn_cast<FunctionTemplateDecl>(Val: D)) { |
1066 | DC = FuncTempl->getTemplatedDecl(); |
1067 | } |
1068 | |
1069 | return DC; |
1070 | } |
1071 | |
1072 | CXIdxClientContainer |
1073 | CXIndexDataConsumer::getClientContainerForDC(const DeclContext *DC) const { |
1074 | return DC ? ContainerMap.lookup(Val: DC) : nullptr; |
1075 | } |
1076 | |
1077 | CXIdxClientFile CXIndexDataConsumer::getIndexFile(OptionalFileEntryRef File) { |
1078 | return File ? FileMap.lookup(Val: *File) : nullptr; |
1079 | } |
1080 | |
1081 | CXIdxLoc CXIndexDataConsumer::getIndexLoc(SourceLocation Loc) const { |
1082 | CXIdxLoc idxLoc = { .ptr_data: {nullptr, nullptr}, .int_data: 0 }; |
1083 | if (Loc.isInvalid()) |
1084 | return idxLoc; |
1085 | |
1086 | idxLoc.ptr_data[0] = const_cast<CXIndexDataConsumer *>(this); |
1087 | idxLoc.int_data = Loc.getRawEncoding(); |
1088 | return idxLoc; |
1089 | } |
1090 | |
1091 | void CXIndexDataConsumer::translateLoc(SourceLocation Loc, |
1092 | CXIdxClientFile *indexFile, CXFile *file, |
1093 | unsigned *line, unsigned *column, |
1094 | unsigned *offset) { |
1095 | if (Loc.isInvalid()) |
1096 | return; |
1097 | |
1098 | SourceManager &SM = Ctx->getSourceManager(); |
1099 | Loc = SM.getFileLoc(Loc); |
1100 | |
1101 | std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); |
1102 | FileID FID = LocInfo.first; |
1103 | unsigned FileOffset = LocInfo.second; |
1104 | |
1105 | if (FID.isInvalid()) |
1106 | return; |
1107 | |
1108 | OptionalFileEntryRef FE = SM.getFileEntryRefForID(FID); |
1109 | if (indexFile) |
1110 | *indexFile = getIndexFile(File: FE); |
1111 | if (file) |
1112 | *file = cxfile::makeCXFile(FE); |
1113 | if (line) |
1114 | *line = SM.getLineNumber(FID, FilePos: FileOffset); |
1115 | if (column) |
1116 | *column = SM.getColumnNumber(FID, FilePos: FileOffset); |
1117 | if (offset) |
1118 | *offset = FileOffset; |
1119 | } |
1120 | |
1121 | static CXIdxEntityKind getEntityKindFromSymbolKind(SymbolKind K, SymbolLanguage L); |
1122 | static CXIdxEntityCXXTemplateKind |
1123 | getEntityKindFromSymbolProperties(SymbolPropertySet K); |
1124 | static CXIdxEntityLanguage getEntityLangFromSymbolLang(SymbolLanguage L); |
1125 | |
1126 | void CXIndexDataConsumer::getEntityInfo(const NamedDecl *D, |
1127 | EntityInfo &EntityInfo, |
1128 | ScratchAlloc &SA) { |
1129 | if (!D) |
1130 | return; |
1131 | |
1132 | D = getEntityDecl(D); |
1133 | EntityInfo.cursor = getCursor(D); |
1134 | EntityInfo.Dcl = D; |
1135 | EntityInfo.IndexCtx = this; |
1136 | |
1137 | SymbolInfo SymInfo = getSymbolInfo(D); |
1138 | EntityInfo.kind = getEntityKindFromSymbolKind(K: SymInfo.Kind, L: SymInfo.Lang); |
1139 | EntityInfo.templateKind = getEntityKindFromSymbolProperties(K: SymInfo.Properties); |
1140 | EntityInfo.lang = getEntityLangFromSymbolLang(L: SymInfo.Lang); |
1141 | |
1142 | if (D->hasAttrs()) { |
1143 | EntityInfo.AttrList = AttrListInfo::create(D, *this); |
1144 | EntityInfo.attributes = EntityInfo.AttrList->getAttrs(); |
1145 | EntityInfo.numAttributes = EntityInfo.AttrList->getNumAttrs(); |
1146 | } |
1147 | |
1148 | if (EntityInfo.kind == CXIdxEntity_Unexposed) |
1149 | return; |
1150 | |
1151 | if (IdentifierInfo *II = D->getIdentifier()) { |
1152 | EntityInfo.name = SA.toCStr(Str: II->getName()); |
1153 | |
1154 | } else if (isa<TagDecl>(Val: D) || isa<FieldDecl>(Val: D) || isa<NamespaceDecl>(Val: D)) { |
1155 | EntityInfo.name = nullptr; // anonymous tag/field/namespace. |
1156 | |
1157 | } else { |
1158 | SmallString<256> StrBuf; |
1159 | { |
1160 | llvm::raw_svector_ostream OS(StrBuf); |
1161 | D->printName(OS); |
1162 | } |
1163 | EntityInfo.name = SA.copyCStr(Str: StrBuf.str()); |
1164 | } |
1165 | |
1166 | { |
1167 | SmallString<512> StrBuf; |
1168 | bool Ignore = getDeclCursorUSR(D, StrBuf); |
1169 | if (Ignore) { |
1170 | EntityInfo.USR = nullptr; |
1171 | } else { |
1172 | EntityInfo.USR = SA.copyCStr(Str: StrBuf.str()); |
1173 | } |
1174 | } |
1175 | } |
1176 | |
1177 | void CXIndexDataConsumer::getContainerInfo(const DeclContext *DC, |
1178 | ContainerInfo &ContInfo) { |
1179 | ContInfo.cursor = getCursor(D: cast<Decl>(Val: DC)); |
1180 | ContInfo.DC = DC; |
1181 | ContInfo.IndexCtx = this; |
1182 | } |
1183 | |
1184 | CXCursor CXIndexDataConsumer::getRefCursor(const NamedDecl *D, SourceLocation Loc) { |
1185 | if (const TypeDecl *TD = dyn_cast<TypeDecl>(Val: D)) |
1186 | return MakeCursorTypeRef(Type: TD, Loc, TU: CXTU); |
1187 | if (const ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(Val: D)) |
1188 | return MakeCursorObjCClassRef(Class: ID, Loc, TU: CXTU); |
1189 | if (const ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(Val: D)) |
1190 | return MakeCursorObjCProtocolRef(Proto: PD, Loc, TU: CXTU); |
1191 | if (const TemplateDecl *Template = dyn_cast<TemplateDecl>(Val: D)) |
1192 | return MakeCursorTemplateRef(Template, Loc, TU: CXTU); |
1193 | if (const NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(Val: D)) |
1194 | return MakeCursorNamespaceRef(Namespace, Loc, CXTU); |
1195 | if (const NamespaceAliasDecl *Namespace = dyn_cast<NamespaceAliasDecl>(Val: D)) |
1196 | return MakeCursorNamespaceRef(Namespace, Loc, CXTU); |
1197 | if (const FieldDecl *Field = dyn_cast<FieldDecl>(Val: D)) |
1198 | return MakeCursorMemberRef(Field, Loc, TU: CXTU); |
1199 | if (const VarDecl *Var = dyn_cast<VarDecl>(Val: D)) |
1200 | return MakeCursorVariableRef(Var, Loc, TU: CXTU); |
1201 | |
1202 | return clang_getNullCursor(); |
1203 | } |
1204 | |
1205 | bool CXIndexDataConsumer::shouldIgnoreIfImplicit(const Decl *D) { |
1206 | if (isa<ObjCInterfaceDecl>(Val: D)) |
1207 | return false; |
1208 | if (isa<ObjCCategoryDecl>(Val: D)) |
1209 | return false; |
1210 | if (isa<ObjCIvarDecl>(Val: D)) |
1211 | return false; |
1212 | if (isa<ObjCMethodDecl>(Val: D)) |
1213 | return false; |
1214 | if (isa<ImportDecl>(Val: D)) |
1215 | return false; |
1216 | return true; |
1217 | } |
1218 | |
1219 | bool CXIndexDataConsumer::isTemplateImplicitInstantiation(const Decl *D) { |
1220 | if (const ClassTemplateSpecializationDecl * |
1221 | SD = dyn_cast<ClassTemplateSpecializationDecl>(Val: D)) { |
1222 | return SD->getSpecializationKind() == TSK_ImplicitInstantiation; |
1223 | } |
1224 | if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Val: D)) { |
1225 | return FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation; |
1226 | } |
1227 | return false; |
1228 | } |
1229 | |
1230 | static CXIdxEntityKind getEntityKindFromSymbolKind(SymbolKind K, SymbolLanguage Lang) { |
1231 | switch (K) { |
1232 | case SymbolKind::Unknown: |
1233 | case SymbolKind::Module: |
1234 | case SymbolKind::Macro: |
1235 | case SymbolKind::ClassProperty: |
1236 | case SymbolKind::Using: |
1237 | case SymbolKind::TemplateTypeParm: |
1238 | case SymbolKind::TemplateTemplateParm: |
1239 | case SymbolKind::NonTypeTemplateParm: |
1240 | return CXIdxEntity_Unexposed; |
1241 | |
1242 | case SymbolKind::Enum: return CXIdxEntity_Enum; |
1243 | case SymbolKind::Struct: return CXIdxEntity_Struct; |
1244 | case SymbolKind::Union: return CXIdxEntity_Union; |
1245 | case SymbolKind::TypeAlias: |
1246 | if (Lang == SymbolLanguage::CXX) |
1247 | return CXIdxEntity_CXXTypeAlias; |
1248 | return CXIdxEntity_Typedef; |
1249 | case SymbolKind::Function: return CXIdxEntity_Function; |
1250 | case SymbolKind::Variable: return CXIdxEntity_Variable; |
1251 | case SymbolKind::Field: |
1252 | if (Lang == SymbolLanguage::ObjC) |
1253 | return CXIdxEntity_ObjCIvar; |
1254 | return CXIdxEntity_Field; |
1255 | case SymbolKind::EnumConstant: return CXIdxEntity_EnumConstant; |
1256 | case SymbolKind::Class: |
1257 | if (Lang == SymbolLanguage::ObjC) |
1258 | return CXIdxEntity_ObjCClass; |
1259 | return CXIdxEntity_CXXClass; |
1260 | case SymbolKind::Protocol: |
1261 | if (Lang == SymbolLanguage::ObjC) |
1262 | return CXIdxEntity_ObjCProtocol; |
1263 | return CXIdxEntity_CXXInterface; |
1264 | case SymbolKind::Extension: return CXIdxEntity_ObjCCategory; |
1265 | case SymbolKind::InstanceMethod: |
1266 | if (Lang == SymbolLanguage::ObjC) |
1267 | return CXIdxEntity_ObjCInstanceMethod; |
1268 | return CXIdxEntity_CXXInstanceMethod; |
1269 | case SymbolKind::ClassMethod: return CXIdxEntity_ObjCClassMethod; |
1270 | case SymbolKind::StaticMethod: return CXIdxEntity_CXXStaticMethod; |
1271 | case SymbolKind::InstanceProperty: return CXIdxEntity_ObjCProperty; |
1272 | case SymbolKind::StaticProperty: return CXIdxEntity_CXXStaticVariable; |
1273 | case SymbolKind::Namespace: return CXIdxEntity_CXXNamespace; |
1274 | case SymbolKind::NamespaceAlias: return CXIdxEntity_CXXNamespaceAlias; |
1275 | case SymbolKind::Constructor: return CXIdxEntity_CXXConstructor; |
1276 | case SymbolKind::Destructor: return CXIdxEntity_CXXDestructor; |
1277 | case SymbolKind::ConversionFunction: return CXIdxEntity_CXXConversionFunction; |
1278 | case SymbolKind::Parameter: return CXIdxEntity_Variable; |
1279 | case SymbolKind::Concept: |
1280 | return CXIdxEntity_CXXConcept; |
1281 | } |
1282 | llvm_unreachable("invalid symbol kind" ); |
1283 | } |
1284 | |
1285 | static CXIdxEntityCXXTemplateKind |
1286 | getEntityKindFromSymbolProperties(SymbolPropertySet K) { |
1287 | if (K & (SymbolPropertySet)SymbolProperty::TemplatePartialSpecialization) |
1288 | return CXIdxEntity_TemplatePartialSpecialization; |
1289 | if (K & (SymbolPropertySet)SymbolProperty::TemplateSpecialization) |
1290 | return CXIdxEntity_TemplateSpecialization; |
1291 | if (K & (SymbolPropertySet)SymbolProperty::Generic) |
1292 | return CXIdxEntity_Template; |
1293 | return CXIdxEntity_NonTemplate; |
1294 | } |
1295 | |
1296 | static CXIdxEntityLanguage getEntityLangFromSymbolLang(SymbolLanguage L) { |
1297 | switch (L) { |
1298 | case SymbolLanguage::C: return CXIdxEntityLang_C; |
1299 | case SymbolLanguage::ObjC: return CXIdxEntityLang_ObjC; |
1300 | case SymbolLanguage::CXX: return CXIdxEntityLang_CXX; |
1301 | case SymbolLanguage::Swift: return CXIdxEntityLang_Swift; |
1302 | } |
1303 | llvm_unreachable("invalid symbol language" ); |
1304 | } |
1305 | |