File: src\Analyzers\CSharp\CodeFixes\GenerateVariable\CSharpGenerateVariableCodeFixProvider.cs
Web Access
Project: src\src\Features\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.Features.csproj (Microsoft.CodeAnalysis.CSharp.Features)
// 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.Collections.Immutable;
using System.Composition;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CodeFixes.GenerateMember;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.GenerateMember.GenerateVariable;
using Microsoft.CodeAnalysis.Shared.Extensions;
 
namespace Microsoft.CodeAnalysis.CSharp.GenerateVariable;
 
[ExportCodeFixProvider(LanguageNames.CSharp, Name = PredefinedCodeFixProviderNames.GenerateVariable), Shared]
[ExtensionOrder(After = PredefinedCodeFixProviderNames.GenerateMethod)]
[method: ImportingConstructor]
[method: SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")]
internal sealed class CSharpGenerateVariableCodeFixProvider() : AbstractGenerateMemberCodeFixProvider
{
    private const string CS1061 = nameof(CS1061); // error CS1061: 'C' does not contain a definition for 'Goo' and no extension method 'Goo' accepting a first argument of type 'C' could be found
    private const string CS0103 = nameof(CS0103); // error CS0103: The name 'Goo' does not exist in the current context
    private const string CS0117 = nameof(CS0117); // error CS0117: 'TestNs.Program' does not contain a definition for 'blah'
    private const string CS0539 = nameof(CS0539); // error CS0539: 'Class.SomeProp' in explicit interface declaration is not a member of interface
    private const string CS0246 = nameof(CS0246); // error CS0246: The type or namespace name 'Version' could not be found
    private const string CS0120 = nameof(CS0120); // error CS0120: An object reference is required for the non-static field, method, or property 'A'
    private const string CS0118 = nameof(CS0118); // error CS0118: 'C' is a type but is used like a variable
 
    public override ImmutableArray<string> FixableDiagnosticIds
        => [CS1061, CS0103, CS0117, CS0539, CS0246, CS0120, CS0118];
 
    protected override bool IsCandidate(SyntaxNode node, SyntaxToken token, Diagnostic diagnostic)
        => node is SimpleNameSyntax or PropertyDeclarationSyntax or MemberBindingExpressionSyntax;
 
    protected override SyntaxNode? GetTargetNode(SyntaxNode node)
    {
        if (node.IsKind(SyntaxKind.MemberBindingExpression))
        {
            var nameNode = node.ChildNodes().FirstOrDefault(n => n.IsKind(SyntaxKind.IdentifierName));
            if (nameNode != null)
            {
                return nameNode;
            }
        }
 
        return base.GetTargetNode(node);
    }
 
    protected override async Task<ImmutableArray<CodeAction>> GetCodeActionsAsync(
        Document document, SyntaxNode node, CancellationToken cancellationToken)
    {
        // While this service is defined for C#, we support running in a torn environment, where we have compiled
        // against the version in the features layer, but the value is provided from the code-fix layer.  In that case
        // we just bail out.  This will not be necessary once we have the code that ensures no torn code scenarios
        // happen regardless of which SDK you are running against.
        var service = document.GetLanguageService<IGenerateVariableService>();
        if (service is null)
            return [];
 
        return await service.GenerateVariableAsync(document, node, cancellationToken).ConfigureAwait(false);
    }
}