提交 eb391d03 编写于 作者: J JieCarolHu 提交者: Sam Harwell

refactoring

上级 c9310c78
......@@ -196,8 +196,13 @@ protected static async Task AssertCodeCleanupResult(string expected, string code
var document = workspace.CurrentSolution.GetDocument(hostdoc.Id);
var codeCleanupService = document.GetLanguageService<ICodeCleanupService>();
var docOptions = await document.GetOptionsAsync(CancellationToken.None).ConfigureAwait(false);
var organizeUsingsSet = new OrganizeUsingsSet(docOptions);
var enabledDiagnostics = codeCleanupService.GetEnabledDiagnostics(docOptions);
var newDoc = await codeCleanupService.CleanupAsync(
document, new ProgressTracker(), CancellationToken.None);
document, organizeUsingsSet, enabledDiagnostics, new ProgressTracker(), CancellationToken.None);
var actual = await newDoc.GetTextAsync();
......
......@@ -9,7 +9,6 @@
using Microsoft.CodeAnalysis.Experiments;
using Microsoft.CodeAnalysis.Extensions;
using Microsoft.CodeAnalysis.Internal.Log;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.Utilities;
using Microsoft.CodeAnalysis.Text;
......@@ -189,8 +188,12 @@ private static bool TurnOnCodeCleanupForGroupBIfInABTest(Document document, Work
Document document, ICodeCleanupService codeCleanupService,
IProgressTracker progressTracker, CancellationToken cancellationToken)
{
var docOptions = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);
var organizeUsingsSet = new OrganizeUsingsSet(docOptions);
var enabledDiagnostics = codeCleanupService.GetEnabledDiagnostics(docOptions);
var newDoc = await codeCleanupService.CleanupAsync(
document, progressTracker, cancellationToken).ConfigureAwait(false);
document, organizeUsingsSet, enabledDiagnostics, progressTracker, cancellationToken).ConfigureAwait(false);
var changes = await newDoc.GetTextChangesAsync(document, cancellationToken).ConfigureAwait(false);
return changes.ToImmutableArrayOrEmpty();
......
......@@ -34,85 +34,80 @@ internal class CSharpCodeCleanupService : ICodeCleanupService
[Import(AllowDefault = true)] ICodeFixService codeFixService)
{
_codeFixServiceOpt = codeFixService;
}
}
/// <summary>
/// Maps format document code cleanup options to DiagnosticId[]
/// </summary>
private static ImmutableArray<(string description, PerLanguageOption<bool> option, ImmutableArray<string> diagnosticIds)> _optionDiagnosticsMappings =
ImmutableArray.Create(
(CSharpFeaturesResources.Apply_implicit_explicit_type_preferences,
CodeCleanupOptions.ApplyImplicitExplicitTypePreferences,
ImmutableArray.Create(IDEDiagnosticIds.UseImplicitTypeDiagnosticId,
IDEDiagnosticIds.UseExplicitTypeDiagnosticId)),
(CSharpFeaturesResources.Apply_this_qualification_preferences,
CodeCleanupOptions.ApplyThisQualificationPreferences,
ImmutableArray.Create(IDEDiagnosticIds.AddQualificationDiagnosticId,
IDEDiagnosticIds.RemoveQualificationDiagnosticId)),
(CSharpFeaturesResources.Apply_language_framework_type_preferences,
CodeCleanupOptions.ApplyLanguageFrameworkTypePreferences,
ImmutableArray.Create(IDEDiagnosticIds.PreferBuiltInOrFrameworkTypeDiagnosticId)),
(CSharpFeaturesResources.Add_remove_braces_for_single_line_control_statements,
CodeCleanupOptions.AddRemoveBracesForSingleLineControlStatements,
ImmutableArray.Create(IDEDiagnosticIds.AddBracesDiagnosticId)),
(CSharpFeaturesResources.Add_accessibility_modifiers,
CodeCleanupOptions.AddAccessibilityModifiers,
ImmutableArray.Create(IDEDiagnosticIds.AddAccessibilityModifiersDiagnosticId)),
(CSharpFeaturesResources.Sort_accessibility_modifiers,
CodeCleanupOptions.SortAccessibilityModifiers,
ImmutableArray.Create(IDEDiagnosticIds.OrderModifiersDiagnosticId)),
(CSharpFeaturesResources.Make_private_field_readonly_when_possible,
CodeCleanupOptions.MakePrivateFieldReadonlyWhenPossible,
ImmutableArray.Create(IDEDiagnosticIds.MakeFieldReadonlyDiagnosticId)),
(CSharpFeaturesResources.Remove_unnecessary_casts,
CodeCleanupOptions.RemoveUnnecessaryCasts,
ImmutableArray.Create(IDEDiagnosticIds.RemoveUnnecessaryCastDiagnosticId)),
(CSharpFeaturesResources.Apply_expression_block_body_preferences,
CodeCleanupOptions.ApplyExpressionBlockBodyPreferences,
ImmutableArray.Create(IDEDiagnosticIds.UseExpressionBodyForConstructorsDiagnosticId,
IDEDiagnosticIds.UseExpressionBodyForMethodsDiagnosticId,
IDEDiagnosticIds.UseExpressionBodyForConversionOperatorsDiagnosticId,
IDEDiagnosticIds.UseExpressionBodyForOperatorsDiagnosticId,
IDEDiagnosticIds.UseExpressionBodyForPropertiesDiagnosticId,
IDEDiagnosticIds.UseExpressionBodyForIndexersDiagnosticId,
IDEDiagnosticIds.UseExpressionBodyForAccessorsDiagnosticId)),
(CSharpFeaturesResources.Apply_inline_out_variable_preferences,
CodeCleanupOptions.ApplyInlineOutVariablePreferences,
ImmutableArray.Create(IDEDiagnosticIds.InlineDeclarationDiagnosticId)),
(CSharpFeaturesResources.Remove_unused_variables,
CodeCleanupOptions.RemoveUnusedVariables,
ImmutableArray.Create(CSharpRemoveUnusedVariableCodeFixProvider.CS0168,
CSharpRemoveUnusedVariableCodeFixProvider.CS0219)),
(CSharpFeaturesResources.Apply_object_collection_initialization_preferences,
CodeCleanupOptions.ApplyObjectCollectionInitializationPreferences,
ImmutableArray.Create(IDEDiagnosticIds.UseObjectInitializerDiagnosticId,
IDEDiagnosticIds.UseCollectionInitializerDiagnosticId))
private static ImmutableArray<(DiagnosticSet diagnosticSet, PerLanguageOption<bool> option)> _optionDiagnosticsMappings =
ImmutableArray.Create(
(new DiagnosticSet(CSharpFeaturesResources.Apply_implicit_explicit_type_preferences,
new[] { IDEDiagnosticIds.UseImplicitTypeDiagnosticId, IDEDiagnosticIds.UseExplicitTypeDiagnosticId }),
CodeCleanupOptions.ApplyImplicitExplicitTypePreferences),
(new DiagnosticSet(CSharpFeaturesResources.Apply_this_qualification_preferences,
new[] { IDEDiagnosticIds.AddQualificationDiagnosticId, IDEDiagnosticIds.RemoveQualificationDiagnosticId }),
CodeCleanupOptions.ApplyThisQualificationPreferences),
(new DiagnosticSet(CSharpFeaturesResources.Apply_language_framework_type_preferences,
new[] { IDEDiagnosticIds.PreferBuiltInOrFrameworkTypeDiagnosticId }),
CodeCleanupOptions.ApplyLanguageFrameworkTypePreferences),
(new DiagnosticSet(CSharpFeaturesResources.Add_remove_braces_for_single_line_control_statements,
new[] { IDEDiagnosticIds.AddBracesDiagnosticId }),
CodeCleanupOptions.AddRemoveBracesForSingleLineControlStatements),
(new DiagnosticSet(CSharpFeaturesResources.Add_accessibility_modifiers,
new[] { IDEDiagnosticIds.AddAccessibilityModifiersDiagnosticId}),
CodeCleanupOptions.AddAccessibilityModifiers),
(new DiagnosticSet(CSharpFeaturesResources.Sort_accessibility_modifiers,
new[] { IDEDiagnosticIds.OrderModifiersDiagnosticId }),
CodeCleanupOptions.SortAccessibilityModifiers),
(new DiagnosticSet(CSharpFeaturesResources.Make_private_field_readonly_when_possible,
new[] { IDEDiagnosticIds.MakeFieldReadonlyDiagnosticId }),
CodeCleanupOptions.MakePrivateFieldReadonlyWhenPossible),
(new DiagnosticSet(CSharpFeaturesResources.Remove_unnecessary_casts,
new[] { IDEDiagnosticIds.RemoveUnnecessaryCastDiagnosticId }),
CodeCleanupOptions.RemoveUnnecessaryCasts),
(new DiagnosticSet(CSharpFeaturesResources.Apply_expression_block_body_preferences,
new[] {IDEDiagnosticIds.UseExpressionBodyForConstructorsDiagnosticId,
IDEDiagnosticIds.UseExpressionBodyForMethodsDiagnosticId,
IDEDiagnosticIds.UseExpressionBodyForConversionOperatorsDiagnosticId,
IDEDiagnosticIds.UseExpressionBodyForOperatorsDiagnosticId,
IDEDiagnosticIds.UseExpressionBodyForPropertiesDiagnosticId,
IDEDiagnosticIds.UseExpressionBodyForIndexersDiagnosticId,
IDEDiagnosticIds.UseExpressionBodyForAccessorsDiagnosticId}),
CodeCleanupOptions.ApplyExpressionBlockBodyPreferences),
(new DiagnosticSet(CSharpFeaturesResources.Apply_inline_out_variable_preferences,
new[] { IDEDiagnosticIds.InlineDeclarationDiagnosticId }),
CodeCleanupOptions.ApplyInlineOutVariablePreferences),
(new DiagnosticSet(CSharpFeaturesResources.Remove_unused_variables,
new[] { CSharpRemoveUnusedVariableCodeFixProvider.CS0168, CSharpRemoveUnusedVariableCodeFixProvider.CS0219 }),
CodeCleanupOptions.RemoveUnusedVariables),
(new DiagnosticSet(CSharpFeaturesResources.Apply_object_collection_initialization_preferences,
new[] { IDEDiagnosticIds.UseObjectInitializerDiagnosticId, IDEDiagnosticIds.UseCollectionInitializerDiagnosticId }),
CodeCleanupOptions.ApplyObjectCollectionInitializationPreferences)
);
public async Task<Document> CleanupAsync(
Document document, IProgressTracker progressTracker, CancellationToken cancellationToken)
Document document,
OrganizeUsingsSet organizeUsingsSet,
ImmutableArray<DiagnosticSet> enabledDiagnostics,
IProgressTracker progressTracker,
CancellationToken cancellationToken)
{
var docOptions = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);
// add one item for the 'format' action we'll do last
progressTracker.AddItems(1);
// and one for 'remove/sort usings' if we're going to run that.
var organizeUsings = docOptions.GetOption(CodeCleanupOptions.RemoveUnusedImports) ||
docOptions.GetOption(CodeCleanupOptions.SortImports);
if (organizeUsings)
if (organizeUsingsSet.IsEnabled)
{
progressTracker.AddItems(1);
}
......@@ -120,15 +115,15 @@ internal class CSharpCodeCleanupService : ICodeCleanupService
if (_codeFixServiceOpt != null)
{
document = await ApplyCodeFixesAsync(
document, docOptions, progressTracker, cancellationToken).ConfigureAwait(false);
document, enabledDiagnostics, progressTracker, cancellationToken).ConfigureAwait(false);
}
// do the remove usings after code fix, as code fix might remove some code which can results in unused usings.
if (organizeUsings)
if (organizeUsingsSet.IsEnabled)
{
progressTracker.Description = CSharpFeaturesResources.Organize_Usings;
document = await RemoveSortUsingsAsync(
document, docOptions, cancellationToken).ConfigureAwait(false);
document, organizeUsingsSet, cancellationToken).ConfigureAwait(false);
progressTracker.ItemCompleted();
}
......@@ -142,9 +137,9 @@ internal class CSharpCodeCleanupService : ICodeCleanupService
}
private async Task<Document> RemoveSortUsingsAsync(
Document document, DocumentOptionSet docOptions, CancellationToken cancellationToken)
Document document, OrganizeUsingsSet organizeUsingsSet, CancellationToken cancellationToken)
{
if (docOptions.GetOption(CodeCleanupOptions.RemoveUnusedImports))
if (organizeUsingsSet.IsRemoveUnusedImportEnabled)
{
var removeUsingsService = document.GetLanguageService<IRemoveUnnecessaryImportsService>();
if (removeUsingsService != null)
......@@ -156,7 +151,7 @@ internal class CSharpCodeCleanupService : ICodeCleanupService
}
}
if (docOptions.GetOption(CodeCleanupOptions.SortImports))
if (organizeUsingsSet.IsSortImportsEnabled)
{
using (Logger.LogBlock(FunctionId.CodeCleanup_SortImports, cancellationToken))
{
......@@ -168,21 +163,19 @@ internal class CSharpCodeCleanupService : ICodeCleanupService
}
private async Task<Document> ApplyCodeFixesAsync(
Document document, DocumentOptionSet docOptions,
Document document, ImmutableArray<DiagnosticSet> enabledDiagnosticSets,
IProgressTracker progressTracker, CancellationToken cancellationToken)
{
var enabledOptions = GetEnabledOptions(docOptions);
// Add a progress item for each enabled option we're going to fixup.
progressTracker.AddItems(enabledOptions.Length);
progressTracker.AddItems(enabledDiagnosticSets.Length);
foreach (var (description, diagnosticIds) in enabledOptions)
foreach (var diagnosticSet in enabledDiagnosticSets)
{
cancellationToken.ThrowIfCancellationRequested();
progressTracker.Description = description;
progressTracker.Description = diagnosticSet.Description;
document = await ApplyCodeFixesForSpecificDiagnosticIds(
document, diagnosticIds, cancellationToken).ConfigureAwait(false);
document, diagnosticSet.DiagnosticIds, cancellationToken).ConfigureAwait(false);
// Mark this option as being completed.
progressTracker.ItemCompleted();
......@@ -206,19 +199,24 @@ internal class CSharpCodeCleanupService : ICodeCleanupService
return document;
}
private ImmutableArray<(string description, ImmutableArray<string> diagnosticIds)> GetEnabledOptions(DocumentOptionSet docOptions)
public ImmutableArray<DiagnosticSet> GetAllDiagnostics()
{
var result = ArrayBuilder<(string description, ImmutableArray<string> diagnosticIds)>.GetInstance();
return _optionDiagnosticsMappings.SelectAsArray(i => i.diagnosticSet);
}
public ImmutableArray<DiagnosticSet> GetEnabledDiagnostics(DocumentOptionSet docOptions)
{
var result = ArrayBuilder<DiagnosticSet>.GetInstance();
foreach (var (description, option, diagnosticIds) in _optionDiagnosticsMappings)
foreach (var (diagnosticSet, option) in _optionDiagnosticsMappings)
{
if (docOptions.GetOption(option))
{
result.AddRange((description, diagnosticIds));
result.AddRange(diagnosticSet);
}
}
return result.ToImmutableAndFree();
}
}
}
}
// 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;
namespace Microsoft.CodeAnalysis.CodeCleanup
{
internal class DiagnosticSet
{
public string Description { get; private set; }
public ImmutableArray<string> DiagnosticIds { get; private set; }
public DiagnosticSet (string description, string[] diagnosticIds)
{
Description = description;
DiagnosticIds = ImmutableArray.Create(diagnosticIds);
}
}
}
// 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 System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Utilities;
namespace Microsoft.CodeAnalysis.CodeCleanup
{
internal interface ICodeCleanupService : ILanguageService
{
Task<Document> CleanupAsync(Document document, IProgressTracker progressTracker, CancellationToken cancellationToken);
Task<Document> CleanupAsync(Document document, OrganizeUsingsSet organizeUsingsSet, ImmutableArray<DiagnosticSet> enabledDiagnostics, IProgressTracker progressTracker, CancellationToken cancellationToken);
ImmutableArray<DiagnosticSet> GetAllDiagnostics();
ImmutableArray<DiagnosticSet> GetEnabledDiagnostics(DocumentOptionSet docOptions);
}
}
// 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.Options;
namespace Microsoft.CodeAnalysis.CodeCleanup
{
internal class OrganizeUsingsSet
{
public bool IsRemoveUnusedImportEnabled { get; private set; }
public bool IsSortImportsEnabled { get; private set; }
public bool IsEnabled { get { return IsRemoveUnusedImportEnabled || IsSortImportsEnabled; } }
public OrganizeUsingsSet(DocumentOptionSet docOptions)
{
IsRemoveUnusedImportEnabled = docOptions.GetOption(CodeCleanupOptions.RemoveUnusedImports);
IsSortImportsEnabled = docOptions.GetOption(CodeCleanupOptions.SortImports);
}
public OrganizeUsingsSet(bool isRemoveUnusedImportEnabled, bool isSortImportsEnabled)
{
IsRemoveUnusedImportEnabled = isRemoveUnusedImportEnabled;
IsSortImportsEnabled = IsSortImportsEnabled;
}
}
}
......@@ -7,15 +7,15 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeCleanup;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp.RemoveUnusedVariable;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor;
using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
using Microsoft.CodeAnalysis.Internal.Log;
using Microsoft.CodeAnalysis.OrganizeImports;
using Microsoft.CodeAnalysis.RemoveUnnecessaryImports;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.Utilities;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.Editor.CodeCleanup;
using Microsoft.VisualStudio.Language.CodeCleanUp;
......@@ -99,64 +99,30 @@ public override async Task<bool> FixAsync(ICodeCleanUpScope scope, FixIdContaine
var buffer = textBufferScope.SubjectBuffer;
if (buffer != null)
{
var progressTracker = new ProgressTracker();
var document = buffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges();
await CleanupDocument(document, cancellationToken).ConfigureAwait(false);
}
}
return false;
}
private async Task<bool> CleanupDocument(Document document, CancellationToken cancellationToken)
{
var oldDoc = document;
foreach (var errorCode in _errorCodes)
{
document = await _codeFixServiceOpt.ApplyCodeFixesForSpecificDiagnosticId(document, errorCode, cancellationToken).ConfigureAwait(true);
}
document = await RemoveAndSortUsingsAsync(document, cancellationToken).ConfigureAwait(true);
var codeCleanupChanges = await document.GetTextChangesAsync(oldDoc, cancellationToken).ConfigureAwait(false);
if (codeCleanupChanges != null && codeCleanupChanges.Any())
{
//progressTracker.Description = EditorFeaturesResources.Applying_changes;
using (Logger.LogBlock(FunctionId.Formatting_ApplyResultToBuffer, cancellationToken))
{
document.Project.Solution.Workspace.ApplyTextChanges(document.Id, codeCleanupChanges, cancellationToken);
}
var codeCleanupService = document.GetLanguageService<ICodeCleanupService>();
return true;
}
var organizeUsingsSet = new OrganizeUsingsSet(true, true);
var enabledDiagnostics = codeCleanupService.GetAllDiagnostics();
return false;
}
var newDoc = await codeCleanupService.CleanupAsync(
document, organizeUsingsSet, enabledDiagnostics, progressTracker, cancellationToken);
private async Task<Document> RemoveAndSortUsingsAsync(Document document, CancellationToken cancellationToken)
{
// removing unused usings:
if (_errorCodes.Contains(RemoveUnusedImports))
{
var removeUsingsService = document.GetLanguageService<IRemoveUnnecessaryImportsService>();
if (removeUsingsService != null)
{
using (Logger.LogBlock(FunctionId.CodeCleanup_RemoveUnusedImports, cancellationToken))
var codeCleanupChanges = await newDoc.GetTextChangesAsync(document, cancellationToken).ConfigureAwait(false);
if (codeCleanupChanges != null && codeCleanupChanges.Any())
{
document = await removeUsingsService.RemoveUnnecessaryImportsAsync(document, cancellationToken).ConfigureAwait(false);
}
}
}
progressTracker.Description = EditorFeaturesResources.Applying_changes;
using (Logger.LogBlock(FunctionId.Formatting_ApplyResultToBuffer, cancellationToken))
{
newDoc.Project.Solution.Workspace.ApplyTextChanges(newDoc.Id, codeCleanupChanges, cancellationToken);
}
// sort usings:
if (_errorCodes.Contains(SortImports))
{
using (Logger.LogBlock(FunctionId.CodeCleanup_SortImports, cancellationToken))
{
document = await OrganizeImportsService.OrganizeImportsAsync(document, cancellationToken).ConfigureAwait(false);
return true;
}
}
}
return document;
return false;
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册