1 //===- CXIndexDataConsumer.h - Index data consumer for libclang--*- C++ -*-===//
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 #ifndef LLVM_CLANG_TOOLS_LIBCLANG_CXINDEXDATACONSUMER_H
10 #define LLVM_CLANG_TOOLS_LIBCLANG_CXINDEXDATACONSUMER_H
11 
12 #include "CXCursor.h"
13 #include "Index_Internal.h"
14 #include "clang/Index/IndexDataConsumer.h"
15 #include "clang/AST/DeclGroup.h"
16 #include "clang/AST/DeclObjC.h"
17 #include "llvm/ADT/DenseSet.h"
18 
19 namespace clang {
20   class FileEntry;
21   class MSPropertyDecl;
22   class ObjCPropertyDecl;
23   class ClassTemplateDecl;
24   class FunctionTemplateDecl;
25   class TypeAliasTemplateDecl;
26   class ClassTemplateSpecializationDecl;
27 
28 namespace cxindex {
29   class CXIndexDataConsumer;
30   class AttrListInfo;
31 
32 class ScratchAlloc {
33   CXIndexDataConsumer &IdxCtx;
34 
35 public:
36   explicit ScratchAlloc(CXIndexDataConsumer &indexCtx);
37   ScratchAlloc(const ScratchAlloc &SA);
38 
39   ~ScratchAlloc();
40 
41   const char *toCStr(StringRef Str);
42   const char *copyCStr(StringRef Str);
43 
44   template <typename T>
45   T *allocate();
46 };
47 
48 struct EntityInfo : public CXIdxEntityInfo {
49   const NamedDecl *Dcl;
50   CXIndexDataConsumer *IndexCtx;
51   IntrusiveRefCntPtr<AttrListInfo> AttrList;
52 
EntityInfoEntityInfo53   EntityInfo() {
54     name = USR = nullptr;
55     attributes = nullptr;
56     numAttributes = 0;
57   }
58 };
59 
60 struct ContainerInfo : public CXIdxContainerInfo {
61   const DeclContext *DC;
62   CXIndexDataConsumer *IndexCtx;
63 };
64 
65 struct DeclInfo : public CXIdxDeclInfo {
66   enum DInfoKind {
67     Info_Decl,
68 
69     Info_ObjCContainer,
70       Info_ObjCInterface,
71       Info_ObjCProtocol,
72       Info_ObjCCategory,
73 
74     Info_ObjCProperty,
75 
76     Info_CXXClass
77   };
78 
79   DInfoKind Kind;
80 
81   EntityInfo EntInfo;
82   ContainerInfo SemanticContainer;
83   ContainerInfo LexicalContainer;
84   ContainerInfo DeclAsContainer;
85 
DeclInfoDeclInfo86   DeclInfo(bool isRedeclaration, bool isDefinition, bool isContainer)
87     : Kind(Info_Decl) {
88     this->isRedeclaration = isRedeclaration;
89     this->isDefinition = isDefinition;
90     this->isContainer = isContainer;
91     attributes = nullptr;
92     numAttributes = 0;
93     declAsContainer = semanticContainer = lexicalContainer = nullptr;
94     flags = 0;
95   }
DeclInfoDeclInfo96   DeclInfo(DInfoKind K,
97            bool isRedeclaration, bool isDefinition, bool isContainer)
98     : Kind(K) {
99     this->isRedeclaration = isRedeclaration;
100     this->isDefinition = isDefinition;
101     this->isContainer = isContainer;
102     attributes = nullptr;
103     numAttributes = 0;
104     declAsContainer = semanticContainer = lexicalContainer = nullptr;
105     flags = 0;
106   }
107 };
108 
109 struct ObjCContainerDeclInfo : public DeclInfo {
110   CXIdxObjCContainerDeclInfo ObjCContDeclInfo;
111 
ObjCContainerDeclInfoObjCContainerDeclInfo112   ObjCContainerDeclInfo(bool isForwardRef,
113                         bool isRedeclaration,
114                         bool isImplementation)
115     : DeclInfo(Info_ObjCContainer, isRedeclaration,
116                /*isDefinition=*/!isForwardRef, /*isContainer=*/!isForwardRef) {
117     init(isForwardRef, isImplementation);
118   }
ObjCContainerDeclInfoObjCContainerDeclInfo119   ObjCContainerDeclInfo(DInfoKind K,
120                         bool isForwardRef,
121                         bool isRedeclaration,
122                         bool isImplementation)
123     : DeclInfo(K, isRedeclaration, /*isDefinition=*/!isForwardRef,
124                /*isContainer=*/!isForwardRef) {
125     init(isForwardRef, isImplementation);
126   }
127 
classofObjCContainerDeclInfo128   static bool classof(const DeclInfo *D) {
129     return Info_ObjCContainer <= D->Kind && D->Kind <= Info_ObjCCategory;
130   }
131 
132 private:
initObjCContainerDeclInfo133   void init(bool isForwardRef, bool isImplementation) {
134     if (isForwardRef)
135       ObjCContDeclInfo.kind = CXIdxObjCContainer_ForwardRef;
136     else if (isImplementation)
137       ObjCContDeclInfo.kind = CXIdxObjCContainer_Implementation;
138     else
139       ObjCContDeclInfo.kind = CXIdxObjCContainer_Interface;
140   }
141 };
142 
143 struct ObjCInterfaceDeclInfo : public ObjCContainerDeclInfo {
144   CXIdxObjCInterfaceDeclInfo ObjCInterDeclInfo;
145   CXIdxObjCProtocolRefListInfo ObjCProtoListInfo;
146 
ObjCInterfaceDeclInfoObjCInterfaceDeclInfo147   ObjCInterfaceDeclInfo(const ObjCInterfaceDecl *D)
148     : ObjCContainerDeclInfo(Info_ObjCInterface,
149                             /*isForwardRef=*/false,
150                             /*isRedeclaration=*/D->getPreviousDecl() != nullptr,
151                             /*isImplementation=*/false) { }
152 
classofObjCInterfaceDeclInfo153   static bool classof(const DeclInfo *D) {
154     return D->Kind == Info_ObjCInterface;
155   }
156 };
157 
158 struct ObjCProtocolDeclInfo : public ObjCContainerDeclInfo {
159   CXIdxObjCProtocolRefListInfo ObjCProtoRefListInfo;
160 
ObjCProtocolDeclInfoObjCProtocolDeclInfo161   ObjCProtocolDeclInfo(const ObjCProtocolDecl *D)
162     : ObjCContainerDeclInfo(Info_ObjCProtocol,
163                             /*isForwardRef=*/false,
164                             /*isRedeclaration=*/D->getPreviousDecl(),
165                             /*isImplementation=*/false) { }
166 
classofObjCProtocolDeclInfo167   static bool classof(const DeclInfo *D) {
168     return D->Kind == Info_ObjCProtocol;
169   }
170 };
171 
172 struct ObjCCategoryDeclInfo : public ObjCContainerDeclInfo {
173   CXIdxObjCCategoryDeclInfo ObjCCatDeclInfo;
174   CXIdxObjCProtocolRefListInfo ObjCProtoListInfo;
175 
ObjCCategoryDeclInfoObjCCategoryDeclInfo176   explicit ObjCCategoryDeclInfo(bool isImplementation)
177     : ObjCContainerDeclInfo(Info_ObjCCategory,
178                             /*isForwardRef=*/false,
179                             /*isRedeclaration=*/isImplementation,
180                             /*isImplementation=*/isImplementation) { }
181 
classofObjCCategoryDeclInfo182   static bool classof(const DeclInfo *D) {
183     return D->Kind == Info_ObjCCategory;
184   }
185 };
186 
187 struct ObjCPropertyDeclInfo : public DeclInfo {
188   CXIdxObjCPropertyDeclInfo ObjCPropDeclInfo;
189 
ObjCPropertyDeclInfoObjCPropertyDeclInfo190   ObjCPropertyDeclInfo()
191     : DeclInfo(Info_ObjCProperty,
192                /*isRedeclaration=*/false, /*isDefinition=*/false,
193                /*isContainer=*/false) { }
194 
classofObjCPropertyDeclInfo195   static bool classof(const DeclInfo *D) {
196     return D->Kind == Info_ObjCProperty;
197   }
198 };
199 
200 struct CXXClassDeclInfo : public DeclInfo {
201   CXIdxCXXClassDeclInfo CXXClassInfo;
202 
CXXClassDeclInfoCXXClassDeclInfo203   CXXClassDeclInfo(bool isRedeclaration, bool isDefinition)
204     : DeclInfo(Info_CXXClass, isRedeclaration, isDefinition, isDefinition) { }
205 
classofCXXClassDeclInfo206   static bool classof(const DeclInfo *D) {
207     return D->Kind == Info_CXXClass;
208   }
209 };
210 
211 struct AttrInfo : public CXIdxAttrInfo {
212   const Attr *A;
213 
AttrInfoAttrInfo214   AttrInfo(CXIdxAttrKind Kind, CXCursor C, CXIdxLoc Loc, const Attr *A) {
215     kind = Kind;
216     cursor = C;
217     loc = Loc;
218     this->A = A;
219   }
220 };
221 
222 struct IBOutletCollectionInfo : public AttrInfo {
223   EntityInfo ClassInfo;
224   CXIdxIBOutletCollectionAttrInfo IBCollInfo;
225 
IBOutletCollectionInfoIBOutletCollectionInfo226   IBOutletCollectionInfo(CXCursor C, CXIdxLoc Loc, const Attr *A) :
227     AttrInfo(CXIdxAttr_IBOutletCollection, C, Loc, A) {
228     assert(C.kind == CXCursor_IBOutletCollectionAttr);
229     IBCollInfo.objcClass = nullptr;
230   }
231 
232   IBOutletCollectionInfo(const IBOutletCollectionInfo &other);
233 
classofIBOutletCollectionInfo234   static bool classof(const AttrInfo *A) {
235     return A->kind == CXIdxAttr_IBOutletCollection;
236   }
237 };
238 
239 class AttrListInfo {
240   ScratchAlloc SA;
241 
242   SmallVector<AttrInfo, 2> Attrs;
243   SmallVector<IBOutletCollectionInfo, 2> IBCollAttrs;
244   SmallVector<CXIdxAttrInfo *, 2> CXAttrs;
245   unsigned ref_cnt;
246 
247   AttrListInfo(const AttrListInfo &) = delete;
248   void operator=(const AttrListInfo &) = delete;
249 public:
250   AttrListInfo(const Decl *D, CXIndexDataConsumer &IdxCtx);
251 
252   static IntrusiveRefCntPtr<AttrListInfo> create(const Decl *D,
253                                                  CXIndexDataConsumer &IdxCtx);
254 
getAttrs()255   const CXIdxAttrInfo *const *getAttrs() const {
256     if (CXAttrs.empty())
257       return nullptr;
258     return CXAttrs.data();
259   }
getNumAttrs()260   unsigned getNumAttrs() const { return (unsigned)CXAttrs.size(); }
261 
262   /// Retain/Release only useful when we allocate a AttrListInfo from the
263   /// BumpPtrAllocator, and not from the stack; so that we keep a pointer
264   // in the EntityInfo
Retain()265   void Retain() { ++ref_cnt; }
Release()266   void Release() {
267     assert (ref_cnt > 0 && "Reference count is already zero.");
268     if (--ref_cnt == 0) {
269       // Memory is allocated from a BumpPtrAllocator, no need to delete it.
270       this->~AttrListInfo();
271     }
272   }
273 };
274 
275 class CXIndexDataConsumer : public index::IndexDataConsumer {
276   ASTContext *Ctx;
277   CXClientData ClientData;
278   IndexerCallbacks &CB;
279   unsigned IndexOptions;
280   CXTranslationUnit CXTU;
281 
282   typedef llvm::DenseMap<const FileEntry *, CXIdxClientFile> FileMapTy;
283   typedef llvm::DenseMap<const DeclContext *, CXIdxClientContainer>
284     ContainerMapTy;
285   typedef llvm::DenseMap<const Decl *, CXIdxClientEntity> EntityMapTy;
286 
287   FileMapTy FileMap;
288   ContainerMapTy ContainerMap;
289   EntityMapTy EntityMap;
290 
291   typedef std::pair<const FileEntry *, const Decl *> RefFileOccurrence;
292   llvm::DenseSet<RefFileOccurrence> RefFileOccurrences;
293 
294   llvm::BumpPtrAllocator StrScratch;
295   unsigned StrAdapterCount;
296   friend class ScratchAlloc;
297 
298   struct ObjCProtocolListInfo {
299     SmallVector<CXIdxObjCProtocolRefInfo, 4> ProtInfos;
300     SmallVector<EntityInfo, 4> ProtEntities;
301     SmallVector<CXIdxObjCProtocolRefInfo *, 4> Prots;
302 
getListInfoObjCProtocolListInfo303     CXIdxObjCProtocolRefListInfo getListInfo() const {
304       CXIdxObjCProtocolRefListInfo Info = { Prots.data(),
305                                             (unsigned)Prots.size() };
306       return Info;
307     }
308 
309     ObjCProtocolListInfo(const ObjCProtocolList &ProtList,
310                          CXIndexDataConsumer &IdxCtx,
311                          ScratchAlloc &SA);
312   };
313 
314   struct CXXBasesListInfo {
315     SmallVector<CXIdxBaseClassInfo, 4> BaseInfos;
316     SmallVector<EntityInfo, 4> BaseEntities;
317     SmallVector<CXIdxBaseClassInfo *, 4> CXBases;
318 
getBasesCXXBasesListInfo319     const CXIdxBaseClassInfo *const *getBases() const {
320       return CXBases.data();
321     }
getNumBasesCXXBasesListInfo322     unsigned getNumBases() const { return (unsigned)CXBases.size(); }
323 
324     CXXBasesListInfo(const CXXRecordDecl *D,
325                      CXIndexDataConsumer &IdxCtx, ScratchAlloc &SA);
326 
327   private:
328     SourceLocation getBaseLoc(const CXXBaseSpecifier &Base) const;
329   };
330 
331   friend class AttrListInfo;
332 
333 public:
CXIndexDataConsumer(CXClientData clientData,IndexerCallbacks & indexCallbacks,unsigned indexOptions,CXTranslationUnit cxTU)334   CXIndexDataConsumer(CXClientData clientData, IndexerCallbacks &indexCallbacks,
335                       unsigned indexOptions, CXTranslationUnit cxTU)
336       : Ctx(nullptr), ClientData(clientData), CB(indexCallbacks),
337         IndexOptions(indexOptions), CXTU(cxTU), StrAdapterCount(0) {}
338 
getASTContext()339   ASTContext &getASTContext() const { return *Ctx; }
getCXTU()340   CXTranslationUnit getCXTU() const { return CXTU; }
341 
342   void setASTContext(ASTContext &ctx);
343   void setPreprocessor(std::shared_ptr<Preprocessor> PP) override;
344 
shouldSuppressRefs()345   bool shouldSuppressRefs() const {
346     return IndexOptions & CXIndexOpt_SuppressRedundantRefs;
347   }
348 
shouldIndexFunctionLocalSymbols()349   bool shouldIndexFunctionLocalSymbols() const {
350     return IndexOptions & CXIndexOpt_IndexFunctionLocalSymbols;
351   }
352 
shouldIndexImplicitTemplateInsts()353   bool shouldIndexImplicitTemplateInsts() const {
354     return IndexOptions & CXIndexOpt_IndexImplicitTemplateInstantiations;
355   }
356 
357   static bool isFunctionLocalDecl(const Decl *D);
358 
359   bool shouldAbort();
360 
hasDiagnosticCallback()361   bool hasDiagnosticCallback() const { return CB.diagnostic; }
362 
363   void enteredMainFile(const FileEntry *File);
364 
365   void ppIncludedFile(SourceLocation hashLoc, StringRef filename,
366                       OptionalFileEntryRef File, bool isImport, bool isAngled,
367                       bool isModuleImport);
368 
369   void importedModule(const ImportDecl *ImportD);
370   void importedPCH(const FileEntry *File);
371 
372   void startedTranslationUnit();
373 
374   void indexDiagnostics();
375 
376   void handleDiagnosticSet(CXDiagnosticSet CXDiagSet);
377 
378   bool handleFunction(const FunctionDecl *FD);
379 
380   bool handleVar(const VarDecl *D);
381 
382   bool handleField(const FieldDecl *D);
383 
384   bool handleEnumerator(const EnumConstantDecl *D);
385 
386   bool handleTagDecl(const TagDecl *D);
387 
388   bool handleTypedefName(const TypedefNameDecl *D);
389 
390   bool handleObjCInterface(const ObjCInterfaceDecl *D);
391   bool handleObjCImplementation(const ObjCImplementationDecl *D);
392 
393   bool handleObjCProtocol(const ObjCProtocolDecl *D);
394 
395   bool handleObjCCategory(const ObjCCategoryDecl *D);
396   bool handleObjCCategoryImpl(const ObjCCategoryImplDecl *D);
397 
398   bool handleObjCMethod(const ObjCMethodDecl *D, SourceLocation Loc);
399 
400   bool handleSynthesizedObjCProperty(const ObjCPropertyImplDecl *D);
401   bool handleSynthesizedObjCMethod(const ObjCMethodDecl *D, SourceLocation Loc,
402                                    const DeclContext *LexicalDC);
403 
404   bool handleObjCProperty(const ObjCPropertyDecl *D);
405 
406   bool handleNamespace(const NamespaceDecl *D);
407 
408   bool handleClassTemplate(const ClassTemplateDecl *D);
409   bool handleFunctionTemplate(const FunctionTemplateDecl *D);
410   bool handleTypeAliasTemplate(const TypeAliasTemplateDecl *D);
411 
412   bool handleConcept(const ConceptDecl *D);
413 
414   bool handleReference(const NamedDecl *D, SourceLocation Loc, CXCursor Cursor,
415                        const NamedDecl *Parent,
416                        const DeclContext *DC,
417                        const Expr *E = nullptr,
418                        CXIdxEntityRefKind Kind = CXIdxEntityRef_Direct,
419                        CXSymbolRole Role = CXSymbolRole_None);
420 
421   bool isNotFromSourceFile(SourceLocation Loc) const;
422 
423   void translateLoc(SourceLocation Loc, CXIdxClientFile *indexFile, CXFile *file,
424                     unsigned *line, unsigned *column, unsigned *offset);
425 
426   CXIdxClientContainer getClientContainerForDC(const DeclContext *DC) const;
427   void addContainerInMap(const DeclContext *DC, CXIdxClientContainer container);
428 
429   CXIdxClientEntity getClientEntity(const Decl *D) const;
430   void setClientEntity(const Decl *D, CXIdxClientEntity client);
431 
432   static bool isTemplateImplicitInstantiation(const Decl *D);
433 
434 private:
435   bool handleDeclOccurrence(const Decl *D, index::SymbolRoleSet Roles,
436                             ArrayRef<index::SymbolRelation> Relations,
437                             SourceLocation Loc, ASTNodeInfo ASTNode) override;
438 
439   bool handleModuleOccurrence(const ImportDecl *ImportD, const Module *Mod,
440                               index::SymbolRoleSet Roles,
441                               SourceLocation Loc) override;
442 
443   void finish() override;
444 
445   bool handleDecl(const NamedDecl *D,
446                   SourceLocation Loc, CXCursor Cursor,
447                   DeclInfo &DInfo,
448                   const DeclContext *LexicalDC = nullptr,
449                   const DeclContext *SemaDC = nullptr);
450 
451   bool handleObjCContainer(const ObjCContainerDecl *D,
452                            SourceLocation Loc, CXCursor Cursor,
453                            ObjCContainerDeclInfo &ContDInfo);
454 
455   bool handleCXXRecordDecl(const CXXRecordDecl *RD, const NamedDecl *OrigD);
456 
457   bool markEntityOccurrenceInFile(const NamedDecl *D, SourceLocation Loc);
458 
459   const NamedDecl *getEntityDecl(const NamedDecl *D) const;
460 
461   const DeclContext *getEntityContainer(const Decl *D) const;
462 
463   CXIdxClientFile getIndexFile(const FileEntry *File);
464 
465   CXIdxLoc getIndexLoc(SourceLocation Loc) const;
466 
467   void getEntityInfo(const NamedDecl *D,
468                      EntityInfo &EntityInfo,
469                      ScratchAlloc &SA);
470 
471   void getContainerInfo(const DeclContext *DC, ContainerInfo &ContInfo);
472 
getCursor(const Decl * D)473   CXCursor getCursor(const Decl *D) {
474     return cxcursor::MakeCXCursor(D, CXTU);
475   }
476 
477   CXCursor getRefCursor(const NamedDecl *D, SourceLocation Loc);
478 
479   static bool shouldIgnoreIfImplicit(const Decl *D);
480 };
481 
ScratchAlloc(CXIndexDataConsumer & idxCtx)482 inline ScratchAlloc::ScratchAlloc(CXIndexDataConsumer &idxCtx) : IdxCtx(idxCtx) {
483   ++IdxCtx.StrAdapterCount;
484 }
ScratchAlloc(const ScratchAlloc & SA)485 inline ScratchAlloc::ScratchAlloc(const ScratchAlloc &SA) : IdxCtx(SA.IdxCtx) {
486   ++IdxCtx.StrAdapterCount;
487 }
488 
~ScratchAlloc()489 inline ScratchAlloc::~ScratchAlloc() {
490   --IdxCtx.StrAdapterCount;
491   if (IdxCtx.StrAdapterCount == 0)
492     IdxCtx.StrScratch.Reset();
493 }
494 
495 template <typename T>
allocate()496 inline T *ScratchAlloc::allocate() {
497   return IdxCtx.StrScratch.Allocate<T>();
498 }
499 
500 }} // end clang::cxindex
501 
502 #endif
503