| File: Microsoft.NetCore.Analyzers\Runtime\UseRegexMembersFixer.cs | Web Access |
| Project: src\sdk\src\Microsoft.CodeAnalysis.NetAnalyzers\src\Microsoft.CodeAnalysis.NetAnalyzers\Microsoft.CodeAnalysis.NetAnalyzers.csproj (Microsoft.CodeAnalysis.NetAnalyzers) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Immutable; using System.Composition; using System.Linq; using System.Threading.Tasks; using Analyzer.Utilities; using Analyzer.Utilities.Extensions; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Operations; namespace Microsoft.NetCore.Analyzers.Runtime { using static MicrosoftNetCoreAnalyzersResources; /// <summary> /// CA1874: <inheritdoc cref="UseRegexIsMatchMessage"/> /// CA1875: <inheritdoc cref="UseRegexCountMessage"/> /// </summary> [ExportCodeFixProvider(LanguageNames.CSharp, LanguageNames.VisualBasic), Shared] public sealed class UseRegexMembersFixer : CodeFixProvider { public sealed override ImmutableArray<string> FixableDiagnosticIds { get; } = ImmutableArray.Create( UseRegexMembers.RegexIsMatchRuleId, UseRegexMembers.RegexCountRuleId); public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { Document doc = context.Document; SemanticModel model = await doc.GetRequiredSemanticModelAsync(context.CancellationToken).ConfigureAwait(false); SyntaxNode root = await doc.GetRequiredSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); if (root.FindNode(context.Span, getInnermostNodeForTie: true) is SyntaxNode node && model.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemTextRegularExpressionsRegex, out var regexType) && model.GetOperation(node, context.CancellationToken) is IPropertyReferenceOperation operation && operation.Instance is IInvocationOperation regexCall) { string title, memberName; switch (context.Diagnostics[0].Id) { case UseRegexMembers.RegexIsMatchRuleId: title = UseRegexIsMatchFix; memberName = "IsMatch"; break; case UseRegexMembers.RegexCountRuleId: title = UseRegexCountFix; memberName = "Count"; break; default: RoslynDebug.Assert(false, $"Unknown id {context.Diagnostics[0].Id}"); return; } context.RegisterCodeFix( CodeAction.Create(title, async cancellationToken => { DocumentEditor editor = await DocumentEditor.CreateAsync(doc, cancellationToken).ConfigureAwait(false); var replacement = editor.Generator.InvocationExpression( // swap in new method name, dropping the subsequent parameter access editor.Generator.MemberAccessExpression( regexCall.Instance?.Syntax ?? editor.Generator.TypeExpressionForStaticMemberAccess(regexType), memberName), regexCall.Arguments.Select(arg => arg.Syntax)); // use the exact same arguments editor.ReplaceNode(node, replacement.WithTriviaFrom(node)); return editor.GetChangedDocument(); }, equivalenceKey: title), context.Diagnostics); } } } }