提交 c74f16af 编写于 作者: S Sam Harwell

Share FormattingAnalyzerHelper and FormattingCodeFixHelper

上级 58e94d2d
......@@ -2,20 +2,26 @@
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Text;
#if CODE_STYLE
using FormatterState = Microsoft.CodeAnalysis.Formatting.ISyntaxFormattingService;
#else
using Microsoft.CodeAnalysis.Options;
using FormatterState = Microsoft.CodeAnalysis.Workspace;
#endif
namespace Microsoft.CodeAnalysis.CodeStyle
{
internal static class FormattingAnalyzerHelper
{
internal static void AnalyzeSyntaxTree(SyntaxTreeAnalysisContext context, ISyntaxFormattingService syntaxFormattingService, DiagnosticDescriptor descriptor, OptionSet options)
internal static void AnalyzeSyntaxTree(SyntaxTreeAnalysisContext context, FormatterState formatterState, DiagnosticDescriptor descriptor, OptionSet options)
{
var tree = context.Tree;
var cancellationToken = context.CancellationToken;
var oldText = tree.GetText(cancellationToken);
var formattingChanges = Formatter.GetFormattedTextChanges(tree.GetRoot(cancellationToken), syntaxFormattingService, options, cancellationToken);
var formattingChanges = Formatter.GetFormattedTextChanges(tree.GetRoot(cancellationToken), formatterState, options, cancellationToken);
// formattingChanges could include changes that impact a larger section of the original document than
// necessary. Before reporting diagnostics, process the changes to minimize the span of individual
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#if CODE_STYLE
extern alias CodeStyle;
#endif
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.Text;
#if CODE_STYLE
using Formatter = CodeStyle::Microsoft.CodeAnalysis.Formatting.Formatter;
using FormatterState = Microsoft.CodeAnalysis.Formatting.ISyntaxFormattingService;
#else
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.Options;
using FormatterState = Microsoft.CodeAnalysis.Workspace;
#endif
namespace Microsoft.CodeAnalysis
{
extern alias CodeStyle;
using Formatter = CodeStyle::Microsoft.CodeAnalysis.Formatting.Formatter;
internal static class FormattingCodeFixHelper
{
internal static async Task<SyntaxTree> FixOneAsync(SyntaxTree syntaxTree, ISyntaxFormattingService syntaxFormattingService, OptionSet options, Diagnostic diagnostic, CancellationToken cancellationToken)
internal static async Task<SyntaxTree> FixOneAsync(SyntaxTree syntaxTree, FormatterState formatterState, OptionSet options, Diagnostic diagnostic, CancellationToken cancellationToken)
{
// The span to format is the full line(s) containing the diagnostic
var text = await syntaxTree.GetTextAsync(cancellationToken).ConfigureAwait(false);
......@@ -22,7 +31,14 @@ internal static async Task<SyntaxTree> FixOneAsync(SyntaxTree syntaxTree, ISynta
text.Lines[diagnosticLinePositionSpan.Start.Line].Start,
text.Lines[diagnosticLinePositionSpan.End.Line].End);
return await Formatter.FormatAsync(syntaxTree, syntaxFormattingService, spanToFormat, options, cancellationToken).ConfigureAwait(false);
var root = await syntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false);
#if CODE_STYLE
var formattedRoot = Formatter.Format(root, formatterState, new[] { spanToFormat }, options, Formatter.GetDefaultFormattingRules(formatterState), cancellationToken);
#else
var formattedRoot = await Formatter.FormatAsync(root, spanToFormat, formatterState, options, cancellationToken).ConfigureAwait(false);
#endif
return syntaxTree.WithRootAndOptions(formattedRoot, syntaxTree.Options);
}
}
}
......@@ -7,6 +7,7 @@
<OutputType>Library</OutputType>
<RootNamespace>Microsoft.CodeAnalysis</RootNamespace>
<TargetFramework>netstandard1.3</TargetFramework>
<DefineConstants>$(DefineConstants),CODE_STYLE</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\..\..\Features\Core\Portable\CodeFixes\PredefinedCodeFixProviderNames.cs" Link="PredefinedCodeFixProviderNames.cs" />
......
// 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 Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.CodeStyle
{
internal static class FormattingAnalyzerHelper
{
internal static void AnalyzeSyntaxTree(SyntaxTreeAnalysisContext context, DiagnosticDescriptor descriptor, Workspace workspace, OptionSet options)
{
var tree = context.Tree;
var cancellationToken = context.CancellationToken;
var oldText = tree.GetText(cancellationToken);
var formattingChanges = Formatter.GetFormattedTextChanges(tree.GetRoot(cancellationToken), workspace, options, cancellationToken);
// formattingChanges could include changes that impact a larger section of the original document than
// necessary. Before reporting diagnostics, process the changes to minimize the span of individual
// diagnostics.
foreach (var formattingChange in formattingChanges)
{
var change = formattingChange;
if (change.NewText.Length > 0 && !change.Span.IsEmpty)
{
// Handle cases where the change is a substring removal from the beginning. In these cases, we want
// the diagnostic span to cover the unwanted leading characters (which should be removed), and
// nothing more.
var offset = change.Span.Length - change.NewText.Length;
if (offset >= 0)
{
if (oldText.GetSubText(new TextSpan(change.Span.Start + offset, change.NewText.Length)).ContentEquals(SourceText.From(change.NewText)))
{
change = new TextChange(new TextSpan(change.Span.Start, offset), "");
}
else
{
// Handle cases where the change is a substring removal from the end. In these cases, we want
// the diagnostic span to cover the unwanted trailing characters (which should be removed), and
// nothing more.
if (oldText.GetSubText(new TextSpan(change.Span.Start, change.NewText.Length)).ContentEquals(SourceText.From(change.NewText)))
{
change = new TextChange(new TextSpan(change.Span.Start + change.NewText.Length, offset), "");
}
}
}
}
if (change.NewText.Length == 0 && change.Span.IsEmpty)
{
// No actual change (allows for the formatter to report a NOP change without triggering a
// diagnostic that can't be fixed).
continue;
}
var location = Location.Create(tree, change.Span);
context.ReportDiagnostic(Diagnostic.Create(
descriptor,
location,
additionalLocations: null,
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.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis
{
internal static class FormattingCodeFixHelper
{
internal static async Task<Document> FixOneAsync(Document document, OptionSet options, Diagnostic diagnostic, CancellationToken cancellationToken)
{
var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
// 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);
return await Formatter.FormatAsync(document, spanToFormat, options, cancellationToken).ConfigureAwait(false);
}
}
}
......@@ -34,7 +34,9 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
private static async Task<Document> FixOneAsync(CodeFixContext context, Diagnostic diagnostic, CancellationToken cancellationToken)
{
var options = await context.Document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);
return await FormattingCodeFixHelper.FixOneAsync(context.Document, options, diagnostic, cancellationToken).ConfigureAwait(false);
var tree = await context.Document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
var formattedTree = await FormattingCodeFixHelper.FixOneAsync(tree, context.Document.Project.Solution.Workspace, options, diagnostic, cancellationToken).ConfigureAwait(false);
return context.Document.WithSyntaxRoot(await formattedTree.GetRootAsync(cancellationToken).ConfigureAwait(false));
}
protected override async Task FixAllAsync(Document document, ImmutableArray<Diagnostic> diagnostics, SyntaxEditor editor, CancellationToken cancellationToken)
......
......@@ -43,7 +43,7 @@ private void AnalyzeSyntaxTree(SyntaxTreeAnalysisContext context)
}
var workspace = workspaceAnalyzerOptions.Services.Workspace;
FormattingAnalyzerHelper.AnalyzeSyntaxTree(context, Descriptor, workspace, options);
FormattingAnalyzerHelper.AnalyzeSyntaxTree(context, workspace, Descriptor, options);
}
}
}
......@@ -97,6 +97,8 @@
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\..\CodeStyle\Core\Analyzers\AbstractCodeStyleDiagnosticAnalyzer.cs" Link="CodeStyle\AbstractCodeStyleDiagnosticAnalyzer.cs" />
<Compile Include="..\..\..\CodeStyle\Core\Analyzers\FormattingAnalyzerHelper.cs" Link="Formatting\FormattingAnalyzerHelper.cs" />
<Compile Include="..\..\..\CodeStyle\Core\CodeFixes\FormattingCodeFixHelper.cs" Link="Formatting\FormattingCodeFixHelper.cs" />
<Compile Include="..\..\..\Compilers\Core\Portable\Text\TextUtilities.cs" Link="Shared\Utilities\TextUtilities.cs" />
<Compile Include="..\..\..\Compilers\Shared\DesktopShim.cs">
<Link>Shared\Utilities\DesktopShim.cs</Link>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册