Browse Source

Merge pull request #134 from erik-kallen/dynamic-methodgroup-of-one

Resolver reports the wrong type when a dynamic call has only one applicable method.
newNRvisualizers
Daniel Grunwald 13 years ago
parent
commit
47c78a11a7
  1. 5
      ICSharpCode.NRefactory.CSharp/Resolver/CSharpInvocationResolveResult.cs
  2. 10
      ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs
  3. 8
      ICSharpCode.NRefactory.CSharp/Resolver/OverloadResolution.cs
  4. 34
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/DynamicTests.cs
  5. 5
      ICSharpCode.NRefactory/Semantics/InvocationResolveResult.cs
  6. 8
      ICSharpCode.NRefactory/Semantics/MemberResolveResult.cs

5
ICSharpCode.NRefactory.CSharp/Resolver/CSharpInvocationResolveResult.cs

@ -57,9 +57,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -57,9 +57,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
bool isExpandedForm = false,
bool isDelegateInvocation = false,
IList<int> argumentToParameterMap = null,
IList<ResolveResult> initializerStatements = null
IList<ResolveResult> initializerStatements = null,
IType returnTypeOverride = null
)
: base(targetResult, member, arguments, initializerStatements)
: base(targetResult, member, arguments, initializerStatements, returnTypeOverride)
{
this.OverloadResolutionErrors = overloadResolutionErrors;
this.IsExtensionMethodInvocation = isExtensionMethodInvocation;

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

@ -1933,9 +1933,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1933,9 +1933,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return new DynamicInvocationResolveResult(target, DynamicInvocationType.Invocation, AddArgumentNamesIfNecessary(arguments, argumentNames));
}
bool isDynamic = arguments.Any(a => a.Type.Kind == TypeKind.Dynamic);
MethodGroupResolveResult mgrr = target as MethodGroupResolveResult;
if (mgrr != null) {
if (arguments.Any(a => a.Type.Kind == TypeKind.Dynamic)) {
if (isDynamic) {
// 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 = CreateOverloadResolution(arguments, argumentNames, mgrr.TypeArguments.ToArray());
var applicableMethods = mgrr.MethodsGroupedByDeclaringType.SelectMany(m => m, (x, m) => new { x.DeclaringType, Method = m }).Where(x => OverloadResolution.IsApplicable(or2.AddCandidate(x.Method))).ToList();
@ -1960,9 +1961,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1960,9 +1961,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
OverloadResolution or = mgrr.PerformOverloadResolution(compilation, arguments, argumentNames, checkForOverflow: checkForOverflow, conversions: conversions, allowOptionalParameters: allowOptionalParameters);
if (or.BestCandidate != null) {
if (or.BestCandidate.IsStatic && !or.IsExtensionMethodInvocation && !(mgrr.TargetResult is TypeResolveResult))
return or.CreateResolveResult(new TypeResolveResult(mgrr.TargetType));
return or.CreateResolveResult(new TypeResolveResult(mgrr.TargetType), returnTypeOverride: isDynamic ? SpecialType.Dynamic : null);
else
return or.CreateResolveResult(mgrr.TargetResult);
return or.CreateResolveResult(mgrr.TargetResult, returnTypeOverride: isDynamic ? SpecialType.Dynamic : null);
} else {
// No candidate found at all (not even an inapplicable one).
// This can happen with empty method groups (as sometimes used with extension methods)
@ -1987,7 +1988,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1987,7 +1988,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
or.GetArgumentsWithConversionsAndNames(), or.BestCandidateErrors,
isExpandedForm: or.BestCandidateIsExpandedForm,
isDelegateInvocation: true,
argumentToParameterMap: or.GetArgumentToParameterMap());
argumentToParameterMap: or.GetArgumentToParameterMap(),
returnTypeOverride: isDynamic ? SpecialType.Dynamic : null);
}
return ErrorResult;
}

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

