From fe6fd3d41a7f48317d6856c9327b6cead32c3498 Mon Sep 17 00:00:00 2001 From: Ted Kremenek Date: Tue, 5 Jan 2010 23:18:49 +0000 Subject: [PATCH] Add C API hook 'clang_getDeclExtent()', which returns the source extent of a declaration. This implements . git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@92802 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang-c/Index.h | 16 ++++++++ test/Index/c-index-api-loadTU-test.m | 59 ++++++++++++++-------------- tools/CIndex/CIndex.cpp | 19 +++++++++ tools/CIndex/CIndex.exports | 1 + tools/c-index-test/c-index-test.c | 58 +++++++++++++++++++-------- 5 files changed, 107 insertions(+), 46 deletions(-) diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h index 8ff9f04dc8..8e35a485d9 100644 --- a/include/clang-c/Index.h +++ b/include/clang-c/Index.h @@ -335,6 +335,22 @@ CINDEX_LINKAGE unsigned clang_getDeclColumn(CXDecl); CINDEX_LINKAGE const char *clang_getDeclSource(CXDecl); /* deprecate */ CINDEX_LINKAGE CXFile clang_getDeclSourceFile(CXDecl); +typedef struct CXSourceLineColumn { + unsigned line; + unsigned column; +} CXSourceLineColumn; + +typedef struct CXDeclExtent { + CXSourceLineColumn begin; + CXSourceLineColumn end; +} CXSourceExtent; + +/* clang_getDeclExtent() returns the physical extent of a declaration. The beginning + * line/column pair points to the start of the first token in the declaration, and the + * ending line/column pair points the start of the last token in the declaration. + */ +CXSourceExtent clang_getDeclExtent(CXDecl); + /* * CXCursor Operations. */ diff --git a/test/Index/c-index-api-loadTU-test.m b/test/Index/c-index-api-loadTU-test.m index 6ee50aef1e..fdcbe55671 100644 --- a/test/Index/c-index-api-loadTU-test.m +++ b/test/Index/c-index-api-loadTU-test.m @@ -16,7 +16,6 @@ - @interface Foo { } @@ -58,28 +57,6 @@ enum { someEnum }; -// CHECK: c-index-api-loadTU-test.m:20:12: ObjCInterfaceDecl=Foo:20:1 [Context=c-index-api-loadTU-test.m] -// CHECK: c-index-api-loadTU-test.m:24:1: ObjCInstanceMethodDecl=foo:24:1 [Context=Foo] -// CHECK: c-index-api-loadTU-test.m:25:1: ObjCClassMethodDecl=fooC:25:1 [Context=Foo] -// CHECK: c-index-api-loadTU-test.m:29:12: ObjCInterfaceDecl=Bar:29:1 [Context=c-index-api-loadTU-test.m] -// CHECK: c-index-api-loadTU-test.m:29:18: ObjCSuperClassRef=Foo:29:1 [Context=Bar] -// CHECK: c-index-api-loadTU-test.m:35:1: ObjCCategoryDecl=FooCat:35:1 [Context=c-index-api-loadTU-test.m] -// CHECK: c-index-api-loadTU-test.m:20:1: ObjCClassRef=Foo:35:1 [Context=FooCat] -// CHECK: c-index-api-loadTU-test.m:36:1: ObjCInstanceMethodDecl=catMethodWithFloat::36:1 [Context=FooCat] -// CHECK: c-index-api-loadTU-test.m:37:1: ObjCInstanceMethodDecl=floatMethod:37:1 [Context=FooCat] -// CHECK: c-index-api-loadTU-test.m:40:1: ObjCProtocolDecl=Proto:40:1 [Context=c-index-api-loadTU-test.m] -// CHECK: c-index-api-loadTU-test.m:41:1: ObjCInstanceMethodDecl=pMethod:41:1 [Context=Proto] -// CHECK: c-index-api-loadTU-test.m:44:1: ObjCProtocolDecl=SubP:44:1 [Context=c-index-api-loadTU-test.m] -// CHECK: c-index-api-loadTU-test.m:40:1: ObjCProtocolRef=Proto:40:1 [Context=SubP] -// CHECK: c-index-api-loadTU-test.m:45:1: ObjCInstanceMethodDecl=spMethod:45:1 [Context=SubP] -// CHECK: c-index-api-loadTU-test.m:48:12: ObjCInterfaceDecl=Baz:48:1 [Context=c-index-api-loadTU-test.m] -// CHECK: c-index-api-loadTU-test.m:48:18: ObjCSuperClassRef=Bar:48:1 [Context=Baz] -// CHECK: c-index-api-loadTU-test.m:44:1: ObjCProtocolRef=SubP:44:1 [Context=Baz] -// CHECK: c-index-api-loadTU-test.m:50:9: ObjCIvarDecl=_anIVar:50:9 [Context=Baz] -// CHECK: c-index-api-loadTU-test.m:53:1: ObjCInstanceMethodDecl=bazMethod:53:1 [Context=Baz] -// CHECK: c-index-api-loadTU-test.m:57:1: EnumDecl=:57:1 [Context=c-index-api-loadTU-test.m] -// CHECK: c-index-api-loadTU-test.m:58:3: EnumConstantDecl=someEnum:58:3 [Context=] - int main (int argc, const char * argv[]) { Baz * bee; id a = [bee foo]; @@ -91,10 +68,32 @@ int main (int argc, const char * argv[]) { main(someEnum, (const char **)bee); } -// CHECK: c-index-api-loadTU-test.m:83:5: FunctionDefn=main [Context=c-index-api-loadTU-test.m] -// CHECK: c-index-api-loadTU-test.m:83:15: ParmDecl=argc:83:15 [Context=main] -// CHECK: c-index-api-loadTU-test.m:83:34: ParmDecl=argv:83:34 [Context=main] -// CHECK: c-index-api-loadTU-test.m:84:8: VarDecl=bee:84:8 [Context=main] -// CHECK: c-index-api-loadTU-test.m:85:5: VarDecl=a:85:5 [Context=main] -// CHECK: c-index-api-loadTU-test.m:86:12: VarDecl=c:86:12 [Context=main] -// CHECK: c-index-api-loadTU-test.m:87:13: VarDecl=d:87:13 [Context=main] +// CHECK: c-index-api-loadTU-test.m:19:12: ObjCInterfaceDecl=Foo:19:1 [Context=c-index-api-loadTU-test.m] [Extent=19:1:26:1] +// CHECK: c-index-api-loadTU-test.m:23:1: ObjCInstanceMethodDecl=foo:23:1 [Context=Foo] [Extent=23:1:23:6] +// CHECK: c-index-api-loadTU-test.m:24:1: ObjCClassMethodDecl=fooC:24:1 [Context=Foo] [Extent=24:1:24:7] +// CHECK: c-index-api-loadTU-test.m:28:12: ObjCInterfaceDecl=Bar:28:1 [Context=c-index-api-loadTU-test.m] [Extent=28:1:32:1] +// CHECK: c-index-api-loadTU-test.m:28:18: ObjCSuperClassRef=Foo:28:1 [Context=Bar] [Extent=28:1:32:1] +// CHECK: c-index-api-loadTU-test.m:34:1: ObjCCategoryDecl=FooCat:34:1 [Context=c-index-api-loadTU-test.m] [Extent=34:1:37:1] +// CHECK: c-index-api-loadTU-test.m:19:1: ObjCClassRef=Foo:34:1 [Context=FooCat] [Extent=34:1:37:1] +// CHECK: c-index-api-loadTU-test.m:35:1: ObjCInstanceMethodDecl=catMethodWithFloat::35:1 [Context=FooCat] [Extent=35:1:35:40] +// CHECK: c-index-api-loadTU-test.m:36:1: ObjCInstanceMethodDecl=floatMethod:36:1 [Context=FooCat] [Extent=36:1:36:22] +// CHECK: c-index-api-loadTU-test.m:39:1: ObjCProtocolDecl=Proto:39:1 [Context=c-index-api-loadTU-test.m] [Extent=39:1:41:1] +// CHECK: c-index-api-loadTU-test.m:40:1: ObjCInstanceMethodDecl=pMethod:40:1 [Context=Proto] [Extent=40:1:40:10] +// CHECK: c-index-api-loadTU-test.m:43:1: ObjCProtocolDecl=SubP:43:1 [Context=c-index-api-loadTU-test.m] [Extent=43:1:45:1] +// CHECK: c-index-api-loadTU-test.m:39:1: ObjCProtocolRef=Proto:39:1 [Context=SubP] [Extent=39:1:41:1] +// CHECK: c-index-api-loadTU-test.m:44:1: ObjCInstanceMethodDecl=spMethod:44:1 [Context=SubP] [Extent=44:1:44:11] +// CHECK: c-index-api-loadTU-test.m:47:12: ObjCInterfaceDecl=Baz:47:1 [Context=c-index-api-loadTU-test.m] [Extent=47:1:54:1] +// CHECK: c-index-api-loadTU-test.m:47:18: ObjCSuperClassRef=Bar:47:1 [Context=Baz] [Extent=47:1:54:1] +// CHECK: c-index-api-loadTU-test.m:43:1: ObjCProtocolRef=SubP:43:1 [Context=Baz] [Extent=43:1:45:1] +// CHECK: c-index-api-loadTU-test.m:49:9: ObjCIvarDecl=_anIVar:49:9 [Context=Baz] [Extent=49:9:49:9] +// CHECK: c-index-api-loadTU-test.m:52:1: ObjCInstanceMethodDecl=bazMethod:52:1 [Context=Baz] [Extent=52:1:52:20] +// CHECK: c-index-api-loadTU-test.m:56:1: EnumDecl=:56:1 [Context=c-index-api-loadTU-test.m] [Extent=56:1:58:1] +// CHECK: c-index-api-loadTU-test.m:57:3: EnumConstantDecl=someEnum:57:3 [Context=] [Extent=57:3:57:3] +// CHECK: c-index-api-loadTU-test.m:60:5: FunctionDefn=main [Context=c-index-api-loadTU-test.m] [Extent=60:5:69:1] +// CHECK: c-index-api-loadTU-test.m:60:15: ParmDecl=argc:60:15 [Context=main] [Extent=60:15:60:15] +// CHECK: c-index-api-loadTU-test.m:60:34: ParmDecl=argv:60:34 [Context=main] [Extent=60:34:60:34] +// CHECK: c-index-api-loadTU-test.m:61:8: VarDecl=bee:61:8 [Context=main] [Extent=61:8:61:8] +// CHECK: c-index-api-loadTU-test.m:62:5: VarDecl=a:62:5 [Context=main] [Extent=62:5:62:17] +// CHECK: c-index-api-loadTU-test.m:63:12: VarDecl=c:63:12 [Context=main] [Extent=63:12:63:25] +// CHECK: c-index-api-loadTU-test.m:64:13: VarDecl=d:64:13 [Context=main] [Extent=64:13:64:13] + diff --git a/tools/CIndex/CIndex.cpp b/tools/CIndex/CIndex.cpp index 7b624e6dd3..fb359c97a1 100644 --- a/tools/CIndex/CIndex.cpp +++ b/tools/CIndex/CIndex.cpp @@ -569,6 +569,25 @@ unsigned clang_getDeclColumn(CXDecl AnonDecl) { SourceManager &SourceMgr = ND->getASTContext().getSourceManager(); return SourceMgr.getSpellingColumnNumber(ND->getLocation()); } + +CXDeclExtent clang_getDeclExtent(CXDecl AnonDecl) { + assert(AnonDecl && "Passed null CXDecl"); + NamedDecl *ND = static_cast(AnonDecl); + SourceManager &SourceMgr = ND->getASTContext().getSourceManager(); + SourceRange R = ND->getSourceRange(); + + CXDeclExtent extent; + + SourceLocation L = SourceMgr.getSpellingLoc(R.getBegin()); + extent.begin.line = SourceMgr.getSpellingLineNumber(L); + extent.begin.column = SourceMgr.getSpellingColumnNumber(L); + + L = SourceMgr.getSpellingLoc(R.getEnd()); + extent.end.line = SourceMgr.getSpellingLineNumber(L); + extent.end.column = SourceMgr.getSpellingColumnNumber(L); + + return extent; +} const char *clang_getDeclSource(CXDecl AnonDecl) { assert(AnonDecl && "Passed null CXDecl"); diff --git a/tools/CIndex/CIndex.exports b/tools/CIndex/CIndex.exports index 2548c82940..ab68217c4d 100644 --- a/tools/CIndex/CIndex.exports +++ b/tools/CIndex/CIndex.exports @@ -23,6 +23,7 @@ _clang_getCursorSourceFile _clang_getCursorSpelling _clang_getDeclColumn _clang_getDeclLine +_clang_getDeclExtent _clang_getDeclSource _clang_getDeclSourceFile _clang_getDeclSpelling diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c index 33013f3b66..e7253e08d2 100644 --- a/tools/c-index-test/c-index-test.c +++ b/tools/c-index-test/c-index-test.c @@ -70,16 +70,32 @@ static const char* GetCursorSource(CXCursor Cursor) { /* Logic for testing clang_loadTranslationUnit(). */ /******************************************************************************/ +static const char *FileCheckPrefix = "CHECK"; + +static void PrintDeclExtent(CXDecl Dcl) { + CXSourceExtent extent = clang_getDeclExtent(Dcl); + printf(" [Extent=%d:%d:%d:%d]", extent.begin.line, extent.begin.column, + extent.end.line, extent.end.column); +} + static void DeclVisitor(CXDecl Dcl, CXCursor Cursor, CXClientData Filter) { if (!Filter || (Cursor.kind == *(enum CXCursorKind *)Filter)) { CXString string; - printf("// CHECK: %s:%d:%d: ", GetCursorSource(Cursor), - clang_getCursorLine(Cursor), - clang_getCursorColumn(Cursor)); + CXDecl subDecl; + CXSourceExtent extent; + printf("// %s: %s:%d:%d: ", FileCheckPrefix, + GetCursorSource(Cursor), + clang_getCursorLine(Cursor), + clang_getCursorColumn(Cursor)); PrintCursor(Cursor); + string = clang_getDeclSpelling(Dcl); - printf(" [Context=%s]\n", clang_getCString(string)); + printf(" [Context=%s]", clang_getCString(string)); clang_disposeString(string); + + PrintDeclExtent(clang_getCursorDecl(Cursor)); + + printf("\n"); } } @@ -87,15 +103,19 @@ static void TranslationUnitVisitor(CXTranslationUnit Unit, CXCursor Cursor, CXClientData Filter) { if (!Filter || (Cursor.kind == *(enum CXCursorKind *)Filter)) { CXString string; - printf("// CHECK: %s:%d:%d: ", GetCursorSource(Cursor), - clang_getCursorLine(Cursor), - clang_getCursorColumn(Cursor)); + printf("// %s: %s:%d:%d: ", FileCheckPrefix, + GetCursorSource(Cursor), clang_getCursorLine(Cursor), + clang_getCursorColumn(Cursor)); PrintCursor(Cursor); string = clang_getTranslationUnitSpelling(Unit); - printf(" [Context=%s]\n", + printf(" [Context=%s]", basename(clang_getCString(string))); clang_disposeString(string); + + PrintDeclExtent(Cursor.decl); + printf("\n"); + clang_loadDeclaration(Cursor.decl, DeclVisitor, 0); } } @@ -130,7 +150,7 @@ static void FunctionScanVisitor(CXTranslationUnit Unit, CXCursor Cursor, /* Nothing found here; that's fine. */ } else if (Ref.kind != CXCursor_FunctionDecl) { CXString string; - printf("// CHECK: %s:%d:%d: ", GetCursorSource(Ref), + printf("// %s: %s:%d:%d: ", FileCheckPrefix, GetCursorSource(Ref), curLine, curColumn); PrintCursor(Ref); string = clang_getDeclSpelling(Ref.decl); @@ -142,11 +162,14 @@ static void FunctionScanVisitor(CXTranslationUnit Unit, CXCursor Cursor, } static int perform_test_load(CXIndex Idx, CXTranslationUnit TU, - const char *filter) { + const char *filter, const char *prefix) { enum CXCursorKind K = CXCursor_NotImplemented; CXTranslationUnitIterator Visitor = TranslationUnitVisitor; enum CXCursorKind *ck = &K; + if (prefix) + FileCheckPrefix = prefix; + /* Perform some simple filtering. */ if (!strcmp(filter, "all") || !strcmp(filter, "local")) ck = NULL; else if (!strcmp(filter, "category")) K = CXCursor_ObjCCategoryDecl; @@ -165,7 +188,8 @@ static int perform_test_load(CXIndex Idx, CXTranslationUnit TU, return 0; } -int perform_test_load_tu(const char *file, const char *filter) { +int perform_test_load_tu(const char *file, const char *filter, + const char *prefix) { CXIndex Idx; CXTranslationUnit TU; Idx = clang_createIndex(/* excludeDeclsFromPCH */ @@ -175,7 +199,7 @@ int perform_test_load_tu(const char *file, const char *filter) { if (!CreateTranslationUnit(Idx, file, &TU)) return 1; - return perform_test_load(Idx, TU, filter); + return perform_test_load(Idx, TU, filter, prefix); } int perform_test_load_source(int argc, const char **argv, const char *filter) { @@ -196,7 +220,7 @@ int perform_test_load_source(int argc, const char **argv, const char *filter) { return 1; } - return perform_test_load(Idx, TU, filter); + return perform_test_load(Idx, TU, filter, NULL); } /******************************************************************************/ @@ -536,7 +560,8 @@ static void print_usage(void) { "usage: c-index-test -code-completion-at= \n" " c-index-test -test-file-scan " "[FileCheck prefix]\n" - " c-index-test -test-load-tu \n\n" + " c-index-test -test-load-tu " + "[FileCheck prefix]\n" " c-index-test -test-load-source {}*\n\n" " options for -test-load-tu and -test-load-source:\n%s", " all - load all symbols, including those from PCH\n" @@ -552,8 +577,9 @@ static void print_usage(void) { int main(int argc, const char **argv) { if (argc > 2 && strstr(argv[1], "-code-completion-at=") == argv[1]) return perform_code_completion(argc, argv); - if (argc == 4 && strcmp(argv[1], "-test-load-tu") == 0) - return perform_test_load_tu(argv[2], argv[3]); + if (argc >= 4 && strcmp(argv[1], "-test-load-tu") == 0) + return perform_test_load_tu(argv[2], argv[3], + argc >= 5 ? argv[4] : 0); if (argc >= 4 && strcmp(argv[1], "-test-load-source") == 0) return perform_test_load_source(argc - 3, argv + 3, argv[2]); if (argc >= 4 && strcmp(argv[1], "-test-file-scan") == 0) -- 2.50.1