File: src\Analyzers\Core\CodeFixes\AddObsoleteAttribute\AbstractAddObsoleteAttributeCodeFixProvider.cs
Web Access
Project: src\src\CodeStyle\Core\CodeFixes\Microsoft.CodeAnalysis.CodeStyle.Fixes.csproj (Microsoft.CodeAnalysis.CodeStyle.Fixes)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.LanguageService;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.AddObsoleteAttribute;
 
internal abstract class AbstractAddObsoleteAttributeCodeFixProvider
    : SyntaxEditorBasedCodeFixProvider
{
    private readonly ISyntaxFacts _syntaxFacts;
    private readonly string _title;
 
    protected AbstractAddObsoleteAttributeCodeFixProvider(
        ISyntaxFacts syntaxFacts,
        string title)
    {
        _syntaxFacts = syntaxFacts;
        _title = title;
    }
 
    public override async Task RegisterCodeFixesAsync(CodeFixContext context)
    {
        var cancellationToken = context.CancellationToken;
        var document = context.Document;
 
        var attribute = await GetObsoleteAttributeAsync(document, cancellationToken).ConfigureAwait(false);
        if (attribute == null)
        {
            return;
        }
 
        var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
 
        var node = context.Diagnostics[0].Location.FindNode(cancellationToken);
 
        var container = GetContainer(root, node);
 
        if (container == null)
        {
            return;
        }
 
        RegisterCodeFix(context, _title, _title);
    }
 
    private static async Task<INamedTypeSymbol?> GetObsoleteAttributeAsync(Document document, CancellationToken cancellationToken)
    {
        var compilation = await document.Project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false);
        var attribute = compilation.GetTypeByMetadataName(typeof(ObsoleteAttribute).FullName!);
        return attribute;
    }
 
    private SyntaxNode? GetContainer(SyntaxNode root, SyntaxNode node)
    {
        return _syntaxFacts.GetContainingMemberDeclaration(root, node.SpanStart) ??
               _syntaxFacts.GetContainingTypeDeclaration(root, node.SpanStart);
    }
 
    protected override async Task FixAllAsync(
        Document document, ImmutableArray<Diagnostic> diagnostics,
        SyntaxEditor editor, CancellationToken cancellationToken)
    {
        var obsoleteAttribute = await GetObsoleteAttributeAsync(document, cancellationToken).ConfigureAwait(false);
 
        // RegisterCodeFixesAsync checked for null
        Contract.ThrowIfNull(obsoleteAttribute);
 
        var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
 
        var containers = diagnostics.Select(d => GetContainer(root, d.Location.FindNode(cancellationToken)))
                                    .WhereNotNull()
                                    .ToSet();
 
        var generator = editor.Generator;
        foreach (var container in containers)
        {
            editor.AddAttribute(container,
                generator.Attribute(editor.Generator.TypeExpression(obsoleteAttribute)));
        }
    }
}