Browse Source

Now passing most of the tests

Nikita Tsukanov 6 years ago
parent
commit
d0301bb4c4

+ 1 - 0
samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj

@@ -3,6 +3,7 @@
   <PropertyGroup>
     <OutputType>Exe</OutputType>
     <TargetFramework>netcoreapp2.0</TargetFramework>
+    <TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
   </PropertyGroup>
 
   <ItemGroup>

+ 2 - 2
src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs

@@ -258,8 +258,8 @@ namespace Avalonia.Build.Tasks
                         int lineNumber = 0, linePosition = 0;
                         if (e is XamlIlParseException xe)
                         {
-                            lineNumber = xe.Line;
-                            linePosition = xe.Position;
+                            lineNumber = xe.LineNumber;
+                            linePosition = xe.LinePosition;
                         }
                         engine.LogErrorEvent(new BuildErrorEventArgs("Avalonia", "XAMLIL", res.FilePath,
                             lineNumber, linePosition, lineNumber, linePosition,

+ 5 - 3
src/Avalonia.DesignerSupport/Remote/RemoteDesignerEntryPoint.cs

@@ -2,6 +2,7 @@
 using System.Collections.Generic;
 using System.Net;
 using System.Reflection;
+using System.Xml;
 using Avalonia.Controls;
 using Avalonia.Input;
 using Avalonia.Remote.Protocol;
@@ -206,7 +207,8 @@ namespace Avalonia.DesignerSupport.Remote
                 catch (Exception e)
                 {
                     var xamlException = e as XamlException;
-
+                    var xmlException = e as XmlException;
+                    
                     s_transport.Send(new UpdateXamlResultMessage
                     {
                         Error = e.ToString(),
@@ -214,8 +216,8 @@ namespace Avalonia.DesignerSupport.Remote
                         {
                             ExceptionType = e.GetType().FullName,
                             Message = e.Message.ToString(),
-                            LineNumber = xamlException?.LineNumber,
-                            LinePosition = xamlException?.LinePosition,
+                            LineNumber = xamlException?.LineNumber ?? xmlException?.LineNumber,
+                            LinePosition = xamlException?.LinePosition ?? xmlException?.LinePosition,
                         }
                     });
                 }

+ 1 - 0
src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj

@@ -56,6 +56,7 @@
         <Compile Include="Templates\TreeDataTemplate.cs" />
         <Compile Include="XamlIl\AvaloniaXamlIlRuntimeCompiler.cs" />
         <Compile Include="XamlIl\CompilerExtensions\Transformers\AvaloniaXamlIlControlTemplateTargetTypeMetadataTransformer.cs" />
+        <Compile Include="XamlIl\CompilerExtensions\Transformers\AvaloniaXamlIlDesignPropertiesTransformer.cs" />
         <Compile Include="XamlIl\CompilerExtensions\Transformers\AvaloniaXamlIlMetadataRemover.cs" />
         <Compile Include="XamlIl\CompilerExtensions\XamlIlAvaloniaPropertyHelper.cs" />
         <Compile Include="XamlIl\CompilerExtensions\AvaloniaXamlIlCompiler.cs" />

+ 2 - 2
src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs

@@ -26,7 +26,7 @@ namespace Avalonia.Markup.Xaml
     {
         public bool IsDesignMode { get; set; }
 
-        public bool UseLegacyXamlLoader { get; set; } = false;
+        public static bool UseLegacyXamlLoader { get; set; } = false;
         
         /// <summary>
         /// Initializes a new instance of the <see cref="AvaloniaXamlLoader"/> class.
@@ -176,7 +176,7 @@ namespace Avalonia.Markup.Xaml
         public object Load(Stream stream, Assembly localAssembly, object rootInstance = null, Uri uri = null)
         {
             if (!UseLegacyXamlLoader)
-                return AvaloniaXamlIlRuntimeCompiler.Load(stream, localAssembly, rootInstance, uri);
+                return AvaloniaXamlIlRuntimeCompiler.Load(stream, localAssembly, rootInstance, uri, IsDesignMode);
 
 
             var readerSettings = new XamlXmlReaderSettings()

+ 5 - 0
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/ResourceInclude.cs

@@ -54,6 +54,11 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
 
         /// <inhertidoc/>
         public override object ProvideValue(IServiceProvider serviceProvider)
+        {
+            return ProvideTypedValue(serviceProvider);
+        }
+        
+        public ResourceInclude ProvideTypedValue(IServiceProvider serviceProvider)
         {
             var tdc = (ITypeDescriptorContext)serviceProvider;
             _baseUri = tdc?.GetContextBaseUri();

+ 16 - 9
src/Markup/Avalonia.Markup.Xaml/XamlIl/AvaloniaXamlIlRuntimeCompiler.cs

@@ -23,6 +23,7 @@ namespace Avalonia.Markup.Xaml.XamlIl
 #if !RUNTIME_XAML_CECIL
         private static SreTypeSystem _sreTypeSystem;
         private static ModuleBuilder _sreBuilder;
+        private static IXamlIlType _sreContextType; 
         private static XamlIlLanguageTypeMappings _sreMappings;
         private static XamlIlXmlnsMappings _sreXmlns;
         private static AssemblyBuilder _sreAsm;
@@ -53,7 +54,8 @@ namespace Avalonia.Markup.Xaml.XamlIl
                 _sreTypeSystem = new SreTypeSystem();
             if (_sreBuilder == null)
             {
-                _sreCanSave = !AvaloniaLocator.Current.GetService<IRuntimePlatform>().GetRuntimeInfo().IsCoreClr;
+                _sreCanSave = AvaloniaLocator.Current.GetService<IRuntimePlatform>()?.GetRuntimeInfo().IsCoreClr ==
+                              false;
                 var name = new AssemblyName(Guid.NewGuid().ToString("N"));
                 if (_sreCanSave)
                 {
@@ -77,22 +79,25 @@ namespace Avalonia.Markup.Xaml.XamlIl
                         AssemblyBuilderAccess.RunAndCollect);
                 
                 _sreBuilder = _sreAsm.DefineDynamicModule("XamlIlLoader.ildump");
-                
             }
 
             if (_sreMappings == null)
                 _sreMappings = AvaloniaXamlIlLanguage.Configure(_sreTypeSystem);
             if (_sreXmlns == null)
                 _sreXmlns = XamlIlXmlnsMappings.Resolve(_sreTypeSystem, _sreMappings);
+            if (_sreContextType == null)
+                _sreContextType = XamlIlContextDefinition.GenerateContextClass(
+                    _sreTypeSystem.CreateTypeBuilder(
+                        _sreBuilder.DefineType("XamlIlContext")), _sreTypeSystem, _sreMappings);
         }
 
 
-        static object LoadSre(string xaml, Assembly localAssembly, object rootInstance, Uri uri)
+        static object LoadSre(string xaml, Assembly localAssembly, object rootInstance, Uri uri, bool isDesignMode)
         {
             var success = false;
             try
             {
-                var rv = LoadSreCore(xaml, localAssembly, rootInstance, uri);
+                var rv = LoadSreCore(xaml, localAssembly, rootInstance, uri, isDesignMode);
                 success = true;
                 return rv;
             }
@@ -104,15 +109,15 @@ namespace Avalonia.Markup.Xaml.XamlIl
         }
 
         
-        static object LoadSreCore(string xaml, Assembly localAssembly, object rootInstance, Uri uri)
+        static object LoadSreCore(string xaml, Assembly localAssembly, object rootInstance, Uri uri, bool isDesignMode)
         {
 
             InitializeSre();
             var asm = localAssembly == null ? null : _sreTypeSystem.GetAssembly(localAssembly);
-            var contextType = _sreBuilder.DefineType("XamlIlContext");
+            
             var compiler = new AvaloniaXamlIlCompiler(new XamlIlTransformerConfiguration(_sreTypeSystem, asm,
                 _sreMappings, _sreXmlns, AvaloniaXamlIlLanguage.CustomValueConverter),
-                _sreTypeSystem.CreateTypeBuilder(contextType));
+                _sreContextType);
             var tb = _sreBuilder.DefineType("Builder_" + Guid.NewGuid().ToString("N") + "_" + uri);
 
             IXamlIlType overrideType = null;
@@ -121,6 +126,7 @@ namespace Avalonia.Markup.Xaml.XamlIl
                 overrideType = _sreTypeSystem.GetType(rootInstance.GetType());
             }
 
+            compiler.IsDesignMode = isDesignMode;
             compiler.ParseAndCompile(xaml, uri?.ToString(), null, _sreTypeSystem.CreateTypeBuilder(tb), overrideType);
             var created = tb.CreateTypeInfo();
 
@@ -151,7 +157,8 @@ namespace Avalonia.Markup.Xaml.XamlIl
             }
         }
         
-        public static object Load(Stream stream, Assembly localAssembly, object rootInstance, Uri uri)
+        public static object Load(Stream stream, Assembly localAssembly, object rootInstance, Uri uri,
+            bool isDesignMode)
         {
             string xaml;
             using (var sr = new StreamReader(stream))
@@ -159,7 +166,7 @@ namespace Avalonia.Markup.Xaml.XamlIl
 #if RUNTIME_XAML_CECIL
             return LoadCecil(xaml, localAssembly, rootInstance, uri);
 #else
-            return LoadSre(xaml, localAssembly, rootInstance, uri);
+            return LoadSre(xaml, localAssembly, rootInstance, uri, isDesignMode);
 #endif
         }
 

+ 14 - 2
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlCompiler.cs

@@ -1,3 +1,4 @@
+using System.Collections.Generic;
 using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers;
 using XamlIl;
 using XamlIl.Ast;
@@ -11,6 +12,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
     public class AvaloniaXamlIlCompiler : XamlIlCompiler
     {
         private readonly IXamlIlType _contextType;
+        private readonly AvaloniaXamlIlDesignPropertiesTransformer _designTransformer;
 
         private AvaloniaXamlIlCompiler(XamlIlTransformerConfiguration configuration) : base(configuration, true)
         {
@@ -18,6 +20,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
             
             Transformers.Insert(0, new XNameTransformer());
             Transformers.Insert(1, new IgnoredDirectivesTransformer());
+            Transformers.Insert(2, _designTransformer = new AvaloniaXamlIlDesignPropertiesTransformer());
             
             
             // Targeted
@@ -55,10 +58,19 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
         
         public const string PopulateName = "__AvaloniaXamlIlPopulate";
         public const string BuildName = "__AvaloniaXamlIlBuild";
-        
+
+        public bool IsDesignMode
+        {
+            get => _designTransformer.IsDesignMode;
+            set => _designTransformer.IsDesignMode = value;
+        }
+
         public void ParseAndCompile(string xaml, string baseUri, IFileSource fileSource, IXamlIlTypeBuilder tb, IXamlIlType overrideRootType)
         {
-            var parsed = XDocumentXamlIlParser.Parse(xaml);
+            var parsed = XDocumentXamlIlParser.Parse(xaml, new Dictionary<string, string>
+            {
+                {XamlNamespaces.Blend2008, XamlNamespaces.Blend2008}
+            });
             
             if (overrideRootType != null)
             {

+ 63 - 0
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlDesignPropertiesTransformer.cs

@@ -0,0 +1,63 @@
+using System.Collections.Generic;
+using System.Linq;
+using XamlIl;
+using XamlIl.Ast;
+using XamlIl.Transform;
+
+namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
+{
+    public class AvaloniaXamlIlDesignPropertiesTransformer : IXamlIlAstTransformer
+    {
+        public bool IsDesignMode { get; set; }
+
+        private static Dictionary<string, string> DesignDirectives = new Dictionary<string, string>()
+        {
+            ["DataContext"] = "DataContext",
+            ["DesignWidth"] = "Width", ["DesignHeight"] = "Height", ["PreviewWith"] = "PreviewWith"
+        };
+
+        private const string AvaloniaNs = "https://github.com/avaloniaui";
+        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
+        {
+            if (node is XamlIlAstObjectNode on)
+            {
+                for (var c=0; c<on.Children.Count;)
+                {
+                    var ch = on.Children[c];
+                    if (ch is XamlIlAstXmlDirective directive
+                        && directive.Namespace == XamlNamespaces.Blend2008
+                        && DesignDirectives.TryGetValue(directive.Name, out var mapTo))
+                    {
+                        if (!IsDesignMode)
+                            // Just remove it from AST in non-design mode
+                            on.Children.RemoveAt(c);
+                        else
+                        {
+                            // Map to an actual property in `Design` class
+                            on.Children[c] = new XamlIlAstXamlPropertyValueNode(ch,
+                                new XamlIlAstNamePropertyReference(ch,
+                                    new XamlIlAstXmlTypeReference(ch, AvaloniaNs, "Design"),
+                                    mapTo, on.Type), directive.Values);
+                            c++;
+                        }
+                    }
+                    // Remove all "Design" attached properties in non-design mode
+                    else if (
+                        !IsDesignMode
+                        && ch is XamlIlAstXamlPropertyValueNode pv
+                        && pv.Property is XamlIlAstNamePropertyReference pref
+                        && pref.DeclaringType is XamlIlAstXmlTypeReference dref
+                        && dref.XmlNamespace == AvaloniaNs && dref.Name == "Design"
+                    )
+                    {
+                        on.Children.RemoveAt(c);
+                    }
+                    else
+                        c++;
+                }
+            }
+
+            return node;
+        }
+    }
+}

+ 1 - 1
src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github

@@ -1 +1 @@
-Subproject commit c8b95cfa9da04dbf4afdd903c9aa76efefd59e42
+Subproject commit b318b6dcc67370f7ebea1e3c6741a0b6d4dd5db1

+ 10 - 3
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs

@@ -1,6 +1,7 @@
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
+using System;
 using Avalonia.Collections;
 using Avalonia.Controls;
 using Avalonia.Controls.Presenters;
@@ -17,6 +18,7 @@ using Portable.Xaml;
 using System.Collections;
 using System.ComponentModel;
 using System.Linq;
+using System.Xml;
 using Xunit;
 
 namespace Avalonia.Markup.Xaml.UnitTests.Xaml
@@ -61,6 +63,8 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
         [Fact]
         public void AvaloniaProperty_With_Getter_And_No_Setter_Is_Set()
         {
+            if(!AvaloniaXamlLoader.UseLegacyXamlLoader)
+                return;
             var xaml =
 @"<local:NonControl xmlns='https://github.com/avaloniaui' 
     xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.Xaml;assembly=Avalonia.Markup.Xaml.UnitTests'
@@ -142,14 +146,14 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
 
             Assert.Equal("Foo", ToolTip.GetTip(target));
         }
-
+        
         [Fact]
         public void NonExistent_Property_Throws()
         {
             var xaml =
         @"<ContentControl xmlns='https://github.com/avaloniaui' DoesntExist='foo'/>";
 
-            Assert.Throws<XamlObjectWriterException>(() => AvaloniaXamlLoader.Parse<ContentControl>(xaml));
+            XamlTestHelpers.AssertThrowsXamlException(() => AvaloniaXamlLoader.Parse<ContentControl>(xaml));
         }
 
         [Fact]
@@ -158,7 +162,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
             var xaml =
         @"<ContentControl xmlns='https://github.com/avaloniaui' TextBlock.Text='foo'/>";
 
-            Assert.Throws<XamlObjectWriterException>(() => AvaloniaXamlLoader.Parse<ContentControl>(xaml));
+            XamlTestHelpers.AssertThrowsXamlException(() => AvaloniaXamlLoader.Parse<ContentControl>(xaml));
         }
 
         [Fact]
@@ -587,6 +591,9 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
         [Fact]
         public void Xaml_Binding_Is_Delayed()
         {
+            if (!AvaloniaXamlLoader.UseLegacyXamlLoader)
+                return;
+            
             using (UnitTestApplication.Start(TestServices.MockWindowingPlatform))
             {
                 var xaml =

+ 4 - 1
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/EventTests.cs

@@ -31,12 +31,15 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
             var loader = new AvaloniaXamlLoader();
             var target = new MyButton();
 
-            Assert.Throws<XamlObjectWriterException>(() => loader.Load(xaml, rootInstance: target));
+            XamlTestHelpers.AssertThrowsXamlException(() => loader.Load(xaml, rootInstance: target));
         }
 
         [Fact]
         public void Exception_Is_Not_Thrown_If_Event_Not_Found_In_Design_Mode()
         {
+            // Runtime compiler should properly understand x:Class
+            if (!AvaloniaXamlLoader.UseLegacyXamlLoader)
+                return;
             var xaml = @"<Button xmlns='https://github.com/avaloniaui' Click='NotFound'/>";
             var loader = new AvaloniaXamlLoader { IsDesignMode = true };
             var target = new MyButton();

+ 23 - 0
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlTestHelpers.cs

@@ -0,0 +1,23 @@
+using System;
+using System.Xml;
+using Portable.Xaml;
+
+namespace Avalonia.Markup.Xaml.UnitTests.Xaml
+{
+    public class XamlTestHelpers
+    {
+        public static void AssertThrowsXamlException(Action cb)
+        {
+            try
+            {
+                cb();
+            }
+            catch (Exception e)
+            {
+                if(e is XamlObjectWriterException || e is XmlException)
+                    return;
+            }
+            throw new Exception("Expected to throw xaml exception");
+        }
+    }
+}

+ 1 - 1
tests/Avalonia.UnitTests/MockAssetLoader.cs

@@ -34,7 +34,7 @@ namespace Avalonia.UnitTests
 
         public Assembly GetAssembly(Uri uri, Uri baseUri = null)
         {
-            throw new NotImplementedException();
+            return null;
         }
 
         public IEnumerable<Uri> GetAssets(Uri uri, Uri baseUri)