diff --git a/src/EditorFeatures/CSharpTest/AddBraces/AddBracesFixAllTests.cs b/src/EditorFeatures/CSharpTest/AddBraces/AddBracesFixAllTests.cs index bbe422ca5f38c598aaa25a871a0710a8061bf62e..0ab232d635568a57b709b150cb0b9c9d21f796f5 100644 --- a/src/EditorFeatures/CSharpTest/AddBraces/AddBracesFixAllTests.cs +++ b/src/EditorFeatures/CSharpTest/AddBraces/AddBracesFixAllTests.cs @@ -6,6 +6,61 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.AddBraces { public partial class AddBracesTests { + [Fact] + [Trait(Traits.Feature, Traits.Features.CodeActionsAddBraces)] + [Trait(Traits.Feature, Traits.Features.CodeActionsFixAllOccurrences)] + public async Task TestFixAllInDocument1() + { + var input = @" +class Program1 +{ + static void Main() + { + {|FixAllInDocument:if|} (true) if (true) return; + } +} +"; + + var expected = @" +class Program1 +{ + static void Main() + { + if (true) { if (true) { return; } } + } +} +"; + + await TestAsync(input, expected); + } + [Fact] + [Trait(Traits.Feature, Traits.Features.CodeActionsAddBraces)] + [Trait(Traits.Feature, Traits.Features.CodeActionsFixAllOccurrences)] + public async Task TestFixAllInDocument2() + { + var input = @" +class Program1 +{ + static void Main() + { + if (true) {|FixAllInDocument:if|} (true) return; + } +} +"; + + var expected = @" +class Program1 +{ + static void Main() + { + if (true) { if (true) { return; } } + } +} +"; + + await TestAsync(input, expected); + } + [Fact] [Trait(Traits.Feature, Traits.Features.CodeActionsAddBraces)] [Trait(Traits.Feature, Traits.Features.CodeActionsFixAllOccurrences)] diff --git a/src/EditorFeatures/CSharpTest/AddBraces/AddBracesTests.cs b/src/EditorFeatures/CSharpTest/AddBraces/AddBracesTests.cs index cdfb873c06b25952bf37004c195e7a239262b356..6329e94a64fd502e3c18f47faa12980fffaf9fd8 100644 --- a/src/EditorFeatures/CSharpTest/AddBraces/AddBracesTests.cs +++ b/src/EditorFeatures/CSharpTest/AddBraces/AddBracesTests.cs @@ -13,7 +13,8 @@ public partial class AddBracesTests : AbstractCSharpDiagnosticProviderBasedUserD { internal override Tuple CreateDiagnosticProviderAndFixer(Workspace workspace) { - return new Tuple(new CSharpAddBracesDiagnosticAnalyzer(), + return new Tuple( + new CSharpAddBracesDiagnosticAnalyzer(), new CSharpAddBracesCodeFixProvider()); } diff --git a/src/Features/CSharp/Portable/AddBraces/CSharpAddBracesCodeFixProvider.cs b/src/Features/CSharp/Portable/AddBraces/CSharpAddBracesCodeFixProvider.cs index f26193c766dbd552f3f8527607c177188a1e2ffa..15647f9df4b1adaf3e6c6e8ad509beaad4cace2a 100644 --- a/src/Features/CSharp/Portable/AddBraces/CSharpAddBracesCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/AddBraces/CSharpAddBracesCodeFixProvider.cs @@ -8,38 +8,44 @@ using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editing; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Diagnostics.AddBraces { [ExportCodeFixProvider(LanguageNames.CSharp, Name = PredefinedCodeFixProviderNames.AddBraces), Shared] [ExtensionOrder(After = PredefinedCodeFixProviderNames.AddAwait)] - internal class CSharpAddBracesCodeFixProvider : CodeFixProvider + internal class CSharpAddBracesCodeFixProvider : SyntaxEditorBasedCodeFixProvider { - public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(IDEDiagnosticIds.AddBracesDiagnosticId); - - public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; + public override ImmutableArray FixableDiagnosticIds + => ImmutableArray.Create(IDEDiagnosticIds.AddBracesDiagnosticId); public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) { context.RegisterCodeFix( - new MyCodeAction( - FeaturesResources.Add_braces, - c => AddBracesAsync(context, c)), + new MyCodeAction(c => FixAsync(context.Document, context.Diagnostics.First(), c)), context.Diagnostics); return SpecializedTasks.EmptyTask; } - protected async Task AddBracesAsync(CodeFixContext context, CancellationToken cancellationToken) + protected override Task FixAllAsync( + Document document, ImmutableArray diagnostics, + SyntaxEditor editor, CancellationToken cancellationToken) { - var root = await context.Document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var diagnostic = context.Diagnostics.First(); - var diagnosticSpan = diagnostic.Location.SourceSpan; - var statement = root.FindNode(diagnosticSpan); + var root = editor.OriginalRoot; + foreach (var diagnostic in diagnostics) + { + var statement = root.FindNode(diagnostic.Location.SourceSpan); - var newRoot = root.ReplaceNode(statement, GetReplacementNode(statement)); - return context.Document.WithSyntaxRoot(newRoot); + // Use the callback version of ReplaceNode so that we see the effects + // of other replace calls. i.e. we may have statements nested in statements, + // we need to make sure that any inner edits are seen when we make the outer + // replacement. + editor.ReplaceNode(statement, (s, g) => GetReplacementNode(s)); + } + + return SpecializedTasks.EmptyTask; } private SyntaxNode GetReplacementNode(SyntaxNode statement) @@ -83,13 +89,13 @@ private SyntaxNode GetReplacementNode(SyntaxNode statement) return default(SyntaxNode); } - private SyntaxNode GetNewBlock(SyntaxNode statement, StatementSyntax statementBody) => - statement.ReplaceNode(statementBody, SyntaxFactory.Block(statementBody)); + private SyntaxNode GetNewBlock(SyntaxNode statement, StatementSyntax statementBody) + => statement.ReplaceNode(statementBody, SyntaxFactory.Block(statementBody)); private class MyCodeAction : CodeAction.DocumentChangeAction { - public MyCodeAction(string title, Func> createChangedDocument) : - base(title, createChangedDocument) + public MyCodeAction(Func> createChangedDocument) : + base(FeaturesResources.Add_braces, createChangedDocument, FeaturesResources.Add_braces) { } } diff --git a/src/Features/Core/Portable/PopulateSwitch/PopulateSwitchCodeFixProvider.cs b/src/Features/Core/Portable/PopulateSwitch/PopulateSwitchCodeFixProvider.cs index 2d235296f18f1787cdc186d979403b93d06f5782..426da27cfec3f346eb87d4eeeea4e0141ccf9c57 100644 --- a/src/Features/Core/Portable/PopulateSwitch/PopulateSwitchCodeFixProvider.cs +++ b/src/Features/Core/Portable/PopulateSwitch/PopulateSwitchCodeFixProvider.cs @@ -27,7 +27,8 @@ namespace Microsoft.CodeAnalysis.PopulateSwitch [ExtensionOrder(After = PredefinedCodeFixProviderNames.ImplementInterface)] internal class PopulateSwitchCodeFixProvider : CodeFixProvider { - public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(IDEDiagnosticIds.PopulateSwitchDiagnosticId); + public override ImmutableArray FixableDiagnosticIds + => ImmutableArray.Create(IDEDiagnosticIds.PopulateSwitchDiagnosticId); public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer;