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 @@ -115,6 +115,15 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
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]
public void ArrayConversions()
{
@ -153,5 +162,82 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -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<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 @@ -17,7 +17,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
ITypeResolveContext ctx = Mscorlib;
[TestFixtureSetUp]
public void SetUp()
public void FixtureSetUp()
{
// use "IncludeInternalMembers" so that Cecil results match C# parser results
CecilLoader loader = new CecilLoader() { IncludeInternalMembers = true };

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

@ -0,0 +1,22 @@ @@ -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 @@ -23,6 +23,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
#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)
{
if (fromType == null)
@ -36,8 +46,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -36,8 +46,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return true;
if (ImplicitReferenceConversion(fromType, toType))
return true;
if (ImplicitEnumerationConversion(fromType, toType))
return true;
if (ImplicitNullableConversion(fromType, toType))
return true;
if (NullLiteralConversion(fromType, toType))
@ -46,8 +54,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -46,8 +54,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return true;
if (ImplicitDynamicConversion(fromType, toType))
return true;
if (ImplicitConstantExpressionConversion(fromType, toType))
return true;
return false;
}
#endregion
@ -117,10 +123,15 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -117,10 +123,15 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#endregion
#region ImplicitEnumerationConversion
bool ImplicitEnumerationConversion(IType fromType, IType toType)
bool ImplicitEnumerationConversion(ConstantResolveResult rr, IType toType)
{
// 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;
}
#endregion
@ -271,10 +282,31 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -271,10 +282,31 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#endregion
#region ImplicitConstantExpressionConversion
bool ImplicitConstantExpressionConversion(IType fromType, IType toType)
bool ImplicitConstantExpressionConversion(ConstantResolveResult rr, IType toType)
{
// 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;
}
#endregion

1
ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj

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

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

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

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

@ -3,6 +3,7 @@ @@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.NRefactory.Util;
namespace ICSharpCode.NRefactory.TypeSystem.Implementation
@ -10,7 +11,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -10,7 +11,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
/// <summary>
/// Default implementation of <see cref="ITypeParameter"/>.
/// </summary>
public class DefaultTypeParameter : AbstractType, ITypeParameter, ISupportsInterning
public class DefaultTypeParameter : AbstractFreezable, ITypeParameter, ISupportsInterning
{
IEntity parent;
@ -58,11 +59,19 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -58,11 +59,19 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
this.name = name;
}
public override string Name {
public string 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 {
if (parent is IMethod)
return "``" + index.ToString();
@ -71,7 +80,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -71,7 +80,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
}
}
public override bool? IsReferenceType {
public bool? IsReferenceType {
get {
switch (flags.Data & (FlagReferenceTypeConstraint | FlagValueTypeConstraint)) {
case FlagReferenceTypeConstraint:
@ -84,6 +93,24 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -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()
{
int hashCode = parent.GetHashCode();
@ -93,7 +120,12 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -93,7 +120,12 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
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;
if (p == null)
@ -174,11 +206,16 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -174,11 +206,16 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
get { return null; }
}
public override IType AcceptVisitor(TypeVisitor visitor)
public IType AcceptVisitor(TypeVisitor visitor)
{
return visitor.VisitTypeParameter(this);
}
public IType VisitChildren(TypeVisitor visitor)
{
return this;
}
DefaultTypeDefinition GetDummyClassForTypeParameter()
{
DefaultTypeDefinition c = new DefaultTypeDefinition(ParentClass ?? ParentMethod.DeclaringTypeDefinition, this.Name);
@ -193,7 +230,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -193,7 +230,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
return c;
}
public override IEnumerable<IMethod> GetConstructors(ITypeResolveContext context)
public IEnumerable<IMethod> GetConstructors(ITypeResolveContext context)
{
if (HasDefaultConstructorConstraint || HasValueTypeConstraint) {
return new [] { DefaultMethod.CreateDefaultConstructor(GetDummyClassForTypeParameter()) };
@ -202,6 +239,51 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -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)
{
constraints = provider.InternList(constraints);

15
ICSharpCode.NRefactory/TypeSystem/SharedTypes.cs

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

Loading…
Cancel
Save