diff --git a/ChangeLog.md b/ChangeLog.md index 670d905a29..0ed49713b6 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix [RCS1056](https://github.com/JosefPihrt/Roslynator/blob/main/docs/analyzers/RCS1056.md) ([#1096](https://github.com/JosefPihrt/Roslynator/pull/1096)). - Fix [RCS1216](https://github.com/JosefPihrt/Roslynator/blob/main/docs/analyzers/RCS1216.md) ([#1094](https://github.com/JosefPihrt/Roslynator/pull/1094)). - Fix [RCS1146](https://github.com/JosefPihrt/Roslynator/blob/main/docs/analyzers/RCS1146.md) ([#1098](https://github.com/JosefPihrt/Roslynator/pull/1098)). +- Fix [RCS1154](https://github.com/JosefPihrt/Roslynator/blob/main/docs/analyzers/RCS1154.md) ([#1105](https://github.com/JosefPihrt/Roslynator/pull/1105)). ## [4.3.0] - 2023-04-24 diff --git a/src/Analyzers.CodeFixes/CSharp/CodeFixes/EnumDeclarationCodeFixProvider.cs b/src/Analyzers.CodeFixes/CSharp/CodeFixes/EnumDeclarationCodeFixProvider.cs index 70cb187715..ddebe158a2 100644 --- a/src/Analyzers.CodeFixes/CSharp/CodeFixes/EnumDeclarationCodeFixProvider.cs +++ b/src/Analyzers.CodeFixes/CSharp/CodeFixes/EnumDeclarationCodeFixProvider.cs @@ -119,68 +119,65 @@ private static async Task SortEnumMembersAsync( CancellationToken cancellationToken) { SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); - SpecialType enumSpecialType = semanticModel.GetDeclaredSymbol(enumDeclaration).EnumUnderlyingType.SpecialType; - SeparatedSyntaxList members = enumDeclaration.Members; - SeparatedSyntaxList newMembers = members + List sortedList = members .OrderBy(f => GetConstantValue(f, semanticModel, cancellationToken), EnumValueComparer.GetInstance(enumSpecialType)) - .ToSeparatedSyntaxList(); - - if (AreSeparatedWithEmptyLine(members)) - { - for (int i = 0; i < newMembers.Count; i++) - { - newMembers = newMembers.ReplaceAt(i, newMembers[i].TrimLeadingTrivia()); - } - - for (int i = 0; i < newMembers.Count - 1; i++) - { - SyntaxToken separator = newMembers.GetSeparator(i); + .ToList(); - newMembers = newMembers.ReplaceSeparator( - separator, - separator.TrimTrailingTrivia().AppendToTrailingTrivia(new SyntaxTrivia[] { NewLine(), NewLine() })); - } - } + bool hasTrailingSeparator = members.HasTrailingSeparator(); + int lastIndex = sortedList.Count - 1; - if (newMembers.SeparatorCount == members.SeparatorCount - 1) + if (!hasTrailingSeparator) { - SyntaxNodeOrTokenList newMembersWithSeparators = newMembers.GetWithSeparators(); + int index = members.IndexOf(sortedList.Last()); - newMembersWithSeparators = newMembersWithSeparators.Add(CommaToken()); + SyntaxTriviaList trailingTrivia = (index == members.Count - 1) + ? members[index].GetTrailingTrivia() + : members.GetSeparator(index).TrailingTrivia; - newMembers = newMembersWithSeparators.ToSeparatedSyntaxList(); + sortedList[sortedList.Count - 1] = sortedList[sortedList.Count - 1].WithTrailingTrivia(trailingTrivia); + lastIndex--; } - MemberDeclarationSyntax newNode = enumDeclaration - .WithMembers(newMembers) - .WithFormatterAnnotation(); + List sortedMembers = sortedList.ConvertAll(member => (SyntaxNodeOrToken)member); - return await document.ReplaceNodeAsync(enumDeclaration, newNode, cancellationToken).ConfigureAwait(false); - } + for (int i = lastIndex; i >= 0; i--) + { + int oldIndex = members.IndexOf((EnumMemberDeclarationSyntax)sortedMembers[i]); - private static bool AreSeparatedWithEmptyLine(SeparatedSyntaxList members) - { - int count = members.Count; + if (oldIndex == 0 + && members[i].GetLeadingTrivia().FirstOrDefault().IsEndOfLineTrivia()) + { + sortedMembers[i] = sortedMembers[i].WithLeadingTrivia(sortedMembers[i].GetLeadingTrivia().Insert(0, NewLine())); + } - if (members.SeparatorCount < count - 1) - return false; + SyntaxTriviaList trailingTrivia; + if (!hasTrailingSeparator + && oldIndex == members.Count - 1) + { + trailingTrivia = members.Last().GetTrailingTrivia(); + sortedMembers[i] = sortedMembers[i].WithoutTrailingTrivia(); + } + else + { + trailingTrivia = members.GetSeparator(oldIndex).TrailingTrivia; + } - for (int i = 1; i < count; i++) - { - if (!members[i].GetLeadingTrivia().Any(SyntaxKind.EndOfLineTrivia)) - return false; + sortedMembers.Insert(i + 1, Token(SyntaxKind.CommaToken).WithTrailingTrivia(trailingTrivia)); } - for (int i = 0; i < count - 1; i++) - { - if (!members.GetSeparator(i).TrailingTrivia.Any(SyntaxKind.EndOfLineTrivia)) - return false; - } + SyntaxTriviaList leadingTrivia = sortedMembers[0].GetLeadingTrivia(); + + if (leadingTrivia.FirstOrDefault().IsEndOfLineTrivia()) + sortedMembers[0] = sortedMembers[0].WithLeadingTrivia(leadingTrivia.RemoveAt(0)); - return true; + MemberDeclarationSyntax newEnumDeclaration = enumDeclaration + .WithMembers(sortedMembers.ToSeparatedSyntaxList()) + .WithFormatterAnnotation(); + + return await document.ReplaceNodeAsync(enumDeclaration, newEnumDeclaration, cancellationToken).ConfigureAwait(false); } private static object GetConstantValue( diff --git a/src/Tests/Analyzers.Tests/RCS1154SortEnumMembersTests.cs b/src/Tests/Analyzers.Tests/RCS1154SortEnumMembersTests.cs index fcc9e2a40d..9dba4581c1 100644 --- a/src/Tests/Analyzers.Tests/RCS1154SortEnumMembersTests.cs +++ b/src/Tests/Analyzers.Tests/RCS1154SortEnumMembersTests.cs @@ -91,25 +91,25 @@ await VerifyDiagnosticAndFixAsync(@" enum [|Foo|] { /// B - B = 1, + B = 1, // B /// A - A = 0, + A = 0, // A /// D - D = 3, + D = 3, // D /// C - C = 2, + C = 2, // C } ", @" enum Foo { /// A - A = 0, + A = 0, // A /// B - B = 1, + B = 1, // B /// C - C = 2, + C = 2, // C /// D - D = 3, + D = 3, // D } "); } @@ -121,31 +121,31 @@ await VerifyDiagnosticAndFixAsync(@" enum [|Foo|] { /// B - B = 1, + B = 1, // B /// A - A = 0, + A = 0, // A /// D - D = 3, + D = 3, // D /// C - C = 2 + C = 2 // C } ", @" enum Foo { /// A - A = 0, + A = 0, // A /// B - B = 1, + B = 1, // B /// C - C = 2, + C = 2, // C /// D - D = 3 + D = 3 // D } "); } @@ -157,31 +157,31 @@ await VerifyDiagnosticAndFixAsync(@" enum [|Foo|] { /// B - B = 1, + B = 1, // B /// A - A = 0, + A = 0, // A /// D - D = 3, + D = 3, // D /// C - C = 2, + C = 2, // C } ", @" enum Foo { /// A - A = 0, + A = 0, // A /// B - B = 1, + B = 1, // B /// C - C = 2, + C = 2, // C /// D - D = 3, + D = 3, // D } "); }