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
bool isExpandedForm = false, bool isExpandedForm = false,
bool isDelegateInvocation = false, bool isDelegateInvocation = false,
IList<int> argumentToParameterMap = null, 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.OverloadResolutionErrors = overloadResolutionErrors;
this.IsExtensionMethodInvocation = isExtensionMethodInvocation; this.IsExtensionMethodInvocation = isExtensionMethodInvocation;

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

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

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

@ -933,8 +933,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// <param name="initializerStatements"> /// <param name="initializerStatements">
/// Statements for Objects/Collections initializer. /// Statements for Objects/Collections initializer.
/// <see cref="InvocationResolveResult.InitializerStatements"/> /// <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> /// </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(); IParameterizedMember member = GetBestCandidateWithSubstitutedTypeArguments();
if (member == null) if (member == null)
@ -949,7 +952,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
this.BestCandidateIsExpandedForm, this.BestCandidateIsExpandedForm,
isDelegateInvocation: false, isDelegateInvocation: false,
argumentToParameterMap: this.GetArgumentToParameterMap(), argumentToParameterMap: this.GetArgumentToParameterMap(),
initializerStatements: initializerStatements); initializerStatements: initializerStatements,
returnTypeOverride: returnTypeOverride);
} }
#endregion #endregion
} }

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

@ -110,8 +110,8 @@ class TestClass {
public void InvocationWithDynamicArgumentWithOneApplicableMethod() { public void InvocationWithDynamicArgumentWithOneApplicableMethod() {
string program = @"using System; string program = @"using System;
class TestClass { class TestClass {
public void SomeMethod(int a) {} public int SomeMethod(int a) {}
public void SomeMethod(int a, string b) {} public int SomeMethod(int a, string b) {}
void F() { void F() {
dynamic obj = null; dynamic obj = null;
@ -119,7 +119,9 @@ class TestClass {
} }
}"; }";
var rr = Resolve<CSharpInvocationResolveResult>(program); var rr = Resolve<CSharpInvocationResolveResult>(program);
Assert.That(rr, Is.Not.Null);
Assert.That(rr.Member.Name, Is.EqualTo("SomeMethod")); 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(((IParameterizedMember)rr.Member).Parameters.Count, Is.EqualTo(1));
Assert.That(rr.Arguments.Count, Is.EqualTo(1)); Assert.That(rr.Arguments.Count, Is.EqualTo(1));
var cr = rr.Arguments[0] as ConversionResolveResult; var cr = rr.Arguments[0] as ConversionResolveResult;
@ -129,6 +131,32 @@ class TestClass {
Assert.That(cr.Input is LocalResolveResult && ((LocalResolveResult)cr.Input).Variable.Name == "obj"); 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] [Test]
public void InvocationWithDynamicArgumentWhenBothAnOwnAndABaseMethodAreApplicable() { public void InvocationWithDynamicArgumentWhenBothAnOwnAndABaseMethodAreApplicable() {
string program = @"using System; string program = @"using System;
@ -286,7 +314,7 @@ class TestClass {
var x = $this.SomeMethod(obj)$; var x = $this.SomeMethod(obj)$;
} }
}"; }";
var rr = Resolve(program); var rr = Resolve<CSharpInvocationResolveResult>(program);
Assert.That(rr.IsError, Is.True); Assert.That(rr.IsError, Is.True);
} }

5
ICSharpCode.NRefactory/Semantics/InvocationResolveResult.cs

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

8
ICSharpCode.NRefactory/Semantics/MemberResolveResult.cs

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

Loading…
Cancel
Save