[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 llvm-svn: 326815
This commit is contained in:
parent
6cd91f1d44
commit
1d6c6ee1cf
|
@ -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))
|
||||
|
|
|
@ -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@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
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue