Allow to apply code fix in top-level statements

This commit is contained in:
Gérald Barré 2023-02-19 15:03:45 -05:00 committed by Phil Scott
parent 819b948e78
commit 955fe07bac
4 changed files with 45 additions and 10 deletions

View File

@ -69,8 +69,8 @@ public class SwitchToAnsiConsoleAction : CodeAction
{ {
return _originalInvocation return _originalInvocation
.Ancestors().OfType<MethodDeclarationSyntax>() .Ancestors().OfType<MethodDeclarationSyntax>()
.First() .FirstOrDefault()
.ParameterList.Parameters ?.ParameterList.Parameters
.FirstOrDefault(i => i.Type?.NormalizeWhitespace()?.ToString() == "IAnsiConsole") .FirstOrDefault(i => i.Type?.NormalizeWhitespace()?.ToString() == "IAnsiConsole")
?.Identifier.Text; ?.Identifier.Text;
} }
@ -80,11 +80,18 @@ public class SwitchToAnsiConsoleAction : CodeAction
// let's look to see if our call is in a static method. // let's look to see if our call is in a static method.
// if so we'll only want to look for static IAnsiConsoles // if so we'll only want to look for static IAnsiConsoles
// and vice-versa if we aren't. // and vice-versa if we aren't.
// If there is no parent method, the SyntaxNode should be in
// a top-level statement, so there is no field anyway.
var isStatic = _originalInvocation var isStatic = _originalInvocation
.Ancestors() .Ancestors()
.OfType<MethodDeclarationSyntax>() .OfType<MethodDeclarationSyntax>()
.First() .FirstOrDefault()
.Modifiers.Any(i => i.IsKind(SyntaxKind.StaticKeyword)); ?.Modifiers.Any(i => i.IsKind(SyntaxKind.StaticKeyword));
if (isStatic == null)
{
return null;
}
return _originalInvocation return _originalInvocation
.Ancestors().OfType<ClassDeclarationSyntax>() .Ancestors().OfType<ClassDeclarationSyntax>()
@ -93,7 +100,7 @@ public class SwitchToAnsiConsoleAction : CodeAction
.OfType<FieldDeclarationSyntax>() .OfType<FieldDeclarationSyntax>()
.FirstOrDefault(i => .FirstOrDefault(i =>
i.Declaration.Type.NormalizeWhitespace().ToString() == "IAnsiConsole" && i.Declaration.Type.NormalizeWhitespace().ToString() == "IAnsiConsole" &&
(!isStatic ^ i.Modifiers.Any(modifier => modifier.IsKind(SyntaxKind.StaticKeyword)))) (!isStatic.GetValueOrDefault() ^ i.Modifiers.Any(modifier => modifier.IsKind(SyntaxKind.StaticKeyword))))
?.Declaration.Variables.First().Identifier.Text; ?.Declaration.Variables.First().Identifier.Text;
} }

View File

@ -20,7 +20,7 @@ public class StaticAnsiConsoleToInstanceFix : CodeFixProvider
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
if (root != null) if (root != null)
{ {
var methodDeclaration = root.FindNode(context.Span).FirstAncestorOrSelf<InvocationExpressionSyntax>(); var methodDeclaration = root.FindNode(context.Span, getInnermostNodeForTie: true).FirstAncestorOrSelf<InvocationExpressionSyntax>();
if (methodDeclaration != null) if (methodDeclaration != null)
{ {
context.RegisterCodeFix( context.RegisterCodeFix(

View File

@ -4,13 +4,20 @@ public static class SpectreAnalyzerVerifier<TAnalyzer>
where TAnalyzer : DiagnosticAnalyzer, new() where TAnalyzer : DiagnosticAnalyzer, new()
{ {
public static Task VerifyCodeFixAsync(string source, DiagnosticResult expected, string fixedSource) public static Task VerifyCodeFixAsync(string source, DiagnosticResult expected, string fixedSource)
=> VerifyCodeFixAsync(source, new[] { expected }, fixedSource); => VerifyCodeFixAsync(source, OutputKind.DynamicallyLinkedLibrary, new[] { expected }, fixedSource);
private static Task VerifyCodeFixAsync(string source, IEnumerable<DiagnosticResult> expected, string fixedSource) public static Task VerifyCodeFixAsync(string source, OutputKind outputKind, DiagnosticResult expected, string fixedSource)
=> VerifyCodeFixAsync(source, outputKind, new[] { expected }, fixedSource);
private static Task VerifyCodeFixAsync(string source, OutputKind outputKind, IEnumerable<DiagnosticResult> expected, string fixedSource)
{ {
var test = new Test var test = new Test
{ {
TestCode = source, TestCode = source,
TestState =
{
OutputKind = outputKind,
},
FixedCode = fixedSource, FixedCode = fixedSource,
}; };

View File

@ -139,4 +139,25 @@ class TestClass
.VerifyCodeFixAsync(Source, _expectedDiagnostic.WithLocation(11, 9), FixedSource) .VerifyCodeFixAsync(Source, _expectedDiagnostic.WithLocation(11, 9), FixedSource)
.ConfigureAwait(false); .ConfigureAwait(false);
} }
[Fact]
public async Task SystemConsole_replaced_with_AnsiConsole_in_top_level_statements()
{
const string Source = @"
using System;
Console.WriteLine(""Hello, World"");
";
const string FixedSource = @"
using System;
using Spectre.Console;
AnsiConsole.WriteLine(""Hello, World"");
";
await SpectreAnalyzerVerifier<UseSpectreInsteadOfSystemConsoleAnalyzer>
.VerifyCodeFixAsync(Source, OutputKind.ConsoleApplication, _expectedDiagnostic.WithLocation(4, 1), FixedSource)
.ConfigureAwait(false);
}
} }