From 6c0eca6a7e43244336f0e58173dd7b21d1b222ee Mon Sep 17 00:00:00 2001 From: Yufei Zhang Date: Sun, 29 Sep 2019 12:58:31 +0800 Subject: [PATCH] Add a fixer for CA2200 --- .../RethrowToPreserveStackDetails.Fixer.cs | 58 +++++++++++ ...ethrowToPreserveStackDetailsTests.Fixer.cs | 95 +++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 src/Microsoft.CodeQuality.Analyzers/Core/QualityGuidelines/RethrowToPreserveStackDetails.Fixer.cs create mode 100644 src/Microsoft.CodeQuality.Analyzers/UnitTests/QualityGuidelines/RethrowToPreserveStackDetailsTests.Fixer.cs diff --git a/src/Microsoft.CodeQuality.Analyzers/Core/QualityGuidelines/RethrowToPreserveStackDetails.Fixer.cs b/src/Microsoft.CodeQuality.Analyzers/Core/QualityGuidelines/RethrowToPreserveStackDetails.Fixer.cs new file mode 100644 index 0000000000..261ea10081 --- /dev/null +++ b/src/Microsoft.CodeQuality.Analyzers/Core/QualityGuidelines/RethrowToPreserveStackDetails.Fixer.cs @@ -0,0 +1,58 @@ +using System.Collections.Immutable; +using System.Composition; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Formatting; + +namespace Microsoft.CodeQuality.Analyzers.QualityGuidelines +{ + /// + /// CA2200: Rethrow to preserve stack details + /// + [ExportCodeFixProvider(LanguageNames.CSharp, LanguageNames.VisualBasic, Name = RethrowToPreserveStackDetailsAnalyzer.RuleId), Shared] + public sealed class RethrowToPreserveStackDetailsFixer : CodeFixProvider + { + public sealed override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(RethrowToPreserveStackDetailsAnalyzer.RuleId); + + public sealed override FixAllProvider GetFixAllProvider() + { + // See https://github.com/dotnet/roslyn/blob/master/docs/analyzers/FixAllProvider.md for more information on Fix All Providers' + return WellKnownFixAllProviders.BatchFixer; + } + public async sealed override Task RegisterCodeFixesAsync(CodeFixContext context) + { + var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); + var diagnostics = context.Diagnostics; + + var nodeToReplace = root.FindNode(context.Span); + if (nodeToReplace == null) + { + return; + } + // Register a code action that will invoke the fix. + context.RegisterCodeFix( + CodeAction.Create( + title: MicrosoftCodeQualityAnalyzersResources.RethrowToPreserveStackDetailsTitle, + createChangedDocument: c => MakeThrowAsync(context.Document, nodeToReplace, c), + equivalenceKey: nameof(RethrowToPreserveStackDetailsFixer)), + diagnostics); + } + + private async Task MakeThrowAsync(Document document, SyntaxNode nodeToReplace, CancellationToken cancellationToken) + { + var formattednewLocal = SyntaxGenerator.GetGenerator(document).ThrowStatement() + .WithLeadingTrivia(nodeToReplace.GetLeadingTrivia()) + .WithTrailingTrivia(nodeToReplace.GetTrailingTrivia()) + .WithAdditionalAnnotations(Formatter.Annotation); + + var oldRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var newRoot = oldRoot.ReplaceNode(nodeToReplace, formattednewLocal); + + return document.WithSyntaxRoot(newRoot); + } + } +} diff --git a/src/Microsoft.CodeQuality.Analyzers/UnitTests/QualityGuidelines/RethrowToPreserveStackDetailsTests.Fixer.cs b/src/Microsoft.CodeQuality.Analyzers/UnitTests/QualityGuidelines/RethrowToPreserveStackDetailsTests.Fixer.cs new file mode 100644 index 0000000000..4d075b847e --- /dev/null +++ b/src/Microsoft.CodeQuality.Analyzers/UnitTests/QualityGuidelines/RethrowToPreserveStackDetailsTests.Fixer.cs @@ -0,0 +1,95 @@ +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Testing; +using Xunit; +using VerifyCS = Test.Utilities.CSharpCodeFixVerifier< + Microsoft.CodeQuality.CSharp.Analyzers.QualityGuidelines.CSharpRethrowToPreserveStackDetailsAnalyzer, + Microsoft.CodeQuality.Analyzers.QualityGuidelines.RethrowToPreserveStackDetailsFixer>; +using VerifyVB = Test.Utilities.VisualBasicCodeFixVerifier< + Microsoft.CodeQuality.VisualBasic.Analyzers.QualityGuidelines.BasicRethrowToPreserveStackDetailsAnalyzer, + Microsoft.CodeQuality.Analyzers.QualityGuidelines.RethrowToPreserveStackDetailsFixer>; + +namespace Microsoft.CodeQuality.Analyzers.UnitTests.QualityGuidelines +{ + public class RethrowToPreserveStackDetailsTests + { + [Fact] + public async Task TestCSharp_RethrowExplicitlyToThrowImplicitly() + { + await VerifyCS.VerifyCodeFixAsync(@" +using System; + +class Program +{ + void CatchAndRethrowExplicitly() + { + try + { + ThrowException(); + } + catch (ArithmeticException e) + { + throw e; //Some comments + } + } + + void ThrowException() + { + throw new ArithmeticException(); + } +}", new DiagnosticResult(CSharp.Analyzers.QualityGuidelines.CSharpRethrowToPreserveStackDetailsAnalyzer.Rule).WithLocation(14, 13), +@" +using System; + +class Program +{ + void CatchAndRethrowExplicitly() + { + try + { + ThrowException(); + } + catch (ArithmeticException e) + { + throw; //Some comments + } + } + + void ThrowException() + { + throw new ArithmeticException(); + } +}"); + } + [Fact] + public async Task TestBasic_RethrowExplicitlyToThrowImplicitly() + { + await VerifyVB.VerifyCodeFixAsync(@" +Imports System +Class Program + Sub CatchAndRethrowExplicitly() + Try + Throw New ArithmeticException() + Catch e As ArithmeticException + Throw e 'Some comment + End Try + End Sub +End Class +", new DiagnosticResult(VisualBasic.Analyzers.QualityGuidelines.BasicRethrowToPreserveStackDetailsAnalyzer.Rule).WithLocation(8, 13), + @" +Imports System +Class Program + Sub CatchAndRethrowExplicitly() + Try + Throw New ArithmeticException() + Catch e As ArithmeticException + Throw 'Some comment + End Try + End Sub +End Class +" + ); + } + } +} + +