From 191a6a86ad74f10b27250fb62483326f4b22c394 Mon Sep 17 00:00:00 2001 From: Argyrios Kyrtzidis Date: Fri, 30 Mar 2012 20:58:35 +0000 Subject: [PATCH] [libclang] Introduce clang_Cursor_getSpellingNameRange(). It retrieves a source range for a piece that forms the cursors spelling name. Most of the times there is only one range for the complete spelling but for objc methods and objc message expressions, there are multiple pieces for each selector identifier. Part of rdar://11113120 llvm-svn: 153775 --- clang/include/clang-c/Index.h | 15 +++++++ clang/test/Index/get-cursor.m | 21 +++++++-- clang/tools/c-index-test/c-index-test.c | 18 ++++++-- clang/tools/libclang/CIndex.cpp | 57 +++++++++++++++++++++++++ clang/tools/libclang/libclang.exports | 1 + 5 files changed, 105 insertions(+), 7 deletions(-) diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h index 54f461b9a105..a65bb635b26b 100644 --- a/clang/include/clang-c/Index.h +++ b/clang/include/clang-c/Index.h @@ -2903,6 +2903,21 @@ CINDEX_LINKAGE CXString clang_constructUSR_ObjCProperty(const char *property, */ CINDEX_LINKAGE CXString clang_getCursorSpelling(CXCursor); +/** + * \brief Retrieve a range for a piece that forms the cursors spelling name. + * Most of the times there is only one range for the complete spelling but for + * objc methods and objc message expressions, there are multiple pieces for each + * selector identifier. + * + * \param pieceIndex the index of the spelling name piece. If this is greater + * than the actual number of pieces, it will return a NULL (invalid) range. + * + * \param options Reserved. + */ +CINDEX_LINKAGE CXSourceRange clang_Cursor_getSpellingNameRange(CXCursor, + unsigned pieceIndex, + unsigned options); + /** * \brief Retrieve the display name for the entity referenced by this cursor. * diff --git a/clang/test/Index/get-cursor.m b/clang/test/Index/get-cursor.m index ead18de0c019..d73b23a18f14 100644 --- a/clang/test/Index/get-cursor.m +++ b/clang/test/Index/get-cursor.m @@ -52,6 +52,14 @@ void foo1(Test2 *test2) { ++test2.implicitProp; } +@interface Test3 +-(void)setFoo:(int)x withBar:(int)y; +@end + +void foo3(Test3 *test3) { + [test3 setFoo:2 withBar:4]; +} + // RUN: c-index-test -cursor-at=%s:4:28 -cursor-at=%s:5:28 %s | FileCheck -check-prefix=CHECK-PROP %s // CHECK-PROP: ObjCPropertyDecl=foo1:4:26 // CHECK-PROP: ObjCPropertyDecl=foo2:5:27 @@ -68,7 +76,12 @@ void foo1(Test2 *test2) { // RUN: c-index-test -cursor-at=%s:38:6 -cursor-at=%s:40:11 \ // RUN: -cursor-at=%s:50:20 -cursor-at=%s:51:15 -cursor-at=%s:52:20 %s | FileCheck -check-prefix=CHECK-MEMBERREF %s // CHECK-MEMBERREF: 38:6 MemberRefExpr=x:34:16 SingleRefName=[38:6 - 38:7] RefName=[38:6 - 38:7] Extent=[38:3 - 38:7] -// CHECK-MEMBERREF: 40:9 MemberRefExpr=name:23:21 Extent=[40:3 - 40:13] Spelling=name -// CHECK-MEMBERREF: 50:17 MemberRefExpr=implicitProp:45:7 Extent=[50:11 - 50:29] Spelling=implicitProp -// CHECK-MEMBERREF: 51:9 MemberRefExpr=setImplicitProp::46:8 Extent=[51:3 - 51:21] -// CHECK-MEMBERREF: 52:11 MemberRefExpr=setImplicitProp::46:8 Extent=[52:5 - 52:23] +// CHECK-MEMBERREF: 40:9 MemberRefExpr=name:23:21 Extent=[40:3 - 40:13] Spelling=name ([40:9 - 40:13]) +// CHECK-MEMBERREF: 50:17 MemberRefExpr=implicitProp:45:7 Extent=[50:11 - 50:29] Spelling=implicitProp ([50:17 - 50:29]) +// CHECK-MEMBERREF: 51:9 MemberRefExpr=setImplicitProp::46:8 Extent=[51:3 - 51:21] Spelling=setImplicitProp: ([51:9 - 51:21]) +// CHECK-MEMBERREF: 52:11 MemberRefExpr=setImplicitProp::46:8 Extent=[52:5 - 52:23] Spelling=setImplicitProp: ([52:11 - 52:23]) + +// RUN: c-index-test -cursor-at=%s:56:24 -cursor-at=%s:60:14 \ +// RUN: %s | FileCheck -check-prefix=CHECK-SPELLRANGE %s +// CHECK-SPELLRANGE: 56:8 ObjCInstanceMethodDecl=setFoo:withBar::56:8 Extent=[56:1 - 56:37] Spelling=setFoo:withBar: ([56:8 - 56:14][56:22 - 56:29]) +// CHECK-SPELLRANGE: 60:3 ObjCMessageExpr=setFoo:withBar::56:8 Extent=[60:3 - 60:29] Spelling=setFoo:withBar: ([60:10 - 60:16][60:19 - 60:26]) diff --git a/clang/tools/c-index-test/c-index-test.c b/clang/tools/c-index-test/c-index-test.c index 5dd925463133..e774e78086c5 100644 --- a/clang/tools/c-index-test/c-index-test.c +++ b/clang/tools/c-index-test/c-index-test.c @@ -171,7 +171,8 @@ static void PrintRange(CXSourceRange R, const char *str) { if (!begin_file || !end_file) return; - printf(" %s=", str); + if (str) + printf(" %s=", str); PrintExtent(stdout, begin_line, begin_column, end_line, end_column); } @@ -1449,8 +1450,19 @@ static int inspect_cursor_at(int argc, const char **argv) { PrintCursorExtent(Cursor); Spelling = clang_getCursorSpelling(Cursor); cspell = clang_getCString(Spelling); - if (cspell && strlen(cspell) != 0) - printf(" Spelling=%s", cspell); + if (cspell && strlen(cspell) != 0) { + unsigned pieceIndex; + CXSourceRange range, extent; + extent = clang_getCursorExtent(Cursor); + printf(" Spelling=%s (", cspell); + for (pieceIndex = 0; ; ++pieceIndex) { + range = clang_Cursor_getSpellingNameRange(Cursor, pieceIndex, 0); + if (clang_Range_isNull(range)) + break; + PrintRange(range, 0); + } + printf(")"); + } clang_disposeString(Spelling); if (completionString != NULL) { printf("\nCompletion string: "); diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 2a05b1b6f728..c63a969fe46d 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -3167,6 +3167,63 @@ CXString clang_getCursorSpelling(CXCursor C) { return createCXString(""); } +CXSourceRange clang_Cursor_getSpellingNameRange(CXCursor C, + unsigned pieceIndex, + unsigned options) { + if (clang_Cursor_isNull(C)) + return clang_getNullRange(); + + ASTContext &Ctx = getCursorContext(C); + + if (clang_isStatement(C.kind)) { + Stmt *S = getCursorStmt(C); + if (LabelStmt *Label = dyn_cast_or_null(S)) { + if (pieceIndex > 0) + return clang_getNullRange(); + return cxloc::translateSourceRange(Ctx, Label->getIdentLoc()); + } + + return clang_getNullRange(); + } + + if (C.kind == CXCursor_ObjCMessageExpr) { + if (ObjCMessageExpr * + ME = dyn_cast_or_null(getCursorExpr(C))) { + if (pieceIndex >= ME->getNumSelectorLocs()) + return clang_getNullRange(); + return cxloc::translateSourceRange(Ctx, ME->getSelectorLoc(pieceIndex)); + } + } + + if (C.kind == CXCursor_ObjCInstanceMethodDecl || + C.kind == CXCursor_ObjCClassMethodDecl) { + if (ObjCMethodDecl * + MD = dyn_cast_or_null(getCursorDecl(C))) { + if (pieceIndex >= MD->getNumSelectorLocs()) + return clang_getNullRange(); + return cxloc::translateSourceRange(Ctx, MD->getSelectorLoc(pieceIndex)); + } + } + + // FIXME: A CXCursor_InclusionDirective should give the location of the + // filename, but we don't keep track of this. + + // FIXME: A CXCursor_AnnotateAttr should give the location of the annotation + // but we don't keep track of this. + + // FIXME: A CXCursor_AsmLabelAttr should give the location of the label + // but we don't keep track of this. + + // Default handling, give the location of the cursor. + + if (pieceIndex > 0) + return clang_getNullRange(); + + CXSourceLocation CXLoc = clang_getCursorLocation(C); + SourceLocation Loc = cxloc::translateSourceLocation(CXLoc); + return cxloc::translateSourceRange(Ctx, Loc); +} + CXString clang_getCursorDisplayName(CXCursor C) { if (!clang_isDeclaration(C.kind)) return clang_getCursorSpelling(C); diff --git a/clang/tools/libclang/libclang.exports b/clang/tools/libclang/libclang.exports index 21861fb7097c..2fe3f1d53c6c 100644 --- a/clang/tools/libclang/libclang.exports +++ b/clang/tools/libclang/libclang.exports @@ -4,6 +4,7 @@ clang_CXIndex_getGlobalOptions clang_CXIndex_setGlobalOptions clang_CXXMethod_isStatic clang_CXXMethod_isVirtual +clang_Cursor_getSpellingNameRange clang_Cursor_getTranslationUnit clang_Cursor_isNull clang_IndexAction_create