Browse Source

Drop original internal XAML resources after merge

pull/12074/head
Julien Lebosquain 3 years ago
parent
commit
4405d7970c
No known key found for this signature in database GPG Key ID: 1833CAD10ACC46FD
  1. 39
      src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
  2. 23
      src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaXamlIlRuntimeCompiler.cs
  3. 6
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs
  4. 20
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/GroupTransformers/XamlMergeResourceGroupTransformer.cs
  5. 4
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/IXamlDocumentResource.cs
  6. 34
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentResource.cs
  7. 23
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentTypeBuilderProvider.cs
  8. 8
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentUsage.cs

39
src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs

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

23
src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaXamlIlRuntimeCompiler.cs

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

6
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs

@ -179,9 +179,11 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
return parsed; 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 ? _configuration.TypeMappings.XmlNamespaceInfoProvider == null ?
null : null :
tb.DefineSubType(_configuration.WellKnownTypes.Object, tb.DefineSubType(_configuration.WellKnownTypes.Object,

20
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/GroupTransformers/XamlMergeResourceGroupTransformer.cs

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

4
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/IXamlDocumentResource.cs

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

34
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentResource.cs

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

23
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
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
}
Loading…
Cancel
Save