Browse Source

Expose conversions as part of the ResolveResult.

newNRvisualizers
Daniel Grunwald 15 years ago
parent
commit
37626e1bc7
  1. 193
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/BinaryOperatorTests.cs
  2. 30
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/CastTests.cs
  3. 31
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConversionsTest.cs
  4. 32
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/ResolverTestBase.cs
  5. 94
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/UnaryOperatorTests.cs
  6. 18
      ICSharpCode.NRefactory/CSharp/Resolver/ByReferenceResolveResult.cs
  7. 295
      ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs
  8. 40
      ICSharpCode.NRefactory/CSharp/Resolver/ConversionResolveResult.cs
  9. 351
      ICSharpCode.NRefactory/CSharp/Resolver/Conversions.cs
  10. 7
      ICSharpCode.NRefactory/CSharp/Resolver/InvocationResolveResult.cs
  11. 14
      ICSharpCode.NRefactory/CSharp/Resolver/MemberResolveResult.cs
  12. 8
      ICSharpCode.NRefactory/CSharp/Resolver/MethodGroupResolveResult.cs
  13. 130
      ICSharpCode.NRefactory/CSharp/Resolver/OperatorResolveResult.cs
  14. 7
      ICSharpCode.NRefactory/CSharp/Resolver/ResolveResult.cs
  15. 2
      ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs
  16. 2
      ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj
  17. 1
      ICSharpCode.NRefactory/TypeSystem/PointerType.cs

193
ICSharpCode.NRefactory.Tests/CSharp/Resolver/BinaryOperatorTests.cs

@ -16,11 +16,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -16,11 +16,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
[Test]
public void Multiplication()
{
AssertType(typeof(int), resolver.ResolveBinaryOperator(
BinaryOperatorType.Multiply, MakeResult(typeof(int)), MakeResult(typeof(int))));
TestOperator(MakeResult(typeof(int)), BinaryOperatorType.Multiply, MakeResult(typeof(int)),
Conversion.IdentityConversion, Conversion.IdentityConversion, typeof(int));
AssertType(typeof(float), resolver.ResolveBinaryOperator(
BinaryOperatorType.Multiply, MakeResult(typeof(int)), MakeConstant(0.0f)));
TestOperator(MakeResult(typeof(int)), BinaryOperatorType.Multiply, MakeConstant(0.0f),
Conversion.ImplicitNumericConversion, Conversion.IdentityConversion, typeof(float));
AssertConstant(3.0f, resolver.ResolveBinaryOperator(
BinaryOperatorType.Multiply, MakeConstant(1.5f), MakeConstant(2)));
@ -28,8 +28,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -28,8 +28,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
AssertConstant(6, resolver.ResolveBinaryOperator(
BinaryOperatorType.Multiply, MakeConstant((byte)2), MakeConstant((byte)3)));
AssertType(typeof(long?), resolver.ResolveBinaryOperator(
BinaryOperatorType.Multiply, MakeResult(typeof(uint?)), MakeResult(typeof(int?))));
TestOperator(MakeResult(typeof(uint?)), BinaryOperatorType.Multiply, MakeResult(typeof(int?)),
Conversion.ImplicitNullableConversion, Conversion.ImplicitNullableConversion, typeof(long?));
AssertError(typeof(decimal), resolver.ResolveBinaryOperator(
BinaryOperatorType.Multiply, MakeResult(typeof(float)), MakeResult(typeof(decimal))));
@ -38,18 +38,12 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -38,18 +38,12 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
[Test]
public void Addition()
{
AssertType(typeof(int?), resolver.ResolveBinaryOperator(
BinaryOperatorType.Add, MakeResult(typeof(short)), MakeResult(typeof(byte?))));
TestOperator(MakeResult(typeof(short)), BinaryOperatorType.Add, MakeResult(typeof(byte?)),
Conversion.ImplicitNullableConversion, Conversion.ImplicitNullableConversion, typeof(int?));
AssertConstant(3.0, resolver.ResolveBinaryOperator(
BinaryOperatorType.Add, MakeConstant(1.0f), MakeConstant(2.0)));
AssertConstant(StringComparison.Ordinal, resolver.ResolveBinaryOperator(
BinaryOperatorType.Add, MakeConstant(StringComparison.InvariantCulture), MakeConstant(2)));
AssertConstant(StringComparison.OrdinalIgnoreCase, resolver.ResolveBinaryOperator(
BinaryOperatorType.Add, MakeConstant((short)3), MakeConstant(StringComparison.InvariantCulture)));
AssertConstant("Text", resolver.ResolveBinaryOperator(
BinaryOperatorType.Add, MakeConstant("Te"), MakeConstant("xt")));
@ -59,38 +53,76 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -59,38 +53,76 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
AssertError(typeof(ReflectionHelper.Null), resolver.ResolveBinaryOperator(
BinaryOperatorType.Add, MakeConstant(null), MakeConstant(null)));
AssertType(typeof(Action), resolver.ResolveBinaryOperator(
BinaryOperatorType.Add, MakeResult(typeof(Action)), MakeResult(typeof(Action))));
TestOperator(MakeResult(typeof(int?)), BinaryOperatorType.Add, MakeResult(typeof(uint?)),
Conversion.ImplicitNullableConversion, Conversion.ImplicitNullableConversion, typeof(long?));
AssertType(typeof(Action<string>), resolver.ResolveBinaryOperator(
BinaryOperatorType.Add, MakeResult(typeof(Action<object>)), MakeResult(typeof(Action<string>))));
TestOperator(MakeResult(typeof(ushort?)), BinaryOperatorType.Add, MakeResult(typeof(ushort?)),
Conversion.ImplicitNullableConversion, Conversion.ImplicitNullableConversion, typeof(int?));
Assert.IsTrue(resolver.ResolveBinaryOperator(
BinaryOperatorType.Add, MakeResult(typeof(Action<int>)), MakeResult(typeof(Action<long>))).IsError);
TestOperator(MakeConstant(1), BinaryOperatorType.Add, MakeConstant(null),
Conversion.ImplicitNullableConversion, Conversion.NullLiteralConversion, typeof(int?));
}
[Test]
public void StringPlusNull()
{
ResolveResult left = MakeResult(typeof(string));
var rr = (BinaryOperatorResolveResult)resolver.ResolveBinaryOperator(
BinaryOperatorType.Add, left, MakeConstant(null));
AssertType(typeof(string), rr);
Assert.AreSame(left, rr.Left);
Assert.AreEqual("System.String", rr.Right.Type.FullName);
Assert.IsTrue(rr.Right.IsCompileTimeConstant);
Assert.IsNull(rr.Right.ConstantValue);
}
[Test]
public void DelegateAddition()
{
TestOperator(MakeResult(typeof(Action)), BinaryOperatorType.Add, MakeResult(typeof(Action)),
Conversion.IdentityConversion, Conversion.IdentityConversion, typeof(Action));
AssertType(typeof(StringComparison?), resolver.ResolveBinaryOperator(
BinaryOperatorType.Add, MakeResult(typeof(StringComparison?)), MakeResult(typeof(int))));
TestOperator(MakeResult(typeof(Action<object>)), BinaryOperatorType.Add, MakeResult(typeof(Action<string>)),
Conversion.ImplicitReferenceConversion, Conversion.IdentityConversion, typeof(Action<string>));
AssertType(typeof(StringComparison?), resolver.ResolveBinaryOperator(
BinaryOperatorType.Add, MakeResult(typeof(int?)), MakeResult(typeof(StringComparison))));
TestOperator(MakeResult(typeof(Action<string>)), BinaryOperatorType.Add, MakeResult(typeof(Action<object>)),
Conversion.IdentityConversion, Conversion.ImplicitReferenceConversion, typeof(Action<string>));
AssertType(typeof(long?), resolver.ResolveBinaryOperator(
BinaryOperatorType.Add, MakeResult(typeof(int?)), MakeResult(typeof(uint?))));
Assert.IsTrue(resolver.ResolveBinaryOperator(
BinaryOperatorType.Add, MakeResult(typeof(Action<int>)), MakeResult(typeof(Action<long>))).IsError);
}
[Test]
public void EnumAddition()
{
AssertConstant(StringComparison.Ordinal, resolver.ResolveBinaryOperator(
BinaryOperatorType.Add, MakeConstant(StringComparison.InvariantCulture), MakeConstant(2)));
AssertType(typeof(int?), resolver.ResolveBinaryOperator(
BinaryOperatorType.Add, MakeResult(typeof(ushort?)), MakeResult(typeof(ushort?))));
AssertConstant(StringComparison.OrdinalIgnoreCase, resolver.ResolveBinaryOperator(
BinaryOperatorType.Add, MakeConstant((short)3), MakeConstant(StringComparison.InvariantCulture)));
Assert.IsTrue(resolver.ResolveBinaryOperator(
BinaryOperatorType.Add, MakeConstant(null), MakeConstant(null)).IsError);
TestOperator(MakeResult(typeof(StringComparison?)), BinaryOperatorType.Add, MakeResult(typeof(int)),
Conversion.IdentityConversion, Conversion.ImplicitNullableConversion, typeof(StringComparison?));
AssertType(typeof(int?), resolver.ResolveBinaryOperator(
BinaryOperatorType.Add, MakeConstant(1), MakeConstant(null)));
TestOperator(MakeResult(typeof(StringComparison?)), BinaryOperatorType.Add, MakeResult(typeof(int?)),
Conversion.IdentityConversion, Conversion.IdentityConversion, typeof(StringComparison?));
AssertType(typeof(int*), resolver.ResolveBinaryOperator(
BinaryOperatorType.Add, MakeResult(typeof(int*)), MakeConstant(1)));
TestOperator(MakeResult(typeof(int)), BinaryOperatorType.Add, MakeResult(typeof(StringComparison?)),
Conversion.ImplicitNullableConversion, Conversion.IdentityConversion, typeof(StringComparison?));
AssertType(typeof(byte*), resolver.ResolveBinaryOperator(
BinaryOperatorType.Add, MakeResult(typeof(long)), MakeResult(typeof(byte*))));
TestOperator(MakeResult(typeof(int?)), BinaryOperatorType.Add, MakeResult(typeof(StringComparison?)),
Conversion.IdentityConversion, Conversion.IdentityConversion, typeof(StringComparison?));
}
[Test]
public void PointerAddition()
{
TestOperator(MakeResult(typeof(int*)), BinaryOperatorType.Add, MakeConstant(1),
Conversion.IdentityConversion, Conversion.IdentityConversion, typeof(int*));
TestOperator(MakeResult(typeof(long)), BinaryOperatorType.Add, MakeResult(typeof(byte*)),
Conversion.IdentityConversion, Conversion.IdentityConversion, typeof(byte*));
}
[Test]
@ -109,44 +141,70 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -109,44 +141,70 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
[Test]
public void Subtraction()
{
AssertType(typeof(int?), resolver.ResolveBinaryOperator(
BinaryOperatorType.Subtract, MakeResult(typeof(short)), MakeResult(typeof(byte?))));
TestOperator(MakeResult(typeof(short)), BinaryOperatorType.Subtract, MakeResult(typeof(byte?)),
Conversion.ImplicitNullableConversion, Conversion.ImplicitNullableConversion, typeof(int?));
TestOperator(MakeResult(typeof(float)), BinaryOperatorType.Subtract, MakeResult(typeof(long)),
Conversion.IdentityConversion, Conversion.ImplicitNumericConversion, typeof(float));
AssertConstant(-1.0, resolver.ResolveBinaryOperator(
BinaryOperatorType.Subtract, MakeConstant(1.0f), MakeConstant(2.0)));
Assert.IsTrue(resolver.ResolveBinaryOperator(
BinaryOperatorType.Subtract, MakeConstant("Te"), MakeConstant("xt")).IsError);
}
[Test]
public void EnumSubtraction()
{
AssertConstant(StringComparison.InvariantCulture, resolver.ResolveBinaryOperator(
BinaryOperatorType.Subtract, MakeConstant(StringComparison.Ordinal), MakeConstant(2)));
AssertConstant(3, resolver.ResolveBinaryOperator(
BinaryOperatorType.Subtract, MakeConstant(StringComparison.OrdinalIgnoreCase), MakeConstant(StringComparison.InvariantCulture)));
TestOperator(MakeResult(typeof(StringComparison?)), BinaryOperatorType.Subtract, MakeResult(typeof(int)),
Conversion.IdentityConversion, Conversion.ImplicitNullableConversion, typeof(StringComparison?));
TestOperator(MakeResult(typeof(StringComparison?)), BinaryOperatorType.Subtract, MakeResult(typeof(StringComparison)),
Conversion.IdentityConversion, Conversion.ImplicitNullableConversion, typeof(int?));
Assert.IsTrue(resolver.ResolveBinaryOperator(
BinaryOperatorType.Subtract, MakeConstant("Te"), MakeConstant("xt")).IsError);
BinaryOperatorType.Subtract, MakeResult(typeof(int?)), MakeResult(typeof(StringComparison))).IsError);
}
[Test]
public void DelegateSubtraction()
{
TestOperator(MakeResult(typeof(Action)), BinaryOperatorType.Subtract, MakeResult(typeof(Action)),
Conversion.IdentityConversion, Conversion.IdentityConversion, typeof(Action));
AssertType(typeof(Action), resolver.ResolveBinaryOperator(
BinaryOperatorType.Subtract, MakeResult(typeof(Action)), MakeResult(typeof(Action))));
TestOperator(MakeResult(typeof(Action<object>)), BinaryOperatorType.Subtract, MakeResult(typeof(Action<string>)),
Conversion.ImplicitReferenceConversion, Conversion.IdentityConversion, typeof(Action<string>));
AssertType(typeof(Action<string>), resolver.ResolveBinaryOperator(
BinaryOperatorType.Subtract, MakeResult(typeof(Action<object>)), MakeResult(typeof(Action<string>))));
TestOperator(MakeResult(typeof(Action<string>)), BinaryOperatorType.Subtract, MakeResult(typeof(Action<object>)),
Conversion.IdentityConversion, Conversion.ImplicitReferenceConversion, typeof(Action<string>));
Assert.IsTrue(resolver.ResolveBinaryOperator(
BinaryOperatorType.Subtract, MakeResult(typeof(Action<int>)), MakeResult(typeof(Action<long>))).IsError);
}
[Test]
public void PointerSubtraction()
{
TestOperator(MakeResult(typeof(int*)), BinaryOperatorType.Subtract, MakeConstant(1),
Conversion.IdentityConversion, Conversion.IdentityConversion, typeof(int*));
AssertType(typeof(StringComparison?), resolver.ResolveBinaryOperator(
BinaryOperatorType.Subtract, MakeResult(typeof(StringComparison?)), MakeResult(typeof(int))));
AssertType(typeof(int?), resolver.ResolveBinaryOperator(
BinaryOperatorType.Subtract, MakeResult(typeof(StringComparison?)), MakeResult(typeof(StringComparison))));
TestOperator(MakeResult(typeof(byte*)), BinaryOperatorType.Subtract, MakeResult(typeof(uint)),
Conversion.IdentityConversion, Conversion.IdentityConversion, typeof(byte*));
Assert.IsTrue(resolver.ResolveBinaryOperator(
BinaryOperatorType.Subtract, MakeResult(typeof(int?)), MakeResult(typeof(StringComparison))).IsError);
TestOperator(MakeResult(typeof(byte*)), BinaryOperatorType.Subtract, MakeResult(typeof(short)),
Conversion.IdentityConversion, Conversion.ImplicitNumericConversion, typeof(byte*));
AssertType(typeof(byte*), resolver.ResolveBinaryOperator(
BinaryOperatorType.Subtract, MakeResult(typeof(byte*)), MakeResult(typeof(uint))));
TestOperator(MakeResult(typeof(byte*)), BinaryOperatorType.Subtract, MakeResult(typeof(byte*)),
Conversion.IdentityConversion, Conversion.IdentityConversion, typeof(long));
AssertType(typeof(long), resolver.ResolveBinaryOperator(
BinaryOperatorType.Subtract, MakeResult(typeof(byte*)), MakeResult(typeof(byte*))));
AssertError(typeof(long), resolver.ResolveBinaryOperator(BinaryOperatorType.Subtract, MakeResult(typeof(byte*)), MakeResult(typeof(int*))));
}
[Test]
@ -158,18 +216,21 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -158,18 +216,21 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
AssertConstant(ulong.MaxValue >> 2, resolver.ResolveBinaryOperator(
BinaryOperatorType.ShiftRight, MakeConstant(ulong.MaxValue), MakeConstant(2)));
AssertType(typeof(int?), resolver.ResolveBinaryOperator(
BinaryOperatorType.ShiftLeft, MakeResult(typeof(ushort?)), MakeConstant(1)));
TestOperator(MakeResult(typeof(ushort?)), BinaryOperatorType.ShiftLeft, MakeConstant(1),
Conversion.ImplicitNullableConversion, Conversion.ImplicitNullableConversion, typeof(int?));
AssertType(typeof(int?), resolver.ResolveBinaryOperator(
BinaryOperatorType.ShiftLeft, MakeConstant(null), MakeConstant(1)));
TestOperator(MakeConstant(null), BinaryOperatorType.ShiftLeft, MakeConstant(1),
Conversion.NullLiteralConversion, Conversion.ImplicitNullableConversion, typeof(int?));
AssertType(typeof(int?), resolver.ResolveBinaryOperator(
BinaryOperatorType.ShiftLeft, MakeConstant(null), MakeConstant(null)));
TestOperator(MakeResult(typeof(long)), BinaryOperatorType.ShiftLeft, MakeConstant(null),
Conversion.ImplicitNullableConversion, Conversion.NullLiteralConversion, typeof(long?));
TestOperator(MakeConstant(null), BinaryOperatorType.ShiftLeft, MakeConstant(null),
Conversion.NullLiteralConversion, Conversion.NullLiteralConversion, typeof(int?));
}
[Test]
public void Equality()
public void ConstantEquality()
{
AssertConstant(true, resolver.ResolveBinaryOperator(
BinaryOperatorType.Equality, MakeConstant(3), MakeConstant(3)));
@ -203,9 +264,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -203,9 +264,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
AssertConstant(false, resolver.ResolveBinaryOperator(
BinaryOperatorType.Equality, MakeConstant(null), MakeConstant('a')));
AssertType(typeof(bool), resolver.ResolveBinaryOperator(
BinaryOperatorType.Equality, MakeResult(typeof(int*)), MakeResult(typeof(uint*))));
}
[Test]
public void Equality()
{
TestOperator(MakeResult(typeof(int*)), BinaryOperatorType.Equality, MakeResult(typeof(uint*)),
Conversion.ImplicitPointerConversion, Conversion.ImplicitPointerConversion, typeof(bool));
}
[Test]

