Browse Source

Add tests for full-fidelity method->delegate conversion in compiled bindings.

pull/7246/head
Jeremy Koritzinsky 4 years ago
parent
commit
0576baf5b7
No known key found for this signature in database GPG Key ID: 25A7D1C8126B7A16
  1. 2
      src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
  2. 2
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguageParseIntrinsics.cs
  3. 2
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSelectorTransformer.cs
  4. 17
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlBindingPathHelper.cs
  5. 2
      src/Markup/Avalonia.Markup.Xaml.Loader/xamlil.github
  6. 43
      tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs

2
src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs

@ -255,6 +255,8 @@ namespace Avalonia.Build.Tasks
true),
(closureName, closureBaseType) =>
populateBuilder.DefineSubType(closureBaseType, closureName, false),
(closureName, returnType, parameterTypes) =>
populateBuilder.CreateDelegateSubType(closureName, false, returnType, parameterTypes),
res.Uri, res
);

2
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguageParseIntrinsics.cs

@ -201,7 +201,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
if (type.Equals(types.Classes))
{
var classes = text.Split(' ');
var classNodes = classes.Select(c => new XamlAstTextNode(node, c, types.XamlIlTypes.String)).ToArray();
var classNodes = classes.Select(c => new XamlAstTextNode(node, c, type: types.XamlIlTypes.String)).ToArray();
result = new AvaloniaXamlIlAvaloniaListConstantAstNode(node, types, types.Classes, types.XamlIlTypes.String, classNodes);
return true;

2
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSelectorTransformer.cs

@ -76,7 +76,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
throw new XamlParseException($"Cannot find '{property.Property}' on '{type}", node);
if (!XamlTransformHelpers.TryGetCorrectlyTypedValue(context,
new XamlAstTextNode(node, property.Value, context.Configuration.WellKnownTypes.String),
new XamlAstTextNode(node, property.Value, type: context.Configuration.WellKnownTypes.String),
targetProperty.PropertyType, out var typedValue))
throw new XamlParseException(
$"Cannot convert '{property.Value}' to '{targetProperty.PropertyType.GetFqn()}",

17
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlBindingPathHelper.cs

@ -556,26 +556,33 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
public void Emit(XamlIlEmitContext context, IXamlILEmitter codeGen)
{
IXamlTypeBuilder<IXamlILEmitter> newDelegateTypeBuilder = null;
IXamlType specificDelegateType;
if (_method.ReturnType == context.Configuration.WellKnownTypes.Void && _method.Parameters.Count <= 8)
if (_method.ReturnType == context.Configuration.WellKnownTypes.Void && _method.Parameters.Count == 0)
{
specificDelegateType = context.Configuration.TypeSystem
.GetType("System.Action");
}
else if (_method.ReturnType == context.Configuration.WellKnownTypes.Void && _method.Parameters.Count <= 16)
{
specificDelegateType = context.Configuration.TypeSystem
.GetType($"System.Action`{_method.Parameters.Count}")
.MakeGenericType(_method.Parameters);
}
else if (_method.Parameters.Count <= 7)
else if (_method.Parameters.Count <= 16)
{
List<IXamlType> genericParameters = new();
genericParameters.AddRange(_method.Parameters);
genericParameters.Add(_method.ReturnType);
specificDelegateType = context.Configuration.TypeSystem
.GetType($"System.Func`{_method.Parameters.Count}")
.GetType($"System.Func`{_method.Parameters.Count + 1}")
.MakeGenericType(genericParameters);
}
else
{
// In this case, we need to emit our own delegate type.
specificDelegateType = null;
string delegateTypeName = context.Configuration.IdentifierGenerator.GenerateIdentifierPart();
specificDelegateType = newDelegateTypeBuilder = context.DefineDelegateSubType(delegateTypeName, _method.ReturnType, _method.Parameters);
}
codeGen
@ -583,6 +590,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
.Ldtoken(specificDelegateType)
.EmitCall(context.GetAvaloniaTypes()
.CompiledBindingPathBuilder.FindMethod(m => m.Name == "Method"));
newDelegateTypeBuilder?.CreateType();
}
}

2
src/Markup/Avalonia.Markup.Xaml.Loader/xamlil.github

@ -1 +1 @@
Subproject commit 8e20d65eb5f1efbae08e49b18f39bfdce32df7b3
Subproject commit daaac590e078967b78045f74c38ef046d00d8582

43
tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs

@ -1042,6 +1042,37 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
}
}
[Fact]
public void SupportsMethodBindingAsDelegate()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
<Window xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
x:DataType='local:MethodDataContext'>
<StackPanel>
<ContentControl Content='{CompiledBinding Action}' Name='action' />
<ContentControl Content='{CompiledBinding Func}' Name='func' />
<ContentControl Content='{CompiledBinding Action16}' Name='action16' />
<ContentControl Content='{CompiledBinding Func16}' Name='func16' />
<ContentControl Content='{CompiledBinding CustomDelegateTypeVoid}' Name='customvoid' />
<ContentControl Content='{CompiledBinding CustomDelegateTypeInt}' Name='customint' />
</StackPanel>
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
window.DataContext = new MethodDataContext();
Assert.IsAssignableFrom(typeof(Action), window.FindControl<ContentControl>("action").Content);
Assert.IsAssignableFrom(typeof(Func<int>), window.FindControl<ContentControl>("func").Content);
Assert.IsAssignableFrom(typeof(Action<int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int>), window.FindControl<ContentControl>("action16").Content);
Assert.IsAssignableFrom(typeof(Func<int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int>), window.FindControl<ContentControl>("func16").Content);
Assert.True(typeof(Delegate).IsAssignableFrom(window.FindControl<ContentControl>("customvoid").Content.GetType()));
Assert.True(typeof(Delegate).IsAssignableFrom(window.FindControl<ContentControl>("customint").Content.GetType()));
}
}
void Throws(string type, Action cb)
{
try
@ -1131,4 +1162,16 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
}
}
}
public class MethodDataContext
{
public void Action() { }
public int Func() => 1;
public void Action16(int i, int i2, int i3, int i4, int i5, int i6, int i7, int i8, int i9, int i10, int i11, int i12, int i13, int i14, int i15, int i16) { }
public int Func16(int i, int i2, int i3, int i4, int i5, int i6, int i7, int i8, int i9, int i10, int i11, int i12, int i13, int i14, int i15, int i16) => i;
public void CustomDelegateTypeVoid(int i, int i2, int i3, int i4, int i5, int i6, int i7, int i8, int i9, int i10, int i11, int i12, int i13, int i14, int i15, int i16, int i17) { }
public int CustomDelegateTypeInt(int i, int i2, int i3, int i4, int i5, int i6, int i7, int i8, int i9, int i10, int i11, int i12, int i13, int i14, int i15, int i16, int i17) => i;
}
}

Loading…
Cancel
Save