Skip to content

Commit ec1112e

Browse files
authored
Merge pull request #3607 from bjornhellander/feature/sa1513-linefeed
Update SA1513 codefix to use the existing newline character sequence
2 parents 0e192df + 861b432 commit ec1112e

File tree

4 files changed

+76
-1
lines changed

4 files changed

+76
-1
lines changed

StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/LayoutRules/SA1513CodeFixProvider.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ private static async Task<SyntaxNode> GetTransformedDocumentAsync(Document docum
6565
diagnostics.Select(diagnostic => root.FindToken(diagnostic.Location.SourceSpan.End)),
6666
(originalToken, rewrittenToken) =>
6767
{
68-
var newTrivia = rewrittenToken.LeadingTrivia.Insert(0, SyntaxFactory.CarriageReturnLineFeed);
68+
var endOfLineTrivia = rewrittenToken.GetPrecedingEndOfLineTrivia();
69+
var newTrivia = rewrittenToken.LeadingTrivia.Insert(0, endOfLineTrivia);
6970
return rewrittenToken.WithLeadingTrivia(newTrivia);
7071
});
7172
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
2+
// Licensed under the MIT License. See LICENSE in the project root for license information.
3+
4+
namespace StyleCop.Analyzers.Test.Helpers
5+
{
6+
public static class StringExtensions
7+
{
8+
public static string ReplaceLineEndings(this string input, string replacementText)
9+
{
10+
// First normalize to LF
11+
var lineFeedInput = input
12+
.Replace("\r\n", "\n")
13+
.Replace("\r", "\n")
14+
.Replace("\f", "\n")
15+
.Replace("\x0085", "\n")
16+
.Replace("\x2028", "\n")
17+
.Replace("\x2029", "\n");
18+
19+
// Then normalize to the replacement text
20+
return lineFeedInput.Replace("\n", replacementText);
21+
}
22+
}
23+
}

StyleCop.Analyzers/StyleCop.Analyzers.Test/LayoutRules/SA1513UnitTests.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ namespace StyleCop.Analyzers.Test.LayoutRules
99
using System.Threading.Tasks;
1010
using Microsoft.CodeAnalysis.Testing;
1111
using StyleCop.Analyzers.LayoutRules;
12+
using StyleCop.Analyzers.Test.Helpers;
1213
using Xunit;
1314
using static StyleCop.Analyzers.Test.Verifiers.StyleCopCodeFixVerifier<
1415
StyleCop.Analyzers.LayoutRules.SA1513ClosingBraceMustBeFollowedByBlankLine,
@@ -1013,5 +1014,25 @@ public void TestMethod(string extraSupport)
10131014

10141015
await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
10151016
}
1017+
1018+
[Fact]
1019+
[WorkItem(3360, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3360")]
1020+
public async Task TestLineFeedEndOfLinesAsync()
1021+
{
1022+
var testCode = @"
1023+
public class TestClass
1024+
{
1025+
}[|
1026+
|]// Hello".ReplaceLineEndings("\n");
1027+
1028+
var fixedCode = @"
1029+
public class TestClass
1030+
{
1031+
}
1032+
1033+
// Hello".ReplaceLineEndings("\n");
1034+
1035+
await VerifyCSharpFixAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, fixedCode, CancellationToken.None).ConfigureAwait(false);
1036+
}
10161037
}
10171038
}

StyleCop.Analyzers/StyleCop.Analyzers/Helpers/TokenHelper.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,5 +175,35 @@ internal static bool IsFollowedByWhitespace(this SyntaxToken token)
175175
triviaList = token.GetNextToken().LeadingTrivia;
176176
return triviaList.Count > 0 && triviaList.First().IsKind(SyntaxKind.WhitespaceTrivia);
177177
}
178+
179+
/// <summary>
180+
/// Returns the closest end of line trivia preceding the <paramref name="token"/>.
181+
/// This currently only looks immediately before the specified token.
182+
/// </summary>
183+
/// <param name="token">The token to process.</param>
184+
/// <returns>The closest preceding end of line trivia, or <see cref="SyntaxFactory.CarriageReturnLineFeed"/> if none is found.</returns>
185+
internal static SyntaxTrivia GetPrecedingEndOfLineTrivia(this SyntaxToken token)
186+
{
187+
var leadingTrivia = token.LeadingTrivia;
188+
for (var i = leadingTrivia.Count - 1; i >= 0; i--)
189+
{
190+
if (leadingTrivia[i].IsKind(SyntaxKind.EndOfLineTrivia))
191+
{
192+
return leadingTrivia[i];
193+
}
194+
}
195+
196+
var prevToken = token.GetPreviousToken();
197+
var prevTrailingTrivia = prevToken.TrailingTrivia;
198+
for (var i = prevTrailingTrivia.Count - 1; i >= 0; i--)
199+
{
200+
if (prevTrailingTrivia[i].IsKind(SyntaxKind.EndOfLineTrivia))
201+
{
202+
return prevTrailingTrivia[i];
203+
}
204+
}
205+
206+
return SyntaxFactory.CarriageReturnLineFeed;
207+
}
178208
}
179209
}

0 commit comments

Comments
 (0)