Browse Source

When invoking a method with dynamic arguments (and there is only one applicable method), convert the result of the call to 'dynamic' (http://blogs.msdn.com/b/ericlippert/archive/2012/10/22/a-method-group-of-one.aspx)

newNRvisualizers
Erik Källén 14 years ago
parent
commit
7b1530e814
  1. 21
      ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs
  2. 47
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/DynamicTests.cs

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

@ -1948,6 +1948,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1948,6 +1948,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
MethodGroupResolveResult mgrr = target as MethodGroupResolveResult;
Func<ResolveResult, ResolveResult> convert = x => x;
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.
@ -1969,41 +1970,43 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1969,41 +1970,43 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
return new DynamicInvocationResolveResult(new MethodGroupResolveResult(actualTarget, mgrr.MethodName, l, mgrr.TypeArguments), DynamicInvocationType.Invocation, AddArgumentNamesIfNecessary(arguments, argumentNames));
}
else {
convert = x => x.Type.Kind == TypeKind.Dynamic ? x : Convert(x, SpecialType.Dynamic);
}
}
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))
return or.CreateResolveResult(new TypeResolveResult(mgrr.TargetType));
return convert(or.CreateResolveResult(new TypeResolveResult(mgrr.TargetType)));
else
return or.CreateResolveResult(mgrr.TargetResult);
return convert(or.CreateResolveResult(mgrr.TargetResult));
} else {
// No candidate found at all (not even an inapplicable one).
// This can happen with empty method groups (as sometimes used with extension methods)
return new UnknownMethodResolveResult(
mgrr.TargetType, mgrr.MethodName, mgrr.TypeArguments, CreateParameters(arguments, argumentNames));
return convert(new UnknownMethodResolveResult(mgrr.TargetType, mgrr.MethodName, mgrr.TypeArguments, CreateParameters(arguments, argumentNames)));
}
}
UnknownMemberResolveResult umrr = target as UnknownMemberResolveResult;
if (umrr != null) {
return new UnknownMethodResolveResult(umrr.TargetType, umrr.MemberName, umrr.TypeArguments, CreateParameters(arguments, argumentNames));
return convert(new UnknownMethodResolveResult(umrr.TargetType, umrr.MemberName, umrr.TypeArguments, CreateParameters(arguments, argumentNames)));
}
UnknownIdentifierResolveResult uirr = target as UnknownIdentifierResolveResult;
if (uirr != null && CurrentTypeDefinition != null) {
return new UnknownMethodResolveResult(CurrentTypeDefinition, uirr.Identifier, EmptyList<IType>.Instance, CreateParameters(arguments, argumentNames));
return convert(new UnknownMethodResolveResult(CurrentTypeDefinition, uirr.Identifier, EmptyList<IType>.Instance, CreateParameters(arguments, argumentNames)));
}
IMethod invokeMethod = target.Type.GetDelegateInvokeMethod();
if (invokeMethod != null) {
OverloadResolution or = CreateOverloadResolution(arguments, argumentNames);
or.AddCandidate(invokeMethod);
return new CSharpInvocationResolveResult(
return convert(new CSharpInvocationResolveResult(
target, invokeMethod, //invokeMethod.ReturnType.Resolve(context),
or.GetArgumentsWithConversionsAndNames(), or.BestCandidateErrors,
isExpandedForm: or.BestCandidateIsExpandedForm,
isDelegateInvocation: true,
argumentToParameterMap: or.GetArgumentToParameterMap());
argumentToParameterMap: or.GetArgumentToParameterMap()));
}
return ErrorResult;
return convert(ErrorResult);
}
List<IParameter> CreateParameters(ResolveResult[] arguments, string[] argumentNames)

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

@ -109,20 +109,50 @@ class TestClass { @@ -109,20 +109,50 @@ class TestClass {
[Test]
public void InvocationWithDynamicArgumentWithOneApplicableMethod() {
string program = @"using System;
class TestClass {
public int SomeMethod(int a) {}
public int SomeMethod(int a, string b) {}
void F() {
dynamic obj = null;
var x = $this.SomeMethod(obj)$;
}
}";
var rr = Resolve<ConversionResolveResult>(program);
Assert.That(rr.IsError, Is.False);
Assert.That(rr.Type.Kind, Is.EqualTo(TypeKind.Dynamic));
var irr = rr.Input as CSharpInvocationResolveResult;
Assert.That(irr, Is.Not.Null);
Assert.That(irr.Member.Name, Is.EqualTo("SomeMethod"));
Assert.That(((IParameterizedMember)irr.Member).Parameters.Count, Is.EqualTo(1));
Assert.That(irr.Arguments.Count, Is.EqualTo(1));
var cr = irr.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 InvocationWithDynamicArgumentWithOneApplicableMethodReturningVoid() {
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;
var rr = Resolve<ConversionResolveResult>(program);
Assert.That(rr.IsError, Is.False);
Assert.That(rr.Type.Kind, Is.EqualTo(TypeKind.Dynamic));
var irr = rr.Input as CSharpInvocationResolveResult;
Assert.That(irr, Is.Not.Null);
Assert.That(irr.Member.Name, Is.EqualTo("SomeMethod"));
Assert.That(((IParameterizedMember)irr.Member).Parameters.Count, Is.EqualTo(1));
Assert.That(irr.Arguments.Count, Is.EqualTo(1));
var cr = irr.Arguments[0] as ConversionResolveResult;
Assert.That(cr, Is.Not.Null);
Assert.That(cr.Conversion.IsImplicit, Is.True);
Assert.That(cr.Conversion.IsDynamicConversion, Is.True);
@ -286,8 +316,9 @@ class TestClass { @@ -286,8 +316,9 @@ class TestClass {
var x = $this.SomeMethod(obj)$;
}
}";
var rr = Resolve(program);
Assert.That(rr.IsError, Is.True);
var rr = Resolve<ConversionResolveResult>(program);
var irr = rr.Input;
Assert.That(irr.IsError, Is.True);
}
[Test]

Loading…
Cancel
Save