From 493128651fdefdd8b26b589c355f60ea7544f352 Mon Sep 17 00:00:00 2001 From: Luis von der Eltz Date: Fri, 22 Jul 2022 13:24:48 +0200 Subject: [PATCH 1/9] Add x:SetterTargetType --- .../AvaloniaXamlIlSetterTransformer.cs | 55 +++++++++++++++++-- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs index 6da95be1c1..d6251badd5 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Linq; +using XamlX; using XamlX.Ast; using XamlX.Emit; using XamlX.IL; @@ -17,10 +18,55 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers && on.Type.GetClrType().FullName == "Avalonia.Styling.Setter")) return node; - var targetTypeNode = context.ParentNodes() + IXamlType targetType = null; + IXamlLineInfo lineInfo = null; + + var styleParent = context.ParentNodes() .OfType() - .FirstOrDefault(x => x.ScopeType == AvaloniaXamlIlTargetTypeMetadataNode.ScopeTypes.Style) ?? - throw new XamlParseException("Can not find parent Style Selector or ControlTemplate TargetType", node); + .FirstOrDefault(x => x.ScopeType == AvaloniaXamlIlTargetTypeMetadataNode.ScopeTypes.Style); + + if (styleParent != null) + { + var selectorProperty = styleParent.Children.OfType() + .FirstOrDefault(x => x.Property.GetClrProperty().Name == "Selector"); + + if (selectorProperty == null) + throw new XamlParseException( + "Can not find parent Style Selector", node); + + var selector = selectorProperty.Values.FirstOrDefault() as XamlIlSelectorNode; + + targetType = selector?.TargetType + ?? throw new XamlParseException("Can not resolve parent Style Selector type", node); + lineInfo = selector; + } + else + { + foreach (var p in context.ParentNodes().OfType()) + { + for (var index = 0; index < p.Children.Count; index++) + { + if (p.Children[index] is XamlAstXmlDirective d && + d.Namespace == XamlNamespaces.Xaml2006 && + d.Name == "SetterTargetType") + { + //p.Children.RemoveAt(index); + + targetType = context.Configuration.TypeSystem.GetType(((XamlAstTextNode)d.Values[0]).Text); + lineInfo = d; + + break; + } + } + + if (targetType != null) break; + } + } + + if (targetType == null) + { + throw new XamlParseException("Could not determine target type of Setter", node); + } IXamlType propType = null; var property = @on.Children.OfType() @@ -31,9 +77,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers if (propertyName == null) throw new XamlParseException("Setter.Property must be a string", node); - var avaloniaPropertyNode = XamlIlAvaloniaPropertyHelper.CreateNode(context, propertyName, - new XamlAstClrTypeReference(targetTypeNode, targetTypeNode.TargetType.GetClrType(), false), property.Values[0]); + new XamlAstClrTypeReference(lineInfo, targetType, false), property.Values[0]); property.Values = new List {avaloniaPropertyNode}; propType = avaloniaPropertyNode.AvaloniaPropertyType; } From 6820d019d947870699346f78a0ace186d551cf97 Mon Sep 17 00:00:00 2001 From: Luis von der Eltz Date: Mon, 25 Jul 2022 11:12:40 +0200 Subject: [PATCH 2/9] Fix merge --- .../Transformers/AvaloniaXamlIlSetterTransformer.cs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs index d6251badd5..ddfba5eab2 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs @@ -27,18 +27,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers if (styleParent != null) { - var selectorProperty = styleParent.Children.OfType() - .FirstOrDefault(x => x.Property.GetClrProperty().Name == "Selector"); - - if (selectorProperty == null) - throw new XamlParseException( - "Can not find parent Style Selector", node); - - var selector = selectorProperty.Values.FirstOrDefault() as XamlIlSelectorNode; - - targetType = selector?.TargetType + targetType = styleParent.TargetType.GetClrType() ?? throw new XamlParseException("Can not resolve parent Style Selector type", node); - lineInfo = selector; + lineInfo = on; } else { From 04b7a8b0c19bf1d63ee3bb9ee842f61d0c56c0b5 Mon Sep 17 00:00:00 2001 From: Luis von der Eltz Date: Tue, 26 Jul 2022 11:11:39 +0200 Subject: [PATCH 3/9] Add UT --- .../SetterTests.cs | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 tests/Avalonia.Markup.Xaml.UnitTests/SetterTests.cs diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/SetterTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/SetterTests.cs new file mode 100644 index 0000000000..229fa3aa7d --- /dev/null +++ b/tests/Avalonia.Markup.Xaml.UnitTests/SetterTests.cs @@ -0,0 +1,29 @@ +using System.Linq; +using Avalonia.Data; +using Avalonia.Styling; +using Avalonia.UnitTests; +using Xunit; + +namespace Avalonia.Markup.Xaml.UnitTests +{ + public class SetterTests : XamlTestBase + { + [Fact] + public void Setter_Should_Work_Outside_Of_Style_With_SetterTargetType_Attribute() + { + using (UnitTestApplication.Start(TestServices.MockPlatformWrapper)) + { + var xaml = @" + + + + +"; + var animation = (Animation.Animation)AvaloniaRuntimeXamlLoader.Load(xaml); + var setter = (Setter)animation.Children[0].Setters[0]; + + Assert.IsType(setter.Value); + } + } + } +} From cfad3051aa49fdd15bc0a433732e3fa3aa0f5313 Mon Sep 17 00:00:00 2001 From: Luis von der Eltz Date: Tue, 26 Jul 2022 11:12:14 +0200 Subject: [PATCH 4/9] RemoveChild for now --- .../Transformers/AvaloniaXamlIlSetterTransformer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs index ddfba5eab2..d69e86e409 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs @@ -41,7 +41,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers d.Namespace == XamlNamespaces.Xaml2006 && d.Name == "SetterTargetType") { - //p.Children.RemoveAt(index); + p.Children.RemoveAt(index); targetType = context.Configuration.TypeSystem.GetType(((XamlAstTextNode)d.Values[0]).Text); lineInfo = d; From f6b50e5fde80dd0fb172f07e958dd4739975be0e Mon Sep 17 00:00:00 2001 From: Luis von der Eltz Date: Wed, 27 Jul 2022 11:10:39 +0200 Subject: [PATCH 5/9] Use StyledWindow services --- tests/Avalonia.Markup.Xaml.UnitTests/SetterTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/SetterTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/SetterTests.cs index 229fa3aa7d..357245b826 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/SetterTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/SetterTests.cs @@ -11,7 +11,7 @@ namespace Avalonia.Markup.Xaml.UnitTests [Fact] public void Setter_Should_Work_Outside_Of_Style_With_SetterTargetType_Attribute() { - using (UnitTestApplication.Start(TestServices.MockPlatformWrapper)) + using (UnitTestApplication.Start(TestServices.StyledWindow)) { var xaml = @" From fdf852a60cfb8baf4aa19cd855220a54f520886b Mon Sep 17 00:00:00 2001 From: Luis von der Eltz Date: Wed, 27 Jul 2022 11:12:13 +0200 Subject: [PATCH 6/9] Don't remove node --- .../Transformers/AvaloniaXamlIlSetterTransformer.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs index d69e86e409..8c96ed96a9 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs @@ -41,8 +41,6 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers d.Namespace == XamlNamespaces.Xaml2006 && d.Name == "SetterTargetType") { - p.Children.RemoveAt(index); - targetType = context.Configuration.TypeSystem.GetType(((XamlAstTextNode)d.Values[0]).Text); lineInfo = d; From 8cae9556888dcc1469de061c0a554cb906a1eb6c Mon Sep 17 00:00:00 2001 From: Luis von der Eltz Date: Fri, 29 Jul 2022 11:16:28 +0200 Subject: [PATCH 7/9] Add another keyframe to UT --- tests/Avalonia.Markup.Xaml.UnitTests/SetterTests.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/SetterTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/SetterTests.cs index 357245b826..cc1dce4de8 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/SetterTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/SetterTests.cs @@ -18,6 +18,9 @@ namespace Avalonia.Markup.Xaml.UnitTests + + + "; var animation = (Animation.Animation)AvaloniaRuntimeXamlLoader.Load(xaml); var setter = (Setter)animation.Children[0].Setters[0]; From 0c84ae68b9b8e5eb22faedcbbec5361e8d9bca31 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Mon, 24 Oct 2022 01:19:50 -0400 Subject: [PATCH 8/9] Add AvaloniaXamlIlSetterTargetTypeMetadataTransformer to allow SetterTargetType --- .../AvaloniaXamlIlCompiler.cs | 2 + ...mlIlSetterTargetTypeMetadataTransformer.cs | 34 ++++++++++++++ .../AvaloniaXamlIlSetterTransformer.cs | 23 +-------- .../SetterTests.cs | 47 +++++++++++++------ 4 files changed, 70 insertions(+), 36 deletions(-) create mode 100644 src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTargetTypeMetadataTransformer.cs diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs index f325e6e2d6..4ece433530 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Linq; + using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers; using XamlX; using XamlX.Ast; @@ -51,6 +52,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions new AvaloniaXamlIlControlTemplateTargetTypeMetadataTransformer(), new AvaloniaXamlIlBindingPathParser(), new AvaloniaXamlIlPropertyPathTransformer(), + new AvaloniaXamlIlSetterTargetTypeMetadataTransformer(), new AvaloniaXamlIlSetterTransformer(), new AvaloniaXamlIlConstructorServiceProviderTransformer(), new AvaloniaXamlIlTransitionsTypeMetadataTransformer(), diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTargetTypeMetadataTransformer.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTargetTypeMetadataTransformer.cs new file mode 100644 index 0000000000..ebc6c01ba8 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTargetTypeMetadataTransformer.cs @@ -0,0 +1,34 @@ +using System.Linq; +using XamlX; +using XamlX.Ast; +using XamlX.Transform; +using XamlX.Transform.Transformers; + +namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers; + +internal class AvaloniaXamlIlSetterTargetTypeMetadataTransformer : IXamlAstTransformer +{ + public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node) + { + if (node is XamlAstObjectNode on + && on.Children.FirstOrDefault(c => c is XamlAstXmlDirective + { + Namespace: XamlNamespaces.Xaml2006, + Name: "SetterTargetType" + }) is { } typeDirective) + { + var value = ((XamlAstXmlDirective)typeDirective).Values.Single(); + var type = value is XamlTypeExtensionNode typeNode ? typeNode.Value + : value is XamlAstTextNode tn ? TypeReferenceResolver.ResolveType(context, tn.Text, false, tn, true) + : null; + on.Children.Remove(typeDirective); + + if (type is null) + { + throw new XamlParseException("Unable to resolve SetterTargetType type", typeDirective); + } + return new AvaloniaXamlIlTargetTypeMetadataNode(on, type, AvaloniaXamlIlTargetTypeMetadataNode.ScopeTypes.Style); + } + return node; + } +} diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs index ef322fcce9..b9b8c9e9a2 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs @@ -9,7 +9,6 @@ using XamlX.TypeSystem; namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers { - using XamlParseException = XamlX.XamlParseException; class AvaloniaXamlIlSetterTransformer : IXamlAstTransformer { public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node) @@ -28,29 +27,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers if (styleParent != null) { targetType = styleParent.TargetType.GetClrType() - ?? throw new XamlParseException("Can not resolve parent Style Selector type", node); + ?? throw new XamlParseException("Can not resolve parent Style Selector type. If setter is not part of the style, you can set x:SetterTargetType directive on its parent.", node); lineInfo = on; } - else - { - foreach (var p in context.ParentNodes().OfType()) - { - for (var index = 0; index < p.Children.Count; index++) - { - if (p.Children[index] is XamlAstXmlDirective d && - d.Namespace == XamlNamespaces.Xaml2006 && - d.Name == "SetterTargetType") - { - targetType = context.Configuration.TypeSystem.GetType(((XamlAstTextNode)d.Values[0]).Text); - lineInfo = d; - - break; - } - } - - if (targetType != null) break; - } - } if (targetType == null) { diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/SetterTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/SetterTests.cs index cc1dce4de8..6fc0f2d91c 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/SetterTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/SetterTests.cs @@ -1,20 +1,19 @@ -using System.Linq; -using Avalonia.Data; +using Avalonia.Controls; using Avalonia.Styling; using Avalonia.UnitTests; using Xunit; -namespace Avalonia.Markup.Xaml.UnitTests +namespace Avalonia.Markup.Xaml.UnitTests; + +public class SetterTests : XamlTestBase { - public class SetterTests : XamlTestBase + [Fact] + public void SetterTargetType_Should_Understand_xType_Extensions() { - [Fact] - public void Setter_Should_Work_Outside_Of_Style_With_SetterTargetType_Attribute() + using (UnitTestApplication.Start(TestServices.StyledWindow)) { - using (UnitTestApplication.Start(TestServices.StyledWindow)) - { - var xaml = @" - + var xaml = @" + @@ -22,11 +21,31 @@ namespace Avalonia.Markup.Xaml.UnitTests "; - var animation = (Animation.Animation)AvaloniaRuntimeXamlLoader.Load(xaml); - var setter = (Setter)animation.Children[0].Setters[0]; + var animation = (Animation.Animation)AvaloniaRuntimeXamlLoader.Load(xaml); + var setter = (Setter)animation.Children[0].Setters[0]; + + Assert.Equal(typeof(ContentControl), setter.Property.OwnerType); + } + } + + [Fact] + public void SetterTargetType_Should_Understand_Type_From_Xmlns() + { + using (UnitTestApplication.Start(TestServices.StyledWindow)) + { + var xaml = @" + + + + + + + +"; + var animation = (Animation.Animation)AvaloniaRuntimeXamlLoader.Load(xaml); + var setter = (Setter)animation.Children[0].Setters[0]; - Assert.IsType(setter.Value); - } + Assert.Equal(typeof(ContentControl), setter.Property.OwnerType); } } } From 7683a3bddb1a80901abd31bca3ffa1933d3839f0 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Mon, 24 Oct 2022 01:25:47 -0400 Subject: [PATCH 9/9] Restore old exception message --- .../Transformers/AvaloniaXamlIlSetterTransformer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs index b9b8c9e9a2..5a6fd8246d 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs @@ -27,7 +27,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers if (styleParent != null) { targetType = styleParent.TargetType.GetClrType() - ?? throw new XamlParseException("Can not resolve parent Style Selector type. If setter is not part of the style, you can set x:SetterTargetType directive on its parent.", node); + ?? throw new XamlParseException("Can not find parent Style Selector or ControlTemplate TargetType. If setter is not part of the style, you can set x:SetterTargetType directive on its parent.", node); lineInfo = on; }