[previewer] resilience on createvalue (#5369)
authorStephane Delcroix <stephane@delcroix.org>
Tue, 26 Feb 2019 19:09:16 +0000 (20:09 +0100)
committerGitHub <noreply@github.com>
Tue, 26 Feb 2019 19:09:16 +0000 (20:09 +0100)
- fixes #5171

Xamarin.Forms.Xaml.UnitTests/DesignTimeLoaderTests.cs
Xamarin.Forms.Xaml/ApplyPropertiesVisitor.cs
Xamarin.Forms.Xaml/CreateValuesVisitor.cs
Xamarin.Forms.Xaml/FillResourceDictionariesVisitor.cs

index b07d71b..4c60675 100644 (file)
@@ -51,7 +51,7 @@ namespace Xamarin.Forms.Xaml.UnitTests
                }
 
                [Test]
-               public void ContentPageWithMissingType()
+               public void ContentPageWithMissingTypeMockviewReplacement()
                {
                        XamlLoader.FallbackTypeResolver = (p, type) => type ?? typeof(MockView);
 
@@ -69,6 +69,28 @@ namespace Xamarin.Forms.Xaml.UnitTests
                }
 
                [Test]
+               public void ContentPageWithMissingTypeNoReplacement()
+               {
+                       XamlLoader.FallbackTypeResolver = (p, type) => type;
+
+                       var xaml = @"
+                                       <ContentPage xmlns=""http://xamarin.com/schemas/2014/forms""
+                                               xmlns:local=""clr-namespace:MissingNamespace;assembly=MissingAssembly""
+                                               xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"">
+                                               <ContentPage.Content>
+                                                       <local:MyCustomButton Foo=""Bar"">
+                                                               <local:MyCustomButton.Qux>
+                                                                       <Label />
+                                                               </local:MyCustomButton.Qux>
+                                                       </local:MyCustomButton>
+                                               </ContentPage.Content>
+                                       </ContentPage>";
+
+                       var page = (ContentPage)XamlLoader.Create(xaml, true);
+                       Assert.That(page.Content, Is.Null);
+               }
+
+               [Test]
                public void MissingTypeWithKnownProperty()
                {
                        XamlLoader.FallbackTypeResolver = (p, type) => type ?? typeof(Button);
index 8e35de0..448646e 100644 (file)
@@ -36,13 +36,15 @@ namespace Xamarin.Forms.Xaml
                public bool StopOnResourceDictionary { get; }
                public bool VisitNodeOnDataTemplate => true;
                public bool SkipChildren(INode node, INode parentNode) => false;
-               public bool IsResourceDictionary(ElementNode node) => typeof(ResourceDictionary).IsAssignableFrom(Context.Types[node]);
+               public bool IsResourceDictionary(ElementNode node) => Context.Types.TryGetValue(node, out var type) && typeof(ResourceDictionary).IsAssignableFrom(type);
 
                public void Visit(ValueNode node, INode parentNode)
                {
                        var parentElement = parentNode as IElementNode;
                        var value = Values [node];
-                       var source = Values [parentNode];
+                       if (!Values.TryGetValue(parentNode, out var source) && Context.ExceptionHandler != null)
+                               return;
+
                        XmlName propertyName;
 
                        if (TryGetPropertyName(node, parentNode, out propertyName)) {
@@ -95,7 +97,8 @@ namespace Xamarin.Forms.Xaml
                                parentElement = parentNode as IElementNode;
                        }
 
-                       var value = Values[node];
+                       if (!Values.TryGetValue(node, out var value) && Context.ExceptionHandler != null)
+                               return;
 
                        if (propertyName != XmlName.Empty || TryGetPropertyName(node, parentNode, out propertyName)) {
                                if (Skips.Contains(propertyName))
@@ -103,12 +106,14 @@ namespace Xamarin.Forms.Xaml
                                if (parentElement.SkipProperties.Contains(propertyName))
                                        return;
 
-                               var source = Values[parentNode];
+                               if (!Values.TryGetValue(parentNode, out var source) && Context.ExceptionHandler != null)
+                                       return;
                                ProvideValue(ref value, node, source, propertyName);
                                SetPropertyValue(source, propertyName, value, Context.RootElement, node, Context, node);
                        }
                        else if (IsCollectionItem(node, parentNode) && parentNode is IElementNode) {
-                               var source = Values[parentNode];
+                               if (!Values.TryGetValue(parentNode, out var source) && Context.ExceptionHandler != null)
+                                       return;
                                ProvideValue(ref value, node, source, XmlName.Empty);
                                string contentProperty;
                                Exception xpe = null;
@@ -143,7 +148,8 @@ namespace Xamarin.Forms.Xaml
                                        throw xpe;
                        }
                        else if (IsCollectionItem(node, parentNode) && parentNode is ListNode) {
-                               var source = Values[parentNode.Parent];
+                               if (!Values.TryGetValue(parentNode.Parent, out var source) && Context.ExceptionHandler != null)
+                                       return;
                                ProvideValue(ref value, node, source, XmlName.Empty);
                                var parentList = (ListNode)parentNode;
                                if (Skips.Contains(parentList.XmlName))
index b9bb498..838a417 100644 (file)
@@ -43,12 +43,15 @@ namespace Xamarin.Forms.Xaml
                {
                        object value = null;
 
-                       XamlParseException xpe;
                        var type = XamlParser.GetElementType(node.XmlType, node, Context.RootElement?.GetType().GetTypeInfo().Assembly,
-                               out xpe);
-                       if (xpe != null)
+                               out XamlParseException xpe);
+                       if (xpe != null) {
+                               if (Context.ExceptionHandler != null) {
+                                       Context.ExceptionHandler(xpe);
+                                       return;
+                               }
                                throw xpe;
-
+                       }
                        Context.Types[node] = type;
                        if (IsXaml2009LanguagePrimitive(node))
                                value = CreateLanguagePrimitive(type, node);
index 5013ca6..a927ec9 100644 (file)
@@ -25,7 +25,7 @@ namespace Xamarin.Forms.Xaml
 
                public void Visit(ValueNode node, INode parentNode)
                {
-                       if (!typeof(ResourceDictionary).IsAssignableFrom(Context.Types[((IElementNode)parentNode)]))
+                       if (!Context.Types.TryGetValue((IElementNode)parentNode, out var type) || !typeof(ResourceDictionary).IsAssignableFrom(type))
                                return;
 
                        node.Accept(new ApplyPropertiesVisitor(Context, stopOnResourceDictionary: false), parentNode);
@@ -37,10 +37,11 @@ namespace Xamarin.Forms.Xaml
 
                public void Visit(ElementNode node, INode parentNode)
                {
-                       var value = Values[node];
-                       XmlName propertyName;
+                       if (!Values.TryGetValue(node, out var value) && Context.ExceptionHandler != null)
+                               return;
+                       
                        //Set RD to VE
-                       if (typeof(ResourceDictionary).IsAssignableFrom(Context.Types[node]) && ApplyPropertiesVisitor.TryGetPropertyName(node, parentNode, out propertyName)) {
+                       if (typeof(ResourceDictionary).IsAssignableFrom(Context.Types[node]) && ApplyPropertiesVisitor.TryGetPropertyName(node, parentNode, out XmlName propertyName)) {
                                if ((propertyName.LocalName == "Resources" ||
                                         propertyName.LocalName.EndsWith(".Resources", StringComparison.Ordinal)) && value is ResourceDictionary) {
                                        var source = Values[parentNode];
@@ -51,7 +52,8 @@ namespace Xamarin.Forms.Xaml
 
                        //Only proceed further if the node is a keyless RD
                        if (   parentNode is IElementNode
-                               && typeof(ResourceDictionary).IsAssignableFrom(Context.Types[((IElementNode)parentNode)])
+                               && Context.Types.TryGetValue((IElementNode)parentNode, out var parentType)
+                               && typeof(ResourceDictionary).IsAssignableFrom(parentType)
                                && !((IElementNode)parentNode).Properties.ContainsKey(XmlName.xKey))
                                node.Accept(new ApplyPropertiesVisitor(Context, stopOnResourceDictionary: false), parentNode);
                        else if (   parentNode is ListNode
@@ -74,7 +76,8 @@ namespace Xamarin.Forms.Xaml
                        if (enode is null)
                                return false;
                        if (   parentNode is IElementNode
-                           && typeof(ResourceDictionary).IsAssignableFrom(Context.Types[((IElementNode)parentNode)])
+                               && Context.Types.TryGetValue((IElementNode)parentNode, out var parentType)
+                               && typeof(ResourceDictionary).IsAssignableFrom(parentType)
                            && !((IElementNode)parentNode).Properties.ContainsKey(XmlName.xKey))
                                return true;
                        if (   parentNode is ListNode