Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a fixer for CA2200 #2873

Merged
merged 2 commits into from Sep 30, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -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
{
/// <summary>
/// CA2200: Rethrow to preserve stack details
/// </summary>
[ExportCodeFixProvider(LanguageNames.CSharp, LanguageNames.VisualBasic, Name = RethrowToPreserveStackDetailsAnalyzer.RuleId), Shared]
public sealed class RethrowToPreserveStackDetailsFixer : CodeFixProvider
{
public sealed override ImmutableArray<string> 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<Document> 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);
}
}
}
@@ -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
"
);
}
}
}