r326815 - [clang-format] Improve detection of ObjC for-in statements
Ben Hamilton via cfe-commits
cfe-commits at lists.llvm.org
Tue Mar 6 09:21:42 PST 2018
Author: benhamilton
Date: Tue Mar 6 09:21:42 2018
New Revision: 326815
URL: http://llvm.org/viewvc/llvm-project?rev=326815&view=rev
Log:
[clang-format] Improve detection of ObjC for-in statements
Summary:
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
Reviewers: krasimir, jolesiak
Reviewed By: jolesiak
Subscribers: djasper, cfe-commits, klimek
Differential Revision: https://reviews.llvm.org/D43904
Modified:
cfe/trunk/lib/Format/TokenAnnotator.cpp
cfe/trunk/unittests/Format/FormatTest.cpp
cfe/trunk/unittests/Format/FormatTestObjC.cpp
Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=326815&r1=326814&r2=326815&view=diff
==============================================================================
--- cfe/trunk/lib/Format/TokenAnnotator.cpp (original)
+++ cfe/trunk/lib/Format/TokenAnnotator.cpp Tue Mar 6 09:21:42 2018
@@ -216,6 +216,7 @@ private:
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 @@ private:
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))
Modified: cfe/trunk/unittests/Format/FormatTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTest.cpp?rev=326815&r1=326814&r2=326815&view=diff
==============================================================================
--- cfe/trunk/unittests/Format/FormatTest.cpp (original)
+++ cfe/trunk/unittests/Format/FormatTest.cpp Tue Mar 6 09:21:42 2018
@@ -742,6 +742,12 @@ TEST_F(FormatTest, FormatsForLoop) {
" aaaaaaaaaaaaaaaaaaaaaaaaaaa != bbbbbbbbbbbbbbbbbbbbbbb;\n"
" ++aaaaaaaaaaaaaaaaaaaaaaaaaaa) {");
+ // 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<Bar> &baz = in.value(); !baz.at_end(); ++baz) {\n}");
+
FormatStyle NoBinPacking = getLLVMStyle();
NoBinPacking.BinPackParameters = false;
verifyFormat("for (int aaaaaaaaaaa = 1;\n"
@@ -12082,6 +12088,31 @@ TEST_F(FormatTest, FileAndCode) {
EXPECT_EQ(FormatStyle::LK_ObjC, guessLanguage("foo", "@interface Foo\n at 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<Bar>& baz = in.value(); !baz.at_end(); ++baz) {}"));
+}
+
} // end namespace
} // end namespace format
} // end namespace clang
Modified: cfe/trunk/unittests/Format/FormatTestObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestObjC.cpp?rev=326815&r1=326814&r2=326815&view=diff
==============================================================================
--- cfe/trunk/unittests/Format/FormatTestObjC.cpp (original)
+++ cfe/trunk/unittests/Format/FormatTestObjC.cpp Tue Mar 6 09:21:42 2018
@@ -893,6 +893,13 @@ TEST_F(FormatTestObjC, ObjCForIn) {
" 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) {
More information about the cfe-commits
mailing list