Browse Source

[Format/ObjC] Fix [foo bar]->baz formatting as lambda arrow

Summary:
Currently, `UnwrappedLineParser` thinks an arrow token after
an ObjC method expression is a C++ lambda arrow, so it formats:

```
[foo bar]->baz
```

as:

```
[foo bar] -> baz
```

Because `UnwrappedLineParser` runs before `TokenAnnotator`, it can't
know if the arrow token is after an ObjC method expression or not.

This diff makes `TokenAnnotator` remove the TT_LambdaArrow on
the arrow token if it follows an ObjC method expression.

Test Plan: New test added. Ran test with:
  % ninja FormatTests && ./tools/clang/unittests/Format/FormatTests
  Confirmed test failed before diff and passed after diff.

Reviewers: krasimir, djasper, sammccall

Reviewed By: sammccall

Subscribers: cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D57923

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@353531 91177308-0d34-0410-b5e6-96231b3b80d8
Ben Hamilton 6 years ago
parent
commit
7d86cb1e24

+ 4 - 0
lib/Format/TokenAnnotator.cpp

@@ -520,6 +520,10 @@ private:
           if (Parent && Parent->is(TT_PointerOrReference))
           if (Parent && Parent->is(TT_PointerOrReference))
             Parent->Type = TT_BinaryOperator;
             Parent->Type = TT_BinaryOperator;
         }
         }
+        // An arrow after an ObjC method expression is not a lambda arrow.
+        if (CurrentToken->Type == TT_ObjCMethodExpr && CurrentToken->Next &&
+            CurrentToken->Next->is(TT_LambdaArrow))
+          CurrentToken->Next->Type = TT_Unknown;
         Left->MatchingParen = CurrentToken;
         Left->MatchingParen = CurrentToken;
         CurrentToken->MatchingParen = Left;
         CurrentToken->MatchingParen = Left;
         // FirstObjCSelectorName is set when a colon is found. This does
         // FirstObjCSelectorName is set when a colon is found. This does

+ 3 - 0
lib/Format/UnwrappedLineParser.cpp

@@ -1426,6 +1426,9 @@ bool UnwrappedLineParser::tryToParseLambda() {
       nextToken();
       nextToken();
       break;
       break;
     case tok::arrow:
     case tok::arrow:
+      // This might or might not actually be a lambda arrow (this could be an
+      // ObjC method invocation followed by a dereferencing arrow). We might
+      // reset this back to TT_Unknown in TokenAnnotator.
       FormatTok->Type = TT_LambdaArrow;
       FormatTok->Type = TT_LambdaArrow;
       nextToken();
       nextToken();
       break;
       break;

+ 1 - 0
unittests/Format/FormatTestObjC.cpp

@@ -611,6 +611,7 @@ TEST_F(FormatTestObjC, FormatObjCMethodDeclarations) {
 
 
 TEST_F(FormatTestObjC, FormatObjCMethodExpr) {
 TEST_F(FormatTestObjC, FormatObjCMethodExpr) {
   verifyFormat("[foo bar:baz];");
   verifyFormat("[foo bar:baz];");
+  verifyFormat("[foo bar]->baz;");
   verifyFormat("return [foo bar:baz];");
   verifyFormat("return [foo bar:baz];");
   verifyFormat("return (a)[foo bar:baz];");
   verifyFormat("return (a)[foo bar:baz];");
   verifyFormat("f([foo bar:baz]);");
   verifyFormat("f([foo bar:baz]);");