[PATCH] D43904: [clang-format] Improve detection of ObjC for-in statements

2018-03-06 Thread Ben Hamilton via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL326815: [clang-format] Improve detection of ObjC for-in 
statements (authored by benhamilton, committed by ).
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D43904?vs=137199&id=137218#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D43904

Files:
  cfe/trunk/lib/Format/TokenAnnotator.cpp
  cfe/trunk/unittests/Format/FormatTest.cpp
  cfe/trunk/unittests/Format/FormatTestObjC.cpp


Index: cfe/trunk/lib/Format/TokenAnnotator.cpp
===
--- cfe/trunk/lib/Format/TokenAnnotator.cpp
+++ cfe/trunk/lib/Format/TokenAnnotator.cpp
@@ -216,6 +216,7 @@
 bool HasMultipleParametersOnALine = false;
 bool MightBeObjCForRangeLoop =
 Left->Previous && Left->Previous->is(tok::kw_for);
+FormatToken *PossibleObjCForInToken = nullptr;
 while (CurrentToken) {
   // LookForDecls is set when "if (" has been seen. Check for
   // 'identifier' '*' 'identifier' followed by not '=' -- this
@@ -301,10 +302,17 @@
CurrentToken->Previous->isSimpleTypeSpecifier()) &&
   !CurrentToken->is(tok::l_brace))
 Contexts.back().IsExpression = false;
-  if (CurrentToken->isOneOf(tok::semi, tok::colon))
+  if (CurrentToken->isOneOf(tok::semi, tok::colon)) {
 MightBeObjCForRangeLoop = false;
-  if (MightBeObjCForRangeLoop && CurrentToken->is(Keywords.kw_in))
-CurrentToken->Type = TT_ObjCForIn;
+if (PossibleObjCForInToken) {
+  PossibleObjCForInToken->Type = TT_Unknown;
+  PossibleObjCForInToken = nullptr;
+}
+  }
+  if (MightBeObjCForRangeLoop && CurrentToken->is(Keywords.kw_in)) {
+PossibleObjCForInToken = CurrentToken;
+PossibleObjCForInToken->Type = TT_ObjCForIn;
+  }
   // When we discover a 'new', we set CanBeExpression to 'false' in order 
to
   // parse the type correctly. Reset that after a comma.
   if (CurrentToken->is(tok::comma))
Index: cfe/trunk/unittests/Format/FormatTest.cpp
===
--- cfe/trunk/unittests/Format/FormatTest.cpp
+++ cfe/trunk/unittests/Format/FormatTest.cpp
@@ -742,6 +742,12 @@
" aaa != bbb;\n"
" ++aaa) {");
 
