File: Simplification\Simplifiers\QualifiedCrefSimplifier.cs
Web Access
Project: src\src\Workspaces\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.Workspaces.csproj (Microsoft.CodeAnalysis.CSharp.Workspaces)
// 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.
 
#nullable disable
 
using System.Threading;
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
 
namespace Microsoft.CodeAnalysis.CSharp.Simplification.Simplifiers;
 
using static SyntaxFactory;
 
internal class QualifiedCrefSimplifier : AbstractCSharpSimplifier<QualifiedCrefSyntax, CrefSyntax>
{
    public static readonly QualifiedCrefSimplifier Instance = new();
 
    private QualifiedCrefSimplifier()
    {
    }
 
    public override bool TrySimplify(
        QualifiedCrefSyntax crefSyntax,
        SemanticModel semanticModel,
        CSharpSimplifierOptions options,
        out CrefSyntax replacementNode,
        out TextSpan issueSpan,
        CancellationToken cancellationToken)
    {
        replacementNode = null;
        issueSpan = default;
 
        var memberCref = crefSyntax.Member;
 
        // Currently we are dealing with only the NameMemberCrefs
        if (options.PreferPredefinedTypeKeywordInMemberAccess.Value &&
            memberCref is NameMemberCrefSyntax nameMemberCref)
        {
            var symbolInfo = semanticModel.GetSymbolInfo(nameMemberCref.Name, cancellationToken);
            var symbol = symbolInfo.Symbol;
 
            if (symbol == null)
                return false;
 
            // 1. Check for Predefined Types
            if (symbol is INamedTypeSymbol namedSymbol)
            {
                var keywordToken = TryGetPredefinedKeywordToken(semanticModel, namedSymbol.SpecialType);
                if (keywordToken != null)
                {
                    replacementNode = TypeCref(CreatePredefinedTypeSyntax(crefSyntax, keywordToken.Value))
                        .WithAdditionalAnnotations(new SyntaxAnnotation(nameof(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInMemberAccess)));
                    replacementNode = crefSyntax.CopyAnnotationsTo(replacementNode);
 
                    // we want to show the whole name expression as unnecessary
                    issueSpan = crefSyntax.Span;
 
                    return true;
                }
            }
        }
 
        return CanSimplifyWithReplacement(
            crefSyntax, semanticModel, memberCref,
            out replacementNode, out issueSpan, cancellationToken);
    }
 
    public static bool CanSimplifyWithReplacement(
        QualifiedCrefSyntax crefSyntax, SemanticModel semanticModel,
        CrefSyntax replacement, CancellationToken cancellationToken)
    {
        return CanSimplifyWithReplacement(crefSyntax, semanticModel, replacement, out _, out _, cancellationToken);
    }
 
    private static bool CanSimplifyWithReplacement(
        QualifiedCrefSyntax crefSyntax, SemanticModel semanticModel,
        CrefSyntax replacement, out CrefSyntax replacementNode, out TextSpan issueSpan,
        CancellationToken cancellationToken)
    {
        var oldSymbol = semanticModel.GetSymbolInfo(crefSyntax, cancellationToken).Symbol;
        if (oldSymbol != null)
        {
            var speculativeBindingOption = oldSymbol is INamespaceOrTypeSymbol
                ? SpeculativeBindingOption.BindAsTypeOrNamespace
                : SpeculativeBindingOption.BindAsExpression;
 
            var newSymbol = semanticModel.GetSpeculativeSymbolInfo(crefSyntax.SpanStart, replacement, speculativeBindingOption).Symbol;
 
            if (Equals(newSymbol, oldSymbol))
            {
                // Copy Trivia and Annotations
                replacement = replacement.WithLeadingTrivia(crefSyntax.GetLeadingTrivia());
                replacement = crefSyntax.CopyAnnotationsTo(replacement);
                issueSpan = crefSyntax.Container.Span;
                replacementNode = replacement;
                return true;
            }
        }
 
        replacementNode = null;
        issueSpan = default;
        return false;
    }
}