diff options
Diffstat (limited to 'tools/CIndex/CIndex.cpp')
-rw-r--r-- | tools/CIndex/CIndex.cpp | 745 |
1 files changed, 745 insertions, 0 deletions
diff --git a/tools/CIndex/CIndex.cpp b/tools/CIndex/CIndex.cpp new file mode 100644 index 000000000000..9204d1863d67 --- /dev/null +++ b/tools/CIndex/CIndex.cpp @@ -0,0 +1,745 @@ +//===- CIndex.cpp - Clang-C Source Indexing Library -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Clang-C Source Indexing library. +// +//===----------------------------------------------------------------------===// + +#include "clang-c/Index.h" +#include "clang/Index/Program.h" +#include "clang/Index/Indexer.h" +#include "clang/Index/ASTLocation.h" +#include "clang/Index/Utils.h" +#include "clang/AST/DeclVisitor.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/AST/Decl.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Frontend/ASTUnit.h" +#include <cstdio> +using namespace clang; +using namespace idx; + +namespace { + +static enum CXCursorKind TranslateDeclRefExpr(DeclRefExpr *DRE) +{ + NamedDecl *D = DRE->getDecl(); + if (isa<VarDecl>(D)) + return CXCursor_VarRef; + else if (isa<FunctionDecl>(D)) + return CXCursor_FunctionRef; + else if (isa<EnumConstantDecl>(D)) + return CXCursor_EnumConstantRef; + else + return CXCursor_NotImplemented; +} + +#if 0 +// Will be useful one day. +class CRefVisitor : public StmtVisitor<CRefVisitor> { + CXDecl CDecl; + CXDeclIterator Callback; + CXClientData CData; + + void Call(enum CXCursorKind CK, Stmt *SRef) { + CXCursor C = { CK, CDecl, SRef }; + Callback(CDecl, C, CData); + } + +public: + CRefVisitor(CXDecl C, CXDeclIterator cback, CXClientData D) : + CDecl(C), Callback(cback), CData(D) {} + + void VisitStmt(Stmt *S) { + for (Stmt::child_iterator C = S->child_begin(), CEnd = S->child_end(); + C != CEnd; ++C) + Visit(*C); + } + void VisitDeclRefExpr(DeclRefExpr *Node) { + Call(TranslateDeclRefExpr(Node), Node); + } + void VisitMemberExpr(MemberExpr *Node) { + Call(CXCursor_MemberRef, Node); + } + void VisitObjCMessageExpr(ObjCMessageExpr *Node) { + Call(CXCursor_ObjCSelectorRef, Node); + } + void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { + Call(CXCursor_ObjCIvarRef, Node); + } +}; +#endif + +// Translation Unit Visitor. +class TUVisitor : public DeclVisitor<TUVisitor> { + CXTranslationUnit TUnit; + CXTranslationUnitIterator Callback; + CXClientData CData; + + void Call(enum CXCursorKind CK, NamedDecl *ND) { + CXCursor C = { CK, ND, 0 }; + Callback(TUnit, C, CData); + } +public: + TUVisitor(CXTranslationUnit CTU, + CXTranslationUnitIterator cback, CXClientData D) : + TUnit(CTU), Callback(cback), CData(D) {} + + void VisitTranslationUnitDecl(TranslationUnitDecl *D) { + VisitDeclContext(dyn_cast<DeclContext>(D)); + } + void VisitDeclContext(DeclContext *DC) { + for (DeclContext::decl_iterator + I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) + Visit(*I); + } + void VisitTypedefDecl(TypedefDecl *ND) { + Call(CXCursor_TypedefDecl, ND); + } + void VisitTagDecl(TagDecl *ND) { + switch (ND->getTagKind()) { + case TagDecl::TK_struct: + Call(CXCursor_StructDecl, ND); + break; + case TagDecl::TK_class: + Call(CXCursor_ClassDecl, ND); + break; + case TagDecl::TK_union: + Call(CXCursor_UnionDecl, ND); + break; + case TagDecl::TK_enum: + Call(CXCursor_EnumDecl, ND); + break; + } + } + void VisitVarDecl(VarDecl *ND) { + Call(CXCursor_VarDecl, ND); + } + void VisitFunctionDecl(FunctionDecl *ND) { + Call(ND->isThisDeclarationADefinition() ? CXCursor_FunctionDefn + : CXCursor_FunctionDecl, ND); + } + void VisitObjCInterfaceDecl(ObjCInterfaceDecl *ND) { + Call(CXCursor_ObjCInterfaceDecl, ND); + } + void VisitObjCCategoryDecl(ObjCCategoryDecl *ND) { + Call(CXCursor_ObjCCategoryDecl, ND); + } + void VisitObjCProtocolDecl(ObjCProtocolDecl *ND) { + Call(CXCursor_ObjCProtocolDecl, ND); + } + void VisitObjCImplementationDecl(ObjCImplementationDecl *ND) { + Call(CXCursor_ObjCClassDefn, ND); + } + void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *ND) { + Call(CXCursor_ObjCCategoryDefn, ND); + } +}; + +// Declaration visitor. +class CDeclVisitor : public DeclVisitor<CDeclVisitor> { + CXDecl CDecl; + CXDeclIterator Callback; + CXClientData CData; + + void Call(enum CXCursorKind CK, NamedDecl *ND) { + // Disable the callback when the context is equal to the visiting decl. + if (CDecl == ND && !clang_isReference(CK)) + return; + CXCursor C = { CK, ND, 0 }; + Callback(CDecl, C, CData); + } +public: + CDeclVisitor(CXDecl C, CXDeclIterator cback, CXClientData D) : + CDecl(C), Callback(cback), CData(D) {} + + void VisitObjCCategoryDecl(ObjCCategoryDecl *ND) { + // Issue callbacks for the containing class. + Call(CXCursor_ObjCClassRef, ND); + // FIXME: Issue callbacks for protocol refs. + VisitDeclContext(dyn_cast<DeclContext>(ND)); + } + void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { + // Issue callbacks for super class. + if (D->getSuperClass()) + Call(CXCursor_ObjCSuperClassRef, D); + + for (ObjCProtocolDecl::protocol_iterator I = D->protocol_begin(), + E = D->protocol_end(); I != E; ++I) + Call(CXCursor_ObjCProtocolRef, *I); + VisitDeclContext(dyn_cast<DeclContext>(D)); + } + void VisitObjCProtocolDecl(ObjCProtocolDecl *PID) { + for (ObjCProtocolDecl::protocol_iterator I = PID->protocol_begin(), + E = PID->protocol_end(); I != E; ++I) + Call(CXCursor_ObjCProtocolRef, *I); + + VisitDeclContext(dyn_cast<DeclContext>(PID)); + } + void VisitTagDecl(TagDecl *D) { + VisitDeclContext(dyn_cast<DeclContext>(D)); + } + void VisitObjCImplementationDecl(ObjCImplementationDecl *D) { + VisitDeclContext(dyn_cast<DeclContext>(D)); + } + void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { + VisitDeclContext(dyn_cast<DeclContext>(D)); + } + void VisitDeclContext(DeclContext *DC) { + for (DeclContext::decl_iterator + I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) + Visit(*I); + } + void VisitEnumConstantDecl(EnumConstantDecl *ND) { + Call(CXCursor_EnumConstantDecl, ND); + } + void VisitFieldDecl(FieldDecl *ND) { + Call(CXCursor_FieldDecl, ND); + } + void VisitVarDecl(VarDecl *ND) { + Call(CXCursor_VarDecl, ND); + } + void VisitParmVarDecl(ParmVarDecl *ND) { + Call(CXCursor_ParmDecl, ND); + } + void VisitObjCPropertyDecl(ObjCPropertyDecl *ND) { + Call(CXCursor_ObjCPropertyDecl, ND); + } + void VisitObjCIvarDecl(ObjCIvarDecl *ND) { + Call(CXCursor_ObjCIvarDecl, ND); + } + void VisitFunctionDecl(FunctionDecl *ND) { + if (ND->isThisDeclarationADefinition()) { + VisitDeclContext(dyn_cast<DeclContext>(ND)); +#if 0 + // Not currently needed. + CompoundStmt *Body = dyn_cast<CompoundStmt>(ND->getBody()); + CRefVisitor RVisit(CDecl, Callback, CData); + RVisit.Visit(Body); +#endif + } + } + void VisitObjCMethodDecl(ObjCMethodDecl *ND) { + if (ND->getBody()) { + Call(ND->isInstanceMethod() ? CXCursor_ObjCInstanceMethodDefn + : CXCursor_ObjCClassMethodDefn, ND); + VisitDeclContext(dyn_cast<DeclContext>(ND)); + } else + Call(ND->isInstanceMethod() ? CXCursor_ObjCInstanceMethodDecl + : CXCursor_ObjCClassMethodDecl, ND); + } +}; + +} + +extern "C" { + +CXIndex clang_createIndex() +{ + // FIXME: Program is leaked. + return new Indexer(*new Program()); +} + +void clang_disposeIndex(CXIndex CIdx) +{ + assert(CIdx && "Passed null CXIndex"); + delete static_cast<Indexer *>(CIdx); +} + +// FIXME: need to pass back error info. +CXTranslationUnit clang_createTranslationUnit( + CXIndex CIdx, const char *ast_filename) +{ + assert(CIdx && "Passed null CXIndex"); + Indexer *CXXIdx = static_cast<Indexer *>(CIdx); + std::string astName(ast_filename); + std::string ErrMsg; + + return ASTUnit::LoadFromPCHFile(astName, CXXIdx->getDiagnostics(), + CXXIdx->getFileManager(), &ErrMsg); +} + +void clang_disposeTranslationUnit( + CXTranslationUnit CTUnit) +{ + assert(CTUnit && "Passed null CXTranslationUnit"); + delete static_cast<ASTUnit *>(CTUnit); +} + +const char *clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit) +{ + assert(CTUnit && "Passed null CXTranslationUnit"); + ASTUnit *CXXUnit = static_cast<ASTUnit *>(CTUnit); + return CXXUnit->getOriginalSourceFileName().c_str(); +} + +void clang_loadTranslationUnit(CXTranslationUnit CTUnit, + CXTranslationUnitIterator callback, + CXClientData CData) +{ + assert(CTUnit && "Passed null CXTranslationUnit"); + ASTUnit *CXXUnit = static_cast<ASTUnit *>(CTUnit); + ASTContext &Ctx = CXXUnit->getASTContext(); + + TUVisitor DVisit(CTUnit, callback, CData); + DVisit.Visit(Ctx.getTranslationUnitDecl()); +} + +void clang_loadDeclaration(CXDecl Dcl, + CXDeclIterator callback, + CXClientData CData) +{ + assert(Dcl && "Passed null CXDecl"); + + CDeclVisitor DVisit(Dcl, callback, CData); + DVisit.Visit(static_cast<Decl *>(Dcl)); +} + +// Some notes on CXEntity: +// +// - Since the 'ordinary' namespace includes functions, data, typedefs, +// ObjC interfaces, thecurrent algorithm is a bit naive (resulting in one +// entity for 2 different types). For example: +// +// module1.m: @interface Foo @end Foo *x; +// module2.m: void Foo(int); +// +// - Since the unique name spans translation units, static data/functions +// within a CXTranslationUnit are *not* currently represented by entities. +// As a result, there will be no entity for the following: +// +// module.m: static void Foo() { } +// + + +const char *clang_getDeclarationName(CXEntity) +{ + return ""; +} +const char *clang_getURI(CXEntity) +{ + return ""; +} + +CXEntity clang_getEntity(const char *URI) +{ + return 0; +} + +// +// CXDecl Operations. +// +CXEntity clang_getEntityFromDecl(CXDecl) +{ + return 0; +} +const char *clang_getDeclSpelling(CXDecl AnonDecl) +{ + assert(AnonDecl && "Passed null CXDecl"); + NamedDecl *ND = static_cast<NamedDecl *>(AnonDecl); + + if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(ND)) { + return OMD->getSelector().getAsString().c_str(); + } + if (ND->getIdentifier()) + return ND->getIdentifier()->getName(); + else + return ""; +} + +unsigned clang_getDeclLine(CXDecl AnonDecl) +{ + assert(AnonDecl && "Passed null CXDecl"); + NamedDecl *ND = static_cast<NamedDecl *>(AnonDecl); + SourceManager &SourceMgr = ND->getASTContext().getSourceManager(); + return SourceMgr.getSpellingLineNumber(ND->getLocation()); +} + +unsigned clang_getDeclColumn(CXDecl AnonDecl) +{ + assert(AnonDecl && "Passed null CXDecl"); + NamedDecl *ND = static_cast<NamedDecl *>(AnonDecl); + SourceManager &SourceMgr = ND->getASTContext().getSourceManager(); + return SourceMgr.getSpellingColumnNumber(ND->getLocation()); +} + +const char *clang_getDeclSource(CXDecl AnonDecl) +{ + assert(AnonDecl && "Passed null CXDecl"); + NamedDecl *ND = static_cast<NamedDecl *>(AnonDecl); + SourceManager &SourceMgr = ND->getASTContext().getSourceManager(); + return SourceMgr.getBufferName(ND->getLocation()); +} + +const char *clang_getCursorSpelling(CXCursor C) +{ + assert(C.decl && "CXCursor has null decl"); + NamedDecl *ND = static_cast<NamedDecl *>(C.decl); + + if (clang_isReference(C.kind)) { + switch (C.kind) { + case CXCursor_ObjCSuperClassRef: + { + ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(ND); + assert(OID && "clang_getCursorLine(): Missing interface decl"); + return OID->getSuperClass()->getIdentifier()->getName(); + } + case CXCursor_ObjCClassRef: + { + if (ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(ND)) { + return OID->getIdentifier()->getName(); + } + ObjCCategoryDecl *OID = dyn_cast<ObjCCategoryDecl>(ND); + assert(OID && "clang_getCursorLine(): Missing category decl"); + return OID->getClassInterface()->getIdentifier()->getName(); + } + case CXCursor_ObjCProtocolRef: + { + ObjCProtocolDecl *OID = dyn_cast<ObjCProtocolDecl>(ND); + assert(OID && "clang_getCursorLine(): Missing protocol decl"); + return OID->getIdentifier()->getName(); + } + case CXCursor_ObjCSelectorRef: + { + ObjCMessageExpr *OME = dyn_cast<ObjCMessageExpr>( + static_cast<Stmt *>(C.stmt)); + assert(OME && "clang_getCursorLine(): Missing message expr"); + return OME->getSelector().getAsString().c_str(); + } + case CXCursor_VarRef: + case CXCursor_FunctionRef: + case CXCursor_EnumConstantRef: + { + DeclRefExpr *DRE = dyn_cast<DeclRefExpr>( + static_cast<Stmt *>(C.stmt)); + assert(DRE && "clang_getCursorLine(): Missing decl ref expr"); + return DRE->getDecl()->getIdentifier()->getName(); + } + default: + return "<not implemented>"; + } + } + return clang_getDeclSpelling(C.decl); +} + +const char *clang_getCursorKindSpelling(enum CXCursorKind Kind) +{ + switch (Kind) { + case CXCursor_FunctionDecl: return "FunctionDecl"; + case CXCursor_TypedefDecl: return "TypedefDecl"; + case CXCursor_EnumDecl: return "EnumDecl"; + case CXCursor_EnumConstantDecl: return "EnumConstantDecl"; + case CXCursor_StructDecl: return "StructDecl"; + case CXCursor_UnionDecl: return "UnionDecl"; + case CXCursor_ClassDecl: return "ClassDecl"; + case CXCursor_FieldDecl: return "FieldDecl"; + case CXCursor_VarDecl: return "VarDecl"; + case CXCursor_ParmDecl: return "ParmDecl"; + case CXCursor_ObjCInterfaceDecl: return "ObjCInterfaceDecl"; + case CXCursor_ObjCCategoryDecl: return "ObjCCategoryDecl"; + case CXCursor_ObjCProtocolDecl: return "ObjCProtocolDecl"; + case CXCursor_ObjCPropertyDecl: return "ObjCPropertyDecl"; + case CXCursor_ObjCIvarDecl: return "ObjCIvarDecl"; + case CXCursor_ObjCInstanceMethodDecl: return "ObjCInstanceMethodDecl"; + case CXCursor_ObjCClassMethodDecl: return "ObjCClassMethodDecl"; + case CXCursor_FunctionDefn: return "FunctionDefn"; + case CXCursor_ObjCInstanceMethodDefn: return "ObjCInstanceMethodDefn"; + case CXCursor_ObjCClassMethodDefn: return "ObjCClassMethodDefn"; + case CXCursor_ObjCClassDefn: return "ObjCClassDefn"; + case CXCursor_ObjCCategoryDefn: return "ObjCCategoryDefn"; + case CXCursor_ObjCSuperClassRef: return "ObjCSuperClassRef"; + case CXCursor_ObjCProtocolRef: return "ObjCProtocolRef"; + case CXCursor_ObjCClassRef: return "ObjCClassRef"; + case CXCursor_ObjCSelectorRef: return "ObjCSelectorRef"; + + case CXCursor_VarRef: return "VarRef"; + case CXCursor_FunctionRef: return "FunctionRef"; + case CXCursor_EnumConstantRef: return "EnumConstantRef"; + case CXCursor_MemberRef: return "MemberRef"; + + case CXCursor_InvalidFile: return "InvalidFile"; + case CXCursor_NoDeclFound: return "NoDeclFound"; + case CXCursor_NotImplemented: return "NotImplemented"; + default: return "<not implemented>"; + } +} + +static enum CXCursorKind TranslateKind(Decl *D) { + switch (D->getKind()) { + case Decl::Function: return CXCursor_FunctionDecl; + case Decl::Typedef: return CXCursor_TypedefDecl; + case Decl::Enum: return CXCursor_EnumDecl; + case Decl::EnumConstant: return CXCursor_EnumConstantDecl; + case Decl::Record: return CXCursor_StructDecl; // FIXME: union/class + case Decl::Field: return CXCursor_FieldDecl; + case Decl::Var: return CXCursor_VarDecl; + case Decl::ParmVar: return CXCursor_ParmDecl; + case Decl::ObjCInterface: return CXCursor_ObjCInterfaceDecl; + case Decl::ObjCCategory: return CXCursor_ObjCCategoryDecl; + case Decl::ObjCProtocol: return CXCursor_ObjCProtocolDecl; + case Decl::ObjCMethod: { + ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D); + if (MD->isInstanceMethod()) + return CXCursor_ObjCInstanceMethodDecl; + return CXCursor_ObjCClassMethodDecl; + } + default: break; + } + return CXCursor_NotImplemented; +} +// +// CXCursor Operations. +// +CXCursor clang_getCursor(CXTranslationUnit CTUnit, const char *source_name, + unsigned line, unsigned column) +{ + assert(CTUnit && "Passed null CXTranslationUnit"); + ASTUnit *CXXUnit = static_cast<ASTUnit *>(CTUnit); + + FileManager &FMgr = CXXUnit->getFileManager(); + const FileEntry *File = FMgr.getFile(source_name, + source_name+strlen(source_name)); + if (!File) { + CXCursor C = { CXCursor_InvalidFile, 0, 0 }; + return C; + } + SourceLocation SLoc = + CXXUnit->getSourceManager().getLocation(File, line, column); + + ASTLocation ALoc = ResolveLocationInAST(CXXUnit->getASTContext(), SLoc); + + Decl *Dcl = ALoc.getParentDecl(); + if (ALoc.isNamedRef()) + Dcl = ALoc.AsNamedRef().ND; + Stmt *Stm = ALoc.dyn_AsStmt(); + if (Dcl) { + if (Stm) { + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Stm)) { + CXCursor C = { TranslateDeclRefExpr(DRE), Dcl, Stm }; + return C; + } else if (ObjCMessageExpr *MExp = dyn_cast<ObjCMessageExpr>(Stm)) { + CXCursor C = { CXCursor_ObjCSelectorRef, Dcl, MExp }; + return C; + } + // Fall through...treat as a decl, not a ref. + } + if (ALoc.isNamedRef()) { + if (isa<ObjCInterfaceDecl>(Dcl)) { + CXCursor C = { CXCursor_ObjCClassRef, Dcl, ALoc.getParentDecl() }; + return C; + } + if (isa<ObjCProtocolDecl>(Dcl)) { + CXCursor C = { CXCursor_ObjCProtocolRef, Dcl, ALoc.getParentDecl() }; + return C; + } + } + CXCursor C = { TranslateKind(Dcl), Dcl, 0 }; + return C; + } + CXCursor C = { CXCursor_NoDeclFound, 0, 0 }; + return C; +} + +CXCursor clang_getCursorFromDecl(CXDecl AnonDecl) +{ + assert(AnonDecl && "Passed null CXDecl"); + NamedDecl *ND = static_cast<NamedDecl *>(AnonDecl); + + CXCursor C = { TranslateKind(ND), ND, 0 }; + return C; +} + +unsigned clang_isInvalid(enum CXCursorKind K) +{ + return K >= CXCursor_FirstInvalid && K <= CXCursor_LastInvalid; +} + +unsigned clang_isDeclaration(enum CXCursorKind K) +{ + return K >= CXCursor_FirstDecl && K <= CXCursor_LastDecl; +} + +unsigned clang_isReference(enum CXCursorKind K) +{ + return K >= CXCursor_FirstRef && K <= CXCursor_LastRef; +} + +unsigned clang_isDefinition(enum CXCursorKind K) +{ + return K >= CXCursor_FirstDefn && K <= CXCursor_LastDefn; +} + +CXCursorKind clang_getCursorKind(CXCursor C) +{ + return C.kind; +} + +static Decl *getDeclFromExpr(Stmt *E) { + if (DeclRefExpr *RefExpr = dyn_cast<DeclRefExpr>(E)) + return RefExpr->getDecl(); + if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) + return ME->getMemberDecl(); + if (ObjCIvarRefExpr *RE = dyn_cast<ObjCIvarRefExpr>(E)) + return RE->getDecl(); + + if (CallExpr *CE = dyn_cast<CallExpr>(E)) + return getDeclFromExpr(CE->getCallee()); + if (CastExpr *CE = dyn_cast<CastExpr>(E)) + return getDeclFromExpr(CE->getSubExpr()); + if (ObjCMessageExpr *OME = dyn_cast<ObjCMessageExpr>(E)) + return OME->getMethodDecl(); + + return 0; +} + +CXDecl clang_getCursorDecl(CXCursor C) +{ + if (clang_isDeclaration(C.kind)) + return C.decl; + + if (clang_isReference(C.kind)) { + if (C.stmt) { + if (C.kind == CXCursor_ObjCClassRef || + C.kind == CXCursor_ObjCProtocolRef) + return static_cast<Stmt *>(C.stmt); + else + return getDeclFromExpr(static_cast<Stmt *>(C.stmt)); + } else + return C.decl; + } + return 0; +} + + +static SourceLocation getLocationFromCursor(CXCursor C, + SourceManager &SourceMgr, + NamedDecl *ND) { + if (clang_isReference(C.kind)) { + switch (C.kind) { + case CXCursor_ObjCClassRef: + { + if (isa<ObjCInterfaceDecl>(ND)) { + // FIXME: This is a hack (storing the parent decl in the stmt slot). + NamedDecl *parentDecl = static_cast<NamedDecl *>(C.stmt); + return parentDecl->getLocation(); + } + ObjCCategoryDecl *OID = dyn_cast<ObjCCategoryDecl>(ND); + assert(OID && "clang_getCursorLine(): Missing category decl"); + return OID->getClassInterface()->getLocation(); + } + case CXCursor_ObjCSuperClassRef: + { + ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(ND); + assert(OID && "clang_getCursorLine(): Missing interface decl"); + return OID->getSuperClassLoc(); + } + case CXCursor_ObjCProtocolRef: + { + ObjCProtocolDecl *OID = dyn_cast<ObjCProtocolDecl>(ND); + assert(OID && "clang_getCursorLine(): Missing protocol decl"); + return OID->getLocation(); + } + case CXCursor_ObjCSelectorRef: + { + ObjCMessageExpr *OME = dyn_cast<ObjCMessageExpr>( + static_cast<Stmt *>(C.stmt)); + assert(OME && "clang_getCursorLine(): Missing message expr"); + return OME->getLeftLoc(); /* FIXME: should be a range */ + } + case CXCursor_VarRef: + case CXCursor_FunctionRef: + case CXCursor_EnumConstantRef: + { + DeclRefExpr *DRE = dyn_cast<DeclRefExpr>( + static_cast<Stmt *>(C.stmt)); + assert(DRE && "clang_getCursorLine(): Missing decl ref expr"); + return DRE->getLocation(); + } + default: + return SourceLocation(); + } + } else { // We have a declaration or a definition. + SourceLocation SLoc; + switch (ND->getKind()) { + case Decl::ObjCInterface: + { + SLoc = dyn_cast<ObjCInterfaceDecl>(ND)->getClassLoc(); + break; + } + case Decl::ObjCProtocol: + { + SLoc = ND->getLocation(); /* FIXME: need to get the name location. */ + break; + } + default: + { + SLoc = ND->getLocation(); + break; + } + } + if (SLoc.isInvalid()) + return SourceLocation(); + return SourceMgr.getSpellingLoc(SLoc); // handles macro instantiations. + } +} + +unsigned clang_getCursorLine(CXCursor C) +{ + assert(C.decl && "CXCursor has null decl"); + NamedDecl *ND = static_cast<NamedDecl *>(C.decl); + SourceManager &SourceMgr = ND->getASTContext().getSourceManager(); + + SourceLocation SLoc = getLocationFromCursor(C, SourceMgr, ND); + return SourceMgr.getSpellingLineNumber(SLoc); +} + +unsigned clang_getCursorColumn(CXCursor C) +{ + assert(C.decl && "CXCursor has null decl"); + NamedDecl *ND = static_cast<NamedDecl *>(C.decl); + SourceManager &SourceMgr = ND->getASTContext().getSourceManager(); + + SourceLocation SLoc = getLocationFromCursor(C, SourceMgr, ND); + return SourceMgr.getSpellingColumnNumber(SLoc); +} +const char *clang_getCursorSource(CXCursor C) +{ + assert(C.decl && "CXCursor has null decl"); + NamedDecl *ND = static_cast<NamedDecl *>(C.decl); + SourceManager &SourceMgr = ND->getASTContext().getSourceManager(); + + SourceLocation SLoc = getLocationFromCursor(C, SourceMgr, ND); + return SourceMgr.getBufferName(SLoc); +} + +void clang_getDefinitionSpellingAndExtent(CXCursor C, + const char **startBuf, + const char **endBuf, + unsigned *startLine, + unsigned *startColumn, + unsigned *endLine, + unsigned *endColumn) +{ + assert(C.decl && "CXCursor has null decl"); + NamedDecl *ND = static_cast<NamedDecl *>(C.decl); + FunctionDecl *FD = dyn_cast<FunctionDecl>(ND); + CompoundStmt *Body = dyn_cast<CompoundStmt>(FD->getBody()); + + SourceManager &SM = FD->getASTContext().getSourceManager(); + *startBuf = SM.getCharacterData(Body->getLBracLoc()); + *endBuf = SM.getCharacterData(Body->getRBracLoc()); + *startLine = SM.getSpellingLineNumber(Body->getLBracLoc()); + *startColumn = SM.getSpellingColumnNumber(Body->getLBracLoc()); + *endLine = SM.getSpellingLineNumber(Body->getRBracLoc()); + *endColumn = SM.getSpellingColumnNumber(Body->getRBracLoc()); +} + + +} // end extern "C" |