+  // These should not be formatted as Objective-C for-in loops.
+  verifyFormat("for (Foo *x = 0; x != in; x++) {\n}");
+  verifyFormat("Foo *x;\nfor (x = 0; x != in; x++) {\n}");
+  verifyFormat("Foo *x;\nfor (x in y) {\n}");
+  verifyFormat("for (const Foo &baz = in.value(); !baz.at_end(); ++baz) 
{\n}");
+
   FormatStyle NoBinPacking = getLLVMStyle();
   NoBinPacking.BinPackParameters = false;
   verifyFormat("for (int aaa = 1;\n"
@@ -12082,6 +12088,31 @@
   EXPECT_EQ(FormatStyle::LK_ObjC, guessLanguage("foo", "@interface 
Foo\n@end\n"));
 }
 
+TEST_F(FormatTest, GuessLanguageWithForIn) {
+  EXPECT_EQ(FormatStyle::LK_Cpp,
+guessLanguage("foo.h", "for (Foo *x = 0; x != in; x++) {}"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "for (Foo *x in bar) {}"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "for (Foo *x in [bar baz]) {}"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "for (Foo *x in [bar baz:blech]) {}"));
+  EXPECT_EQ(
+  FormatStyle::LK_ObjC,
+  guessLanguage("foo.h", "for (Foo *x in [bar baz:blech, 1, 2, 3, 0]) 
{}"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "for (Foo *x in [bar baz:^{[uh oh];}]) 
{}"));
+  EXPECT_EQ(FormatStyle::LK_Cpp,
+guessLanguage("foo.h", "Foo *x; for (x = 0; x != in; x++) {}"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "Foo *x; for (x in y) {}"));
+  EXPECT_EQ(
+  FormatStyle::LK_Cpp,
+  guessLanguage(
+  "foo.h",
+  "for (const Foo& baz = in.value(); !baz.at_end(); ++baz) {}"));
+}
+
 } // end namespace
 } // end namespace format
 } // end namespace clang
Index: cfe/trunk/unittests/Format/FormatTestObjC.cpp
===
--- cfe/trunk/unittests/Format/FormatTestObjC.cpp
+++ cfe/trunk/unittests/Format/FormatTestObjC.cpp
@@ -893,6 +893,13 @@
"foo(n);\n"
"  }\n"
"}");
+  verifyFormat("for (Foo *x in bar) {\n}");
+  verifyFormat("for (Foo *x in [bar baz]) {\n}");
+  verifyFormat("for (Foo *x in [bar baz:blech]) {\n}");
+  verifyFormat("for (Foo *x in [bar baz:blech, 1, 2, 3, 0]) {\n}");
+  verifyFormat("for (Foo *x in [bar baz:^{\n"
+   "   [uh oh];\n"
+   " }]) {\n}");
 }
 
 TEST_F(FormatTestObjC, ObjCLiterals) {


Index: cfe/trunk/lib/Format/TokenAnnotator.cpp

[PATCH] D43904: [clang-format] Improve detection of ObjC for-in statements

2018-03-06 Thread Ben Hamilton via Phabricator via cfe-commits
benhamilton added inline comments.



Comment at: unittests/Format/FormatTest.cpp:778
 
+TEST_F(FormatTest, ObjCForInLoop) {
+  verifyFormat("for (Foo *x = 0; x != in; x++) {\n}");

krasimir wrote:
> Please move the ObjC-specific instances to `FormatTestObjC.cpp`.
Done.


Repository:
  rC Clang

https://reviews.llvm.org/D43904



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D43904: [clang-format] Improve detection of ObjC for-in statements

2018-03-06 Thread Ben Hamilton via Phabricator via cfe-commits
benhamilton updated this revision to Diff 137199.
benhamilton marked an inline comment as done.
benhamilton added a comment.

- Move ObjC-specific tests to `FormatTestObjC.cpp`.


Repository:
  rC Clang

https://reviews.llvm.org/D43904

Files:
  lib/Format/TokenAnnotator.cpp
  unittests/Format/FormatTest.cpp
  unittests/Format/FormatTestObjC.cpp


Index: unittests/Format/FormatTestObjC.cpp
===
--- unittests/Format/FormatTestObjC.cpp
+++ unittests/Format/FormatTestObjC.cpp
@@ -893,6 +893,13 @@
"foo(n);\n"
"  }\n"
"}");
+  verifyFormat("for (Foo *x in bar) {\n}");
+  verifyFormat("for (Foo *x in [bar baz]) {\n}");
+  verifyFormat("for (Foo *x in [bar baz:blech]) {\n}");
+  verifyFormat("for (Foo *x in [bar baz:blech, 1, 2, 3, 0]) {\n}");
+  verifyFormat("for (Foo *x in [bar baz:^{\n"
+   "   [uh oh];\n"
+   " }]) {\n}");
 }
 
 TEST_F(FormatTestObjC, ObjCLiterals) {
Index: unittests/Format/FormatTest.cpp
===
--- unittests/Format/FormatTest.cpp
+++ unittests/Format/FormatTest.cpp
@@ -742,6 +742,12 @@
" aaa != bbb;\n"
" ++aaa) {");
 
