/// \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);
/// 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);
/// If the given expression involves a message send to a method
/// with a related result type, emit a note describing what happened.
return transferNullability(ReceiverType);
}
-QualType Sema::getMessageSendResultType(QualType ReceiverType,
+QualType Sema::getMessageSendResultType(const Expr *Receiver,
+ QualType ReceiverType,
ObjCMethodDecl *Method,
bool isClassMessage,
bool isSuperMessage) {
isSuperMessage);
// If this is a class message, ignore the nullability of the receiver.
- if (isClassMessage)
+ if (isClassMessage) {
+ // In a class method, class messages to 'self' that return instancetype can
+ // be typed as the current class. We can safely do this in ARC because self
+ // can't be reassigned, and we do it unsafely outside of ARC because in
+ // practice people never reassign self in class methods and there's some
+ // virtue in not being aggressively pedantic.
+ if (Receiver && Receiver->isObjCSelfExpr()) {
+ 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;
+ }
// There is nothing left to do if the result type cannot have a nullability
// specifier.
<< 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();
return false;
}
- ReturnType = getMessageSendResultType(ReceiverType, Method, isClassMessage,
- isSuperMessage);
+ ReturnType = getMessageSendResultType(Receiver, ReceiverType, Method,
+ isClassMessage, isSuperMessage);
VK = Expr::getValueKindForType(Method->getReturnType());
unsigned NumNamedArgs = Sel.getNumArgs();
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() &&
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();