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