Browse Source

Fix style without selector not finding target type (#18026)

* Add failing style test without selector

* Fix XAML target type of style without selector

* Address review

* Throw for style without selector in ControlTheme
#Conflicts:
#	tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleTests.cs
release/11.2.4
Julien Lebosquain 1 year ago
committed by Max Katz
parent
commit
d29d554f25
  1. 55
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSelectorTransformer.cs
  2. 2
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs
  3. 1
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleTests.cs

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

@ -32,8 +32,26 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
var pn = on.Children.OfType<XamlAstXamlPropertyValueNode>()
.FirstOrDefault(p => p.Property.GetClrProperty().Name == "Selector");
// Missing selector, use the object's target type if available
if (pn == null)
{
// We already went through this node
if (context.ParentNodes().FirstOrDefault() is AvaloniaXamlIlTargetTypeMetadataNode metadataNode
&& metadataNode.Value == on)
{
return node;
}
if (FindStyleParentObject(on, context) is { } parentObjectNode)
{
return new AvaloniaXamlIlTargetTypeMetadataNode(
on,
new XamlAstClrTypeReference(node, parentObjectNode.Type.GetClrType(), false),
AvaloniaXamlIlTargetTypeMetadataNode.ScopeTypes.Style);
}
return node;
}
if (pn.Values.Count != 1)
throw new XamlSelectorsTransformException("Selector property should have exactly one value",
@ -195,6 +213,20 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
pn.Values[0] = selector;
var templateType = GetLastTemplateTypeFromSelector(selector);
// Empty selector, use the object's target type if available
if (selector == initialNode)
{
if (FindStyleParentObject(on, context) is { } parentObjectNode)
{
return new AvaloniaXamlIlTargetTypeMetadataNode(
on,
new XamlAstClrTypeReference(node, parentObjectNode.Type.GetClrType(), false),
AvaloniaXamlIlTargetTypeMetadataNode.ScopeTypes.Style);
}
return node;
}
var styleNode = new AvaloniaXamlIlTargetTypeMetadataNode(on,
new XamlAstClrTypeReference(selector, selector.TargetType!, false),
@ -209,6 +241,29 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
};
}
private static XamlAstObjectNode? FindStyleParentObject(XamlAstNode styleNode, AstTransformationContext context)
{
var avaloniaTypes = context.GetAvaloniaTypes();
var parentNode = context
.ParentNodes()
.OfType<XamlAstObjectNode>()
.FirstOrDefault(n => !avaloniaTypes.Styles.IsAssignableFrom(n.Type.GetClrType()));
if (parentNode is not null)
{
var parentType = parentNode.Type.GetClrType();
if (avaloniaTypes.StyledElement.IsAssignableFrom(parentType))
return parentNode;
if (avaloniaTypes.ControlTheme.IsAssignableFrom(parentType))
throw new XamlTransformException("Cannot add a Style without selector to a ControlTheme.", styleNode);
}
return null;
}
private static IXamlType? GetLastTemplateTypeFromSelector(XamlIlSelectorNode? node)
{
while (node is not null)

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

@ -126,6 +126,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
public IXamlType UriKind { get; }
public IXamlConstructor UriConstructor { get; }
public IXamlType Style { get; }
public IXamlType Styles { get; }
public IXamlType ControlTheme { get; }
public IXamlType WindowTransparencyLevel { get; }
public IXamlType IReadOnlyListOfT { get; }
@ -324,6 +325,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
UriKind = cfg.TypeSystem.GetType("System.UriKind");
UriConstructor = Uri.GetConstructor(new List<IXamlType>() { cfg.WellKnownTypes.String, UriKind });
Style = cfg.TypeSystem.GetType("Avalonia.Styling.Style");
Styles = cfg.TypeSystem.GetType("Avalonia.Styling.Styles");
ControlTheme = cfg.TypeSystem.GetType("Avalonia.Styling.ControlTheme");
ControlTemplate = cfg.TypeSystem.GetType("Avalonia.Markup.Xaml.Templates.ControlTemplate");
IReadOnlyListOfT = cfg.TypeSystem.GetType("System.Collections.Generic.IReadOnlyList`1");

1
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleTests.cs

@ -15,6 +15,7 @@ using Xunit;
namespace Avalonia.Markup.Xaml.UnitTests.Xaml
{
[InvariantCulture]
public class StyleTests : XamlTestBase
{
[Fact]

Loading…
Cancel
Save