// 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.Threading; 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; namespace Microsoft.CodeQuality.Analyzers.ApiDesignGuidelines { /// <summary> /// CA2231: Overload operator equals on overriding ValueType.Equals /// </summary> [ExportCodeFixProvider(LanguageNames.CSharp, LanguageNames.VisualBasic), Shared] public sealed class OverloadOperatorEqualsOnOverridingValueTypeEqualsFixer : CodeFixProvider { public sealed override ImmutableArray<string> FixableDiagnosticIds { get; } = ImmutableArray.Create(OverloadOperatorEqualsOnOverridingValueTypeEqualsAnalyzer.RuleId); public override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxGenerator generator = SyntaxGenerator.GetGenerator(context.Document); SyntaxNode root = await context.Document.GetRequiredSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); SyntaxNode declaration = root.FindNode(context.Span); declaration = generator.GetDeclaration(declaration); if (declaration == null) { return; } SemanticModel model = await context.Document.GetRequiredSemanticModelAsync(context.CancellationToken).ConfigureAwait(false); if (model.GetDeclaredSymbol(declaration, context.CancellationToken) is not INamedTypeSymbol typeSymbol) { return; } string title = MicrosoftCodeQualityAnalyzersResources.OverloadOperatorEqualsOnOverridingValueTypeEqualsTitle; context.RegisterCodeFix( CodeAction.Create(title, async ct => await ImplementOperatorEqualsAsync(context.Document, declaration, typeSymbol, ct).ConfigureAwait(false), equivalenceKey: title), context.Diagnostics); } private static async Task<Document> ImplementOperatorEqualsAsync(Document document, SyntaxNode declaration, INamedTypeSymbol typeSymbol, CancellationToken cancellationToken) { var editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false); var generator = editor.Generator; if (!typeSymbol.ImplementsOperator(WellKnownMemberNames.EqualityOperatorName)) { var equalityOperator = generator.DefaultOperatorEqualityDeclaration(typeSymbol); editor.AddMember(declaration, equalityOperator); } if (!typeSymbol.ImplementsOperator(WellKnownMemberNames.InequalityOperatorName)) { var inequalityOperator = generator.DefaultOperatorInequalityDeclaration(typeSymbol); editor.AddMember(declaration, inequalityOperator); } return editor.GetChangedDocument(); } public override FixAllProvider GetFixAllProvider() { return WellKnownFixAllProviders.BatchFixer; } } }