Skip to content

Commit

Permalink
Add CodeFixer for MA0089 (#542)
Browse files Browse the repository at this point in the history
  • Loading branch information
meziantou committed Jun 4, 2023
1 parent 13a0db6 commit 11b060a
Show file tree
Hide file tree
Showing 3 changed files with 234 additions and 85 deletions.
30 changes: 15 additions & 15 deletions src/Meziantou.Analyzer/Rules/OptimizeStartsWithAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ public void AnalyzeInvocation(OperationAnalysisContext context)
if (operation.Arguments[0].Value is { Type.SpecialType: SpecialType.System_String, ConstantValue: { HasValue: true, Value: string { Length: 1 } } } &&
operation.Arguments[1].Value is { ConstantValue: { HasValue: true, Value: (int)StringComparison.Ordinal } })
{
context.ReportDiagnostic(s_rule, operation.Arguments[0]);
context.ReportDiagnostic(s_rule, operation.Arguments[0].Value);
}
}
}
Expand All @@ -205,7 +205,7 @@ public void AnalyzeInvocation(OperationAnalysisContext context)
if (operation.Arguments[0].Value is { Type.SpecialType: SpecialType.System_String, ConstantValue: { HasValue: true, Value: string { Length: 1 } } } &&
operation.Arguments[1].Value is { ConstantValue: { HasValue: true, Value: (int)StringComparison.Ordinal } })
{
context.ReportDiagnostic(s_rule, operation.Arguments[0]);
context.ReportDiagnostic(s_rule, operation.Arguments[0].Value);
}
}
}
Expand Down Expand Up @@ -241,7 +241,7 @@ public void AnalyzeInvocation(OperationAnalysisContext context)
if (operation.Arguments[0].Value is { Type.SpecialType: SpecialType.System_String, ConstantValue: { HasValue: true, Value: string { Length: 1 } } } &&
operation.Arguments[1].Value is { ConstantValue: { HasValue: true, Value: (int)StringComparison.Ordinal } })
{
context.ReportDiagnostic(s_rule, operation);
context.ReportDiagnostic(s_rule, operation.Arguments[0].Value);
return;
}
}
Expand All @@ -251,7 +251,7 @@ public void AnalyzeInvocation(OperationAnalysisContext context)
if (operation.Arguments[0].Value is { Type.SpecialType: SpecialType.System_String, ConstantValue: { HasValue: true, Value: string { Length: 1 } } } &&
operation.Arguments[1].Value.Type.IsEqualTo(StringComparisonSymbol))
{
context.ReportDiagnostic(s_rule, operation);
context.ReportDiagnostic(s_rule, operation.Arguments[0].Value);
return;
}
}
Expand All @@ -265,7 +265,7 @@ public void AnalyzeInvocation(OperationAnalysisContext context)
operation.Arguments[1].Value.Type.IsInt32() &&
operation.Arguments[2].Value is { ConstantValue: { HasValue: true, Value: (int)StringComparison.Ordinal } })
{
context.ReportDiagnostic(s_rule, operation);
context.ReportDiagnostic(s_rule, operation.Arguments[0].Value);
}
}
else if (operation.Arguments.Length == 4)
Expand All @@ -279,7 +279,7 @@ public void AnalyzeInvocation(OperationAnalysisContext context)
operation.Arguments[2].Value.Type.IsInt32() &&
operation.Arguments[3].Value is { ConstantValue: { HasValue: true, Value: (int)StringComparison.Ordinal } })
{
context.ReportDiagnostic(s_rule, operation);
context.ReportDiagnostic(s_rule, operation.Arguments[0].Value);
}
}
}
Expand All @@ -292,7 +292,7 @@ public void AnalyzeInvocation(OperationAnalysisContext context)
if (operation.Arguments[0].Value is { Type.SpecialType: SpecialType.System_String, ConstantValue: { HasValue: true, Value: string { Length: 1 } } } &&
operation.Arguments[1].Value is { ConstantValue: { HasValue: true, Value: (int)StringComparison.Ordinal } })
{
context.ReportDiagnostic(s_rule, operation);
context.ReportDiagnostic(s_rule, operation.Arguments[0].Value);
return;
}
}
Expand All @@ -302,7 +302,7 @@ public void AnalyzeInvocation(OperationAnalysisContext context)
if (operation.Arguments[0].Value is { Type.SpecialType: SpecialType.System_String, ConstantValue: { HasValue: true, Value: string { Length: 1 } } } &&
operation.Arguments[1].Value.Type.IsEqualTo(StringComparisonSymbol))
{
context.ReportDiagnostic(s_rule, operation);
context.ReportDiagnostic(s_rule, operation.Arguments[0].Value);
return;
}
}
Expand All @@ -317,7 +317,7 @@ public void AnalyzeInvocation(OperationAnalysisContext context)
operation.Arguments[1].Value.Type.IsInt32() &&
operation.Arguments[2].Value is { ConstantValue: { HasValue: true, Value: (int)StringComparison.Ordinal } })
{
context.ReportDiagnostic(s_rule, operation);
context.ReportDiagnostic(s_rule, operation.Arguments[0].Value);
}
}
else if (operation.Arguments.Length == 4)
Expand All @@ -331,7 +331,7 @@ public void AnalyzeInvocation(OperationAnalysisContext context)
operation.Arguments[2].Value.Type.IsInt32() &&
operation.Arguments[3].Value is { ConstantValue: { HasValue: true, Value: (int)StringComparison.Ordinal } })
{
context.ReportDiagnostic(s_rule, operation);
context.ReportDiagnostic(s_rule, operation.Arguments[0].Value);
}
}
}
Expand All @@ -347,19 +347,19 @@ public void AnalyzeInvocation(OperationAnalysisContext context)
case 2:
if (Join_Char_ObjectArray != null && secondParameterType is IArrayTypeSymbol { ElementType.SpecialType: SpecialType.System_Object })
{
context.ReportDiagnostic(s_rule, operation);
context.ReportDiagnostic(s_rule, operation.Arguments[0].Value);
return;
}

