File: src\roslyn\src\Workspaces\SharedUtilitiesAndExtensions\Compiler\CSharp\Extensions\DefaultExpressionSyntaxExtensions.cs
Web Access
Project: src\roslyn\src\CodeStyle\CSharp\Analyzers\Microsoft.CodeAnalysis.CSharp.CodeStyle.csproj (Microsoft.CodeAnalysis.CSharp.CodeStyle)
// 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.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Utilities;

namespace Microsoft.CodeAnalysis.CSharp.Extensions;

internal static class DefaultExpressionSyntaxExtensions
{
    private static readonly LiteralExpressionSyntax s_defaultLiteralExpression =
        SyntaxFactory.LiteralExpression(SyntaxKind.DefaultLiteralExpression);

    public static bool CanReplaceWithDefaultLiteral(
        this DefaultExpressionSyntax defaultExpression,
        CSharpParseOptions parseOptions,
        bool preferSimpleDefaultExpression,
        SemanticModel semanticModel,
        CancellationToken cancellationToken)
    {
        if (parseOptions.LanguageVersion < LanguageVersion.CSharp7_1 ||
            !preferSimpleDefaultExpression)
        {
            return false;
        }

        // Using the speculation analyzer can be slow.  Check for common cases first before
        // trying the expensive path.
        return CanReplaceWithDefaultLiteralFast(defaultExpression, semanticModel, cancellationToken) ??
               CanReplaceWithDefaultLiteralSlow(defaultExpression, semanticModel, cancellationToken);
    }

    private static bool? CanReplaceWithDefaultLiteralFast(
        DefaultExpressionSyntax defaultExpression, SemanticModel semanticModel, CancellationToken cancellationToken)
    {
        if (defaultExpression?.Parent is EqualsValueClauseSyntax equalsValueClause)
        {
            var typeSyntax = GetTypeSyntax(equalsValueClause);

            if (typeSyntax != null)
            {
                if (typeSyntax.IsVar)
                {
                    // If we have:   var v = default(CancellationToken);    then we can't simplify this.
                    return false;
                }

                var entityType = semanticModel.GetTypeInfo(typeSyntax, cancellationToken).Type;
                var defaultType = semanticModel.GetTypeInfo(defaultExpression.Type, cancellationToken).Type;

                if (entityType != null && entityType.Equals(defaultType))
                {
                    // We have a simple case of "CancellationToken c = default(CancellationToken)".
                    // We can just simplify without having to do any additional analysis.
                    return true;
                }
            }
        }

        return null;
    }

    private static TypeSyntax GetTypeSyntax(EqualsValueClauseSyntax equalsValueClause)
    {
        if (equalsValueClause.IsParentKind(SyntaxKind.VariableDeclarator) &&
            equalsValueClause.Parent?.Parent is VariableDeclarationSyntax declaration)
        {
            return declaration.Type;
        }
        else if (equalsValueClause?.Parent is ParameterSyntax parameter)
        {
            return parameter.Type;
        }

        return null;
    }

    private static bool CanReplaceWithDefaultLiteralSlow(
        DefaultExpressionSyntax defaultExpression, SemanticModel semanticModel, CancellationToken cancellationToken)
    {
        var speculationAnalyzer = new SpeculationAnalyzer(
            defaultExpression, s_defaultLiteralExpression, semanticModel,
            cancellationToken,
            skipVerificationForReplacedNode: false,
            failOnOverloadResolutionFailuresInOriginalCode: true);

        return !speculationAnalyzer.ReplacementChangesSemantics();
    }
}