Browse Source

Added unit tests for C# implicit conversions and fixed a few bugs.

newNRvisualizers
Daniel Grunwald 15 years ago
parent
commit
e19cf3785c
  1. 157
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConversionsTest.cs
  2. 3
      ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj
  3. 48
      ICSharpCode.NRefactory/CSharp/Resolver/Conversions.cs
  4. 2
      ICSharpCode.NRefactory/TypeSystem/ExtensionMethods.cs
  5. 12
      ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs
  6. 12
      ICSharpCode.NRefactory/TypeSystem/ParameterizedType.cs

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

@ -0,0 +1,157 @@ @@ -0,0 +1,157 @@
// Copyright (c) 2010 AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using System.Collections;
using System.Collections.Generic;
using ICSharpCode.NRefactory.TypeSystem;
using NUnit.Framework;
namespace ICSharpCode.NRefactory.CSharp.Resolver
{
[TestFixture]
public class ConversionsTest
{
IProjectContent mscorlib = CecilLoaderTests.Mscorlib;
Conversions conversions = new Conversions(CecilLoaderTests.Mscorlib);
bool ImplicitConversion(Type from, Type to)
{
IType from2 = from.ToTypeReference().Resolve(mscorlib);
IType to2 = to.ToTypeReference().Resolve(mscorlib);
return conversions.ImplicitConversion(from2, to2);
}
bool ImplicitConversion(Type from, IType to)
{
IType from2 = from.ToTypeReference().Resolve(mscorlib);
return conversions.ImplicitConversion(from2, to);
}
bool ImplicitConversion(IType from, Type to)
{
IType to2 = to.ToTypeReference().Resolve(mscorlib);
return conversions.ImplicitConversion(from, to2);
}
[Test]
public void IdentityConversions()
{
Assert.IsTrue(ImplicitConversion(typeof(char), typeof(char)));
Assert.IsTrue(ImplicitConversion(typeof(string), typeof(string)));
Assert.IsTrue(conversions.ImplicitConversion(SharedTypes.Dynamic, SharedTypes.Dynamic));
Assert.IsTrue(conversions.ImplicitConversion(SharedTypes.UnknownType, SharedTypes.UnknownType));
Assert.IsTrue(conversions.ImplicitConversion(SharedTypes.Null, SharedTypes.Null));
}
[Test]
public void PrimitiveConversions()
{
Assert.IsTrue(ImplicitConversion(typeof(char), typeof(ushort)));
Assert.IsFalse(ImplicitConversion(typeof(byte), typeof(char)));
Assert.IsTrue(ImplicitConversion(typeof(int), typeof(long)));
Assert.IsFalse(ImplicitConversion(typeof(long), typeof(int)));
Assert.IsTrue(ImplicitConversion(typeof(int), typeof(float)));
Assert.IsFalse(ImplicitConversion(typeof(bool), typeof(float)));
Assert.IsTrue(ImplicitConversion(typeof(float), typeof(double)));
Assert.IsFalse(ImplicitConversion(typeof(float), typeof(decimal)));
}
[Test]
public void NullableConversions()
{
Assert.IsTrue(ImplicitConversion(typeof(char), typeof(ushort?)));
Assert.IsFalse(ImplicitConversion(typeof(byte), typeof(char?)));
Assert.IsTrue(ImplicitConversion(typeof(int), typeof(long?)));
Assert.IsFalse(ImplicitConversion(typeof(long), typeof(int?)));
Assert.IsTrue(ImplicitConversion(typeof(int), typeof(float?)));
Assert.IsFalse(ImplicitConversion(typeof(bool), typeof(float?)));
Assert.IsTrue(ImplicitConversion(typeof(float), typeof(double?)));
Assert.IsFalse(ImplicitConversion(typeof(float), typeof(decimal?)));
}
[Test]
public void NullableConversions2()
{
Assert.IsTrue(ImplicitConversion(typeof(char?), typeof(ushort?)));
Assert.IsFalse(ImplicitConversion(typeof(byte?), typeof(char?)));
Assert.IsTrue(ImplicitConversion(typeof(int?), typeof(long?)));
Assert.IsFalse(ImplicitConversion(typeof(long?), typeof(int?)));
Assert.IsTrue(ImplicitConversion(typeof(int?), typeof(float?)));
Assert.IsFalse(ImplicitConversion(typeof(bool?), typeof(float?)));
Assert.IsTrue(ImplicitConversion(typeof(float?), typeof(double?)));
Assert.IsFalse(ImplicitConversion(typeof(float?), typeof(decimal?)));
}
[Test]
public void NullLiteralConversions()
{
Assert.IsTrue(ImplicitConversion(SharedTypes.Null, typeof(int?)));
Assert.IsTrue(ImplicitConversion(SharedTypes.Null, typeof(char?)));
Assert.IsFalse(ImplicitConversion(SharedTypes.Null, typeof(int)));
Assert.IsTrue(ImplicitConversion(SharedTypes.Null, typeof(object)));
Assert.IsTrue(conversions.ImplicitConversion(SharedTypes.Null, SharedTypes.Dynamic));
Assert.IsTrue(ImplicitConversion(SharedTypes.Null, typeof(string)));
Assert.IsTrue(ImplicitConversion(SharedTypes.Null, typeof(int[])));
}
[Test]
public void SimpleReferenceConversions()
{
Assert.IsTrue(ImplicitConversion(typeof(string), typeof(object)));
Assert.IsTrue(ImplicitConversion(typeof(BitArray), typeof(ICollection)));
Assert.IsTrue(ImplicitConversion(typeof(IList), typeof(IEnumerable)));
Assert.IsFalse(ImplicitConversion(typeof(object), typeof(string)));
Assert.IsFalse(ImplicitConversion(typeof(ICollection), typeof(BitArray)));
Assert.IsFalse(ImplicitConversion(typeof(IEnumerable), typeof(IList)));
}
[Test]
public void SimpleDynamicConversions()
{
Assert.IsTrue(ImplicitConversion(typeof(string), SharedTypes.Dynamic));
Assert.IsTrue(ImplicitConversion(SharedTypes.Dynamic, typeof(string)));
Assert.IsTrue(ImplicitConversion(typeof(int), SharedTypes.Dynamic));
Assert.IsTrue(ImplicitConversion(SharedTypes.Dynamic, typeof(int)));
}
[Test]
public void ArrayConversions()
{
Assert.IsTrue(ImplicitConversion(typeof(string[]), typeof(object[])));
Assert.IsTrue(ImplicitConversion(typeof(string[,]), typeof(object[,])));
Assert.IsFalse(ImplicitConversion(typeof(string[]), typeof(object[,])));
Assert.IsFalse(ImplicitConversion(typeof(object[]), typeof(string[])));
Assert.IsTrue(ImplicitConversion(typeof(string[]), typeof(IList<string>)));
Assert.IsFalse(ImplicitConversion(typeof(string[,]), typeof(IList<string>)));
Assert.IsTrue(ImplicitConversion(typeof(string[]), typeof(IList<object>)));
Assert.IsTrue(ImplicitConversion(typeof(string[]), typeof(Array)));
Assert.IsTrue(ImplicitConversion(typeof(string[]), typeof(ICloneable)));
Assert.IsFalse(ImplicitConversion(typeof(Array), typeof(string[])));
Assert.IsFalse(ImplicitConversion(typeof(object), typeof(object[])));
}
[Test]
public void VarianceConversions()
{
Assert.IsTrue(ImplicitConversion(typeof(List<string>), typeof(IEnumerable<object>)));
Assert.IsFalse(ImplicitConversion(typeof(List<object>), typeof(IEnumerable<string>)));
Assert.IsTrue(ImplicitConversion(typeof(IEnumerable<string>), typeof(IEnumerable<object>)));
Assert.IsFalse(ImplicitConversion(typeof(ICollection<string>), typeof(ICollection<object>)));
Assert.IsTrue(ImplicitConversion(typeof(Comparer<object>), typeof(IComparer<string>)));
Assert.IsTrue(ImplicitConversion(typeof(Comparer<object>), typeof(IComparer<Array>)));
Assert.IsFalse(ImplicitConversion(typeof(Comparer<object>), typeof(Comparer<string>)));
Assert.IsFalse(ImplicitConversion(typeof(List<object>), typeof(IEnumerable<string>)));
Assert.IsTrue(ImplicitConversion(typeof(IEnumerable<string>), typeof(IEnumerable<object>)));
Assert.IsTrue(ImplicitConversion(typeof(Func<ICollection, ICollection>), typeof(Func<IList, IEnumerable>)));
Assert.IsTrue(ImplicitConversion(typeof(Func<IEnumerable, IList>), typeof(Func<ICollection, ICollection>)));
Assert.IsFalse(ImplicitConversion(typeof(Func<ICollection, ICollection>), typeof(Func<IEnumerable, IList>)));
Assert.IsFalse(ImplicitConversion(typeof(Func<IList, IEnumerable>), typeof(Func<ICollection, ICollection>)));
}
}
}

