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