Browse Source

Merge pull request #80 from erik-kallen/DynamicImprovementsNewTry

Dynamic improvements as discussed in https://github.com/icsharpcode/NRefactory/pull/70#issuecomment-6694782
newNRvisualizers
Daniel Grunwald 13 years ago
parent
commit
41b777593a
  1. 57
      ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs
  2. 41
      ICSharpCode.NRefactory.CSharp/Resolver/DynamicInvocationResolveResult.cs
  3. 2
      ICSharpCode.NRefactory.CSharp/Resolver/MethodGroupResolveResult.cs
  4. 612
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/DynamicTests.cs

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

@ -1900,11 +1900,33 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1900,11 +1900,33 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
// C# 4.0 spec: §7.6.5
if (target.Type.Kind == TypeKind.Dynamic) {
return new DynamicInvocationResolveResult(target, arguments.Select((a, i) => new DynamicInvocationArgument(argumentNames != null ? argumentNames[i] : null, a)).ToList().AsReadOnly());
return new DynamicInvocationResolveResult(target, DynamicInvocationType.Invocation, arguments.Select((a, i) => new DynamicInvocationArgument(argumentNames != null ? argumentNames[i] : null, a)).ToList().AsReadOnly());
}
MethodGroupResolveResult mgrr = target as MethodGroupResolveResult;
if (mgrr != null) {
if (arguments.Any(a => a.Type.Kind == TypeKind.Dynamic)) {
// If we have dynamic arguments, we need to represent the invocation as a dynamic invocation if there is more than one applicable method.
var or2 = new OverloadResolution(compilation, arguments, argumentNames, mgrr.TypeArguments.ToArray(), conversions);
var applicableMethods = mgrr.MethodsGroupedByDeclaringType.SelectMany(m => m, (x, m) => new { x.DeclaringType, Method = m }).Where(x => OverloadResolution.IsApplicable(or2.AddCandidate(x.Method))).ToList();
if (applicableMethods.Count > 1) {
ResolveResult actualTarget;
if (applicableMethods.All(x => x.Method.IsStatic) && !(mgrr.TargetResult is TypeResolveResult))
actualTarget = new TypeResolveResult(mgrr.TargetResult.Type);
else
actualTarget = mgrr.TargetResult;
var l = new List<MethodListWithDeclaringType>();
foreach (var m in applicableMethods) {
if (l.Count == 0 || l[l.Count - 1].DeclaringType != m.DeclaringType)
l.Add(new MethodListWithDeclaringType(m.DeclaringType));
l[l.Count - 1].Add(m.Method);
}
return new DynamicInvocationResolveResult(new MethodGroupResolveResult(actualTarget, mgrr.MethodName, l, mgrr.TypeArguments), DynamicInvocationType.Invocation, arguments.Select((a, i) => new DynamicInvocationArgument(argumentNames != null ? argumentNames[i] : null, a)).ToList().AsReadOnly());
}
}
OverloadResolution or = mgrr.PerformOverloadResolution(compilation, arguments, argumentNames, checkForOverflow: checkForOverflow, conversions: conversions);
if (or.BestCandidate != null) {
if (or.BestCandidate.IsStatic && !or.IsExtensionMethodInvocation && !(mgrr.TargetResult is TypeResolveResult))
@ -2043,10 +2065,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -2043,10 +2065,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{
switch (target.Type.Kind) {
case TypeKind.Dynamic:
for (int i = 0; i < arguments.Length; i++) {
arguments[i] = Convert(arguments[i], SpecialType.Dynamic);
}
return new ArrayAccessResolveResult(SpecialType.Dynamic, target, arguments);
return new DynamicInvocationResolveResult(target, DynamicInvocationType.Indexing, arguments.Select((a, i) => new DynamicInvocationArgument(argumentNames != null ? argumentNames[i] : null, a)).ToList().AsReadOnly());
case TypeKind.Array:
case TypeKind.Pointer:
@ -2056,9 +2075,21 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -2056,9 +2075,21 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
// §7.6.6.2 Indexer access
OverloadResolution or = CreateOverloadResolution(arguments, argumentNames);
MemberLookup lookup = CreateMemberLookup();
var indexers = lookup.LookupIndexers(target.Type);
if (arguments.Any(a => a.Type.Kind == TypeKind.Dynamic)) {
// If we have dynamic arguments, we need to represent the invocation as a dynamic invocation if there is more than one applicable indexer.
var or2 = new OverloadResolution(compilation, arguments, argumentNames, null, conversions);
var applicableIndexers = indexers.SelectMany(x => x).Where(m => OverloadResolution.IsApplicable(or2.AddCandidate(m))).ToList();
if (applicableIndexers.Count > 1) {
return new DynamicInvocationResolveResult(target, DynamicInvocationType.Indexing, arguments.Select((a, i) => new DynamicInvocationArgument(argumentNames != null ? argumentNames[i] : null, a)).ToList().AsReadOnly());
}
}
OverloadResolution or = CreateOverloadResolution(arguments, argumentNames);
or.AddMethodLists(indexers);
if (or.BestCandidate != null) {
return or.CreateResolveResult(target);
@ -2122,12 +2153,22 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -2122,12 +2153,22 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
OverloadResolution or = CreateOverloadResolution(arguments, argumentNames);
MemberLookup lookup = CreateMemberLookup();
var allApplicable = (arguments.Any(a => a.Type.Kind == TypeKind.Dynamic) ? new List<IMethod>() : null);
foreach (IMethod ctor in type.GetConstructors()) {
if (lookup.IsAccessible(ctor, allowProtectedAccess))
or.AddCandidate(ctor);
if (lookup.IsAccessible(ctor, allowProtectedAccess)) {
var orErrors = or.AddCandidate(ctor);
if (allApplicable != null && OverloadResolution.IsApplicable(orErrors))
allApplicable.Add(ctor);
}
else
or.AddCandidate(ctor, OverloadResolutionErrors.Inaccessible);
}
if (allApplicable != null && allApplicable.Count > 1) {
// If we have dynamic arguments, we need to represent the invocation as a dynamic invocation if there is more than one applicable constructor.
return new DynamicInvocationResolveResult(new MethodGroupResolveResult(null, allApplicable[0].Name, new[] { new MethodListWithDeclaringType(type, allApplicable) }, null), DynamicInvocationType.ObjectCreation, arguments.Select((a, i) => new DynamicInvocationArgument(argumentNames != null ? argumentNames[i] : null, a)).ToList().AsReadOnly(), initializerStatements);
}
if (or.BestCandidate != null) {
return or.CreateResolveResult(null, initializerStatements);
} else {

41
ICSharpCode.NRefactory.CSharp/Resolver/DynamicInvocationResolveResult.cs

@ -45,24 +45,57 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -45,24 +45,57 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
}
public enum DynamicInvocationType {
/// <summary>
/// The invocation is a normal invocation ( 'a(b)' ).
/// </summary>
Invocation,
/// <summary>
/// The invocation is an indexing ( 'a[b]' ).
/// </summary>
Indexing,
/// <summary>
/// The invocation is an object creation ( 'new a(b)' ). Also used when invoking a base constructor ( ' : base(a) ' ) and chaining constructors ( ' : this(a) ').
/// </summary>
ObjectCreation,
}
/// <summary>
/// Represents the result of an invocation of a member of a dynamic object.
/// </summary>
public class DynamicInvocationResolveResult : ResolveResult
{
/// <summary>
/// Target of the invocation (a dynamic object).
/// Target of the invocation. Can be a dynamic expression or a <see cref="MethodGroupResolveResult"/>.
/// </summary>
public readonly ResolveResult Target;
/// <summary>
/// Type of the invocation.
/// </summary>
public readonly DynamicInvocationType InvocationType;
/// <summary>
/// Arguments for the call.
/// </summary>
public readonly IList<DynamicInvocationArgument> Arguments;
public DynamicInvocationResolveResult(ResolveResult target, IList<DynamicInvocationArgument> arguments) : base(SpecialType.Dynamic) {
this.Target = target;
this.Arguments = arguments ?? EmptyList<DynamicInvocationArgument>.Instance;
/// <summary>
/// Gets the list of initializer statements that are appplied to the result of this invocation.
/// This is used to represent object and collection initializers.
/// With the initializer statements, the <see cref="InitializedObjectResolveResult"/> is used
/// to refer to the result of this invocation.
/// Initializer statements can only exist if the <see cref="InvocationType"/> is <see cref="DynamicInvocationType.ObjectCreation"/>.
/// </summary>
public readonly IList<ResolveResult> InitializerStatements;
public DynamicInvocationResolveResult(ResolveResult target, DynamicInvocationType invocationType, IList<DynamicInvocationArgument> arguments, IList<ResolveResult> initializerStatements = null) : base(SpecialType.Dynamic) {
this.Target = target;
this.InvocationType = invocationType;
this.Arguments = arguments ?? EmptyList<DynamicInvocationArgument>.Instance;
this.InitializerStatements = initializerStatements ?? EmptyList<ResolveResult>.Instance;
}
public override string ToString()

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

@ -86,8 +86,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -86,8 +86,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public MethodGroupResolveResult(ResolveResult targetResult, string methodName, IList<MethodListWithDeclaringType> methods, IList<IType> typeArguments) : base(SpecialType.UnknownType)
{
if (targetResult == null)
throw new ArgumentNullException("targetResult");
if (methods == null)
throw new ArgumentNullException("methods");
this.targetResult = targetResult;

612
ICSharpCode.NRefactory.Tests/CSharp/Resolver/DynamicTests.cs

@ -1,6 +1,7 @@ @@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;
@ -37,6 +38,7 @@ class TestClass { @@ -37,6 +38,7 @@ class TestClass {
}";
var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.Type.Kind, Is.EqualTo(TypeKind.Dynamic));
Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Invocation));
Assert.That(rr.Target, Is.InstanceOf<DynamicMemberResolveResult>());
var dynamicMember = (DynamicMemberResolveResult)rr.Target;
Assert.That(dynamicMember.Target is LocalResolveResult && ((LocalResolveResult)dynamicMember.Target).Variable.Name == "obj");
@ -61,6 +63,7 @@ class TestClass { @@ -61,6 +63,7 @@ class TestClass {
}";
var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.Type.Kind, Is.EqualTo(TypeKind.Dynamic));
Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Invocation));
Assert.That(rr.Target, Is.InstanceOf<DynamicMemberResolveResult>());
var dynamicMember = (DynamicMemberResolveResult)rr.Target;
Assert.That(dynamicMember.Target is LocalResolveResult && ((LocalResolveResult)dynamicMember.Target).Variable.Name == "obj");
@ -86,12 +89,14 @@ class TestClass { @@ -86,12 +89,14 @@ class TestClass {
}";
var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.Type.Kind, Is.EqualTo(TypeKind.Dynamic));
Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Invocation));
Assert.That(rr.Target, Is.InstanceOf<DynamicInvocationResolveResult>());
var innerInvocation = (DynamicInvocationResolveResult)rr.Target;
Assert.That(innerInvocation.Target, Is.InstanceOf<DynamicMemberResolveResult>());
var dynamicMember = (DynamicMemberResolveResult)innerInvocation.Target;
Assert.That(dynamicMember.Target is LocalResolveResult && ((LocalResolveResult)dynamicMember.Target).Variable.Name == "obj");
Assert.That(dynamicMember.Member, Is.EqualTo("SomeMethod"));
Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Invocation));
Assert.That(innerInvocation.Arguments.Count, Is.EqualTo(1));
Assert.That(innerInvocation.Arguments[0].Name, Is.Null);
Assert.That(innerInvocation.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)innerInvocation.Arguments[0].Value).Variable.Name == "a");
@ -99,5 +104,612 @@ class TestClass { @@ -99,5 +104,612 @@ class TestClass {
Assert.That(rr.Arguments[0].Name, Is.Null);
Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "b");
}
[Test]
public void InvocationWithDynamicArgumentWithOneApplicableMethod() {
string program = @"using System;
class TestClass {
public void SomeMethod(int a) {}
public void SomeMethod(int a, string b) {}
void F() {
dynamic obj = null;
var x = $this.SomeMethod(obj)$;
}
}";
var rr = Resolve<CSharpInvocationResolveResult>(program);
Assert.That(rr.Member.Name, Is.EqualTo("SomeMethod"));
Assert.That(((IParameterizedMember)rr.Member).Parameters.Count, Is.EqualTo(1));
Assert.That(rr.Arguments.Count, Is.EqualTo(1));
var cr = rr.Arguments[0] as ConversionResolveResult;
Assert.That(cr, Is.Not.Null);
Assert.That(cr.Conversion.IsImplicit, Is.True);
Assert.That(cr.Conversion.IsDynamicConversion, Is.True);
Assert.That(cr.Input is LocalResolveResult && ((LocalResolveResult)cr.Input).Variable.Name == "obj");
}
[Test]
public void InvocationWithDynamicArgumentWhenBothAnOwnAndABaseMethodAreApplicable() {
string program = @"using System;
class TestBase {
public void SomeMethod(int a) {}
}
class TestClass : TestBase {
public void SomeMethod(string a) {}
public void SomeMethod(string a, int b) {}
void F() {
dynamic obj = null;
var x = $this.SomeMethod(obj)$;
}
}";
var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Invocation));
var mg = rr.Target as MethodGroupResolveResult;
Assert.That(mg, Is.Not.Null, "Expected a MethodGroup");
Assert.That(mg.TargetResult, Is.InstanceOf<ThisResolveResult>());
Assert.That(mg.MethodName, Is.EqualTo("SomeMethod"));
Assert.That(mg.Methods.Count(), Is.EqualTo(2));
Assert.That(mg.Methods.Any(m => m.Parameters.Count == 1 && m.DeclaringType.Name == "TestBase" && m.Name == "SomeMethod" && m.Parameters[0].Type.Name == "Int32"));
Assert.That(mg.Methods.Any(m => m.Parameters.Count == 1 && m.DeclaringType.Name == "TestClass" && m.Name == "SomeMethod" && m.Parameters[0].Type.Name == "String"));
Assert.That(rr.Arguments.Count, Is.EqualTo(1));
Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "obj");
}
[Test, Ignore("Fails")]
public void InvocationWithDynamicArgumentWhenABaseMethodIsShadowed() {
string program = @"using System;
class TestBase {
public void SomeMethod(int a) {}
}
class TestClass : TestBase {
public void SomeMethod(int a) {}
public void SomeMethod(string a, int b) {}
void F() {
dynamic obj = null;
var x = $this.SomeMethod(obj)$;
}
}";
var rr = Resolve<CSharpInvocationResolveResult>(program);
Assert.That(rr.Member.Name, Is.EqualTo("SomeMethod"));
Assert.That(rr.Member.DeclaringType.Name, Is.EqualTo("TestClass"));
Assert.That(((IParameterizedMember)rr.Member).Parameters.Count, Is.EqualTo(1));
Assert.That(rr.Arguments.Count, Is.EqualTo(1));
var cr = rr.Arguments[0] as ConversionResolveResult;
Assert.That(cr, Is.Not.Null);
Assert.That(cr.Conversion.IsImplicit, Is.True);
Assert.That(cr.Conversion.IsDynamicConversion, Is.True);
Assert.That(cr.Input is LocalResolveResult && ((LocalResolveResult)cr.Input).Variable.Name == "obj");
}
[Test]
public void InvocationWithDynamicArgumentWithTwoApplicableMethods() {
string program = @"using System;
class TestClass {
public void SomeMethod(int a) {}
public void SomeMethod(string a) {}
public void SomeMethod(int a, string b) {}
void F() {
dynamic obj = null;
var x = $SomeMethod(obj)$;
}
}";
var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Invocation));
var mg = rr.Target as MethodGroupResolveResult;
Assert.That(mg, Is.Not.Null, "Expected a MethodGroup");
Assert.That(mg.TargetResult, Is.InstanceOf<ThisResolveResult>());
Assert.That(mg.MethodName, Is.EqualTo("SomeMethod"));
Assert.That(mg.Methods.All(m => m.Parameters.Count == 1));
Assert.That(mg.Methods.Select(m => m.Parameters[0].Type.Name), Is.EquivalentTo(new[] { "Int32", "String" }));
Assert.That(mg.Methods.All(m => m.Name == "SomeMethod" && m.DeclaringType.Name == "TestClass"));
Assert.That(rr.Arguments.Count, Is.EqualTo(1));
Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "obj");
}
[Test]
public void InvocationWithDynamicArgumentWithTwoApplicableStaticMethods() {
string program = @"using System;
class TestClass {
public static void SomeMethod(int a) {}
public static void SomeMethod(string a) {}
public static void SomeMethod(int a, string b) {}
void F() {
dynamic obj = null;
var x = $SomeMethod(obj)$;
}
}";
var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Invocation));
var mg = rr.Target as MethodGroupResolveResult;
Assert.That(mg, Is.Not.Null, "Expected a MethodGroup");
Assert.That(mg.TargetResult, Is.InstanceOf<TypeResolveResult>());
Assert.That(mg.MethodName, Is.EqualTo("SomeMethod"));
Assert.That(mg.Methods.All(m => m.Parameters.Count == 1));
Assert.That(mg.Methods.Select(m => m.Parameters[0].Type.Name), Is.EquivalentTo(new[] { "Int32", "String" }));
Assert.That(mg.Methods.All(m => m.Name == "SomeMethod" && m.DeclaringType.Name == "TestClass"));
Assert.That(rr.Arguments.Count, Is.EqualTo(1));
Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "obj");
}
[Test]
public void InvocationWithDynamicArgumentWithApplicableStaticAndNonStaticMethodsFavorTheNonStaticOne() {
string program = @"using System;
class TestClass {
public static void SomeMethod(int a) {}
public void SomeMethod(string a) {}
public static void SomeMethod(int a, string b) {}
void F() {
dynamic obj = null;
var x = $SomeMethod(obj)$;
}
}";
var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Invocation));
var mg = rr.Target as MethodGroupResolveResult;
Assert.That(mg, Is.Not.Null, "Expected a MethodGroup");
Assert.That(mg.TargetResult, Is.InstanceOf<ThisResolveResult>());
Assert.That(mg.MethodName, Is.EqualTo("SomeMethod"));
Assert.That(mg.Methods.All(m => m.Parameters.Count == 1));
Assert.That(mg.Methods.Select(m => m.Parameters[0].Type.Name), Is.EquivalentTo(new[] { "Int32", "String" }));
Assert.That(mg.Methods.All(m => m.Name == "SomeMethod" && m.DeclaringType.Name == "TestClass"));
Assert.That(rr.Arguments.Count, Is.EqualTo(1));
Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "obj");
}
[Test]
public void InvocationWithDynamicArgumentWhenTheOnlyApplicableMethodIsAnExtensionMethod() {
string program = @"using System;
static class OtherClass {
public void SomeMethod(this TestClass x, int a) {}
public void SomeMethod(this TestClass x, string a) {}
public void SomeMethod(this TestClass x, int a, string b) {}
}
class TestClass {
void F() {
dynamic obj = null;
var x = $this.SomeMethod(obj)$;
}
}";
var rr = Resolve(program);
Assert.That(rr.IsError, Is.True);
}
[Test]
public void InvocationWithDynamicArgumentWithTwoApplicableMethodsAndNamedArguments() {
string program = @"using System;
class TestClass {
public void SomeMethod(int a, int i) {}
public void SomeMethod(string a, int i) {}
public void SomeMethod(int a, string b, int i) {}
void F() {
dynamic obj = null;
int idx = 0;
var x = $this.SomeMethod(a: obj, i: idx)$;
}
}";
var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Invocation));
var mg = rr.Target as MethodGroupResolveResult;
Assert.That(mg, Is.Not.Null, "Expected a MethodGroup");
Assert.That(mg.TargetResult, Is.InstanceOf<ThisResolveResult>());
Assert.That(mg.MethodName, Is.EqualTo("SomeMethod"));
Assert.That(mg.Methods.All(m => m.Parameters.Count == 2) && mg.Methods.All(m => m.Parameters[1].Type.Name == "Int32"));
Assert.That(mg.Methods.Select(m => m.Parameters[0].Type.Name), Is.EquivalentTo(new[] { "Int32", "String" }));
Assert.That(mg.Methods.All(m => m.Name == "SomeMethod" && m.DeclaringType.Name == "TestClass"));
Assert.That(rr.Arguments.Count, Is.EqualTo(2));
Assert.That(rr.Arguments[0].Name, Is.EqualTo("a"));
Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "obj");
Assert.That(rr.Arguments[1].Name, Is.EqualTo("i"));
Assert.That(rr.Arguments[1].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[1].Value).Variable.Name == "idx");
}
[Test]
public void IndexingDynamicObjectWithUnnamedArguments() {
string program = @"using System;
class TestClass {
void F() {
dynamic obj = null;
int a = 0, b = 0;
object o = $obj[a]$;
}
}";
var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.Type.Kind, Is.EqualTo(TypeKind.Dynamic));
Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Indexing));
Assert.That(rr.Target is LocalResolveResult && ((LocalResolveResult)rr.Target).Variable.Name == "obj");
Assert.That(rr.Arguments.Count, Is.EqualTo(1));
Assert.That(rr.Arguments[0].Name, Is.Null);
Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "a");
}
[Test]
public void IndexingDynamicObjectWithNamedArguments() {
string program = @"using System;
class TestClass {
void F() {
dynamic obj = null;
int a = 0, b = 0;
$obj[arg1: a, arg2: b]$ = 1;
}
}";
var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.Type.Kind, Is.EqualTo(TypeKind.Dynamic));
Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Indexing));
Assert.That(rr.Target is LocalResolveResult && ((LocalResolveResult)rr.Target).Variable.Name == "obj");
Assert.That(rr.Arguments.Count, Is.EqualTo(2));
Assert.That(rr.Arguments[0].Name, Is.EqualTo("arg1"));
Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "a");
Assert.That(rr.Arguments[1].Name, Is.EqualTo("arg2"));
Assert.That(rr.Arguments[1].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[1].Value).Variable.Name == "b");
}
[Test]
public void IndexingWithDynamicArgumentWithOneApplicableIndexer() {
string program = @"using System;
class TestClass {
public int this[int a] { get { return 0; } }
public int this[int a, string b] { get { return 0; } }
void F() {
dynamic obj = null;
var x = $this[obj]$;
}
}";
var rr = Resolve<CSharpInvocationResolveResult>(program);
Assert.That(rr.Member.Name, Is.EqualTo("Item"));
Assert.That(((IParameterizedMember)rr.Member).Parameters.Count, Is.EqualTo(1));
Assert.That(rr.Arguments.Count, Is.EqualTo(1));
var cr = rr.Arguments[0] as ConversionResolveResult;
Assert.That(cr, Is.Not.Null);
Assert.That(cr.Conversion.IsImplicit, Is.True);
Assert.That(cr.Conversion.IsDynamicConversion, Is.True);
Assert.That(cr.Input is LocalResolveResult && ((LocalResolveResult)cr.Input).Variable.Name == "obj");
}
[Test]
public void IndexingWithDynamicArgumentWithTwoApplicableIndexersAndUnnamedArguments() {
string program = @"using System;
class TestClass {
public int this[int a] { get { return 0; } }
public int this[string a] { get { return 0; } }
void F() {
dynamic obj = null;
var x = $this[obj]$;
}
}";
var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.Type.Kind, Is.EqualTo(TypeKind.Dynamic));
Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Indexing));
Assert.That(rr.Target, Is.InstanceOf<ThisResolveResult>());
Assert.That(rr.Arguments.Count, Is.EqualTo(1));
Assert.That(rr.Arguments[0].Name, Is.Null);
Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "obj");
}
[Test]
public void IndexingWithDynamicArgumentWithAnApplicableBaseIndexer() {
string program = @"using System;
class TestBase {
public int this[int a] { get { return 0; } }
}
class TestClass : TestBase {
public int this[string a] { get { return 0; } }
public int this[string a, int b] { get { return 0; } }
void F() {
dynamic obj = null;
var x = $this[obj]$;
}
}";
var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.Type.Kind, Is.EqualTo(TypeKind.Dynamic));
Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Indexing));
Assert.That(rr.Target, Is.InstanceOf<ThisResolveResult>());
Assert.That(rr.Arguments.Count, Is.EqualTo(1));
Assert.That(rr.Arguments[0].Name, Is.Null);
Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "obj");
}
[Test, Ignore("Fails")]
public void IndexingWithDynamicArgumentWithTheOnlyApplicableIndexerShadowingABaseIndexer() {
string program = @"using System;
class TestBase {
public int this[int a] { get { return 0; } }
}
class TestClass : TestBase {
public new int this[int a] { get { return 0; } }
public int this[int a, string b] { get { return 0; } }
void F() {
dynamic obj = null;
var x = $this[obj]$;
}
}";
var rr = Resolve<CSharpInvocationResolveResult>(program);
Assert.That(rr.Member.Name, Is.EqualTo("Item"));
Assert.That(((IParameterizedMember)rr.Member).Parameters.Count, Is.EqualTo(1));
Assert.That(rr.Arguments.Count, Is.EqualTo(1));
var cr = rr.Arguments[0] as ConversionResolveResult;
Assert.That(cr, Is.Not.Null);
Assert.That(cr.Conversion.IsImplicit, Is.True);
Assert.That(cr.Conversion.IsDynamicConversion, Is.True);
Assert.That(cr.Input is LocalResolveResult && ((LocalResolveResult)cr.Input).Variable.Name == "obj");
}
[Test]
public void IndexingWithDynamicArgumentWithTwoApplicableIndexersAndNamedArguments() {
string program = @"using System;
class TestClass {
public int this[int a, int i] { get { return 0; } }
public int this[string a, int i] { get { return 0; } }
void F() {
dynamic obj = null;
int idx = 0;
var x = $this[a: obj, i: idx]$;
}
}";
var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.Type.Kind, Is.EqualTo(TypeKind.Dynamic));
Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Indexing));
Assert.That(rr.Target, Is.InstanceOf<ThisResolveResult>());
Assert.That(rr.Arguments.Count, Is.EqualTo(2));
Assert.That(rr.Arguments[0].Name, Is.EqualTo("a"));
Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "obj");
Assert.That(rr.Arguments[1].Name, Is.EqualTo("i"));
Assert.That(rr.Arguments[1].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[1].Value).Variable.Name == "idx");
}
[Test]
public void ConstructingObjectWithDynamicArgumentWithOneApplicableConstructor() {
string program = @"using System;
class TestClass {
public TestClass(int a) {}
public void TestClass(int a, string b) {}
void F() {
dynamic obj = null;
var x = $new TestClass(obj)$;
}
}";
var rr = Resolve<CSharpInvocationResolveResult>(program);
Assert.That(rr.Member.Name, Is.EqualTo(".ctor"));
Assert.That(rr.TargetResult, Is.Null);
Assert.That(((IParameterizedMember)rr.Member).Parameters.Count, Is.EqualTo(1));
Assert.That(rr.Arguments.Count, Is.EqualTo(1));
var cr = rr.Arguments[0] as ConversionResolveResult;
Assert.That(cr, Is.Not.Null);
Assert.That(cr.Input is LocalResolveResult && ((LocalResolveResult)cr.Input).Variable.Name == "obj");
}
[Test]
public void ConstructingObjectWithDynamicArgumentWithTwoApplicableConstructors() {
string program = @"using System;
class TestClass {
public TestClass(int a, int b) {}
public TestClass(string a, int b) {}
public void TestClass(int a, string b) {}
void F() {
dynamic obj = null;
int i = 0;
var x = $new TestClass(obj, i)$;
}
}";
var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.ObjectCreation));
var mg = rr.Target as MethodGroupResolveResult;
Assert.That(mg, Is.Not.Null, "Expected a MethodGroup");
Assert.That(mg.TargetResult, Is.Null);
Assert.That(mg.MethodName, Is.EqualTo(".ctor"));
Assert.That(mg.Methods.All(m => m.Parameters.Count == 2 && m.Parameters[1].Type.Name == "Int32"));
Assert.That(mg.Methods.Select(m => m.Parameters[0].Type.Name), Is.EquivalentTo(new[] { "Int32", "String" }));
Assert.That(mg.Methods.All(m => m.Name == ".ctor" && m.DeclaringType.Name == "TestClass"));
Assert.That(rr.Arguments.Count, Is.EqualTo(2));
Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "obj");
Assert.That(rr.Arguments[1].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[1].Value).Variable.Name == "i");
}
[Test]
public void ConstructingObjectWithDynamicArgumentWithTwoApplicableConstructorsAndNamedArguments() {
string program = @"using System;
class TestClass {
public TestClass(int arg1, int arg2) {}
public TestClass(string arg1, int arg2) {}
public void TestClass(int a) {}
void F() {
dynamic obj = null;
int i = 0;
var x = $new TestClass(arg1: obj, arg2: i)$;
}
}";
var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.ObjectCreation));
var mg = rr.Target as MethodGroupResolveResult;
Assert.That(mg, Is.Not.Null, "Expected a MethodGroup");
Assert.That(mg.TargetResult, Is.Null);
Assert.That(mg.MethodName, Is.EqualTo(".ctor"));
Assert.That(mg.Methods.All(m => m.Parameters.Count == 2 && m.Parameters[1].Type.Name == "Int32"));
Assert.That(mg.Methods.Select(m => m.Parameters[0].Type.Name), Is.EquivalentTo(new[] { "Int32", "String" }));
Assert.That(mg.Methods.All(m => m.Name == ".ctor" && m.DeclaringType.Name == "TestClass"));
Assert.That(rr.Arguments.Count, Is.EqualTo(2));
Assert.That(rr.Arguments[0].Name, Is.EqualTo("arg1"));
Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "obj");
Assert.That(rr.Arguments[1].Name, Is.EqualTo("arg2"));
Assert.That(rr.Arguments[1].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[1].Value).Variable.Name == "i");
}
[Test]
public void ConstructingObjectWithDynamicArgumentWithTwoApplicableConstructorsAndInitializerStatements() {
string program = @"using System;
class TestClass {
public TestClass(int a, int b) {}
public TestClass(string a, int b) {}
public int A { get; set; }
void F() {
dynamic obj = null;
int i = 0;
int j = 0;
var x = $new TestClass(obj, i) { A = j }$;
}
}";
var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.ObjectCreation));
Assert.That(rr.InitializerStatements.Count, Is.EqualTo(1));
var or = rr.InitializerStatements[0] as OperatorResolveResult;
Assert.That(or, Is.Not.Null);
Assert.That(or.OperatorType, Is.EqualTo(ExpressionType.Assign));
var mrr = or.Operands[0] as MemberResolveResult;
Assert.That(mrr, Is.Not.Null);
Assert.That(mrr.TargetResult, Is.InstanceOf<InitializedObjectResolveResult>());
Assert.That(mrr.Member.Name, Is.EqualTo("A"));
Assert.That(or.Operands[1], Is.InstanceOf<LocalResolveResult>());
Assert.That(((LocalResolveResult)or.Operands[1]).Variable.Name, Is.EqualTo("j"));
}
[Test]
public void InitializingBaseWithDynamicArgumentAndOneApplicableConstructor() {
string program = @"using System;
class TestBase {
public TestBase(int a, int b) {}
public TestBase(string a) {}
}
class TestClass : TestBase {
private static dynamic d;
private static int i;
public TestClass() : $base(d, i)$ {}
}";
var rr = Resolve<CSharpInvocationResolveResult>(program);
Assert.That(rr.Member.Name, Is.EqualTo(".ctor"));
Assert.That(rr.TargetResult, Is.Null);
Assert.That(((IParameterizedMember)rr.Member).Parameters.Count, Is.EqualTo(2));
Assert.That(rr.Arguments.Count, Is.EqualTo(2));
Assert.That(rr.Member.DeclaringType.Name, Is.EqualTo("TestBase"));
var cr = rr.Arguments[0] as ConversionResolveResult;
Assert.That(cr, Is.Not.Null);
Assert.That(cr.Input is MemberResolveResult && ((MemberResolveResult)cr.Input).Member.Name == "d");
Assert.That(rr.Arguments[1] is MemberResolveResult && ((MemberResolveResult)rr.Arguments[1]).Member.Name == "i");
}
[Test]
public void InitializingBaseWithDynamicArgumentAndTwoApplicableConstructors() {
string program = @"using System;
class TestBase {
public TestBase(int a, int b) {}
public TestBase(string a, int b) {}
public TestBase(string a) {}
}
class TestClass : TestBase {
private static dynamic d;
private static int i;
public TestClass() : $base(d, i)$ {}
}";
var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.ObjectCreation));
var mg = rr.Target as MethodGroupResolveResult;
Assert.That(mg, Is.Not.Null, "Expected a MethodGroup");
Assert.That(mg.TargetResult, Is.Null);
Assert.That(mg.MethodName, Is.EqualTo(".ctor"));
Assert.That(mg.Methods.All(m => m.Parameters.Count == 2 && m.Parameters[1].Type.Name == "Int32"));
Assert.That(mg.Methods.Select(m => m.Parameters[0].Type.Name), Is.EquivalentTo(new[] { "Int32", "String" }));
Assert.That(mg.Methods.All(m => m.Name == ".ctor" && m.DeclaringType.Name == "TestBase"));
Assert.That(rr.Arguments.Count, Is.EqualTo(2));
Assert.That(rr.Arguments[0].Value is MemberResolveResult && ((MemberResolveResult)rr.Arguments[0].Value).Member.Name == "d");
Assert.That(rr.Arguments[1].Value is MemberResolveResult && ((MemberResolveResult)rr.Arguments[1].Value).Member.Name == "i");
}
[Test]
public void ConstructorChainingWithDynamicArgumentAndOneApplicableConstructor() {
string program = @"using System;
class TestClass {
private static dynamic d;
private static int i;
public TestClass(int a, int b) {}
public TestClass(string a) {}
public TestClass() : $this(d, i)$ {}
}";
var rr = Resolve<CSharpInvocationResolveResult>(program);
Assert.That(rr.Member.Name, Is.EqualTo(".ctor"));
Assert.That(rr.TargetResult, Is.Null);
Assert.That(((IParameterizedMember)rr.Member).Parameters.Count, Is.EqualTo(2));
Assert.That(rr.Arguments.Count, Is.EqualTo(2));
Assert.That(rr.Member.DeclaringType.Name, Is.EqualTo("TestClass"));
var cr = rr.Arguments[0] as ConversionResolveResult;
Assert.That(cr, Is.Not.Null);
Assert.That(cr.Input is MemberResolveResult && ((MemberResolveResult)cr.Input).Member.Name == "d");
Assert.That(rr.Arguments[1] is MemberResolveResult && ((MemberResolveResult)rr.Arguments[1]).Member.Name == "i");
}
[Test]
public void ConstructorChainingWithDynamicArgumentAndTwoApplicableConstructors() {
string program = @"using System;
class TestBase {
}
class TestClass {
private static dynamic d;
private static int i;
public TestClass(int a, int b) {}
public TestClass(string a, int b) {}
public TestClass(string a) {}
public TestClass() : $this(d, i)$ {}
}";
var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.ObjectCreation));
var mg = rr.Target as MethodGroupResolveResult;
Assert.That(mg, Is.Not.Null, "Expected a MethodGroup");
Assert.That(mg.TargetResult, Is.Null);
Assert.That(mg.MethodName, Is.EqualTo(".ctor"));
Assert.That(mg.Methods.All(m => m.Parameters.Count == 2 && m.Parameters[1].Type.Name == "Int32"));
Assert.That(mg.Methods.Select(m => m.Parameters[0].Type.Name), Is.EquivalentTo(new[] { "Int32", "String" }));
Assert.That(mg.Methods.All(m => m.Name == ".ctor" && m.DeclaringType.Name == "TestClass"));
Assert.That(rr.Arguments.Count, Is.EqualTo(2));
Assert.That(rr.Arguments[0].Value is MemberResolveResult && ((MemberResolveResult)rr.Arguments[0].Value).Member.Name == "d");
Assert.That(rr.Arguments[1].Value is MemberResolveResult && ((MemberResolveResult)rr.Arguments[1].Value).Member.Name == "i");
}
}
}

Loading…
Cancel
Save