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