[libclang] Introduce clang_Cursor_getReceiverType which returns the CXType for
the receiver of an ObjC message expression.

rdar://12578643

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@167201 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
index 299fa8f..2b52c0c 100644
--- a/include/clang-c/Index.h
+++ b/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_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/include/clang/AST/ExprObjC.h b/include/clang/AST/ExprObjC.h
index 748aaa1..27f5da0 100644
--- a/include/clang/AST/ExprObjC.h
+++ b/include/clang/AST/ExprObjC.h
@@ -1195,6 +1195,17 @@
     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/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 4a8033f..114aad5 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -3442,33 +3442,29 @@
   return Selector(SelectorOrMethod); 
 }
 
-ObjCInterfaceDecl *ObjCMessageExpr::getReceiverInterface() const {
+QualType ObjCMessageExpr::getReceiverType() const {
   switch (getReceiverKind()) {
   case Instance:
-    if (const ObjCObjectPointerType *Ptr
-          = getInstanceReceiver()->getType()->getAs<ObjCObjectPointerType>())
-      return Ptr->getInterfaceDecl();
-    break;
-
+    return getInstanceReceiver()->getType();
   case Class:
-    if (const ObjCObjectType *Ty
-          = getClassReceiver()->getAs<ObjCObjectType>())
-      return Ty->getInterface();
-    break;
-
+    return getClassReceiver();
   case SuperInstance:
-    if (const ObjCObjectPointerType *Ptr
-          = getSuperType()->getAs<ObjCObjectPointerType>())
-      return Ptr->getInterfaceDecl();
-    break;
-
   case SuperClass:
-    if (const ObjCObjectType *Iface
-          = getSuperType()->getAs<ObjCObjectType>())
-      return Iface->getInterface();
-    break;
+    return getSuperType();
   }
 
+  llvm_unreachable("unexpected receiver kind");
+}
+
+ObjCInterfaceDecl *ObjCMessageExpr::getReceiverInterface() const {
+  QualType T = getReceiverType();
+
+  if (const ObjCObjectPointerType *Ptr = T->getAs<ObjCObjectPointerType>())
+    return Ptr->getInterfaceDecl();
+
+  if (const ObjCObjectType *Ty = T->getAs<ObjCObjectType>())
+    return Ty->getInterface();
+
   return 0;
 }
 
diff --git a/test/Index/cursor-dynamic-call.mm b/test/Index/cursor-dynamic-call.mm
index f9d6a87..ac9e6d3 100644
--- a/test/Index/cursor-dynamic-call.mm
+++ b/test/Index/cursor-dynamic-call.mm
@@ -50,10 +50,12 @@
 
 // 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/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
index 2df2e4b..3e4404c 100644
--- a/tools/c-index-test/c-index-test.c
+++ b/tools/c-index-test/c-index-test.c
@@ -1955,6 +1955,12 @@
           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/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp
index ce51702..8d3e169 100644
--- a/tools/libclang/CXCursor.cpp
+++ b/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 @@
   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<ObjCMessageExpr>(E))
+    return cxtype::MakeCXType(MsgE->getReceiverType(), TU);
+
+  return cxtype::MakeCXType(QualType(), TU);
+}
+
 } // end: extern "C"
diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports
index ec77faf..4495b66 100644
--- a/tools/libclang/libclang.exports
+++ b/tools/libclang/libclang.exports
@@ -13,6 +13,7 @@
 clang_Cursor_getObjCSelectorIndex
 clang_Cursor_getSpellingNameRange
 clang_Cursor_getTranslationUnit
+clang_Cursor_getReceiverType
 clang_Cursor_isDynamicCall
 clang_Cursor_isNull
 clang_Cursor_getModule