[cfe-commits] r113968 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td include/clang/Parse/Parser.h lib/Parse/ParseExpr.cpp lib/Parse/ParseInit.cpp lib/Parse/ParseObjc.cpp lib/Parse/ParseStmt.cpp lib/Parse/Parser.cpp lib/Parse/RAIIObjectsForParser.h lib/Sema/SemaExprObjC.cpp test/FixIt/fixit-objc-message.m
Douglas Gregor
dgregor at apple.com
Wed Sep 15 07:51:05 PDT 2010
Author: dgregor
Date: Wed Sep 15 09:51:05 2010
New Revision: 113968
URL: http://llvm.org/viewvc/llvm-project?rev=113968&view=rev
Log:
Implement bracket insertion for Objective-C instance message sends as
part of parser recovery. For example, given:
a method1:arg];
we detect after parsing the expression "a" that we have the start of a
message send expression. We pretend we've seen a '[' prior to the a,
then parse the remainder as a message send. We'll then give a
diagnostic+fix-it such as:
fixit-objc-message.m:17:3: error: missing '[' at start of message
send expression
a method1:arg];
^
[
The algorithm here is very simple, and always assumes that the open
bracket goes at the beginning of the message send. It also only works
for non-super instance message sends at this time.
Added:
cfe/trunk/test/FixIt/fixit-objc-message.m
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Parse/Parser.h
cfe/trunk/lib/Parse/ParseExpr.cpp
cfe/trunk/lib/Parse/ParseInit.cpp
cfe/trunk/lib/Parse/ParseObjc.cpp
cfe/trunk/lib/Parse/ParseStmt.cpp
cfe/trunk/lib/Parse/Parser.cpp
cfe/trunk/lib/Parse/RAIIObjectsForParser.h
cfe/trunk/lib/Sema/SemaExprObjC.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=113968&r1=113967&r2=113968&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Sep 15 09:51:05 2010
@@ -2302,6 +2302,8 @@
"'super' is only valid in a method body">;
def err_invalid_receiver_class_message : Error<
"receiver type %0 is not an Objective-C class">;
+def err_missing_open_square_message_send : Error<
+ "missing '[' at start of message send expression">;
def warn_bad_receiver_type : Warning<
"receiver type %0 is not 'id' or interface pointer, consider "
"casting it to 'id'">;
Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=113968&r1=113967&r2=113968&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Wed Sep 15 09:51:05 2010
@@ -34,7 +34,8 @@
class Parser;
class PragmaUnusedHandler;
class ColonProtectionRAIIObject;
-
+ class InMessageExpressionRAIIObject;
+
/// PrettyStackTraceParserEntry - If a crash happens while the parser is active,
/// an entry is printed for it.
class PrettyStackTraceParserEntry : public llvm::PrettyStackTraceEntry {
@@ -75,6 +76,7 @@
class Parser : public CodeCompletionHandler {
friend class PragmaUnusedHandler;
friend class ColonProtectionRAIIObject;
+ friend class InMessageExpressionRAIIObject;
friend class ParenBraceBracketBalancer;
PrettyStackTraceParserEntry CrashInfo;
@@ -131,6 +133,13 @@
/// ColonProtectionRAIIObject RAII object.
bool ColonIsSacred;
+ /// \brief When true, we are directly inside an Ojective-C messsage
+ /// send expression.
+ ///
+ /// This is managed by the \c InMessageExpressionRAIIObject class, and
+ /// should not be set directly.
+ bool InMessageExpression;
+
/// The "depth" of the template parameters currently being parsed.
unsigned TemplateParameterDepth;
Modified: cfe/trunk/lib/Parse/ParseExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=113968&r1=113967&r2=113968&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExpr.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExpr.cpp Wed Sep 15 09:51:05 2010
@@ -576,9 +576,10 @@
SourceLocation RParenLoc;
{
- // The inside of the parens don't need to be a colon protected scope.
+ // The inside of the parens don't need to be a colon protected scope, and
+ // isn't immediately a message send.
ColonProtectionRAIIObject X(*this, false);
-
+
Res = ParseParenExpression(ParenExprType, false/*stopIfCastExr*/,
TypeOfCast, CastTy, RParenLoc);
if (Res.isInvalid())
@@ -978,6 +979,19 @@
SourceLocation Loc;
while (1) {
switch (Tok.getKind()) {
+ case tok::identifier:
+ // If we see identifier: after an expression, and we're not already in a
+ // message send, then this is probably a message send with a missing
+ // opening bracket '['.
+ if (getLang().ObjC1 && !InMessageExpression &&
+ NextToken().is(tok::colon)) {
+ LHS = ParseObjCMessageExpressionBody(SourceLocation(), SourceLocation(),
+ ParsedType(), LHS.get());
+ break;
+ }
+
+ // Fall through; this isn't a message send.
+
default: // Not a postfix-expression suffix.
return move(LHS);
case tok::l_square: { // postfix-expression: p-e '[' expression ']'
@@ -1008,6 +1022,8 @@
}
case tok::l_paren: { // p-e: p-e '(' argument-expression-list[opt] ')'
+ InMessageExpressionRAIIObject InMessage(*this, false);
+
ExprVector ArgExprs(Actions);
CommaLocsTy CommaLocs;
@@ -1483,8 +1499,13 @@
return ParseCXXAmbiguousParenExpression(ExprType, CastTy,
OpenLoc, RParenLoc);
- TypeResult Ty = ParseTypeName();
-
+ TypeResult Ty;
+
+ {
+ InMessageExpressionRAIIObject InMessage(*this, false);
+ Ty = ParseTypeName();
+ }
+
// Match the ')'.
if (Tok.is(tok::r_paren))
RParenLoc = ConsumeParen();
@@ -1532,6 +1553,8 @@
return ExprError();
} else if (TypeOfCast) {
// Parse the expression-list.
+ InMessageExpressionRAIIObject InMessage(*this, false);
+
ExprVector ArgExprs(Actions);
CommaLocsTy CommaLocs;
@@ -1541,6 +1564,8 @@
move_arg(ArgExprs), TypeOfCast);
}
} else {
+ InMessageExpressionRAIIObject InMessage(*this, false);
+
Result = ParseExpression();
ExprType = SimpleExpr;
if (!Result.isInvalid() && Tok.is(tok::r_paren))
Modified: cfe/trunk/lib/Parse/ParseInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseInit.cpp?rev=113968&r1=113967&r2=113968&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseInit.cpp (original)
+++ cfe/trunk/lib/Parse/ParseInit.cpp Wed Sep 15 09:51:05 2010
@@ -13,6 +13,7 @@
#include "clang/Parse/Parser.h"
#include "clang/Parse/ParseDiagnostic.h"
+#include "RAIIObjectsForParser.h"
#include "clang/Sema/Designator.h"
#include "clang/Sema/Scope.h"
#include "llvm/ADT/SmallString.h"
@@ -136,6 +137,8 @@
// [foo ... bar] -> array designator
// [4][foo bar] -> obsolete GNU designation with objc message send.
//
+ InMessageExpressionRAIIObject InMessage(*this, true);
+
SourceLocation StartLoc = ConsumeBracket();
ExprResult Idx;
@@ -146,7 +149,8 @@
if (getLang().ObjC1 && getLang().CPlusPlus) {
// Send to 'super'.
if (Tok.is(tok::identifier) && Tok.getIdentifierInfo() == Ident_super &&
- NextToken().isNot(tok::period) && getCurScope()->isInObjcMethodScope()) {
+ NextToken().isNot(tok::period) &&
+ getCurScope()->isInObjcMethodScope()) {
CheckArrayDesignatorSyntax(*this, StartLoc, Desig);
return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
ConsumeToken(),
@@ -310,6 +314,8 @@
/// initializer-list ',' designation[opt] initializer
///
ExprResult Parser::ParseBraceInitializer() {
+ InMessageExpressionRAIIObject InMessage(*this, false);
+
SourceLocation LBraceLoc = ConsumeBrace();
/// InitExprs - This is the actual list of expressions contained in the
Modified: cfe/trunk/lib/Parse/ParseObjc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseObjc.cpp?rev=113968&r1=113967&r2=113968&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseObjc.cpp (original)
+++ cfe/trunk/lib/Parse/ParseObjc.cpp Wed Sep 15 09:51:05 2010
@@ -13,6 +13,7 @@
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
+#include "RAIIObjectsForParser.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/PrettyDeclStackTrace.h"
#include "clang/Sema/Scope.h"
@@ -1785,6 +1786,8 @@
/// simple-type-specifier
/// typename-specifier
bool Parser::ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr) {
+ InMessageExpressionRAIIObject InMessage(*this, true);
+
if (Tok.is(tok::identifier) || Tok.is(tok::coloncolon) ||
Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope))
TryAnnotateTypeOrScopeToken();
@@ -1879,6 +1882,8 @@
return ExprError();
}
+ InMessageExpressionRAIIObject InMessage(*this, true);
+
if (getLang().CPlusPlus) {
// We completely separate the C and C++ cases because C++ requires
// more complicated (read: slower) parsing.
@@ -1992,6 +1997,8 @@
SourceLocation SuperLoc,
ParsedType ReceiverType,
ExprArg ReceiverExpr) {
+ InMessageExpressionRAIIObject InMessage(*this, true);
+
if (Tok.is(tok::code_completion)) {
if (SuperLoc.isValid())
Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc, 0, 0);
Modified: cfe/trunk/lib/Parse/ParseStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseStmt.cpp?rev=113968&r1=113967&r2=113968&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseStmt.cpp (original)
+++ cfe/trunk/lib/Parse/ParseStmt.cpp Wed Sep 15 09:51:05 2010
@@ -460,7 +460,8 @@
PrettyStackTraceLoc CrashInfo(PP.getSourceManager(),
Tok.getLocation(),
"in compound statement ('{}')");
-
+ InMessageExpressionRAIIObject InMessage(*this, false);
+
SourceLocation LBraceLoc = ConsumeBrace(); // eat the '{'.
// TODO: "__label__ X, Y, Z;" is the GNU "Local Label" extension. These are
Modified: cfe/trunk/lib/Parse/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/Parser.cpp?rev=113968&r1=113967&r2=113968&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/Parser.cpp (original)
+++ cfe/trunk/lib/Parse/Parser.cpp Wed Sep 15 09:51:05 2010
@@ -23,8 +23,8 @@
Parser::Parser(Preprocessor &pp, Sema &actions)
: CrashInfo(*this), PP(pp), Actions(actions), Diags(PP.getDiagnostics()),
- GreaterThanIsOperator(true), ColonIsSacred(false),
- TemplateParameterDepth(0) {
+ GreaterThanIsOperator(true), ColonIsSacred(false),
+ InMessageExpression(false), TemplateParameterDepth(0) {
Tok.setKind(tok::eof);
Actions.CurScope = 0;
NumCachedScopes = 0;
Modified: cfe/trunk/lib/Parse/RAIIObjectsForParser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/RAIIObjectsForParser.h?rev=113968&r1=113967&r2=113968&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/RAIIObjectsForParser.h (original)
+++ cfe/trunk/lib/Parse/RAIIObjectsForParser.h Wed Sep 15 09:51:05 2010
@@ -80,6 +80,22 @@
}
};
+ class InMessageExpressionRAIIObject {
+ bool &InMessageExpression;
+ bool OldValue;
+
+ public:
+ InMessageExpressionRAIIObject(Parser &P, bool Value)
+ : InMessageExpression(P.InMessageExpression),
+ OldValue(P.InMessageExpression) {
+ InMessageExpression = Value;
+ }
+
+ ~InMessageExpressionRAIIObject() {
+ InMessageExpression = OldValue;
+ }
+ };
+
/// \brief RAII object that makes sure paren/bracket/brace count is correct
/// after declaration/statement parsing, even when there's a parsing error.
class ParenBraceBracketBalancer {
Modified: cfe/trunk/lib/Sema/SemaExprObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprObjC.cpp?rev=113968&r1=113967&r2=113968&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprObjC.cpp Wed Sep 15 09:51:05 2010
@@ -626,12 +626,12 @@
}
ExprResult Sema::ActOnSuperMessage(Scope *S,
- SourceLocation SuperLoc,
- Selector Sel,
- SourceLocation LBracLoc,
- SourceLocation SelectorLoc,
- SourceLocation RBracLoc,
- MultiExprArg Args) {
+ SourceLocation SuperLoc,
+ Selector Sel,
+ SourceLocation LBracLoc,
+ SourceLocation SelectorLoc,
+ SourceLocation RBracLoc,
+ MultiExprArg Args) {
// Determine whether we are inside a method or not.
ObjCMethodDecl *Method = getCurMethodDecl();
if (!Method) {
@@ -702,13 +702,21 @@
///
/// \param Args The message arguments.
ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
- QualType ReceiverType,
- SourceLocation SuperLoc,
- Selector Sel,
- ObjCMethodDecl *Method,
- SourceLocation LBracLoc,
- SourceLocation RBracLoc,
- MultiExprArg ArgsIn) {
+ QualType ReceiverType,
+ SourceLocation SuperLoc,
+ Selector Sel,
+ ObjCMethodDecl *Method,
+ SourceLocation LBracLoc,
+ SourceLocation RBracLoc,
+ MultiExprArg ArgsIn) {
+ SourceLocation Loc = SuperLoc.isValid()? SuperLoc
+ : ReceiverTypeInfo->getTypeLoc().getLocalSourceRange().getBegin();
+ if (LBracLoc.isInvalid()) {
+ Diag(Loc, diag::err_missing_open_square_message_send)
+ << FixItHint::CreateInsertion(Loc, "[");
+ LBracLoc = Loc;
+ }
+
if (ReceiverType->isDependentType()) {
// If the receiver type is dependent, we can't type-check anything
// at this point. Build a dependent expression.
@@ -720,9 +728,6 @@
Args, NumArgs, RBracLoc));
}
- SourceLocation Loc = SuperLoc.isValid()? SuperLoc
- : ReceiverTypeInfo->getTypeLoc().getLocalSourceRange().getBegin();
-
// Find the class to which we are sending this message.
ObjCInterfaceDecl *Class = 0;
const ObjCObjectType *ClassType = ReceiverType->getAs<ObjCObjectType>();
@@ -837,6 +842,15 @@
SourceLocation LBracLoc,
SourceLocation RBracLoc,
MultiExprArg ArgsIn) {
+ // The location of the receiver.
+ SourceLocation Loc = SuperLoc.isValid()? SuperLoc : Receiver->getLocStart();
+
+ if (LBracLoc.isInvalid()) {
+ Diag(Loc, diag::err_missing_open_square_message_send)
+ << FixItHint::CreateInsertion(Loc, "[");
+ LBracLoc = Loc;
+ }
+
// If we have a receiver expression, perform appropriate promotions
// and determine receiver type.
if (Receiver) {
@@ -858,9 +872,6 @@
ReceiverType = Receiver->getType();
}
- // The location of the receiver.
- SourceLocation Loc = SuperLoc.isValid()? SuperLoc : Receiver->getLocStart();
-
if (!Method) {
// Handle messages to id.
bool receiverIsId = ReceiverType->isObjCIdType();
Added: cfe/trunk/test/FixIt/fixit-objc-message.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/FixIt/fixit-objc-message.m?rev=113968&view=auto
==============================================================================
--- cfe/trunk/test/FixIt/fixit-objc-message.m (added)
+++ cfe/trunk/test/FixIt/fixit-objc-message.m Wed Sep 15 09:51:05 2010
@@ -0,0 +1,19 @@
+// Objective-C recovery
+// RUN: cp %s %t
+// RUN: %clang_cc1 -pedantic -Wall -fixit -x objective-c %t || true
+// RUN: %clang_cc1 -fsyntax-only -pedantic -Wall -Werror -x objective-c %t
+
+// Objective-C++ recovery
+// RUN: cp %s %t
+// RUN: %clang_cc1 -pedantic -Wall -fixit -x objective-c++ %t || true
+// RUN: %clang_cc1 -fsyntax-only -pedantic -Wall -Werror -x objective-c++ %t
+
+ at interface A
+- (int)method1:(int)x second:(float)y;
++ (int)method2:(int)x second:(double)y;
+ at end
+
+void f(A *a, int i, int j) {
+ a method1:5+2 second:+(3.14159)];
+ a method1:[a method1:3 second:j] second:i++]
+}
More information about the cfe-commits
mailing list