diff --git a/clang/lib/Format/FormatTokenLexer.h b/clang/lib/Format/FormatTokenLexer.h --- a/clang/lib/Format/FormatTokenLexer.h +++ b/clang/lib/Format/FormatTokenLexer.h @@ -55,6 +55,7 @@ bool tryMergeCSharpDoubleQuestion(); bool tryMergeCSharpNullConditional(); bool tryTransformCSharpForEach(); + bool tryMergeForEach(); bool tryMergeTokens(ArrayRef Kinds, TokenType NewType); diff --git a/clang/lib/Format/FormatTokenLexer.cpp b/clang/lib/Format/FormatTokenLexer.cpp --- a/clang/lib/Format/FormatTokenLexer.cpp +++ b/clang/lib/Format/FormatTokenLexer.cpp @@ -74,6 +74,8 @@ return; if (tryMergeLessLess()) return; + if (tryMergeForEach()) + return; if (Style.isCSharp()) { if (tryMergeCSharpKeywordVariables()) @@ -359,6 +361,28 @@ return true; } +bool FormatTokenLexer::tryMergeForEach() { + if (Tokens.size() < 2) + return false; + auto &For = *(Tokens.end() - 2); + auto &Each = *(Tokens.end() - 1); + if (!For->is(tok::kw_for)) + return false; + if (!Each->is(tok::identifier)) + return false; + if (Each->TokenText != "each") + return false; + + For->setType(TT_ForEachMacro); + For->Tok.setKind(tok::kw_for); + + For->TokenText = StringRef(For->TokenText.begin(), + Each->TokenText.end() - For->TokenText.begin()); + For->ColumnWidth += Each->ColumnWidth; + Tokens.erase(Tokens.end() - 1); + return true; +} + bool FormatTokenLexer::tryMergeLessLess() { // Merge X,less,less,Y into X,lessless,Y unless X or Y is less. if (Tokens.size() < 3) diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -994,6 +994,9 @@ "#define Q_FOREACH (x, y)\n" "#define BOOST_FOREACH (x, y)\n" "#define UNKNOWN_FOREACH (x, y)\n"); + + // handle microsoft non standard extension + verifyFormat("for each (char c in x->MyStringProperty)"); } TEST_F(FormatTest, FormatsWhileLoop) {