Skip to content

Commit 95acc4e

Browse files
committed
Merge pull request #1820 from sharwell/fix-1800
Add the `newlineAtEndOfFile` configuration property
2 parents c6fb55b + 71c6d9e commit 95acc4e

12 files changed

Lines changed: 541 additions & 89 deletions

File tree

StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/LayoutRules/SA1518CodeFixProvider.cs

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ namespace StyleCop.Analyzers.LayoutRules
55
{
66
using System.Collections.Immutable;
77
using System.Composition;
8-
using System.Linq;
98
using System.Threading;
109
using System.Threading.Tasks;
1110
using Helpers;
1211
using Microsoft.CodeAnalysis;
1312
using Microsoft.CodeAnalysis.CodeActions;
1413
using Microsoft.CodeAnalysis.CodeFixes;
15-
using Microsoft.CodeAnalysis.CSharp;
14+
using Microsoft.CodeAnalysis.Text;
15+
using Settings.ObjectModel;
1616

1717
/// <summary>
1818
/// Implements a code fix for <see cref="SA1518CodeMustNotContainBlankLinesAtEndOfFile"/>.
@@ -28,50 +28,61 @@ internal class SA1518CodeFixProvider : CodeFixProvider
2828
/// <inheritdoc/>
2929
public override FixAllProvider GetFixAllProvider()
3030
{
31-
return CustomFixAllProviders.BatchFixer;
31+
return FixAll.Instance;
3232
}
3333

3434
/// <inheritdoc/>
3535
public override Task RegisterCodeFixesAsync(CodeFixContext context)
3636
{
37-
foreach (Diagnostic diagnostic in context.Diagnostics)
37+
var settings = SettingsHelper.GetStyleCopSettings(context.Document.Project.AnalyzerOptions, context.CancellationToken);
38+
foreach (var diagnostic in context.Diagnostics)
3839
{
3940
context.RegisterCodeFix(
4041
CodeAction.Create(
4142
LayoutResources.SA1518CodeFix,
42-
cancellationToken => GetTransformedDocumentAsync(context.Document, cancellationToken),
43+
cancellationToken => FixEndOfFileAsync(context.Document, diagnostic, settings.LayoutRules.NewlineAtEndOfFile, cancellationToken),
4344
nameof(SA1518CodeFixProvider)),
4445
diagnostic);
4546
}
4647

4748
return SpecializedTasks.CompletedTask;
4849
}
4950

50-
private static async Task<Document> GetTransformedDocumentAsync(Document document, CancellationToken token)
51+
/// <summary>
52+
/// Fixes the whitespace at the end of a document.
53+
/// </summary>
54+
/// <param name="document">The document to be changed.</param>
55+
/// <param name="diagnostic">The diagnostic to fix.</param>
56+
/// <param name="newlineAtEndOfFile">A <see cref="EndOfFileHandling"/> value indicating the desired behavior.</param>
57+
/// <param name="cancellationToken">The cancellation token associated with the fix action.</param>
58+
/// <returns>The transformed document.</returns>
59+
private static async Task<Document> FixEndOfFileAsync(Document document, Diagnostic diagnostic, EndOfFileHandling newlineAtEndOfFile, CancellationToken cancellationToken)
5160
{
52-
var syntaxRoot = await document.GetSyntaxRootAsync(token).ConfigureAwait(false);
53-
54-
var lastToken = syntaxRoot.GetLastToken(includeZeroWidth: true);
55-
56-
var newLastToken = StripViolatingWhitespace(lastToken);
57-
var newSyntaxRoot = syntaxRoot.ReplaceToken(lastToken, newLastToken);
58-
var newDocument = document.WithSyntaxRoot(newSyntaxRoot);
59-
60-
return newDocument;
61+
var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
62+
string replacement = newlineAtEndOfFile == EndOfFileHandling.Omit ? string.Empty : "\r\n";
63+
return document.WithText(text.WithChanges(new TextChange(diagnostic.Location.SourceSpan, replacement)));
6164
}
6265

63-
private static SyntaxToken StripViolatingWhitespace(SyntaxToken token)
66+
private class FixAll : DocumentBasedFixAllProvider
6467
{
65-
SyntaxToken result = token;
68+
public static FixAllProvider Instance { get; } =
69+
new FixAll();
6670

67-
var trailingWhitespaceIndex = TriviaHelper.IndexOfTrailingWhitespace(token.LeadingTrivia);
68-
if (trailingWhitespaceIndex != -1)
71+
protected override string CodeActionTitle =>
72+
LayoutResources.SA1518CodeFix;
73+
74+
protected override async Task<SyntaxNode> FixAllInDocumentAsync(FixAllContext fixAllContext, Document document)
6975
{
70-
var newTriviaList = SyntaxFactory.TriviaList(token.LeadingTrivia.Take(trailingWhitespaceIndex));
71-
result = token.WithLeadingTrivia(newTriviaList);
72-
}
76+
var diagnostics = await fixAllContext.GetDocumentDiagnosticsAsync(document).ConfigureAwait(false);
77+
if (diagnostics.IsEmpty)
78+
{
79+
return null;
80+
}
7381

74-
return result;
82+
var settings = SettingsHelper.GetStyleCopSettings(document.Project.AnalyzerOptions, fixAllContext.CancellationToken);
83+
Document updatedDocument = await FixEndOfFileAsync(document, diagnostics[0], settings.LayoutRules.NewlineAtEndOfFile, fixAllContext.CancellationToken).ConfigureAwait(false);
84+
return await updatedDocument.GetSyntaxRootAsync(fixAllContext.CancellationToken).ConfigureAwait(false);
85+
}
7586
}
7687
}
7788
}

0 commit comments

Comments
 (0)