Skip to content
This repository has been archived by the owner on May 1, 2024. It is now read-only.

Commit

Permalink
[X] throw XPE on missing element .ctor
Browse files Browse the repository at this point in the history
In case of runtime parse, wrap the MissingMethodException in a
XamlParseException, to get lineInfo. In case of XamlC, detect missing
constructor and fail early.

- fixes #4751
  • Loading branch information
StephaneDelcroix committed Dec 18, 2018
1 parent 5a8e612 commit d4978da
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 4 deletions.
3 changes: 3 additions & 0 deletions Xamarin.Forms.Build.Tasks/CreateObjectVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@ public void Visit(ElementNode node, INode parentNode)
md.IsSpecialName &&
md.Name == "op_Implicit" && md.Parameters [0].ParameterType.FullName == "System.String");

if (!typedef.IsValueType && ctorInfo == null && factoryMethodInfo == null)
throw new XamlParseException($"Missing default constructor for '{typedef.FullName}'.", node);

if (ctorinforef != null || factorymethodinforef != null || typedef.IsValueType) {
VariableDefinition vardef = new VariableDefinition(typeref);
Context.Variables [node] = vardef;
Expand Down
10 changes: 10 additions & 0 deletions Xamarin.Forms.Xaml.UnitTests/Issues/Gh4751.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="using:Xamarin.Forms.Xaml.UnitTests"
x:Class="Xamarin.Forms.Xaml.UnitTests.Gh4751">
<ContentPage.BindingContext>
<local:Gh4751VM />
</ContentPage.BindingContext>
</ContentPage>
41 changes: 41 additions & 0 deletions Xamarin.Forms.Xaml.UnitTests/Issues/Gh4751.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;

using NUnit.Framework;

using Xamarin.Forms.Core.UnitTests;

namespace Xamarin.Forms.Xaml.UnitTests
{
public class Gh4751VM
{
public string Title { get; }
public Gh4751VM(string title = null) => Title = title; //a .ctor with a default value IS NOT a default .ctor
}

[XamlCompilation(XamlCompilationOptions.Skip)]
public partial class Gh4751 : ContentPage
{
public Gh4751() => InitializeComponent();
public Gh4751(bool useCompiledXaml)
{
//this stub will be replaced at compile time
}

[TestFixture]
class Tests
{
[SetUp] public void Setup() => Device.PlatformServices = new MockPlatformServices();
[TearDown] public void TearDown() => Device.PlatformServices = null;

[Test]
public void ErrorOnMissingDefaultCtor([Values (false, true)]bool useCompiledXaml)
{
if (useCompiledXaml)
Assert.Throws<XamlParseException>(() => MockCompiler.Compile(typeof(Gh4751)));
else
Assert.Throws<XamlParseException>(() => new Gh4751(useCompiledXaml));
}
}
}
}
9 changes: 5 additions & 4 deletions Xamarin.Forms.Xaml/CreateValuesVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,11 @@ public void Visit(ElementNode node, INode parentNode)
if (value == null)
value = Activator.CreateInstance(type);
}
catch (TargetInvocationException e) {
if (e.InnerException is XamlParseException || e.InnerException is XmlException)
throw e.InnerException;
throw;
catch (TargetInvocationException e) when (e.InnerException is XamlParseException || e.InnerException is XmlException) {
throw e.InnerException;
}
catch (MissingMethodException mme) {
throw new XamlParseException(mme.Message, node, mme);
}
}

Expand Down

0 comments on commit d4978da

Please sign in to comment.