//===- 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;
}
};
}