+  // These should not be formatted as Objective-C for-in loops.
+  verifyFormat("for (Foo *x = 0; x != in; x++) {\n}");
+  verifyFormat("Foo *x;\nfor (x = 0; x != in; x++) {\n}");
+  verifyFormat("Foo *x;\nfor (x in y) {\n}");
+  verifyFormat("for (const Foo &baz = in.value(); !baz.at_end(); ++baz) 
{\n}");
+
   FormatStyle NoBinPacking = getLLVMStyle();
   NoBinPacking.BinPackParameters = false;
   verifyFormat("for (int aaa = 1;\n"
@@ -12120,6 +12126,31 @@
   EXPECT_EQ(FormatStyle::LK_Cpp, guessLanguage("foo.h", "[[foo::bar, ...]]"));
 }
 
+TEST_F(FormatTest, GuessLanguageWithForIn) {
+  EXPECT_EQ(FormatStyle::LK_Cpp,
+guessLanguage("foo.h", "for (Foo *x = 0; x != in; x++) {}"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "for (Foo *x in bar) {}"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "for (Foo *x in [bar baz]) {}"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "for (Foo *x in [bar baz:blech]) {}"));
+  EXPECT_EQ(
+  FormatStyle::LK_ObjC,
+  guessLanguage("foo.h", "for (Foo *x in [bar baz:blech, 1, 2, 3, 0]) 
{}"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "for (Foo *x in [bar baz:^{[uh oh];}]) 
{}"));
+  EXPECT_EQ(FormatStyle::LK_Cpp,
+guessLanguage("foo.h", "Foo *x; for (x = 0; x != in; x++) {}"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "Foo *x; for (x in y) {}"));
+  EXPECT_EQ(
+  FormatStyle::LK_Cpp,
+  guessLanguage(
+  "foo.h",
+  "for (const Foo& baz = in.value(); !baz.at_end(); ++baz) {}"));
+}
+
 } // end namespace
 } // end namespace format
 } // end namespace clang
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -216,6 +216,7 @@
 bool HasMultipleParametersOnALine = false;
 bool MightBeObjCForRangeLoop =
 Left->Previous && Left->Previous->is(tok::kw_for);
+FormatToken *PossibleObjCForInToken = nullptr;
 while (CurrentToken) {
   // LookForDecls is set when "if (" has been seen. Check for
   // 'identifier' '*' 'identifier' followed by not '=' -- this
@@ -301,10 +302,17 @@
CurrentToken->Previous->isSimpleTypeSpecifier()) &&
   !CurrentToken->is(tok::l_brace))
 Contexts.back().IsExpression = false;
-  if (CurrentToken->isOneOf(tok::semi, tok::colon))
+  if (CurrentToken->isOneOf(tok::semi, tok::colon)) {
 MightBeObjCForRangeLoop = false;
-  if (MightBeObjCForRangeLoop && CurrentToken->is(Keywords.kw_in))
-CurrentToken->Type = TT_ObjCForIn;
+if (PossibleObjCForInToken) {
+  PossibleObjCForInToken->Type = TT_Unknown;
+  PossibleObjCForInToken = nullptr;
+}
+  }
+  if (MightBeObjCForRangeLoop && CurrentToken->is(Keywords.kw_in)) {
+PossibleObjCForInToken = CurrentToken;
+PossibleObjCForInToken->Type = TT_ObjCForIn;
+  }
   // When we discover a 'new', we set CanBeExpression to 'false' in order 
to
   // parse the type correctly. Reset that after a comma.
   if (CurrentToken->is(tok::comma))


