diff --git a/Src/CSharpier.Core/CSharp/SyntaxPrinter/ArgumentListLikeSyntax.cs b/Src/CSharpier.Core/CSharp/SyntaxPrinter/ArgumentListLikeSyntax.cs index 9bdb318d5..26ab2e647 100644 --- a/Src/CSharpier.Core/CSharp/SyntaxPrinter/ArgumentListLikeSyntax.cs +++ b/Src/CSharpier.Core/CSharp/SyntaxPrinter/ArgumentListLikeSyntax.cs @@ -2,6 +2,7 @@ using CSharpier.Core.DocTypes; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Text; namespace CSharpier.Core.CSharp.SyntaxPrinter; @@ -78,6 +79,21 @@ lambda.Block is not null { args = SeparatedSyntaxList.Print(arguments, Argument.Print, Doc.Line, context); } + else if ( + arguments.Count > 1 + && arguments[^1].Expression is LambdaExpressionSyntax lastLambda + && !arguments + .Take(arguments.Count - 1) + .Any(o => o.Expression is AnonymousFunctionExpressionSyntax) + && !openParenToken + .Parent!.DescendantTrivia( + TextSpan.FromBounds(openParenToken.SpanStart, lastLambda.ArrowToken.SpanStart) + ) + .Any(o => o.IsComment() || o.IsDirective) + ) + { + args = ArgumentListWithTrailingLambda.Print(arguments, lastLambda, context); + } else if (arguments.Count > 0) { args = Doc.Concat( diff --git a/Src/CSharpier.Core/CSharp/SyntaxPrinter/ArgumentListWithTrailingLambda.cs b/Src/CSharpier.Core/CSharp/SyntaxPrinter/ArgumentListWithTrailingLambda.cs new file mode 100644 index 000000000..b2a49ca72 --- /dev/null +++ b/Src/CSharpier.Core/CSharp/SyntaxPrinter/ArgumentListWithTrailingLambda.cs @@ -0,0 +1,75 @@ +using CSharpier.Core.CSharp.SyntaxPrinter.SyntaxNodePrinters; +using CSharpier.Core.DocTypes; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace CSharpier.Core.CSharp.SyntaxPrinter; + +internal static class ArgumentListWithTrailingLambda +{ + public static Doc Print( + SeparatedSyntaxList arguments, + LambdaExpressionSyntax lastLambda, + PrintingContext context + ) + { + var chop = Doc.Concat( + Doc.Indent( + Doc.SoftLine, + SeparatedSyntaxList.Print(arguments, Argument.Print, Doc.Line, context) + ), + Doc.SoftLine + ); + + Doc lambdaHead; + Doc lambdaBody; + bool bodyIsBraced; + if (lastLambda is SimpleLambdaExpressionSyntax simpleLambda) + { + bodyIsBraced = + simpleLambda.Body + is BlockSyntax + or ObjectCreationExpressionSyntax + or AnonymousObjectCreationExpressionSyntax; + + lambdaHead = SimpleLambdaExpression.PrintHead(simpleLambda, context); + lambdaBody = SimpleLambdaExpression.PrintBody(simpleLambda, context); + } + else if (lastLambda is ParenthesizedLambdaExpressionSyntax parenthesizedLambda) + { + bodyIsBraced = parenthesizedLambda.Block is not null; + lambdaHead = ParenthesizedLambdaExpression.PrintHead(parenthesizedLambda, context); + lambdaBody = bodyIsBraced + ? ParenthesizedLambdaExpression.PrintBody(parenthesizedLambda, context) + : Doc.Indent(Doc.Line, Node.Print(parenthesizedLambda.Body, context)); + } + else + { + return chop; + } + + var flatParts = new List((arguments.Count - 1) * 3 + 2); + for (var x = 0; x < arguments.Count - 1; x++) + { + flatParts.Add(Argument.Print(arguments[x], context)); + flatParts.Add(Token.Print(arguments.GetSeparator(x), context)); + flatParts.Add(" "); + } + + flatParts.Add(Argument.PrintModifiers(arguments[^1], context)); + flatParts.Add(lambdaHead); + + if (flatParts.Any(DocUtilities.ContainsBreak)) + { + return chop; + } + + var wrap = Doc.Concat( + Doc.ForceFlat(flatParts), + lambdaBody, + bodyIsBraced ? Doc.Null : Doc.SoftLine + ); + + return Doc.ConditionalGroup(wrap, wrap, chop); + } +} diff --git a/Src/CSharpier.Tests/FormattingTests/TestFiles/cs/ObnoxiousEdgeCases.test b/Src/CSharpier.Tests/FormattingTests/TestFiles/cs/ObnoxiousEdgeCases.test index 7c0cce35b..4f55432d1 100644 --- a/Src/CSharpier.Tests/FormattingTests/TestFiles/cs/ObnoxiousEdgeCases.test +++ b/Src/CSharpier.Tests/FormattingTests/TestFiles/cs/ObnoxiousEdgeCases.test @@ -9,9 +9,8 @@ class ClassName internal StackObjectPool< Dictionary > KeyedItemInfoDictionaryPool { get; } = - new StackObjectPool>( - maxPreservedItems: 10, - () => new Dictionary() + new StackObjectPool>(maxPreservedItems: 10, () => + new Dictionary() ); RenderFragment customNotAuthorized = state => diff --git a/Src/CSharpier.Tests/FormattingTests/TestFiles/cs/ParenthesizedLambdaExpressions.test b/Src/CSharpier.Tests/FormattingTests/TestFiles/cs/ParenthesizedLambdaExpressions.test index 90fff78ab..77974aac1 100644 --- a/Src/CSharpier.Tests/FormattingTests/TestFiles/cs/ParenthesizedLambdaExpressions.test +++ b/Src/CSharpier.Tests/FormattingTests/TestFiles/cs/ParenthesizedLambdaExpressions.test @@ -104,8 +104,26 @@ public class ClassName CallAnotherMethod______________________________________________________123() ); + CallMethod(CallAnotherMethod_________________(), () => + CallAnotherMethod_________________() + ); + + CallMethod( + CallAnotherMethod_________________(), + // Comment + () => CallAnotherMethod_________________() + ); + + CallMethod( +#if DEBUG + CallAnotherMethod_________________(), +#endif + () => CallAnotherMethod_________________() + ); + CallMethod( CallAnotherMethod_________________(), + () => CallAnotherMethod_________________(), () => CallAnotherMethod_________________() ); }