Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions TUnit.Analyzers.CodeFixers/MatrixDataSourceCodeFixProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using System.Collections.Immutable;
using System.Composition;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Editing;

namespace TUnit.Analyzers.CodeFixers;

[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(MatrixDataSourceCodeFixProvider)), Shared]
public class MatrixDataSourceCodeFixProvider : CodeFixProvider
{
private const string Title = "Add [MatrixDataSource]";

public sealed override ImmutableArray<string> FixableDiagnosticIds { get; } =
ImmutableArray.Create(Rules.MatrixDataSourceAttributeRequired.Id);

public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer;

public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
{
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
if (root is null)
{
return;
}

foreach (var diagnostic in context.Diagnostics)
{
var node = root.FindNode(diagnostic.Location.SourceSpan);
var target = node.FirstAncestorOrSelf<SyntaxNode>(n => n is MethodDeclarationSyntax or TypeDeclarationSyntax);

if (target is null)
{
continue;
}

context.RegisterCodeFix(
CodeAction.Create(
title: Title,
createChangedDocument: c => AddMatrixDataSourceAsync(context.Document, target, c),
equivalenceKey: Title),
diagnostic);
}
}

private static async Task<Document> AddMatrixDataSourceAsync(Document document, SyntaxNode target, CancellationToken cancellationToken)
{
var editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false);
var attributeList = SyntaxFactory.AttributeList(
SyntaxFactory.SingletonSeparatedList(
SyntaxFactory.Attribute(SyntaxFactory.IdentifierName("MatrixDataSource"))));

SyntaxNode updated = target switch
{
MethodDeclarationSyntax method => method.AddAttributeLists(attributeList),
TypeDeclarationSyntax type => type.AddAttributeLists(attributeList),
_ => throw new InvalidOperationException($"Unexpected node kind: {target.Kind()}"),
};

editor.ReplaceNode(target, updated);
return editor.GetChangedDocument();
}
}
86 changes: 86 additions & 0 deletions TUnit.Analyzers.Tests/MatrixDataSourceCodeFixProviderTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
using Verifier = TUnit.Analyzers.Tests.Verifiers.CSharpCodeFixVerifier<
TUnit.Analyzers.MatrixAnalyzer,
TUnit.Analyzers.CodeFixers.MatrixDataSourceCodeFixProvider>;

namespace TUnit.Analyzers.Tests;

public class MatrixDataSourceCodeFixProviderTests
{
[Test]
public async Task Adds_MatrixDataSource_On_Method()
{
await Verifier.VerifyCodeFixAsync(
"""
using TUnit.Core;

public class MyClass
{
[Test]
public void {|#0:MyTest|}(
[Matrix(1, 2, 3)] int value,
[Matrix(true, false)] bool flag)
{
}
}
""",
Verifier.Diagnostic(Rules.MatrixDataSourceAttributeRequired).WithLocation(0),
"""
using TUnit.Core;

public class MyClass
{
[Test]
[MatrixDataSource]
public void MyTest(
[Matrix(1, 2, 3)] int value,
[Matrix(true, false)] bool flag)
{
}
}
"""
);
}

[Test]
public async Task Adds_MatrixDataSource_On_Class()
{
await Verifier.VerifyCodeFixAsync(
"""
using TUnit.Core;

public class {|#0:MyClass|}
{
public MyClass(
[Matrix(1, 2)] int value,
[Matrix(true, false)] bool flag)
{
}

[Test]
public void MyTest()
{
}
}
""",
Verifier.Diagnostic(Rules.MatrixDataSourceAttributeRequired).WithLocation(0),
"""
using TUnit.Core;

[MatrixDataSource]
public class MyClass
{
public MyClass(
[Matrix(1, 2)] int value,
[Matrix(true, false)] bool flag)
{
}

[Test]
public void MyTest()
{
}
}
"""
);
}
}
Loading