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