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),
338       StrScratch(), StrAdapterCount(0) { }
339 
getASTContext()340   ASTContext &getASTContext() const { return *Ctx; }
getCXTU()341   CXTranslationUnit getCXTU() const { return CXTU; }
342 
343   void setASTContext(ASTContext &ctx);
344   void setPreprocessor(std::shared_ptr<Preprocessor> PP) override;
345 
shouldSuppressRefs()346   bool shouldSuppressRefs() const {
347     return IndexOptions & CXIndexOpt_SuppressRedundantRefs;
348   }
349 
shouldIndexFunctionLocalSymbols()350   bool shouldIndexFunctionLocalSymbols() const {
351     return IndexOptions & CXIndexOpt_IndexFunctionLocalSymbols;
352   }
353 
shouldIndexImplicitTemplateInsts()354   bool shouldIndexImplicitTemplateInsts() const {
355     return IndexOptions & CXIndexOpt_IndexImplicitTemplateInstantiations;
356   }
357 
358   static bool isFunctionLocalDecl(const Decl *D);
359 
360   bool shouldAbort();
361 
hasDiagnosticCallback()362   bool hasDiagnosticCallback() const { return CB.diagnostic; }
363 
364   void enteredMainFile(const FileEntry *File);
365 
366   void ppIncludedFile(SourceLocation hashLoc,
367                       StringRef filename, const FileEntry *File,
368                       bool isImport, bool isAngled, bool isModuleImport);
369 
370   void importedModule(const ImportDecl *ImportD);
371   void importedPCH(const FileEntry *File);
372 
373   void startedTranslationUnit();
374 
375   void indexDiagnostics();
376 
377   void handleDiagnosticSet(CXDiagnosticSet CXDiagSet);
378 
379   bool handleFunction(const FunctionDecl *FD);
380 
381   bool handleVar(const VarDecl *D);
382 
383   bool handleField(const FieldDecl *D);
384 
385   bool handleEnumerator(const EnumConstantDecl *D);
386 
387   bool handleTagDecl(const TagDecl *D);
388 
389   bool handleTypedefName(const TypedefNameDecl *D);
390 
391   bool handleObjCInterface(const ObjCInterfaceDecl *D);
392   bool handleObjCImplementation(const ObjCImplementationDecl *D);
393 
394   bool handleObjCProtocol(const ObjCProtocolDecl *D);
395 
396   bool handleObjCCategory(const ObjCCategoryDecl *D);
397   bool handleObjCCategoryImpl(const ObjCCategoryImplDecl *D);
398 
399   bool handleObjCMethod(const ObjCMethodDecl *D, SourceLocation Loc);
400 
401   bool handleSynthesizedObjCProperty(const ObjCPropertyImplDecl *D);
402   bool handleSynthesizedObjCMethod(const ObjCMethodDecl *D, SourceLocation Loc,
403                                    const DeclContext *LexicalDC);
404 
405   bool handleObjCProperty(const ObjCPropertyDecl *D);
406 
407   bool handleNamespace(const NamespaceDecl *D);
408 
409   bool handleClassTemplate(const ClassTemplateDecl *D);
410   bool handleFunctionTemplate(const FunctionTemplateDecl *D);
411   bool handleTypeAliasTemplate(const TypeAliasTemplateDecl *D);
412 
413   bool handleReference(const NamedDecl *D, SourceLocation Loc, CXCursor Cursor,
414                        const NamedDecl *Parent,
415                        const DeclContext *DC,
416                        const Expr *E = nullptr,
417                        CXIdxEntityRefKind Kind = CXIdxEntityRef_Direct,
418                        CXSymbolRole Role = CXSymbolRole_None);
419 
420   bool isNotFromSourceFile(SourceLocation Loc) const;
421 
422   void translateLoc(SourceLocation Loc, CXIdxClientFile *indexFile, CXFile *file,
423                     unsigned *line, unsigned *column, unsigned *offset);
424 
425   CXIdxClientContainer getClientContainerForDC(const DeclContext *DC) const;
426   void addContainerInMap(const DeclContext *DC, CXIdxClientContainer container);
427 
428   CXIdxClientEntity getClientEntity(const Decl *D) const;
429   void setClientEntity(const Decl *D, CXIdxClientEntity client);
430 
431   static bool isTemplateImplicitInstantiation(const Decl *D);
432 
433 private:
434   bool handleDeclOccurrence(const Decl *D, index::SymbolRoleSet Roles,
435                             ArrayRef<index::SymbolRelation> Relations,
436                             SourceLocation Loc, ASTNodeInfo ASTNode) override;
437 
438   bool handleModuleOccurrence(const ImportDecl *ImportD, const Module *Mod,
439                               index::SymbolRoleSet Roles,
440                               SourceLocation Loc) override;
441 
442   void finish() override;
443 
444   bool handleDecl(const NamedDecl *D,
445                   SourceLocation Loc, CXCursor Cursor,
446                   DeclInfo &DInfo,
447                   const DeclContext *LexicalDC = nullptr,
448                   const DeclContext *SemaDC = nullptr);
449 
450   bool handleObjCContainer(const ObjCContainerDecl *D,
451                            SourceLocation Loc, CXCursor Cursor,
452                            ObjCContainerDeclInfo &ContDInfo);
453 
454   bool handleCXXRecordDecl(const CXXRecordDecl *RD, const NamedDecl *OrigD);
455 
456   bool markEntityOccurrenceInFile(const NamedDecl *D, SourceLocation Loc);
457 
458   const NamedDecl *getEntityDecl(const NamedDecl *D) const;
459 
460   const DeclContext *getEntityContainer(const Decl *D) const;
461 
462   CXIdxClientFile getIndexFile(const FileEntry *File);
463 
464   CXIdxLoc getIndexLoc(SourceLocation Loc) const;
465 
466   void getEntityInfo(const NamedDecl *D,
467                      EntityInfo &EntityInfo,
468                      ScratchAlloc &SA);
469 
470   void getContainerInfo(const DeclContext *DC, ContainerInfo &ContInfo);
471 
getCursor(const Decl * D)472   CXCursor getCursor(const Decl *D) {
473     return cxcursor::MakeCXCursor(D, CXTU);
474   }
475 
476   CXCursor getRefCursor(const NamedDecl *D, SourceLocation Loc);
477 
478   static bool shouldIgnoreIfImplicit(const Decl *D);
479 };
480 
ScratchAlloc(CXIndexDataConsumer & idxCtx)481 inline ScratchAlloc::ScratchAlloc(CXIndexDataConsumer &idxCtx) : IdxCtx(idxCtx) {
482   ++IdxCtx.StrAdapterCount;
483 }
ScratchAlloc(const ScratchAlloc & SA)484 inline ScratchAlloc::ScratchAlloc(const ScratchAlloc &SA) : IdxCtx(SA.IdxCtx) {
485   ++IdxCtx.StrAdapterCount;
486 }
487 
~ScratchAlloc()488 inline ScratchAlloc::~ScratchAlloc() {
489   --IdxCtx.StrAdapterCount;
490   if (IdxCtx.StrAdapterCount == 0)
491     IdxCtx.StrScratch.Reset();
492 }
493 
494 template <typename T>
allocate()495 inline T *ScratchAlloc::allocate() {
496   return IdxCtx.StrScratch.Allocate<T>();
497 }
498 
499 }} // end clang::cxindex
500 
501 #endif
502