Index: unittests/Format/FormatTestObjC.cpp
===
--- unittests/Format/FormatTestObjC.cpp
+++ unittests/Format/FormatTestObjC.cpp
@@ -893,6 +893,13 @@
"foo(n);\n"
"  }\n"
"}");
+  verifyFormat("for (Foo *x in bar) {\n}");
+  verifyFormat("for (Foo *x in [bar baz]) {\

[PATCH] D43904: [clang-format] Improve detection of ObjC for-in statements

2018-03-06 Thread Krasimir Georgiev via Phabricator via cfe-commits
krasimir added inline comments.



Comment at: unittests/Format/FormatTest.cpp:778
 
+TEST_F(FormatTest, ObjCForInLoop) {
+  verifyFormat("for (Foo *x = 0; x != in; x++) {\n}");

Please move the ObjC-specific instances to `FormatTestObjC.cpp`.


Repository:
  rC Clang

https://reviews.llvm.org/D43904



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D43904: [clang-format] Improve detection of ObjC for-in statements

2018-03-05 Thread Ben Hamilton via Phabricator via cfe-commits
benhamilton added inline comments.



Comment at: lib/Format/TokenAnnotator.cpp:288
 
+if (MightBeObjCForRangeLoop) {
+  FormatToken *ForInToken = Left;

djasper wrote:
> There can be only one ObjCForIn token in any for loop, right? If that's the 
> case, can we just remember that in addition to (or instead of) 
> MightBeObjCForRangeLoop? That way, we wouldn't have to re-iterate over all 
> the tokens here, but could just set this directly.
Nice optimization, done.



Comment at: unittests/Format/FormatTest.cpp:12002
 
+TEST_F(FormatTest, GuessLanguageWithForIn) {
+  EXPECT_EQ(FormatStyle::LK_Cpp,

krasimir wrote:
> Please also add this instances as formatting tests.
Thanks, tests added.

The new formatting tests revealed a new regression I'd introduced: we were not 
inserting a space between keyword 'in' and the opening `[` of the ObjC message 
send.

This was because the ObjC message send parsing logic depended on the 
TT_ObjCForIn keyword being set before parsing the `[`, but by delaying setting 
the type until after parsing the for-loop was complete, we broke that logic.

Fixed regression and made sure tests passed.


Repository:
  rC Clang

https://reviews.llvm.org/D43904



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D43904: [clang-format] Improve detection of ObjC for-in statements

2018-03-05 Thread Ben Hamilton via Phabricator via cfe-commits
benhamilton updated this revision to Diff 137093.
benhamilton added a comment.

One more cleanup


Repository:
  rC Clang

https://reviews.llvm.org/D43904

Files:
  lib/Format/TokenAnnotator.cpp
  unittests/Format/FormatTest.cpp


Index: unittests/Format/FormatTest.cpp
===
--- unittests/Format/FormatTest.cpp
+++ unittests/Format/FormatTest.cpp
@@ -775,6 +775,20 @@
" .().a().a()) {\n}");
 }
 
+TEST_F(FormatTest, ObjCForInLoop) {
+  verifyFormat("for (Foo *x = 0; x != in; x++) {\n}");
+  verifyFormat("for (Foo *x in bar) {\n}");
+  verifyFormat("for (Foo *x in [bar baz]) {\n}");
+  verifyFormat("for (Foo *x in [bar baz:blech]) {\n}");
+  verifyFormat("for (Foo *x in [bar baz:blech, 1, 2, 3, 0]) {\n}");
+  verifyFormat("for (Foo *x in [bar baz:^{\n"
+   "   [uh oh];\n"
+   " }]) {\n}");
+  verifyFormat("Foo *x;\nfor (x = 0; x != in; x++) {\n}");
+  verifyFormat("Foo *x;\nfor (x in y) {\n}");
+  verifyFormat("for (const Foo &baz = in.value(); !baz.at_end(); ++baz) 
{\n}");
+}
+
 TEST_F(FormatTest, ForEachLoops) {
   verifyFormat("void f() {\n"
"  foreach (Item *item, itemlist) {}\n"
@@ -12120,6 +12134,31 @@
   EXPECT_EQ(FormatStyle::LK_Cpp, guessLanguage("foo.h", "[[foo::bar, ...]]"));
 }
 
+TEST_F(FormatTest, GuessLanguageWithForIn) {
+  EXPECT_EQ(FormatStyle::LK_Cpp,
+guessLanguage("foo.h", "for (Foo *x = 0; x != in; x++) {}"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "for (Foo *x in bar) {}"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "for (Foo *x in [bar baz]) {}"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "for (Foo *x in [bar baz:blech]) {}"));
+  EXPECT_EQ(
+  FormatStyle::LK_ObjC,
+  guessLanguage("foo.h", "for (Foo *x in [bar baz:blech, 1, 2, 3, 0]) 
{}"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "for (Foo *x in [bar baz:^{[uh oh];}]) 
{}"));
+  EXPECT_EQ(FormatStyle::LK_Cpp,
+guessLanguage("foo.h", "Foo *x; for (x = 0; x != in; x++) {}"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "Foo *x; for (x in y) {}"));
+  EXPECT_EQ(
+  FormatStyle::LK_Cpp,
+  guessLanguage(
+  "foo.h",
+  "for (const Foo& baz = in.value(); !baz.at_end(); ++baz) {}"));
+}
+
 } // end namespace
 } // end namespace format
 } // end namespace clang
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -216,6 +216,7 @@
 bool HasMultipleParametersOnALine = false;
 bool MightBeObjCForRangeLoop =
 Left->Previous && Left->Previous->is(tok::kw_for);
+FormatToken *PossibleObjCForInToken = nullptr;
 while (CurrentToken) {
   // LookForDecls is set when "if (" has been seen. Check for
   // 'identifier' '*' 'identifier' followed by not '=' -- this
@@ -301,10 +302,17 @@
CurrentToken->Previous->isSimpleTypeSpecifier()) &&
   !CurrentToken->is(tok::l_brace))
 Contexts.back().IsExpression = false;
-  if (CurrentToken->isOneOf(tok::semi, tok::colon))
+  if (CurrentToken->isOneOf(tok::semi, tok::colon)) {
 MightBeObjCForRangeLoop = false;
-  if (MightBeObjCForRangeLoop && CurrentToken->is(Keywords.kw_in))
-CurrentToken->Type = TT_ObjCForIn;
+if (PossibleObjCForInToken) {
+  PossibleObjCForInToken->Type = TT_Unknown;
+  PossibleObjCForInToken = nullptr;
+}
+  }
+  if (MightBeObjCForRangeLoop && CurrentToken->is(Keywords.kw_in)) {
+PossibleObjCForInToken = CurrentToken;
+PossibleObjCForInToken->Type = TT_ObjCForIn;
+  }
   // When we discover a 'new', we set CanBeExpression to 'false' in order 
to
   // parse the type correctly. Reset that after a comma.
   if (CurrentToken->is(tok::comma))


Index: unittests/Format/FormatTest.cpp
===
--- unittests/Format/FormatTest.cpp
+++ unittests/Format/FormatTest.cpp
@@ -775,6 +775,20 @@
" .().a().a()) {\n}");
 }
 
+TEST_F(FormatTest, ObjCForInLoop) {
+  verifyFormat("for (Foo *x = 0; x != in; x++) {\n}");
+  verifyFormat("for (Foo *x in bar) {\n}");
+  verifyFormat("for (Foo *x in [bar baz]) {\n}");
+  verifyFormat("for (Foo *x in [bar baz:blech]) {\n}");
+  verifyFormat("for (Foo *x in [bar baz:blech, 1, 2, 3, 0]) {\n}");
+  verifyFormat("for (Foo *x in [bar baz:^{\n"
+   "   [uh oh];\n"
+   " }]) {\n}");
+  verifyFormat("Foo *x;\nfor (x = 0; x != in; x++) {\n}");
+  verifyFormat("Foo *x;\nfor (x in y) {\n}");
+  verifyFormat("for (const Foo &baz = in.value(); !baz.at_end(); ++baz) {\n}");
+}
+
 TEST_F(FormatTest, ForEach

[PATCH] D43904: [clang-format] Improve detection of ObjC for-in statements

2018-03-05 Thread Ben Hamilton via Phabricator via cfe-commits
benhamilton updated this revision to Diff 137092.
benhamilton marked an inline comment as done.
benhamilton added a comment.

- Fix comments from @djasper and @krasimir.


Repository:
  rC Clang

https://reviews.llvm.org/D43904

Files:
  lib/Format/TokenAnnotator.cpp
  unittests/Format/FormatTest.cpp


Index: unittests/Format/FormatTest.cpp
===
--- unittests/Format/FormatTest.cpp
+++ unittests/Format/FormatTest.cpp
@@ -775,6 +775,20 @@
" .().a().a()) {\n}");
 }
 
