[cfe-commits] r172304 - in /cfe/trunk: lib/Format/Format.cpp unittests/Format/FormatTest.cpp

Nico Weber nicolasweber at gmx.de
Fri Jan 11 22:18:41 PST 2013


Author: nico
Date: Sat Jan 12 00:18:40 2013
New Revision: 172304

URL: http://llvm.org/viewvc/llvm-project?rev=172304&view=rev
Log:
Formatter: Initial support for formatting Objective-C method expressions.        
                                                                                 
This follows the approach suggested by djasper in PR14911: When a '[' is         
seen that's at the start of a line, follows a binary operator, or follows one    
of : [ ( return throw, that '[' and its closing ']' are marked as
TT_ObjCMethodExpr and every ':' in that range that isn't part of a ternary
?: is marked as TT_ObjCMethodExpr as well.

Update the layout routines to not output spaces around ':' tokens that are
marked TT_ObjCMethodExpr, and only allow breaking after such tokens, not
before.

Before:
    [self adjustButton : closeButton_ ofKind : NSWindowCloseButton];

Now:
    [self adjustButton:closeButton_ ofKind:NSWindowCloseButton];


Modified:
    cfe/trunk/lib/Format/Format.cpp
    cfe/trunk/unittests/Format/FormatTest.cpp

Modified: cfe/trunk/lib/Format/Format.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/Format.cpp?rev=172304&r1=172303&r2=172304&view=diff
==============================================================================
--- cfe/trunk/lib/Format/Format.cpp (original)
+++ cfe/trunk/lib/Format/Format.cpp Sat Jan 12 00:18:40 2013
@@ -39,6 +39,7 @@
   TT_ObjCBlockLParen,
   TT_ObjCDecl,
   TT_ObjCMethodSpecifier,
+  TT_ObjCMethodExpr,
   TT_ObjCSelectorStart,
   TT_ObjCProperty,
   TT_OverloadedOperator,
@@ -613,7 +614,8 @@
   class AnnotatingParser {
   public:
     AnnotatingParser(AnnotatedToken &RootToken)
-        : CurrentToken(&RootToken), KeywordVirtualFound(false) {}
+        : CurrentToken(&RootToken), KeywordVirtualFound(false),
+          ColonIsObjCMethodExpr(false) {}
 
     bool parseAngle() {
       while (CurrentToken != NULL) {
@@ -651,8 +653,34 @@
     }
 
     bool parseSquare() {
+      if (!CurrentToken)
+        return false;
+
+      // A '[' could be an index subscript (after an indentifier or after
+      // ')' or ']'), or it could be the start of an Objective-C method
+      // expression.
+      AnnotatedToken *LSquare = CurrentToken->Parent;
+      bool StartsObjCMethodExpr =
+          !LSquare->Parent || LSquare->Parent->is(tok::colon) ||
+          LSquare->Parent->is(tok::l_square) ||
+          LSquare->Parent->is(tok::l_paren) ||
+          LSquare->Parent->is(tok::kw_return) ||
+          LSquare->Parent->is(tok::kw_throw) ||
+          getBinOpPrecedence(LSquare->Parent->FormatTok.Tok.getKind(),
+                             true, true) > prec::Unknown;
+
+      bool ColonWasObjCMethodExpr = ColonIsObjCMethodExpr;
+      if (StartsObjCMethodExpr) {
+        ColonIsObjCMethodExpr = true;
+        LSquare->Type = TT_ObjCMethodExpr;
+      }
+
       while (CurrentToken != NULL) {
         if (CurrentToken->is(tok::r_square)) {
+          if (StartsObjCMethodExpr) {
+            ColonIsObjCMethodExpr = ColonWasObjCMethodExpr;
+            CurrentToken->Type = TT_ObjCMethodExpr;
+          }
           next();
           return true;
         }
@@ -716,6 +744,11 @@
         if (Tok->Parent == NULL)
           Tok->Type = TT_ObjCMethodSpecifier;
         break;
+      case tok::colon:
+        // Colons from ?: are handled in parseConditional().
+        if (ColonIsObjCMethodExpr)
+          Tok->Type = TT_ObjCMethodExpr;
+        break;
       case tok::l_paren: {
         bool ParensWereObjCReturnType =
             Tok->Parent && Tok->Parent->Type == TT_ObjCMethodSpecifier;
@@ -841,6 +874,7 @@
   private:
     AnnotatedToken *CurrentToken;
     bool KeywordVirtualFound;
+    bool ColonIsObjCMethodExpr;
   };
 
   void createAnnotatedTokens(AnnotatedToken &Current) {
@@ -1048,8 +1082,9 @@
              Style.PointerAndReferenceBindToType;
     if (Right.is(tok::star) && Left.is(tok::l_paren))
       return false;
-    if (Left.is(tok::l_square) || Right.is(tok::l_square) ||
-        Right.is(tok::r_square))
+    if (Left.is(tok::l_square) || Right.is(tok::r_square))
+      return false;
+    if (Right.is(tok::l_square) && Right.Type != TT_ObjCMethodExpr)
       return false;
     if (Left.is(tok::coloncolon) ||
         (Right.is(tok::coloncolon) &&
@@ -1057,8 +1092,10 @@
       return false;
     if (Left.is(tok::period) || Right.is(tok::period))
       return false;
-    if (Left.is(tok::colon) || Right.is(tok::colon))
-      return true;
+    if (Left.is(tok::colon))
+      return Left.Type != TT_ObjCMethodExpr;
+    if (Right.is(tok::colon))
+      return Right.Type != TT_ObjCMethodExpr;
     if (Left.is(tok::l_paren))
       return false;
     if (Right.is(tok::l_paren)) {
@@ -1106,7 +1143,8 @@
     if (Tok.Parent->Type == TT_OverloadedOperator)
       return false;
     if (Tok.is(tok::colon))
-      return RootToken.isNot(tok::kw_case) && (!Tok.Children.empty());
+      return RootToken.isNot(tok::kw_case) && !Tok.Children.empty() &&
+             Tok.Type != TT_ObjCMethodExpr;
     if (Tok.Parent->Type == TT_UnaryOperator ||
         Tok.Parent->Type == TT_CastRParen)
       return false;
@@ -1148,6 +1186,10 @@
         // Don't break at ':' if identifier before it can beak.
         return false;
     }
+    if (Right.is(tok::colon) && Right.Type == TT_ObjCMethodExpr)
+      return false;
+    if (Left.is(tok::colon) && Left.Type == TT_ObjCMethodExpr)
+      return true;
     if (Left.ClosesTemplateDeclaration)
       return true;
     if (Left.Type == TT_PointerOrReference || Left.Type == TT_TemplateCloser ||

Modified: cfe/trunk/unittests/Format/FormatTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTest.cpp?rev=172304&r1=172303&r2=172304&view=diff
==============================================================================
--- cfe/trunk/unittests/Format/FormatTest.cpp (original)
+++ cfe/trunk/unittests/Format/FormatTest.cpp Sat Jan 12 00:18:40 2013
@@ -1468,6 +1468,67 @@
                "@end\n");
 }
 
+TEST_F(FormatTest, FormatObjCMethodExpr) {
+  verifyFormat("[foo bar:baz];");
+  verifyFormat("return [foo bar:baz];");
+  verifyFormat("f([foo bar:baz]);");
+  verifyFormat("f(2, [foo bar:baz]);");
+  verifyFormat("f(2, a ? b : c);");
+  verifyFormat("[[self initWithInt:4] bar:[baz quux:arrrr]];");
+
+  verifyFormat("[foo bar:baz], [foo bar:baz];");
+  verifyFormat("[foo bar:baz] = [foo bar:baz];");
+  verifyFormat("[foo bar:baz] *= [foo bar:baz];");
+  verifyFormat("[foo bar:baz] /= [foo bar:baz];");
+  verifyFormat("[foo bar:baz] %= [foo bar:baz];");
+  verifyFormat("[foo bar:baz] += [foo bar:baz];");
+  verifyFormat("[foo bar:baz] -= [foo bar:baz];");
+  verifyFormat("[foo bar:baz] <<= [foo bar:baz];");
+  verifyFormat("[foo bar:baz] >>= [foo bar:baz];");
+  verifyFormat("[foo bar:baz] &= [foo bar:baz];");
+  verifyFormat("[foo bar:baz] ^= [foo bar:baz];");
+  verifyFormat("[foo bar:baz] |= [foo bar:baz];");
+  verifyFormat("[foo bar:baz] ? [foo bar:baz] : [foo bar:baz];");
+  verifyFormat("[foo bar:baz] || [foo bar:baz];");
+  verifyFormat("[foo bar:baz] && [foo bar:baz];");
+  verifyFormat("[foo bar:baz] | [foo bar:baz];");
+  verifyFormat("[foo bar:baz] ^ [foo bar:baz];");
+  verifyFormat("[foo bar:baz] & [foo bar:baz];");
+  verifyFormat("[foo bar:baz] == [foo bar:baz];");
+  verifyFormat("[foo bar:baz] != [foo bar:baz];");
+  verifyFormat("[foo bar:baz] >= [foo bar:baz];");
+  verifyFormat("[foo bar:baz] <= [foo bar:baz];");
+  verifyFormat("[foo bar:baz] > [foo bar:baz];");
+  verifyFormat("[foo bar:baz] < [foo bar:baz];");
+  verifyFormat("[foo bar:baz] >> [foo bar:baz];");
+  verifyFormat("[foo bar:baz] << [foo bar:baz];");
+  verifyFormat("[foo bar:baz] - [foo bar:baz];");
+  verifyFormat("[foo bar:baz] + [foo bar:baz];");
+  verifyFormat("[foo bar:baz] * [foo bar:baz];");
+  verifyFormat("[foo bar:baz] / [foo bar:baz];");
+  verifyFormat("[foo bar:baz] % [foo bar:baz];");
+  // Whew!
+
+  verifyFormat("[self stuffWithInt:(4 + 2) float:4.5];");
+  verifyFormat("[self stuffWithInt:a ? b : c float:4.5];");
+  verifyFormat("[self stuffWithInt:a ? [self foo:bar] : c];");
+  verifyFormat("[self stuffWithInt:a ? (e ? f : g) : c];");
+  verifyFormat("[cond ? obj1 : obj2 methodWithParam:param]");
+  
+
+  verifyFormat("arr[[self indexForFoo:a]];");
+  verifyFormat("throw [self errorFor:a];");
+  verifyFormat("@throw [self errorFor:a];");
+
+  // The formatting of this isn't ideal yet. It tests that the formatter doesn't
+  // break after "backing" but before ":", which would be at 80 columns.
+  verifyFormat(
+      "void f() {\n"
+      "  if ((self = [super initWithContentRect:contentRect styleMask:\n"
+      "                  styleMask backing:NSBackingStoreBuffered defer:YES]))");
+  
+}
+
 TEST_F(FormatTest, ObjCAt) {
   verifyFormat("@autoreleasepool");
   verifyFormat("@catch");





More information about the cfe-commits mailing list