Browse Source

Merge remote-tracking branch 'upstream/master' into mansheng

newNRvisualizers
Mansheng Yang 14 years ago
parent
commit
8635a6f604
  1. 50
      ICSharpCode.NRefactory.CSharp/Resolver/CSharpConversions.cs
  2. 2
      ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/ArrayCreateExpressionTests.cs
  3. 18
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/ExplicitConversionsTest.cs

50
ICSharpCode.NRefactory.CSharp/Resolver/CSharpConversions.cs

@ -421,14 +421,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
&& ImplicitReferenceConversion(fromArray.ElementType, toArray.ElementType, subtypeCheckNestingDepth); && ImplicitReferenceConversion(fromArray.ElementType, toArray.ElementType, subtypeCheckNestingDepth);
} }
// conversion from single-dimensional array S[] to IList<T>: // conversion from single-dimensional array S[] to IList<T>:
ParameterizedType toPT = toType as ParameterizedType; IType toTypeArgument = UnpackGenericArrayInterface(toType);
if (fromArray.Dimensions == 1 && toPT != null) { if (fromArray.Dimensions == 1 && toTypeArgument != null) {
KnownTypeCode tc = toPT.GetDefinition().KnownTypeCode; // array covariance plays a part here as well (string[] is IList<object>)
if (tc == KnownTypeCode.IListOfT || tc == KnownTypeCode.ICollectionOfT || tc == KnownTypeCode.IEnumerableOfT || tc == KnownTypeCode.IReadOnlyListOfT) { return IdentityConversion(fromArray.ElementType, toTypeArgument)
// array covariance plays a part here as well (string[] is IList<object>) || ImplicitReferenceConversion(fromArray.ElementType, toTypeArgument, subtypeCheckNestingDepth);
return IdentityConversion(fromArray.ElementType, toPT.GetTypeArgument(0))
|| ImplicitReferenceConversion(fromArray.ElementType, toPT.GetTypeArgument(0), subtypeCheckNestingDepth);
}
} }
// conversion from any array to System.Array and the interfaces it implements: // conversion from any array to System.Array and the interfaces it implements:
IType systemArray = compilation.FindType(KnownTypeCode.Array); IType systemArray = compilation.FindType(KnownTypeCode.Array);
@ -439,6 +436,22 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return IsSubtypeOf(fromType, toType, subtypeCheckNestingDepth); return IsSubtypeOf(fromType, toType, subtypeCheckNestingDepth);
} }
/// <summary>
/// For IList{T}, ICollection{T}, IEnumerable{T} and IReadOnlyList{T}, returns T.
/// Otherwise, returns null.
/// </summary>
IType UnpackGenericArrayInterface(IType interfaceType)
{
ParameterizedType pt = interfaceType as ParameterizedType;
if (pt != null) {
KnownTypeCode tc = pt.GetDefinition().KnownTypeCode;
if (tc == KnownTypeCode.IListOfT || tc == KnownTypeCode.ICollectionOfT || tc == KnownTypeCode.IEnumerableOfT || tc == KnownTypeCode.IReadOnlyListOfT) {
return pt.GetTypeArgument(0);
}
}
return null;
}
// Determines whether s is a subtype of t. // Determines whether s is a subtype of t.
// Helper method used for ImplicitReferenceConversion, BoxingConversion and ImplicitTypeParameterConversion // Helper method used for ImplicitReferenceConversion, BoxingConversion and ImplicitTypeParameterConversion
@ -530,16 +543,21 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return false; return false;
return ExplicitReferenceConversion(fromArray.ElementType, toArray.ElementType); return ExplicitReferenceConversion(fromArray.ElementType, toArray.ElementType);
} }
ParameterizedType pt = fromType as ParameterizedType; IType fromTypeArgument = UnpackGenericArrayInterface(fromType);
if (pt != null && toArray.Dimensions == 1) { if (fromTypeArgument != null && toArray.Dimensions == 1) {
KnownTypeCode tc = pt.GetDefinition().KnownTypeCode; return ExplicitReferenceConversion(fromTypeArgument, toArray.ElementType)
if (tc == KnownTypeCode.IListOfT || tc == KnownTypeCode.ICollectionOfT || tc == KnownTypeCode.IEnumerableOfT || tc == KnownTypeCode.IReadOnlyListOfT) { || IdentityConversion(fromTypeArgument, toArray.ElementType);
return ExplicitReferenceConversion(pt.GetTypeArgument(0), toArray.ElementType)
|| IdentityConversion(pt.GetTypeArgument(0), toArray.ElementType);
}
} }
// Otherwise treat the array like a sealed class - require implicit conversion in the opposite direction // Otherwise treat the array like a sealed class - require implicit conversion in the opposite direction
return IsImplicitReferenceConversion(toType, fromType); return IsImplicitReferenceConversion(toType, fromType);
} else if (fromType.Kind == TypeKind.Array) {
ArrayType fromArray = (ArrayType)fromType;
IType toTypeArgument = UnpackGenericArrayInterface(toType);
if (toTypeArgument != null && fromArray.Dimensions == 1) {
return ExplicitReferenceConversion(fromArray.ElementType, toTypeArgument);
}
// Otherwise treat the array like a sealed class
return IsImplicitReferenceConversion(fromType, toType);
} else if (fromType.Kind == TypeKind.Delegate && toType.Kind == TypeKind.Delegate) { } else if (fromType.Kind == TypeKind.Delegate && toType.Kind == TypeKind.Delegate) {
ITypeDefinition def = fromType.GetDefinition(); ITypeDefinition def = fromType.GetDefinition();
if (def == null || !def.Equals(toType.GetDefinition())) if (def == null || !def.Equals(toType.GetDefinition()))
@ -570,7 +588,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
} }
} }
return true; return true;
} else if (IsSealedReferenceType(fromType) || fromType.Kind == TypeKind.Array) { } else if (IsSealedReferenceType(fromType)) {
// If the source type is sealed, explicit conversions can't do anything more than implicit ones // If the source type is sealed, explicit conversions can't do anything more than implicit ones
return IsImplicitReferenceConversion(fromType, toType); return IsImplicitReferenceConversion(fromType, toType);
} else if (IsSealedReferenceType(toType)) { } else if (IsSealedReferenceType(toType)) {

2
ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/ArrayCreateExpressionTests.cs

@ -158,7 +158,7 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Expression
}, ace.Initializer.Children.Select(c => c.Role).ToArray()); }, ace.Initializer.Children.Select(c => c.Role).ToArray());
} }
[Test, Ignore("Parser bug")] [Test]
public void ArrayInitializerWithCommaAtEnd() public void ArrayInitializerWithCommaAtEnd()
{ {
var ace = ParseUtilCSharp.ParseExpression<ArrayCreateExpression>("new [] { 1, }"); var ace = ParseUtilCSharp.ParseExpression<ArrayCreateExpression>("new [] { 1, }");

18
ICSharpCode.NRefactory.Tests/CSharp/Resolver/ExplicitConversionsTest.cs

@ -197,6 +197,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
Assert.AreEqual(C.None, ExplicitConversion(typeof(object[]), typeof(int[]))); Assert.AreEqual(C.None, ExplicitConversion(typeof(object[]), typeof(int[])));
Assert.AreEqual(C.None, ExplicitConversion(typeof(short[]), typeof(int[]))); Assert.AreEqual(C.None, ExplicitConversion(typeof(short[]), typeof(int[])));
Assert.AreEqual(C.ExplicitReferenceConversion, ExplicitConversion(typeof(Array), typeof(int[]))); Assert.AreEqual(C.ExplicitReferenceConversion, ExplicitConversion(typeof(Array), typeof(int[])));
}
[Test]
public void ExplicitReferenceConversion_InterfaceToArray()
{
Assert.AreEqual(C.ExplicitReferenceConversion, ExplicitConversion(typeof(ICloneable), typeof(int[]))); Assert.AreEqual(C.ExplicitReferenceConversion, ExplicitConversion(typeof(ICloneable), typeof(int[])));
Assert.AreEqual(C.ExplicitReferenceConversion, ExplicitConversion(typeof(IEnumerable<string>), typeof(string[]))); Assert.AreEqual(C.ExplicitReferenceConversion, ExplicitConversion(typeof(IEnumerable<string>), typeof(string[])));
Assert.AreEqual(C.ExplicitReferenceConversion, ExplicitConversion(typeof(IEnumerable<object>), typeof(string[]))); Assert.AreEqual(C.ExplicitReferenceConversion, ExplicitConversion(typeof(IEnumerable<object>), typeof(string[])));
@ -207,6 +212,19 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
Assert.AreEqual(C.None, ExplicitConversion(typeof(IEnumerable<short>), typeof(object[]))); Assert.AreEqual(C.None, ExplicitConversion(typeof(IEnumerable<short>), typeof(object[])));
} }
[Test]
public void ExplicitReferenceConversion_ArrayToInterface()
{
Assert.AreEqual(C.ImplicitReferenceConversion, ExplicitConversion(typeof(int[]), typeof(ICloneable)));
Assert.AreEqual(C.ImplicitReferenceConversion, ExplicitConversion(typeof(string[]), typeof(IEnumerable<string>)));
Assert.AreEqual(C.ImplicitReferenceConversion, ExplicitConversion(typeof(string[]), typeof(IEnumerable<object>)));
Assert.AreEqual(C.ExplicitReferenceConversion, ExplicitConversion(typeof(object[]), typeof(IEnumerable<string>)));
Assert.AreEqual(C.ExplicitReferenceConversion, ExplicitConversion(typeof(dynamic[]), typeof(IEnumerable<string>)));
Assert.AreEqual(C.ImplicitReferenceConversion, ExplicitConversion(typeof(int[]), typeof(IEnumerable<int>)));
Assert.AreEqual(C.None, ExplicitConversion(typeof(object[,]), typeof(IEnumerable<string>)));
Assert.AreEqual(C.None, ExplicitConversion(typeof(object[]), typeof(IEnumerable<short>)));
}
[Test] [Test]
public void ExplicitReferenceConversion_Delegates() public void ExplicitReferenceConversion_Delegates()
{ {

Loading…
Cancel
Save