Browse Source

Add support for integer literal conversions.

newNRvisualizers
Daniel Grunwald 15 years ago
parent
commit
5c57f8fd0d
  1. 86
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConversionsTest.cs
  2. 2
      ICSharpCode.NRefactory.Tests/TypeSystem/CecilLoaderTests.cs
  3. 22
      ICSharpCode.NRefactory/CSharp/Resolver/ConstantResolveResult.cs
  4. 48
      ICSharpCode.NRefactory/CSharp/Resolver/Conversions.cs
  5. 1
      ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj
  6. 4
      ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractType.cs
  7. 96
      ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeParameter.cs
  8. 15
      ICSharpCode.NRefactory/TypeSystem/SharedTypes.cs

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

@ -115,6 +115,15 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
Assert.IsTrue(ImplicitConversion(SharedTypes.Dynamic, typeof(int))); Assert.IsTrue(ImplicitConversion(SharedTypes.Dynamic, typeof(int)));
} }
[Test]
public void ParameterizedTypeConversions()
{
Assert.IsTrue(ImplicitConversion(typeof(List<string>), typeof(ICollection<string>)));
Assert.IsTrue(ImplicitConversion(typeof(IList<string>), typeof(ICollection<string>)));
Assert.IsFalse(ImplicitConversion(typeof(List<string>), typeof(ICollection<object>)));
Assert.IsFalse(ImplicitConversion(typeof(IList<string>), typeof(ICollection<object>)));
}
[Test] [Test]
public void ArrayConversions() public void ArrayConversions()
{ {
@ -153,5 +162,82 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
Assert.IsFalse(ImplicitConversion(typeof(Func<ICollection, ICollection>), typeof(Func<IEnumerable, IList>))); Assert.IsFalse(ImplicitConversion(typeof(Func<ICollection, ICollection>), typeof(Func<IEnumerable, IList>)));
Assert.IsFalse(ImplicitConversion(typeof(Func<IList, IEnumerable>), typeof(Func<ICollection, ICollection>))); Assert.IsFalse(ImplicitConversion(typeof(Func<IList, IEnumerable>), typeof(Func<ICollection, ICollection>)));
} }
bool IntegerLiteralConversion(object value, Type to)
{
IType fromType = value.GetType().ToTypeReference().Resolve(mscorlib);
ConstantResolveResult crr = new ConstantResolveResult(fromType, value);
IType to2 = to.ToTypeReference().Resolve(mscorlib);
return conversions.ImplicitConversion(crr, to2);
}
[Test]
public void IntegerLiteralToEnumConversions()
{
Assert.IsTrue(IntegerLiteralConversion(0, typeof(LoaderOptimization)));
Assert.IsTrue(IntegerLiteralConversion(0L, typeof(LoaderOptimization)));
Assert.IsTrue(IntegerLiteralConversion(0, typeof(LoaderOptimization?)));
Assert.IsFalse(IntegerLiteralConversion(0, typeof(string)));
Assert.IsFalse(IntegerLiteralConversion(1, typeof(LoaderOptimization)));
}
[Test]
public void ImplicitConstantExpressionConversion()
{
Assert.IsTrue(IntegerLiteralConversion(0, typeof(int)));
Assert.IsTrue(IntegerLiteralConversion(0, typeof(ushort)));
Assert.IsTrue(IntegerLiteralConversion(0, typeof(sbyte)));
Assert.IsTrue (IntegerLiteralConversion(-1, typeof(int)));
Assert.IsFalse(IntegerLiteralConversion(-1, typeof(ushort)));
Assert.IsTrue (IntegerLiteralConversion(-1, typeof(sbyte)));
Assert.IsTrue (IntegerLiteralConversion(200, typeof(int)));
Assert.IsTrue (IntegerLiteralConversion(200, typeof(ushort)));
Assert.IsFalse(IntegerLiteralConversion(200, typeof(sbyte)));
}
[Test]
public void ImplicitLongConstantExpressionConversion()
{
Assert.IsFalse(IntegerLiteralConversion(0L, typeof(int)));
Assert.IsTrue(IntegerLiteralConversion(0L, typeof(long)));
Assert.IsTrue(IntegerLiteralConversion(0L, typeof(ulong)));
Assert.IsTrue(IntegerLiteralConversion(-1L, typeof(long)));
Assert.IsFalse(IntegerLiteralConversion(-1L, typeof(ulong)));
}
[Test]
public void ImplicitConstantExpressionConversionToNullable()
{
Assert.IsTrue(IntegerLiteralConversion(0, typeof(uint?)));
Assert.IsTrue(IntegerLiteralConversion(0, typeof(short?)));
Assert.IsTrue(IntegerLiteralConversion(0, typeof(byte?)));
Assert.IsFalse(IntegerLiteralConversion(-1, typeof(uint?)));
Assert.IsTrue (IntegerLiteralConversion(-1, typeof(short?)));
Assert.IsFalse(IntegerLiteralConversion(-1, typeof(byte?)));
Assert.IsTrue(IntegerLiteralConversion(200, typeof(uint?)));
Assert.IsTrue(IntegerLiteralConversion(200, typeof(short?)));
Assert.IsTrue(IntegerLiteralConversion(200, typeof(byte?)));
Assert.IsFalse(IntegerLiteralConversion(0L, typeof(uint?)));
Assert.IsTrue (IntegerLiteralConversion(0L, typeof(long?)));
Assert.IsTrue (IntegerLiteralConversion(0L, typeof(ulong?)));
Assert.IsTrue(IntegerLiteralConversion(-1L, typeof(long?)));
Assert.IsFalse(IntegerLiteralConversion(-1L, typeof(ulong?)));
}
[Test]
public void ImplicitConstantExpressionConversionNumberInterfaces()
{
Assert.IsTrue(IntegerLiteralConversion(0, typeof(IFormattable)));
Assert.IsTrue(IntegerLiteralConversion(0, typeof(IComparable<int>)));
Assert.IsFalse(IntegerLiteralConversion(0, typeof(IComparable<short>)));
Assert.IsFalse(IntegerLiteralConversion(0, typeof(IComparable<long>)));
}
} }
} }

