//===- 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 #include #include "llvm/System/Path.h" using namespace clang; using namespace idx; namespace { static enum CXCursorKind TranslateDeclRefExpr(DeclRefExpr *DRE) { NamedDecl *D = DRE->getDecl(); if (isa(D)) return CXCursor_VarRef; else if (isa(D)) return CXCursor_FunctionRef; else if (isa(D)) return CXCursor_EnumConstantRef; else return CXCursor_NotImplemented; } #if 0 // Will be useful one day. class CRefVisitor : public StmtVisitor { 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 { 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(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 { 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(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(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(PID)); } void VisitTagDecl(TagDecl *D) { VisitDeclContext(dyn_cast(D)); } void VisitObjCImplementationDecl(ObjCImplementationDecl *D) { VisitDeclContext(dyn_cast(D)); } void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { VisitDeclContext(dyn_cast(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(ND)); #if 0 // Not currently needed. CompoundStmt *Body = dyn_cast(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(ND)); } else Call(ND->isInstanceMethod() ? CXCursor_ObjCInstanceMethodDecl : CXCursor_ObjCClassMethodDecl, ND); } }; } extern "C" { static const char *clangPath; CXIndex clang_createIndex() { // FIXME: Program is leaked. // Find the location where this library lives (libCIndex.dylib). // We do the lookup here to avoid poking dladdr too many times. // This silly cast below avoids a C++ warning. Dl_info info; if (dladdr((void *)(uintptr_t)clang_createTranslationUnit, &info) == 0) assert(0 && "Call to dladdr() failed"); llvm::sys::Path CIndexPath(info.dli_fname); std::string CIndexDir = CIndexPath.getDirname(); // We now have the CIndex directory, locate clang relative to it. std::string ClangPath = CIndexDir + "/../bin/clang"; clangPath = ClangPath.c_str(); return new Indexer(*new Program()); } void clang_disposeIndex(CXIndex CIdx) { assert(CIdx && "Passed null CXIndex"); delete static_cast(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(CIdx); std::string astName(ast_filename); std::string ErrMsg; return ASTUnit::LoadFromPCHFile(astName, CXXIdx->getDiagnostics(), CXXIdx->getFileManager(), &ErrMsg); } CXTranslationUnit clang_createTranslationUnitFromSourceFile( CXIndex CIdx, const char *source_filename, int num_command_line_args, const char **command_line_args) { // Build up the arguments for involking clang. int argc = 0; const char * argv[ARG_MAX]; argv[argc++] = clangPath; argv[argc++] = "-emit-ast"; argv[argc++] = source_filename; argv[argc++] = "-o"; // Generate a temporary name for the AST file. char astTmpFile[L_tmpnam]; argv[argc++] = tmpnam(astTmpFile); for (int i = num_command_line_args; i < num_command_line_args; i++) argv[argc++] = command_line_args[i]; argv[argc] = 0; // Generate the AST file in a separate process. pid_t child_pid = fork(); if (child_pid == 0) { // Child process // Execute the command, passing the appropriate arguments. execv(argv[0], (char *const *)argv); // If execv returns, it failed. assert(0 && "execv() failed"); } // This is run by the parent. int child_status; pid_t tpid; do { // Wait for the child to terminate. tpid = wait(&child_status); } while (tpid != child_pid); // Finally, we create the translation unit from the ast file. return clang_createTranslationUnit(CIdx, astTmpFile); } void clang_disposeTranslationUnit( CXTranslationUnit CTUnit) { assert(CTUnit && "Passed null CXTranslationUnit"); delete static_cast(CTUnit); } const char *clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit) { assert(CTUnit && "Passed null CXTranslationUnit"); ASTUnit *CXXUnit = static_cast(CTUnit); return CXXUnit->getOriginalSourceFileName().c_str(); } void clang_loadTranslationUnit(CXTranslationUnit CTUnit, CXTranslationUnitIterator callback, CXClientData CData) { assert(CTUnit && "Passed null CXTranslationUnit"); ASTUnit *CXXUnit = static_cast(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(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(AnonDecl); if (ObjCMethodDecl *OMD = dyn_cast(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(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(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(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(C.decl); if (clang_isReference(C.kind)) { switch (C.kind) { case CXCursor_ObjCSuperClassRef: { ObjCInterfaceDecl *OID = dyn_cast(ND); assert(OID && "clang_getCursorLine(): Missing interface decl"); return OID->getSuperClass()->getIdentifier()->getName(); } case CXCursor_ObjCClassRef: { if (ObjCInterfaceDecl *OID = dyn_cast(ND)) { return OID->getIdentifier()->getName(); } ObjCCategoryDecl *OID = dyn_cast(ND); assert(OID && "clang_getCursorLine(): Missing category decl"); return OID->getClassInterface()->getIdentifier()->getName(); } case CXCursor_ObjCProtocolRef: { ObjCProtocolDecl *OID = dyn_cast(ND); assert(OID && "clang_getCursorLine(): Missing protocol decl"); return OID->getIdentifier()->getName(); } case CXCursor_ObjCSelectorRef: { ObjCMessageExpr *OME = dyn_cast( static_cast(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( static_cast(C.stmt)); assert(DRE && "clang_getCursorLine(): Missing decl ref expr"); return DRE->getDecl()->getIdentifier()->getName(); } default: return ""; } } 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 ""; } } 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(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(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(Stm)) { CXCursor C = { TranslateDeclRefExpr(DRE), Dcl, Stm }; return C; } else if (ObjCMessageExpr *MExp = dyn_cast(Stm)) { CXCursor C = { CXCursor_ObjCSelectorRef, Dcl, MExp }; return C; } // Fall through...treat as a decl, not a ref. } if (ALoc.isNamedRef()) { if (isa(Dcl)) { CXCursor C = { CXCursor_ObjCClassRef, Dcl, ALoc.getParentDecl() }; return C; } if (isa(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(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(E)) return RefExpr->getDecl(); if (MemberExpr *ME = dyn_cast(E)) return ME->getMemberDecl(); if (ObjCIvarRefExpr *RE = dyn_cast(E)) return RE->getDecl(); if (CallExpr *CE = dyn_cast(E)) return getDeclFromExpr(CE->getCallee()); if (CastExpr *CE = dyn_cast(E)) return getDeclFromExpr(CE->getSubExpr()); if (ObjCMessageExpr *OME = dyn_cast(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(C.stmt); else return getDeclFromExpr(static_cast(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(ND)) { // FIXME: This is a hack (storing the parent decl in the stmt slot). NamedDecl *parentDecl = static_cast(C.stmt); return parentDecl->getLocation(); } ObjCCategoryDecl *OID = dyn_cast(ND); assert(OID && "clang_getCursorLine(): Missing category decl"); return OID->getClassInterface()->getLocation(); } case CXCursor_ObjCSuperClassRef: { ObjCInterfaceDecl *OID = dyn_cast(ND); assert(OID && "clang_getCursorLine(): Missing interface decl"); return OID->getSuperClassLoc(); } case CXCursor_ObjCProtocolRef: { ObjCProtocolDecl *OID = dyn_cast(ND); assert(OID && "clang_getCursorLine(): Missing protocol decl"); return OID->getLocation(); } case CXCursor_ObjCSelectorRef: { ObjCMessageExpr *OME = dyn_cast( static_cast(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( static_cast(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(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(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(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(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(C.decl); FunctionDecl *FD = dyn_cast(ND); CompoundStmt *Body = dyn_cast(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"