Browse Source

Merge pull request #10113 from DmitryZhelnin/9612-duplicate-setters

Check for duplicate property setters in styles and control themes
pull/10155/head
Max Katz 4 years ago
committed by GitHub
parent
commit
315c6dce42
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs
  2. 3
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlControlThemeTransformer.cs
  3. 45
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlDuplicateSettersChecker.cs
  4. 3
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSelectorTransformer.cs
  5. 4
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs
  6. 41
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs

1
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs

@ -49,6 +49,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
InsertBefore<ContentConvertTransformer>(
new AvaloniaXamlIlControlThemeTransformer(),
new AvaloniaXamlIlSelectorTransformer(),
new AvaloniaXamlIlDuplicateSettersChecker(),
new AvaloniaXamlIlControlTemplateTargetTypeMetadataTransformer(),
new AvaloniaXamlIlBindingPathParser(),
new AvaloniaXamlIlPropertyPathTransformer(),

3
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlControlThemeTransformer.cs

@ -11,7 +11,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
{
public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
{
if (!(node is XamlAstObjectNode on && on.Type.GetClrType().FullName == "Avalonia.Styling.ControlTheme"))
if (node is not XamlAstObjectNode on ||
!context.GetAvaloniaTypes().ControlTheme.IsAssignableFrom(on.Type.GetClrType()))
return node;
// Check if we've already transformed this node.

45
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlDuplicateSettersChecker.cs

@ -0,0 +1,45 @@
using System.Collections.Generic;
using System.Linq;
using XamlX;
using XamlX.Ast;
using XamlX.Transform;
namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers;
class AvaloniaXamlIlDuplicateSettersChecker : IXamlAstTransformer
{
public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
{
if (node is not XamlAstObjectNode objectNode)
{
return node;
}
var nodeType = objectNode.Type.GetClrType();
if (!context.GetAvaloniaTypes().Style.IsAssignableFrom(nodeType) &&
!context.GetAvaloniaTypes().ControlTheme.IsAssignableFrom(nodeType))
{
return node;
}
var properties = objectNode.Children
.OfType<XamlAstObjectNode>()
.Where(n => n.Type.GetClrType().Name == "Setter")
.SelectMany(setter =>
setter.Children.OfType<XamlAstXamlPropertyValueNode>()
.Where(c => c.Property.GetClrProperty().Name == "Property"))
.Select(p => p.Values[0])
.OfType<XamlAstTextNode>()
.Select(x => x.Text);
var index = new HashSet<string>();
foreach (var property in properties)
{
if (!index.Add(property))
{
throw new XamlParseException($"Duplicate setter encountered for property '{property}'", node);
}
}
return node;
}
}

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

@ -19,7 +19,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
{
public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
{
if (!(node is XamlAstObjectNode on && on.Type.GetClrType().FullName == "Avalonia.Styling.Style"))
if (node is not XamlAstObjectNode on ||
!context.GetAvaloniaTypes().Style.IsAssignableFrom(on.Type.GetClrType()))
return node;
var pn = on.Children.OfType<XamlAstXamlPropertyValueNode>()

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

@ -112,6 +112,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
public IXamlMethod ResourceDictionaryDeferredAdd { get; }
public IXamlType UriKind { get; }
public IXamlConstructor UriConstructor { get; }
public IXamlType Style { get; }
public IXamlType ControlTheme { get; }
public AvaloniaXamlIlWellKnownTypes(TransformerConfiguration cfg)
{
@ -250,6 +252,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
XamlIlTypes.Object));
UriKind = cfg.TypeSystem.GetType("System.UriKind");
UriConstructor = Uri.GetConstructor(new List<IXamlType>() { cfg.WellKnownTypes.String, UriKind });
Style = cfg.TypeSystem.GetType("Avalonia.Styling.Style");
ControlTheme = cfg.TypeSystem.GetType("Avalonia.Styling.ControlTheme");
}
}

41
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs

@ -334,6 +334,47 @@ namespace Avalonia.Markup.Xaml.UnitTests
var parsed = (Button)AvaloniaRuntimeXamlLoader.Load(document);
Assert.Equal(Colors.Blue, ((ISolidColorBrush)parsed.Background!).Color);
}
[Fact]
public void Style_Parser_Throws_For_Duplicate_Setter()
{
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.Xaml;assembly=Avalonia.Markup.Xaml.UnitTests'>
<Window.Styles>
<Style Selector='TextBlock'>
<Setter Property='Width' Value='100'/>
<Setter Property='Height' Value='20'/>
<Setter Property='Height' Value='30'/>
</Style>
</Window.Styles>
<TextBlock/>
</Window>";
AssertThrows(() => AvaloniaRuntimeXamlLoader.Load(xaml, typeof(XamlIlTests).Assembly, designMode: true),
e => e.Message.StartsWith("Duplicate setter encountered for property 'Height'"));
}
[Fact]
public void Control_Theme_Parser_Throws_For_Duplicate_Setter()
{
var xaml = @"
<Window xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
xmlns:u='using:Avalonia.Markup.Xaml.UnitTests.Xaml'>
<Window.Resources>
<ControlTheme x:Key='MyTheme' TargetType='u:TestTemplatedControl'>
<Setter Property='Width' Value='100'/>
<Setter Property='Height' Value='20'/>
<Setter Property='Height' Value='30'/>
</ControlTheme>
</Window.Resources>
<u:TestTemplatedControl Theme='{StaticResource MyTheme}'/>
</Window>";
AssertThrows(() => AvaloniaRuntimeXamlLoader.Load(xaml, typeof(XamlIlTests).Assembly, designMode: true),
e => e.Message.StartsWith("Duplicate setter encountered for property 'Height'"));
}
}
public class XamlIlBugTestsEventHandlerCodeBehind : Window

Loading…
Cancel
Save