2
ICSharpCode.NRefactory.Tests/TypeSystem/CecilLoaderTests.cs

@ -17,7 +17,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
ITypeResolveContext ctx = Mscorlib; ITypeResolveContext ctx = Mscorlib;
[TestFixtureSetUp] [TestFixtureSetUp]
public void SetUp() public void FixtureSetUp()
{ {
// use "IncludeInternalMembers" so that Cecil results match C# parser results // use "IncludeInternalMembers" so that Cecil results match C# parser results
CecilLoader loader = new CecilLoader() { IncludeInternalMembers = true }; CecilLoader loader = new CecilLoader() { IncludeInternalMembers = true };

22
ICSharpCode.NRefactory/CSharp/Resolver/ConstantResolveResult.cs

@ -0,0 +1,22 @@

using System;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.Resolver
{
public class ConstantResolveResult
{
public IType Type { get; set; }
public object Value { get; set; }
public ConstantResolveResult(IType type, object value)
{
if (type == null)
throw new ArgumentNullException("type");
if (value == null)
throw new ArgumentNullException("value");
this.Type = type;
this.Value = value;
}
}
}

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

@ -23,6 +23,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
} }
#region ImplicitConversion #region ImplicitConversion
public bool ImplicitConversion(ConstantResolveResult resolveResult, IType toType)
{
if (resolveResult == null)
throw new ArgumentNullException("resolveResult");
ConstantResolveResult crr = resolveResult as ConstantResolveResult;
if (crr != null && (ImplicitEnumerationConversion(crr, toType) || ImplicitConstantExpressionConversion(crr, toType)))
return true;
return ImplicitConversion(resolveResult.Type, toType);
}
public bool ImplicitConversion(IType fromType, IType toType) public bool ImplicitConversion(IType fromType, IType toType)
{ {
if (fromType == null) if (fromType == null)
@ -36,8 +46,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return true; return true;
if (ImplicitReferenceConversion(fromType, toType)) if (ImplicitReferenceConversion(fromType, toType))
return true; return true;
if (ImplicitEnumerationConversion(fromType, toType))
return true;
if (ImplicitNullableConversion(fromType, toType)) if (ImplicitNullableConversion(fromType, toType))
return true; return true;
if (NullLiteralConversion(fromType, toType)) if (NullLiteralConversion(fromType, toType))
@ -46,8 +54,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return true; return true;
if (ImplicitDynamicConversion(fromType, toType)) if (ImplicitDynamicConversion(fromType, toType))
return true; return true;
if (ImplicitConstantExpressionConversion(fromType, toType))
return true;
return false; return false;
} }
#endregion #endregion
@ -117,10 +123,15 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#endregion #endregion
#region ImplicitEnumerationConversion #region ImplicitEnumerationConversion
bool ImplicitEnumerationConversion(IType fromType, IType toType) bool ImplicitEnumerationConversion(ConstantResolveResult rr, IType toType)
{ {
// C# 4.0 spec: §6.1.3 // C# 4.0 spec: §6.1.3
// TODO: implement ImplicitEnumerationConversion and ImplicitConstantExpressionConversion TypeCode constantType = ReflectionHelper.GetTypeCode(rr.Type);
if (constantType >= TypeCode.SByte && constantType <= TypeCode.Decimal && Convert.ToDecimal(rr.Value) == 0) {
toType = UnpackNullable(toType) ?? toType;
ITypeDefinition toDef = toType.GetDefinition();
return toDef.ClassType == ClassType.Enum;
}
return false; return false;
} }
#endregion #endregion
@ -271,10 +282,31 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#endregion #endregion
#region ImplicitConstantExpressionConversion #region ImplicitConstantExpressionConversion
bool ImplicitConstantExpressionConversion(IType fromType, IType toType) bool ImplicitConstantExpressionConversion(ConstantResolveResult rr, IType toType)
{ {
// C# 4.0 spec: §6.1.9 // C# 4.0 spec: §6.1.9
// TODO: implement ImplicitEnumerationConversion and ImplicitConstantExpressionConversion TypeCode fromTypeCode = ReflectionHelper.GetTypeCode(rr.Type);
TypeCode toTypeCode = ReflectionHelper.GetTypeCode(UnpackNullable(toType) ?? toType);
if (fromTypeCode == TypeCode.Int64) {
long val = (long)rr.Value;
return val >= 0 && toTypeCode == TypeCode.UInt64;
} else if (fromTypeCode == TypeCode.Int32) {
int val = (int)rr.Value;
switch (toTypeCode) {
case TypeCode.SByte:
return val >= SByte.MinValue && val <= SByte.MaxValue;
case TypeCode.Byte:
return val >= Byte.MinValue && val <= Byte.MaxValue;
case TypeCode.Int16:
return val >= Int16.MinValue && val <= Int16.MaxValue;
case TypeCode.UInt16:
return val >= UInt16.MinValue && val <= UInt16.MaxValue;
case TypeCode.UInt32:
return val >= 0;
case TypeCode.UInt64:
return val >= 0;
}
}
return false; return false;
} }
#endregion #endregion