30
ICSharpCode.NRefactory.Tests/CSharp/Resolver/CastTests.cs

@ -2,6 +2,7 @@ @@ -2,6 +2,7 @@
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using ICSharpCode.NRefactory.TypeSystem;
using NUnit.Framework;
namespace ICSharpCode.NRefactory.CSharp.Resolver
@ -12,13 +13,34 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -12,13 +13,34 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
[TestFixture]
public class CastTests : ResolverTestBase
{
void TestCast(Type targetType, ResolveResult input, Conversion expectedConversion)
{
IType type = targetType.ToTypeReference().Resolve(context);
ResolveResult rr = resolver.ResolveCast(type, input);
AssertType(targetType, rr);
Assert.AreEqual(typeof(ConversionResolveResult), rr.GetType());
var crr = (ConversionResolveResult)rr;
Assert.AreEqual(expectedConversion, crr.Conversion, "ConversionResolveResult.Conversion");
Assert.AreSame(input, crr.Input, "ConversionResolveResult.Input");
}
[Test]
public void SimpleCast()
{
AssertType(typeof(int), resolver.ResolveCast(ResolveType(typeof(int)), MakeResult(typeof(float))));
AssertType(typeof(string), resolver.ResolveCast(ResolveType(typeof(string)), MakeResult(typeof(object))));
AssertType(typeof(byte), resolver.ResolveCast(ResolveType(typeof(byte)), MakeResult(typeof(dynamic))));
AssertType(typeof(dynamic), resolver.ResolveCast(ResolveType(typeof(dynamic)), MakeResult(typeof(double))));
TestCast(typeof(int), MakeResult(typeof(float)), Conversion.ExplicitNumericConversion);
TestCast(typeof(string), MakeResult(typeof(object)), Conversion.ExplicitReferenceConversion);
TestCast(typeof(byte), MakeResult(typeof(dynamic)), Conversion.ExplicitDynamicConversion);
TestCast(typeof(dynamic), MakeResult(typeof(double)), Conversion.BoxingConversion);
}
[Test]
public void NullableCasts()
{
TestCast(typeof(int), MakeResult(typeof(int?)), Conversion.ExplicitNullableConversion);
TestCast(typeof(int?), MakeResult(typeof(int)), Conversion.ImplicitNullableConversion);
TestCast(typeof(int?), MakeResult(typeof(long?)), Conversion.ExplicitNullableConversion);
TestCast(typeof(long?), MakeResult(typeof(int?)), Conversion.ImplicitNullableConversion);
}
[Test]

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

@ -28,6 +28,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -28,6 +28,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return conversions.ImplicitConversion(from2, to2);
}
Conversion ExplicitConversion(Type from, Type to)
{
IType from2 = from.ToTypeReference().Resolve(ctx);
IType to2 = to.ToTypeReference().Resolve(ctx);
return conversions.ExplicitConversion(from2, to2);
}
[Test]
public void IdentityConversions()
{
@ -196,12 +203,22 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -196,12 +203,22 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
[Test]
public void PointerConversion()
public void ImplicitPointerConversion()
{
Assert.AreEqual(C.ImplicitPointerConversion, ImplicitConversion(typeof(Null), typeof(int*)));
Assert.AreEqual(C.ImplicitPointerConversion, ImplicitConversion(typeof(int*), typeof(void*)));
}
[Test]
public void ExplicitPointerConversion()
{
Assert.AreEqual(C.ExplicitPointerConversion, ExplicitConversion(typeof(int*), typeof(short)));
Assert.AreEqual(C.ExplicitPointerConversion, ExplicitConversion(typeof(short), typeof(void*)));
Assert.AreEqual(C.ExplicitPointerConversion, ExplicitConversion(typeof(void*), typeof(int*)));
Assert.AreEqual(C.ExplicitPointerConversion, ExplicitConversion(typeof(long*), typeof(byte*)));
}
[Test]
public void NoConversionFromPointerTypeToObject()
{
@ -217,8 +234,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -217,8 +234,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
DefaultTypeParameter tm = new DefaultTypeParameter(EntityType.Method, 0, "TM");
Assert.AreEqual(C.None, conversions.ImplicitConversion(SharedTypes.Null, t));
Assert.AreEqual(C.ImplicitTypeParameterConversion, conversions.ImplicitConversion(t, KnownTypeReference.Object.Resolve(ctx)));
Assert.AreEqual(C.ImplicitTypeParameterConversion, conversions.ImplicitConversion(t, SharedTypes.Dynamic));
Assert.AreEqual(C.BoxingConversion, conversions.ImplicitConversion(t, KnownTypeReference.Object.Resolve(ctx)));
Assert.AreEqual(C.BoxingConversion, conversions.ImplicitConversion(t, SharedTypes.Dynamic));
Assert.AreEqual(C.None, conversions.ImplicitConversion(t, ctx.GetTypeDefinition(typeof(ValueType))));
Assert.AreEqual(C.IdentityConversion, conversions.ImplicitConversion(t, t));
@ -281,14 +298,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -281,14 +298,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
t.Constraints.Add(ctx.GetTypeDefinition(typeof(IList)));
Assert.AreEqual(C.None, conversions.ImplicitConversion(SharedTypes.Null, t));
Assert.AreEqual(C.ImplicitTypeParameterConversion,
Assert.AreEqual(C.BoxingConversion,
conversions.ImplicitConversion(t, KnownTypeReference.Object.Resolve(ctx)));
Assert.AreEqual(C.ImplicitTypeParameterConversion,
Assert.AreEqual(C.BoxingConversion,
conversions.ImplicitConversion(t, SharedTypes.Dynamic));
Assert.AreEqual(C.None, conversions.ImplicitConversion(t, ctx.GetTypeDefinition(typeof(ValueType))));
Assert.AreEqual(C.ImplicitTypeParameterConversion,
Assert.AreEqual(C.BoxingConversion,
conversions.ImplicitConversion(t, ctx.GetTypeDefinition(typeof(IList))));
Assert.AreEqual(C.ImplicitTypeParameterConversion,
Assert.AreEqual(C.BoxingConversion,
conversions.ImplicitConversion(t, ctx.GetTypeDefinition(typeof(IEnumerable))));
}

32
ICSharpCode.NRefactory.Tests/CSharp/Resolver/ResolverTestBase.cs

@ -121,6 +121,38 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -121,6 +121,38 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
Assert.AreEqual(expectedType.ToTypeReference().Resolve(context), rr.Type);
}
protected void TestOperator(UnaryOperatorType op, ResolveResult input,
Conversion expectedConversion, Type expectedResultType)
{
var rr = resolver.ResolveUnaryOperator(op, input);
AssertType(expectedResultType, rr);
Assert.AreEqual(typeof(UnaryOperatorResolveResult), rr.GetType());
var uorr = (UnaryOperatorResolveResult)rr;
AssertConversion(uorr.Input, input, expectedConversion, "Conversion");
}
protected void TestOperator(ResolveResult lhs, BinaryOperatorType op, ResolveResult rhs,
Conversion expectedLeftConversion, Conversion expectedRightConversion, Type expectedResultType)
{
var rr = resolver.ResolveBinaryOperator(op, lhs, rhs);
AssertType(expectedResultType, rr);
Assert.AreEqual(typeof(BinaryOperatorResolveResult), rr.GetType());
var borr = (BinaryOperatorResolveResult)rr;
AssertConversion(borr.Left, lhs, expectedLeftConversion, "Left conversion");
AssertConversion(borr.Right, rhs, expectedRightConversion, "Right conversion");
}
protected void AssertConversion(ResolveResult conversionResult, ResolveResult expectedRR, Conversion expectedConversion, string text)
{
if (expectedConversion == Conversion.IdentityConversion) {
Assert.AreSame(expectedRR, conversionResult, "Expected no " + text);
} else {
ConversionResolveResult crr = (ConversionResolveResult)conversionResult;
Assert.AreEqual(expectedConversion, crr.Conversion, text);
Assert.AreSame(expectedRR, crr.Input, "Input of " + text);
}
}
IEnumerable<AstLocation> FindDollarSigns(string code)
{
int line = 1;

94
ICSharpCode.NRefactory.Tests/CSharp/Resolver/UnaryOperatorTests.cs

@ -16,33 +16,59 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -16,33 +16,59 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
[Test]
public void TestAddressOf()
{
AssertType(typeof(int*), resolver.ResolveUnaryOperator(UnaryOperatorType.AddressOf, MakeResult(typeof(int))));
AssertType(typeof(byte**), resolver.ResolveUnaryOperator(UnaryOperatorType.AddressOf, MakeResult(typeof(byte*))));
AssertType(typeof(dynamic), resolver.ResolveUnaryOperator(UnaryOperatorType.AddressOf, MakeResult(typeof(dynamic))));
TestOperator(UnaryOperatorType.AddressOf, MakeResult(typeof(int)),
Conversion.IdentityConversion, typeof(int*));
TestOperator(UnaryOperatorType.AddressOf, MakeResult(typeof(byte*)),
Conversion.IdentityConversion, typeof(byte**));
TestOperator(UnaryOperatorType.AddressOf, MakeResult(typeof(dynamic)),
Conversion.IdentityConversion, typeof(dynamic));
}
[Test]
public void TestDereference()
{
AssertType(typeof(int), resolver.ResolveUnaryOperator(UnaryOperatorType.Dereference, MakeResult(typeof(int*))));
AssertType(typeof(long*), resolver.ResolveUnaryOperator(UnaryOperatorType.Dereference, MakeResult(typeof(long**))));
TestOperator(UnaryOperatorType.Dereference, MakeResult(typeof(int*)),
Conversion.IdentityConversion, typeof(int));
TestOperator(UnaryOperatorType.Dereference, MakeResult(typeof(long**)),
Conversion.IdentityConversion, typeof(long*));
Assert.IsTrue(resolver.ResolveUnaryOperator(UnaryOperatorType.Dereference, MakeResult(typeof(int))).IsError);
AssertType(typeof(dynamic), resolver.ResolveUnaryOperator(UnaryOperatorType.Dereference, MakeResult(typeof(dynamic))));
TestOperator(UnaryOperatorType.Dereference, MakeResult(typeof(dynamic)),
Conversion.IdentityConversion, typeof(dynamic));
}
[Test]
public void TestIncrementDecrement()
{
AssertType(typeof(byte), resolver.ResolveUnaryOperator(UnaryOperatorType.Increment, MakeResult(typeof(byte))));
AssertType(typeof(ulong), resolver.ResolveUnaryOperator(UnaryOperatorType.Decrement, MakeResult(typeof(ulong))));
AssertType(typeof(short?), resolver.ResolveUnaryOperator(UnaryOperatorType.PostDecrement, MakeResult(typeof(short?))));
AssertType(typeof(TypeCode), resolver.ResolveUnaryOperator(UnaryOperatorType.PostIncrement, MakeResult(typeof(TypeCode))));
AssertType(typeof(TypeCode?), resolver.ResolveUnaryOperator(UnaryOperatorType.PostIncrement, MakeResult(typeof(TypeCode?))));
AssertType(typeof(dynamic), resolver.ResolveUnaryOperator(UnaryOperatorType.PostIncrement, MakeResult(typeof(dynamic))));
TestOperator(UnaryOperatorType.Increment, MakeResult(typeof(byte)),
Conversion.IdentityConversion, typeof(byte));
TestOperator(UnaryOperatorType.Decrement, MakeResult(typeof(ulong)),
Conversion.IdentityConversion, typeof(ulong));
TestOperator(UnaryOperatorType.PostDecrement, MakeResult(typeof(short?)),
Conversion.IdentityConversion, typeof(short?));
TestOperator(UnaryOperatorType.PostIncrement, MakeResult(typeof(TypeCode)),
Conversion.IdentityConversion, typeof(TypeCode));
TestOperator(UnaryOperatorType.PostIncrement, MakeResult(typeof(TypeCode?)),
Conversion.IdentityConversion, typeof(TypeCode?));
TestOperator(UnaryOperatorType.PostIncrement, MakeResult(typeof(dynamic)),
Conversion.IdentityConversion, typeof(dynamic));
AssertError(typeof(object), resolver.ResolveUnaryOperator(UnaryOperatorType.Increment, MakeResult(typeof(object))));
AssertType(typeof(int*), resolver.ResolveUnaryOperator(UnaryOperatorType.Increment, MakeResult(typeof(int*))));
AssertType(typeof(uint*), resolver.ResolveUnaryOperator(UnaryOperatorType.PostDecrement, MakeResult(typeof(uint*))));
TestOperator(UnaryOperatorType.Increment, MakeResult(typeof(int*)),
Conversion.IdentityConversion, typeof(int*));
TestOperator(UnaryOperatorType.PostDecrement, MakeResult(typeof(uint*)),
Conversion.IdentityConversion, typeof(uint*));
}
[Test]
@ -58,8 +84,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -58,8 +84,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
AssertConstant(1L, resolver.ResolveUnaryOperator(UnaryOperatorType.Plus, MakeConstant((long)1)));
AssertConstant((ulong)1, resolver.ResolveUnaryOperator(UnaryOperatorType.Plus, MakeConstant((ulong)1)));
AssertType(typeof(dynamic), resolver.ResolveUnaryOperator(UnaryOperatorType.Plus, MakeResult(typeof(dynamic))));
AssertType(typeof(int?), resolver.ResolveUnaryOperator(UnaryOperatorType.Plus, MakeResult(typeof(ushort?))));
TestOperator(UnaryOperatorType.Plus, MakeResult(typeof(dynamic)),
Conversion.IdentityConversion, typeof(dynamic));
TestOperator(UnaryOperatorType.Plus, MakeResult(typeof(ushort?)),
Conversion.ImplicitNullableConversion, typeof(int?));
}
[Test]
@ -73,8 +102,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -73,8 +102,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
AssertConstant(1m, resolver.ResolveUnaryOperator(UnaryOperatorType.Minus, MakeConstant(-1m)));
AssertConstant(-65, resolver.ResolveUnaryOperator(UnaryOperatorType.Minus, MakeConstant('A')));
AssertType(typeof(dynamic), resolver.ResolveUnaryOperator(UnaryOperatorType.Minus, MakeResult(typeof(dynamic))));
AssertType(typeof(long?), resolver.ResolveUnaryOperator(UnaryOperatorType.Minus, MakeResult(typeof(uint?))));
TestOperator(UnaryOperatorType.Minus, MakeResult(typeof(dynamic)),
Conversion.IdentityConversion, typeof(dynamic));
TestOperator(UnaryOperatorType.Minus, MakeResult(typeof(uint?)),
Conversion.ImplicitNullableConversion, typeof(long?));
}
[Test]
@ -104,9 +136,17 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -104,9 +136,17 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
AssertConstant(~(ulong)1, resolver.ResolveUnaryOperator(UnaryOperatorType.BitNot, MakeConstant((ulong)1)));
Assert.IsTrue(resolver.ResolveUnaryOperator(UnaryOperatorType.BitNot, MakeConstant(1.0)).IsError);
AssertType(typeof(dynamic), resolver.ResolveUnaryOperator(UnaryOperatorType.BitNot, MakeResult(typeof(dynamic))));
AssertType(typeof(uint), resolver.ResolveUnaryOperator(UnaryOperatorType.BitNot, MakeResult(typeof(uint))));
AssertType(typeof(int?), resolver.ResolveUnaryOperator(UnaryOperatorType.BitNot, MakeResult(typeof(ushort?))));
TestOperator(UnaryOperatorType.BitNot, MakeResult(typeof(dynamic)),
Conversion.IdentityConversion, typeof(dynamic));
TestOperator(UnaryOperatorType.BitNot, MakeResult(typeof(uint)),
Conversion.IdentityConversion, typeof(uint));
TestOperator(UnaryOperatorType.BitNot, MakeResult(typeof(sbyte)),
Conversion.ImplicitNumericConversion, typeof(int));
TestOperator(UnaryOperatorType.BitNot, MakeResult(typeof(ushort?)),
Conversion.ImplicitNullableConversion, typeof(int?));
}
[Test]
@ -114,9 +154,15 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -114,9 +154,15 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{
AssertConstant(true, resolver.ResolveUnaryOperator(UnaryOperatorType.Not, MakeConstant(false)));
AssertConstant(false, resolver.ResolveUnaryOperator(UnaryOperatorType.Not, MakeConstant(true)));
AssertType(typeof(dynamic), resolver.ResolveUnaryOperator(UnaryOperatorType.Not, MakeResult(typeof(dynamic))));
AssertType(typeof(bool), resolver.ResolveUnaryOperator(UnaryOperatorType.Not, MakeResult(typeof(bool))));
AssertType(typeof(bool?), resolver.ResolveUnaryOperator(UnaryOperatorType.Not, MakeResult(typeof(bool?))));
TestOperator(UnaryOperatorType.Not, MakeResult(typeof(dynamic)),
Conversion.IdentityConversion, typeof(dynamic));
TestOperator(UnaryOperatorType.Not, MakeResult(typeof(bool)),
Conversion.IdentityConversion, typeof(bool));
TestOperator(UnaryOperatorType.Not, MakeResult(typeof(bool?)),
Conversion.IdentityConversion, typeof(bool?));
}
[Test]

18
ICSharpCode.NRefactory/CSharp/Resolver/ByReferenceResolveResult.cs

@ -17,6 +17,8 @@ @@ -17,6 +17,8 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.Resolver
@ -29,6 +31,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -29,6 +31,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public bool IsOut { get; private set; }
public bool IsRef { get { return !IsOut;} }
public readonly ResolveResult ElementResult;
public ByReferenceResolveResult(ResolveResult elementResult, bool isOut)
: this(elementResult.Type, isOut)
{
this.ElementResult = elementResult;
}
public ByReferenceResolveResult(IType elementType, bool isOut)
: base(new ByReferenceType(elementType))
{
@ -39,6 +49,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -39,6 +49,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
get { return ((ByReferenceType)this.Type).ElementType; }
}
public override IEnumerable<ResolveResult> GetChildResults()
{
if (ElementResult != null)
return new[] { ElementResult };
else
return Enumerable.Empty<ResolveResult>();
}
public override string ToString()
{
return string.Format("[{0} {1} {2}]", GetType().Name, IsOut ? "out" : "ref", ElementType);

295
ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs

@ -38,6 +38,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -38,6 +38,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
static readonly ResolveResult NullResult = new ResolveResult(SharedTypes.Null);
readonly ITypeResolveContext context;
readonly Conversions conversions;
internal readonly CancellationToken cancellationToken;
#region Constructor
@ -51,6 +52,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -51,6 +52,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
throw new ArgumentNullException("context");
this.context = context;
this.cancellationToken = cancellationToken;
this.conversions = new Conversions(context);
}
#endregion
@ -450,7 +452,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -450,7 +452,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
cancellationToken.ThrowIfCancellationRequested();
if (SharedTypes.Dynamic.Equals(expression.Type))
return DynamicResult;
return new UnaryOperatorResolveResult(SharedTypes.Dynamic, op, expression);
// C# 4.0 spec: §7.3.3 Unary operator overload resolution
string overloadableOperatorName = GetOverloadableOperatorName(op);
@ -459,11 +461,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -459,11 +461,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
case UnaryOperatorType.Dereference:
PointerType p = expression.Type as PointerType;
if (p != null)
return new ResolveResult(p.ElementType);
return new UnaryOperatorResolveResult(p.ElementType, op, expression);
else
return ErrorResult;
case UnaryOperatorType.AddressOf:
return new ResolveResult(new PointerType(expression.Type));
return new UnaryOperatorResolveResult(new PointerType(expression.Type), op, expression);
default:
throw new ArgumentException("Invalid value for UnaryOperatorType", "op");
}
@ -486,8 +488,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -486,8 +488,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
// C# 4.0 spec: §7.6.9 Postfix increment and decrement operators
// C# 4.0 spec: §7.7.5 Prefix increment and decrement operators
TypeCode code = ReflectionHelper.GetTypeCode(type);
if ((code >= TypeCode.SByte && code <= TypeCode.Decimal) || type.IsEnum() || type is PointerType)
return new ResolveResult(expression.Type);
if ((code >= TypeCode.SByte && code <= TypeCode.Decimal) || type.Kind == TypeKind.Enum || type.Kind == TypeKind.Pointer)
return new UnaryOperatorResolveResult(expression.Type, op, expression);
else
return new ErrorResolveResult(expression.Type);
case UnaryOperatorType.Plus:
@ -500,14 +502,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -500,14 +502,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
methodGroup = logicalNegationOperator;
break;
case UnaryOperatorType.BitNot:
if (type.IsEnum()) {
if (type.Kind == TypeKind.Enum) {
if (expression.IsCompileTimeConstant && !isNullable) {
// evaluate as (E)(~(U)x);
var U = expression.ConstantValue.GetType().ToTypeReference().Resolve(context);
var unpackedEnum = new ConstantResolveResult(U, expression.ConstantValue);
return CheckErrorAndResolveCast(expression.Type, ResolveUnaryOperator(op, unpackedEnum));
} else {
return new ResolveResult(expression.Type);
return new UnaryOperatorResolveResult(expression.Type, op, expression);
}
} else {
methodGroup = bitwiseComplementOperators;
@ -533,7 +535,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -533,7 +535,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
return new ConstantResolveResult(resultType, val);
} else {
return new ResolveResult(resultType);
expression = Convert(expression, m.Parameters[0].Type, r.ArgumentConversions[0]);
return new UnaryOperatorResolveResult(resultType, op, expression);
}
}
#endregion
@ -548,19 +551,17 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -548,19 +551,17 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
switch (op) {
case UnaryOperatorType.Minus:
if (code == TypeCode.UInt32) {
IType targetType = KnownTypeReference.Int64.Resolve(context);
type = targetType;
if (isNullable) targetType = NullableType.Create(targetType, context);
return ResolveCast(targetType, expression);
type = KnownTypeReference.Int64.Resolve(context);
return Convert(expression, MakeNullable(type, isNullable),
isNullable ? Conversion.ImplicitNullableConversion : Conversion.ImplicitNumericConversion);
}
goto case UnaryOperatorType.Plus;
case UnaryOperatorType.Plus:
case UnaryOperatorType.BitNot:
if (code >= TypeCode.Char && code <= TypeCode.UInt16) {
IType targetType = KnownTypeReference.Int32.Resolve(context);
type = targetType;
if (isNullable) targetType = NullableType.Create(targetType, context);
return ResolveCast(targetType, expression);
type = KnownTypeReference.Int32.Resolve(context);
return Convert(expression, MakeNullable(type, isNullable),
isNullable ? Conversion.ImplicitNullableConversion : Conversion.ImplicitNumericConversion);
}
break;
}
@ -700,8 +701,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -700,8 +701,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{
cancellationToken.ThrowIfCancellationRequested();
if (SharedTypes.Dynamic.Equals(lhs.Type) || SharedTypes.Dynamic.Equals(rhs.Type))
return DynamicResult;
if (SharedTypes.Dynamic.Equals(lhs.Type) || SharedTypes.Dynamic.Equals(rhs.Type)) {
lhs = Convert(lhs, SharedTypes.Dynamic, conversions.ImplicitConversion(lhs, SharedTypes.Dynamic));
rhs = Convert(rhs, SharedTypes.Dynamic, conversions.ImplicitConversion(rhs, SharedTypes.Dynamic));
return new BinaryOperatorResolveResult(SharedTypes.Dynamic, lhs, op, rhs);
}
// C# 4.0 spec: §7.3.4 Binary operator overload resolution
string overloadableOperatorName = GetOverloadableOperatorName(op);
@ -765,23 +769,41 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -765,23 +769,41 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
case BinaryOperatorType.Add:
methodGroup = CheckForOverflow ? checkedAdditionOperators : uncheckedAdditionOperators;
{
Conversions conversions = new Conversions(context);
if (lhsType.IsEnum() && conversions.ImplicitConversion(rhsType, lhsType.GetEnumUnderlyingType(context))) {
if (lhsType.Kind == TypeKind.Enum) {
// E operator +(E x, U y);
return HandleEnumAdditionOrSubtraction(isNullable, lhsType, op, lhs, rhs);
} else if (rhsType.IsEnum() && conversions.ImplicitConversion(lhsType, rhsType.GetEnumUnderlyingType(context))) {
IType underlyingType = MakeNullable(lhsType.GetEnumUnderlyingType(context), isNullable);
if (TryConvert(ref rhs, underlyingType)) {
return HandleEnumOperator(isNullable, lhsType, op, lhs, rhs);
}
}
if (rhsType.Kind == TypeKind.Enum) {
// E operator +(U x, E y);
return ResolveBinaryOperator(op, rhs, lhs); // swap arguments
IType underlyingType = MakeNullable(rhsType.GetEnumUnderlyingType(context), isNullable);
if (TryConvert(ref lhs, underlyingType)) {
return HandleEnumOperator(isNullable, rhsType, op, lhs, rhs);
}
}
if (lhsType.IsDelegate() && conversions.ImplicitConversion(rhsType, lhsType)) {
return new ResolveResult(lhsType);
} else if (rhsType.IsDelegate() && conversions.ImplicitConversion(lhsType, rhsType)) {
return new ResolveResult(rhsType);
if (lhsType.Kind == TypeKind.Delegate && TryConvert(ref rhs, lhsType)) {
return new BinaryOperatorResolveResult(lhsType, lhs, op, rhs);
} else if (rhsType.Kind == TypeKind.Delegate && TryConvert(ref lhs, rhsType)) {
return new BinaryOperatorResolveResult(rhsType, lhs, op, rhs);
}
if (lhsType is PointerType && IsInteger(ReflectionHelper.GetTypeCode(rhsType))) {
return new ResolveResult(lhsType);
} else if (rhsType is PointerType && IsInteger(ReflectionHelper.GetTypeCode(lhsType))) {
return new ResolveResult(rhsType);
if (lhsType is PointerType) {
methodGroup = new [] {
new PointerArithmeticOperator(lhsType, lhsType, KnownTypeReference.Int32),
new PointerArithmeticOperator(lhsType, lhsType, KnownTypeReference.UInt32),
new PointerArithmeticOperator(lhsType, lhsType, KnownTypeReference.Int64),
new PointerArithmeticOperator(lhsType, lhsType, KnownTypeReference.UInt64)
};
} else if (rhsType is PointerType) {
methodGroup = new [] {
new PointerArithmeticOperator(rhsType, KnownTypeReference.Int32, rhsType),
new PointerArithmeticOperator(rhsType, KnownTypeReference.UInt32, rhsType),
new PointerArithmeticOperator(rhsType, KnownTypeReference.Int64, rhsType),
new PointerArithmeticOperator(rhsType, KnownTypeReference.UInt64, rhsType)
};
}
if (SharedTypes.Null.Equals(lhsType) && SharedTypes.Null.Equals(rhsType))
return new ErrorResolveResult(SharedTypes.Null);
@ -790,27 +812,47 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -790,27 +812,47 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
case BinaryOperatorType.Subtract:
methodGroup = CheckForOverflow ? checkedSubtractionOperators : uncheckedSubtractionOperators;
{
Conversions conversions = new Conversions(context);
if (lhsType.IsEnum() && conversions.ImplicitConversion(rhsType, lhsType.GetEnumUnderlyingType(context))) {
if (lhsType.Kind == TypeKind.Enum) {
// E operator –(E x, U y);
return HandleEnumAdditionOrSubtraction(isNullable, lhsType, op, lhs, rhs);
} else if (lhsType.IsEnum() && conversions.ImplicitConversion(rhs, lhs.Type)) {
IType underlyingType = MakeNullable(lhsType.GetEnumUnderlyingType(context), isNullable);
if (TryConvert(ref rhs, underlyingType)) {
return HandleEnumOperator(isNullable, lhsType, op, lhs, rhs);
}
// U operator –(E x, E y);
return HandleEnumSubtraction(isNullable, lhsType, lhs, rhs);
} else if (rhsType.IsEnum() && conversions.ImplicitConversion(lhs, rhs.Type)) {
if (TryConvert(ref rhs, lhs.Type)) {
return HandleEnumSubtraction(isNullable, lhsType, lhs, rhs);
}
}
if (rhsType.Kind == TypeKind.Enum) {
// U operator –(E x, E y);
return HandleEnumSubtraction(isNullable, lhsType, lhs, rhs);
if (TryConvert(ref lhs, rhs.Type)) {
return HandleEnumSubtraction(isNullable, rhsType, lhs, rhs);
}
}
if (lhsType.IsDelegate() && conversions.ImplicitConversion(rhsType, lhsType)) {
return new ResolveResult(lhsType);
} else if (rhsType.IsDelegate() && conversions.ImplicitConversion(lhsType, rhsType)) {
return new ResolveResult(rhsType);
if (lhsType.Kind == TypeKind.Delegate && TryConvert(ref rhs, lhsType)) {
return new BinaryOperatorResolveResult(lhsType, lhs, op, rhs);
} else if (rhsType.Kind == TypeKind.Delegate && TryConvert(ref lhs, rhsType)) {
return new BinaryOperatorResolveResult(rhsType, lhs, op, rhs);
}
if (lhsType is PointerType && IsInteger(ReflectionHelper.GetTypeCode(rhsType))) {
return new ResolveResult(lhsType);
} else if (lhsType is PointerType && lhsType.Equals(rhsType)) {
return new ResolveResult(KnownTypeReference.Int64.Resolve(context));
if (lhsType is PointerType) {
if (rhsType is PointerType) {
IType int64 = KnownTypeReference.Int64.Resolve(context);
if (lhsType.Equals(rhsType)) {
return new BinaryOperatorResolveResult(int64, lhs, op, rhs);
} else {
return new ErrorResolveResult(int64);
}
}
methodGroup = new [] {
new PointerArithmeticOperator(lhsType, lhsType, KnownTypeReference.Int32),
new PointerArithmeticOperator(lhsType, lhsType, KnownTypeReference.UInt32),
new PointerArithmeticOperator(lhsType, lhsType, KnownTypeReference.Int64),
new PointerArithmeticOperator(lhsType, lhsType, KnownTypeReference.UInt64)
};
}
if (SharedTypes.Null.Equals(lhsType) && SharedTypes.Null.Equals(rhsType))
return new ErrorResolveResult(SharedTypes.Null);
}
@ -828,11 +870,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -828,11 +870,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
case BinaryOperatorType.LessThanOrEqual:
case BinaryOperatorType.GreaterThanOrEqual:
{
Conversions conversions = new Conversions(context);
if (lhsType.IsEnum() && conversions.ImplicitConversion(rhs, lhs.Type)) {
if (lhsType.Kind == TypeKind.Enum && TryConvert(ref rhs, lhs.Type)) {
// bool operator op(E x, E y);
return HandleEnumComparison(op, lhsType, isNullable, lhs, rhs);
} else if (rhsType.IsEnum() && conversions.ImplicitConversion(lhs, rhs.Type)) {
} else if (rhsType.Kind == TypeKind.Enum && TryConvert(ref lhs, rhs.Type)) {
// bool operator op(E x, E y);
return HandleEnumComparison(op, rhsType, isNullable, lhs, rhs);
} else if (lhsType is PointerType && rhsType is PointerType) {
@ -866,14 +907,15 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -866,14 +907,15 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
case BinaryOperatorType.BitwiseOr:
case BinaryOperatorType.ExclusiveOr:
{
Conversions conversions = new Conversions(context);
if (lhsType.IsEnum() && conversions.ImplicitConversion(rhs, lhs.Type)) {
// E operator op(E x, E y);
return HandleEnumAdditionOrSubtraction(isNullable, lhsType, op, lhs, rhs);
} else if (rhsType.IsEnum() && conversions.ImplicitConversion(lhs, rhs.Type)) {
// E operator op(E x, E y);
return HandleEnumAdditionOrSubtraction(isNullable, rhsType, op, lhs, rhs);
Conversion c;
if (lhsType.Kind == TypeKind.Enum && TryConvert(ref rhs, lhs.Type)) {
// bool operator op(E x, E y);
return HandleEnumOperator(isNullable, lhsType, op, lhs, rhs);
} else if (rhsType.Kind == TypeKind.Enum && TryConvert(ref lhs, rhs.Type)) {
// bool operator op(E x, E y);
return HandleEnumOperator(isNullable, rhsType, op, lhs, rhs);
}
switch (op) {
case BinaryOperatorType.BitwiseAnd:
methodGroup = bitwiseAndOperators;
@ -915,7 +957,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -915,7 +957,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
return new ConstantResolveResult(resultType, val);
} else {
return new ResolveResult(resultType);
lhs = Convert(lhs, m.Parameters[0].Type, r.ArgumentConversions[0]);
rhs = Convert(rhs, m.Parameters[1].Type, r.ArgumentConversions[1]);
return new BinaryOperatorResolveResult(resultType, lhs, op, rhs);
}
}
#endregion
@ -938,7 +982,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -938,7 +982,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return rhs;
return ResolveBinaryOperator(op, lhs, rhs);
}
return new ResolveResult(KnownTypeReference.Boolean.Resolve(context));
IType resultType = KnownTypeReference.Boolean.Resolve(context);
return new BinaryOperatorResolveResult(resultType, lhs, op, rhs);
}
/// <summary>
@ -958,19 +1003,20 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -958,19 +1003,20 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return rhs;
return CheckErrorAndResolveCast(elementType, ResolveBinaryOperator(BinaryOperatorType.Subtract, lhs, rhs));
}
return new ResolveResult(isNullable ? NullableType.Create(elementType, context) : elementType);
IType resultType = MakeNullable(elementType, isNullable);
return new BinaryOperatorResolveResult(resultType, lhs, BinaryOperatorType.Subtract, rhs);
}
/// <summary>
/// Handle the case where an integral value is added to or subtracted from an enum value,
/// or when two enum values of the same type are combined using a bitwise operator.
/// Handle the following enum operators:
/// E operator +(E x, U y);
/// E operator +(U x, E y);
/// E operator –(E x, U y);
/// E operator &amp;(E x, E y);
/// E operator |(E x, E y);
/// E operator ^(E x, E y);
/// </summary>
ResolveResult HandleEnumAdditionOrSubtraction(bool isNullable, IType enumType, BinaryOperatorType op, ResolveResult lhs, ResolveResult rhs)
ResolveResult HandleEnumOperator(bool isNullable, IType enumType, BinaryOperatorType op, ResolveResult lhs, ResolveResult rhs)
{
// evaluate as (E)((U)x op (U)y)
if (lhs.IsCompileTimeConstant && rhs.IsCompileTimeConstant && !isNullable) {
@ -983,7 +1029,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -983,7 +1029,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return rhs;
return CheckErrorAndResolveCast(enumType, ResolveBinaryOperator(op, lhs, rhs));
}
return new ResolveResult(isNullable ? NullableType.Create(enumType, context) : enumType);
IType resultType = MakeNullable(enumType, isNullable);
return new BinaryOperatorResolveResult(resultType, lhs, op, rhs);
}
IType MakeNullable(IType type, bool isNullable)
{
if (isNullable)
return NullableType.Create(type, context);
else
return type;
}
#endregion
@ -1055,15 +1110,12 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1055,15 +1110,12 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
}
static bool IsInteger(TypeCode code)
{
return code >= TypeCode.SByte && code <= TypeCode.UInt64;
}
ResolveResult CastTo(TypeCode targetType, bool isNullable, ResolveResult expression, bool allowNullableConstants)
{
IType elementType = targetType.ToTypeReference().Resolve(context);
IType nullableType = isNullable ? NullableType.Create(elementType, context) : elementType;
IType nullableType = MakeNullable(elementType, isNullable);
if (nullableType.Equals(expression.Type))
return expression;
if (allowNullableConstants && expression.IsCompileTimeConstant) {
if (expression.ConstantValue == null)
return new ConstantResolveResult(nullableType, null);
@ -1073,7 +1125,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1073,7 +1125,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
Debug.Assert(rr.IsCompileTimeConstant);
return new ConstantResolveResult(nullableType, rr.ConstantValue);
} else {
return ResolveCast(nullableType, expression);
return Convert(expression, nullableType,
isNullable ? Conversion.ImplicitNullableConversion : Conversion.ImplicitNumericConversion);
}
}
#endregion
@ -1127,6 +1180,25 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1127,6 +1180,25 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public abstract object Invoke(CSharpResolver resolver, object lhs, object rhs);
}
sealed class PointerArithmeticOperator : BinaryOperatorMethod
{
public PointerArithmeticOperator(ITypeReference returnType, ITypeReference parameter1, ITypeReference parameter2)
{
this.ReturnType = returnType;
this.Parameters.Add(new DefaultParameter(parameter1, "x"));
this.Parameters.Add(new DefaultParameter(parameter2, "y"));
}
public override bool CanEvaluateAtCompileTime {
get { return false; }
}
public override object Invoke(CSharpResolver resolver, object lhs, object rhs)
{
throw new NotSupportedException();
}
}
sealed class LambdaBinaryOperatorMethod<T1, T2> : BinaryOperatorMethod
{
readonly Func<T1, T2, T1> func;
@ -1517,18 +1589,20 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1517,18 +1589,20 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#region Null coalescing operator
ResolveResult ResolveNullCoalescingOperator(ResolveResult lhs, ResolveResult rhs)
{
Conversions conversions = new Conversions(context);
if (NullableType.IsNullable(lhs.Type)) {
IType a0 = NullableType.GetUnderlyingType(lhs.Type);
if (conversions.ImplicitConversion(rhs, a0))
return new ResolveResult(a0);
if (TryConvert(ref rhs, a0)) {
return new BinaryOperatorResolveResult(a0, lhs, BinaryOperatorType.NullCoalescing, rhs);
}
}
if (conversions.ImplicitConversion(rhs, lhs.Type))
return new ResolveResult(lhs.Type);
if (conversions.ImplicitConversion(lhs, rhs.Type))
return new ResolveResult(rhs.Type);
else
if (TryConvert(ref rhs, lhs.Type)) {
return new BinaryOperatorResolveResult(lhs.Type, lhs, BinaryOperatorType.NullCoalescing, rhs);
}
if (TryConvert(ref lhs, rhs.Type)) {
return new BinaryOperatorResolveResult(rhs.Type, lhs, BinaryOperatorType.NullCoalescing, rhs);
} else {
return new ErrorResolveResult(lhs.Type);
}
}
#endregion
@ -1541,6 +1615,27 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1541,6 +1615,27 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#endregion
#region ResolveCast
bool TryConvert(ref ResolveResult rr, IType targetType)
{
Conversion c = conversions.ImplicitConversion(rr, targetType);
if (c) {
rr = Convert(rr, targetType, c);
return true;
} else {
return false;
}
}
ResolveResult Convert(ResolveResult rr, ITypeReference targetType, Conversion c)
{
if (c == Conversion.IdentityConversion)
return rr;
else if (rr.IsCompileTimeConstant && c != Conversion.None)
return ResolveCast(targetType.Resolve(context), rr);
else
return new ConversionResolveResult(targetType.Resolve(context), rr, c);
}
public ResolveResult ResolveCast(IType targetType, ResolveResult expression)
{
cancellationToken.ThrowIfCancellationRequested();
@ -1570,8 +1665,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1570,8 +1665,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
}
}
// TODO: return implicit/explicit conversion being applied
return new ResolveResult(targetType);
Conversion c = conversions.ExplicitConversion(expression, targetType);
if (c)
return new ConversionResolveResult(targetType, expression, c);
else
return new ErrorResolveResult(targetType);
}
object CSharpPrimitiveCast(TypeCode targetType, object input)
@ -1860,7 +1958,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1860,7 +1958,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// <summary>
/// Gets all extension methods available in the current using scope.
/// This list includes unaccessible
/// This list includes unaccessible
/// </summary>
List<List<IMethod>> GetAllExtensionMethods()
{
@ -2024,9 +2122,31 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -2024,9 +2122,31 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{
cancellationToken.ThrowIfCancellationRequested();
if (SharedTypes.Dynamic.Equals(target.Type))
return DynamicResult;
switch (target.Type.Kind) {
case TypeKind.Dynamic:
for (int i = 0; i < arguments.Length; i++) {
arguments[i] = Convert(arguments[i], SharedTypes.Dynamic,
conversions.ImplicitConversion(arguments[i], SharedTypes.Dynamic));
}
return new ArrayAccessResolveResult(SharedTypes.Dynamic, target, arguments);
case TypeKind.Array:
case TypeKind.Pointer:
// §7.6.6.1 Array access / §18.5.3 Pointer element access
for (int i = 0; i < arguments.Length; i++) {
if (!(TryConvert(ref arguments[i], KnownTypeReference.Int32.Resolve(context)) ||
TryConvert(ref arguments[i], KnownTypeReference.UInt32.Resolve(context)) ||
TryConvert(ref arguments[i], KnownTypeReference.Int64.Resolve(context)) ||
TryConvert(ref arguments[i], KnownTypeReference.UInt64.Resolve(context))))
{
// conversion failed
arguments[i] = Convert(arguments[i], KnownTypeReference.Int32, Conversion.None);
}
}
return new ArrayAccessResolveResult(((TypeWithElementType)target.Type).ElementType, target, arguments);
}
// §7.6.6.2 Array access
OverloadResolution or = new OverloadResolution(context, arguments, argumentNames, new IType[0]);
MemberLookup lookup = CreateMemberLookup();
bool allowProtectedAccess = lookup.IsProtectedAccessAllowed(target.Type);
@ -2137,15 +2257,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -2137,15 +2257,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
cancellationToken.ThrowIfCancellationRequested();
Conversions c = new Conversions(context);
bool isValid;
IType resultType;
if (SharedTypes.Dynamic.Equals(trueExpression.Type) || SharedTypes.Dynamic.Equals(falseExpression.Type)) {
resultType = SharedTypes.Dynamic;
isValid = true;
} else if (HasType(trueExpression) && HasType(falseExpression)) {
bool t2f = c.ImplicitConversion(trueExpression.Type, falseExpression.Type);
bool f2t = c.ImplicitConversion(falseExpression.Type, trueExpression.Type);
bool t2f = conversions.ImplicitConversion(trueExpression.Type, falseExpression.Type);
bool f2t = conversions.ImplicitConversion(falseExpression.Type, trueExpression.Type);
resultType = (f2t && !t2f) ? trueExpression.Type : falseExpression.Type;
// The operator is valid:
// a) if there's a conversion in one direction but not the other
@ -2153,10 +2272,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -2153,10 +2272,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
isValid = (t2f != f2t) || (t2f && f2t && trueExpression.Type.Equals(falseExpression.Type));
} else if (HasType(trueExpression)) {
resultType = trueExpression.Type;
isValid = c.ImplicitConversion(falseExpression, resultType);
isValid = conversions.ImplicitConversion(falseExpression, resultType);
} else if (HasType(falseExpression)) {
resultType = falseExpression.Type;
isValid = c.ImplicitConversion(trueExpression, resultType);
isValid = conversions.ImplicitConversion(trueExpression, resultType);
} else {
return ErrorResult;
}

40
ICSharpCode.NRefactory/CSharp/Resolver/ConversionResolveResult.cs

@ -0,0 +1,40 @@ @@ -0,0 +1,40 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.Resolver
{
public class ConversionResolveResult : ResolveResult
{
public readonly ResolveResult Input;
public readonly Conversion Conversion;
public ConversionResolveResult(IType targetType, ResolveResult input, Conversion conversion)
: base(targetType)
{
this.Input = input;
this.Conversion = conversion;
}
public override bool IsError {
get { return !Conversion.IsValid; }
}
}
}

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

@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.Utils;
@ -39,11 +40,18 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -39,11 +40,18 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public static readonly Conversion BoxingConversion = new Conversion(7);
public static readonly Conversion ImplicitDynamicConversion = new Conversion(8);
public static readonly Conversion ImplicitConstantExpressionConversion = new Conversion(9);
public static readonly Conversion ImplicitTypeParameterConversion = new Conversion(10);
const int userDefinedImplicitConversionKind = 11;
public static readonly Conversion ImplicitPointerConversion = new Conversion(12);
const int anonymousFunctionConversionKind = 13;
const int methodGroupConversionKind = 14;
const int userDefinedImplicitConversionKind = 10;
public static readonly Conversion ImplicitPointerConversion = new Conversion(11);
const int anonymousFunctionConversionKind = 12;
const int methodGroupConversionKind = 13;
public static readonly Conversion ExplicitNumericConversion = new Conversion(14);
public static readonly Conversion ExplicitEnumerationConversion = new Conversion(15);
public static readonly Conversion ExplicitNullableConversion = new Conversion(16);
public static readonly Conversion ExplicitReferenceConversion = new Conversion(17);
public static readonly Conversion UnboxingConversion = new Conversion(18);
public static readonly Conversion ExplicitDynamicConversion = new Conversion(19);
public static readonly Conversion ExplicitPointerConversion = new Conversion(20);
const int userDefinedExplicitConversionKind = 21;
static readonly string[] conversionNames = {
"None",
@ -56,11 +64,18 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -56,11 +64,18 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
"Boxing conversion",
"Implicit dynamic conversion",
"Implicit constant expression conversion",
"Implicit conversion involving type parameter",
"User-defined implicit conversion",
"Implicit pointer conversion",
"Anonymous function conversion",
"Method group conversion",
"Explicit numeric conversion",
"Explicit enumeration conversion",
"Explicit nullable conversion",
"Explicit reference conversion",
"Unboxing conversion",
"Explicit dynamic conversion",
"Explicit pointer conversion",
"User-defined explicit conversion"
};
public static Conversion UserDefinedImplicitConversion(IMethod operatorMethod)
@ -68,6 +83,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -68,6 +83,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return new Conversion(userDefinedImplicitConversionKind, operatorMethod);
}
public static Conversion UserDefinedExplicitConversion(IMethod operatorMethod)
{
return new Conversion(userDefinedExplicitConversionKind, operatorMethod);
}
public static Conversion MethodGroupConversion(IMethod chosenMethod)
{
return new Conversion(methodGroupConversionKind, chosenMethod);
@ -95,16 +115,21 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -95,16 +115,21 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// Gets whether this conversion is an implicit conversion.
/// </summary>
public bool IsImplicitConversion {
get {
return kind >= IdentityConversion.kind && kind <= methodGroupConversionKind;
}
get { return kind >= IdentityConversion.kind && kind <= methodGroupConversionKind; }
}
/// <summary>
/// Gets whether this conversion is an explicit conversion.
/// </summary>
public bool IsExplicitConversion {
get { return kind > methodGroupConversionKind; }
}
/// <summary>
/// Gets whether this conversion is user-defined.
/// </summary>
public bool IsUserDefined {
get { return kind == userDefinedImplicitConversionKind; }
get { return kind == userDefinedImplicitConversionKind || kind == userDefinedExplicitConversionKind; }
}
/// <summary>
@ -139,9 +164,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -139,9 +164,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return name;
}
public bool IsValid {
get { return kind > 0; }
}
public static implicit operator bool(Conversion conversion)
{
return conversion.kind != 0;
return conversion.kind > 0;
}
#region Equals and GetHashCode implementation
@ -219,6 +248,19 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -219,6 +248,19 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (toType == null)
throw new ArgumentNullException("toType");
// C# 4.0 spec: §6.1
Conversion c = StandardImplicitConversion(fromType, toType);
if (c) return c;
return UserDefinedImplicitConversion(fromType, toType);
}
public Conversion StandardImplicitConversion(IType fromType, IType toType)
{
if (fromType == null)
throw new ArgumentNullException("fromType");
if (toType == null)
throw new ArgumentNullException("toType");
// C# 4.0 spec: §6.3.1
if (IdentityConversion(fromType, toType))
return Conversion.IdentityConversion;
if (ImplicitNumericConversion(fromType, toType))
@ -231,39 +273,78 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -231,39 +273,78 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return Conversion.ImplicitReferenceConversion;
if (BoxingConversion(fromType, toType))
return Conversion.BoxingConversion;
if (ImplicitDynamicConversion(fromType, toType))
if (fromType.Kind == TypeKind.Dynamic)
return Conversion.ImplicitDynamicConversion;
if (ImplicitTypeParameterConversion(fromType, toType))
return Conversion.ImplicitTypeParameterConversion;
if (ImplicitTypeParameterConversion(fromType, toType)) {
// Implicit type parameter conversions that aren't also
// reference conversions are considered to be boxing conversions
return Conversion.BoxingConversion;
}
if (ImplicitPointerConversion(fromType, toType))
return Conversion.ImplicitPointerConversion;
return UserDefinedImplicitConversion(fromType, toType);
return Conversion.None;
}
#endregion
public Conversion StandardImplicitConversion(IType fromType, IType toType)
#region ExplicitConversion
public Conversion ExplicitConversion(ResolveResult resolveResult, IType toType)
{
if (resolveResult == null)
throw new ArgumentNullException("resolveResult");
if (toType == null)
throw new ArgumentNullException("toType");
if (resolveResult.Type.Kind == TypeKind.Dynamic)
return Conversion.ExplicitDynamicConversion;
Conversion c = ImplicitConversion(resolveResult, toType);
if (c)
return c;
else
return ExplicitConversionImpl(resolveResult.Type, toType);
}
public Conversion ExplicitConversion(IType fromType, IType toType)
{
if (fromType == null)
throw new ArgumentNullException("fromType");
if (toType == null)
throw new ArgumentNullException("toType");
// C# 4.0 spec: §6.3.1
if (IdentityConversion(fromType, toType))
return Conversion.IdentityConversion;
if (ImplicitNumericConversion(fromType, toType))
return Conversion.ImplicitNumericConversion;
if (ImplicitNullableConversion(fromType, toType))
return Conversion.ImplicitNullableConversion;
if (ImplicitReferenceConversion(fromType, toType))
return Conversion.ImplicitReferenceConversion;
if (ImplicitTypeParameterConversion(fromType, toType))
return Conversion.ImplicitTypeParameterConversion;
if (BoxingConversion(fromType, toType))
return Conversion.BoxingConversion;
return Conversion.None;
if (fromType.Kind == TypeKind.Dynamic)
return Conversion.ExplicitDynamicConversion;
Conversion c = ImplicitConversion(fromType, toType);
if (c)
return c;
else
return ExplicitConversionImpl(fromType, toType);
}
Conversion ExplicitConversionImpl(IType fromType, IType toType)
{
// This method is called after we already checked for implicit conversions,
// so any remaining conversions must be explicit.
if (AnyNumericConversion(fromType, toType))
return Conversion.ExplicitNumericConversion;
if (ExplicitEnumerationConversion(fromType, toType))
return Conversion.ExplicitEnumerationConversion;
if (ExplicitNullableConversion(fromType, toType))
return Conversion.ExplicitNullableConversion;
if (ExplicitReferenceConversion(fromType, toType))
return Conversion.ExplicitReferenceConversion;
if (UnboxingConversion(fromType, toType))
return Conversion.UnboxingConversion;
if (ExplicitTypeParameterConversion(fromType, toType)) {
// Explicit type parameter conversions that aren't also
// reference conversions are considered to be unboxing conversions
return Conversion.UnboxingConversion;
}
if (ExplicitPointerConversion(fromType, toType))
return Conversion.ExplicitPointerConversion;
return UserDefinedExplicitConversion(fromType, toType);
}
#endregion
#region IdentityConversion
#region Identity Conversion
/// <summary>
/// Gets whether there is an identity conversion from <paramref name="fromType"/> to <paramref name="toType"/>
/// </summary>
@ -294,7 +375,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -294,7 +375,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
#endregion
#region ImplicitNumericConversion
#region Numeric Conversions
static readonly bool[,] implicitNumericConversionLookup = {
// to: short ushort int uint long ulong
// from:
@ -325,21 +406,45 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -325,21 +406,45 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
&& implicitNumericConversionLookup[from - TypeCode.Char, to - TypeCode.Int16];
}
}
bool IsNumericType(IType type)
{
TypeCode c = ReflectionHelper.GetTypeCode(type);
return c >= TypeCode.Char && c <= TypeCode.Decimal;
}
bool AnyNumericConversion(IType fromType, IType toType)
{
// C# 4.0 spec: §6.1.2 + §6.2.1
return IsNumericType(fromType) && IsNumericType(toType);
}
#endregion
#region ImplicitEnumerationConversion
#region Enumeration Conversions
bool ImplicitEnumerationConversion(ResolveResult rr, IType toType)
{
// C# 4.0 spec: §6.1.3
Debug.Assert(rr.IsCompileTimeConstant);
TypeCode constantType = ReflectionHelper.GetTypeCode(rr.Type);
if (constantType >= TypeCode.SByte && constantType <= TypeCode.Decimal && Convert.ToDouble(rr.ConstantValue) == 0) {
return NullableType.GetUnderlyingType(toType).IsEnum();
}
return false;
}
bool ExplicitEnumerationConversion(IType fromType, IType toType)
{
// C# 4.0 spec: §6.2.2
if (fromType.Kind == TypeKind.Enum) {
return toType.Kind == TypeKind.Enum || IsNumericType(toType);
} else if (IsNumericType(fromType)) {
return toType.Kind == TypeKind.Enum;
}
return false;
}
#endregion
#region ImplicitNullableConversion
#region Nullable Conversions
bool ImplicitNullableConversion(IType fromType, IType toType)
{
// C# 4.0 spec: §6.1.4
@ -351,9 +456,21 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -351,9 +456,21 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return false;
}
}
bool ExplicitNullableConversion(IType fromType, IType toType)
{
// C# 4.0 spec: §6.1.4
if (NullableType.IsNullable(toType) || NullableType.IsNullable(fromType)) {
IType t = NullableType.GetUnderlyingType(toType);
IType s = NullableType.GetUnderlyingType(fromType);
return IdentityConversion(s, t) || AnyNumericConversion(s, t) || ExplicitEnumerationConversion(s, t);
} else {
return false;
}
}
#endregion
#region NullLiteralConversion
#region Null Literal Conversion
bool NullLiteralConversion(IType fromType, IType toType)
{
// C# 4.0 spec: §6.1.5
@ -365,7 +482,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -365,7 +482,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
#endregion
#region ImplicitReferenceConversion
#region Implicit Reference Conversion
bool ImplicitReferenceConversion(IType fromType, IType toType)
{
// C# 4.0 spec: §6.1.6
@ -456,27 +573,48 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -456,27 +573,48 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
#endregion
#region BoxingConversion
#region Explicit Reference Conversion
bool ExplicitReferenceConversion(IType fromType, IType toType)
{
// C# 4.0 spec: §6.2.4
// reference conversions are possible only if both types are known to be reference types
if (!(fromType.IsReferenceType(context) == true && toType.IsReferenceType(context) == true))
return false;
// There's lots of additional rules, but they're not really relevant,
// as they are only used to identify invalid casts, and we don't care about reporting those.
return true;
}
#endregion
#region Boxing Conversions
bool BoxingConversion(IType fromType, IType toType)
{
// C# 4.0 spec: §6.1.7
fromType = NullableType.GetUnderlyingType(fromType);
return fromType.IsReferenceType(context) == false && toType.IsReferenceType(context) == true && IsSubtypeOf(fromType, toType);
if (fromType.IsReferenceType(context) == false && toType.IsReferenceType(context) == true)
return IsSubtypeOf(fromType, toType);
else
return false;
}
#endregion
#region ImplicitDynamicConversion
bool ImplicitDynamicConversion(IType fromType, IType toType)
bool UnboxingConversion(IType fromType, IType toType)
{
// C# 4.0 spec: §6.1.8
return SharedTypes.Dynamic.Equals(fromType);
// C# 4.0 spec: §6.2.5
toType = NullableType.GetUnderlyingType(toType);
if (fromType.IsReferenceType(context) == true && toType.IsReferenceType(context) == false)
return IsSubtypeOf(toType, fromType);
else
return false;
}
#endregion
#region ImplicitConstantExpressionConversion
#region Implicit Constant-Expression Conversion
bool ImplicitConstantExpressionConversion(ResolveResult rr, IType toType)
{
// C# 4.0 spec: §6.1.9
Debug.Assert(rr.IsCompileTimeConstant);
TypeCode fromTypeCode = ReflectionHelper.GetTypeCode(rr.Type);
TypeCode toTypeCode = ReflectionHelper.GetTypeCode(NullableType.GetUnderlyingType(toType));
if (fromTypeCode == TypeCode.Int64) {
@ -503,22 +641,30 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -503,22 +641,30 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
#endregion
#region ImplicitTypeParameterConversion
#region Conversions involving type parameters
/// <summary>
/// Implicit conversions involving type parameters.
/// </summary>
bool ImplicitTypeParameterConversion(IType fromType, IType toType)
{
ITypeParameter t = fromType as ITypeParameter;
if (t == null)
if (fromType.Kind != TypeKind.TypeParameter)
return false; // not a type parameter
if (t.IsReferenceType(context) == true)
if (fromType.IsReferenceType(context) == true)
return false; // already handled by ImplicitReferenceConversion
return IsSubtypeOf(t, toType);
return IsSubtypeOf(fromType, toType);
}
bool ExplicitTypeParameterConversion(IType fromType, IType toType)
{
if (toType.Kind == TypeKind.TypeParameter) {
return fromType.Kind == TypeKind.TypeParameter || fromType.IsReferenceType(context) == true;
} else {
return fromType.Kind == TypeKind.TypeParameter && toType.Kind == TypeKind.Interface;
}
}
#endregion
#region ImplicitPointerConversion
#region Pointer Conversions
bool ImplicitPointerConversion(IType fromType, IType toType)
{
// C# 4.0 spec: §18.4 Pointer conversions
@ -528,37 +674,120 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -528,37 +674,120 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return true;
return false;
}
bool ExplicitPointerConversion(IType fromType, IType toType)
{
// C# 4.0 spec: §18.4 Pointer conversions
if (fromType.Kind == TypeKind.Pointer) {
return toType.Kind == TypeKind.Pointer || IsIntegerType(toType);
} else {
return toType.Kind == TypeKind.Pointer && IsIntegerType(fromType);
}
}
bool IsIntegerType(IType type)
{
TypeCode c = ReflectionHelper.GetTypeCode(type);
return c >= TypeCode.SByte && c <= TypeCode.UInt64;
}
#endregion
#region UserDefinedImplicitConversion
#region User-Defined Conversions
/// <summary>
/// Gets whether type A is encompassed by type B.
/// </summary>
bool IsEncompassedBy(IType a, IType b)
{
return a.Kind != TypeKind.Interface && b.Kind != TypeKind.Interface && StandardImplicitConversion(a, b);
}
bool IsEncompassingOrEncompassedBy(IType a, IType b)
{
return a.Kind != TypeKind.Interface && b.Kind != TypeKind.Interface
&& (StandardImplicitConversion(a, b) || StandardImplicitConversion(b, a));
}
Conversion UserDefinedImplicitConversion(IType fromType, IType toType)
{
// C# 4.0 spec §6.4.4 User-defined implicit conversions
// Currently we only test whether an applicable implicit conversion exists,
// we do not resolve which conversion is the most specific and gets used.
var operators = GetApplicableConversionOperators(fromType, toType, false);
// TODO: Find most specific conversion
if (operators.Count > 0)
return Conversion.UserDefinedImplicitConversion(operators[0].Method);
else
return Conversion.None;
}
Conversion UserDefinedExplicitConversion(IType fromType, IType toType)
{
// C# 4.0 spec §6.4.5 User-defined implicit conversions
var operators = GetApplicableConversionOperators(fromType, toType, true);
// TODO: Find most specific conversion
if (operators.Count > 0)
return Conversion.UserDefinedExplicitConversion(operators[0].Method);
else
return Conversion.None;
}
class OperatorInfo
{
public readonly IMethod Method;
public readonly IType SourceType;
public readonly IType TargetType;
public readonly bool IsLifted;
public OperatorInfo(IMethod method, IType sourceType, IType targetType, bool isLifted)
{
this.Method = method;
this.SourceType = sourceType;
this.TargetType = targetType;
this.IsLifted = isLifted;
}
}
List<OperatorInfo> GetApplicableConversionOperators(IType fromType, IType toType, bool isExplicit)
{
// Find the candidate operators:
Predicate<IMethod> opImplicitFilter = m => m.IsStatic && m.IsOperator && m.Name == "op_Implicit" && m.Parameters.Count == 1;
var operators = NullableType.GetUnderlyingType(fromType).GetMethods(context, opImplicitFilter)
.Concat(NullableType.GetUnderlyingType(toType).GetMethods(context, opImplicitFilter));
Predicate<IMethod> opFilter;
if (isExplicit)
opFilter = m => m.IsStatic && m.IsOperator && m.Name == "op_Explicit" && m.Parameters.Count == 1;
else
opFilter = m => m.IsStatic && m.IsOperator && m.Name == "op_Implicit" && m.Parameters.Count == 1;
var operators = NullableType.GetUnderlyingType(fromType).GetMethods(context, opFilter)
.Concat(NullableType.GetUnderlyingType(toType).GetMethods(context, opFilter)).Distinct();
// Determine whether one of them is applicable:
List<OperatorInfo> result = new List<OperatorInfo>();
foreach (IMethod op in operators) {
IType sourceType = op.Parameters[0].Type.Resolve(context);
IType targetType = op.ReturnType.Resolve(context);
// Try if the operator is applicable:
if (StandardImplicitConversion(fromType, sourceType) && StandardImplicitConversion(targetType, toType)) {
return Conversion.UserDefinedImplicitConversion(op);
bool isApplicable;
if (isExplicit) {
isApplicable = IsEncompassingOrEncompassedBy(fromType, sourceType)
&& IsEncompassingOrEncompassedBy(targetType, toType);
} else {
isApplicable = IsEncompassedBy(fromType, sourceType) && IsEncompassedBy(targetType, toType);
}
if (isApplicable) {
result.Add(new OperatorInfo(op, sourceType, targetType, false));
}
// Try if the operator is applicable in lifted form:
if (sourceType.IsReferenceType(context) == false && targetType.IsReferenceType(context) == false) {
IType liftedSourceType = NullableType.Create(sourceType, context);
IType liftedTargetType = NullableType.Create(targetType, context);
if (StandardImplicitConversion(fromType, liftedSourceType) && StandardImplicitConversion(liftedTargetType, toType)) {
return Conversion.UserDefinedImplicitConversion(op);
if (isExplicit) {
isApplicable = IsEncompassingOrEncompassedBy(fromType, liftedSourceType)
&& IsEncompassingOrEncompassedBy(liftedTargetType, toType);
} else {
isApplicable = IsEncompassedBy(fromType, liftedSourceType) && IsEncompassedBy(liftedTargetType, toType);
}
if (isApplicable) {
result.Add(new OperatorInfo(op, liftedSourceType, liftedTargetType, true));
}
}
}
return Conversion.None;
return result;
}
#endregion

7
ICSharpCode.NRefactory/CSharp/Resolver/InvocationResolveResult.cs

@ -18,6 +18,8 @@ @@ -18,6 +18,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
@ -97,5 +99,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -97,5 +99,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public new IParameterizedMember Member {
get { return (IParameterizedMember)base.Member; }
}
public override IEnumerable<ResolveResult> GetChildResults()
{
return base.GetChildResults().Concat(this.Arguments);
}
}
}

14
ICSharpCode.NRefactory/CSharp/Resolver/MemberResolveResult.cs

@ -17,6 +17,8 @@ @@ -17,6 +17,8 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.Resolver
@ -61,6 +63,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -61,6 +63,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
}
public ResolveResult TargetResult {
get { return targetResult; }
}
public IMember Member {
get { return member; }
}
@ -73,6 +79,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -73,6 +79,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
get { return constantValue; }
}
public override IEnumerable<ResolveResult> GetChildResults()
{
if (targetResult != null)
return new[] { targetResult };
else
return Enumerable.Empty<ResolveResult>();
}
public override string ToString()
{
return string.Format("[{0} {1}]", GetType().Name, member);

8
ICSharpCode.NRefactory/CSharp/Resolver/MethodGroupResolveResult.cs

@ -163,5 +163,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -163,5 +163,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
return or;
}
public override IEnumerable<ResolveResult> GetChildResults()
{
if (targetResult != null)
return new[] { targetResult };
else
return Enumerable.Empty<ResolveResult>();
}
}
}

130
ICSharpCode.NRefactory/CSharp/Resolver/OperatorResolveResult.cs

@ -0,0 +1,130 @@ @@ -0,0 +1,130 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.Resolver
{
/// <summary>
/// Resolve result representing a built-in unary operator.
/// (user-defined operators use InvocationResolveResult)
/// </summary>
public class UnaryOperatorResolveResult : ResolveResult
{
public readonly UnaryOperatorType Operator;
public readonly ResolveResult Input;
public UnaryOperatorResolveResult(IType resultType, UnaryOperatorType op, ResolveResult input)
: base(resultType)
{
if (input == null)
throw new ArgumentNullException("input");
this.Operator = op;
this.Input = input;
}
public override IEnumerable<ResolveResult> GetChildResults()
{
return new [] { Input };
}
}
/// <summary>
/// Resolve result representing a built-in binary operator.
/// (user-defined operators use InvocationResolveResult)
/// </summary>
public class BinaryOperatorResolveResult : ResolveResult
{
public readonly BinaryOperatorType Operator;
public readonly ResolveResult Left;
public readonly ResolveResult Right;
public BinaryOperatorResolveResult(IType resultType, ResolveResult lhs, BinaryOperatorType op, ResolveResult rhs)
: base(resultType)
{
if (lhs == null)
throw new ArgumentNullException("lhs");
if (rhs == null)
throw new ArgumentNullException("rhs");
this.Left = lhs;
this.Operator = op;
this.Right = rhs;
}
public override IEnumerable<ResolveResult> GetChildResults()
{
return new [] { Left, Right };
}
}
/// <summary>
/// Resolve result representing the conditional operator.
/// </summary>
public class ConditionalOperatorResolveResult : ResolveResult
{
public readonly ResolveResult Condition;
public readonly ResolveResult True;
public readonly ResolveResult False;
public ConditionalOperatorResolveResult(IType targetType, ResolveResult condition, ResolveResult @true, ResolveResult @false)
: base(targetType)
{
if (condition == null)
throw new ArgumentNullException("condition");
if (@true == null)
throw new ArgumentNullException("true");
if (@false == null)
throw new ArgumentNullException("false");
this.Condition = condition;
this.True = @true;
this.False = @false;
}
public override IEnumerable<ResolveResult> GetChildResults()
{
return new [] { Condition, True, False };
}
}
/// <summary>
/// Resolve result representing an array access.
/// </summary>
public class ArrayAccessResolveResult : ResolveResult
{
public readonly ResolveResult Array;
public readonly ResolveResult[] Indices;
public ArrayAccessResolveResult(IType elementType, ResolveResult array, ResolveResult[] indices) : base(elementType)
{
if (array == null)
throw new ArgumentNullException("array");
if (indices == null)
throw new ArgumentNullException("indices");
this.Array = array;
this.Indices = indices;
}
public override IEnumerable<ResolveResult> GetChildResults()
{
return new [] { Array }.Concat(Indices);
}
}
}

7
ICSharpCode.NRefactory/CSharp/Resolver/ResolveResult.cs

@ -17,6 +17,8 @@ @@ -17,6 +17,8 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
@ -56,5 +58,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -56,5 +58,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{
return "[" + GetType().Name + " " + type + "]";
}
public virtual IEnumerable<ResolveResult> GetChildResults()
{
return Enumerable.Empty<ResolveResult>();
}
}
}

2
ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs

@ -765,7 +765,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -765,7 +765,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{
if (resolverEnabled) {
ResolveResult rr = Resolve(directionExpression.Expression);
return new ByReferenceResolveResult(rr.Type, directionExpression.FieldDirection == FieldDirection.Out);
return new ByReferenceResolveResult(rr, directionExpression.FieldDirection == FieldDirection.Out);
} else {
ScanChildren(directionExpression);
return null;

2
ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj

@ -102,6 +102,8 @@ @@ -102,6 +102,8 @@
<Compile Include="CSharp\Ast\GeneralScope\TypeParameterDeclaration.cs" />
<Compile Include="CSharp\Ast\MemberType.cs" />
<Compile Include="CSharp\Refactoring\TypeSystemAstBuilder.cs" />
<Compile Include="CSharp\Resolver\OperatorResolveResult.cs" />
<Compile Include="CSharp\Resolver\ConversionResolveResult.cs" />
<Compile Include="CSharp\Resolver\CSharpAttribute.cs" />
<Compile Include="CSharp\Resolver\ConstantValues.cs" />
<Compile Include="CSharp\Resolver\InvocationResolveResult.cs" />

1
ICSharpCode.NRefactory/TypeSystem/PointerType.cs

@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
namespace ICSharpCode.NRefactory.TypeSystem

Loading…
Cancel
Save