[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