[clang-format] PR50727 C# Invoke Lamda Expression indentation incorrect

https://bugs.llvm.org/show_bug.cgi?id=50727

When processing C# Lambda expression in the indentation can goes a little wrong,
resulting the the closing } being at the wrong indentation level and meaning the remaining part of the file is
incorrectly indented.

This can be a fairly common pattern for when C# wants to peform a UI action from a thread,
and it wants to invoke that action on the main thread

Reviewed By: exv, jbcoe

Differential Revision: https://reviews.llvm.org/D104388
This commit is contained in:
mydeveloperday 2021-07-01 10:45:59 +01:00
parent c32186038d
commit f9937106b7
2 changed files with 133 additions and 5 deletions

View File

@ -1482,8 +1482,8 @@ void UnwrappedLineParser::parseStructuralElement() {
}
case tok::equal:
// Fat arrows (=>) have tok::TokenKind tok::equal but TokenType
// TT_FatArrow. The always start an expression or a child block if
// followed by a curly.
// TT_FatArrow. They always start an expression or a child block if
// followed by a curly brace.
if (FormatTok->is(TT_FatArrow)) {
nextToken();
if (FormatTok->is(tok::l_brace)) {
@ -1790,14 +1790,20 @@ bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons,
bool HasError = false;
// FIXME: Once we have an expression parser in the UnwrappedLineParser,
// replace this by using parseAssigmentExpression() inside.
// replace this by using parseAssignmentExpression() inside.
do {
if (Style.isCSharp()) {
// Fat arrows (=>) have tok::TokenKind tok::equal but TokenType
// TT_FatArrow. They always start an expression or a child block if
// followed by a curly brace.
if (FormatTok->is(TT_FatArrow)) {
nextToken();
// Fat arrows can be followed by simple expressions or by child blocks
// in curly braces.
if (FormatTok->is(tok::l_brace)) {
// C# may break after => if the next character is a newline.
if (Style.isCSharp() && Style.BraceWrapping.AfterFunction == true) {
// calling `addUnwrappedLine()` here causes odd parsing errors.
FormatTok->MustBreakBefore = true;
}
parseChildBlock();
continue;
}
@ -1927,6 +1933,12 @@ void UnwrappedLineParser::parseParens() {
parseBracedList();
}
break;
case tok::equal:
if (Style.isCSharp() && FormatTok->is(TT_FatArrow))
parseStructuralElement();
else
nextToken();
break;
case tok::kw_class:
if (Style.Language == FormatStyle::LK_JavaScript)
parseRecord(/*ParseAsExpr=*/true);

View File

@ -640,6 +640,122 @@ class MyClass
};
})",
MicrosoftStyle);
verifyFormat("void bar()\n"
"{\n"
" Function(Val, (Action)(() =>\n"
" {\n"
" lock (mylock)\n"
" {\n"
" if (true)\n"
" {\n"
" A.Remove(item);\n"
" }\n"
" }\n"
" }));\n"
"}",
MicrosoftStyle);
verifyFormat("void baz()\n"
"{\n"
" Function(Val, (Action)(() =>\n"
" {\n"
" using (var a = new Lock())\n"
" {\n"
" if (true)\n"
" {\n"
" A.Remove(item);\n"
" }\n"
" }\n"
" }));\n"
"}",
MicrosoftStyle);
verifyFormat("void baz()\n"
"{\n"
" Function(Val, (Action)(() =>\n"
" {\n"
" if (true)\n"
" {\n"
" A.Remove(item);\n"
" }\n"
" }));\n"
"}",
MicrosoftStyle);
verifyFormat("void baz()\n"
"{\n"
" Function(Val, (Action)(() =>\n"
" {\n"
" do\n"
" {\n"
" A.Remove(item);\n"
" } while (true)\n"
" }));\n"
"}",
MicrosoftStyle);
verifyFormat("void baz()\n"
"{\n"
" Function(Val, (Action)(() =>\n"
" { A.Remove(item); }));\n"
"}",
MicrosoftStyle);
verifyFormat("void bar()\n"
"{\n"
" Function(Val, (() =>\n"
" {\n"
" lock (mylock)\n"
" {\n"
" if (true)\n"
" {\n"
" A.Remove(item);\n"
" }\n"
" }\n"
" }));\n"
"}",
MicrosoftStyle);
verifyFormat("void bar()\n"
"{\n"
" Function((() =>\n"
" {\n"
" lock (mylock)\n"
" {\n"
" if (true)\n"
" {\n"
" A.Remove(item);\n"
" }\n"
" }\n"
" }));\n"
"}",
MicrosoftStyle);
MicrosoftStyle.IndentWidth = 2;
verifyFormat("void bar()\n"
"{\n"
" Function((() =>\n"
" {\n"
" lock (mylock)\n"
" {\n"
" if (true)\n"
" {\n"
" A.Remove(item);\n"
" }\n"
" }\n"
" }));\n"
"}",
MicrosoftStyle);
verifyFormat("void bar() {\n"
" Function((() => {\n"
" lock (mylock) {\n"
" if (true) {\n"
" A.Remove(item);\n"
" }\n"
" }\n"
" }));\n"
"}",
GoogleStyle);
}
TEST_F(FormatTestCSharp, CSharpObjectInitializers) {