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