From b26a24cca2fa03ae7db14b0b6290c005ed93cd55 Mon Sep 17 00:00:00 2001 From: Argyrios Kyrtzidis Date: Thu, 1 Nov 2012 02:01:34 +0000 Subject: [PATCH] [libclang] Introduce clang_Cursor_getReceiverType which returns the CXType for the receiver of an ObjC message expression. rdar://12578643 llvm-svn: 167201 --- clang/include/clang-c/Index.h | 8 +++++++- clang/include/clang/AST/ExprObjC.h | 11 ++++++++++ clang/lib/AST/Expr.cpp | 36 +++++++++++++++------------------ clang/test/Index/cursor-dynamic-call.mm | 8 +++++--- clang/tools/c-index-test/c-index-test.c | 6 ++++++ clang/tools/libclang/CXCursor.cpp | 13 ++++++++++++ clang/tools/libclang/libclang.exports | 1 + 7 files changed, 59 insertions(+), 24 deletions(-) diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h index 299fa8f..2b52c0c 100644 --- a/clang/include/clang-c/Index.h +++ b/clang/include/clang-c/Index.h @@ -24,7 +24,7 @@ #include "clang-c/CXString.h" #define CINDEX_VERSION_MAJOR 0 -#define CINDEX_VERSION_MINOR 5 +#define CINDEX_VERSION_MINOR 6 #define CINDEX_VERSION_ENCODE(major, minor) ( \ ((major) * 10000) \ @@ -3197,6 +3197,12 @@ CINDEX_LINKAGE int clang_Cursor_getObjCSelectorIndex(CXCursor); CINDEX_LINKAGE int clang_Cursor_isDynamicCall(CXCursor C); /** + * \brief Given a cursor pointing to an ObjC message, returns the CXType of the + * receiver. + */ +CINDEX_LINKAGE CXType clang_Cursor_getReceiverType(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/clang/include/clang/AST/ExprObjC.h b/clang/include/clang/AST/ExprObjC.h index 748aaa1..27f5da0 100644 --- a/clang/include/clang/AST/ExprObjC.h +++ b/clang/include/clang/AST/ExprObjC.h @@ -1195,6 +1195,17 @@ public: return SourceLocation(); } + /// \brief Retrieve the receiver type to which this message is being directed. + /// + /// This routine cross-cuts all of the different kinds of message + /// sends to determine what the underlying (statically known) type + /// of the receiver will be; use \c getReceiverKind() to determine + /// whether the message is a class or an instance method, whether it + /// is a send to super or not, etc. + /// + /// \returns The type of the receiver. + QualType getReceiverType() const; + /// \brief Retrieve the Objective-C interface to which this message /// is being directed, if known. /// diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 4a8033f..114aad5 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -3442,33 +3442,29 @@ Selector ObjCMessageExpr::getSelector() const { return Selector(SelectorOrMethod); } -ObjCInterfaceDecl *ObjCMessageExpr::getReceiverInterface() const { +QualType ObjCMessageExpr::getReceiverType() const { switch (getReceiverKind()) { case Instance: - if (const ObjCObjectPointerType *Ptr - = getInstanceReceiver()->getType()->getAs()) - return Ptr->getInterfaceDecl(); - break; - + return getInstanceReceiver()->getType(); case Class: - if (const ObjCObjectType *Ty - = getClassReceiver()->getAs()) - return Ty->getInterface(); - break; - + return getClassReceiver(); case SuperInstance: - if (const ObjCObjectPointerType *Ptr - = getSuperType()->getAs()) - return Ptr->getInterfaceDecl(); - break; - case SuperClass: - if (const ObjCObjectType *Iface - = getSuperType()->getAs()) - return Iface->getInterface(); - break; + return getSuperType(); } + llvm_unreachable("unexpected receiver kind"); +} + +ObjCInterfaceDecl *ObjCMessageExpr::getReceiverInterface() const { + QualType T = getReceiverType(); + + if (const ObjCObjectPointerType *Ptr = T->getAs()) + return Ptr->getInterfaceDecl(); + + if (const ObjCObjectType *Ty = T->getAs()) + return Ty->getInterface(); + return 0; } diff --git a/clang/test/Index/cursor-dynamic-call.mm b/clang/test/Index/cursor-dynamic-call.mm index f9d6a87..ac9e6d3 100644 --- a/clang/test/Index/cursor-dynamic-call.mm +++ b/clang/test/Index/cursor-dynamic-call.mm @@ -50,10 +50,12 @@ void foo(SS *ss, IS* is, Class cls) { // 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: 25:3 ObjCMessageExpr=meth:14:8 {{.*}} Dynamic-call Receiver-type=ObjCObjectPointer // CHECK-NOT: 26:3 {{.*}} Dynamic-call // CHECK-NOT: 29:3 {{.*}} Dynamic-call +// CHECK: 29:3 {{.*}} Receiver-type=ObjCInterface // CHECK: 34:7 MemberRefExpr=meth:3:16 {{.*}} Dynamic-call -// CHECK: 35:3 ObjCMessageExpr=meth:14:8 {{.*}} Dynamic-call +// CHECK: 35:3 ObjCMessageExpr=meth:14:8 {{.*}} Dynamic-call Receiver-type=ObjCObjectPointer // CHECK-NOT: 36:3 {{.*}} Dynamic-call -// CHECK: 37:3 ObjCMessageExpr=ClsMeth:15:8 {{.*}} Dynamic-call +// CHECK: 36:3 {{.*}} Receiver-type=ObjCInterface +// CHECK: 37:3 ObjCMessageExpr=ClsMeth:15:8 {{.*}} Dynamic-call Receiver-type=ObjCClass diff --git a/clang/tools/c-index-test/c-index-test.c b/clang/tools/c-index-test/c-index-test.c index 2df2e4b..3e4404c 100644 --- a/clang/tools/c-index-test/c-index-test.c +++ b/clang/tools/c-index-test/c-index-test.c @@ -1955,6 +1955,12 @@ static int inspect_cursor_at(int argc, const char **argv) { printf(" Selector index=%d",clang_Cursor_getObjCSelectorIndex(Cursor)); if (clang_Cursor_isDynamicCall(Cursor)) printf(" Dynamic-call"); + if (Cursor.kind == CXCursor_ObjCMessageExpr) { + CXType T = clang_Cursor_getReceiverType(Cursor); + CXString S = clang_getTypeKindSpelling(T.kind); + printf(" Receiver-type=%s", clang_getCString(S)); + clang_disposeString(S); + } { CXModule mod = clang_Cursor_getModule(Cursor); diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp index ce517023..8d3e169 100644 --- a/clang/tools/libclang/CXCursor.cpp +++ b/clang/tools/libclang/CXCursor.cpp @@ -15,6 +15,7 @@ #include "CXTranslationUnit.h" #include "CXCursor.h" +#include "CXType.h" #include "CXString.h" #include "clang/Frontend/ASTUnit.h" #include "clang/AST/Decl.h" @@ -1172,4 +1173,16 @@ int clang_Cursor_isDynamicCall(CXCursor C) { return 0; } +CXType clang_Cursor_getReceiverType(CXCursor C) { + CXTranslationUnit TU = cxcursor::getCursorTU(C); + const Expr *E = 0; + if (clang_isExpression(C.kind)) + E = getCursorExpr(C); + + if (const ObjCMessageExpr *MsgE = dyn_cast_or_null(E)) + return cxtype::MakeCXType(MsgE->getReceiverType(), TU); + + return cxtype::MakeCXType(QualType(), TU); +} + } // end: extern "C" diff --git a/clang/tools/libclang/libclang.exports b/clang/tools/libclang/libclang.exports index ec77faf..4495b66 100644 --- a/clang/tools/libclang/libclang.exports +++ b/clang/tools/libclang/libclang.exports @@ -13,6 +13,7 @@ clang_Cursor_getNumArguments clang_Cursor_getObjCSelectorIndex clang_Cursor_getSpellingNameRange clang_Cursor_getTranslationUnit +clang_Cursor_getReceiverType clang_Cursor_isDynamicCall clang_Cursor_isNull clang_Cursor_getModule -- 2.7.4