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