Skip to content

Commit

Permalink
Add code fixer for MA0154
Browse files Browse the repository at this point in the history
  • Loading branch information
meziantou committed Feb 24, 2024
1 parent 78170a9 commit c0972b2
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
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.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Editing;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;

namespace Meziantou.Analyzer.Rules;

[ExportCodeFixProvider(LanguageNames.CSharp), Shared]
public sealed class UseLangwordInXmlCommentFixer : CodeFixProvider
{
public override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create(RuleIdentifiers.UseLangwordInXmlComment);

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

public override async Task RegisterCodeFixesAsync(CodeFixContext context)
{
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
var nodeToFix = root?.FindNode(context.Span, getInnermostNodeForTie: true, findInsideTrivia: true);
if (nodeToFix is null)
return;

if (!context.Diagnostics[0].Properties.TryGetValue("keyword", out var keyword) || keyword is null)
return;

var title = $"Use <see langword=\"{keyword}\" />";
var codeAction = CodeAction.Create(
title,
cancellationToken => Fix(context.Document, nodeToFix, keyword, cancellationToken),
equivalenceKey: title);

context.RegisterCodeFix(codeAction, context.Diagnostics);
}

private static async Task<Document> Fix(Document document, SyntaxNode nodeToFix, string keyword, CancellationToken cancellationToken)
{
var editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false);

var newNode = XmlNullKeywordElement()
.WithLessThanToken(Token(SyntaxKind.LessThanToken))
.WithAttributes(
SingletonList<XmlAttributeSyntax>(
XmlTextAttribute("langword", keyword)));

editor.ReplaceNode(nodeToFix, newNode);
return editor.GetChangedDocument();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,8 @@ private static void AnalyzeSymbol(SymbolAnalysisContext context)
var item = elementSyntax.Content.SingleOrDefaultIfMultiple();
if (item is XmlTextSyntax { TextTokens: [var codeText] } && CSharpKeywords.Contains(codeText.Text))
{
context.ReportDiagnostic(Rule, elementSyntax);
var properties = ImmutableDictionary<string, string?>.Empty.Add("keyword", codeText.Text);
context.ReportDiagnostic(Rule, properties, elementSyntax);
}
}
else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,33 @@ private static ProjectBuilder CreateProjectBuilder()
{
return new ProjectBuilder()
.WithAnalyzer<UseLangwordInXmlCommentAnalyzer>()
.WithCodeFixProvider<UseLangwordInXmlCommentFixer>()
.WithTargetFramework(TargetFramework.NetLatest);
}

[Theory]
[InlineData("[|<c>void</c>|]")]
[InlineData("[|<code>void</code>|]")]
[InlineData("[|<code>null</code>|]")]
[InlineData("[|<c>void</c>|]", "<see langword=\"void\"/>")]
[InlineData("[|<code>void</code>|]", "<see langword=\"void\"/>")]
[InlineData("[|<code>null</code>|]", "<see langword=\"null\"/>")]
public async Task ValidateSummary_Invalid(string comment, string fix)
{
await CreateProjectBuilder()
.WithSourceCode($$"""
/// <summary>{{comment}}</summary>
class Sample { }
""")
.ShouldFixCodeWith($$"""
/// <summary>{{fix}}</summary>
class Sample { }
""")
.ValidateAsync();
}

[Theory]
[InlineData("<i>in</i>")]
[InlineData("null")]
[InlineData("this is null")]
public async Task ValidateSummary(string comment)
public async Task ValidateSummary_Valid(string comment)
{
await CreateProjectBuilder()
.WithSourceCode($$"""
Expand Down

0 comments on commit c0972b2

Please sign in to comment.