Browse Source

Add BetterConversion logic to C# Conversions.

newNRvisualizers
Daniel Grunwald 15 years ago
parent
commit
f3a8325390
  1. 48
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConversionsTest.cs
  2. 76
      ICSharpCode.NRefactory/CSharp/Resolver/Conversions.cs

48
ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConversionsTest.cs

@ -55,6 +55,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -55,6 +55,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
Assert.IsFalse(ImplicitConversion(typeof(bool), typeof(float)));
Assert.IsTrue(ImplicitConversion(typeof(float), typeof(double)));
Assert.IsFalse(ImplicitConversion(typeof(float), typeof(decimal)));
Assert.IsTrue(ImplicitConversion(typeof(char), typeof(long)));
Assert.IsTrue(ImplicitConversion(typeof(uint), typeof(long)));
}
[Test]
@ -239,5 +241,51 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -239,5 +241,51 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
Assert.IsFalse(IntegerLiteralConversion(0, typeof(IComparable<short>)));
Assert.IsFalse(IntegerLiteralConversion(0, typeof(IComparable<long>)));
}
int BetterConversion(Type s, Type t1, Type t2)
{
IType sType = s.ToTypeReference().Resolve(mscorlib);
IType t1Type = t1.ToTypeReference().Resolve(mscorlib);
IType t2Type = t2.ToTypeReference().Resolve(mscorlib);
return conversions.BetterConversion(sType, t1Type, t2Type);
}
int BetterConversion(object value, Type t1, Type t2)
{
IType fromType = value.GetType().ToTypeReference().Resolve(mscorlib);
ConstantResolveResult crr = new ConstantResolveResult(fromType, value);
IType t1Type = t1.ToTypeReference().Resolve(mscorlib);
IType t2Type = t2.ToTypeReference().Resolve(mscorlib);
return conversions.BetterConversion(crr, t1Type, t2Type);
}
[Test]
public void BetterConversion()
{
Assert.AreEqual(1, BetterConversion(typeof(string), typeof(string), typeof(object)));
Assert.AreEqual(2, BetterConversion(typeof(string), typeof(object), typeof(IComparable<string>)));
Assert.AreEqual(0, BetterConversion(typeof(string), typeof(IEnumerable<char>), typeof(IComparable<string>)));
}
[Test]
public void BetterPrimitiveConversion()
{
Assert.AreEqual(1, BetterConversion(typeof(short), typeof(int), typeof(long)));
Assert.AreEqual(1, BetterConversion(typeof(short), typeof(int), typeof(uint)));
Assert.AreEqual(2, BetterConversion(typeof(ushort), typeof(uint), typeof(int)));
}
[Test]
public void BetterNullableConversion()
{
Assert.AreEqual(0, BetterConversion(typeof(byte), typeof(int), typeof(uint?)));
Assert.AreEqual(0, BetterConversion(typeof(byte?), typeof(int?), typeof(uint?)));
Assert.AreEqual(1, BetterConversion(typeof(byte), typeof(ushort?), typeof(uint?)));
Assert.AreEqual(2, BetterConversion(typeof(byte?), typeof(ulong?), typeof(uint?)));
Assert.AreEqual(0, BetterConversion(typeof(byte), typeof(ushort?), typeof(uint)));
Assert.AreEqual(0, BetterConversion(typeof(byte), typeof(ushort?), typeof(int)));
Assert.AreEqual(2, BetterConversion(typeof(byte), typeof(ulong?), typeof(uint)));
Assert.AreEqual(0, BetterConversion(typeof(byte), typeof(ulong?), typeof(int)));
}
}
}

76
ICSharpCode.NRefactory/CSharp/Resolver/Conversions.cs

@ -8,6 +8,9 @@ using ICSharpCode.NRefactory.TypeSystem; @@ -8,6 +8,9 @@ using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.Resolver
{
/// <summary>
/// Contains logic that determines whether an implicit conversion exists between two types.
/// </summary>
public class Conversions
{
readonly ITypeResolveContext context;
@ -117,7 +120,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -117,7 +120,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
// Conversions to integral types: look at the table
return from >= TypeCode.Char && from <= TypeCode.UInt32
&& to >= TypeCode.Int16 && to <= TypeCode.UInt64
&& implicitNumericConversionLookup[to - TypeCode.Int16, from - TypeCode.Char];
&& implicitNumericConversionLookup[from - TypeCode.Char, to - TypeCode.Int16];
}
}
#endregion
@ -312,5 +315,76 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -312,5 +315,76 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#endregion
// TODO: add support for user-defined conversions
#region BetterConversion
/// <summary>
/// Gets the better conversion (C# 4.0 spec, §7.5.3.3)
/// </summary>
/// <returns>0 = neither is better; 1 = t1 is better; 2 = t2 is better</returns>
public int BetterConversion(ConstantResolveResult rr, IType t1, IType t2)
{
// TODO: implement the special logic for anonymous functions
return BetterConversion(rr.Type, t1, t2);
}
/// <summary>
/// Gets the better conversion (C# 4.0 spec, §7.5.3.4)
/// </summary>
/// <returns>0 = neither is better; 1 = t1 is better; 2 = t2 is better</returns>
public int BetterConversion(IType s, IType t1, IType t2)
{
bool ident1 = IdentityConversion(s, t1);
bool ident2 = IdentityConversion(s, t2);
if (ident1 && !ident2)
return 1;
if (ident2 && !ident1)
return 2;
return BetterConversionTarget(t1, t2);
}
/// <summary>
/// Gets the better conversion target (C# 4.0 spec, §7.5.3.5)
/// </summary>
/// <returns>0 = neither is better; 1 = t1 is better; 2 = t2 is better</returns>
int BetterConversionTarget(IType t1, IType t2)
{
bool t1To2 = ImplicitConversion(t1, t2);
bool t2To1 = ImplicitConversion(t2, t1);
if (t1To2 && !t2To1)
return 1;
if (t2To1 && !t1To2)
return 2;
TypeCode t1Code = ReflectionHelper.GetTypeCode(t1);
TypeCode t2Code = ReflectionHelper.GetTypeCode(t2);
if (IsBetterIntegralType(t1Code, t2Code))
return 1;
if (IsBetterIntegralType(t2Code, t1Code))
return 2;
return 0;
}
bool IsBetterIntegralType(TypeCode t1, TypeCode t2)
{
// signed types are better than unsigned types
switch (t1) {
case TypeCode.SByte:
return t2 == TypeCode.Byte || t2 == TypeCode.UInt16 || t2 == TypeCode.UInt32 || t2 == TypeCode.UInt64;
case TypeCode.Int16:
return t2 == TypeCode.UInt16 || t2 == TypeCode.UInt32 || t2 == TypeCode.UInt64;
case TypeCode.Int32:
return t2 == TypeCode.UInt32 || t2 == TypeCode.UInt64;
case TypeCode.Int64:
return t2 == TypeCode.UInt64;
default:
return false;
}
}
static void Test(short a) {}
static void Test(sbyte a)
{
Test(1);
}
#endregion
}
}

Loading…
Cancel
Save