File: Lowering\Extensions.cs
Web Access
Project: src\src\Compilers\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.csproj (Microsoft.CodeAnalysis.CSharp)
// 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.Collections.Immutable;
using System.Diagnostics;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
 
namespace Microsoft.CodeAnalysis.CSharp
{
    internal static partial class OperatorKindExtensions
    {
        public static RefKind RefKinds(this ImmutableArray<RefKind> ArgumentRefKinds, int index)
        {
            if (!ArgumentRefKinds.IsDefault && index < ArgumentRefKinds.Length)
            {
                return ArgumentRefKinds[index];
            }
            else
            {
                return RefKind.None;
            }
        }
    }
 
    internal static partial class BoundExpressionExtensions
    {
        public static bool NullableAlwaysHasValue(this BoundExpression expr)
        {
            Debug.Assert(expr != null);
            if ((object)expr.Type == null)
            {
                return false;
            }
 
            if (expr.Type.IsDynamic())
            {
                return false;
            }
 
            if (!expr.Type.IsNullableType())
            {
                return true;
            }
 
            // new int?(123) always has a value:
            if (expr.Kind == BoundKind.ObjectCreationExpression)
            {
                var creation = (BoundObjectCreationExpression)expr;
                return creation.Constructor.ParameterCount != 0;
            }
            else if (expr.Kind == BoundKind.Conversion)
            {
                var conversion = (BoundConversion)expr;
                switch (conversion.ConversionKind)
                {
                    case ConversionKind.ImplicitNullable:
                    case ConversionKind.ExplicitNullable:
                        // A conversion from X? to Y? will be non-null if the operand is non-null,
                        // so simply recurse.
                        return conversion.Operand.NullableAlwaysHasValue();
                    case ConversionKind.ImplicitEnumeration:
                        // The C# specification categorizes conversion from literal zero to nullable enum as 
                        // an Implicit Enumeration Conversion. 
                        return conversion.Operand.NullableAlwaysHasValue();
                }
            }
 
            return false;
        }
 
        public static bool NullableNeverHasValue(this BoundExpression expr)
        {
            Debug.Assert(expr != null);
 
            if ((object)expr.Type == null && expr.ConstantValueOpt == ConstantValue.Null)
            {
                return true;
            }
 
            if ((object)expr.Type == null || !expr.Type.IsNullableType())
            {
                return false;
            }
 
            // "default(int?)" and "default" never have a value.
            if (expr is BoundDefaultLiteral || expr is BoundDefaultExpression)
            {
                return true;
            }
 
            // "new int?()" never has a value, but "new int?(x)" always does.
            if (expr.Kind == BoundKind.ObjectCreationExpression)
            {
                var creation = (BoundObjectCreationExpression)expr;
                return creation.Constructor.ParameterCount == 0;
            }
 
            if (expr.Kind == BoundKind.Conversion)
            {
                var conversion = (BoundConversion)expr;
                switch (conversion.ConversionKind)
                {
                    case ConversionKind.NullLiteral:
                        // Any null literal conversion is a conversion from the literal null to
                        // a nullable value type; obviously it never has a value.
                        return true;
                    case ConversionKind.DefaultLiteral:
                        // Any default literal to a nullable value type never has a value. 
                        return true;
                    case ConversionKind.ImplicitNullable:
                    case ConversionKind.ExplicitNullable:
                        // A conversion from X? to Y? will be null if the operand is null,
                        // so simply recurse.
                        return conversion.Operand.NullableNeverHasValue();
                }
            }
 
            // UNDONE: We could be more sophisticated here. For example, most lifted operators that have 
            // UNDONE: a known-to-be-null operand are also known to be null.
 
            return false;
        }
 
        public static bool IsNullableNonBoolean(this BoundExpression expr)
        {
            Debug.Assert(expr != null);
            if (expr.Type.IsNullableType() && expr.Type.GetNullableUnderlyingType().SpecialType != SpecialType.System_Boolean)
                return true;
            return false;
        }
    }
}