+TEST_F(FormatTest, ObjCForInLoop) {
+  verifyFormat("for (Foo *x = 0; x != in; x++) {\n}");
+  verifyFormat("for (Foo *x in bar) {\n}");
+  verifyFormat("for (Foo *x in [bar baz]) {\n}");
+  verifyFormat("for (Foo *x in [bar baz:blech]) {\n}");
+  verifyFormat("for (Foo *x in [bar baz:blech, 1, 2, 3, 0]) {\n}");
+  verifyFormat("for (Foo *x in [bar baz:^{\n"
+   "   [uh oh];\n"
+   " }]) {\n}");
+  verifyFormat("Foo *x;\nfor (x = 0; x != in; x++) {\n}");
+  verifyFormat("Foo *x;\nfor (x in y) {\n}");
+  verifyFormat("for (const Foo &baz = in.value(); !baz.at_end(); ++baz) 
{\n}");
+}
+
 TEST_F(FormatTest, ForEachLoops) {
   verifyFormat("void f() {\n"
"  foreach (Item *item, itemlist) {}\n"
@@ -12120,6 +12134,31 @@
   EXPECT_EQ(FormatStyle::LK_Cpp, guessLanguage("foo.h", "[[foo::bar, ...]]"));
 }
 
+TEST_F(FormatTest, GuessLanguageWithForIn) {
+  EXPECT_EQ(FormatStyle::LK_Cpp,
+guessLanguage("foo.h", "for (Foo *x = 0; x != in; x++) {}"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "for (Foo *x in bar) {}"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "for (Foo *x in [bar baz]) {}"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "for (Foo *x in [bar baz:blech]) {}"));
+  EXPECT_EQ(
+  FormatStyle::LK_ObjC,
+  guessLanguage("foo.h", "for (Foo *x in [bar baz:blech, 1, 2, 3, 0]) 
{}"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "for (Foo *x in [bar baz:^{[uh oh];}]) 
{}"));
+  EXPECT_EQ(FormatStyle::LK_Cpp,
+guessLanguage("foo.h", "Foo *x; for (x = 0; x != in; x++) {}"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "Foo *x; for (x in y) {}"));
+  EXPECT_EQ(
+  FormatStyle::LK_Cpp,
+  guessLanguage(
+  "foo.h",
+  "for (const Foo& baz = in.value(); !baz.at_end(); ++baz) {}"));
+}
+
 } // end namespace
 } // end namespace format
 } // end namespace clang
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -216,6 +216,7 @@
 bool HasMultipleParametersOnALine = false;
 bool MightBeObjCForRangeLoop =
 Left->Previous && Left->Previous->is(tok::kw_for);
+FormatToken *PossibleObjCForInToken = nullptr;
 while (CurrentToken) {
   // LookForDecls is set when "if (" has been seen. Check for
   // 'identifier' '*' 'identifier' followed by not '=' -- this
@@ -301,10 +302,15 @@
CurrentToken->Previous->isSimpleTypeSpecifier()) &&
   !CurrentToken->is(tok::l_brace))
 Contexts.back().IsExpression = false;
