diff --git a/src/CodeFixes/CSharp/CodeFixes/UnreachableCodeCodeFixProvider.cs b/src/CodeFixes/CSharp/CodeFixes/UnreachableCodeCodeFixProvider.cs index 0da295b135..4c397adf59 100644 --- a/src/CodeFixes/CSharp/CodeFixes/UnreachableCodeCodeFixProvider.cs +++ b/src/CodeFixes/CSharp/CodeFixes/UnreachableCodeCodeFixProvider.cs @@ -1,9 +1,10 @@ // Copyright (c) Josef Pihrt. 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.Diagnostics; -using System.Linq; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeActions; @@ -68,18 +69,17 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) } else { - SyntaxRemoveOptions removeOptions = SyntaxRefactorings.DefaultRemoveOptions; + int lastIndex = statements.LastIndexOf(f => !f.IsKind(SyntaxKind.LocalFunctionStatement)); - if (statement.GetLeadingTrivia().IsEmptyOrWhitespace()) - removeOptions &= ~SyntaxRemoveOptions.KeepLeadingTrivia; + SyntaxList nodes = RemoveRange(statements, index, lastIndex - index + 1, f => !f.IsKind(SyntaxKind.LocalFunctionStatement)); - if (statements.Last().GetTrailingTrivia().IsEmptyOrWhitespace()) - removeOptions &= ~SyntaxRemoveOptions.KeepTrailingTrivia; - - return context.Document.RemoveNodesAsync(statements.Skip(index), removeOptions, cancellationToken); + return context.Document.ReplaceStatementsAsync( + statementsInfo, + nodes, + cancellationToken); } }, - GetEquivalenceKey(diagnostic)); + base.GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } @@ -210,5 +210,43 @@ private CodeAction CreateCodeAction(Document document, Diagnostic diagnostic, If }, GetEquivalenceKey(diagnostic)); } + + //TODO: move to API + private SyntaxList RemoveRange( + SyntaxList list, + int index, + int count, + Func predicate) where TNode : SyntaxNode + { + return SyntaxFactory.List(RemoveRange()); + + IEnumerable RemoveRange() + { + SyntaxList.Enumerator en = list.GetEnumerator(); + + int i = 0; + + while (i < index + && en.MoveNext()) + { + yield return en.Current; + i++; + } + + int endIndex = index + count; + + while (i < endIndex + && en.MoveNext()) + { + if (!predicate(en.Current)) + yield return en.Current; + + i++; + } + + while (en.MoveNext()) + yield return en.Current; + } + } } } diff --git a/src/Tests/CodeFixes.Tests/CS0162UnreachableCodeDetectedTests.cs b/src/Tests/CodeFixes.Tests/CS0162UnreachableCodeDetectedTests.cs index 1eaab51e56..55cb9eb077 100644 --- a/src/Tests/CodeFixes.Tests/CS0162UnreachableCodeDetectedTests.cs +++ b/src/Tests/CodeFixes.Tests/CS0162UnreachableCodeDetectedTests.cs @@ -42,6 +42,94 @@ int M() return 0; } } +", equivalenceKey: EquivalenceKey.Create(DiagnosticId)); + } + + [Fact, Trait(Traits.CodeFix, CompilerDiagnosticIdentifiers.UnreachableCodeDetected)] + public async Task Test_LocalFunction() + { + await VerifyFixAsync(@" +class C +{ + void M() + { + LF(); + + return; + + LF(); + + void LF() + { + return; + } + } +} +", @" +class C +{ + void M() + { + LF(); + + return; + + void LF() + { + return; + } + } +} +", equivalenceKey: EquivalenceKey.Create(DiagnosticId)); + } + + [Fact, Trait(Traits.CodeFix, CompilerDiagnosticIdentifiers.UnreachableCodeDetected)] + public async Task Test_LocalFunction2() + { + await VerifyFixAsync(@" +class C +{ + void M() + { + LF(); + + return; + + LF(); + + void LF() + { + return; + } + + LF2(); + + void LF2() + { + return; + } + } +} +", @" +class C +{ + void M() + { + LF(); + + return; + + void LF() + { + return; + } + + void LF2() + { + return; + } + } +} ", equivalenceKey: EquivalenceKey.Create(DiagnosticId)); } }