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