-  if (CurrentToken->isOneOf(tok::semi, tok::colon))
+  if (CurrentToken->isOneOf(tok::semi, tok::colon)) {
 MightBeObjCForRangeLoop = false;
-  if (MightBeObjCForRangeLoop && CurrentToken->is(Keywords.kw_in))
-CurrentToken->Type = TT_ObjCForIn;
+if (PossibleObjCForInToken)
+  PossibleObjCForInToken->Type = TT_Unknown;
+  }
+  if (MightBeObjCForRangeLoop && CurrentToken->is(Keywords.kw_in)) {
+PossibleObjCForInToken = CurrentToken;
+PossibleObjCForInToken->Type = TT_ObjCForIn;
+  }
   // When we discover a 'new', we set CanBeExpression to 'false' in order 
to
   // parse the type correctly. Reset that after a comma.
   if (CurrentToken->is(tok::comma))


Index: unittests/Format/FormatTest.cpp
===
--- unittests/Format/FormatTest.cpp
+++ unittests/Format/FormatTest.cpp
@@ -775,6 +775,20 @@
" .().a().a()) {\n}");
 }
 
+TEST_F(FormatTest, ObjCForInLoop) {
+  verifyFormat("for (Foo *x = 0; x != in; x++) {\n}");
+  verifyFormat("for (Foo *x in bar) {\n}");
+  verifyFormat("for (Foo *x in [bar baz]) {\n}");
+  verifyFormat("for (Foo *x in [bar baz:blech]) {\n}");
+  verifyFormat("for (Foo *x in [bar baz:blech, 1, 2, 3, 0]) {\n}");
+  verifyFormat("for (Foo *x in [bar baz:^{\n"
+   "   [uh oh];\n"
+   " }]) {\n}");
+  verifyFormat("Foo *x;\nfor (x = 0; x != in; x++) {\n}");
+  verifyFormat("Foo *x;\nfor (x in y) {\n}");
+  verifyFormat("for (const Foo &baz = in.value(); !baz.at_end(); ++baz) {\n}");
+}
+
 TEST_F(Form

[PATCH] D43904: [clang-format] Improve detection of ObjC for-in statements

2018-03-05 Thread Krasimir Georgiev via Phabricator via cfe-commits
krasimir added inline comments.



Comment at: unittests/Format/FormatTest.cpp:12002
 
+TEST_F(FormatTest, GuessLanguageWithForIn) {
+  EXPECT_EQ(FormatStyle::LK_Cpp,

Please also add this instances as formatting tests.


Repository:
  rC Clang

https://reviews.llvm.org/D43904



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D43904: [clang-format] Improve detection of ObjC for-in statements

2018-03-05 Thread Daniel Jasper via Phabricator via cfe-commits
djasper added inline comments.



Comment at: lib/Format/TokenAnnotator.cpp:288
 
+if (MightBeObjCForRangeLoop) {
+  FormatToken *ForInToken = Left;

There can be only one ObjCForIn token in any for loop, right? If that's the 
case, can we just remember that in addition to (or instead of) 
MightBeObjCForRangeLoop? That way, we wouldn't have to re-iterate over all the 
tokens here, but could just set this directly.


Repository:
  rC Clang

https://reviews.llvm.org/D43904



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D43904: [clang-format] Improve detection of ObjC for-in statements

2018-02-28 Thread Ben Hamilton via Phabricator via cfe-commits
benhamilton created this revision.
benhamilton added reviewers: krasimir, jolesiak.
Herald added a subscriber: cfe-commits.

Previously, clang-format would detect the following as an
Objective-C for-in statement:

  for (int x = in.value(); ...) {}

because the logic only decided a for-loop was definitely *not*
an Objective-C for-in loop after it saw a semicolon or a colon.

To fix this, I delayed the decision of whether this was a for-in
statement until after we found the matching right-paren, at which
point we know if we've seen a semicolon or not.

Test Plan: New tests added. Ran tests with:

  make -j12 FormatTests && ./tools/clang/unittests/Format/FormatTests


Repository:
  rC Clang

https://reviews.llvm.org/D43904

Files:
  lib/Format/TokenAnnotator.cpp
  unittests/Format/FormatTest.cpp


Index: unittests/Format/FormatTest.cpp
===
--- unittests/Format/FormatTest.cpp
+++ unittests/Format/FormatTest.cpp
@@ -11999,6 +11999,31 @@
   EXPECT_EQ(FormatStyle::LK_Cpp, guessLanguage("foo.h", "[[foo::bar, ...]]"));
 }
 
+TEST_F(FormatTest, GuessLanguageWithForIn) {
+  EXPECT_EQ(FormatStyle::LK_Cpp,
+guessLanguage("foo.h", "for (Foo *x = 0; x != in; x++) {}"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "for (Foo *x in bar) {}"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "for (Foo *x in [bar baz]) {}"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "for (Foo *x in [bar baz:blech]) {}"));
+  EXPECT_EQ(
+  FormatStyle::LK_ObjC,
+  guessLanguage("foo.h", "for (Foo *x in [bar baz:blech, 1, 2, 3, 0]) 
{}"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "for (Foo *x in [bar baz:^{[uh oh];}]) 
{}"));
+  EXPECT_EQ(FormatStyle::LK_Cpp,
+guessLanguage("foo.h", "Foo *x; for (x = 0; x != in; x++) {}"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "Foo *x; for (x in y) {}"));
+  EXPECT_EQ(
+  FormatStyle::LK_Cpp,
+  guessLanguage(
+  "foo.h",
+  "for (const Foo& baz = in.value(); !baz.at_end(); ++baz) {}"));
+}
+
 } // end namespace
 } // end namespace format
 } // end namespace clang
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -285,6 +285,16 @@
 else
   Left->PackingKind = PPK_OnePerLine;
 
+if (MightBeObjCForRangeLoop) {
+  FormatToken *ForInToken = Left;
+  while (ForInToken && ForInToken != CurrentToken) {
+if (ForInToken->is(Keywords.kw_in)) {
+  ForInToken->Type = TT_ObjCForIn;
+  break;
+}
+ForInToken = ForInToken->Next;
+  }
+}
 next();
 return true;
   }
@@ -303,8 +313,6 @@
 Contexts.back().IsExpression = false;
   if (CurrentToken->isOneOf(tok::semi, tok::colon))
 MightBeObjCForRangeLoop = false;
-  if (MightBeObjCForRangeLoop && CurrentToken->is(Keywords.kw_in))
-CurrentToken->Type = TT_ObjCForIn;
   // When we discover a 'new', we set CanBeExpression to 'false' in order 
to
   // parse the type correctly. Reset that after a comma.
   if (CurrentToken->is(tok::comma))


Index: unittests/Format/FormatTest.cpp
===
--- unittests/Format/FormatTest.cpp
+++ unittests/Format/FormatTest.cpp
@@ -11999,6 +11999,31 @@
   EXPECT_EQ(FormatStyle::LK_Cpp, guessLanguage("foo.h", "[[foo::bar, ...]]"));
 }
 
+TEST_F(FormatTest, GuessLanguageWithForIn) {
+  EXPECT_EQ(FormatStyle::LK_Cpp,
+guessLanguage("foo.h", "for (Foo *x = 0; x != in; x++) {}"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "for (Foo *x in bar) {}"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "for (Foo *x in [bar baz]) {}"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "for (Foo *x in [bar baz:blech]) {}"));
+  EXPECT_EQ(
+  FormatStyle::LK_ObjC,
+  guessLanguage("foo.h", "for (Foo *x in [bar baz:blech, 1, 2, 3, 0]) {}"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "for (Foo *x in [bar baz:^{[uh oh];}]) {}"));
+  EXPECT_EQ(FormatStyle::LK_Cpp,
+guessLanguage("foo.h", "Foo *x; for (x = 0; x != in; x++) {}"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+guessLanguage("foo.h", "Foo *x; for (x in y) {}"));
+  EXPECT_EQ(
+  FormatStyle::LK_Cpp,
+  guessLanguage(
+  "foo.h",
+  "for (const Foo& baz = in.value(); !baz.at_end(); ++baz) {}"));
+}
+
 } // end namespace
 } // end namespace format
 } // end namespace clang
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotat