//===- CIndexHigh.cpp - 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 "IndexingContext.h" #include "CXTranslationUnit.h" #include "CIndexDiagnostic.h" #include "clang/Frontend/ASTUnit.h" #include "clang/AST/DeclObjC.h" using namespace clang; using namespace cxindex; using namespace cxcursor; IndexingContext::ObjCProtocolListInfo::ObjCProtocolListInfo( const ObjCProtocolList &ProtList, IndexingContext &IdxCtx, StrAdapter &SA) { ObjCInterfaceDecl::protocol_loc_iterator LI = ProtList.loc_begin(); for (ObjCInterfaceDecl::protocol_iterator I = ProtList.begin(), E = ProtList.end(); I != E; ++I, ++LI) { SourceLocation Loc = *LI; ObjCProtocolDecl *PD = *I; ProtEntities.push_back(CXIdxEntityInfo()); IdxCtx.getEntityInfo(PD, ProtEntities.back(), SA); CXIdxObjCProtocolRefInfo ProtInfo = { 0, MakeCursorObjCProtocolRef(PD, Loc, IdxCtx.CXTU), IdxCtx.getIndexLoc(Loc) }; ProtInfos.push_back(ProtInfo); } for (unsigned i = 0, e = ProtInfos.size(); i != e; ++i) ProtInfos[i].protocol = &ProtEntities[i]; for (unsigned i = 0, e = ProtInfos.size(); i != e; ++i) Prots.push_back(&ProtInfos[i]); } const char *IndexingContext::StrAdapter::toCStr(StringRef Str) { if (Str.empty()) return ""; if (Str.data()[Str.size()] == '\0') return Str.data(); Scratch += Str; Scratch.push_back('\0'); return Scratch.data() + (Scratch.size() - Str.size() - 1); } void IndexingContext::setASTContext(ASTContext &ctx) { Ctx = &ctx; static_cast(CXTU->TUData)->setASTContext(&ctx); } void IndexingContext::enteredMainFile(const FileEntry *File) { if (File && CB.enteredMainFile) { CXIdxClientFile idxFile = CB.enteredMainFile(ClientData, (CXFile)File, 0); FileMap[File] = idxFile; } } void IndexingContext::ppIncludedFile(SourceLocation hashLoc, StringRef filename, const FileEntry *File, bool isImport, bool isAngled) { if (!CB.ppIncludedFile) return; StrAdapter SA(*this); CXIdxIncludedFileInfo Info = { getIndexLoc(hashLoc), SA.toCStr(filename), (CXFile)File, isImport, isAngled }; CXIdxClientFile idxFile = CB.ppIncludedFile(ClientData, &Info); FileMap[File] = idxFile; } void IndexingContext::startedTranslationUnit() { CXIdxClientContainer idxCont = 0; if (CB.startedTranslationUnit) idxCont = CB.startedTranslationUnit(ClientData, 0); addContainerInMap(Ctx->getTranslationUnitDecl(), idxCont); } void IndexingContext::handleDiagnostic(const StoredDiagnostic &StoredDiag) { if (!CB.diagnostic) return; CXStoredDiagnostic CXDiag(StoredDiag, Ctx->getLangOptions()); CB.diagnostic(ClientData, &CXDiag, 0); } void IndexingContext::handleDiagnostic(CXDiagnostic CXDiag) { if (!CB.diagnostic) return; CB.diagnostic(ClientData, CXDiag, 0); } void IndexingContext::handleDecl(const NamedDecl *D, SourceLocation Loc, CXCursor Cursor, DeclInfo &DInfo) { if (!CB.indexDeclaration) return; StrAdapter SA(*this); getEntityInfo(D, DInfo.CXEntInfo, SA); DInfo.entityInfo = &DInfo.CXEntInfo; DInfo.cursor = Cursor; DInfo.loc = getIndexLoc(Loc); DInfo.container = getIndexContainer(D); DInfo.isImplicit = D->isImplicit(); CXIdxClientContainer clientCont = 0; CXIdxDeclOut DeclOut = { DInfo.isContainer ? &clientCont : 0 }; CB.indexDeclaration(ClientData, &DInfo, &DeclOut); if (DInfo.isContainer) addContainerInMap(cast(D), clientCont); } void IndexingContext::handleObjCContainer(const ObjCContainerDecl *D, SourceLocation Loc, CXCursor Cursor, ObjCContainerDeclInfo &ContDInfo) { ContDInfo.ObjCContDeclInfo.declInfo = &ContDInfo; handleDecl(D, Loc, Cursor, ContDInfo); } void IndexingContext::handleFunction(const FunctionDecl *D) { DeclInfo DInfo(!D->isFirstDeclaration(), D->isThisDeclarationADefinition(), D->isThisDeclarationADefinition()); handleDecl(D, D->getLocation(), getCursor(D), DInfo); } void IndexingContext::handleVar(const VarDecl *D) { DeclInfo DInfo(!D->isFirstDeclaration(), D->isThisDeclarationADefinition(), /*isContainer=*/false); handleDecl(D, D->getLocation(), getCursor(D), DInfo); } void IndexingContext::handleField(const FieldDecl *D) { DeclInfo DInfo(/*isRedeclaration=*/false, /*isDefinition=*/true, /*isContainer=*/false); handleDecl(D, D->getLocation(), getCursor(D), DInfo); } void IndexingContext::handleEnumerator(const EnumConstantDecl *D) { DeclInfo DInfo(/*isRedeclaration=*/false, /*isDefinition=*/true, /*isContainer=*/false); handleDecl(D, D->getLocation(), getCursor(D), DInfo); } void IndexingContext::handleTagDecl(const TagDecl *D) { DeclInfo DInfo(!D->isFirstDeclaration(), D->isThisDeclarationADefinition(), D->isThisDeclarationADefinition()); handleDecl(D, D->getLocation(), getCursor(D), DInfo); } void IndexingContext::handleTypedef(const TypedefDecl *D) { DeclInfo DInfo(!D->isFirstDeclaration(), /*isDefinition=*/true, /*isContainer=*/false); handleDecl(D, D->getLocation(), getCursor(D), DInfo); } void IndexingContext::handleObjCClass(const ObjCClassDecl *D) { const ObjCClassDecl::ObjCClassRef *Ref = D->getForwardDecl(); ObjCInterfaceDecl *IFaceD = Ref->getInterface(); SourceLocation Loc = Ref->getLocation(); bool isRedeclaration = IFaceD->getLocation() != Loc; ObjCContainerDeclInfo ContDInfo(/*isForwardRef=*/true, isRedeclaration, /*isImplementation=*/false); handleObjCContainer(IFaceD, Loc, MakeCursorObjCClassRef(IFaceD, Loc, CXTU), ContDInfo); } void IndexingContext::handleObjCInterface(const ObjCInterfaceDecl *D) { StrAdapter SA(*this); CXIdxBaseClassInfo BaseClass; CXIdxEntityInfo BaseEntity; BaseClass.cursor = clang_getNullCursor(); if (ObjCInterfaceDecl *SuperD = D->getSuperClass()) { getEntityInfo(SuperD, BaseEntity, SA); SourceLocation SuperLoc = D->getSuperClassLoc(); BaseClass.base = &BaseEntity; BaseClass.cursor = MakeCursorObjCSuperClassRef(SuperD, SuperLoc, CXTU); BaseClass.loc = getIndexLoc(SuperLoc); } ObjCProtocolListInfo ProtInfo(D->getReferencedProtocols(), *this, SA); ObjCInterfaceDeclInfo InterInfo(D); InterInfo.ObjCProtoListInfo = ProtInfo.getListInfo(); InterInfo.ObjCInterDeclInfo.containerInfo = &InterInfo.ObjCContDeclInfo; InterInfo.ObjCInterDeclInfo.superInfo = D->getSuperClass() ? &BaseClass : 0; InterInfo.ObjCInterDeclInfo.protocols = &InterInfo.ObjCProtoListInfo; handleObjCContainer(D, D->getLocation(), getCursor(D), InterInfo); } void IndexingContext::handleObjCImplementation( const ObjCImplementationDecl *D) { ObjCContainerDeclInfo ContDInfo(/*isForwardRef=*/false, /*isRedeclaration=*/true, /*isImplementation=*/true); handleObjCContainer(D, D->getLocation(), getCursor(D), ContDInfo); } void IndexingContext::handleObjCForwardProtocol(const ObjCProtocolDecl *D, SourceLocation Loc, bool isRedeclaration) { ObjCContainerDeclInfo ContDInfo(/*isForwardRef=*/true, isRedeclaration, /*isImplementation=*/false); handleObjCContainer(D, Loc, MakeCursorObjCProtocolRef(D, Loc, CXTU), ContDInfo); } void IndexingContext::handleObjCProtocol(const ObjCProtocolDecl *D) { StrAdapter SA(*this); ObjCProtocolListInfo ProtListInfo(D->getReferencedProtocols(), *this, SA); ObjCProtocolDeclInfo ProtInfo(D); ProtInfo.ObjCProtoRefListInfo = ProtListInfo.getListInfo(); handleObjCContainer(D, D->getLocation(), getCursor(D), ProtInfo); } void IndexingContext::handleObjCCategory(const ObjCCategoryDecl *D) { ObjCCategoryDeclInfo CatDInfo(/*isImplementation=*/false); CXIdxEntityInfo ClassEntity; StrAdapter SA(*this); const ObjCInterfaceDecl *IFaceD = D->getClassInterface(); SourceLocation ClassLoc = D->getLocation(); SourceLocation CategoryLoc = D->getCategoryNameLoc(); getEntityInfo(IFaceD, ClassEntity, SA); CatDInfo.ObjCCatDeclInfo.containerInfo = &CatDInfo.ObjCContDeclInfo; if (IFaceD) { CatDInfo.ObjCCatDeclInfo.objcClass = &ClassEntity; CatDInfo.ObjCCatDeclInfo.classCursor = MakeCursorObjCClassRef(IFaceD, ClassLoc, CXTU); } else { CatDInfo.ObjCCatDeclInfo.objcClass = 0; CatDInfo.ObjCCatDeclInfo.classCursor = clang_getNullCursor(); } CatDInfo.ObjCCatDeclInfo.classLoc = getIndexLoc(ClassLoc); handleObjCContainer(D, CategoryLoc, getCursor(D), CatDInfo); } void IndexingContext::handleObjCCategoryImpl(const ObjCCategoryImplDecl *D) { const ObjCCategoryDecl *CatD = D->getCategoryDecl(); ObjCCategoryDeclInfo CatDInfo(/*isImplementation=*/true); CXIdxEntityInfo ClassEntity; StrAdapter SA(*this); getEntityInfo(CatD->getClassInterface(), ClassEntity, SA); CatDInfo.ObjCCatDeclInfo.containerInfo = &CatDInfo.ObjCContDeclInfo; CatDInfo.ObjCCatDeclInfo.objcClass = &ClassEntity; handleObjCContainer(D, D->getLocation(), getCursor(D), CatDInfo); } void IndexingContext::handleObjCMethod(const ObjCMethodDecl *D) { DeclInfo DInfo(!D->isCanonicalDecl(), D->isThisDeclarationADefinition(), D->isThisDeclarationADefinition()); handleDecl(D, D->getLocation(), getCursor(D), DInfo); } void IndexingContext::handleObjCProperty(const ObjCPropertyDecl *D) { DeclInfo DInfo(/*isRedeclaration=*/false, /*isDefinition=*/false, /*isContainer=*/false); handleDecl(D, D->getLocation(), getCursor(D), DInfo); } void IndexingContext::handleReference(const NamedDecl *D, SourceLocation Loc, const NamedDecl *Parent, const DeclContext *DC, const Expr *E, CXIdxEntityRefKind Kind) { if (Loc.isInvalid()) return; if (!CB.indexEntityReference) return; if (isNotFromSourceFile(D->getLocation())) return; D = getEntityDecl(D); if (onlyOneRefPerFile()) { SourceManager &SM = Ctx->getSourceManager(); SourceLocation FileLoc = SM.getFileLoc(Loc); std::pair LocInfo = SM.getDecomposedLoc(Loc); FileID FID = LocInfo.first; if (FID.isInvalid()) return; const FileEntry *FE = SM.getFileEntryForID(FID); if (!FE) return; RefFileOccurence RefOccur(FE, D); std::pair::iterator, bool> res = RefFileOccurences.insert(RefOccur); if (!res.second) return; // already in map. } StrAdapter SA(*this); CXCursor Cursor = E ? MakeCXCursor(const_cast(E), const_cast(cast(DC)), CXTU) : getRefCursor(D, Loc); CXIdxEntityInfo RefEntity, ParentEntity; getEntityInfo(D, RefEntity, SA); getEntityInfo(Parent, ParentEntity, SA); CXIdxEntityRefInfo Info = { Cursor, getIndexLoc(Loc), &RefEntity, Parent ? &ParentEntity : 0, getIndexContainerForDC(DC), Kind }; CB.indexEntityReference(ClientData, &Info); } bool IndexingContext::isNotFromSourceFile(SourceLocation Loc) const { if (Loc.isInvalid()) return true; SourceManager &SM = Ctx->getSourceManager(); SourceLocation FileLoc = SM.getFileLoc(Loc); FileID FID = SM.getFileID(FileLoc); return SM.getFileEntryForID(FID) == 0; } void IndexingContext::addContainerInMap(const DeclContext *DC, CXIdxClientContainer container) { assert(getScopedContext(DC) == DC); ContainerMapTy::iterator I = ContainerMap.find(DC); if (I == ContainerMap.end()) { if (container) ContainerMap[DC] = container; return; } // Allow changing the container of a previously seen DeclContext so we // can handle invalid user code, like a function re-definition. if (container) I->second = container; else ContainerMap.erase(I); } const NamedDecl *IndexingContext::getEntityDecl(const NamedDecl *D) const { assert(D); D = cast(D->getCanonicalDecl()); if (const ObjCCategoryDecl *Cat = dyn_cast(D)) { if (Cat->IsClassExtension()) return getEntityDecl(Cat->getClassInterface()); } else if (const ObjCImplementationDecl * ImplD = dyn_cast(D)) { return getEntityDecl(ImplD->getClassInterface()); } else if (const ObjCCategoryImplDecl * CatImplD = dyn_cast(D)) { return getEntityDecl(CatImplD->getCategoryDecl()); } return D; } const DeclContext * IndexingContext::getScopedContext(const DeclContext *DC) const { // Local contexts are ignored for indexing. const DeclContext *FuncCtx = cast(DC)->getParentFunctionOrMethod(); if (FuncCtx) return FuncCtx; // We consider enums always scoped for indexing. if (isa(DC)) return DC; if (const NamespaceDecl *NS = dyn_cast(DC)) { if (NS->isAnonymousNamespace()) return getScopedContext(NS->getParent()); return NS; } return DC->getRedeclContext(); } CXIdxClientContainer IndexingContext::getIndexContainerForDC(const DeclContext *DC) const { DC = getScopedContext(DC); ContainerMapTy::const_iterator I = ContainerMap.find(DC); // assert(I != ContainerMap.end() && // "Failed to include a scoped context in the container map"); return I->second; } CXIdxClientFile IndexingContext::getIndexFile(const FileEntry *File) { if (!File) return 0; FileMapTy::iterator FI = FileMap.find(File); if (FI != FileMap.end()) return FI->second; return 0; } CXIdxLoc IndexingContext::getIndexLoc(SourceLocation Loc) const { CXIdxLoc idxLoc = { {0, 0}, 0 }; if (Loc.isInvalid()) return idxLoc; idxLoc.ptr_data[0] = (void*)this; idxLoc.int_data = Loc.getRawEncoding(); return idxLoc; } void IndexingContext::translateLoc(SourceLocation Loc, CXIdxClientFile *indexFile, CXFile *file, unsigned *line, unsigned *column, unsigned *offset) { if (Loc.isInvalid()) return; SourceManager &SM = Ctx->getSourceManager(); Loc = SM.getFileLoc(Loc); std::pair LocInfo = SM.getDecomposedLoc(Loc); FileID FID = LocInfo.first; unsigned FileOffset = LocInfo.second; if (FID.isInvalid()) return; const FileEntry *FE = SM.getFileEntryForID(FID); if (indexFile) *indexFile = getIndexFile(FE); if (file) *file = (void *)FE; if (line) *line = SM.getLineNumber(FID, FileOffset); if (column) *column = SM.getColumnNumber(FID, FileOffset); if (offset) *offset = FileOffset; } void IndexingContext::getEntityInfo(const NamedDecl *D, CXIdxEntityInfo &EntityInfo, StrAdapter &SA) { if (!D) return; D = getEntityDecl(D); EntityInfo.kind = CXIdxEntity_Unexposed; if (const TagDecl *TD = dyn_cast(D)) { switch (TD->getTagKind()) { case TTK_Struct: EntityInfo.kind = CXIdxEntity_Struct; break; case TTK_Union: EntityInfo.kind = CXIdxEntity_Union; break; case TTK_Class: EntityInfo.kind = CXIdxEntity_CXXClass; break; case TTK_Enum: EntityInfo.kind = CXIdxEntity_Enum; break; } } else { switch (D->getKind()) { case Decl::Typedef: EntityInfo.kind = CXIdxEntity_Typedef; break; case Decl::Function: EntityInfo.kind = CXIdxEntity_Function; break; case Decl::Var: EntityInfo.kind = CXIdxEntity_Variable; break; case Decl::Field: EntityInfo.kind = CXIdxEntity_Field; break; case Decl::EnumConstant: EntityInfo.kind = CXIdxEntity_EnumConstant; break; case Decl::ObjCInterface: EntityInfo.kind = CXIdxEntity_ObjCClass; break; case Decl::ObjCProtocol: EntityInfo.kind = CXIdxEntity_ObjCProtocol; break; case Decl::ObjCCategory: EntityInfo.kind = CXIdxEntity_ObjCCategory; break; case Decl::ObjCMethod: if (cast(D)->isInstanceMethod()) EntityInfo.kind = CXIdxEntity_ObjCInstanceMethod; else EntityInfo.kind = CXIdxEntity_ObjCClassMethod; break; case Decl::ObjCProperty: EntityInfo.kind = CXIdxEntity_ObjCProperty; break; case Decl::ObjCIvar: EntityInfo.kind = CXIdxEntity_ObjCIvar; break; default: break; } } if (IdentifierInfo *II = D->getIdentifier()) { EntityInfo.name = SA.toCStr(II->getName()); } else if (isa(D) || isa(D)) { EntityInfo.name = 0; // anonymous record/namespace. } else { unsigned Begin = SA.getCurSize(); { llvm::raw_svector_ostream OS(SA.getBuffer()); D->printName(OS); } EntityInfo.name = SA.getCStr(Begin); } { unsigned Begin = SA.getCurSize(); bool Ignore = getDeclCursorUSR(D, SA.getBuffer()); if (Ignore) { EntityInfo.USR = ""; } else { EntityInfo.USR = SA.getCStr(Begin); } } } CXCursor IndexingContext::getRefCursor(const NamedDecl *D, SourceLocation Loc) { if (const TypeDecl *TD = dyn_cast(D)) return MakeCursorTypeRef(TD, Loc, CXTU); if (const ObjCInterfaceDecl *ID = dyn_cast(D)) return MakeCursorObjCClassRef(ID, Loc, CXTU); if (const ObjCProtocolDecl *PD = dyn_cast(D)) return MakeCursorObjCProtocolRef(PD, Loc, CXTU); //assert(0 && "not yet"); return clang_getNullCursor(); }