diff options
author | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2012-07-02 23:54:36 +0000 |
---|---|---|
committer | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2012-07-02 23:54:36 +0000 |
commit | f39a7aea7dd0bf0716a066e2db2f97ea8730e4fa (patch) | |
tree | fdcd2af9e8a3dc278eaecda2c16d22e2ef468185 | |
parent | 6c89eafc90f5c51a0bf185a993961170aee530c2 (diff) |
[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
-rw-r--r-- | include/clang-c/Index.h | 13 | ||||
-rw-r--r-- | test/Index/cursor-dynamic-call.mm | 59 | ||||
-rw-r--r-- | tools/c-index-test/c-index-test.c | 3 | ||||
-rw-r--r-- | tools/libclang/CXCursor.cpp | 27 | ||||
-rw-r--r-- | tools/libclang/libclang.exports | 1 |
5 files changed, 102 insertions, 1 deletions
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 @@ -3144,6 +3144,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 * with whitespace in between. 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<ObjCMessageExpr>(E)) + return MsgE->getReceiverKind() == ObjCMessageExpr::Instance; + + const MemberExpr *ME = 0; + if (isa<MemberExpr>(E)) + ME = cast<MemberExpr>(E); + else if (const CallExpr *CE = dyn_cast<CallExpr>(E)) + ME = dyn_cast_or_null<MemberExpr>(CE->getCallee()); + + if (ME) { + if (const CXXMethodDecl * + MD = dyn_cast_or_null<CXXMethodDecl>(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 |