arphaman updated this revision to Diff 120157.
arphaman retitled this revision from "[ObjC] Messages to 'self' in class 
methods should use class method dispatch to avoid multiple method ambiguities" 
to "[ObjC] Messages to 'self' in class methods that return 'instancetype' 
should use the pointer to the class as the result type of the message".
arphaman added a comment.

I changed the approach for this patch. Now, instead of using class method 
dispatch Clang instead adjusts the result type of the message sends to methods 
that return `instancetype` with `self` receivers in class methods.


Repository:
  rL LLVM

https://reviews.llvm.org/D36790

Files:
  include/clang/Sema/Sema.h
  lib/Sema/SemaExprObjC.cpp
  test/SemaObjC/multiple-method-names-in-class-self.m

Index: test/SemaObjC/multiple-method-names-in-class-self.m
===================================================================
--- /dev/null
+++ test/SemaObjC/multiple-method-names-in-class-self.m
@@ -0,0 +1,53 @@
+// RUN: %clang_cc1 -Wobjc-multiple-method-names -x objective-c -verify %s
+// RUN: %clang_cc1 -Wobjc-multiple-method-names -x objective-c -verify -fobjc-arc -DARC %s
+#ifdef ARC
+// expected-no-diagnostics
+#endif
+
+@interface NSObj
+
++ (instancetype) alloc;
+
++ (_Nonnull instancetype) globalObject;
+
+@end
+
+@interface SelfAllocReturn: NSObj
+
+- (instancetype)initWithFoo:(int)x;
+#ifndef ARC
+// expected-note@-2 2 {{using}}
+#endif
+
+@end
+
+@interface SelfAllocReturn2: NSObj
+
+- (instancetype)initWithFoo:(SelfAllocReturn *)x;
+#ifndef ARC
+// expected-note@-2 2 {{also found}}
+#endif
+
+@end
+
+@implementation SelfAllocReturn
+
+- (instancetype)initWithFoo:(int)x {
+    return self;
+}
+
++ (instancetype) thingWithFoo:(int)x {
+    return [[self alloc] initWithFoo: x];
+#ifndef ARC
+// expected-warning@-2 {{multiple methods named 'initWithFoo:' found}}
+#endif
+}
+
++ (void) initGlobal {
+  (void)[[self globalObject] initWithFoo: 20];
+#ifndef ARC
+// expected-warning@-2 {{multiple methods named 'initWithFoo:' found}}
+#endif
+}
+
+@end
Index: lib/Sema/SemaExprObjC.cpp
===================================================================
--- lib/Sema/SemaExprObjC.cpp
+++ lib/Sema/SemaExprObjC.cpp
@@ -1336,7 +1336,8 @@
   return transferNullability(ReceiverType);
 }
 
-QualType Sema::getMessageSendResultType(QualType ReceiverType,
+QualType Sema::getMessageSendResultType(const Expr *Receiver,
+                                        QualType ReceiverType,
                                         ObjCMethodDecl *Method,
                                         bool isClassMessage,
                                         bool isSuperMessage) {
@@ -1347,8 +1348,34 @@
                                                      isSuperMessage);
 
   // If this is a class message, ignore the nullability of the receiver.
-  if (isClassMessage)
+  if (isClassMessage) {
+    // Messages to 'self' that return 'instancetype' in class methods return
+    // pointer to the parent interface of the method when ARC is enabled (
+    // because self can't be reassigned when ARC is on).
+    if (Receiver &&
+        (ReceiverType->isObjCClassOrClassKindOfType() ||
+         ReceiverType->isObjCQualifiedClassType()) &&
+        Receiver->isObjCSelfExpr() && getLangOpts().ObjCAutoRefCount) {
+      assert(ReceiverType->isObjCClassType() && "expected a Class self");
+      QualType T = Method->getSendResultType(ReceiverType);
+      AttributedType::stripOuterNullability(T);
+      if (T == Context.getObjCInstanceType()) {
+        const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(
+            cast<ImplicitParamDecl>(
+                cast<DeclRefExpr>(Receiver->IgnoreParenImpCasts())->getDecl())
+                ->getDeclContext());
+        assert(MD->isClassMethod() && "expected a class method");
+        QualType NewResultType = Context.getObjCObjectPointerType(
+            Context.getObjCInterfaceType(MD->getClassInterface()));
+        if (auto Nullability = resultType->getNullability(Context))
+          NewResultType = Context.getAttributedType(
+              AttributedType::getNullabilityAttrKind(*Nullability),
+              NewResultType, NewResultType);
+        return NewResultType;
+      }
+    }
     return resultType;
+  }
 
   // Map the nullability of the result into a table index.
   unsigned receiverNullabilityIdx = 0;
@@ -1490,15 +1517,12 @@
     << MsgSend->getType();
 }
 
-bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
-                                     MultiExprArg Args,
-                                     Selector Sel,
-                                     ArrayRef<SourceLocation> SelectorLocs,
-                                     ObjCMethodDecl *Method,
-                                     bool isClassMessage, bool isSuperMessage,
-                                     SourceLocation lbrac, SourceLocation rbrac,
-                                     SourceRange RecRange,
-                                     QualType &ReturnType, ExprValueKind &VK) {
+bool Sema::CheckMessageArgumentTypes(
+    const Expr *Receiver, QualType ReceiverType, MultiExprArg Args,
+    Selector Sel, ArrayRef<SourceLocation> SelectorLocs, ObjCMethodDecl *Method,
+    bool isClassMessage, bool isSuperMessage, SourceLocation lbrac,
+    SourceLocation rbrac, SourceRange RecRange, QualType &ReturnType,
+    ExprValueKind &VK) {
   SourceLocation SelLoc;
   if (!SelectorLocs.empty() && SelectorLocs.front().isValid())
     SelLoc = SelectorLocs.front();
@@ -1575,8 +1599,8 @@
     return false;
   }
 
-  ReturnType = getMessageSendResultType(ReceiverType, Method, isClassMessage, 
-                                        isSuperMessage);
+  ReturnType = getMessageSendResultType(Receiver, ReceiverType, Method,
+                                        isClassMessage, isSuperMessage);
   VK = Expr::getValueKindForType(Method->getReturnType());
 
   unsigned NumNamedArgs = Sel.getNumArgs();
@@ -2460,12 +2484,10 @@
 
   unsigned NumArgs = ArgsIn.size();
   Expr **Args = ArgsIn.data();
-  if (CheckMessageArgumentTypes(ReceiverType, MultiExprArg(Args, NumArgs),
-                                Sel, SelectorLocs,
-                                Method, true,
-                                SuperLoc.isValid(), LBracLoc, RBracLoc,
-                                SourceRange(),
-                                ReturnType, VK))
+  if (CheckMessageArgumentTypes(/*Receiver=*/nullptr, ReceiverType,
+                                MultiExprArg(Args, NumArgs), Sel, SelectorLocs,
+                                Method, true, SuperLoc.isValid(), LBracLoc,
+                                RBracLoc, SourceRange(), ReturnType, VK))
     return ExprError();
 
   if (Method && !Method->getReturnType()->isVoidType() &&
@@ -2954,9 +2976,9 @@
   ExprValueKind VK = VK_RValue;
   bool ClassMessage = (ReceiverType->isObjCClassType() ||
                        ReceiverType->isObjCQualifiedClassType());
-  if (CheckMessageArgumentTypes(ReceiverType, MultiExprArg(Args, NumArgs),
-                                Sel, SelectorLocs, Method,
-                                ClassMessage, SuperLoc.isValid(), 
+  if (CheckMessageArgumentTypes(Receiver, ReceiverType,
+                                MultiExprArg(Args, NumArgs), Sel, SelectorLocs,
+                                Method, ClassMessage, SuperLoc.isValid(),
                                 LBracLoc, RBracLoc, RecRange, ReturnType, VK))
     return ExprError();
 
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -9663,21 +9663,20 @@
   /// \param Method - May be null.
   /// \param [out] ReturnType - The return type of the send.
   /// \return true iff there were any incompatible types.
-  bool CheckMessageArgumentTypes(QualType ReceiverType,
+  bool CheckMessageArgumentTypes(const Expr *Receiver, QualType ReceiverType,
                                  MultiExprArg Args, Selector Sel,
                                  ArrayRef<SourceLocation> SelectorLocs,
                                  ObjCMethodDecl *Method, bool isClassMessage,
-                                 bool isSuperMessage,
-                                 SourceLocation lbrac, SourceLocation rbrac,
-                                 SourceRange RecRange,
+                                 bool isSuperMessage, SourceLocation lbrac,
+                                 SourceLocation rbrac, SourceRange RecRange,
                                  QualType &ReturnType, ExprValueKind &VK);
 
   /// \brief Determine the result of a message send expression based on
   /// the type of the receiver, the method expected to receive the message,
   /// and the form of the message send.
-  QualType getMessageSendResultType(QualType ReceiverType,
-                                    ObjCMethodDecl *Method,
-                                    bool isClassMessage, bool isSuperMessage);
+  QualType getMessageSendResultType(const Expr *Receiver, QualType ReceiverType,
+                                    ObjCMethodDecl *Method, bool isClassMessage,
+                                    bool isSuperMessage);
 
   /// \brief If the given expression involves a message send to a method
   /// with a related result type, emit a note describing what happened.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to