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