1
ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj

@ -139,6 +139,7 @@
<Compile Include="CSharp\Parser\mcs\MonoSymbolWriter.cs" /> <Compile Include="CSharp\Parser\mcs\MonoSymbolWriter.cs" />
<Compile Include="CSharp\Parser\mcs\outline.cs" /> <Compile Include="CSharp\Parser\mcs\outline.cs" />
<Compile Include="CSharp\Parser\mcs\roottypes.cs" /> <Compile Include="CSharp\Parser\mcs\roottypes.cs" />
<Compile Include="CSharp\Resolver\ConstantResolveResult.cs" />
<Compile Include="CSharp\Resolver\Conversions.cs" /> <Compile Include="CSharp\Resolver\Conversions.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TypeSystem\Accessibility.cs" /> <Compile Include="TypeSystem\Accessibility.cs" />

4
ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractType.cs

@ -10,7 +10,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
/// <summary> /// <summary>
/// Default implementation for IType interface. /// Default implementation for IType interface.
/// </summary> /// </summary>
public abstract class AbstractType : AbstractFreezable, IType public abstract class AbstractType : IType
{ {
public virtual string FullName { public virtual string FullName {
get { get {
@ -51,7 +51,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
return null; return null;
} }
public IType Resolve(ITypeResolveContext context) IType ITypeReference.Resolve(ITypeResolveContext context)
{ {
return this; return this;
} }

96
ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeParameter.cs

@ -3,6 +3,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using ICSharpCode.NRefactory.Util; using ICSharpCode.NRefactory.Util;
namespace ICSharpCode.NRefactory.TypeSystem.Implementation namespace ICSharpCode.NRefactory.TypeSystem.Implementation
@ -10,7 +11,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
/// <summary> /// <summary>
/// Default implementation of <see cref="ITypeParameter"/>. /// Default implementation of <see cref="ITypeParameter"/>.
/// </summary> /// </summary>
public class DefaultTypeParameter : AbstractType, ITypeParameter, ISupportsInterning public class DefaultTypeParameter : AbstractFreezable, ITypeParameter, ISupportsInterning
{ {
IEntity parent; IEntity parent;
@ -58,11 +59,19 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
this.name = name; this.name = name;
} }
public override string Name { public string Name {
get { return name; } get { return name; }
} }
public override string DotNetName { string INamedElement.FullName {
get { return name; }
}
string INamedElement.Namespace {
get { return string.Empty; }
}
public string DotNetName {
get { get {
if (parent is IMethod) if (parent is IMethod)
return "``" + index.ToString(); return "``" + index.ToString();
@ -71,7 +80,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
} }
} }
public override bool? IsReferenceType { public bool? IsReferenceType {
get { get {
switch (flags.Data & (FlagReferenceTypeConstraint | FlagValueTypeConstraint)) { switch (flags.Data & (FlagReferenceTypeConstraint | FlagValueTypeConstraint)) {
case FlagReferenceTypeConstraint: case FlagReferenceTypeConstraint:
@ -84,6 +93,24 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
} }
} }
int IType.TypeParameterCount {
get { return 0; }
}
IType IType.DeclaringType {
get { return null; }
}
ITypeDefinition IType.GetDefinition()
{
return null;
}
IType ITypeReference.Resolve(ITypeResolveContext context)
{
return this;
}
public override int GetHashCode() public override int GetHashCode()
{ {
int hashCode = parent.GetHashCode(); int hashCode = parent.GetHashCode();
@ -93,7 +120,12 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
return hashCode; return hashCode;
} }
public override bool Equals(IType other) public override bool Equals(object obj)
{
return Equals(obj as IType);
}
public bool Equals(IType other)
{ {
DefaultTypeParameter p = other as DefaultTypeParameter; DefaultTypeParameter p = other as DefaultTypeParameter;
if (p == null) if (p == null)
@ -174,11 +206,16 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
get { return null; } get { return null; }
} }
public override IType AcceptVisitor(TypeVisitor visitor) public IType AcceptVisitor(TypeVisitor visitor)
{ {
return visitor.VisitTypeParameter(this); return visitor.VisitTypeParameter(this);
} }
public IType VisitChildren(TypeVisitor visitor)
{
return this;
}
DefaultTypeDefinition GetDummyClassForTypeParameter() DefaultTypeDefinition GetDummyClassForTypeParameter()
{ {
DefaultTypeDefinition c = new DefaultTypeDefinition(ParentClass ?? ParentMethod.DeclaringTypeDefinition, this.Name); DefaultTypeDefinition c = new DefaultTypeDefinition(ParentClass ?? ParentMethod.DeclaringTypeDefinition, this.Name);
@ -193,7 +230,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
return c; return c;
} }
public override IEnumerable<IMethod> GetConstructors(ITypeResolveContext context) public IEnumerable<IMethod> GetConstructors(ITypeResolveContext context)
{ {
if (HasDefaultConstructorConstraint || HasValueTypeConstraint) { if (HasDefaultConstructorConstraint || HasValueTypeConstraint) {
return new [] { DefaultMethod.CreateDefaultConstructor(GetDummyClassForTypeParameter()) }; return new [] { DefaultMethod.CreateDefaultConstructor(GetDummyClassForTypeParameter()) };
@ -202,6 +239,51 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
} }
} }
public IEnumerable<IMethod> GetMethods(ITypeResolveContext context)
{
// TODO: get methods from constraints
IType objectType = context.GetClass("System.Object", 0, StringComparer.Ordinal);
IEnumerable<IMethod> objectMethods;
if (objectType != null)
objectMethods = objectType.GetMethods(context);
else
objectMethods = EmptyList<IMethod>.Instance;
// don't return static methods (those cannot be called from type parameter)
return objectMethods.Where(m => !m.IsStatic);
}
public IEnumerable<IProperty> GetProperties(ITypeResolveContext context)
{
return EmptyList<IProperty>.Instance;
}
public IEnumerable<IField> GetFields(ITypeResolveContext context)
{
return EmptyList<IField>.Instance;
}
public IEnumerable<IEvent> GetEvents(ITypeResolveContext context)
{
return EmptyList<IEvent>.Instance;
}
IEnumerable<IType> IType.GetNestedTypes(ITypeResolveContext context)
{
return EmptyList<IType>.Instance;
}
public IEnumerable<IType> GetBaseTypes(ITypeResolveContext context)
{
IType defaultBaseType = context.GetClass(HasValueTypeConstraint ? "System.ValueType" : "System.Object", 0, StringComparer.Ordinal);
if (defaultBaseType != null)
yield return defaultBaseType;
foreach (ITypeReference constraint in this.Constraints) {
yield return constraint.Resolve(context);
}
}
void ISupportsInterning.PrepareForInterning(IInterningProvider provider) void ISupportsInterning.PrepareForInterning(IInterningProvider provider)
{ {
constraints = provider.InternList(constraints); constraints = provider.InternList(constraints);

15
ICSharpCode.NRefactory/TypeSystem/SharedTypes.cs

@ -54,11 +54,6 @@ namespace ICSharpCode.NRefactory.TypeSystem
/// </summary> /// </summary>
sealed class UnknownTypeImpl : AbstractType sealed class UnknownTypeImpl : AbstractType
{ {
public UnknownTypeImpl()
{
Freeze();
}
public override string Name { public override string Name {
get { return "?"; } get { return "?"; }
} }
@ -83,11 +78,6 @@ namespace ICSharpCode.NRefactory.TypeSystem
/// </summary> /// </summary>
sealed class NullType : AbstractType sealed class NullType : AbstractType
{ {
public NullType()
{
Freeze();
}
public override string Name { public override string Name {
get { return "null"; } get { return "null"; }
} }
@ -112,11 +102,6 @@ namespace ICSharpCode.NRefactory.TypeSystem
/// </summary> /// </summary>
sealed class DynamicType : AbstractType sealed class DynamicType : AbstractType
{ {
public DynamicType()
{
Freeze();
}
public override string Name { public override string Name {
get { return "dynamic"; } get { return "dynamic"; }
} }

Loading…
Cancel
Save