//===- IndexingContext.h - Higher level API functions ------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "Index_Internal.h" #include "CXCursor.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclGroup.h" #include "llvm/ADT/DenseSet.h" #include <deque> namespace clang { class FileEntry; class ObjCPropertyDecl; class ClassTemplateDecl; class FunctionTemplateDecl; class TypeAliasTemplateDecl; class ClassTemplateSpecializationDecl; namespace cxindex { class IndexingContext; class AttrListInfo; class ScratchAlloc { IndexingContext &IdxCtx; public: explicit ScratchAlloc(IndexingContext &indexCtx); ScratchAlloc(const ScratchAlloc &SA); ~ScratchAlloc(); const char *toCStr(StringRef Str); const char *copyCStr(StringRef Str); template <typename T> T *allocate(); }; struct EntityInfo : public CXIdxEntityInfo { const NamedDecl *Dcl; IndexingContext *IndexCtx; IntrusiveRefCntPtr<AttrListInfo> AttrList; EntityInfo() { name = USR = 0; attributes = 0; numAttributes = 0; } }; struct ContainerInfo : public CXIdxContainerInfo { const DeclContext *DC; IndexingContext *IndexCtx; }; struct DeclInfo : public CXIdxDeclInfo { enum DInfoKind { Info_Decl, Info_ObjCContainer, Info_ObjCInterface, Info_ObjCProtocol, Info_ObjCCategory, Info_ObjCProperty, Info_CXXClass }; DInfoKind Kind; EntityInfo EntInfo; ContainerInfo SemanticContainer; ContainerInfo LexicalContainer; ContainerInfo DeclAsContainer; DeclInfo(bool isRedeclaration, bool isDefinition, bool isContainer) : Kind(Info_Decl) { this->isRedeclaration = isRedeclaration; this->isDefinition = isDefinition; this->isContainer = isContainer; attributes = 0; numAttributes = 0; declAsContainer = semanticContainer = lexicalContainer = 0; } DeclInfo(DInfoKind K, bool isRedeclaration, bool isDefinition, bool isContainer) : Kind(K) { this->isRedeclaration = isRedeclaration; this->isDefinition = isDefinition; this->isContainer = isContainer; attributes = 0; numAttributes = 0; declAsContainer = semanticContainer = lexicalContainer = 0; } static bool classof(const DeclInfo *) { return true; } }; struct ObjCContainerDeclInfo : public DeclInfo { CXIdxObjCContainerDeclInfo ObjCContDeclInfo; ObjCContainerDeclInfo(bool isForwardRef, bool isRedeclaration, bool isImplementation) : DeclInfo(Info_ObjCContainer, isRedeclaration, /*isDefinition=*/!isForwardRef, /*isContainer=*/!isForwardRef) { init(isForwardRef, isImplementation); } ObjCContainerDeclInfo(DInfoKind K, bool isForwardRef, bool isRedeclaration, bool isImplementation) : DeclInfo(K, isRedeclaration, /*isDefinition=*/!isForwardRef, /*isContainer=*/!isForwardRef) { init(isForwardRef, isImplementation); } static bool classof(const DeclInfo *D) { return Info_ObjCContainer <= D->Kind && D->Kind <= Info_ObjCCategory; } static bool classof(const ObjCContainerDeclInfo *D) { return true; } private: void init(bool isForwardRef, bool isImplementation) { if (isForwardRef) ObjCContDeclInfo.kind = CXIdxObjCContainer_ForwardRef; else if (isImplementation) ObjCContDeclInfo.kind = CXIdxObjCContainer_Implementation; else ObjCContDeclInfo.kind = CXIdxObjCContainer_Interface; } }; struct ObjCInterfaceDeclInfo : public ObjCContainerDeclInfo { CXIdxObjCInterfaceDeclInfo ObjCInterDeclInfo; CXIdxObjCProtocolRefListInfo ObjCProtoListInfo; ObjCInterfaceDeclInfo(const ObjCInterfaceDecl *D) : ObjCContainerDeclInfo(Info_ObjCInterface, /*isForwardRef=*/false, /*isRedeclaration=*/D->getPreviousDecl() != 0, /*isImplementation=*/false) { } static bool classof(const DeclInfo *D) { return D->Kind == Info_ObjCInterface; } static bool classof(const ObjCInterfaceDeclInfo *D) { return true; } }; struct ObjCProtocolDeclInfo : public ObjCContainerDeclInfo { CXIdxObjCProtocolRefListInfo ObjCProtoRefListInfo; ObjCProtocolDeclInfo(const ObjCProtocolDecl *D) : ObjCContainerDeclInfo(Info_ObjCProtocol, /*isForwardRef=*/false, /*isRedeclaration=*/D->getPreviousDecl(), /*isImplementation=*/false) { } static bool classof(const DeclInfo *D) { return D->Kind == Info_ObjCProtocol; } static bool classof(const ObjCProtocolDeclInfo *D) { return true; } }; struct ObjCCategoryDeclInfo : public ObjCContainerDeclInfo { CXIdxObjCCategoryDeclInfo ObjCCatDeclInfo; CXIdxObjCProtocolRefListInfo ObjCProtoListInfo; explicit ObjCCategoryDeclInfo(bool isImplementation) : ObjCContainerDeclInfo(Info_ObjCCategory, /*isForwardRef=*/false, /*isRedeclaration=*/isImplementation, /*isImplementation=*/isImplementation) { } static bool classof(const DeclInfo *D) { return D->Kind == Info_ObjCCategory; } static bool classof(const ObjCCategoryDeclInfo *D) { return true; } }; struct ObjCPropertyDeclInfo : public DeclInfo { CXIdxObjCPropertyDeclInfo ObjCPropDeclInfo; ObjCPropertyDeclInfo() : DeclInfo(Info_ObjCProperty, /*isRedeclaration=*/false, /*isDefinition=*/false, /*isContainer=*/false) { } static bool classof(const DeclInfo *D) { return D->Kind == Info_ObjCProperty; } static bool classof(const ObjCPropertyDeclInfo *D) { return true; } }; struct CXXClassDeclInfo : public DeclInfo { CXIdxCXXClassDeclInfo CXXClassInfo; CXXClassDeclInfo(bool isRedeclaration, bool isDefinition) : DeclInfo(Info_CXXClass, isRedeclaration, isDefinition, isDefinition) { } static bool classof(const DeclInfo *D) { return D->Kind == Info_CXXClass; } static bool classof(const CXXClassDeclInfo *D) { return true; } }; struct AttrInfo : public CXIdxAttrInfo { const Attr *A; AttrInfo(CXIdxAttrKind Kind, CXCursor C, CXIdxLoc Loc, const Attr *A) { kind = Kind; cursor = C; loc = Loc; this->A = A; } static bool classof(const AttrInfo *) { return true; } }; struct IBOutletCollectionInfo : public AttrInfo { EntityInfo ClassInfo; CXIdxIBOutletCollectionAttrInfo IBCollInfo; IBOutletCollectionInfo(CXCursor C, CXIdxLoc Loc, const Attr *A) : AttrInfo(CXIdxAttr_IBOutletCollection, C, Loc, A) { assert(C.kind == CXCursor_IBOutletCollectionAttr); IBCollInfo.objcClass = 0; } IBOutletCollectionInfo(const IBOutletCollectionInfo &other); static bool classof(const AttrInfo *A) { return A->kind == CXIdxAttr_IBOutletCollection; } static bool classof(const IBOutletCollectionInfo *D) { return true; } }; class AttrListInfo { ScratchAlloc SA; SmallVector<AttrInfo, 2> Attrs; SmallVector<IBOutletCollectionInfo, 2> IBCollAttrs; SmallVector<CXIdxAttrInfo *, 2> CXAttrs; unsigned ref_cnt; AttrListInfo(const AttrListInfo&); // DO NOT IMPLEMENT void operator=(const AttrListInfo&); // DO NOT IMPLEMENT public: AttrListInfo(const Decl *D, IndexingContext &IdxCtx); static IntrusiveRefCntPtr<AttrListInfo> create(const Decl *D, IndexingContext &IdxCtx); const CXIdxAttrInfo *const *getAttrs() const { if (CXAttrs.empty()) return 0; return CXAttrs.data(); } unsigned getNumAttrs() const { return (unsigned)CXAttrs.size(); } /// \brief Retain/Release only useful when we allocate a AttrListInfo from the /// BumpPtrAllocator, and not from the stack; so that we keep a pointer // in the EntityInfo void Retain() { ++ref_cnt; } void Release() { assert (ref_cnt > 0 && "Reference count is already zero."); if (--ref_cnt == 0) { // Memory is allocated from a BumpPtrAllocator, no need to delete it. this->~AttrListInfo(); } } }; struct RefFileOccurence { const FileEntry *File; const Decl *Dcl; RefFileOccurence(const FileEntry *File, const Decl *Dcl) : File(File), Dcl(Dcl) { } }; class IndexingContext { ASTContext *Ctx; CXClientData ClientData; IndexerCallbacks &CB; unsigned IndexOptions; CXTranslationUnit CXTU; typedef llvm::DenseMap<const FileEntry *, CXIdxClientFile> FileMapTy; typedef llvm::DenseMap<const DeclContext *, CXIdxClientContainer> ContainerMapTy; typedef llvm::DenseMap<const Decl *, CXIdxClientEntity> EntityMapTy; FileMapTy FileMap; ContainerMapTy ContainerMap; EntityMapTy EntityMap; llvm::DenseSet<RefFileOccurence> RefFileOccurences; std::deque<DeclGroupRef> TUDeclsInObjCContainer; llvm::BumpPtrAllocator StrScratch; unsigned StrAdapterCount; friend class ScratchAlloc; struct ObjCProtocolListInfo { SmallVector<CXIdxObjCProtocolRefInfo, 4> ProtInfos; SmallVector<EntityInfo, 4> ProtEntities; SmallVector<CXIdxObjCProtocolRefInfo *, 4> Prots; CXIdxObjCProtocolRefListInfo getListInfo() const { CXIdxObjCProtocolRefListInfo Info = { Prots.data(), (unsigned)Prots.size() }; return Info; } ObjCProtocolListInfo(const ObjCProtocolList &ProtList, IndexingContext &IdxCtx, ScratchAlloc &SA); }; struct CXXBasesListInfo { SmallVector<CXIdxBaseClassInfo, 4> BaseInfos; SmallVector<EntityInfo, 4> BaseEntities; SmallVector<CXIdxBaseClassInfo *, 4> CXBases; const CXIdxBaseClassInfo *const *getBases() const { return CXBases.data(); } unsigned getNumBases() const { return (unsigned)CXBases.size(); } CXXBasesListInfo(const CXXRecordDecl *D, IndexingContext &IdxCtx, ScratchAlloc &SA); private: SourceLocation getBaseLoc(const CXXBaseSpecifier &Base) const; }; friend class AttrListInfo; public: IndexingContext(CXClientData clientData, IndexerCallbacks &indexCallbacks, unsigned indexOptions, CXTranslationUnit cxTU) : Ctx(0), ClientData(clientData), CB(indexCallbacks), IndexOptions(indexOptions), CXTU(cxTU), StrScratch(/*size=*/1024), StrAdapterCount(0) { } ASTContext &getASTContext() const { return *Ctx; } void setASTContext(ASTContext &ctx); void setPreprocessor(Preprocessor &PP); bool shouldSuppressRefs() const { return IndexOptions & CXIndexOpt_SuppressRedundantRefs; } bool shouldIndexFunctionLocalSymbols() const { return IndexOptions & CXIndexOpt_IndexFunctionLocalSymbols; } bool shouldIndexImplicitTemplateInsts() const { return IndexOptions & CXIndexOpt_IndexImplicitTemplateInstantiations; } bool shouldAbort(); bool hasDiagnosticCallback() const { return CB.diagnostic; } void enteredMainFile(const FileEntry *File); void ppIncludedFile(SourceLocation hashLoc, StringRef filename, const FileEntry *File, bool isImport, bool isAngled); void startedTranslationUnit(); void indexDecl(const Decl *D); void indexTagDecl(const TagDecl *D); void indexTypeSourceInfo(TypeSourceInfo *TInfo, const NamedDecl *Parent, const DeclContext *DC = 0); void indexTypeLoc(TypeLoc TL, const NamedDecl *Parent, const DeclContext *DC = 0); void indexNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS, const NamedDecl *Parent, const DeclContext *DC = 0); void indexDeclContext(const DeclContext *DC); void indexBody(const Stmt *S, const NamedDecl *Parent, const DeclContext *DC = 0); void handleDiagnosticSet(CXDiagnosticSet CXDiagSet); bool handleFunction(const FunctionDecl *FD); bool handleVar(const VarDecl *D); bool handleField(const FieldDecl *D); bool handleEnumerator(const EnumConstantDecl *D); bool handleTagDecl(const TagDecl *D); bool handleTypedefName(const TypedefNameDecl *D); bool handleObjCInterface(const ObjCInterfaceDecl *D); bool handleObjCImplementation(const ObjCImplementationDecl *D); bool handleObjCProtocol(const ObjCProtocolDecl *D); bool handleObjCCategory(const ObjCCategoryDecl *D); bool handleObjCCategoryImpl(const ObjCCategoryImplDecl *D); bool handleObjCMethod(const ObjCMethodDecl *D); bool handleSynthesizedObjCProperty(const ObjCPropertyImplDecl *D); bool handleSynthesizedObjCMethod(const ObjCMethodDecl *D, SourceLocation Loc, const DeclContext *LexicalDC); bool handleObjCProperty(const ObjCPropertyDecl *D); bool handleNamespace(const NamespaceDecl *D); bool handleClassTemplate(const ClassTemplateDecl *D); bool handleFunctionTemplate(const FunctionTemplateDecl *D); bool handleTypeAliasTemplate(const TypeAliasTemplateDecl *D); bool handleReference(const NamedDecl *D, SourceLocation Loc, CXCursor Cursor, const NamedDecl *Parent, const DeclContext *DC, const Expr *E = 0, CXIdxEntityRefKind Kind = CXIdxEntityRef_Direct); bool handleReference(const NamedDecl *D, SourceLocation Loc, const NamedDecl *Parent, const DeclContext *DC, const Expr *E = 0, CXIdxEntityRefKind Kind = CXIdxEntityRef_Direct); bool isNotFromSourceFile(SourceLocation Loc) const; void indexTopLevelDecl(Decl *D); void indexTUDeclsInObjCContainer(); void indexDeclGroupRef(DeclGroupRef DG); void addTUDeclInObjCContainer(DeclGroupRef DG) { TUDeclsInObjCContainer.push_back(DG); } void translateLoc(SourceLocation Loc, CXIdxClientFile *indexFile, CXFile *file, unsigned *line, unsigned *column, unsigned *offset); CXIdxClientContainer getClientContainerForDC(const DeclContext *DC) const; void addContainerInMap(const DeclContext *DC, CXIdxClientContainer container); CXIdxClientEntity getClientEntity(const Decl *D) const; void setClientEntity(const Decl *D, CXIdxClientEntity client); static bool isTemplateImplicitInstantiation(const Decl *D); private: bool handleDecl(const NamedDecl *D, SourceLocation Loc, CXCursor Cursor, DeclInfo &DInfo, const DeclContext *LexicalDC = 0); bool handleObjCContainer(const ObjCContainerDecl *D, SourceLocation Loc, CXCursor Cursor, ObjCContainerDeclInfo &ContDInfo); bool handleCXXRecordDecl(const CXXRecordDecl *RD, const NamedDecl *OrigD); bool markEntityOccurrenceInFile(const NamedDecl *D, SourceLocation Loc); const NamedDecl *getEntityDecl(const NamedDecl *D) const; const DeclContext *getEntityContainer(const Decl *D) const; CXIdxClientFile getIndexFile(const FileEntry *File); CXIdxLoc getIndexLoc(SourceLocation Loc) const; void getEntityInfo(const NamedDecl *D, EntityInfo &EntityInfo, ScratchAlloc &SA); void getContainerInfo(const DeclContext *DC, ContainerInfo &ContInfo); CXCursor getCursor(const Decl *D) { return cxcursor::MakeCXCursor(const_cast<Decl*>(D), CXTU); } CXCursor getRefCursor(const NamedDecl *D, SourceLocation Loc); static bool shouldIgnoreIfImplicit(const Decl *D); }; inline ScratchAlloc::ScratchAlloc(IndexingContext &idxCtx) : IdxCtx(idxCtx) { ++IdxCtx.StrAdapterCount; } inline ScratchAlloc::ScratchAlloc(const ScratchAlloc &SA) : IdxCtx(SA.IdxCtx) { ++IdxCtx.StrAdapterCount; } inline ScratchAlloc::~ScratchAlloc() { --IdxCtx.StrAdapterCount; if (IdxCtx.StrAdapterCount == 0) IdxCtx.StrScratch.Reset(); } template <typename T> inline T *ScratchAlloc::allocate() { return IdxCtx.StrScratch.Allocate<T>(); } }} // end clang::cxindex namespace llvm { /// Define DenseMapInfo so that FileID's can be used as keys in DenseMap and /// DenseSets. template <> struct DenseMapInfo<clang::cxindex::RefFileOccurence> { static inline clang::cxindex::RefFileOccurence getEmptyKey() { return clang::cxindex::RefFileOccurence(0, 0); } static inline clang::cxindex::RefFileOccurence getTombstoneKey() { return clang::cxindex::RefFileOccurence((const clang::FileEntry *)~0, (const clang::Decl *)~0); } static unsigned getHashValue(clang::cxindex::RefFileOccurence S) { llvm::FoldingSetNodeID ID; ID.AddPointer(S.File); ID.AddPointer(S.Dcl); return ID.ComputeHash(); } static bool isEqual(clang::cxindex::RefFileOccurence LHS, clang::cxindex::RefFileOccurence RHS) { return LHS.File == RHS.File && LHS.Dcl == RHS.Dcl; } }; }