Skip to content

Commit

Permalink
Add a simple code fix for ARGP0004
Browse files Browse the repository at this point in the history
  • Loading branch information
DoctorKrolic committed Mar 14, 2024
1 parent abec33d commit 9dfcc1c
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 12 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using System.Collections.Immutable;
using System.Composition;
using ArgumentParsing.Generators.Diagnostics;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;

namespace ArgumentParsing.CodeFixes;

[ExportCodeFixProvider(LanguageNames.CSharp), Shared]
public sealed class UseArgsParameterNameCodeFixProvider : CodeFixProvider

Check warning on line 13 in src/ArgumentParsing.CodeFixes/UseArgsParameterNameCodeFixProvider.cs

View workflow job for this annotation

GitHub Actions / build-and-test

'UseArgsParameterNameCodeFixProvider' registers one or more code fixes, but does not override the method 'CodeFixProvider.GetFixAllProvider'. Override this method and provide a non-null FixAllProvider for FixAll support, potentially 'WellKnownFixAllProviders.BatchFixer', or 'null' to explicitly disable FixAll support.

Check warning on line 13 in src/ArgumentParsing.CodeFixes/UseArgsParameterNameCodeFixProvider.cs

View workflow job for this annotation

GitHub Actions / build-and-test

'UseArgsParameterNameCodeFixProvider' registers one or more code fixes, but does not override the method 'CodeFixProvider.GetFixAllProvider'. Override this method and provide a non-null FixAllProvider for FixAll support, potentially 'WellKnownFixAllProviders.BatchFixer', or 'null' to explicitly disable FixAll support.
{
public override ImmutableArray<string> FixableDiagnosticIds { get; } = ImmutableArray.Create(DiagnosticDescriptors.PreferArgsParameterName.Id);

public override async Task RegisterCodeFixesAsync(CodeFixContext context)
{
var document = context.Document;
var root = await document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);

if (root?.FindNode(context.Span) is ParameterSyntax parameter)
{
context.RegisterCodeFix(
CodeAction.Create(
"Use 'args' name for the parameter",
_ => ChangeNameToArgs(document, root, parameter)),
context.Diagnostics[0]);
}
}

private static Task<Document> ChangeNameToArgs(Document document, SyntaxNode root, ParameterSyntax parameter)
{
var fixedParameter = parameter
.WithIdentifier(
SyntaxFactory.Identifier("args")
.WithTriviaFrom(parameter.Identifier));

var fixedRoot = root.ReplaceNode(parameter, fixedParameter);
return Task.FromResult(document.WithSyntaxRoot(fixedRoot));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace ArgumentParsing.Generators.Diagnostics;

internal static class DiagnosticDescriptors
public static class DiagnosticDescriptors
{
private const string ArgumentParsingCategoryName = "ArgumentParsing";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using ArgumentParsing.CodeFixes;
using ArgumentParsing.Generators.Diagnostics.Analyzers;
using ArgumentParsing.Tests.Unit.Utilities;

Expand Down Expand Up @@ -148,7 +149,15 @@ partial class C
}
""";

await VerifyAnalyzerAsync(source);
var fixedSource = """
partial class C
{
[GeneratedArgumentParser]
public static partial ParseResult<EmptyOptions> {|CS8795:ParseArguments|}(string[] args);
}
""";

await VerifyAnalyzerWithCodeFixAsync<UseArgsParameterNameCodeFixProvider>(source, fixedSource);
}

[Theory]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="$(MicrosoftCodeAnalysisVersion)" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="$(MicrosoftCodeAnalysisVersion)" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="$(MicrosoftCodeAnalysisVersion)" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing" Version="$(MicrosoftCodeAnalysisTestingVersion)" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.CodeFix.Testing.XUnit" Version="$(MicrosoftCodeAnalysisTestingVersion)" />
</ItemGroup>
Expand Down
43 changes: 33 additions & 10 deletions tests/ArgumentParsing.Tests.Unit/Utilities/AnalyzerTestBase.cs
Original file line number Diff line number Diff line change
@@ -1,35 +1,51 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Testing;

namespace ArgumentParsing.Tests.Unit.Utilities;

public abstract class AnalyzerTestBase<TAnalyzer>
where TAnalyzer: DiagnosticAnalyzer, new()
where TAnalyzer : DiagnosticAnalyzer, new()
{
protected static Task VerifyAnalyzerAsync(string source, LanguageVersion languageVersion = LanguageVersion.Latest, ReferenceAssemblies referenceAssemblies = null)
=> VerifyAnalyzerAsync(source, [], languageVersion, referenceAssemblies);

protected static async Task VerifyAnalyzerAsync(string source, DiagnosticResult[] diagnostics, LanguageVersion languageVersion = LanguageVersion.Latest, ReferenceAssemblies referenceAssemblies = null)
protected static Task VerifyAnalyzerAsync(string source, DiagnosticResult[] diagnostics, LanguageVersion languageVersion = LanguageVersion.Latest, ReferenceAssemblies referenceAssemblies = null)
=> VerifyAnalyzerWithCodeFixAsync<EmptyCodeFixProvider>(source, fixedSource: null, diagnostics, languageVersion, referenceAssemblies);

protected static Task VerifyAnalyzerWithCodeFixAsync<TCodeFix>(string source, string fixedSource, LanguageVersion languageVersion = LanguageVersion.Latest, ReferenceAssemblies referenceAssemblies = null)
where TCodeFix : CodeFixProvider, new()
{
var test = new CSharpCodeFixTest<TAnalyzer, EmptyCodeFixProvider>()
return VerifyAnalyzerWithCodeFixAsync<TCodeFix>(source, fixedSource, [], languageVersion, referenceAssemblies);
}

protected static async Task VerifyAnalyzerWithCodeFixAsync<TCodeFix>(string source, string fixedSource, DiagnosticResult[] diagnostics, LanguageVersion languageVersion = LanguageVersion.Latest, ReferenceAssemblies referenceAssemblies = null)
where TCodeFix : CodeFixProvider, new()
{
var additionalDoc = """
global using ArgumentParsing;
global using ArgumentParsing.Results;
global using System;
class EmptyOptions { }
""";

var mainLibraryReference = MetadataReference.CreateFromFile(typeof(GeneratedArgumentParserAttribute).Assembly.Location);

var test = new CSharpCodeFixTest<TAnalyzer, TCodeFix>()
{
TestState =
{
Sources =
{
source,
"""
global using ArgumentParsing;
global using ArgumentParsing.Results;
global using System;
""",
"class EmptyOptions { }"
additionalDoc,
},
AdditionalReferences =
{
MetadataReference.CreateFromFile(typeof(GeneratedArgumentParserAttribute).Assembly.Location),
mainLibraryReference,
}
},
LanguageVersion = languageVersion,
Expand All @@ -38,6 +54,13 @@ protected static async Task VerifyAnalyzerAsync(string source, DiagnosticResult[

test.ExpectedDiagnostics.AddRange(diagnostics);

if (fixedSource is not null)
{
test.FixedState.Sources.Add(fixedSource);
test.FixedState.Sources.Add(additionalDoc);
test.FixedState.AdditionalReferences.Add(mainLibraryReference);
}

await test.RunAsync();
}
}

0 comments on commit 9dfcc1c

Please sign in to comment.