Browse Source

Trimmable runtime xaml loader (#12937)

* Add trimming attributes to the Runtime XAML Loader project

* Create CompilerDynamicDependenciesAttribute with all known dynamic types

* Use master XamlX

* Implement CompilerDynamicDependenciesGenerator to simplify CompilerDynamicDependencies attribute

* Better formatting of generated code

* Be safe about type converters as well

* Remove unnecessary warning

* Also include FindType just in case
release/11.0.5-rc1
Max Katz 3 years ago
committed by Dan Walmsley
parent
commit
2bfb008cd8
  1. 4
      src/Markup/Avalonia.Markup.Xaml.Loader/Avalonia.Markup.Xaml.Loader.csproj
  2. 12
      src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaRuntimeXamlLoader.cs
  3. 38
      src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaXamlIlRuntimeCompiler.cs
  4. 18
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerDynamicDependencies.cs
  5. 9
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs
  6. 20
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguage.cs
  7. 3
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs
  8. 1
      src/tools/Avalonia.Designer.HostApp/Avalonia.Designer.HostApp.csproj
  9. 3
      src/tools/Avalonia.Generators/Avalonia.Generators.csproj
  10. 77
      src/tools/DevGenerators/CompilerDynamicDependenciesGenerator.cs
  11. 3
      src/tools/DevGenerators/DevGenerators.csproj
  12. 8
      src/tools/DevGenerators/Properties/launchSettings.json

4
src/Markup/Avalonia.Markup.Xaml.Loader/Avalonia.Markup.Xaml.Loader.csproj

@ -3,7 +3,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks> <TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
<IsPackable>true</IsPackable> <IsPackable>true</IsPackable>
<DefineConstants>$(DefineConstants);XAMLX_INTERNAL</DefineConstants> <DefineConstants>$(DefineConstants);XAMLX_INTERNAL;XAML_RUNTIME_LOADER</DefineConstants>
</PropertyGroup> </PropertyGroup>
<!--Disable Net Perf. analyzer for submodule to avoid commit issue --> <!--Disable Net Perf. analyzer for submodule to avoid commit issue -->
<PropertyGroup> <PropertyGroup>
@ -21,4 +21,6 @@
<ProjectReference Include="..\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj" /> <ProjectReference Include="..\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj" />
</ItemGroup> </ItemGroup>
<Import Project="..\..\..\build\DevAnalyzers.props" /> <Import Project="..\..\..\build\DevAnalyzers.props" />
<Import Project="..\..\..\build\TrimmingEnable.props" />
<Import Project="..\..\..\build\SourceGenerators.props" />
</Project> </Project>

12
src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaRuntimeXamlLoader.cs

@ -1,9 +1,12 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO; using System.IO;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
using Avalonia.Markup.Xaml.XamlIl; using Avalonia.Markup.Xaml.XamlIl;
using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions;
#nullable enable #nullable enable
namespace Avalonia.Markup.Xaml namespace Avalonia.Markup.Xaml
{ {
@ -18,6 +21,7 @@ namespace Avalonia.Markup.Xaml
/// <param name="uri">The URI of the XAML being loaded.</param> /// <param name="uri">The URI of the XAML being loaded.</param>
/// <param name="designMode">Indicates whether the XAML is being loaded in design mode.</param> /// <param name="designMode">Indicates whether the XAML is being loaded in design mode.</param>
/// <returns>The loaded object.</returns> /// <returns>The loaded object.</returns>
[RequiresUnreferencedCode(XamlX.TrimmingMessages.DynamicXamlReference)]
public static object Load(string xaml, Assembly? localAssembly = null, object? rootInstance = null, Uri? uri = null, bool designMode = false) public static object Load(string xaml, Assembly? localAssembly = null, object? rootInstance = null, Uri? uri = null, bool designMode = false)
{ {
xaml = xaml ?? throw new ArgumentNullException(nameof(xaml)); xaml = xaml ?? throw new ArgumentNullException(nameof(xaml));
@ -37,6 +41,7 @@ namespace Avalonia.Markup.Xaml
/// <param name="uri">The URI of the XAML being loaded.</param> /// <param name="uri">The URI of the XAML being loaded.</param>
/// <param name="designMode">Indicates whether the XAML is being loaded in design mode.</param> /// <param name="designMode">Indicates whether the XAML is being loaded in design mode.</param>
/// <returns>The loaded object.</returns> /// <returns>The loaded object.</returns>
[RequiresUnreferencedCode(XamlX.TrimmingMessages.DynamicXamlReference)]
public static object Load(Stream stream, Assembly? localAssembly = null, object? rootInstance = null, Uri? uri = null, public static object Load(Stream stream, Assembly? localAssembly = null, object? rootInstance = null, Uri? uri = null,
bool designMode = false) bool designMode = false)
=> AvaloniaXamlIlRuntimeCompiler.Load(new RuntimeXamlLoaderDocument(uri, rootInstance, stream), => AvaloniaXamlIlRuntimeCompiler.Load(new RuntimeXamlLoaderDocument(uri, rootInstance, stream),
@ -48,6 +53,7 @@ namespace Avalonia.Markup.Xaml
/// <param name="document">The stream containing the XAML.</param> /// <param name="document">The stream containing the XAML.</param>
/// <param name="configuration">Xaml loader configuration.</param> /// <param name="configuration">Xaml loader configuration.</param>
/// <returns>The loaded object.</returns> /// <returns>The loaded object.</returns>
[RequiresUnreferencedCode(XamlX.TrimmingMessages.DynamicXamlReference)]
public static object Load(RuntimeXamlLoaderDocument document, RuntimeXamlLoaderConfiguration? configuration = null) public static object Load(RuntimeXamlLoaderDocument document, RuntimeXamlLoaderConfiguration? configuration = null)
=> AvaloniaXamlIlRuntimeCompiler.Load(document, configuration ?? new RuntimeXamlLoaderConfiguration()); => AvaloniaXamlIlRuntimeCompiler.Load(document, configuration ?? new RuntimeXamlLoaderConfiguration());
@ -57,6 +63,7 @@ namespace Avalonia.Markup.Xaml
/// <param name="documents">Collection of documents.</param> /// <param name="documents">Collection of documents.</param>
/// <param name="configuration">Xaml loader configuration.</param> /// <param name="configuration">Xaml loader configuration.</param>
/// <returns>The loaded objects per each input document. If document was removed, the element by index is null.</returns> /// <returns>The loaded objects per each input document. If document was removed, the element by index is null.</returns>
[RequiresUnreferencedCode(XamlX.TrimmingMessages.DynamicXamlReference)]
public static IReadOnlyList<object?> LoadGroup(IReadOnlyCollection<RuntimeXamlLoaderDocument> documents, RuntimeXamlLoaderConfiguration? configuration = null) public static IReadOnlyList<object?> LoadGroup(IReadOnlyCollection<RuntimeXamlLoaderDocument> documents, RuntimeXamlLoaderConfiguration? configuration = null)
=> AvaloniaXamlIlRuntimeCompiler.LoadGroup(documents, configuration ?? new RuntimeXamlLoaderConfiguration()); => AvaloniaXamlIlRuntimeCompiler.LoadGroup(documents, configuration ?? new RuntimeXamlLoaderConfiguration());
@ -66,6 +73,7 @@ namespace Avalonia.Markup.Xaml
/// <param name="xaml">The string containing the XAML.</param> /// <param name="xaml">The string containing the XAML.</param>
/// <param name="localAssembly">Default assembly for clr-namespace:.</param> /// <param name="localAssembly">Default assembly for clr-namespace:.</param>
/// <returns>The loaded object.</returns> /// <returns>The loaded object.</returns>
[RequiresUnreferencedCode(XamlX.TrimmingMessages.DynamicXamlReference)]
public static object Parse(string xaml, Assembly? localAssembly = null) public static object Parse(string xaml, Assembly? localAssembly = null)
=> Load(xaml, localAssembly); => Load(xaml, localAssembly);
@ -76,8 +84,8 @@ namespace Avalonia.Markup.Xaml
/// <param name="xaml">>The string containing the XAML.</param> /// <param name="xaml">>The string containing the XAML.</param>
/// <param name="localAssembly">>Default assembly for clr-namespace:.</param> /// <param name="localAssembly">>Default assembly for clr-namespace:.</param>
/// <returns>The loaded object.</returns> /// <returns>The loaded object.</returns>
public static T Parse<T>(string xaml, Assembly? localAssembly = null) [RequiresUnreferencedCode(XamlX.TrimmingMessages.DynamicXamlReference)]
public static T Parse<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>(string xaml, Assembly? localAssembly = null)
=> (T)Parse(xaml, localAssembly); => (T)Parse(xaml, localAssembly);
} }
} }

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

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@ -11,6 +12,7 @@ using System.Runtime.InteropServices;
using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions; using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions;
using Avalonia.Markup.Xaml.XamlIl.Runtime; using Avalonia.Markup.Xaml.XamlIl.Runtime;
using Avalonia.Platform; using Avalonia.Platform;
using XamlX;
using XamlX.Ast; using XamlX.Ast;
using XamlX.Transform; using XamlX.Transform;
using XamlX.TypeSystem; using XamlX.TypeSystem;
@ -22,9 +24,13 @@ using Mono.Cecil;
using XamlX.Ast; using XamlX.Ast;
using XamlX.IL.Cecil; using XamlX.IL.Cecil;
#endif #endif
namespace Avalonia.Markup.Xaml.XamlIl namespace Avalonia.Markup.Xaml.XamlIl
{ {
static class AvaloniaXamlIlRuntimeCompiler #if !RUNTIME_XAML_CECIL
[RequiresUnreferencedCode(XamlX.TrimmingMessages.DynamicXamlReference)]
#endif
internal static class AvaloniaXamlIlRuntimeCompiler
{ {
#if !RUNTIME_XAML_CECIL #if !RUNTIME_XAML_CECIL
private static SreTypeSystem _sreTypeSystem; private static SreTypeSystem _sreTypeSystem;
@ -37,6 +43,7 @@ namespace Avalonia.Markup.Xaml.XamlIl
private static AssemblyBuilder _sreAsm; private static AssemblyBuilder _sreAsm;
private static bool _sreCanSave; private static bool _sreCanSave;
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = XamlX.TrimmingMessages.CanBeSafelyTrimmed)]
public static void DumpRuntimeCompilationResults() public static void DumpRuntimeCompilationResults()
{ {
if (_sreBuilder == null) if (_sreBuilder == null)
@ -55,7 +62,9 @@ namespace Avalonia.Markup.Xaml.XamlIl
//Ignore //Ignore
} }
} }
[CompilerDynamicDependencies]
[UnconditionalSuppressMessage("Trimming", "IL2072", Justification = XamlX.TrimmingMessages.GeneratedTypes)]
static void InitializeSre() static void InitializeSre()
{ {
if (_sreTypeSystem == null) if (_sreTypeSystem == null)
@ -66,10 +75,7 @@ namespace Avalonia.Markup.Xaml.XamlIl
var name = new AssemblyName(Guid.NewGuid().ToString("N")); var name = new AssemblyName(Guid.NewGuid().ToString("N"));
if (_sreCanSave) if (_sreCanSave)
{ {
var define = AppDomain.CurrentDomain.GetType().GetMethods() var define = GetDefineDynamicAssembly();
.FirstOrDefault(m => m.Name == "DefineDynamicAssembly"
&& m.GetParameters().Length == 3 &&
m.GetParameters()[2].ParameterType == typeof(string));
if (define != null) if (define != null)
_sreAsm = (AssemblyBuilder)define.Invoke(AppDomain.CurrentDomain, new object[] _sreAsm = (AssemblyBuilder)define.Invoke(AppDomain.CurrentDomain, new object[]
{ {
@ -101,6 +107,12 @@ namespace Avalonia.Markup.Xaml.XamlIl
_ignoresAccessChecksFromAttribute = EmitIgnoresAccessCheckAttributeDefinition(_sreBuilder); _ignoresAccessChecksFromAttribute = EmitIgnoresAccessCheckAttributeDefinition(_sreBuilder);
} }
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = XamlX.TrimmingMessages.CanBeSafelyTrimmed)]
static MethodInfo GetDefineDynamicAssembly() => AppDomain.CurrentDomain.GetType().GetMethods()
.FirstOrDefault(m => m.Name == "DefineDynamicAssembly"
&& m.GetParameters().Length == 3 &&
m.GetParameters()[2].ParameterType == typeof(string));
static Type EmitIgnoresAccessCheckAttributeDefinition(ModuleBuilder builder) static Type EmitIgnoresAccessCheckAttributeDefinition(ModuleBuilder builder)
{ {
var tb = builder.DefineType("System.Runtime.CompilerServices.IgnoresAccessChecksToAttribute", var tb = builder.DefineType("System.Runtime.CompilerServices.IgnoresAccessChecksToAttribute",
@ -138,6 +150,7 @@ namespace Avalonia.Markup.Xaml.XamlIl
return tb.CreateTypeInfo(); return tb.CreateTypeInfo();
} }
[UnconditionalSuppressMessage("Trimming", "IL2080", Justification = XamlX.TrimmingMessages.GeneratedTypes)]
static void EmitIgnoresAccessCheckToAttribute(AssemblyName assemblyName) static void EmitIgnoresAccessCheckToAttribute(AssemblyName assemblyName)
{ {
var name = assemblyName.Name; var name = assemblyName.Name;
@ -150,7 +163,6 @@ namespace Avalonia.Markup.Xaml.XamlIl
_ignoresAccessChecksFromAttribute.GetConstructors()[0], _ignoresAccessChecksFromAttribute.GetConstructors()[0],
new object[] { name })); new object[] { name }));
} }
static object LoadSre(RuntimeXamlLoaderDocument document, RuntimeXamlLoaderConfiguration configuration) static object LoadSre(RuntimeXamlLoaderDocument document, RuntimeXamlLoaderConfiguration configuration)
{ {
@ -184,7 +196,8 @@ namespace Avalonia.Markup.Xaml.XamlIl
DumpRuntimeCompilationResults(); DumpRuntimeCompilationResults();
} }
} }
[UnconditionalSuppressMessage("Trimming", "IL2072", Justification = XamlX.TrimmingMessages.GeneratedTypes)]
static IReadOnlyList<object> LoadGroupSreCore(IReadOnlyCollection<RuntimeXamlLoaderDocument> documents, RuntimeXamlLoaderConfiguration configuration) static IReadOnlyList<object> LoadGroupSreCore(IReadOnlyCollection<RuntimeXamlLoaderDocument> documents, RuntimeXamlLoaderConfiguration configuration)
{ {
InitializeSre(); InitializeSre();
@ -264,14 +277,16 @@ namespace Avalonia.Markup.Xaml.XamlIl
.Select(t => LoadOrPopulate(t.Item1, t.Item2.RootInstance, t.Item2.ServiceProvider)) .Select(t => LoadOrPopulate(t.Item1, t.Item2.RootInstance, t.Item2.ServiceProvider))
.ToArray(); .ToArray();
} }
static object LoadSreCore(RuntimeXamlLoaderDocument document, RuntimeXamlLoaderConfiguration configuration) static object LoadSreCore(RuntimeXamlLoaderDocument document, RuntimeXamlLoaderConfiguration configuration)
{ {
return LoadGroupSreCore(new[] { document }, configuration).Single(); return LoadGroupSreCore(new[] { document }, configuration).Single();
} }
#endif #endif
static object LoadOrPopulate(Type created, object rootInstance, IServiceProvider parentServiceProvider) [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = XamlX.TrimmingMessages.GeneratedTypes)]
[UnconditionalSuppressMessage("Trimming", "IL2072", Justification = XamlX.TrimmingMessages.GeneratedTypes)]
static object LoadOrPopulate([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type created, object rootInstance, IServiceProvider parentServiceProvider)
{ {
var isp = Expression.Parameter(typeof(IServiceProvider)); var isp = Expression.Parameter(typeof(IServiceProvider));
@ -317,7 +332,7 @@ namespace Avalonia.Markup.Xaml.XamlIl
return rootInstance; return rootInstance;
} }
} }
public static object Load(RuntimeXamlLoaderDocument document, RuntimeXamlLoaderConfiguration configuration) public static object Load(RuntimeXamlLoaderDocument document, RuntimeXamlLoaderConfiguration configuration)
{ {
#if RUNTIME_XAML_CECIL #if RUNTIME_XAML_CECIL
@ -364,6 +379,7 @@ namespace Avalonia.Markup.Xaml.XamlIl
private static XamlIlXmlnsMappings _cecilXmlns; private static XamlIlXmlnsMappings _cecilXmlns;
private static bool _cecilInitialized; private static bool _cecilInitialized;
[CompilerDynamicDependencies]
static void InitializeCecil() static void InitializeCecil()
{ {
if(_cecilInitialized) if(_cecilInitialized)

18
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerDynamicDependencies.cs

@ -0,0 +1,18 @@
using System;
using System.Diagnostics.CodeAnalysis;
// WARNING: this is a partial class, second part of which is generated by CompilerDynamicDependenciesGenerator.
namespace Avalonia.Markup.Xaml.XamlIl;
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
internal sealed partial class CompilerDynamicDependenciesAttribute : Attribute
{
public const DynamicallyAccessedMemberTypes XamlDynamicallyAccessedMemberTypes = DynamicallyAccessedMemberTypes.All ^
(DynamicallyAccessedMemberTypes.NonPublicConstructors
| DynamicallyAccessedMemberTypes.NonPublicEvents
| DynamicallyAccessedMemberTypes.NonPublicFields
| DynamicallyAccessedMemberTypes.NonPublicMethods
| DynamicallyAccessedMemberTypes.NonPublicProperties
| DynamicallyAccessedMemberTypes.NonPublicNestedTypes);
}

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

@ -1,4 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.GroupTransformers; using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.GroupTransformers;
using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers; using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers;
@ -143,6 +144,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
} }
} }
#if !XAMLX_CECIL_INTERNAL
[RequiresUnreferencedCode(XamlX.TrimmingMessages.DynamicXamlReference)]
#endif
public XamlDocument Parse(string xaml, IXamlType overrideRootType) public XamlDocument Parse(string xaml, IXamlType overrideRootType)
{ {
var parsed = XDocumentXamlParser.Parse(xaml, new Dictionary<string, string> var parsed = XDocumentXamlParser.Parse(xaml, new Dictionary<string, string>
@ -191,7 +195,10 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
(s, returnType, parameters) => tb.DefineDelegateSubType(s, false, returnType, parameters), baseUri, (s, returnType, parameters) => tb.DefineDelegateSubType(s, false, returnType, parameters), baseUri,
fileSource); fileSource);
} }
#if !XAMLX_CECIL_INTERNAL
[RequiresUnreferencedCode(XamlX.TrimmingMessages.DynamicXamlReference)]
#endif
public void ParseAndCompile(string xaml, string baseUri, IFileSource fileSource, IXamlTypeBuilder<IXamlILEmitter> tb, IXamlType overrideRootType) public void ParseAndCompile(string xaml, string baseUri, IFileSource fileSource, IXamlTypeBuilder<IXamlILEmitter> tb, IXamlType overrideRootType)
{ {
var parsed = Parse(xaml, overrideRootType); var parsed = Parse(xaml, overrideRootType);

20
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguage.cs

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using Avalonia.Controls; using Avalonia.Controls;
@ -120,21 +121,18 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
void AddType(IXamlType type, IXamlType conv) void AddType(IXamlType type, IXamlType conv)
=> _converters.Add(new KeyValuePair<IXamlType, IXamlType>(type, conv)); => _converters.Add(new KeyValuePair<IXamlType, IXamlType>(type, conv));
void Add(string type, string conv)
=> AddType(typeSystem.GetType(type), typeSystem.GetType(conv));
Add("Avalonia.Media.IImage","Avalonia.Markup.Xaml.Converters.BitmapTypeConverter"); AddType(typeSystem.GetType("Avalonia.Media.IImage"), typeSystem.GetType("Avalonia.Markup.Xaml.Converters.BitmapTypeConverter"));
Add("Avalonia.Media.Imaging.Bitmap","Avalonia.Markup.Xaml.Converters.BitmapTypeConverter"); AddType(typeSystem.GetType("Avalonia.Media.Imaging.Bitmap"), typeSystem.GetType("Avalonia.Markup.Xaml.Converters.BitmapTypeConverter"));
Add("Avalonia.Media.IImageBrushSource","Avalonia.Markup.Xaml.Converters.BitmapTypeConverter"); AddType(typeSystem.GetType("Avalonia.Media.IImageBrushSource"), typeSystem.GetType("Avalonia.Markup.Xaml.Converters.BitmapTypeConverter"));
var ilist = typeSystem.GetType("System.Collections.Generic.IList`1"); var ilist = typeSystem.GetType("System.Collections.Generic.IList`1");
AddType(ilist.MakeGenericType(typeSystem.GetType("Avalonia.Point")), AddType(ilist.MakeGenericType(typeSystem.GetType("Avalonia.Point")),
typeSystem.GetType("Avalonia.Markup.Xaml.Converters.PointsListTypeConverter")); typeSystem.GetType("Avalonia.Markup.Xaml.Converters.PointsListTypeConverter"));
Add("Avalonia.Controls.WindowIcon","Avalonia.Markup.Xaml.Converters.IconTypeConverter"); AddType(typeSystem.GetType("Avalonia.Controls.WindowIcon"), typeSystem.GetType("Avalonia.Markup.Xaml.Converters.IconTypeConverter"));
Add("System.Globalization.CultureInfo", "System.ComponentModel.CultureInfoConverter"); AddType(typeSystem.GetType("System.Globalization.CultureInfo"), typeSystem.GetType( "System.ComponentModel.CultureInfoConverter"));
Add("System.Uri", "Avalonia.Markup.Xaml.Converters.AvaloniaUriTypeConverter"); AddType(typeSystem.GetType("System.Uri"), typeSystem.GetType( "Avalonia.Markup.Xaml.Converters.AvaloniaUriTypeConverter"));
Add("System.TimeSpan", "Avalonia.Markup.Xaml.Converters.TimeSpanTypeConverter"); AddType(typeSystem.GetType("System.TimeSpan"), typeSystem.GetType( "Avalonia.Markup.Xaml.Converters.TimeSpanTypeConverter"));
Add("Avalonia.Media.FontFamily","Avalonia.Markup.Xaml.Converters.FontFamilyTypeConverter"); AddType(typeSystem.GetType("Avalonia.Media.FontFamily"), typeSystem.GetType("Avalonia.Markup.Xaml.Converters.FontFamilyTypeConverter"));
_avaloniaList = typeSystem.GetType("Avalonia.Collections.AvaloniaList`1"); _avaloniaList = typeSystem.GetType("Avalonia.Collections.AvaloniaList`1");
_avaloniaListConverter = typeSystem.GetType("Avalonia.Collections.AvaloniaListConverter`1"); _avaloniaListConverter = typeSystem.GetType("Avalonia.Collections.AvaloniaListConverter`1");
} }

3
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs

@ -1,4 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.GroupTransformers; using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.GroupTransformers;
using XamlX.Emit; using XamlX.Emit;
@ -203,7 +204,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
ThemeVariant = cfg.TypeSystem.GetType("Avalonia.Styling.ThemeVariant"); ThemeVariant = cfg.TypeSystem.GetType("Avalonia.Styling.ThemeVariant");
WindowTransparencyLevel = cfg.TypeSystem.GetType("Avalonia.Controls.WindowTransparencyLevel"); WindowTransparencyLevel = cfg.TypeSystem.GetType("Avalonia.Controls.WindowTransparencyLevel");
(IXamlType, IXamlConstructor) GetNumericTypeInfo(string name, IXamlType componentType, int componentCount) (IXamlType, IXamlConstructor) GetNumericTypeInfo([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] string name, IXamlType componentType, int componentCount)
{ {
var type = cfg.TypeSystem.GetType(name); var type = cfg.TypeSystem.GetType(name);
var ctor = type.GetConstructor(Enumerable.Range(0, componentCount).Select(_ => componentType).ToList()); var ctor = type.GetConstructor(Enumerable.Range(0, componentCount).Select(_ => componentType).ToList());

1
src/tools/Avalonia.Designer.HostApp/Avalonia.Designer.HostApp.csproj

@ -18,6 +18,7 @@
<ItemGroup> <ItemGroup>
<Compile Include="..\..\..\src\Markup\Avalonia.Markup.Xaml.Loader\CompilerExtensions\**\*.cs" /> <Compile Include="..\..\..\src\Markup\Avalonia.Markup.Xaml.Loader\CompilerExtensions\**\*.cs" />
<Compile Include="..\..\..\src\Markup\Avalonia.Markup.Xaml.Loader\AvaloniaXamlIlRuntimeCompiler.cs" /> <Compile Include="..\..\..\src\Markup\Avalonia.Markup.Xaml.Loader\AvaloniaXamlIlRuntimeCompiler.cs" />
<Compile Include="..\..\..\src\Markup\Avalonia.Markup.Xaml.Loader\CompilerDynamicDependencies.cs" />
<Compile Include="..\..\Avalonia.Base\Utilities\StringBuilderCache.cs" Link="Utilities\StringBuilderCache.cs" /> <Compile Include="..\..\Avalonia.Base\Utilities\StringBuilderCache.cs" Link="Utilities\StringBuilderCache.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

3
src/tools/Avalonia.Generators/Avalonia.Generators.csproj

@ -19,7 +19,8 @@
<Compile Link="Compiler\XamlX\filename" Include="../../Markup/Avalonia.Markup.Xaml.Loader/xamlil.github/src/XamlX/**/*.cs" /> <Compile Link="Compiler\XamlX\filename" Include="../../Markup/Avalonia.Markup.Xaml.Loader/xamlil.github/src/XamlX/**/*.cs" />
<Compile Remove="../../Markup/Avalonia.Markup.Xaml.Loader/xamlil.github/src/XamlX/obj/**/*.cs" /> <Compile Remove="../../Markup/Avalonia.Markup.Xaml.Loader/xamlil.github/src/XamlX/obj/**/*.cs" />
<Compile Remove="../../Markup/Avalonia.Markup.Xaml.Loader/xamlil.github/src/XamlX/**/SreTypeSystem.cs" /> <Compile Remove="../../Markup/Avalonia.Markup.Xaml.Loader/xamlil.github/src/XamlX/**/SreTypeSystem.cs" />
<Compile Include="..\..\Shared\IsExternalInit.cs" Link="IsExternalInit.cs" /> <Compile Include="..\..\Shared\IsExternalInit.cs" Link="IsExternalInit.cs" Visible="False" />
<Compile Include="..\..\Avalonia.Base\Compatibility\TrimmingAttributes.cs" Link="TrimmingAttributes.cs" Visible="False" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

77
src/tools/DevGenerators/CompilerDynamicDependenciesGenerator.cs

@ -0,0 +1,77 @@
using System.Linq;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace DevGenerators;
[Generator(LanguageNames.CSharp)]
public class CompilerDynamicDependenciesGenerator : IIncrementalGenerator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
var invocationSyntaxes = context.SyntaxProvider
.CreateSyntaxProvider(
static (s, _) => s is InvocationExpressionSyntax inv && inv.Expression is MemberAccessExpressionSyntax
{
Name: { Identifier: { Text: "GetType" or "FindType" } }
} && inv.ArgumentList.Arguments.Count == 1 && inv.ArgumentList.Arguments[0].Expression is LiteralExpressionSyntax,
static (context, _) => (InvocationExpressionSyntax)context.Node!);
context.RegisterSourceOutput(invocationSyntaxes.Collect(), static (context, invocations) =>
{
var types = invocations
.Select(t => t.ArgumentList.Arguments[0].GetText().ToString())
.Distinct()
.Select(t => t
.Replace("\"", "")
.Replace("`1", "<>")
.Replace("`2", "<,>")
.Replace("`3", "<,,>")
.Replace("`4", "<,,,>"))
.OrderBy(t => t)
.ToArray();
if (types.Length == 0)
{
return;
}
var attributesBuilder = new StringBuilder();
attributesBuilder.AppendLine("""
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by CompilerDynamicDependenciesGenerator source generator.
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.Diagnostics.CodeAnalysis;
#if XAML_RUNTIME_LOADER
namespace Avalonia.Markup.Xaml.XamlIl
{
internal sealed partial class CompilerDynamicDependenciesAttribute
{
""");
foreach (var type in types)
{
if (type is "System.Void" or "XamlX.XamlDebugHatch"
|| type.StartsWith("CompiledAvaloniaXaml"))
{
continue;
}
attributesBuilder.AppendFormat(
" [DynamicDependency(XamlDynamicallyAccessedMemberTypes, typeof({0}))]", type);
attributesBuilder.AppendLine();
}
attributesBuilder.AppendLine("""
public CompilerDynamicDependenciesAttribute() {}
}
}
#endif
""");
var str = attributesBuilder.ToString();
context.AddSource("CompilerDynamicDependenciesAttribute.generated.cs", attributesBuilder.ToString());
});
}
}

3
src/tools/DevGenerators/DevGenerators.csproj

@ -1,10 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
<EnforceExtendedAnalyzerRules>True</EnforceExtendedAnalyzerRules> <EnforceExtendedAnalyzerRules>True</EnforceExtendedAnalyzerRules>
<IsRoslynComponent>true</IsRoslynComponent>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

8
src/tools/DevGenerators/Properties/launchSettings.json

@ -0,0 +1,8 @@
{
"profiles": {
"Profile 1": {
"commandName": "DebugRoslynComponent",
"targetProject": "..\\..\\Markup\\Avalonia.Markup.Xaml.Loader\\Avalonia.Markup.Xaml.Loader.csproj"
}
}
}
Loading…
Cancel
Save