File: Binder\Semantics\Operators\OperatorFacts.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 Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.CSharp
{
    internal static class OperatorFacts
    {
        public static bool DefinitelyHasNoUserDefinedOperators(TypeSymbol type)
        {
            // We can take an early out and not look for user-defined operators.
 
            switch (type.TypeKind)
            {
                case TypeKind.Struct:
                case TypeKind.Class:
                case TypeKind.TypeParameter:
                case TypeKind.Interface:
                    break;
                default:
                    return true;
            }
 
            // System.Decimal does have user-defined operators but it is treated as 
            // though it were a built-in type.
            switch (type.SpecialType)
            {
                case SpecialType.System_Array:
                case SpecialType.System_Boolean:
                case SpecialType.System_Byte:
                case SpecialType.System_Char:
                case SpecialType.System_Decimal:
                case SpecialType.System_Delegate:
                case SpecialType.System_Double:
                case SpecialType.System_Enum:
                case SpecialType.System_Int16:
                case SpecialType.System_Int32:
                case SpecialType.System_Int64:
                case SpecialType.System_IntPtr when type.IsNativeIntegerType:
                case SpecialType.System_UIntPtr when type.IsNativeIntegerType:
                case SpecialType.System_MulticastDelegate:
                case SpecialType.System_Object:
                case SpecialType.System_SByte:
                case SpecialType.System_Single:
                case SpecialType.System_String:
                case SpecialType.System_UInt16:
                case SpecialType.System_UInt32:
                case SpecialType.System_UInt64:
                case SpecialType.System_ValueType:
                case SpecialType.System_Void:
                    return true;
            }
 
            return false;
        }
 
        public static string BinaryOperatorNameFromSyntaxKind(SyntaxKind kind, bool isChecked)
        {
            return BinaryOperatorNameFromSyntaxKindIfAny(kind, isChecked) ??
                (isChecked ? WellKnownMemberNames.CheckedAdditionOperatorName : WellKnownMemberNames.AdditionOperatorName); // This can occur in the presence of syntax errors.
        }
 
        internal static string BinaryOperatorNameFromSyntaxKindIfAny(SyntaxKind kind, bool isChecked)
        {
            switch (kind)
            {
                case SyntaxKind.PlusToken: return isChecked ? WellKnownMemberNames.CheckedAdditionOperatorName : WellKnownMemberNames.AdditionOperatorName;
                case SyntaxKind.MinusToken: return isChecked ? WellKnownMemberNames.CheckedSubtractionOperatorName : WellKnownMemberNames.SubtractionOperatorName;
                case SyntaxKind.AsteriskToken: return isChecked ? WellKnownMemberNames.CheckedMultiplyOperatorName : WellKnownMemberNames.MultiplyOperatorName;
                case SyntaxKind.SlashToken: return isChecked ? WellKnownMemberNames.CheckedDivisionOperatorName : WellKnownMemberNames.DivisionOperatorName;
                case SyntaxKind.PercentToken: return WellKnownMemberNames.ModulusOperatorName;
                case SyntaxKind.CaretToken: return WellKnownMemberNames.ExclusiveOrOperatorName;
                case SyntaxKind.AmpersandToken: return WellKnownMemberNames.BitwiseAndOperatorName;
                case SyntaxKind.BarToken: return WellKnownMemberNames.BitwiseOrOperatorName;
                case SyntaxKind.EqualsEqualsToken: return WellKnownMemberNames.EqualityOperatorName;
                case SyntaxKind.LessThanToken: return WellKnownMemberNames.LessThanOperatorName;
                case SyntaxKind.LessThanEqualsToken: return WellKnownMemberNames.LessThanOrEqualOperatorName;
                case SyntaxKind.LessThanLessThanToken: return WellKnownMemberNames.LeftShiftOperatorName;
                case SyntaxKind.GreaterThanToken: return WellKnownMemberNames.GreaterThanOperatorName;
                case SyntaxKind.GreaterThanEqualsToken: return WellKnownMemberNames.GreaterThanOrEqualOperatorName;
                case SyntaxKind.GreaterThanGreaterThanToken: return WellKnownMemberNames.RightShiftOperatorName;
                case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: return WellKnownMemberNames.UnsignedRightShiftOperatorName;
                case SyntaxKind.ExclamationEqualsToken: return WellKnownMemberNames.InequalityOperatorName;
                default:
                    return null;
            }
        }
 
        public static string UnaryOperatorNameFromSyntaxKind(SyntaxKind kind, bool isChecked)
        {
            return UnaryOperatorNameFromSyntaxKindIfAny(kind, isChecked) ??
                WellKnownMemberNames.UnaryPlusOperatorName; // This can occur in the presence of syntax errors.
        }
 
        internal static string UnaryOperatorNameFromSyntaxKindIfAny(SyntaxKind kind, bool isChecked)
        {
            switch (kind)
            {
                case SyntaxKind.PlusToken: return WellKnownMemberNames.UnaryPlusOperatorName;
                case SyntaxKind.MinusToken: return isChecked ? WellKnownMemberNames.CheckedUnaryNegationOperatorName : WellKnownMemberNames.UnaryNegationOperatorName;
                case SyntaxKind.TildeToken: return WellKnownMemberNames.OnesComplementOperatorName;
                case SyntaxKind.ExclamationToken: return WellKnownMemberNames.LogicalNotOperatorName;
                case SyntaxKind.PlusPlusToken: return isChecked ? WellKnownMemberNames.CheckedIncrementOperatorName : WellKnownMemberNames.IncrementOperatorName;
                case SyntaxKind.MinusMinusToken: return isChecked ? WellKnownMemberNames.CheckedDecrementOperatorName : WellKnownMemberNames.DecrementOperatorName;
                case SyntaxKind.TrueKeyword: return WellKnownMemberNames.TrueOperatorName;
                case SyntaxKind.FalseKeyword: return WellKnownMemberNames.FalseOperatorName;
                default:
                    return null;
            }
        }
 
        public static string OperatorNameFromDeclaration(OperatorDeclarationSyntax declaration)
        {
            return OperatorNameFromDeclaration((Syntax.InternalSyntax.OperatorDeclarationSyntax)(declaration.Green));
        }
 
        public static string OperatorNameFromDeclaration(Syntax.InternalSyntax.OperatorDeclarationSyntax declaration)
        {
            var opTokenKind = declaration.OperatorToken.Kind;
            bool isChecked = declaration.CheckedKeyword?.Kind == SyntaxKind.CheckedKeyword;
 
            if (SyntaxFacts.IsBinaryExpressionOperatorToken(opTokenKind))
            {
                // Some tokens may be either unary or binary operators (e.g. +, -).
                if (opTokenKind != SyntaxKind.AsteriskToken && // IsPrefixUnaryExpressionOperatorToken treats it as pointer dereference operator
                    SyntaxFacts.IsPrefixUnaryExpressionOperatorToken(opTokenKind) &&
                    declaration.ParameterList.Parameters.Count == 1)
                {
                    return OperatorFacts.UnaryOperatorNameFromSyntaxKind(opTokenKind, isChecked);
                }
 
                return OperatorFacts.BinaryOperatorNameFromSyntaxKind(opTokenKind, isChecked);
            }
            else if (SyntaxFacts.IsUnaryOperatorDeclarationToken(opTokenKind))
            {
                return OperatorFacts.UnaryOperatorNameFromSyntaxKind(opTokenKind, isChecked);
            }
            else
            {
                // fallback for error recovery
                return WellKnownMemberNames.UnaryPlusOperatorName;
            }
        }
 
        public static string OperatorNameFromDeclaration(ConversionOperatorDeclarationSyntax declaration)
        {
            return OperatorNameFromDeclaration((Syntax.InternalSyntax.ConversionOperatorDeclarationSyntax)(declaration.Green));
        }
 
        public static string OperatorNameFromDeclaration(Syntax.InternalSyntax.ConversionOperatorDeclarationSyntax declaration)
        {
            switch (declaration.ImplicitOrExplicitKeyword.Kind)
            {
                case SyntaxKind.ImplicitKeyword:
                    return WellKnownMemberNames.ImplicitConversionName;
                default:
                    return declaration.CheckedKeyword?.Kind == SyntaxKind.CheckedKeyword ?
                                WellKnownMemberNames.CheckedExplicitConversionName :
                                WellKnownMemberNames.ExplicitConversionName;
            }
        }
 
        public static string UnaryOperatorNameFromOperatorKind(UnaryOperatorKind kind, bool isChecked)
        {
            switch (kind & UnaryOperatorKind.OpMask)
            {
                case UnaryOperatorKind.UnaryPlus: return WellKnownMemberNames.UnaryPlusOperatorName;
                case UnaryOperatorKind.UnaryMinus: return isChecked ? WellKnownMemberNames.CheckedUnaryNegationOperatorName : WellKnownMemberNames.UnaryNegationOperatorName;
                case UnaryOperatorKind.BitwiseComplement: return WellKnownMemberNames.OnesComplementOperatorName;
                case UnaryOperatorKind.LogicalNegation: return WellKnownMemberNames.LogicalNotOperatorName;
                case UnaryOperatorKind.PostfixIncrement:
                case UnaryOperatorKind.PrefixIncrement: return isChecked ? WellKnownMemberNames.CheckedIncrementOperatorName : WellKnownMemberNames.IncrementOperatorName;
                case UnaryOperatorKind.PostfixDecrement:
                case UnaryOperatorKind.PrefixDecrement: return isChecked ? WellKnownMemberNames.CheckedDecrementOperatorName : WellKnownMemberNames.DecrementOperatorName;
                case UnaryOperatorKind.True: return WellKnownMemberNames.TrueOperatorName;
                case UnaryOperatorKind.False: return WellKnownMemberNames.FalseOperatorName;
                default:
                    throw ExceptionUtilities.UnexpectedValue(kind & UnaryOperatorKind.OpMask);
            }
        }
 
        public static string BinaryOperatorNameFromOperatorKind(BinaryOperatorKind kind, bool isChecked)
        {
            switch (kind & BinaryOperatorKind.OpMask)
            {
                case BinaryOperatorKind.Addition: return isChecked ? WellKnownMemberNames.CheckedAdditionOperatorName : WellKnownMemberNames.AdditionOperatorName;
                case BinaryOperatorKind.And: return WellKnownMemberNames.BitwiseAndOperatorName;
                case BinaryOperatorKind.Division: return isChecked ? WellKnownMemberNames.CheckedDivisionOperatorName : WellKnownMemberNames.DivisionOperatorName;
                case BinaryOperatorKind.Equal: return WellKnownMemberNames.EqualityOperatorName;
                case BinaryOperatorKind.GreaterThan: return WellKnownMemberNames.GreaterThanOperatorName;
                case BinaryOperatorKind.GreaterThanOrEqual: return WellKnownMemberNames.GreaterThanOrEqualOperatorName;
                case BinaryOperatorKind.LeftShift: return WellKnownMemberNames.LeftShiftOperatorName;
                case BinaryOperatorKind.LessThan: return WellKnownMemberNames.LessThanOperatorName;
                case BinaryOperatorKind.LessThanOrEqual: return WellKnownMemberNames.LessThanOrEqualOperatorName;
                case BinaryOperatorKind.Multiplication: return isChecked ? WellKnownMemberNames.CheckedMultiplyOperatorName : WellKnownMemberNames.MultiplyOperatorName;
                case BinaryOperatorKind.Or: return WellKnownMemberNames.BitwiseOrOperatorName;
                case BinaryOperatorKind.NotEqual: return WellKnownMemberNames.InequalityOperatorName;
                case BinaryOperatorKind.Remainder: return WellKnownMemberNames.ModulusOperatorName;
                case BinaryOperatorKind.RightShift: return WellKnownMemberNames.RightShiftOperatorName;
                case BinaryOperatorKind.UnsignedRightShift: return WellKnownMemberNames.UnsignedRightShiftOperatorName;
                case BinaryOperatorKind.Subtraction: return isChecked ? WellKnownMemberNames.CheckedSubtractionOperatorName : WellKnownMemberNames.SubtractionOperatorName;
                case BinaryOperatorKind.Xor: return WellKnownMemberNames.ExclusiveOrOperatorName;
                default:
                    throw ExceptionUtilities.UnexpectedValue(kind & BinaryOperatorKind.OpMask);
            }
        }
    }
}