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
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits