提交 1124126a 编写于 作者: S Sam Harwell

Avoid storing code fixes in the diagnostic property bags

上级 75c90a04
......@@ -165,5 +165,34 @@ void MyMethod()
await Verify.VerifyCodeFixAsync(testCode, fixedCode);
}
[Fact]
public async Task TestIncrementalFixesFullLine()
{
var testCode = @"
class MyClass
{
int Property1$${$$get;$$set;$$}
int Property2$${$$get;$$}
}
";
var fixedCode = @"
class MyClass
{
int Property1 { get; set; }
int Property2 { get; }
}
";
await new CSharpCodeFixTest<CSharpFormattingAnalyzer, FormattingCodeFixProvider, XUnitVerifier>
{
TestCode = testCode,
FixedCode = fixedCode,
// Each application of a single code fix covers all diagnostics on the same line. In total, two lines
// require changes so the number of incremental iterations is exactly 2.
NumberOfIncrementalIterations = 2,
}.RunAsync();
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Immutable;
using System.IO;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Formatting;
......@@ -13,11 +12,6 @@ namespace Microsoft.CodeAnalysis.CodeStyle
{
internal abstract class AbstractFormattingAnalyzerImpl
{
public static readonly string ReplaceTextKey = nameof(ReplaceTextKey);
public static readonly ImmutableDictionary<string, string> RemoveTextProperties =
ImmutableDictionary.Create<string, string>().Add(ReplaceTextKey, "");
private readonly DiagnosticDescriptor _descriptor;
protected AbstractFormattingAnalyzerImpl(DiagnosticDescriptor descriptor)
......@@ -87,23 +81,13 @@ private void AnalyzeSyntaxTree(SyntaxTreeAnalysisContext context, Workspace work
throw new InvalidOperationException("This program location is thought to be unreachable.");
}
ImmutableDictionary<string, string> properties;
if (change.NewText.Length == 0)
{
properties = RemoveTextProperties;
}
else
{
properties = ImmutableDictionary.Create<string, string>().Add(ReplaceTextKey, change.NewText);
}
var location = Location.Create(tree, change.Span);
context.ReportDiagnostic(DiagnosticHelper.Create(
_descriptor,
location,
ReportDiagnostic.Default,
additionalLocations: null,
properties));
properties: null));
}
}
}
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using System.Threading;
......@@ -26,34 +25,34 @@ public override FixAllProvider GetFixAllProvider()
public override Task RegisterCodeFixesAsync(CodeFixContext context)
{
context.RegisterCodeFix(
CodeAction.Create(
CodeStyleFixesResources.Formatting_analyzer_code_fix,
c => FixOneAsync(context.Document, context.Diagnostics, c),
nameof(FormattingCodeFixProvider)),
context.Diagnostics);
foreach (var diagnostic in context.Diagnostics)
{
context.RegisterCodeFix(
CodeAction.Create(
CodeStyleFixesResources.Formatting_analyzer_code_fix,
c => FixOneAsync(context.Document, diagnostic, c),
nameof(FormattingCodeFixProvider)),
diagnostic);
}
return Task.CompletedTask;
}
protected async Task<Document> FixOneAsync(Document document, ImmutableArray<Diagnostic> diagnostics, CancellationToken cancellationToken)
protected async Task<Document> FixOneAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken)
{
var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
var changes = new List<TextChange>();
foreach (var diagnostic in diagnostics)
{
if (!diagnostic.Properties.TryGetValue(AbstractFormattingAnalyzerImpl.ReplaceTextKey, out var replacement))
{
continue;
}
changes.Add(new TextChange(diagnostic.Location.SourceSpan, replacement));
}
// The span to format is the full line(s) containing the diagnostic
var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
var diagnosticSpan = diagnostic.Location.SourceSpan;
var diagnosticLinePositionSpan = text.Lines.GetLinePositionSpan(diagnosticSpan);
var spanToFormat = TextSpan.FromBounds(
text.Lines[diagnosticLinePositionSpan.Start.Line].Start,
text.Lines[diagnosticLinePositionSpan.End.Line].End);
changes.Sort((left, right) => left.Span.Start.CompareTo(right.Span.Start));
return document.WithText(text.WithChanges(changes));
var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);
return await Formatter.FormatAsync(document, spanToFormat, options, cancellationToken).ConfigureAwait(false);
}
private class FixAll : DocumentBasedFixAllProvider
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using System.Threading;
......@@ -23,31 +22,31 @@ public override ImmutableArray<string> FixableDiagnosticIds
public override Task RegisterCodeFixesAsync(CodeFixContext context)
{
context.RegisterCodeFix(
new MyCodeAction(c => FixOneAsync(context.Document, context.Diagnostics, c)),
context.Diagnostics);
foreach (var diagnostic in context.Diagnostics)
{
context.RegisterCodeFix(
new MyCodeAction(c => FixOneAsync(context.Document, diagnostic, c)),
diagnostic);
}
return Task.CompletedTask;
}
protected async Task<Document> FixOneAsync(Document document, ImmutableArray<Diagnostic> diagnostics, CancellationToken cancellationToken)
protected async Task<Document> FixOneAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken)
{
var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
var changes = new List<TextChange>();
foreach (var diagnostic in diagnostics)
{
if (!diagnostic.Properties.TryGetValue(FormattingDiagnosticAnalyzer.ReplaceTextKey, out var replacement))
{
continue;
}
changes.Add(new TextChange(diagnostic.Location.SourceSpan, replacement));
}
// The span to format is the full line(s) containing the diagnostic
var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
var diagnosticSpan = diagnostic.Location.SourceSpan;
var diagnosticLinePositionSpan = text.Lines.GetLinePositionSpan(diagnosticSpan);
var spanToFormat = TextSpan.FromBounds(
text.Lines[diagnosticLinePositionSpan.Start.Line].Start,
text.Lines[diagnosticLinePositionSpan.End.Line].End);
changes.Sort((left, right) => left.Span.Start.CompareTo(right.Span.Start));
return document.WithText(text.WithChanges(changes));
var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);
return await Formatter.FormatAsync(document, spanToFormat, options, cancellationToken).ConfigureAwait(false);
}
protected override async Task FixAllAsync(Document document, ImmutableArray<Diagnostic> diagnostics, SyntaxEditor editor, CancellationToken cancellationToken)
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Text;
......@@ -12,11 +11,6 @@ namespace Microsoft.CodeAnalysis.Formatting
internal class FormattingDiagnosticAnalyzer
: AbstractCodeStyleDiagnosticAnalyzer
{
public static readonly string ReplaceTextKey = nameof(ReplaceTextKey);
public static readonly ImmutableDictionary<string, string> RemoveTextProperties =
ImmutableDictionary.Create<string, string>().Add(ReplaceTextKey, "");
public FormattingDiagnosticAnalyzer()
: base(
IDEDiagnosticIds.FormattingDiagnosticId,
......@@ -91,23 +85,13 @@ private void AnalyzeSyntaxTree(SyntaxTreeAnalysisContext context)
throw ExceptionUtilities.Unreachable;
}
ImmutableDictionary<string, string> properties;
if (change.NewText.Length == 0)
{
properties = RemoveTextProperties;
}
else
{
properties = ImmutableDictionary.Create<string, string>().Add(ReplaceTextKey, change.NewText);
}
var location = Location.Create(tree, change.Span);
context.ReportDiagnostic(DiagnosticHelper.Create(
Descriptor,
location,
ReportDiagnostic.Default,
additionalLocations: null,
properties));
properties: null));
}
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册