From f39a7aea7dd0bf0716a066e2db2f97ea8730e4fa Mon Sep 17 00:00:00 2001 From: Argyrios Kyrtzidis Date: Mon, 2 Jul 2012 23:54:36 +0000 Subject: [PATCH] [libclang] Introduce clang_Cursor_isDynamicCall which, given a cursor pointing to a C++ method call or an ObjC message, returns non-zero if the method/message is "dynamic", meaning: For a C++ method: the call is virtual. For an ObjC message: the receiver is an object instance, not 'super' or a specific class. rdar://11779185 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@159627 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang-c/Index.h | 13 +++++++ test/Index/cursor-dynamic-call.mm | 59 +++++++++++++++++++++++++++++++ tools/c-index-test/c-index-test.c | 3 ++ tools/libclang/CXCursor.cpp | 27 +++++++++++++- tools/libclang/libclang.exports | 1 + 5 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 test/Index/cursor-dynamic-call.mm diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h index b34918fb6f..33a92e4653 100644 --- a/include/clang-c/Index.h +++ b/include/clang-c/Index.h @@ -3143,6 +3143,19 @@ CINDEX_LINKAGE CXCursor clang_getCanonicalCursor(CXCursor); */ CINDEX_LINKAGE int clang_Cursor_getObjCSelectorIndex(CXCursor); +/** + * \brief Given a cursor pointing to a C++ method call or an ObjC message, + * returns non-zero if the method/message is "dynamic", meaning: + * + * For a C++ method: the call is virtual. + * For an ObjC message: the receiver is an object instance, not 'super' or a + * specific class. + * + * If the method/message is "static" or the cursor does not point to a + * method/message, it will return zero. + */ +CINDEX_LINKAGE int clang_Cursor_isDynamicCall(CXCursor C); + /** * \brief Given a cursor that represents a declaration, return the associated * comment's source range. The range may include multiple consecutive comments diff --git a/test/Index/cursor-dynamic-call.mm b/test/Index/cursor-dynamic-call.mm new file mode 100644 index 0000000000..f9d6a8716d --- /dev/null +++ b/test/Index/cursor-dynamic-call.mm @@ -0,0 +1,59 @@ + +struct SB { + virtual void meth(); +}; + +struct SS : public SB { + void submeth() { + this->meth(); + SB::meth(); + } +}; + +@interface IB +-(void)meth; ++(void)ClsMeth; +@end + +@interface IS : IB +-(void)submeth; ++(void)ClsMeth; +@end + +@implementation IS +-(void)submeth { + [self meth]; + [super meth]; +} ++(void)ClsMeth { + [super ClsMeth]; +} +@end + +void foo(SS *ss, IS* is, Class cls) { + ss->meth(); + [is meth]; + [IB ClsMeth]; + [cls ClsMeth]; +} + +// RUN: c-index-test -cursor-at=%s:8:11 \ +// RUN: -cursor-at=%s:9:11 \ +// RUN: -cursor-at=%s:25:11 \ +// RUN: -cursor-at=%s:26:11 \ +// RUN: -cursor-at=%s:29:11 \ +// RUN: -cursor-at=%s:34:9 \ +// RUN: -cursor-at=%s:35:9 \ +// RUN: -cursor-at=%s:36:9 \ +// RUN: -cursor-at=%s:37:9 \ +// RUN: %s | FileCheck %s + +// CHECK: 8:11 MemberRefExpr=meth:3:16 {{.*}} Dynamic-call +// CHECK-NOT: 9:9 {{.*}} Dynamic-call +// CHECK: 25:3 ObjCMessageExpr=meth:14:8 {{.*}} Dynamic-call +// CHECK-NOT: 26:3 {{.*}} Dynamic-call +// CHECK-NOT: 29:3 {{.*}} Dynamic-call +// CHECK: 34:7 MemberRefExpr=meth:3:16 {{.*}} Dynamic-call +// CHECK: 35:3 ObjCMessageExpr=meth:14:8 {{.*}} Dynamic-call +// CHECK-NOT: 36:3 {{.*}} Dynamic-call +// CHECK: 37:3 ObjCMessageExpr=ClsMeth:15:8 {{.*}} Dynamic-call diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c index 43229fdc13..79a3c573b9 100644 --- a/tools/c-index-test/c-index-test.c +++ b/tools/c-index-test/c-index-test.c @@ -1614,6 +1614,9 @@ static int inspect_cursor_at(int argc, const char **argv) { clang_disposeString(Spelling); if (clang_Cursor_getObjCSelectorIndex(Cursor) != -1) printf(" Selector index=%d",clang_Cursor_getObjCSelectorIndex(Cursor)); + if (clang_Cursor_isDynamicCall(Cursor)) + printf(" Dynamic-call"); + if (completionString != NULL) { printf("\nCompletion string: "); print_completion_string(completionString, stdout); diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp index ae7d806c7f..2757af434c 100644 --- a/tools/libclang/CXCursor.cpp +++ b/tools/libclang/CXCursor.cpp @@ -1319,5 +1319,30 @@ void clang_disposeOverriddenCursors(CXCursor *overridden) { pool.AvailableCursors.push_back(Vec); } - + +int clang_Cursor_isDynamicCall(CXCursor C) { + const Expr *E = 0; + if (clang_isExpression(C.kind)) + E = getCursorExpr(C); + if (!E) + return 0; + + if (const ObjCMessageExpr *MsgE = dyn_cast(E)) + return MsgE->getReceiverKind() == ObjCMessageExpr::Instance; + + const MemberExpr *ME = 0; + if (isa(E)) + ME = cast(E); + else if (const CallExpr *CE = dyn_cast(E)) + ME = dyn_cast_or_null(CE->getCallee()); + + if (ME) { + if (const CXXMethodDecl * + MD = dyn_cast_or_null(ME->getMemberDecl())) + return MD->isVirtual() && !ME->hasQualifier(); + } + + return 0; +} + } // end: extern "C" diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports index 1272a02a12..3775ce1476 100644 --- a/tools/libclang/libclang.exports +++ b/tools/libclang/libclang.exports @@ -12,6 +12,7 @@ clang_Cursor_getNumArguments clang_Cursor_getObjCSelectorIndex clang_Cursor_getSpellingNameRange clang_Cursor_getTranslationUnit +clang_Cursor_isDynamicCall clang_Cursor_isNull clang_IndexAction_create clang_IndexAction_dispose -- 2.40.0