3
ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj

@ -43,6 +43,7 @@ @@ -43,6 +43,7 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="CSharp\Resolver\ConversionsTest.cs" />
<Compile Include="FormattingTests\TestBraceStlye.cs" />
<Compile Include="FormattingTests\TestFormattingBugs.cs" />
<Compile Include="FormattingTests\TestSpacingVisitor.cs" />
@ -64,6 +65,8 @@ @@ -64,6 +65,8 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Folder Include="CSharp" />
<Folder Include="CSharp\Resolver" />
<Folder Include="Util" />
<Folder Include="TypeSystem" />
</ItemGroup>

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

@ -19,20 +19,36 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -19,20 +19,36 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
throw new ArgumentNullException("context");
this.context = context;
this.objectType = context.GetClass(typeof(object)) ?? SharedTypes.UnknownType;
this.dynamicErasure = new DynamicErasure(this);
}
#region ImplicitConversion
public bool ImplicitConversion(IType fromType, IType toType)
{
if (fromType == null)
throw new ArgumentNullException("fromType");
if (toType == null)
throw new ArgumentNullException("toType");
// C# 4.0 spec: §6.1
return IdentityConversion(fromType, toType)
|| ImplicitNumericConversion(fromType, toType)
|| ImplicitEnumerationConversion(fromType, toType)
|| ImplicitNullableConversion(fromType, toType)
|| NullLiteralConversion(fromType, toType)
|| ImplicitReferenceConversion(fromType, toType)
|| BoxingConversion(fromType, toType)
|| ImplicitConstantExpressionConversion(fromType, toType);
if (IdentityConversion(fromType, toType))
return true;
if (ImplicitNumericConversion(fromType, toType))
return true;
if (ImplicitReferenceConversion(fromType, toType))
return true;
if (ImplicitEnumerationConversion(fromType, toType))
return true;
if (ImplicitNullableConversion(fromType, toType))
return true;
if (NullLiteralConversion(fromType, toType))
return true;
if (BoxingConversion(fromType, toType))
return true;
if (ImplicitDynamicConversion(fromType, toType))
return true;
if (ImplicitConstantExpressionConversion(fromType, toType))
return true;
return false;
}
#endregion
@ -43,10 +59,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -43,10 +59,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
bool IdentityConversion(IType fromType, IType toType)
{
// C# 4.0 spec: §6.1.1
DynamicErasure erasure = new DynamicErasure(this);
return fromType.AcceptVisitor(erasure).Equals(toType.AcceptVisitor(erasure));
return fromType.AcceptVisitor(dynamicErasure).Equals(toType.AcceptVisitor(dynamicErasure));
}
readonly DynamicErasure dynamicErasure;
sealed class DynamicErasure : TypeVisitor
{
readonly IType objectType;
@ -166,7 +183,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -166,7 +183,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
ParameterizedType toPT = toType as ParameterizedType;
if (fromArray.Dimensions == 1 && toPT != null && toPT.TypeArguments.Count == 1
&& toPT.Namespace == "System.Collections.Generic"
&& (toPT.Name == "List" || toPT.Name == "Collection" || toPT.Name == "IEnumerable"))
&& (toPT.Name == "IList" || toPT.Name == "ICollection" || toPT.Name == "IEnumerable"))
{
// array covariance plays a part here as well (string[] is IList<object>)
return IdentityConversion(fromArray.ElementType, toPT.TypeArguments[0])
@ -189,6 +206,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -189,6 +206,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (t == SharedTypes.Dynamic || t.Equals(objectType))
return true;
// let GetAllBaseTypes do the work for us
foreach (IType baseType in s.GetAllBaseTypes(context)) {
if (IdentityOrVarianceConversion(baseType, t))
return true;
@ -202,11 +220,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -202,11 +220,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (def != null && def.Equals(t.GetDefinition())) {
ParameterizedType ps = s as ParameterizedType;
ParameterizedType pt = t as ParameterizedType;
if (ps != null && pt != null
if (ps != null && pt != null
&& ps.TypeArguments.Count == pt.TypeArguments.Count
&& ps.TypeArguments.Count == def.TypeParameters.Count)
&& ps.TypeArguments.Count == def.TypeParameters.Count)
{
// §13.1.3.2 Variance Conversion
// C# 4.0 spec: §13.1.3.2 Variance Conversion
for (int i = 0; i < def.TypeParameters.Count; i++) {
IType si = ps.TypeArguments[i];
IType ti = pt.TypeArguments[i];
@ -222,6 +240,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -222,6 +240,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (!ImplicitReferenceConversion(ti, si))
return false;
break;
default:
return false;
}
}
} else if (ps != null || pt != null) {

2
ICSharpCode.NRefactory/TypeSystem/ExtensionMethods.cs

@ -20,7 +20,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -20,7 +20,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
/// Note that this method does not return all supertypes - doing so is impossible due to contravariance
/// (and underisable for covariance and the list could become very large).
/// This method may return an infinite list for certain (invalid) class declarations like <c>class C{T} : C{C{T}}</c>
/// TODO: we could ensure a finite list by filtering out cyclic inheritance
/// TODO: ensure we never produce infinite lists (important for C# Conversions implementation)
/// </remarks>
public static IEnumerable<IType> GetAllBaseTypes(this IType type, ITypeResolveContext context)
{

12
ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs

@ -159,7 +159,17 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -159,7 +159,17 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
public bool? IsReferenceType {
get {
return this.ClassType == ClassType.Enum || this.ClassType == ClassType.Struct;
switch (this.ClassType) {
case ClassType.Class:
case ClassType.Interface:
case ClassType.Delegate:
return true;
case ClassType.Enum:
case ClassType.Struct:
return false;
default:
return null;
}
}
}

12
ICSharpCode.NRefactory/TypeSystem/ParameterizedType.cs

@ -252,13 +252,11 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -252,13 +252,11 @@ namespace ICSharpCode.NRefactory.TypeSystem
public bool Equals(IType other)
{
ParameterizedType c = other as ParameterizedType;
if (c == null || typeArguments.Length != c.typeArguments.Length)
if (c == null || !genericType.Equals(c.genericType) || typeArguments.Length != c.typeArguments.Length)
return false;
if (genericType.Equals(c.genericType)) {
for (int i = 0; i < typeArguments.Length; i++) {
if (!typeArguments[i].Equals(c.typeArguments[i]))
return false;
}
for (int i = 0; i < typeArguments.Length; i++) {
if (!typeArguments[i].Equals(c.typeArguments[i]))
return false;
}
return true;
}
@ -287,7 +285,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -287,7 +285,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
if (def == null)
return g;
IType[] ta = new IType[typeArguments.Length];
bool isSame = g == this;
bool isSame = g == genericType;
for (int i = 0; i < typeArguments.Length; i++) {
ta[i] = typeArguments[i].AcceptVisitor(visitor);
isSame &= ta[i] == typeArguments[i];

Loading…
Cancel
Save