diff --git a/ICSharpCode.NRefactory.CSharp/Resolver/CSharpConversions.cs b/ICSharpCode.NRefactory.CSharp/Resolver/CSharpConversions.cs index d75e4de3f0..8e6e92248f 100644 --- a/ICSharpCode.NRefactory.CSharp/Resolver/CSharpConversions.cs +++ b/ICSharpCode.NRefactory.CSharp/Resolver/CSharpConversions.cs @@ -921,7 +921,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver args[i] = new ResolveResult(parameterType); } } - var or = rr.PerformOverloadResolution(compilation, args, allowExpandingParams: false, conversions: this); + var or = rr.PerformOverloadResolution(compilation, args, allowExpandingParams: false, allowOptionalParameters: false, conversions: this); if (or.FoundApplicableCandidate) { IMethod method = (IMethod)or.GetBestCandidateWithSubstitutedTypeArguments(); var thisRR = rr.TargetResult as ThisResolveResult; diff --git a/ICSharpCode.NRefactory.CSharp/Resolver/MethodGroupResolveResult.cs b/ICSharpCode.NRefactory.CSharp/Resolver/MethodGroupResolveResult.cs index 39571f2918..fddfda7c5a 100644 --- a/ICSharpCode.NRefactory.CSharp/Resolver/MethodGroupResolveResult.cs +++ b/ICSharpCode.NRefactory.CSharp/Resolver/MethodGroupResolveResult.cs @@ -220,7 +220,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver return string.Format("[{0} with {1} method(s)]", GetType().Name, this.Methods.Count()); } - public OverloadResolution PerformOverloadResolution(ICompilation compilation, ResolveResult[] arguments, string[] argumentNames = null, bool allowExtensionMethods = true, bool allowExpandingParams = true, bool checkForOverflow = false, CSharpConversions conversions = null) + public OverloadResolution PerformOverloadResolution(ICompilation compilation, ResolveResult[] arguments, string[] argumentNames = null, + bool allowExtensionMethods = true, + bool allowExpandingParams = true, + bool allowOptionalParameters = true, + bool checkForOverflow = false, CSharpConversions conversions = null) { Log.WriteLine("Performing overload resolution for " + this); Log.WriteCollection(" Arguments: ", arguments); @@ -228,6 +232,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver var typeArgumentArray = this.TypeArguments.ToArray(); OverloadResolution or = new OverloadResolution(compilation, arguments, argumentNames, typeArgumentArray, conversions); or.AllowExpandingParams = allowExpandingParams; + or.AllowOptionalParameters = allowOptionalParameters; or.CheckForOverflow = checkForOverflow; or.AddMethodLists(methodLists); @@ -249,6 +254,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } var extOr = new OverloadResolution(compilation, extArguments, extArgumentNames, typeArgumentArray, conversions); extOr.AllowExpandingParams = allowExpandingParams; + extOr.AllowOptionalParameters = allowOptionalParameters; extOr.IsExtensionMethodInvocation = true; extOr.CheckForOverflow = checkForOverflow; diff --git a/ICSharpCode.NRefactory.CSharp/Resolver/OverloadResolution.cs b/ICSharpCode.NRefactory.CSharp/Resolver/OverloadResolution.cs index ce1ce09570..6c4e814f20 100644 --- a/ICSharpCode.NRefactory.CSharp/Resolver/OverloadResolution.cs +++ b/ICSharpCode.NRefactory.CSharp/Resolver/OverloadResolution.cs @@ -155,6 +155,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver this.conversions = conversions ?? CSharpConversions.Get(compilation); this.AllowExpandingParams = true; + this.AllowOptionalParameters = true; } #endregion @@ -174,6 +175,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver /// public bool AllowExpandingParams { get; set; } + /// + /// Gets/Sets whether optional parameters may be left at their default value. + /// The default value is true. + /// If this property is set to false, optional parameters will be treated like regular parameters. + /// + public bool AllowOptionalParameters { get; set; } + /// /// Gets/Sets whether ConversionResolveResults created by this OverloadResolution /// instance apply overflow checking. @@ -543,7 +551,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver if (candidate.IsExpandedForm && i == argumentCountPerParameter.Length - 1) continue; // any number of arguments is fine for the params-array if (argumentCountPerParameter[i] == 0) { - if (candidate.Parameters[i].IsOptional) + if (this.AllowOptionalParameters && candidate.Parameters[i].IsOptional) candidate.HasUnmappedOptionalParameters = true; else candidate.AddError(OverloadResolutionErrors.MissingArgumentForRequiredParameter); diff --git a/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs b/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs index 4776a5185d..d9a3438a25 100644 --- a/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs +++ b/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs @@ -1583,7 +1583,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver var addRR = memberLookup.Lookup(initializedObject, "Add", EmptyList.Instance, true); var mgrr = addRR as MethodGroupResolveResult; if (mgrr != null) { - OverloadResolution or = mgrr.PerformOverloadResolution(resolver.Compilation, addArguments, null, false, false, resolver.CheckForOverflow, resolver.conversions); + OverloadResolution or = mgrr.PerformOverloadResolution(resolver.Compilation, addArguments, null, false, false, false, resolver.CheckForOverflow, resolver.conversions); var invocationRR = or.CreateResolveResult(initializedObject); StoreResult(aie, invocationRR); ProcessInvocationResult(null, aie.Elements, invocationRR); @@ -2745,7 +2745,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } else { var getEnumeratorMethodGroup = memberLookup.Lookup(expression, "GetEnumerator", EmptyList.Instance, true) as MethodGroupResolveResult; if (getEnumeratorMethodGroup != null) { - var or = getEnumeratorMethodGroup.PerformOverloadResolution(compilation, new ResolveResult[0]); + var or = getEnumeratorMethodGroup.PerformOverloadResolution( + compilation, new ResolveResult[0], + allowExtensionMethods: false, allowExpandingParams: false, allowOptionalParameters: false); if (or.FoundApplicableCandidate && !or.IsAmbiguous && !or.BestCandidate.IsStatic && or.BestCandidate.IsPublic) { collectionType = expression.Type; getEnumeratorInvocation = or.CreateResolveResult(expression); @@ -2762,7 +2764,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver IMethod moveNextMethod = null; var moveNextMethodGroup = memberLookup.Lookup(new ResolveResult(enumeratorType), "MoveNext", EmptyList.Instance, false) as MethodGroupResolveResult; if (moveNextMethodGroup != null) { - var or = moveNextMethodGroup.PerformOverloadResolution(compilation, new ResolveResult[0]); + var or = moveNextMethodGroup.PerformOverloadResolution( + compilation, new ResolveResult[0], + allowExtensionMethods: false, allowExpandingParams: false, allowOptionalParameters: false); moveNextMethod = or.GetBestCandidateWithSubstitutedTypeArguments() as IMethod; } diff --git a/ICSharpCode.NRefactory.CSharp/Resolver/TypeInference.cs b/ICSharpCode.NRefactory.CSharp/Resolver/TypeInference.cs index e082f98d8e..6438b82856 100644 --- a/ICSharpCode.NRefactory.CSharp/Resolver/TypeInference.cs +++ b/ICSharpCode.NRefactory.CSharp/Resolver/TypeInference.cs @@ -510,7 +510,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } var or = mgrr.PerformOverloadResolution(compilation, args, - allowExpandingParams: false); + allowExpandingParams: false, allowOptionalParameters: false); if (or.FoundApplicableCandidate && or.BestCandidateAmbiguousWith == null) { IType returnType = or.GetBestCandidateWithSubstitutedTypeArguments().ReturnType; MakeLowerBoundInference(returnType, m.ReturnType); diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConversionsTest.cs b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConversionsTest.cs index 3087c1cd3a..836d9c2526 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConversionsTest.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConversionsTest.cs @@ -19,6 +19,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Linq; using ICSharpCode.NRefactory.CSharp.TypeSystem; using ICSharpCode.NRefactory.Semantics; using ICSharpCode.NRefactory.TypeSystem; @@ -782,5 +783,53 @@ class Test { //Assert.IsFrue(c.IsValid); Assert.IsTrue(c.IsMethodGroupConversion); } + + [Test] + public void MethodGroupConversion_ExactMatchIsBetter() + { + string program = @"using System; +class Test { + delegate void D(string a); + D d = $M$; + static void M(object x) {} + static void M(string x = null) {} +}"; + var c = GetConversion(program); + Assert.IsTrue(c.IsValid); + Assert.IsTrue(c.IsMethodGroupConversion); + Assert.AreEqual("System.String", c.Method.Parameters.Single().Type.FullName); + } + + [Test] + public void MethodGroupConversion_CannotLeaveOutOptionalParameters() + { + string program = @"using System; +class Test { + delegate void D(string a); + D d = $M$; + static void M(object x) {} + static void M(string x, string y = null) {} +}"; + var c = GetConversion(program); + Assert.IsTrue(c.IsValid); + Assert.IsTrue(c.IsMethodGroupConversion); + Assert.AreEqual("System.Object", c.Method.Parameters.Single().Type.FullName); + } + + [Test] + public void MethodGroupConversion_CannotUseExpandedParams() + { + string program = @"using System; +class Test { + delegate void D(string a); + D d = $M$; + static void M(object x) {} + static void M(params string[] x) {} +}"; + var c = GetConversion(program); + Assert.IsTrue(c.IsValid); + Assert.IsTrue(c.IsMethodGroupConversion); + Assert.AreEqual("System.Object", c.Method.Parameters.Single().Type.FullName); + } } }