From 77328d1bb92c2c46bc3e4badc4b4b97c517903b7 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Wed, 15 Sep 2010 23:19:31 +0000 Subject: [PATCH] Handle bracket insertion for Objective-C class messages in a very narrow, almost useless case where we're inside a parenthesized expression, e.g., (NSArray alloc]) The solution to the general case still eludes me. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@114039 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Parse/ParseExpr.cpp | 86 +++++++++++++++++------------- lib/Sema/SemaExprObjC.cpp | 12 ++--- test/FixIt/fixit-objc-message.m | 1 + test/Index/complete-objc-message.m | 2 +- 4 files changed, 57 insertions(+), 44 deletions(-) diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 26563de2b2..33c7d67ce1 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -1529,51 +1529,63 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, Ty = ParseTypeName(); } - // Match the ')'. - if (Tok.is(tok::r_paren)) - RParenLoc = ConsumeParen(); - else - MatchRHSPunctuation(tok::r_paren, OpenLoc); + // If our type is followed by an identifier and either ':' or ']', then + // this is probably an Objective-C message send where the leading '[' is + // missing. Recover as if that were the case. + if (!Ty.isInvalid() && Tok.is(tok::identifier) && !InMessageExpression && + getLang().ObjC1 && !Ty.get().get().isNull() && + (NextToken().is(tok::colon) || NextToken().is(tok::r_square)) && + Ty.get().get()->isObjCObjectOrInterfaceType()) { + Result = ParseObjCMessageExpressionBody(SourceLocation(), + SourceLocation(), + Ty.get(), 0); + } else { + // Match the ')'. + if (Tok.is(tok::r_paren)) + RParenLoc = ConsumeParen(); + else + MatchRHSPunctuation(tok::r_paren, OpenLoc); + + if (Tok.is(tok::l_brace)) { + ExprType = CompoundLiteral; + return ParseCompoundLiteralExpression(Ty.get(), OpenLoc, RParenLoc); + } - if (Tok.is(tok::l_brace)) { - ExprType = CompoundLiteral; - return ParseCompoundLiteralExpression(Ty.get(), OpenLoc, RParenLoc); - } + if (ExprType == CastExpr) { + // We parsed '(' type-name ')' and the thing after it wasn't a '{'. - if (ExprType == CastExpr) { - // We parsed '(' type-name ')' and the thing after it wasn't a '{'. + if (Ty.isInvalid()) + return ExprError(); - if (Ty.isInvalid()) - return ExprError(); + CastTy = Ty.get(); - CastTy = Ty.get(); + // Note that this doesn't parse the subsequent cast-expression, it just + // returns the parsed type to the callee. + if (stopIfCastExpr) + return ExprResult(); + + // Reject the cast of super idiom in ObjC. + if (Tok.is(tok::identifier) && getLang().ObjC1 && + Tok.getIdentifierInfo() == Ident_super && + getCurScope()->isInObjcMethodScope() && + GetLookAheadToken(1).isNot(tok::period)) { + Diag(Tok.getLocation(), diag::err_illegal_super_cast) + << SourceRange(OpenLoc, RParenLoc); + return ExprError(); + } - // Note that this doesn't parse the subsequent cast-expression, it just - // returns the parsed type to the callee. - if (stopIfCastExpr) - return ExprResult(); - - // Reject the cast of super idiom in ObjC. - if (Tok.is(tok::identifier) && getLang().ObjC1 && - Tok.getIdentifierInfo() == Ident_super && - getCurScope()->isInObjcMethodScope() && - GetLookAheadToken(1).isNot(tok::period)) { - Diag(Tok.getLocation(), diag::err_illegal_super_cast) - << SourceRange(OpenLoc, RParenLoc); - return ExprError(); + // Parse the cast-expression that follows it next. + // TODO: For cast expression with CastTy. + Result = ParseCastExpression(false, false, CastTy); + if (!Result.isInvalid()) + Result = Actions.ActOnCastExpr(getCurScope(), OpenLoc, CastTy, + RParenLoc, Result.take()); + return move(Result); } - // Parse the cast-expression that follows it next. - // TODO: For cast expression with CastTy. - Result = ParseCastExpression(false, false, CastTy); - if (!Result.isInvalid()) - Result = Actions.ActOnCastExpr(getCurScope(), OpenLoc, CastTy, RParenLoc, - Result.take()); - return move(Result); + Diag(Tok, diag::err_expected_lbrace_in_compound_literal); + return ExprError(); } - - Diag(Tok, diag::err_expected_lbrace_in_compound_literal); - return ExprError(); } else if (TypeOfCast) { // Parse the expression-list. InMessageExpressionRAIIObject InMessage(*this, false); diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index ebeed130e3..caa2762d7f 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -786,12 +786,12 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, // ArgExprs is optional - if it is present, the number of expressions // is obtained from Sel.getNumArgs(). ExprResult Sema::ActOnClassMessage(Scope *S, - ParsedType Receiver, - Selector Sel, - SourceLocation LBracLoc, - SourceLocation SelectorLoc, - SourceLocation RBracLoc, - MultiExprArg Args) { + ParsedType Receiver, + Selector Sel, + SourceLocation LBracLoc, + SourceLocation SelectorLoc, + SourceLocation RBracLoc, + MultiExprArg Args) { TypeSourceInfo *ReceiverTypeInfo; QualType ReceiverType = GetTypeFromParser(Receiver, &ReceiverTypeInfo); if (ReceiverType.isNull()) diff --git a/test/FixIt/fixit-objc-message.m b/test/FixIt/fixit-objc-message.m index 72728d20ad..1969faab3b 100644 --- a/test/FixIt/fixit-objc-message.m +++ b/test/FixIt/fixit-objc-message.m @@ -21,6 +21,7 @@ void f(A *a, int i, int j) { int array[17]; (void)array[a method1:5+2 second:+(3.14159)]]; + (A method2:5+2 second:3.14159]) } @interface B : A diff --git a/test/Index/complete-objc-message.m b/test/Index/complete-objc-message.m index d6abd4bd83..02d7f2140c 100644 --- a/test/Index/complete-objc-message.m +++ b/test/Index/complete-objc-message.m @@ -135,7 +135,7 @@ void test_ranking(B *b) { b method1]; } -void test_overload_2(Overload *ovl) { +void test_overload3(Overload *ovl) { ovl Method:1 Arg1:1 OtherArg:ovl]; } -- 2.40.0