[Xaml] Throw XamlParseException when a duplicate property is detected (#5558)
authorAkihiko Odaki <akihiko.odaki.4i@stu.hosei.ac.jp>
Tue, 26 Mar 2019 14:49:05 +0000 (23:49 +0900)
committerStephane Delcroix <stephane@delcroix.org>
Tue, 26 Mar 2019 14:49:05 +0000 (15:49 +0100)
Xamarin.Forms.Xaml.UnitTests/DuplicatePropertyElements.xaml [new file with mode: 0644]
Xamarin.Forms.Xaml.UnitTests/DuplicatePropertyElements.xaml.cs [new file with mode: 0644]
Xamarin.Forms.Xaml.UnitTests/DuplicateXArgumentsElements.xaml [new file with mode: 0644]
Xamarin.Forms.Xaml.UnitTests/DuplicateXArgumentsElements.xaml.cs [new file with mode: 0644]
Xamarin.Forms.Xaml.UnitTests/MultipleDataTemplateChildElements.xaml [new file with mode: 0644]
Xamarin.Forms.Xaml.UnitTests/MultipleDataTemplateChildElements.xaml.cs [new file with mode: 0644]
Xamarin.Forms.Xaml/XamlParser.cs

diff --git a/Xamarin.Forms.Xaml.UnitTests/DuplicatePropertyElements.xaml b/Xamarin.Forms.Xaml.UnitTests/DuplicatePropertyElements.xaml
new file mode 100644 (file)
index 0000000..f68fd1c
--- /dev/null
@@ -0,0 +1,4 @@
+<BindableObject xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Xamarin.Forms.Xaml.UnitTests.DuplicatePropertyElements">
+       <BindableObject.BindingContext>0</BindableObject.BindingContext>
+       <BindableObject.BindingContext>0</BindableObject.BindingContext>
+</BindableObject>
diff --git a/Xamarin.Forms.Xaml.UnitTests/DuplicatePropertyElements.xaml.cs b/Xamarin.Forms.Xaml.UnitTests/DuplicatePropertyElements.xaml.cs
new file mode 100644 (file)
index 0000000..5085159
--- /dev/null
@@ -0,0 +1,26 @@
+using NUnit.Framework;
+
+namespace Xamarin.Forms.Xaml.UnitTests
+{
+       [XamlCompilation(XamlCompilationOptions.Skip)]
+       public partial class DuplicatePropertyElements : BindableObject
+       {
+               public DuplicatePropertyElements(bool useCompiledXaml)
+               {
+                       //this stub will be replaced at compile time
+               }
+
+               [TestFixture]
+               public static class Tests
+               {
+                       [TestCase(false)]
+                       [TestCase(true)]
+                       public static void ThrowXamlParseException(bool useCompiledXaml)
+                       {
+                               Assert.Throws<XamlParseException>(useCompiledXaml ?
+                                       (TestDelegate)(() => MockCompiler.Compile(typeof(DuplicatePropertyElements))) :
+                                       () => new DuplicatePropertyElements(useCompiledXaml));
+                       }
+               }
+       }
+}
diff --git a/Xamarin.Forms.Xaml.UnitTests/DuplicateXArgumentsElements.xaml b/Xamarin.Forms.Xaml.UnitTests/DuplicateXArgumentsElements.xaml
new file mode 100644 (file)
index 0000000..16ff683
--- /dev/null
@@ -0,0 +1,8 @@
+<BindableObject xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:system="clr-namespace:System;assembly=mscorlib.dll" x:Class="Xamarin.Forms.Xaml.UnitTests.DuplicateXArgumentsElements">
+       <BindableObject.BindingContext>
+        <system:Uri>
+            <x:Arguments>https://example.com/</x:Arguments>
+            <x:Arguments>https://example.com/</x:Arguments>
+        </system:Uri>
+    </BindableObject.BindingContext>
+</BindableObject>
diff --git a/Xamarin.Forms.Xaml.UnitTests/DuplicateXArgumentsElements.xaml.cs b/Xamarin.Forms.Xaml.UnitTests/DuplicateXArgumentsElements.xaml.cs
new file mode 100644 (file)
index 0000000..33de829
--- /dev/null
@@ -0,0 +1,26 @@
+using NUnit.Framework;
+
+namespace Xamarin.Forms.Xaml.UnitTests
+{
+       [XamlCompilation(XamlCompilationOptions.Skip)]
+       public partial class DuplicateXArgumentsElements : BindableObject
+       {
+               public DuplicateXArgumentsElements(bool useCompiledXaml)
+               {
+                       //this stub will be replaced at compile time
+               }
+
+               [TestFixture]
+               public static class Tests
+               {
+                       [TestCase(false)]
+                       [TestCase(true)]
+                       public static void ThrowXamlParseException(bool useCompiledXaml)
+                       {
+                               Assert.Throws<XamlParseException>(useCompiledXaml ?
+                                       (TestDelegate)(() => MockCompiler.Compile(typeof(DuplicateXArgumentsElements))) :
+                                       () => new DuplicateXArgumentsElements(useCompiledXaml));
+                       }
+               }
+       }
+}
diff --git a/Xamarin.Forms.Xaml.UnitTests/MultipleDataTemplateChildElements.xaml b/Xamarin.Forms.Xaml.UnitTests/MultipleDataTemplateChildElements.xaml
new file mode 100644 (file)
index 0000000..0728a08
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<BindableObject xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Xamarin.Forms.Xaml.UnitTests.MultipleDataTemplateChildElements">
+       <BindableObject.BindingContext>
+               <DataTemplate>
+                       <Page />
+                       <Page />
+               </DataTemplate>
+       </BindableObject.BindingContext>
+</BindableObject>
diff --git a/Xamarin.Forms.Xaml.UnitTests/MultipleDataTemplateChildElements.xaml.cs b/Xamarin.Forms.Xaml.UnitTests/MultipleDataTemplateChildElements.xaml.cs
new file mode 100644 (file)
index 0000000..1f32578
--- /dev/null
@@ -0,0 +1,26 @@
+using NUnit.Framework;
+
+namespace Xamarin.Forms.Xaml.UnitTests
+{
+       [XamlCompilation(XamlCompilationOptions.Skip)]
+       public partial class MultipleDataTemplateChildElements : BindableObject
+       {
+               public MultipleDataTemplateChildElements(bool useCompiledXaml)
+               {
+                       //this stub will be replaced at compile time
+               }
+
+               [TestFixture]
+               public static class Tests
+               {
+                       [TestCase(false)]
+                       [TestCase(true)]
+                       public static void ThrowXamlParseException(bool useCompiledXaml)
+                       {
+                               Assert.Throws<XamlParseException>(useCompiledXaml ?
+                                       (TestDelegate)(() => MockCompiler.Compile(typeof(MultipleDataTemplateChildElements))) :
+                                       () => new MultipleDataTemplateChildElements(useCompiledXaml));
+                       }
+               }
+       }
+}
index 6da68c1..78b86c6 100644 (file)
@@ -80,16 +80,23 @@ namespace Xamarin.Forms.Xaml
                                                        else //Attached BP
                                                                name = new XmlName(reader.NamespaceURI, reader.LocalName);
 
+                                                       if (node.Properties.ContainsKey(name))
+                                                               throw new XamlParseException($"'{reader.Name}' is a duplicate property name.", (IXmlLineInfo)reader);
+
                                                        INode prop = null;
                                                        if (reader.IsEmptyElement)
                                                                Debug.WriteLine($"Unexpected empty element '<{reader.Name} />'", (IXmlLineInfo)reader);
                                                        else
                                                                prop = ReadNode(reader);
+
                                                        if (prop != null)
                                                                node.Properties.Add(name, prop);
                                                }
                                                // 2. Xaml2009 primitives, x:Arguments, ...
                                                else if (reader.NamespaceURI == X2009Uri && reader.LocalName == "Arguments") {
+                                                       if (node.Properties.ContainsKey(XmlName.xArguments))
+                                                               throw new XamlParseException($"'x:Arguments' is a duplicate directive name.", (IXmlLineInfo)reader);
+
                                                        var prop = ReadNode(reader);
                                                        if (prop != null)
                                                                node.Properties.Add(XmlName.xArguments, prop);
@@ -97,6 +104,9 @@ namespace Xamarin.Forms.Xaml
                                                // 3. DataTemplate (should be handled by 4.)
                                                else if (node.XmlType.NamespaceUri == XFUri &&
                                                                 (node.XmlType.Name == "DataTemplate" || node.XmlType.Name == "ControlTemplate")) {
+                                                       if (node.Properties.ContainsKey(XmlName._CreateContent))
+                                                               throw new XamlParseException($"Multiple child elements in {node.XmlType.Name}", (IXmlLineInfo)reader);
+
                                                        var prop = ReadNode(reader, true);
                                                        if (prop != null)
                                                                node.Properties.Add(XmlName._CreateContent, prop);