diff --git a/StyleCop.Analyzers/StyleCop.Analyzers.Test/Helpers/TestDiagnosticProvider.cs b/StyleCop.Analyzers/StyleCop.Analyzers.Test/Helpers/TestDiagnosticProvider.cs index bec8e8ffc..a3c41a985 100644 --- a/StyleCop.Analyzers/StyleCop.Analyzers.Test/Helpers/TestDiagnosticProvider.cs +++ b/StyleCop.Analyzers/StyleCop.Analyzers.Test/Helpers/TestDiagnosticProvider.cs @@ -2,6 +2,7 @@ { using System.Collections.Generic; using System.Collections.Immutable; + using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; @@ -23,12 +24,12 @@ public override Task> GetAllDiagnosticsAsync(Project pro public override Task> GetDocumentDiagnosticsAsync(Document document, CancellationToken cancellationToken) { - return Task.FromResult>(this.diagnostics); + return Task.FromResult(this.diagnostics.Where(i => i.Location.GetLineSpan().Path == document.Name)); } public override Task> GetProjectDiagnosticsAsync(Project project, CancellationToken cancellationToken) { - return Task.FromResult>(this.diagnostics); + return Task.FromResult(this.diagnostics.Where(i => !i.Location.IsInSource)); } internal static TestDiagnosticProvider Create(ImmutableArray diagnostics) diff --git a/StyleCop.Analyzers/StyleCop.Analyzers.Test/MaintainabilityRules/SA1412UnitTests.cs b/StyleCop.Analyzers/StyleCop.Analyzers.Test/MaintainabilityRules/SA1412UnitTests.cs index b7fb0a0ea..3c6521ac6 100644 --- a/StyleCop.Analyzers/StyleCop.Analyzers.Test/MaintainabilityRules/SA1412UnitTests.cs +++ b/StyleCop.Analyzers/StyleCop.Analyzers.Test/MaintainabilityRules/SA1412UnitTests.cs @@ -77,9 +77,11 @@ public async Task TestCodeFixAsync(int codepage) var document = project.Documents.First(); // Create a diagnostic for the document to fix + var properties = ImmutableDictionary.Empty.SetItem(SA1412StoreFilesAsUtf8.EncodingProperty, this.fileEncoding.WebName); var diagnostic = Diagnostic.Create( this.GetCSharpDiagnosticAnalyzers().First().SupportedDiagnostics.First(), - Location.Create(await document.GetSyntaxTreeAsync().ConfigureAwait(false), TextSpan.FromBounds(0, 0))); + Location.Create(await document.GetSyntaxTreeAsync().ConfigureAwait(false), TextSpan.FromBounds(0, 0)), + properties); await codeFixer.RegisterCodeFixesAsync(new CodeFixContext(document, diagnostic, (ca, d) => { @@ -161,9 +163,11 @@ private async Task TestFixAllAsync(int codepage, FixAllScope scope) foreach (var document in project.Documents) { // Create a diagnostic for the document to fix + var properties = ImmutableDictionary.Empty.SetItem(SA1412StoreFilesAsUtf8.EncodingProperty, (await document.GetTextAsync().ConfigureAwait(false)).Encoding.WebName); var diagnostic = Diagnostic.Create( descriptor, - Location.Create(await document.GetSyntaxTreeAsync().ConfigureAwait(false), TextSpan.FromBounds(0, 0))); + Location.Create(await document.GetSyntaxTreeAsync().ConfigureAwait(false), TextSpan.FromBounds(0, 0)), + properties); diagnostics.Add(diagnostic); } @@ -225,9 +229,11 @@ private async Task TestFixAllWithMultipleEncodingsAsync(FixAllScope scope) foreach (var document in project.Documents) { // Create a diagnostic for the document to fix + var properties = ImmutableDictionary.Empty.SetItem(SA1412StoreFilesAsUtf8.EncodingProperty, (await document.GetTextAsync().ConfigureAwait(false)).Encoding.WebName); var diagnostic = Diagnostic.Create( descriptor, - Location.Create(await document.GetSyntaxTreeAsync().ConfigureAwait(false), TextSpan.FromBounds(0, 0))); + Location.Create(await document.GetSyntaxTreeAsync().ConfigureAwait(false), TextSpan.FromBounds(0, 0)), + properties); diagnostics.Add(diagnostic); } @@ -246,7 +252,7 @@ private async Task TestFixAllWithMultipleEncodingsAsync(FixAllScope scope) operation.Apply(workspace, CancellationToken.None); // project should now have the "fixed document" in it. - // Because of limitations in roslyn the fixed document should + // Because of limitations in Roslyn the fixed document should // have a different DocumentId then the broken document project = workspace.CurrentSolution.Projects.First(); diff --git a/StyleCop.Analyzers/StyleCop.Analyzers/MaintainabilityRules/SA1412CodeFixProvider.cs b/StyleCop.Analyzers/StyleCop.Analyzers/MaintainabilityRules/SA1412CodeFixProvider.cs index c35e3619f..02ab7325b 100644 --- a/StyleCop.Analyzers/StyleCop.Analyzers/MaintainabilityRules/SA1412CodeFixProvider.cs +++ b/StyleCop.Analyzers/StyleCop.Analyzers/MaintainabilityRules/SA1412CodeFixProvider.cs @@ -3,7 +3,9 @@ using System.Collections.Immutable; using System.Composition; using System.Text; + using System.Threading; using System.Threading.Tasks; + using Helpers; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; @@ -32,7 +34,7 @@ public override FixAllProvider GetFixAllProvider() } /// - public override async Task RegisterCodeFixesAsync(CodeFixContext context) + public override Task RegisterCodeFixesAsync(CodeFixContext context) { foreach (var diagnostic in context.Diagnostics) { @@ -41,30 +43,22 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) continue; } - string usedEncoding = await GetEncodingNameForDocumentAsync(context.Document).ConfigureAwait(false); + string usedEncoding = diagnostic.Properties[SA1412StoreFilesAsUtf8.EncodingProperty]; context.RegisterCodeFix( CodeAction.Create( string.Format(MaintainabilityResources.SA1412CodeFix, usedEncoding), - token => GetTransformedSolutionAsync(context.Document), - equivalenceKey: await GetEquivalenceKeyForDocumentAsync(context.Document).ConfigureAwait(false)), diagnostic); + cancellationToken => GetTransformedSolutionAsync(context.Document, cancellationToken), + equivalenceKey: nameof(SA1412CodeFixProvider) + "." + usedEncoding), + diagnostic); } - } - internal static async Task GetEncodingNameForDocumentAsync(Document document) - { - return (await document.GetTextAsync().ConfigureAwait(false)).Encoding?.WebName ?? ""; - } - - internal static async Task GetEquivalenceKeyForDocumentAsync(Document document) - { - string usedEncoding = await GetEncodingNameForDocumentAsync(document).ConfigureAwait(false); - return nameof(SA1412CodeFixProvider) + "." + usedEncoding; + return SpecializedTasks.CompletedTask; } - internal static async Task GetTransformedSolutionAsync(Document document) + internal static async Task GetTransformedSolutionAsync(Document document, CancellationToken cancellationToken) { - SourceText text = await document.GetTextAsync().ConfigureAwait(false); + SourceText text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); string actualSourceText = text.ToString(); diff --git a/StyleCop.Analyzers/StyleCop.Analyzers/MaintainabilityRules/SA1412FixAllProvider.cs b/StyleCop.Analyzers/StyleCop.Analyzers/MaintainabilityRules/SA1412FixAllProvider.cs index 9c0f24827..bbb92aca8 100644 --- a/StyleCop.Analyzers/StyleCop.Analyzers/MaintainabilityRules/SA1412FixAllProvider.cs +++ b/StyleCop.Analyzers/StyleCop.Analyzers/MaintainabilityRules/SA1412FixAllProvider.cs @@ -36,20 +36,27 @@ public override async Task GetFixAsync(FixAllContext fixAllContext) return null; } - return CodeAction.Create(string.Format(MaintainabilityResources.SA1412CodeFix, await SA1412CodeFixProvider.GetEncodingNameForDocumentAsync(fixAllContext.Document).ConfigureAwait(false)), token => Task.FromResult(newSolution)); + return CodeAction.Create( + string.Format(MaintainabilityResources.SA1412CodeFix, fixAllContext.CodeActionEquivalenceKey.Substring(fixAllContext.CodeActionEquivalenceKey.IndexOf('.') + 1)), + token => Task.FromResult(newSolution)); } private static async Task FixDocumentAsync(FixAllContext fixAllContext, Document document) { Solution solution = document.Project.Solution; var diagnostics = await fixAllContext.GetDocumentDiagnosticsAsync(document).ConfigureAwait(false); + if (diagnostics.Length == 0) + { + return solution; + } - if (diagnostics.Length == 0 || fixAllContext.CodeActionEquivalenceKey != await SA1412CodeFixProvider.GetEquivalenceKeyForDocumentAsync(document).ConfigureAwait(false)) + string equivalenceKey = nameof(SA1412CodeFixProvider) + "." + diagnostics[0].Properties[SA1412StoreFilesAsUtf8.EncodingProperty]; + if (fixAllContext.CodeActionEquivalenceKey != equivalenceKey) { return solution; } - return await SA1412CodeFixProvider.GetTransformedSolutionAsync(document).ConfigureAwait(false); + return await SA1412CodeFixProvider.GetTransformedSolutionAsync(document, fixAllContext.CancellationToken).ConfigureAwait(false); } private static async Task GetProjectFixesAsync(FixAllContext fixAllContext, Project project) diff --git a/StyleCop.Analyzers/StyleCop.Analyzers/MaintainabilityRules/SA1412StoreFilesAsUtf8.cs b/StyleCop.Analyzers/StyleCop.Analyzers/MaintainabilityRules/SA1412StoreFilesAsUtf8.cs index 8a1c811c9..92b70bf5d 100644 --- a/StyleCop.Analyzers/StyleCop.Analyzers/MaintainabilityRules/SA1412StoreFilesAsUtf8.cs +++ b/StyleCop.Analyzers/StyleCop.Analyzers/MaintainabilityRules/SA1412StoreFilesAsUtf8.cs @@ -37,6 +37,14 @@ public class SA1412StoreFilesAsUtf8 : DiagnosticAnalyzer private static byte[] utf8Preamble = Encoding.UTF8.GetPreamble(); + /// + /// Gets the key for the detected encoding name in the collection. + /// + /// + /// The key for the detected encoding name in the collection. + /// + public static string EncodingProperty { get; } = "Encoding"; + /// public override ImmutableArray SupportedDiagnostics { @@ -58,7 +66,8 @@ private static void HandleSyntaxTree(SyntaxTreeAnalysisContext context) if (!IsUtf8Preamble(preamble)) { - context.ReportDiagnostic(Diagnostic.Create(Descriptor, Location.Create(context.Tree, TextSpan.FromBounds(0, 0)))); + ImmutableDictionary properties = ImmutableDictionary.Empty.SetItem(EncodingProperty, context.Tree.Encoding?.WebName ?? ""); + context.ReportDiagnostic(Diagnostic.Create(Descriptor, Location.Create(context.Tree, TextSpan.FromBounds(0, 0)), properties)); } }