From 082a93abed659b97bdf00f1c6c549f6d58dfd2e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrej=20=C4=8Ci=C5=BEm=C3=A1rik?= Date: Thu, 24 Jun 2021 17:36:28 +0200 Subject: [PATCH 1/3] Fixed issue with generating expression for extension methods with default parameter values --- .../Binding/CustomExtensionMethodTests.cs | 31 +++++++++++++++++++ .../Binding/MemberExpressionFactory.cs | 2 +- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/DotVVM.Framework.Tests/Binding/CustomExtensionMethodTests.cs b/src/DotVVM.Framework.Tests/Binding/CustomExtensionMethodTests.cs index 4819cf85be..54067dfc02 100644 --- a/src/DotVVM.Framework.Tests/Binding/CustomExtensionMethodTests.cs +++ b/src/DotVVM.Framework.Tests/Binding/CustomExtensionMethodTests.cs @@ -88,12 +88,43 @@ public void Call_NotImportedExtensionMethodThrows() // Not imported extension CreateCall(notImportedTarget, Array.Empty(), new[] { new NamespaceImport("DotVVM.Framework.Tests.Binding") }); } + + [TestMethod] + public void Call_ExtensionMethodsWithOptionalArguments_UseDefaultValue() + { + var importedTarget = new MethodGroupExpression() { + MethodName = nameof(TestExtensions.ExtensionMethodWithOptionalArgument), + Target = Expression.Constant(11) + }; + + // Imported extension + var expression = CreateCall(importedTarget, Array.Empty(), new[] { new NamespaceImport("DotVVM.Framework.Tests.Binding") }); + var result = Expression.Lambda>(expression).Compile().Invoke(); + Assert.AreEqual(321, result); + } + + [TestMethod] + public void Call_ExtensionMethodsWithOptionalArguments_OverrideDefaultValue() + { + var importedTarget = new MethodGroupExpression() { + MethodName = nameof(TestExtensions.ExtensionMethodWithOptionalArgument), + Target = Expression.Constant(11) + }; + + // Imported extension + var expression = CreateCall(importedTarget, new[] { Expression.Constant(123) }, new[] { new NamespaceImport("DotVVM.Framework.Tests.Binding") }); + var result = Expression.Lambda>(expression).Compile().Invoke(); + Assert.AreEqual(123, result); + } } public static class TestExtensions { public static int Increment(this int number) => ++number; + + public static int ExtensionMethodWithOptionalArgument(this int number, int arg = 321) + => arg; } namespace AmbiguousExtensions diff --git a/src/DotVVM.Framework/Compilation/Binding/MemberExpressionFactory.cs b/src/DotVVM.Framework/Compilation/Binding/MemberExpressionFactory.cs index 430c6126f5..45e2de2e54 100644 --- a/src/DotVVM.Framework/Compilation/Binding/MemberExpressionFactory.cs +++ b/src/DotVVM.Framework/Compilation/Binding/MemberExpressionFactory.cs @@ -192,7 +192,7 @@ public Expression CallMethod(Expression target, BindingFlags flags, string name, if (method.IsExtension) { // Change to a static call - var newArguments = new[] { target }.Concat(arguments); + var newArguments = new[] { method.Arguments.First() }.Concat(method.Arguments.Skip(1)); return Expression.Call(method.Method, newArguments); } return Expression.Call(target, method.Method, method.Arguments); From ecc7c32fbf035f14d1f862bd54b7cf9d25e45595 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrej=20=C4=8Ci=C5=BEm=C3=A1rik?= Date: Thu, 24 Jun 2021 17:55:01 +0200 Subject: [PATCH 2/3] Fixed issue with duplicit @import directive when resolving extension methods --- .../Binding/CustomExtensionMethodTests.cs | 20 ++++++++++++++++++- .../Binding/MemberExpressionFactory.cs | 4 ++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/DotVVM.Framework.Tests/Binding/CustomExtensionMethodTests.cs b/src/DotVVM.Framework.Tests/Binding/CustomExtensionMethodTests.cs index 54067dfc02..e8041eb72e 100644 --- a/src/DotVVM.Framework.Tests/Binding/CustomExtensionMethodTests.cs +++ b/src/DotVVM.Framework.Tests/Binding/CustomExtensionMethodTests.cs @@ -98,7 +98,7 @@ public void Call_ExtensionMethodsWithOptionalArguments_UseDefaultValue() }; // Imported extension - var expression = CreateCall(importedTarget, Array.Empty(), new[] { new NamespaceImport("DotVVM.Framework.Tests.Binding") }); + var expression = CreateCall(importedTarget, Array.Empty(), new[] { new NamespaceImport("DotVVM.Framework.Tests.Binding"), new NamespaceImport("DotVVM.Framework.Tests.Binding") }); var result = Expression.Lambda>(expression).Compile().Invoke(); Assert.AreEqual(321, result); } @@ -116,6 +116,24 @@ public void Call_ExtensionMethodsWithOptionalArguments_OverrideDefaultValue() var result = Expression.Lambda>(expression).Compile().Invoke(); Assert.AreEqual(123, result); } + + [TestMethod] + public void Call_ExtensionMethods_DuplicitImport_DoesNotThrow() + { + var importedTarget = new MethodGroupExpression() { + MethodName = nameof(TestExtensions.Increment), + Target = Expression.Constant(11) + }; + + // Imported extension + var expression = CreateCall(importedTarget, Array.Empty(), + new[] { + new NamespaceImport("DotVVM.Framework.Tests.Binding"), + new NamespaceImport("DotVVM.Framework.Tests.Binding") + }); + var result = Expression.Lambda>(expression).Compile().Invoke(); + Assert.AreEqual(12, result); + } } public static class TestExtensions diff --git a/src/DotVVM.Framework/Compilation/Binding/MemberExpressionFactory.cs b/src/DotVVM.Framework/Compilation/Binding/MemberExpressionFactory.cs index 45e2de2e54..411272b30a 100644 --- a/src/DotVVM.Framework/Compilation/Binding/MemberExpressionFactory.cs +++ b/src/DotVVM.Framework/Compilation/Binding/MemberExpressionFactory.cs @@ -248,8 +248,8 @@ private MethodRecognitionResult FindValidMethodOveloads(Expression target, Type private IEnumerable GetAllExtensionMethods() { - foreach (var ns in importedNamespaces) - foreach (var method in extensionMethodsCache.GetExtensionsForNamespace(ns.Namespace)) + foreach (var ns in importedNamespaces.Select(ns => ns.Namespace).Distinct()) + foreach (var method in extensionMethodsCache.GetExtensionsForNamespace(ns)) yield return method; } From 52e53d63c74ac495437e53d5aac585eb883d8929 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrej=20=C4=8Ci=C5=BEm=C3=A1rik?= Date: Mon, 28 Jun 2021 13:05:23 +0200 Subject: [PATCH 3/3] Refactored changes --- .../Compilation/Binding/MemberExpressionFactory.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/DotVVM.Framework/Compilation/Binding/MemberExpressionFactory.cs b/src/DotVVM.Framework/Compilation/Binding/MemberExpressionFactory.cs index 411272b30a..149ab6741b 100644 --- a/src/DotVVM.Framework/Compilation/Binding/MemberExpressionFactory.cs +++ b/src/DotVVM.Framework/Compilation/Binding/MemberExpressionFactory.cs @@ -192,8 +192,7 @@ public Expression CallMethod(Expression target, BindingFlags flags, string name, if (method.IsExtension) { // Change to a static call - var newArguments = new[] { method.Arguments.First() }.Concat(method.Arguments.Skip(1)); - return Expression.Call(method.Method, newArguments); + return Expression.Call(method.Method, method.Arguments); } return Expression.Call(target, method.Method, method.Arguments); }