From 4405d7970c5408400fa1132d45e0a375b1bc66ab Mon Sep 17 00:00:00 2001 From: Julien Lebosquain Date: Thu, 6 Jul 2023 16:33:32 +0200 Subject: [PATCH] Drop original internal XAML resources after merge --- .../XamlCompilerTaskExecutor.cs | 39 ++++++++++++------- .../AvaloniaXamlIlRuntimeCompiler.cs | 23 +++++++---- .../AvaloniaXamlIlCompiler.cs | 6 ++- .../XamlMergeResourceGroupTransformer.cs | 20 +++++----- .../IXamlDocumentResource.cs | 4 +- .../XamlDocumentResource.cs | 34 ++++++++++------ .../XamlDocumentTypeBuilderProvider.cs | 23 +++++++++++ .../CompilerExtensions/XamlDocumentUsage.cs | 8 ++++ 8 files changed, 111 insertions(+), 46 deletions(-) create mode 100644 src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentTypeBuilderProvider.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentUsage.cs diff --git a/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs b/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs index 1b611db62b..80876f1819 100644 --- a/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs +++ b/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() @@ -353,10 +353,16 @@ namespace Avalonia.Build.Tasks ((List)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 => diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaXamlIlRuntimeCompiler.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaXamlIlRuntimeCompiler.cs index e2aab7d685..995ed91b8d 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaXamlIlRuntimeCompiler.cs +++ b/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(); diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs index 23c67df810..af34d55a3d 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs +++ b/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 tb, IXamlMethodBuilder populateMethod, IXamlMethodBuilder 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, diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/GroupTransformers/XamlMergeResourceGroupTransformer.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/GroupTransformers/XamlMergeResourceGroupTransformer.cs index 8e04a7d467..f135ed5ffb 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/GroupTransformers/XamlMergeResourceGroupTransformer.cs +++ b/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(); - 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().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. diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/IXamlDocumentResource.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/IXamlDocumentResource.cs index b859b3ed59..9b5c59682f 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/IXamlDocumentResource.cs +++ b/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; } } diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentResource.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentResource.cs index 932fe067af..0dab80d743 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentResource.cs +++ b/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 _createTypeBuilderProvider; + private XamlDocumentTypeBuilderProvider? _typeBuilderProvider; + public XamlDocumentResource( XamlDocument xamlDocument, string? uri, IFileSource? fileSource, IXamlType? classType, bool isPublic, - IXamlTypeBuilder typeBuilder, - IXamlMethodBuilder populateMethod, - IXamlMethodBuilder? buildMethod) + Func 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 TypeBuilder { get; } - public IXamlMethodBuilder PopulateMethod { get; } - public IXamlMethodBuilder? 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; } diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentTypeBuilderProvider.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentTypeBuilderProvider.cs new file mode 100644 index 0000000000..4701403fb9 --- /dev/null +++ b/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 typeBuilder, + IXamlMethodBuilder populateMethod, + IXamlMethodBuilder? buildMethod) + { + TypeBuilder = typeBuilder; + PopulateMethod = populateMethod; + BuildMethod = buildMethod; + } + + public IXamlTypeBuilder TypeBuilder { get; } + public IXamlMethodBuilder PopulateMethod { get; } + public IXamlMethodBuilder? BuildMethod { get; } +} diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentUsage.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentUsage.cs new file mode 100644 index 0000000000..ec5b931548 --- /dev/null +++ b/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 +}