|
// 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.Generic;
using System.Diagnostics;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis
{
/// <summary>
/// Contains helper methods for switch statement label constants
/// </summary>
internal static class SwitchConstantValueHelper
{
public static bool IsValidSwitchCaseLabelConstant(ConstantValue constant)
{
switch (constant.Discriminator)
{
case ConstantValueTypeDiscriminator.Null:
case ConstantValueTypeDiscriminator.SByte:
case ConstantValueTypeDiscriminator.Byte:
case ConstantValueTypeDiscriminator.Int16:
case ConstantValueTypeDiscriminator.UInt16:
case ConstantValueTypeDiscriminator.Int32:
case ConstantValueTypeDiscriminator.UInt32:
case ConstantValueTypeDiscriminator.Int64:
case ConstantValueTypeDiscriminator.UInt64:
case ConstantValueTypeDiscriminator.Char:
case ConstantValueTypeDiscriminator.Boolean:
case ConstantValueTypeDiscriminator.String:
return true;
default:
return false;
}
}
/// <summary>
/// Method used to compare ConstantValues for switch statement case labels
/// </summary>
/// <param name="first"></param>
/// <param name="second"></param>
/// <returns>A value that indicates the relative order of the objects being compared. The return value has these meanings:
/// Less than zero: first instance precedes second in the sort order.
/// Zero: first instance occurs in the same position in the sort order as second.
/// Greater than zero: first instance follows second in the sort order.
/// </returns>
public static int CompareSwitchCaseLabelConstants(ConstantValue first, ConstantValue second)
{
RoslynDebug.Assert(first != null);
RoslynDebug.Assert(second != null);
RoslynDebug.Assert(IsValidSwitchCaseLabelConstant(first));
RoslynDebug.Assert(IsValidSwitchCaseLabelConstant(second));
if (first.IsNull)
{
// first instance has ConstantValue Null.
// If second instance ConstantValue is Null, both instances are equal.
// Else, second instance is greater.
return second.IsNull ? 0 : -1;
}
else if (second.IsNull)
{
// second instance has ConstantValue Null and first instance has non-null ConstantValue.
// first instance is greater.
return 1;
}
switch (first.Discriminator)
{
case ConstantValueTypeDiscriminator.SByte:
case ConstantValueTypeDiscriminator.Int16:
case ConstantValueTypeDiscriminator.Int32:
case ConstantValueTypeDiscriminator.Int64:
return first.Int64Value.CompareTo(second.Int64Value);
case ConstantValueTypeDiscriminator.Boolean:
case ConstantValueTypeDiscriminator.Byte:
case ConstantValueTypeDiscriminator.UInt16:
case ConstantValueTypeDiscriminator.UInt32:
case ConstantValueTypeDiscriminator.UInt64:
case ConstantValueTypeDiscriminator.Char:
return first.UInt64Value.CompareTo(second.UInt64Value);
case ConstantValueTypeDiscriminator.String:
Debug.Assert(second.IsString);
return string.CompareOrdinal(first.StringValue, second.StringValue);
default:
throw ExceptionUtilities.UnexpectedValue(first.Discriminator);
}
}
public class SwitchLabelsComparer : EqualityComparer<object>
{
public override bool Equals(object? first, object? second)
{
RoslynDebug.Assert(first != null && second != null);
var firstConstant = first as ConstantValue;
if (firstConstant != null)
{
var secondConstant = second as ConstantValue;
if (secondConstant != null)
{
if (!IsValidSwitchCaseLabelConstant(firstConstant)
|| !IsValidSwitchCaseLabelConstant(secondConstant))
{
// We don't care about invalid case labels with duplicate value as
// we will generate diagnostics for invalid case label.
return firstConstant.Equals(secondConstant);
}
return CompareSwitchCaseLabelConstants(firstConstant, secondConstant) == 0;
}
}
var firstString = first as string;
if (firstString != null)
{
return string.Equals(firstString, second as string, System.StringComparison.Ordinal);
}
return first.Equals(second);
}
public override int GetHashCode(object obj)
{
var constant = obj as ConstantValue;
if (constant != null)
{
switch (constant.Discriminator)
{
case ConstantValueTypeDiscriminator.SByte:
case ConstantValueTypeDiscriminator.Int16:
case ConstantValueTypeDiscriminator.Int32:
case ConstantValueTypeDiscriminator.Int64:
return constant.Int64Value.GetHashCode();
case ConstantValueTypeDiscriminator.Boolean:
case ConstantValueTypeDiscriminator.Byte:
case ConstantValueTypeDiscriminator.UInt16:
case ConstantValueTypeDiscriminator.UInt32:
case ConstantValueTypeDiscriminator.UInt64:
case ConstantValueTypeDiscriminator.Char:
return constant.UInt64Value.GetHashCode();
case ConstantValueTypeDiscriminator.String:
return constant.RopeValue!.GetHashCode();
}
}
return obj.GetHashCode();
}
}
}
}
|