Browse Source

Drop original internal XAML resources after merge

Julien Lebosquain 2 years ago
parent
commit
4405d7970c

+ 26 - 13
src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs

@@ -304,7 +304,7 @@ namespace Avalonia.Build.Tasks
                                      || "Internal".Equals(classModifierText, StringComparison.OrdinalIgnoreCase))
                                 classModifierPublic = false;
                             else
-                                throw new XamlParseException("Invalid value for x:ClassModifier. Expected value are: Public, NotPublic (internal).", precompileDirective);
+                                throw new XamlParseException("Invalid value for x:ClassModifier. Expected value are: Public, NotPublic (internal).", classModifierDirective);
                         }
                         
                         var classDirective = initialRoot.Children.OfType<XamlAstXmlDirective>()
@@ -353,10 +353,16 @@ namespace Avalonia.Build.Tasks
                         ((List<XamlDocumentResource>)parsedXamlDocuments).Add(new XamlDocumentResource(
                             parsed, res.Uri, res, classType,
                             classModifierPublic.Value,
-                            populateBuilder,
-                            compiler.DefinePopulateMethod(populateBuilder, parsed, populateName,
-                                classTypeDefinition == null && classModifierPublic.Value),
-                            buildName == null ? null : compiler.DefineBuildMethod(builder, parsed, buildName, classModifierPublic.Value)));
+                            () => new XamlDocumentTypeBuilderProvider(
+                                populateBuilder,
+                                compiler.DefinePopulateMethod(
+                                    populateBuilder,
+                                    parsed,
+                                    populateName,
+                                    classTypeDefinition == null && classModifierPublic.Value),
+                                buildName == null ?
+                                    null :
+                                    compiler.DefineBuildMethod(builder, parsed, buildName, classModifierPublic.Value))));
                     }
                     catch (Exception e)
                     {
@@ -387,10 +393,17 @@ namespace Avalonia.Build.Tasks
 
                 foreach (var document in parsedXamlDocuments)
                 {
+                    var res = (IResource)document.FileSource!;
+
+                    if (document.Usage == XamlDocumentUsage.Merged && !document.IsPublic)
+                    {
+                        res.Remove();
+                        continue;
+                    }
+
                     var parsed = document.XamlDocument;
-                    var res = (IResource)document.FileSource;
                     var classType = document.ClassType;
-                    var populateBuilder = document.TypeBuilder;
+                    var populateBuilder = document.TypeBuilderProvider.TypeBuilder;
 
                     try
                     {
@@ -399,8 +412,8 @@ namespace Avalonia.Build.Tasks
 
                         compiler.Compile(parsed, 
                             contextClass,
-                            document.PopulateMethod,
-                            document.BuildMethod,
+                            document.TypeBuilderProvider.PopulateMethod,
+                            document.TypeBuilderProvider.BuildMethod,
                             builder.DefineSubType(compilerConfig.WellKnownTypes.Object, "NamespaceInfo:" + res.Name, true),
                             (closureName, closureBaseType) =>
                                 populateBuilder.DefineSubType(closureBaseType, closureName, false),
@@ -412,7 +425,7 @@ namespace Avalonia.Build.Tasks
                         if (classTypeDefinition != null)
                         {
                             var compiledPopulateMethod = typeSystem.GetTypeReference(populateBuilder).Resolve()
-                                .Methods.First(m => m.Name == document.PopulateMethod.Name);
+                                .Methods.First(m => m.Name == document.TypeBuilderProvider.PopulateMethod.Name);
 
                             var designLoaderFieldType = typeSystem
                                 .GetType("System.Action`1")
@@ -536,12 +549,12 @@ namespace Avalonia.Build.Tasks
                         }
 
                         if (document.IsPublic
-                            && (document.BuildMethod != null || classTypeDefinition != null))
+                            && (document.TypeBuilderProvider.BuildMethod != null || classTypeDefinition != null))
                         {
-                            var compiledBuildMethod = document.BuildMethod == null ?
+                            var compiledBuildMethod = document.TypeBuilderProvider.BuildMethod is not { } buildMethod ?
                                 null :
                                 typeSystem.GetTypeReference(builder).Resolve()
-                                    .Methods.First(m => m.Name == document.BuildMethod?.Name);
+                                    .Methods.First(m => m.Name == buildMethod.Name);
                             var parameterlessConstructor = compiledBuildMethod != null ?
                                 null :
                                 classTypeDefinition.GetConstructors().FirstOrDefault(c =>

+ 16 - 7
src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaXamlIlRuntimeCompiler.cs

@@ -1,5 +1,6 @@
 using System;
 using System.Collections.Generic;
+using System.Diagnostics;
 using System.Globalization;
 using System.IO;
 using System.Linq;
@@ -231,10 +232,19 @@ namespace Avalonia.Markup.Xaml.XamlIl
                                ?? ((IXamlAstValueNode)parsed.Root).Type.GetClrType().Name;
                 var tb = _sreBuilder.DefineType("Builder_" + Guid.NewGuid().ToString("N") + "_" + xamlName);
                 var builder = _sreTypeSystem.CreateTypeBuilder(tb);
-                parsedDocuments.Add(new XamlDocumentResource(parsed, document.BaseUri?.ToString(),
-                    null, null, true, builder,
-                    compiler.DefinePopulateMethod(builder, parsed, AvaloniaXamlIlCompiler.PopulateName, true),
-                    document.RootInstance is null ? compiler.DefineBuildMethod(builder, parsed, AvaloniaXamlIlCompiler.BuildName, true) : null));
+
+                parsedDocuments.Add(new XamlDocumentResource(
+                    parsed,
+                    document.BaseUri?.ToString(),
+                    null,
+                    null,
+                    true,
+                    () => new XamlDocumentTypeBuilderProvider(
+                        builder,
+                        compiler.DefinePopulateMethod(builder, parsed, AvaloniaXamlIlCompiler.PopulateName, true),
+                        document.RootInstance is null ?
+                            compiler.DefineBuildMethod(builder, parsed, AvaloniaXamlIlCompiler.BuildName, true) :
+                            null)));
                 originalDocuments.Add(document);
             }
 
@@ -242,9 +252,8 @@ namespace Avalonia.Markup.Xaml.XamlIl
 
             var createdTypes = parsedDocuments.Select(document =>
             {
-                compiler.Compile(document.XamlDocument, document.TypeBuilder, document.PopulateMethod,
-                    document.BuildMethod, document.Uri, document.FileSource);
-                return _sreTypeSystem.GetType(document.TypeBuilder.CreateType());
+                compiler.Compile(document.XamlDocument, document.TypeBuilderProvider, document.Uri, document.FileSource);
+                return _sreTypeSystem.GetType(document.TypeBuilderProvider.TypeBuilder.CreateType());
             }).ToArray();
             
             clrPropertyBuilder.CreateTypeInfo();

+ 4 - 2
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs

@@ -179,9 +179,11 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
             return parsed;
         }
 
-        public void Compile(XamlDocument document, IXamlTypeBuilder<IXamlILEmitter> tb, IXamlMethodBuilder<IXamlILEmitter> populateMethod, IXamlMethodBuilder<IXamlILEmitter> buildMethod, string baseUri, IFileSource fileSource)
+        public void Compile(XamlDocument document, XamlDocumentTypeBuilderProvider typeBuilderProvider, string baseUri, IFileSource fileSource)
         {
-            Compile(document, _contextType, populateMethod, buildMethod,
+            var tb = typeBuilderProvider.TypeBuilder;
+
+            Compile(document, _contextType, typeBuilderProvider.PopulateMethod, typeBuilderProvider.BuildMethod,
                 _configuration.TypeMappings.XmlNamespaceInfoProvider == null ?
                     null :
                     tb.DefineSubType(_configuration.WellKnownTypes.Object,

+ 10 - 10
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/GroupTransformers/XamlMergeResourceGroupTransformer.cs

@@ -3,8 +3,6 @@ using System.Collections.Generic;
 using System.Linq;
 using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers;
 using XamlX.Ast;
-using XamlX.IL.Emitters;
-using XamlX.Transform.Transformers;
 using XamlX.TypeSystem;
 
 namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.GroupTransformers;
@@ -24,7 +22,6 @@ internal class XamlMergeResourceGroupTransformer : IXamlAstGroupTransformer
 
         var mergeResourceIncludeType = context.GetAvaloniaTypes().MergeResourceInclude;
         var mergeSourceNodes = new List<XamlPropertyAssignmentNode>();
-        var mergedResourceWasAdded = false;
         foreach (var manipulationNode in resourceDictionaryManipulation.Children.ToArray())
         {
             void ProcessXamlPropertyAssignmentNode(XamlManipulationGroupNode parent, XamlPropertyAssignmentNode assignmentNode)
@@ -39,7 +36,6 @@ internal class XamlMergeResourceGroupTransformer : IXamlAstGroupTransformer
                         {
                             parent.Children.Remove(assignmentNode);
                             mergeSourceNodes.Add(sourceAssignmentNode);
-                            mergedResourceWasAdded = true;
                         }
                         else
                         {
@@ -85,25 +81,29 @@ internal class XamlMergeResourceGroupTransformer : IXamlAstGroupTransformer
                 return context.ParseError(
                     $"Node MergeResourceInclude is unable to resolve \"{originalAssetPath}\" path.", propertyNode, node);
             }
-            
+
             var targetDocument = context.Documents.FirstOrDefault(d =>
-                    string.Equals(d.Uri, originalAssetPath, StringComparison.InvariantCultureIgnoreCase))
-                ?.XamlDocument.Root as XamlValueWithManipulationNode;
-            if (targetDocument is null)
+                string.Equals(d.Uri, originalAssetPath, StringComparison.InvariantCultureIgnoreCase));
+            if (targetDocument?.XamlDocument.Root is not XamlValueWithManipulationNode targetDocumentRoot)
             {
                 return context.ParseError(
                     $"Node MergeResourceInclude is unable to resolve \"{originalAssetPath}\" path.", propertyNode, node);
             }
 
-            var singleRootObject = ((XamlManipulationGroupNode)targetDocument.Manipulation)
+            var singleRootObject = ((XamlManipulationGroupNode)targetDocumentRoot.Manipulation)
                 .Children.OfType<XamlObjectInitializationNode>().Single();
             if (singleRootObject.Type != resourceDictionaryType)
             {
                 return context.ParseError(
-                    $"MergeResourceInclude can only include another ResourceDictionary", propertyNode, node);
+                    "MergeResourceInclude can only include another ResourceDictionary", propertyNode, node);
             }
             
             manipulationGroup.Add(singleRootObject.Manipulation);
+
+            if (targetDocument.Usage == XamlDocumentUsage.Unknown)
+            {
+                targetDocument.Usage = XamlDocumentUsage.Merged;
+            }
         }
         
         // Order of resources is defined by ResourceDictionary.TryGetResource.

+ 2 - 2
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/IXamlDocumentResource.cs

@@ -1,5 +1,4 @@
-using System;
-using XamlX.Ast;
+using XamlX.Ast;
 using XamlX.TypeSystem;
 
 namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions;
@@ -14,4 +13,5 @@ internal interface IXamlDocumentResource
     IXamlMethod PopulateMethod { get; }
     IFileSource? FileSource { get; }
     XamlDocument XamlDocument { get; }
+    XamlDocumentUsage Usage { get; set; }
 }

+ 22 - 12
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentResource.cs

@@ -1,6 +1,5 @@
 using System;
 using XamlX.Ast;
-using XamlX.IL;
 using XamlX.TypeSystem;
 #nullable enable
 
@@ -8,24 +7,23 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions;
 
 internal class XamlDocumentResource : IXamlDocumentResource
 {
+    private readonly Func<XamlDocumentTypeBuilderProvider> _createTypeBuilderProvider;
+    private XamlDocumentTypeBuilderProvider? _typeBuilderProvider;
+
     public XamlDocumentResource(
         XamlDocument xamlDocument,
         string? uri,
         IFileSource? fileSource,
         IXamlType? classType,
         bool isPublic,
-        IXamlTypeBuilder<IXamlILEmitter> typeBuilder,
-        IXamlMethodBuilder<IXamlILEmitter> populateMethod,
-        IXamlMethodBuilder<IXamlILEmitter>? buildMethod)
+        Func<XamlDocumentTypeBuilderProvider> createTypeBuilderProvider)
     {
+        _createTypeBuilderProvider = createTypeBuilderProvider;
         XamlDocument = xamlDocument;
         Uri = uri;
         FileSource = fileSource;
         ClassType = classType;
         IsPublic = isPublic;
-        TypeBuilder = typeBuilder;
-        PopulateMethod = populateMethod;
-        BuildMethod = buildMethod;
     }
 
     public XamlDocument XamlDocument { get; }
@@ -34,10 +32,22 @@ internal class XamlDocumentResource : IXamlDocumentResource
 
     public IXamlType? ClassType { get; }
     public bool IsPublic { get; }
-    public IXamlTypeBuilder<IXamlILEmitter> TypeBuilder { get; }
-    public IXamlMethodBuilder<IXamlILEmitter> PopulateMethod { get; }
-    public IXamlMethodBuilder<IXamlILEmitter>? BuildMethod { get; }
+    public XamlDocumentUsage Usage { get; set; }
+
+    public XamlDocumentTypeBuilderProvider TypeBuilderProvider
+    {
+        get
+        {
+            if (_typeBuilderProvider is null)
+            {
+                _typeBuilderProvider = _createTypeBuilderProvider();
+                Usage = XamlDocumentUsage.Used;
+            }
+
+            return _typeBuilderProvider;
+        }
+    }
 
-    IXamlMethod? IXamlDocumentResource.BuildMethod => BuildMethod;
-    IXamlMethod IXamlDocumentResource.PopulateMethod => PopulateMethod;
+    IXamlMethod? IXamlDocumentResource.BuildMethod => TypeBuilderProvider.BuildMethod;
+    IXamlMethod IXamlDocumentResource.PopulateMethod => TypeBuilderProvider.PopulateMethod;
 }

+ 23 - 0
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentTypeBuilderProvider.cs

@@ -0,0 +1,23 @@
+#nullable enable
+
+using XamlX.IL;
+using XamlX.TypeSystem;
+
+namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions;
+
+internal sealed class XamlDocumentTypeBuilderProvider
+{
+    public XamlDocumentTypeBuilderProvider(
+        IXamlTypeBuilder<IXamlILEmitter> typeBuilder,
+        IXamlMethodBuilder<IXamlILEmitter> populateMethod,
+        IXamlMethodBuilder<IXamlILEmitter>? buildMethod)
+    {
+        TypeBuilder = typeBuilder;
+        PopulateMethod = populateMethod;
+        BuildMethod = buildMethod;
+    }
+
+    public IXamlTypeBuilder<IXamlILEmitter> TypeBuilder { get; }
+    public IXamlMethodBuilder<IXamlILEmitter> PopulateMethod { get; }
+    public IXamlMethodBuilder<IXamlILEmitter>? BuildMethod { get; }
+}

+ 8 - 0
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentUsage.cs

@@ -0,0 +1,8 @@
+namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions;
+
+internal enum XamlDocumentUsage
+{
+    Unknown,
+    Merged,
+    Used
+}