diff --git a/Src/CSharpier.Core/CSharp/SyntaxNodeComparer.cs b/Src/CSharpier.Core/CSharp/SyntaxNodeComparer.cs index 7d5bed4a1..ec772ad64 100644 --- a/Src/CSharpier.Core/CSharp/SyntaxNodeComparer.cs +++ b/Src/CSharpier.Core/CSharp/SyntaxNodeComparer.cs @@ -50,6 +50,7 @@ CancellationToken cancellationToken cSharpParseOptions, cancellationToken: cancellationToken ); + this.CompareFunc = Compare; } public string CompareSource() @@ -148,14 +149,16 @@ SyntaxNode formattedStart return Equal; } +#pragma warning disable CA1822 private CompareResult CompareLists( - IReadOnlyList originalList, - IReadOnlyList formattedList, - Func comparer, - Func getSpan, + T originalList, + T formattedList, + Func comparer, + Func getSpan, TextSpan originalParentSpan, TextSpan newParentSpan ) + where T : IReadOnlyList { for (var x = 0; x < originalList.Count || x < formattedList.Count; x++) { @@ -169,25 +172,71 @@ TextSpan newParentSpan return NotEqual(getSpan(originalList[x]), newParentSpan); } - if ( - originalList[x] is SyntaxNode originalNode - && formattedList[x] is SyntaxNode formattedNode - ) + var result = comparer(originalList[x], formattedList[x]); + if (result.IsInvalid) + { + return result; + } + } + + return Equal; + } +#pragma warning restore CA1822 + + private CompareResult CompareLists( + T originalList, + T formattedList, + Func comparer, + Func getSpan, + TextSpan originalParentSpan, + TextSpan newParentSpan + ) + where T : IReadOnlyList + { + for (var x = 0; x < originalList.Count || x < formattedList.Count; x++) + { + if (x == originalList.Count) + { + return NotEqual(originalParentSpan, getSpan(formattedList[x])); + } + + if (x == formattedList.Count) { - this.originalStack.Push((originalNode, originalNode.Parent)); - this.formattedStack.Push((formattedNode, formattedNode.Parent)); + return NotEqual(getSpan(originalList[x]), newParentSpan); } - else + + var originalNode = originalList[x]; + var formattedNode = formattedList[x]; + this.originalStack.Push((originalNode, originalNode.Parent)); + this.formattedStack.Push((formattedNode, formattedNode.Parent)); + } + + return Equal; + } + + private static SyntaxToken[] AllSeparatorsButLast(in SeparatedSyntaxList list) + { + if (list.Count <= 1) + { + return []; + } + + var tokens = new SyntaxToken[list.Count - 1]; + var tokenIndex = 0; + + foreach (var element in list.GetWithSeparators()) + { + if (element.IsToken) { - var result = comparer(originalList[x], formattedList[x]); - if (result.IsInvalid) + tokens[tokenIndex++] = element.AsToken(); + if (tokenIndex == tokens.Length) { - return result; + break; } } } - return Equal; + return tokens; } private static CompareResult NotEqual(SyntaxNode? originalNode, SyntaxNode? formattedNode) @@ -210,6 +259,8 @@ private static CompareResult NotEqual(TextSpan? originalSpan, TextSpan? formatte }; } + private Func CompareFunc { get; } + private CompareResult Compare(SyntaxToken originalToken, SyntaxToken formattedToken) { return this.Compare(originalToken, formattedToken, null, null); diff --git a/Src/CSharpier.Generators/SyntaxNodeComparerGenerator.cs b/Src/CSharpier.Generators/SyntaxNodeComparerGenerator.cs index 4985e499e..1f938810d 100644 --- a/Src/CSharpier.Generators/SyntaxNodeComparerGenerator.cs +++ b/Src/CSharpier.Generators/SyntaxNodeComparerGenerator.cs @@ -137,7 +137,7 @@ private static void GenerateMethod(StringBuilder sourceBuilder, INamedTypeSymbol $$""" private CompareResult Compare{{type.Name}}({{type.Name}} originalNode, {{type.Name}} formattedNode) { - CompareResult result; + CompareResult result; """ ); @@ -228,10 +228,13 @@ private static void GenerateMethod(StringBuilder sourceBuilder, INamedTypeSymbol } else { - var compare = propertyType.Name == nameof(SyntaxTokenList) ? "Compare" : "null"; + var compare = + propertyType.Name == nameof(SyntaxTokenList) + ? "CompareFunc" + : "static (_, _) => default"; if (propertyName == "Modifiers") { - propertyName += ".OrderBy(o => o.Text).ToList()"; + propertyName += ".OrderBy(o => o.Text).ToArray()"; } sourceBuilder.AppendLine( @@ -249,13 +252,13 @@ private static void GenerateMethod(StringBuilder sourceBuilder, INamedTypeSymbol ) { sourceBuilder.AppendLine( - $" result = this.CompareLists(originalNode.{propertyName}, formattedNode.{propertyName}, null, o => o.Span, originalNode.Span, formattedNode.Span);" + $" result = this.CompareLists(originalNode.{propertyName}, formattedNode.{propertyName}, static (_, _) => default, o => o.Span, originalNode.Span, formattedNode.Span);" ); sourceBuilder.AppendLine(" if (result.IsInvalid) return result;"); // Omit the last separator when comparing the original node with the formatted node, as it legitimately may be added or removed sourceBuilder.AppendLine( - $" result = this.CompareLists(originalNode.{propertyName}.GetSeparators().Take(originalNode.{propertyName}.Count() - 1).ToList(), formattedNode.{propertyName}.GetSeparators().Take(formattedNode.{propertyName}.Count() - 1).ToList(), Compare, o => o.Span, originalNode.Span, formattedNode.Span);" + $" result = this.CompareLists(AllSeparatorsButLast(originalNode.{propertyName}), AllSeparatorsButLast(formattedNode.{propertyName}), CompareFunc, o => o.Span, originalNode.Span, formattedNode.Span);" ); sourceBuilder.AppendLine(" if (result.IsInvalid) return result;"); }