@ -933,8 +933,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -933,8 +933,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// <param name="initializerStatements">
/// Statements for Objects/Collections initializer.
/// <see cref="InvocationResolveResult.InitializerStatements"/>
/// <param name="returnTypeOverride">
/// If not null, use this instead of the ReturnType of the member as the type of the created resolve result.
/// </param>
public CSharpInvocationResolveResult CreateResolveResult(ResolveResult targetResolveResult, IList<ResolveResult> initializerStatements = null)
/// </param>
public CSharpInvocationResolveResult CreateResolveResult(ResolveResult targetResolveResult, IList<ResolveResult> initializerStatements = null, IType returnTypeOverride = null)
{
IParameterizedMember member = GetBestCandidateWithSubstitutedTypeArguments();
if (member == null)
@ -949,7 +952,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -949,7 +952,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
this.BestCandidateIsExpandedForm,
isDelegateInvocation: false,
argumentToParameterMap: this.GetArgumentToParameterMap(),
initializerStatements: initializerStatements);
initializerStatements: initializerStatements,
returnTypeOverride: returnTypeOverride);
}
#endregion
}

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

@ -110,8 +110,8 @@ class TestClass { @@ -110,8 +110,8 @@ class TestClass {
public void InvocationWithDynamicArgumentWithOneApplicableMethod() {
string program = @"using System;
class TestClass {
public void SomeMethod(int a) {}
public void SomeMethod(int a, string b) {}
public int SomeMethod(int a) {}
public int SomeMethod(int a, string b) {}
void F() {
dynamic obj = null;
@ -119,7 +119,9 @@ class TestClass { @@ -119,7 +119,9 @@ class TestClass {
}
}";
var rr = Resolve<CSharpInvocationResolveResult>(program);
Assert.That(rr, Is.Not.Null);
Assert.That(rr.Member.Name, Is.EqualTo("SomeMethod"));
Assert.That(rr.Type.Kind == TypeKind.Dynamic);
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;
@ -129,6 +131,32 @@ class TestClass { @@ -129,6 +131,32 @@ class TestClass {
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) {}
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 InvocationWithDynamicArgumentWhenBothAnOwnAndABaseMethodAreApplicable() {
string program = @"using System;
@ -286,7 +314,7 @@ class TestClass { @@ -286,7 +314,7 @@ class TestClass {
var x = $this.SomeMethod(obj)$;
}
}";
var rr = Resolve(program);
var rr = Resolve<CSharpInvocationResolveResult>(program);
Assert.That(rr.IsError, Is.True);
}

5
ICSharpCode.NRefactory/Semantics/InvocationResolveResult.cs

@ -45,8 +45,9 @@ namespace ICSharpCode.NRefactory.Semantics @@ -45,8 +45,9 @@ namespace ICSharpCode.NRefactory.Semantics
public InvocationResolveResult(ResolveResult targetResult, IParameterizedMember member,
IList<ResolveResult> arguments = null,
IList<ResolveResult> initializerStatements = null)
: base(targetResult, member)
IList<ResolveResult> initializerStatements = null,
IType returnTypeOverride = null)
: base(targetResult, member, returnTypeOverride)
{
this.Arguments = arguments ?? EmptyList<ResolveResult>.Instance;
this.InitializerStatements = initializerStatements ?? EmptyList<ResolveResult>.Instance;

8
ICSharpCode.NRefactory/Semantics/MemberResolveResult.cs

@ -38,8 +38,8 @@ namespace ICSharpCode.NRefactory.Semantics @@ -38,8 +38,8 @@ namespace ICSharpCode.NRefactory.Semantics
readonly ResolveResult targetResult;
readonly bool isVirtualCall;
public MemberResolveResult(ResolveResult targetResult, IMember member)
: base(member.EntityType == EntityType.Constructor ? member.DeclaringType : member.ReturnType)
public MemberResolveResult(ResolveResult targetResult, IMember member, IType returnTypeOverride = null)
: base(returnTypeOverride ?? (member.EntityType == EntityType.Constructor ? member.DeclaringType : member.ReturnType))
{
this.targetResult = targetResult;
this.member = member;
@ -54,8 +54,8 @@ namespace ICSharpCode.NRefactory.Semantics @@ -54,8 +54,8 @@ namespace ICSharpCode.NRefactory.Semantics
}
}
public MemberResolveResult(ResolveResult targetResult, IMember member, bool isVirtualCall)
: base(member.EntityType == EntityType.Constructor ? member.DeclaringType : member.ReturnType)
public MemberResolveResult(ResolveResult targetResult, IMember member, bool isVirtualCall, IType returnTypeOverride = null)
: base(returnTypeOverride ?? (member.EntityType == EntityType.Constructor ? member.DeclaringType : member.ReturnType))
{
this.targetResult = targetResult;
this.member = member;

Loading…
Cancel
Save