if (Join_Char_StringArray != null && secondParameterType is IArrayTypeSymbol { ElementType.SpecialType: SpecialType.System_String })
{
context.ReportDiagnostic(s_rule, operation);
context.ReportDiagnostic(s_rule, operation.Arguments[0].Value);
return;
}

if (Join_Char_IEnumerableT != null && secondParameterType is INamedTypeSymbol symbol && symbol.ConstructedFrom.IsEqualTo(EnumerableOfTSymbol))
{
context.ReportDiagnostic(s_rule, operation);
context.ReportDiagnostic(s_rule, operation.Arguments[0].Value);
return;
}

Expand All @@ -368,7 +368,7 @@ public void AnalyzeInvocation(OperationAnalysisContext context)
case 4:
if (Join_Char_StringArray_Int32_Int32 != null)
{
context.ReportDiagnostic(s_rule, operation);
context.ReportDiagnostic(s_rule, operation.Arguments[0].Value);
return;
}

Expand All @@ -382,7 +382,7 @@ public void AnalyzeInvocation(OperationAnalysisContext context)
{
if (operation.Arguments[0].Value is { Type.SpecialType: SpecialType.System_String, ConstantValue: { HasValue: true, Value: string { Length: 1 } } })
{
context.ReportDiagnostic(s_rule, operation);
context.ReportDiagnostic(s_rule, operation.Arguments[0].Value);
return;
}
}
Expand Down
63 changes: 63 additions & 0 deletions src/Meziantou.Analyzer/Rules/OptimizeStartsWithFixer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
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.Operations;

namespace Meziantou.Analyzer.Rules;

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

public override FixAllProvider GetFixAllProvider()
{
return 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);
if (nodeToFix == null)
return;

var title = "Optimize arguments";
var codeAction = CodeAction.Create(
title,
ct => Fix(context.Document, nodeToFix, ct),
equivalenceKey: title);
context.RegisterCodeFix(codeAction, context.Diagnostics);
}

private static async Task<Document> Fix(Document document, SyntaxNode nodeToFix, CancellationToken cancellationToken)
{
var editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false);
var operation = editor.SemanticModel.GetOperation(nodeToFix, cancellationToken);
if (operation is ILiteralOperation literalOperation && literalOperation.ConstantValue.Value is string { Length: 1 } literalValue)
{
editor.ReplaceNode(literalOperation.Syntax, editor.Generator.LiteralExpression(literalValue[0]));
}
else if (operation is IArgumentOperation argumentOperation && argumentOperation.Value.ConstantValue.Value is string { Length: 1 } argumentValue)
{
editor.ReplaceNode(argumentOperation.Value.Syntax, editor.Generator.LiteralExpression(argumentValue[0]));
}
else if (operation is IInvocationOperation invocation && invocation.TargetMethod.Name == "Replace" && invocation.Arguments.Length >= 2)
{
for (var i = 0; i < 2; i++)
{
if (invocation.Arguments[i].Value.ConstantValue.Value is string { Length: 1 } arg)
{
editor.ReplaceNode(invocation.Arguments[i].Value.Syntax, editor.Generator.LiteralExpression(arg[0]));
}
}
}

return editor.GetChangedDocument();
}
}
Loading

0 comments on commit 11b060a

Please sign in to comment.