Browse Source

Nullable annotations for projects using XamlX (#15796)

* Nullable annotations for projects using XamlX

* Update .NET SDK

* Update XamlX to latest master

* Use ILRepack tool instead of submodule

* Fix build

---------

Co-authored-by: Max Katz <maxkatz6@outlook.com>
pull/16539/head
Julien Lebosquain 2 years ago
committed by GitHub
parent
commit
d1bd85e9b8
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 3
      .gitmodules
  2. 2
      global.json
  3. 6
      nukebuild/Build.cs
  4. 34
      nukebuild/BuildTasksPatcher.cs
  5. 4
      nukebuild/_build.csproj
  6. 1
      nukebuild/il-repack
  7. 162
      src/Avalonia.Base/Compatibility/NullableAttributes.cs
  8. 21
      src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj
  9. 2
      src/Avalonia.Controls.ColorPicker/Avalonia.Controls.ColorPicker.csproj
  10. 1
      src/Markup/Avalonia.Markup.Xaml.Loader/Avalonia.Markup.Xaml.Loader.csproj
  11. 58
      src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaXamlIlRuntimeCompiler.cs
  12. 4
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AstNodes/AvaloniaXamlIlFontFamilyAstNode.cs
  13. 8
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs
  14. 13
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompilerConfiguration.cs
  15. 50
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguage.cs
  16. 29
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguageParseIntrinsics.cs
  17. 7
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/GroupTransformers/IXamlAstGroupTransformer.cs
  18. 4
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/GroupTransformers/XamlIncludeGroupTransformer.cs
  19. 3
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/GroupTransformers/XamlMergeResourceGroupTransformer.cs
  20. 10
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AddNameScopeRegistration.cs
  21. 5
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaBindingExtensionTransformer.cs
  22. 32
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlBindingPathParser.cs
  23. 12
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlBindingPathTransformer.cs
  24. 2
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlClassesPropertyResolver.cs
  25. 24
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlDataContextTypeTransformer.cs
  26. 6
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlDeferredResourceTransformer.cs
  27. 4
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlEnsureResourceDictionaryCapacityTransformer.cs
  28. 33
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlOptionMarkupExtensionTransformer.cs
  29. 35
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlPropertyPathTransformer.cs
  30. 4
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlReorderClassesPropertiesTransformer.cs
  31. 4
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlRootObjectScopeTransformer.cs
  32. 72
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSelectorTransformer.cs
  33. 26
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs
  34. 3
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlThemeVariantProviderTransformer.cs
  35. 14
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlTransformInstanceAttachedProperties.cs
  36. 31
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs
  37. 2
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Visitors/NameScopeRegistrationVisitor.cs
  38. 43
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs
  39. 99
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlBindingPathHelper.cs
  40. 23
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlClrPropertyInfoHelper.cs
  41. 4
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlPropertyInfoAccessorFactoryEmitter.cs
  42. 4
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlTrampolineBuilder.cs
  43. 2
      src/Markup/Avalonia.Markup.Xaml.Loader/xamlil.github
  44. 2
      src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs
  45. 3
      src/tools/Avalonia.Designer.HostApp/Avalonia.Designer.HostApp.csproj
  46. 6
      src/tools/Avalonia.Designer.HostApp/DesignXamlLoader.cs
  47. 12
      src/tools/Avalonia.Generators/Avalonia.Generators.csproj
  48. 2
      src/tools/Avalonia.Generators/Common/Domain/IViewResolver.cs
  49. 16
      src/tools/Avalonia.Generators/Common/XamlXViewResolver.cs
  50. 63
      src/tools/Avalonia.Generators/Compiler/RoslynTypeSystem.cs
  51. 2
      src/tools/Avalonia.Generators/GeneratorContextExtensions.cs
  52. 2
      src/tools/Avalonia.Generators/NameGenerator/AvaloniaNameSourceGenerator.cs
  53. 3
      tests/Avalonia.Generators.Tests/InitializeComponent/InitializeComponentTests.cs
  54. 3
      tests/Avalonia.Generators.Tests/OnlyProperties/OnlyPropertiesTests.cs
  55. 1
      tests/Avalonia.Generators.Tests/XamlXClassResolverTests.cs
  56. 1
      tests/Avalonia.Generators.Tests/XamlXNameResolverTests.cs

3
.gitmodules

@ -4,6 +4,3 @@
[submodule "src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github"] [submodule "src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github"]
path = src/Markup/Avalonia.Markup.Xaml.Loader/xamlil.github path = src/Markup/Avalonia.Markup.Xaml.Loader/xamlil.github
url = https://github.com/kekekeks/XamlX.git url = https://github.com/kekekeks/XamlX.git
[submodule "nukebuild/il-repack"]
path = nukebuild/il-repack
url = https://github.com/Gillibald/il-repack

2
global.json

@ -1,6 +1,6 @@
{ {
"sdk": { "sdk": {
"version": "8.0.101", "version": "8.0.204",
"rollForward": "latestFeature" "rollForward": "latestFeature"
}, },
"msbuild-sdks": { "msbuild-sdks": {

6
nukebuild/Build.cs

@ -40,7 +40,8 @@ partial class Build : NukeBuild
[PackageExecutable("Microsoft.DotNet.GenAPI.Tool", "Microsoft.DotNet.GenAPI.Tool.dll", Framework = "net8.0")] [PackageExecutable("Microsoft.DotNet.GenAPI.Tool", "Microsoft.DotNet.GenAPI.Tool.dll", Framework = "net8.0")]
Tool ApiGenTool; Tool ApiGenTool;
[PackageExecutable("dotnet-ilrepack", "ILRepackTool.dll", Framework = "net8.0")]
Tool IlRepackTool;
protected override void OnBuildInitialized() protected override void OnBuildInitialized()
{ {
@ -307,7 +308,8 @@ partial class Build : NukeBuild
.Executes(() => .Executes(() =>
{ {
BuildTasksPatcher.PatchBuildTasksInPackage(Parameters.NugetIntermediateRoot / "Avalonia.Build.Tasks." + BuildTasksPatcher.PatchBuildTasksInPackage(Parameters.NugetIntermediateRoot / "Avalonia.Build.Tasks." +
Parameters.Version + ".nupkg"); Parameters.Version + ".nupkg",
IlRepackTool);
var config = Numerge.MergeConfiguration.LoadFile(RootDirectory / "nukebuild" / "numerge.config"); var config = Numerge.MergeConfiguration.LoadFile(RootDirectory / "nukebuild" / "numerge.config");
EnsureCleanDirectory(Parameters.NugetRoot); EnsureCleanDirectory(Parameters.NugetRoot);
if(!Numerge.NugetPackageMerger.Merge(Parameters.NugetIntermediateRoot, Parameters.NugetRoot, config, if(!Numerge.NugetPackageMerger.Merge(Parameters.NugetIntermediateRoot, Parameters.NugetRoot, config,

34
nukebuild/BuildTasksPatcher.cs

@ -2,9 +2,9 @@ using System;
using System.IO; using System.IO;
using System.IO.Compression; using System.IO.Compression;
using System.Linq; using System.Linq;
using ILRepacking;
using Mono.Cecil; using Mono.Cecil;
using Mono.Cecil.Cil; using Mono.Cecil.Cil;
using Nuke.Common.Tooling;
public class BuildTasksPatcher public class BuildTasksPatcher
{ {
@ -56,7 +56,7 @@ public class BuildTasksPatcher
return null; return null;
} }
public static void PatchBuildTasksInPackage(string packagePath) public static void PatchBuildTasksInPackage(string packagePath, Tool ilRepackTool)
{ {
using (var archive = new ZipArchive(File.Open(packagePath, FileMode.Open, FileAccess.ReadWrite), using (var archive = new ZipArchive(File.Open(packagePath, FileMode.Open, FileAccess.ReadWrite),
ZipArchiveMode.Update)) ZipArchiveMode.Update))
@ -70,7 +70,7 @@ public class BuildTasksPatcher
Directory.CreateDirectory(tempDir); Directory.CreateDirectory(tempDir);
var temp = Path.Combine(tempDir, entry.Name); var temp = Path.Combine(tempDir, entry.Name);
var output = temp + ".output"; var output = temp + ".output";
File.Copy(typeof(Microsoft.Build.Framework.ITask).Assembly.GetModules()[0].FullyQualifiedName, File.Copy(GetAssemblyPath(typeof(Microsoft.Build.Framework.ITask)),
Path.Combine(tempDir, "Microsoft.Build.Framework.dll")); Path.Combine(tempDir, "Microsoft.Build.Framework.dll"));
var patched = new MemoryStream(); var patched = new MemoryStream();
try try
@ -78,22 +78,15 @@ public class BuildTasksPatcher
entry.ExtractToFile(temp, true); entry.ExtractToFile(temp, true);
// Get Original SourceLinkInfo Content // Get Original SourceLinkInfo Content
var sourceLinkInfoContent = GetSourceLinkInfo(temp); var sourceLinkInfoContent = GetSourceLinkInfo(temp);
var repack = new ILRepacking.ILRepack(new RepackOptions()
{ var cecilAsm = GetAssemblyPath(typeof(Mono.Cecil.AssemblyDefinition));
Internalize = true, var cecilRocksAsm = GetAssemblyPath(typeof(Mono.Cecil.Rocks.MethodBodyRocks));
InputAssemblies = new[] var cecilPdbAsm = GetAssemblyPath(typeof(Mono.Cecil.Pdb.PdbReaderProvider));
{ var cecilMdbAsm = GetAssemblyPath(typeof(Mono.Cecil.Mdb.MdbReaderProvider));
temp,
typeof(Mono.Cecil.AssemblyDefinition).Assembly.GetModules()[0].FullyQualifiedName, ilRepackTool.Invoke(
typeof(Mono.Cecil.Rocks.MethodBodyRocks).Assembly.GetModules()[0].FullyQualifiedName, $"/internalize /out:\"{output}\" \"{temp}\" \"{cecilAsm}\" \"{cecilRocksAsm}\" \"{cecilPdbAsm}\" \"{cecilMdbAsm}\"",
typeof(Mono.Cecil.Pdb.PdbReaderProvider).Assembly.GetModules()[0].FullyQualifiedName, tempDir);
typeof(Mono.Cecil.Mdb.MdbReaderProvider).Assembly.GetModules()[0].FullyQualifiedName,
},
SearchDirectories = Array.Empty<string>(),
DebugInfo = true, // Allowed read debug info
OutputFile = output
});
repack.Repack();
// 'hurr-durr assembly with the same name is already loaded' prevention // 'hurr-durr assembly with the same name is already loaded' prevention
using (var asm = AssemblyDefinition.ReadAssembly(output, using (var asm = AssemblyDefinition.ReadAssembly(output,
@ -161,4 +154,7 @@ public class BuildTasksPatcher
} }
} }
} }
private static string GetAssemblyPath(Type typeInAssembly)
=> typeInAssembly.Assembly.GetModules()[0].FullyQualifiedName;
} }

4
nukebuild/_build.csproj

@ -20,7 +20,6 @@
<PackageReference Include="MicroCom.CodeGenerator" Version="0.11.0" /> <PackageReference Include="MicroCom.CodeGenerator" Version="0.11.0" />
<!-- Keep in sync with Avalonia.Build.Tasks --> <!-- Keep in sync with Avalonia.Build.Tasks -->
<PackageReference Include="Mono.Cecil" Version="0.11.5" /> <PackageReference Include="Mono.Cecil" Version="0.11.5" />
<PackageReference Include="Microsoft.Debugging.Tools.PdbStr" Version="20230731.1609.0" GeneratePathProperty="true" PrivateAssets="All"/>
<PackageReference Include="Microsoft.Build.Framework" Version="17.3.2" PrivateAssets="All" /> <PackageReference Include="Microsoft.Build.Framework" Version="17.3.2" PrivateAssets="All" />
<PackageReference Include="xunit.runner.console" Version="2.4.2"> <PackageReference Include="xunit.runner.console" Version="2.4.2">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
@ -29,6 +28,7 @@
<PackageDownload Include="Microsoft.DotNet.ApiCompat.Tool" Version="[8.0.200]" /> <PackageDownload Include="Microsoft.DotNet.ApiCompat.Tool" Version="[8.0.200]" />
<PackageDownload Include="Microsoft.DotNet.GenAPI.Tool" Version="[8.0.300-preview.24115.44]" /> <PackageDownload Include="Microsoft.DotNet.GenAPI.Tool" Version="[8.0.300-preview.24115.44]" />
<PackageDownload Include="dotnet-ilrepack" Version="[1.0.0]" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@ -38,9 +38,7 @@
<!-- Common build related files --> <!-- Common build related files -->
<Compile Remove="Numerge/**/*.*" /> <Compile Remove="Numerge/**/*.*" />
<Compile Include="Numerge/Numerge/**/*.cs" Exclude="Numerge/Numerge/obj/**/*.cs" /> <Compile Include="Numerge/Numerge/**/*.cs" Exclude="Numerge/Numerge/obj/**/*.cs" />
<EmbeddedResource Include="$(PkgMicrosoft_Debugging_Tools_PdbStr)/content/x86/pdbstr.exe" />
<EmbeddedResource Include="../build/avalonia.snk" /> <EmbeddedResource Include="../build/avalonia.snk" />
<Compile Remove="il-repack\ILRepack\Application.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

1
nukebuild/il-repack

@ -1 +0,0 @@
Subproject commit 892f079ea8cb0c178f0a68f53a7a7eac13acdda9

162
src/Avalonia.Base/Metadata/NullableAttributes.cs → src/Avalonia.Base/Compatibility/NullableAttributes.cs

@ -1,63 +1,30 @@
#pragma warning disable MA0048 // File name must match type name // https://raw.githubusercontent.com/dotnet/runtime/753648476b64946b8f5f4d25e1294adbabd3165b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullableAttributes.cs
#define INTERNAL_NULLABLE_ATTRIBUTES
// https://github.com/dotnet/corefx/blob/48363ac826ccf66fbe31a5dcb1dc2aab9a7dd768/src/Common/src/CoreLib/System/Diagnostics/CodeAnalysis/NullableAttributes.cs
// Licensed to the .NET Foundation under one or more agreements. // Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license. // The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace System.Diagnostics.CodeAnalysis namespace System.Diagnostics.CodeAnalysis
{ {
#if NETSTANDARD2_0 || NETCOREAPP2_0 || NETCOREAPP2_1 || NETCOREAPP2_2 || NET45 || NET451 || NET452 || NET6 || NET461 || NET462 || NET47 || NET471 || NET472 || NET48 #if !NET6_0_OR_GREATER
/// <summary>Specifies that null is allowed as an input even if the corresponding type disallows it.</summary> /// <summary>Specifies that null is allowed as an input even if the corresponding type disallows it.</summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)]
#if INTERNAL_NULLABLE_ATTRIBUTES internal sealed class AllowNullAttribute : Attribute { }
internal
#else
public
#endif
sealed class AllowNullAttribute : Attribute
{ }
/// <summary>Specifies that null is disallowed as an input even if the corresponding type allows it.</summary> /// <summary>Specifies that null is disallowed as an input even if the corresponding type allows it.</summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)]
#if INTERNAL_NULLABLE_ATTRIBUTES internal sealed class DisallowNullAttribute : Attribute { }
internal
#else
public
#endif
sealed class DisallowNullAttribute : Attribute
{ }
/// <summary>Specifies that an output may be null even if the corresponding type disallows it.</summary> /// <summary>Specifies that an output may be null even if the corresponding type disallows it.</summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)]
#if INTERNAL_NULLABLE_ATTRIBUTES internal sealed class MaybeNullAttribute : Attribute { }
internal
#else
public
#endif
sealed class MaybeNullAttribute : Attribute
{ }
/// <summary>Specifies that an output will not be null even if the corresponding type allows it.</summary> /// <summary>Specifies that an output will not be null even if the corresponding type allows it. Specifies that an input argument was not null when the call returns.</summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)]
#if INTERNAL_NULLABLE_ATTRIBUTES internal sealed class NotNullAttribute : Attribute { }
internal
#else
public
#endif
sealed class NotNullAttribute : Attribute
{ }
/// <summary>Specifies that when a method returns <see cref="ReturnValue"/>, the parameter may be null even if the corresponding type disallows it.</summary> /// <summary>Specifies that when a method returns <see cref="ReturnValue"/>, the parameter may be null even if the corresponding type disallows it.</summary>
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)] [AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
#if INTERNAL_NULLABLE_ATTRIBUTES internal sealed class MaybeNullWhenAttribute : Attribute
internal
#else
public
#endif
sealed class MaybeNullWhenAttribute : Attribute
{ {
/// <summary>Initializes the attribute with the specified return value condition.</summary> /// <summary>Initializes the attribute with the specified return value condition.</summary>
/// <param name="returnValue"> /// <param name="returnValue">
@ -71,12 +38,7 @@ namespace System.Diagnostics.CodeAnalysis
/// <summary>Specifies that when a method returns <see cref="ReturnValue"/>, the parameter will not be null even if the corresponding type allows it.</summary> /// <summary>Specifies that when a method returns <see cref="ReturnValue"/>, the parameter will not be null even if the corresponding type allows it.</summary>
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)] [AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
#if INTERNAL_NULLABLE_ATTRIBUTES internal sealed class NotNullWhenAttribute : Attribute
internal
#else
public
#endif
sealed class NotNullWhenAttribute : Attribute
{ {
/// <summary>Initializes the attribute with the specified return value condition.</summary> /// <summary>Initializes the attribute with the specified return value condition.</summary>
/// <param name="returnValue"> /// <param name="returnValue">
@ -90,12 +52,7 @@ namespace System.Diagnostics.CodeAnalysis
/// <summary>Specifies that the output will be non-null if the named parameter is non-null.</summary> /// <summary>Specifies that the output will be non-null if the named parameter is non-null.</summary>
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)] [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)]
#if INTERNAL_NULLABLE_ATTRIBUTES internal sealed class NotNullIfNotNullAttribute : Attribute
internal
#else
public
#endif
sealed class NotNullIfNotNullAttribute : Attribute
{ {
/// <summary>Initializes the attribute with the associated parameter name.</summary> /// <summary>Initializes the attribute with the associated parameter name.</summary>
/// <param name="parameterName"> /// <param name="parameterName">
@ -109,22 +66,11 @@ namespace System.Diagnostics.CodeAnalysis
/// <summary>Applied to a method that will never return under any circumstance.</summary> /// <summary>Applied to a method that will never return under any circumstance.</summary>
[AttributeUsage(AttributeTargets.Method, Inherited = false)] [AttributeUsage(AttributeTargets.Method, Inherited = false)]
#if INTERNAL_NULLABLE_ATTRIBUTES internal sealed class DoesNotReturnAttribute : Attribute { }
internal
#else
public
#endif
sealed class DoesNotReturnAttribute : Attribute
{ }
/// <summary>Specifies that the method will not return if the associated Boolean parameter is passed the specified value.</summary> /// <summary>Specifies that the method will not return if the associated Boolean parameter is passed the specified value.</summary>
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)] [AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
#if INTERNAL_NULLABLE_ATTRIBUTES internal sealed class DoesNotReturnIfAttribute : Attribute
internal
#else
public
#endif
sealed class DoesNotReturnIfAttribute : Attribute
{ {
/// <summary>Initializes the attribute with the specified parameter value.</summary> /// <summary>Initializes the attribute with the specified parameter value.</summary>
/// <param name="parameterValue"> /// <param name="parameterValue">
@ -136,82 +82,62 @@ namespace System.Diagnostics.CodeAnalysis
/// <summary>Gets the condition parameter value.</summary> /// <summary>Gets the condition parameter value.</summary>
public bool ParameterValue { get; } public bool ParameterValue { get; }
} }
#endif // NETSTANDARD2_0 attributes
#if NETSTANDARD2_1 || NETSTANDARD2_0 || NETCOREAPP2_0 || NETCOREAPP2_1 || NETCOREAPP2_2 || NETCOREAPP3_1 || NET45 || NET451 || NET452 || NET6 || NET461 || NET462 || NET47 || NET471 || NET472 || NET48 /// <summary>Specifies that the method or property will ensure that the listed field and property members have not-null values.</summary>
/// <summary>
/// Specifies that the method or property will ensure that the listed field and property members have
/// not-<see langword="null"/> values.
/// </summary>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
#if INTERNAL_NULLABLE_ATTRIBUTES internal sealed class MemberNotNullAttribute : Attribute
internal
#else
public
#endif
sealed class MemberNotNullAttribute : Attribute
{ {
/// <summary>Gets field or property member names.</summary>
public string[] Members { get; }
/// <summary>Initializes the attribute with a field or property member.</summary> /// <summary>Initializes the attribute with a field or property member.</summary>
/// <param name="member">The field or property member that is promised to be not-null.</param> /// <param name="member">
public MemberNotNullAttribute(string member) /// The field or property member that is promised to be not-null.
{ /// </param>
Members = new[] { member }; public MemberNotNullAttribute(string member) => Members = [member];
}
/// <summary>Initializes the attribute with the list of field and property members.</summary> /// <summary>Initializes the attribute with the list of field and property members.</summary>
/// <param name="members">The list of field and property members that are promised to be not-null.</param> /// <param name="members">
public MemberNotNullAttribute(params string[] members) /// The list of field and property members that are promised to be not-null.
{ /// </param>
Members = members; public MemberNotNullAttribute(params string[] members) => Members = members;
}
}
/// <summary>
/// Specifies that the method or property will ensure that the listed field and property members have
/// non-<see langword="null"/> values when returning with the specified return value condition.
/// </summary>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
#if INTERNAL_NULLABLE_ATTRIBUTES
internal
#else
public
#endif
sealed class MemberNotNullWhenAttribute : Attribute
{
/// <summary>Gets the return value condition.</summary>
public bool ReturnValue { get; }
/// <summary>Gets field or property member names.</summary> /// <summary>Gets field or property member names.</summary>
public string[] Members { get; } public string[] Members { get; }
}
/// <summary>Specifies that the method or property will ensure that the listed field and property members have not-null values when returning with the specified return value condition.</summary>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
internal sealed class MemberNotNullWhenAttribute : Attribute
{
/// <summary>Initializes the attribute with the specified return value condition and a field or property member.</summary> /// <summary>Initializes the attribute with the specified return value condition and a field or property member.</summary>
/// <param name="returnValue"> /// <param name="returnValue">
/// The return value condition. If the method returns this value, /// The return value condition. If the method returns this value, the associated parameter will not be null.
/// the associated parameter will not be <see langword="null"/>. /// </param>
/// <param name="member">
/// The field or property member that is promised to be not-null.
/// </param> /// </param>
/// <param name="member">The field or property member that is promised to be not-<see langword="null"/>.</param>
public MemberNotNullWhenAttribute(bool returnValue, string member) public MemberNotNullWhenAttribute(bool returnValue, string member)
{ {
ReturnValue = returnValue; ReturnValue = returnValue;
Members = new[] { member }; Members = [member];
} }
/// <summary>Initializes the attribute with the specified return value condition and list of field and property members. /// <summary>Initializes the attribute with the specified return value condition and list of field and property members.</summary>
/// </summary>
/// <param name="returnValue"> /// <param name="returnValue">
/// The return value condition. If the method returns this value, /// The return value condition. If the method returns this value, the associated parameter will not be null.
/// the associated parameter will not be <see langword="null"/>. /// </param>
/// <param name="members">
/// The list of field and property members that are promised to be not-null.
/// </param> /// </param>
/// <param name="members">The list of field and property members that are promised to be not-null.</param>
public MemberNotNullWhenAttribute(bool returnValue, params string[] members) public MemberNotNullWhenAttribute(bool returnValue, params string[] members)
{ {
ReturnValue = returnValue; ReturnValue = returnValue;
Members = members; Members = members;
} }
/// <summary>Gets the return value condition.</summary>
public bool ReturnValue { get; }
/// <summary>Gets field or property member names.</summary>
public string[] Members { get; }
} }
#endif // NETSTANDARD2_1 attributes #endif
} }

21
src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj

@ -1,6 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.0</TargetFrameworks> <TargetFramework>netstandard2.0</TargetFramework>
<Nullable>enable</Nullable>
<GenerateDocumentationFile>false</GenerateDocumentationFile> <GenerateDocumentationFile>false</GenerateDocumentationFile>
<BuildOutputTargetFolder>tools</BuildOutputTargetFolder> <BuildOutputTargetFolder>tools</BuildOutputTargetFolder>
<DefineConstants>$(DefineConstants);BUILDTASK;XAMLX_CECIL_INTERNAL;XAMLX_INTERNAL</DefineConstants> <DefineConstants>$(DefineConstants);BUILDTASK;XAMLX_CECIL_INTERNAL;XAMLX_INTERNAL</DefineConstants>
@ -114,16 +115,18 @@
<Compile Include="../Avalonia.Base/RelativePoint.cs"> <Compile Include="../Avalonia.Base/RelativePoint.cs">
<Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link> <Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link>
</Compile> </Compile>
<Compile Include="..\Avalonia.Base\Metadata\NullableAttributes.cs" Link="NullableAttributes.cs" /> <Compile Include="../Avalonia.Base/Compatibility/NullableAttributes.cs" Link="Compatibility/NullableAttributes.cs" />
<Compile Include="..\Avalonia.Base\Compatibility\TrimmingAttributes.cs" Link="TrimmingAttributes.cs" Visible="False" /> <Compile Include="../Avalonia.Base/Compatibility/TrimmingAttributes.cs" Link="Compatibility/TrimmingAttributes.cs" />
<Compile Include="..\Avalonia.Base\Utilities\SpanHelpers.cs" Link="Utilities\SpanHelpers.cs" /> <Compile Include="../Avalonia.Base/Utilities/SpanHelpers.cs" Link="Utilities/SpanHelpers.cs" />
<Compile Include="..\Shared\StringCompatibilityExtensions.cs" Link="Compatibility\StringCompatibilityExtensions.cs" /> <Compile Include="../Shared/StringCompatibilityExtensions.cs" Link="Compatibility/StringCompatibilityExtensions.cs" />
<Compile Include="..\Shared\IsExternalInit.cs" Link="Compatibility\IsExternalInit.cs" /> <Compile Include="../Shared/IsExternalInit.cs" Link="Compatibility/IsExternalInit.cs" />
<Compile Remove="../Markup/Avalonia.Markup.Xaml.Loader\xamlil.github\**\obj\**\*.cs" /> <Compile Remove="../Markup/Avalonia.Markup.Xaml.Loader/xamlil.github/**/obj/**/*.cs" />
<Compile Remove="../Markup/Avalonia.Markup.Xaml.Loader\xamlil.github\src\XamlX\IL\SreTypeSystem.cs" /> <Compile Remove="../Markup/Avalonia.Markup.Xaml.Loader/xamlil.github/src/XamlX/Compatibility/*.cs" />
<Compile Remove="../Markup/Avalonia.Markup.Xaml.Loader/xamlil.github/src/XamlX/IL/SreTypeSystem.cs" />
<PackageReference Include="Mono.Cecil" Version="0.11.5" /> <PackageReference Include="Mono.Cecil" Version="0.11.5" />
<PackageReference Include="Microsoft.Build.Framework" Version="15.1.548" PrivateAssets="All" /> <PackageReference Include="Microsoft.Build.Framework" Version="15.1.548" PrivateAssets="All" />
<PackageReference Include="System.Numerics.Vectors" Version="4.5.0" /> <PackageReference Include="System.Numerics.Vectors" Version="4.5.0" />
</ItemGroup> </ItemGroup>
<Import Project="..\..\build\SourceGenerators.props" /> <Import Project="../../build/SourceGenerators.props" />
<Import Project="../../build/NullableEnable.props" />
</Project> </Project>

2
src/Avalonia.Controls.ColorPicker/Avalonia.Controls.ColorPicker.csproj

@ -4,7 +4,7 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Compile Include="..\Avalonia.Base\Metadata\NullableAttributes.cs" Link="NullableAttributes.cs" /> <Compile Include="..\Avalonia.Base\Compatibility\NullableAttributes.cs" Link="NullableAttributes.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Avalonia.Base\Avalonia.Base.csproj" /> <ProjectReference Include="..\Avalonia.Base\Avalonia.Base.csproj" />

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

@ -14,4 +14,5 @@
<Import Project="..\..\..\build\DevAnalyzers.props" /> <Import Project="..\..\..\build\DevAnalyzers.props" />
<Import Project="..\..\..\build\TrimmingEnable.props" /> <Import Project="..\..\..\build\TrimmingEnable.props" />
<Import Project="..\..\..\build\SourceGenerators.props" /> <Import Project="..\..\..\build\SourceGenerators.props" />
<Import Project="..\..\..\build\NullableEnable.props" />
</Project> </Project>

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

@ -33,14 +33,14 @@ namespace Avalonia.Markup.Xaml.XamlIl
internal static class AvaloniaXamlIlRuntimeCompiler internal static class AvaloniaXamlIlRuntimeCompiler
{ {
#if !RUNTIME_XAML_CECIL #if !RUNTIME_XAML_CECIL
private static SreTypeSystem _sreTypeSystem; private static SreTypeSystem? _sreTypeSystem;
private static Type _ignoresAccessChecksFromAttribute; private static Type? _ignoresAccessChecksFromAttribute;
private static ModuleBuilder _sreBuilder; private static ModuleBuilder? _sreBuilder;
private static IXamlType _sreContextType; private static IXamlType? _sreContextType;
private static XamlLanguageTypeMappings _sreMappings; private static XamlLanguageTypeMappings? _sreMappings;
private static XamlLanguageEmitMappings<IXamlILEmitter, XamlILNodeEmitResult> _sreEmitMappings; private static XamlLanguageEmitMappings<IXamlILEmitter, XamlILNodeEmitResult>? _sreEmitMappings;
private static XamlXmlnsMappings _sreXmlns; private static XamlXmlnsMappings? _sreXmlns;
private static AssemblyBuilder _sreAsm; private static AssemblyBuilder? _sreAsm;
private static bool _sreCanSave; private static bool _sreCanSave;
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = XamlX.TrimmingMessages.CanBeSafelyTrimmed)] [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = XamlX.TrimmingMessages.CanBeSafelyTrimmed)]
@ -48,7 +48,7 @@ namespace Avalonia.Markup.Xaml.XamlIl
{ {
if (_sreBuilder == null) if (_sreBuilder == null)
return; return;
var saveMethod = _sreAsm.GetType().GetMethods() var saveMethod = _sreAsm!.GetType().GetMethods()
.FirstOrDefault(m => m.Name == "Save" && m.GetParameters().Length == 1); .FirstOrDefault(m => m.Name == "Save" && m.GetParameters().Length == 1);
if (saveMethod == null) if (saveMethod == null)
return; return;
@ -65,6 +65,13 @@ namespace Avalonia.Markup.Xaml.XamlIl
[CompilerDynamicDependencies] [CompilerDynamicDependencies]
[UnconditionalSuppressMessage("Trimming", "IL2072", Justification = XamlX.TrimmingMessages.GeneratedTypes)] [UnconditionalSuppressMessage("Trimming", "IL2072", Justification = XamlX.TrimmingMessages.GeneratedTypes)]
[MemberNotNull(nameof(_sreTypeSystem))]
[MemberNotNull(nameof(_sreBuilder))]
[MemberNotNull(nameof(_sreMappings))]
[MemberNotNull(nameof(_sreEmitMappings))]
[MemberNotNull(nameof(_sreXmlns))]
[MemberNotNull(nameof(_sreContextType))]
[MemberNotNull(nameof(_ignoresAccessChecksFromAttribute))]
static void InitializeSre() static void InitializeSre()
{ {
if (_sreTypeSystem == null) if (_sreTypeSystem == null)
@ -81,8 +88,8 @@ namespace Avalonia.Markup.Xaml.XamlIl
{ {
name, (AssemblyBuilderAccess)3, name, (AssemblyBuilderAccess)3,
Path.GetDirectoryName(typeof(AvaloniaXamlIlRuntimeCompiler).Assembly.GetModules()[0] Path.GetDirectoryName(typeof(AvaloniaXamlIlRuntimeCompiler).Assembly.GetModules()[0]
.FullyQualifiedName) .FullyQualifiedName)!
}); })!;
else else
_sreCanSave = false; _sreCanSave = false;
} }
@ -94,7 +101,7 @@ namespace Avalonia.Markup.Xaml.XamlIl
_sreBuilder = _sreAsm.DefineDynamicModule("XamlIlLoader.ildump"); _sreBuilder = _sreAsm.DefineDynamicModule("XamlIlLoader.ildump");
} }
if (_sreMappings == null) if (_sreMappings is null || _sreEmitMappings is null)
(_sreMappings, _sreEmitMappings) = AvaloniaXamlIlLanguage.Configure(_sreTypeSystem); (_sreMappings, _sreEmitMappings) = AvaloniaXamlIlLanguage.Configure(_sreTypeSystem);
if (_sreXmlns == null) if (_sreXmlns == null)
_sreXmlns = XamlXmlnsMappings.Resolve(_sreTypeSystem, _sreMappings); _sreXmlns = XamlXmlnsMappings.Resolve(_sreTypeSystem, _sreMappings);
@ -108,7 +115,7 @@ namespace Avalonia.Markup.Xaml.XamlIl
} }
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = XamlX.TrimmingMessages.CanBeSafelyTrimmed)] [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = XamlX.TrimmingMessages.CanBeSafelyTrimmed)]
static MethodInfo GetDefineDynamicAssembly() => AppDomain.CurrentDomain.GetType().GetMethods() static MethodInfo? GetDefineDynamicAssembly() => AppDomain.CurrentDomain.GetType().GetMethods()
.FirstOrDefault(m => m.Name == "DefineDynamicAssembly" .FirstOrDefault(m => m.Name == "DefineDynamicAssembly"
&& m.GetParameters().Length == 3 && && m.GetParameters().Length == 3 &&
m.GetParameters()[2].ParameterType == typeof(string)); m.GetParameters()[2].ParameterType == typeof(string));
@ -142,12 +149,12 @@ namespace Avalonia.Markup.Xaml.XamlIl
ctorIl.Emit(OpCodes.Ret); ctorIl.Emit(OpCodes.Ret);
tb.SetCustomAttribute(new CustomAttributeBuilder( tb.SetCustomAttribute(new CustomAttributeBuilder(
typeof(AttributeUsageAttribute).GetConstructor(new[] { typeof(AttributeTargets) }), typeof(AttributeUsageAttribute).GetConstructor(new[] { typeof(AttributeTargets) })!,
new object[] { AttributeTargets.Assembly }, new object[] { AttributeTargets.Assembly },
new[] { typeof(AttributeUsageAttribute).GetProperty("AllowMultiple") }, new[] { typeof(AttributeUsageAttribute).GetProperty(nameof(AttributeUsageAttribute.AllowMultiple))! },
new object[] { true })); new object[] { true }));
return tb.CreateTypeInfo(); return tb.CreateTypeInfo()!;
} }
[UnconditionalSuppressMessage("Trimming", "IL2080", Justification = XamlX.TrimmingMessages.GeneratedTypes)] [UnconditionalSuppressMessage("Trimming", "IL2080", Justification = XamlX.TrimmingMessages.GeneratedTypes)]
@ -159,8 +166,8 @@ namespace Avalonia.Markup.Xaml.XamlIl
var key = assemblyName.GetPublicKey(); var key = assemblyName.GetPublicKey();
if (key != null && key.Length != 0) if (key != null && key.Length != 0)
name += ", PublicKey=" + BitConverter.ToString(key).Replace("-", "").ToUpperInvariant(); name += ", PublicKey=" + BitConverter.ToString(key).Replace("-", "").ToUpperInvariant();
_sreAsm.SetCustomAttribute(new CustomAttributeBuilder( _sreAsm!.SetCustomAttribute(new CustomAttributeBuilder(
_ignoresAccessChecksFromAttribute.GetConstructors()[0], _ignoresAccessChecksFromAttribute!.GetConstructors()[0],
new object[] { name })); new object[] { name }));
} }
@ -267,7 +274,7 @@ namespace Avalonia.Markup.Xaml.XamlIl
using (var sr = new StreamReader(document.XamlStream)) using (var sr = new StreamReader(document.XamlStream))
xaml = sr.ReadToEnd(); xaml = sr.ReadToEnd();
IXamlType overrideType = null; IXamlType? overrideType = null;
if (document.RootInstance != null) if (document.RootInstance != null)
{ {
overrideType = _sreTypeSystem.GetType(document.RootInstance.GetType()); overrideType = _sreTypeSystem.GetType(document.RootInstance.GetType());
@ -326,13 +333,16 @@ namespace Avalonia.Markup.Xaml.XamlIl
[UnconditionalSuppressMessage("Trimming", "IL2075", Justification = XamlX.TrimmingMessages.GeneratedTypes)] [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = XamlX.TrimmingMessages.GeneratedTypes)]
[UnconditionalSuppressMessage("Trimming", "IL2072", Justification = XamlX.TrimmingMessages.GeneratedTypes)] [UnconditionalSuppressMessage("Trimming", "IL2072", Justification = XamlX.TrimmingMessages.GeneratedTypes)]
static object LoadOrPopulate([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type created, object rootInstance, IServiceProvider parentServiceProvider) static object LoadOrPopulate(
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type created,
object? rootInstance,
IServiceProvider? parentServiceProvider)
{ {
var isp = Expression.Parameter(typeof(IServiceProvider)); var isp = Expression.Parameter(typeof(IServiceProvider));
var epar = Expression.Parameter(typeof(object)); var epar = Expression.Parameter(typeof(object));
var populate = created.GetMethod(AvaloniaXamlIlCompiler.PopulateName); var populate = created.GetMethod(AvaloniaXamlIlCompiler.PopulateName)!;
isp = Expression.Parameter(typeof(IServiceProvider)); isp = Expression.Parameter(typeof(IServiceProvider));
var populateCb = Expression.Lambda<Action<IServiceProvider, object>>( var populateCb = Expression.Lambda<Action<IServiceProvider, object>>(
Expression.Call(populate, isp, Expression.Convert(epar, populate.GetParameters()[1].ParameterType)), Expression.Call(populate, isp, Expression.Convert(epar, populate.GetParameters()[1].ParameterType)),
@ -353,7 +363,7 @@ namespace Avalonia.Markup.Xaml.XamlIl
target => { populateCb(serviceProvider, target); })); target => { populateCb(serviceProvider, target); }));
try try
{ {
return Activator.CreateInstance(targetType); return Activator.CreateInstance(targetType)!;
} }
finally finally
{ {
@ -363,7 +373,7 @@ namespace Avalonia.Markup.Xaml.XamlIl
var createCb = Expression.Lambda<Func<IServiceProvider, object>>( var createCb = Expression.Lambda<Func<IServiceProvider, object>>(
Expression.Convert(Expression.Call( Expression.Convert(Expression.Call(
created.GetMethod(AvaloniaXamlIlCompiler.BuildName), isp), typeof(object)), isp).Compile(); created.GetMethod(AvaloniaXamlIlCompiler.BuildName)!, isp), typeof(object)), isp).Compile();
return createCb(serviceProvider); return createCb(serviceProvider);
} }
else else
@ -394,7 +404,7 @@ namespace Avalonia.Markup.Xaml.XamlIl
#endif #endif
} }
private static string GetSafeUriIdentifier(Uri uri) private static string? GetSafeUriIdentifier(Uri? uri)
{ {
return uri?.ToString() return uri?.ToString()
.Replace(":", "_") .Replace(":", "_")

4
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AstNodes/AvaloniaXamlIlFontFamilyAstNode.cs

@ -28,8 +28,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.AstNodes
{ {
codeGen codeGen
.Ldloc(context.ContextLocal) .Ldloc(context.ContextLocal)
.Castclass(context.Configuration.TypeMappings.UriContextProvider) .Castclass(context.Configuration.TypeMappings.UriContextProvider!)
.EmitCall(context.Configuration.TypeMappings.UriContextProvider.FindMethod( .EmitCall(context.Configuration.TypeMappings.UriContextProvider!.GetMethod(
"get_BaseUri", _types.Uri, false)) "get_BaseUri", _types.Uri, false))
.Ldstr(_text) .Ldstr(_text)
.Newobj(_types.FontFamilyConstructorUriName); .Newobj(_types.FontFamilyConstructorUriName);

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

@ -17,7 +17,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
{ {
class AvaloniaXamlIlCompiler : XamlILCompiler class AvaloniaXamlIlCompiler : XamlILCompiler
{ {
private readonly IXamlType _contextType; private readonly IXamlType _contextType = null!;
private readonly AvaloniaXamlIlDesignPropertiesTransformer _designTransformer; private readonly AvaloniaXamlIlDesignPropertiesTransformer _designTransformer;
private readonly AvaloniaBindingExtensionTransformer _bindingTransformer; private readonly AvaloniaBindingExtensionTransformer _bindingTransformer;
@ -156,7 +156,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
#if !XAMLX_CECIL_INTERNAL #if !XAMLX_CECIL_INTERNAL
[RequiresUnreferencedCode(XamlX.TrimmingMessages.DynamicXamlReference)] [RequiresUnreferencedCode(XamlX.TrimmingMessages.DynamicXamlReference)]
#endif #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>
{ {
@ -192,7 +192,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
return parsed; return parsed;
} }
public void Compile(XamlDocument document, XamlDocumentTypeBuilderProvider typeBuilderProvider, string baseUri, IFileSource fileSource) public void Compile(XamlDocument document, XamlDocumentTypeBuilderProvider typeBuilderProvider, string? baseUri, IFileSource? fileSource)
{ {
Compile( Compile(
document, document,
@ -211,7 +211,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
#if !XAMLX_CECIL_INTERNAL #if !XAMLX_CECIL_INTERNAL
[RequiresUnreferencedCode(XamlX.TrimmingMessages.DynamicXamlReference)] [RequiresUnreferencedCode(XamlX.TrimmingMessages.DynamicXamlReference)]
#endif #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);

13
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompilerConfiguration.cs

@ -9,16 +9,17 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
public XamlIlPropertyInfoAccessorFactoryEmitter AccessorFactoryEmitter { get; } public XamlIlPropertyInfoAccessorFactoryEmitter AccessorFactoryEmitter { get; }
public XamlIlTrampolineBuilder TrampolineBuilder { get; } public XamlIlTrampolineBuilder TrampolineBuilder { get; }
public AvaloniaXamlIlCompilerConfiguration(IXamlTypeSystem typeSystem, public AvaloniaXamlIlCompilerConfiguration(
IXamlAssembly defaultAssembly, IXamlTypeSystem typeSystem,
IXamlAssembly? defaultAssembly,
XamlLanguageTypeMappings typeMappings, XamlLanguageTypeMappings typeMappings,
XamlXmlnsMappings xmlnsMappings, XamlXmlnsMappings? xmlnsMappings,
XamlValueConverter customValueConverter, XamlValueConverter? customValueConverter,
XamlIlClrPropertyInfoEmitter clrPropertyEmitter, XamlIlClrPropertyInfoEmitter clrPropertyEmitter,
XamlIlPropertyInfoAccessorFactoryEmitter accessorFactoryEmitter, XamlIlPropertyInfoAccessorFactoryEmitter accessorFactoryEmitter,
XamlIlTrampolineBuilder trampolineBuilder, XamlIlTrampolineBuilder trampolineBuilder,
IXamlIdentifierGenerator identifierGenerator, IXamlIdentifierGenerator? identifierGenerator,
XamlDiagnosticsHandler diagnosticsHandler) XamlDiagnosticsHandler? diagnosticsHandler)
: base(typeSystem, defaultAssembly, typeMappings, xmlnsMappings, customValueConverter, identifierGenerator, diagnosticsHandler) : base(typeSystem, defaultAssembly, typeMappings, xmlnsMappings, customValueConverter, identifierGenerator, diagnosticsHandler)
{ {
ClrPropertyEmitter = clrPropertyEmitter; ClrPropertyEmitter = clrPropertyEmitter;

50
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.Linq; using System.Linq;
using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers; using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers;
using XamlX.Ast; using XamlX.Ast;
@ -21,8 +22,6 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
public static (XamlLanguageTypeMappings language, XamlLanguageEmitMappings<IXamlILEmitter, XamlILNodeEmitResult> emit) Configure(IXamlTypeSystem typeSystem) public static (XamlLanguageTypeMappings language, XamlLanguageEmitMappings<IXamlILEmitter, XamlILNodeEmitResult> emit) Configure(IXamlTypeSystem typeSystem)
{ {
var runtimeHelpers = typeSystem.GetType("Avalonia.Markup.Xaml.XamlIl.Runtime.XamlIlRuntimeHelpers"); var runtimeHelpers = typeSystem.GetType("Avalonia.Markup.Xaml.XamlIl.Runtime.XamlIlRuntimeHelpers");
var assignBindingAttribute = typeSystem.GetType("Avalonia.Data.AssignBindingAttribute");
var bindingType = typeSystem.GetType("Avalonia.Data.IBinding");
var rv = new XamlLanguageTypeMappings(typeSystem) var rv = new XamlLanguageTypeMappings(typeSystem)
{ {
SupportInitialize = typeSystem.GetType("System.ComponentModel.ISupportInitialize"), SupportInitialize = typeSystem.GetType("System.ComponentModel.ISupportInitialize"),
@ -89,7 +88,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
IXamlTypeSystem typeSystem, IXamlTypeSystem typeSystem,
IXamlILContextDefinition<IXamlILEmitter> definition) IXamlILContextDefinition<IXamlILEmitter> definition)
{ {
var nameScopeType = typeSystem.FindType("Avalonia.Controls.INameScope"); var nameScopeType = typeSystem.GetType("Avalonia.Controls.INameScope");
var field = definition.TypeBuilder.DefineField(nameScopeType, var field = definition.TypeBuilder.DefineField(nameScopeType,
ContextNameScopeFieldName, XamlVisibility.Public, false); ContextNameScopeFieldName, XamlVisibility.Public, false);
definition.ConstructorBuilder.Generator definition.ConstructorBuilder.Generator
@ -97,7 +96,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
.Ldarg(1) .Ldarg(1)
.Ldtype(nameScopeType) .Ldtype(nameScopeType)
.EmitCall(mappings.ServiceProvider.GetMethod(new FindMethodMethodSignature("GetService", .EmitCall(mappings.ServiceProvider.GetMethod(new FindMethodMethodSignature("GetService",
typeSystem.FindType("System.Object"), typeSystem.FindType("System.Type")))) typeSystem.GetType("System.Object"), typeSystem.GetType("System.Type"))))
.Stfld(field); .Stfld(field);
} }
@ -107,26 +106,26 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
IXamlILContextDefinition<IXamlILEmitter> definition, IXamlILContextDefinition<IXamlILEmitter> definition,
IXamlType runtimeHelpers) IXamlType runtimeHelpers)
{ {
var interfaceType = typeSystem.FindType("Avalonia.Markup.Xaml.XamlIl.Runtime.IAvaloniaXamlIlEagerParentStackProvider"); var interfaceType = typeSystem.GetType("Avalonia.Markup.Xaml.XamlIl.Runtime.IAvaloniaXamlIlEagerParentStackProvider");
definition.TypeBuilder.AddInterfaceImplementation(interfaceType); definition.TypeBuilder.AddInterfaceImplementation(interfaceType);
// IReadOnlyList<object> DirectParentsStack => (IReadOnlyList<object>)ParentsStack; // IReadOnlyList<object> DirectParentsStack => (IReadOnlyList<object>)ParentsStack;
var directParentsGetter = ImplementInterfacePropertyGetter("DirectParentsStack"); var directParentsGetter = ImplementInterfacePropertyGetter("DirectParentsStack");
directParentsGetter.Generator directParentsGetter.Generator
.LdThisFld(definition.ParentListField) .LdThisFld(definition.ParentListField!)
.Castclass(directParentsGetter.ReturnType) .Castclass(directParentsGetter.ReturnType)
.Ret(); .Ret();
var serviceProviderGetServiceMethod = mappings.ServiceProvider.GetMethod(new FindMethodMethodSignature( var serviceProviderGetServiceMethod = mappings.ServiceProvider.GetMethod(new FindMethodMethodSignature(
"GetService", "GetService",
typeSystem.FindType("System.Object"), typeSystem.GetType("System.Object"),
typeSystem.FindType("System.Type"))); typeSystem.GetType("System.Type")));
var asEagerParentStackProviderMethod = runtimeHelpers.GetMethod(new FindMethodMethodSignature( var asEagerParentStackProviderMethod = runtimeHelpers.GetMethod(new FindMethodMethodSignature(
"AsEagerParentStackProvider", "AsEagerParentStackProvider",
interfaceType, interfaceType,
mappings.ParentStackProvider) mappings.ParentStackProvider!)
{ {
IsStatic = true IsStatic = true
}); });
@ -136,14 +135,14 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
var parentProviderGetter = ImplementInterfacePropertyGetter("ParentProvider"); var parentProviderGetter = ImplementInterfacePropertyGetter("ParentProvider");
parentProviderGetter.Generator parentProviderGetter.Generator
.LdThisFld(definition.ParentServiceProviderField) .LdThisFld(definition.ParentServiceProviderField)
.Ldtype(mappings.ParentStackProvider) .Ldtype(mappings.ParentStackProvider!)
.EmitCall(serviceProviderGetServiceMethod) .EmitCall(serviceProviderGetServiceMethod)
.EmitCall(asEagerParentStackProviderMethod) .EmitCall(asEagerParentStackProviderMethod)
.Ret(); .Ret();
IXamlMethodBuilder<IXamlILEmitter> ImplementInterfacePropertyGetter(string propertyName) IXamlMethodBuilder<IXamlILEmitter> ImplementInterfacePropertyGetter(string propertyName)
{ {
var interfaceGetter = interfaceType.FindMethod(m => m.Name == "get_" + propertyName); var interfaceGetter = interfaceType.GetMethod(m => m.Name == "get_" + propertyName);
var getter = definition.TypeBuilder.DefineMethod( var getter = definition.TypeBuilder.DefineMethod(
interfaceGetter.ReturnType, interfaceGetter.ReturnType,
@ -193,7 +192,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
_avaloniaListConverter = typeSystem.GetType("Avalonia.Collections.AvaloniaListConverter`1"); _avaloniaListConverter = typeSystem.GetType("Avalonia.Collections.AvaloniaListConverter`1");
} }
IXamlType LookupConverter(IXamlType type) IXamlType? LookupConverter(IXamlType type)
{ {
foreach(var p in _converters) foreach(var p in _converters)
if (p.Key.Equals(type)) if (p.Key.Equals(type))
@ -205,41 +204,44 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
class ConstructedAttribute : IXamlCustomAttribute class ConstructedAttribute : IXamlCustomAttribute
{ {
public bool Equals(IXamlCustomAttribute other) => false; public bool Equals(IXamlCustomAttribute? other) => false;
public IXamlType Type { get; } public IXamlType Type { get; }
public List<object> Parameters { get; } public List<object?> Parameters { get; }
public Dictionary<string, object> Properties { get; } public Dictionary<string, object?> Properties { get; }
public ConstructedAttribute(IXamlType type, List<object> parameters, Dictionary<string, object> properties) public ConstructedAttribute(IXamlType type, List<object?>? parameters, Dictionary<string, object?>? properties)
{ {
Type = type; Type = type;
Parameters = parameters ?? new List<object>(); Parameters = parameters ?? new List<object?>();
Properties = properties ?? new Dictionary<string, object>(); Properties = properties ?? new Dictionary<string, object?>();
} }
} }
public IXamlCustomAttribute GetCustomAttribute(IXamlType type, IXamlType attributeType) public IXamlCustomAttribute? GetCustomAttribute(IXamlType type, IXamlType attributeType)
{ {
if (attributeType.Equals(_typeConverterAttribute)) if (attributeType.Equals(_typeConverterAttribute))
{ {
var conv = LookupConverter(type); var conv = LookupConverter(type);
if (conv != null) if (conv != null)
return new ConstructedAttribute(_typeConverterAttribute, new List<object>() {conv}, null); return new ConstructedAttribute(_typeConverterAttribute, [conv], null);
} }
return null; return null;
} }
public IXamlCustomAttribute GetCustomAttribute(IXamlProperty property, IXamlType attributeType) public IXamlCustomAttribute? GetCustomAttribute(IXamlProperty property, IXamlType attributeType)
{ {
return null; return null;
} }
} }
public static bool CustomValueConverter(AstTransformationContext context, public static bool CustomValueConverter(
IXamlAstValueNode node, IReadOnlyList<IXamlCustomAttribute> customAttributes, IXamlType type, AstTransformationContext context,
out IXamlAstValueNode result) IXamlAstValueNode node,
IReadOnlyList<IXamlCustomAttribute>? customAttributes,
IXamlType type,
[NotNullWhen(true)] out IXamlAstValueNode? result)
{ {
if (node is AvaloniaXamlIlOptionMarkupExtensionTransformer.OptionsMarkupExtensionNode optionsNode) if (node is AvaloniaXamlIlOptionMarkupExtensionTransformer.OptionsMarkupExtensionNode optionsNode)
{ {

29
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguageParseIntrinsics.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;
@ -15,9 +16,15 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
{ {
class AvaloniaXamlIlLanguageParseIntrinsics class AvaloniaXamlIlLanguageParseIntrinsics
{ {
public static bool TryConvert(AstTransformationContext context, IXamlAstValueNode node, string text, IXamlType type, AvaloniaXamlIlWellKnownTypes types, out IXamlAstValueNode result) public static bool TryConvert(
AstTransformationContext context,
IXamlAstValueNode node,
string text,
IXamlType type,
AvaloniaXamlIlWellKnownTypes types,
[NotNullWhen(true)] out IXamlAstValueNode? result)
{ {
bool ReturnOnParseError(string title, out IXamlAstValueNode result) bool ReturnOnParseError(string title, out IXamlAstValueNode? result)
{ {
context.ReportDiagnostic(new XamlDiagnostic( context.ReportDiagnostic(new XamlDiagnostic(
AvaloniaXamlDiagnosticCodes.AvaloniaIntrinsicsError, AvaloniaXamlDiagnosticCodes.AvaloniaIntrinsicsError,
@ -50,7 +57,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
} }
result = new XamlStaticOrTargetedReturnMethodCallNode(node, result = new XamlStaticOrTargetedReturnMethodCallNode(node,
type.FindMethod("FromTicks", type, false, types.Long), type.GetMethod("FromTicks", type, false, types.Long),
new[] { new XamlConstantNode(node, types.Long, timeSpan.Ticks) }); new[] { new XamlConstantNode(node, types.Long, timeSpan.Ticks) });
return true; return true;
} }
@ -272,7 +279,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
{ {
if (property.PropertyType == types.TextTrimming && property.Name.Equals(text, StringComparison.OrdinalIgnoreCase)) if (property.PropertyType == types.TextTrimming && property.Name.Equals(text, StringComparison.OrdinalIgnoreCase))
{ {
result = new XamlStaticOrTargetedReturnMethodCallNode(node, property.Getter, Enumerable.Empty<IXamlAstValueNode>()); result = new XamlStaticOrTargetedReturnMethodCallNode(node, property.Getter!, Enumerable.Empty<IXamlAstValueNode>());
return true; return true;
} }
@ -285,7 +292,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
{ {
if (property.PropertyType == types.TextDecorationCollection && property.Name.Equals(text, StringComparison.OrdinalIgnoreCase)) if (property.PropertyType == types.TextDecorationCollection && property.Name.Equals(text, StringComparison.OrdinalIgnoreCase))
{ {
result = new XamlStaticOrTargetedReturnMethodCallNode(node, property.Getter, Enumerable.Empty<IXamlAstValueNode>()); result = new XamlStaticOrTargetedReturnMethodCallNode(node, property.Getter!, Enumerable.Empty<IXamlAstValueNode>());
return true; return true;
} }
@ -298,7 +305,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
{ {
if (property.PropertyType == types.WindowTransparencyLevel && property.Name.Equals(text, StringComparison.OrdinalIgnoreCase)) if (property.PropertyType == types.WindowTransparencyLevel && property.Name.Equals(text, StringComparison.OrdinalIgnoreCase))
{ {
result = new XamlStaticOrTargetedReturnMethodCallNode(node, property.Getter, Enumerable.Empty<IXamlAstValueNode>()); result = new XamlStaticOrTargetedReturnMethodCallNode(node, property.Getter!, Enumerable.Empty<IXamlAstValueNode>());
return true; return true;
} }
@ -309,7 +316,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
{ {
var uriText = text.Trim(); var uriText = text.Trim();
var kind = ((!uriText?.StartsWith("/") == true) ? UriKind.RelativeOrAbsolute : UriKind.Relative); var kind = !uriText.StartsWith("/") ? UriKind.RelativeOrAbsolute : UriKind.Relative;
if (string.IsNullOrWhiteSpace(uriText) || !Uri.TryCreate(uriText, kind, out var _)) if (string.IsNullOrWhiteSpace(uriText) || !Uri.TryCreate(uriText, kind, out var _))
{ {
@ -373,12 +380,12 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
{ {
if (attribute.Properties.TryGetValue("Separators", out var separatorsArray)) if (attribute.Properties.TryGetValue("Separators", out var separatorsArray))
{ {
separators = ((Array)separatorsArray)?.OfType<string>().ToArray(); separators = ((Array?)separatorsArray)?.OfType<string>().ToArray();
} }
if (attribute.Properties.TryGetValue("SplitOptions", out var splitOptionsObj)) if (attribute.Properties.TryGetValue("SplitOptions", out var splitOptionsObj))
{ {
splitOptions = (StringSplitOptions)splitOptionsObj; splitOptions = (StringSplitOptions)splitOptionsObj!;
} }
} }
@ -403,7 +410,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
return false; return false;
} }
nodes[index] = itemNode; nodes[index] = itemNode!;
} }
foreach (var element in nodes) foreach (var element in nodes)
@ -440,7 +447,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
return false; return false;
} }
private static IXamlType GetElementType(IXamlType type, XamlTypeWellKnownTypes types) private static IXamlType? GetElementType(IXamlType type, XamlTypeWellKnownTypes types)
{ {
if (type.IsArray) if (type.IsArray)
{ {

7
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/GroupTransformers/IXamlAstGroupTransformer.cs

@ -1,7 +1,4 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using System.Xml;
using XamlX;
using XamlX.Ast; using XamlX.Ast;
using XamlX.Transform; using XamlX.Transform;
@ -18,7 +15,7 @@ internal class AstGroupTransformationContext : AstTransformationContext
} }
public override string Document => CurrentDocument?.FileSource?.FilePath ?? "{unknown document}"; public override string Document => CurrentDocument?.FileSource?.FilePath ?? "{unknown document}";
public IXamlDocumentResource CurrentDocument { get; set; } public IXamlDocumentResource? CurrentDocument { get; set; }
public IReadOnlyCollection<IXamlDocumentResource> Documents { get; } public IReadOnlyCollection<IXamlDocumentResource> Documents { get; }

4
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/GroupTransformers/XamlIncludeGroupTransformer.cs

@ -192,7 +192,7 @@ internal class AvaloniaXamlIncludeTransformer : IXamlAstGroupTransformer
var uriPath = new Uri(originalAssetPath, (UriKind)uriKind); var uriPath = new Uri(originalAssetPath, (UriKind)uriKind);
if (!uriPath.IsAbsoluteUri) if (!uriPath.IsAbsoluteUri)
{ {
var baseUrl = context.CurrentDocument.Uri ?? throw new InvalidOperationException("CurrentDocument URI is null."); var baseUrl = context.CurrentDocument?.Uri ?? throw new InvalidOperationException("CurrentDocument URI is null.");
uriPath = new Uri(new Uri(baseUrl, UriKind.Absolute), uriPath); uriPath = new Uri(new Uri(baseUrl, UriKind.Absolute), uriPath);
} }
else if (!uriPath.Scheme.Equals("avares", StringComparison.CurrentCultureIgnoreCase)) else if (!uriPath.Scheme.Equals("avares", StringComparison.CurrentCultureIgnoreCase))
@ -218,7 +218,7 @@ internal class AvaloniaXamlIncludeTransformer : IXamlAstGroupTransformer
{ {
codeGen.Ldloc(context.ContextLocal); codeGen.Ldloc(context.ContextLocal);
var method = context.GetAvaloniaTypes().RuntimeHelpers var method = context.GetAvaloniaTypes().RuntimeHelpers
.FindMethod(m => m.Name == "CreateRootServiceProviderV3"); .GetMethod(m => m.Name == "CreateRootServiceProviderV3");
codeGen.EmitCall(method); codeGen.EmitCall(method);
return XamlILNodeEmitResult.Type(0, Type.GetClrType()); return XamlILNodeEmitResult.Type(0, Type.GetClrType());

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

@ -7,7 +7,6 @@ using XamlX.Ast;
using XamlX.TypeSystem; using XamlX.TypeSystem;
namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.GroupTransformers; namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.GroupTransformers;
#nullable enable
internal class XamlMergeResourceGroupTransformer : IXamlAstGroupTransformer internal class XamlMergeResourceGroupTransformer : IXamlAstGroupTransformer
{ {
@ -94,7 +93,7 @@ internal class XamlMergeResourceGroupTransformer : IXamlAstGroupTransformer
$"Node MergeResourceInclude is unable to resolve \"{originalAssetPath}\" path.", propertyNode, node); $"Node MergeResourceInclude is unable to resolve \"{originalAssetPath}\" path.", propertyNode, node);
} }
var singleRootObject = ((XamlManipulationGroupNode)targetDocumentRoot.Manipulation) var singleRootObject = ((XamlManipulationGroupNode)targetDocumentRoot.Manipulation!)
.Children.OfType<XamlObjectInitializationNode>().Single(); .Children.OfType<XamlObjectInitializationNode>().Single();
if (singleRootObject.Type != resourceDictionaryType) if (singleRootObject.Type != resourceDictionaryType)
{ {

10
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AddNameScopeRegistration.cs

@ -22,7 +22,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
&& mg.Children.OfType<AvaloniaNameScopeRegistrationXamlIlNode>().Any()) && mg.Children.OfType<AvaloniaNameScopeRegistrationXamlIlNode>().Any())
return node; return node;
IXamlAstValueNode value = null; IXamlAstValueNode? value = null;
for (var c = 0; c < pa.Values.Count; c++) for (var c = 0; c < pa.Values.Count; c++)
if (pa.Values[c].Type.GetClrType().Equals(context.Configuration.WellKnownTypes.String)) if (pa.Values[c].Type.GetClrType().Equals(context.Configuration.WellKnownTypes.String))
{ {
@ -73,9 +73,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
class AvaloniaNameScopeRegistrationXamlIlNode : XamlAstNode, IXamlAstManipulationNode class AvaloniaNameScopeRegistrationXamlIlNode : XamlAstNode, IXamlAstManipulationNode
{ {
public IXamlAstValueNode Name { get; set; } public IXamlAstValueNode Name { get; set; }
public IXamlType TargetType { get; } public IXamlType? TargetType { get; }
public AvaloniaNameScopeRegistrationXamlIlNode(IXamlAstValueNode name, IXamlType targetType) : base(name) public AvaloniaNameScopeRegistrationXamlIlNode(IXamlAstValueNode name, IXamlType? targetType) : base(name)
{ {
TargetType = targetType; TargetType = targetType;
Name = name; Name = name;
@ -87,7 +87,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
class AvaloniaNameScopeRegistrationXamlIlNodeEmitter : IXamlAstLocalsNodeEmitter<IXamlILEmitter, XamlILNodeEmitResult> class AvaloniaNameScopeRegistrationXamlIlNodeEmitter : IXamlAstLocalsNodeEmitter<IXamlILEmitter, XamlILNodeEmitResult>
{ {
public XamlILNodeEmitResult Emit(IXamlAstNode node, XamlEmitContextWithLocals<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen) public XamlILNodeEmitResult? Emit(IXamlAstNode node, XamlEmitContextWithLocals<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen)
{ {
if (node is AvaloniaNameScopeRegistrationXamlIlNode registration) if (node is AvaloniaNameScopeRegistrationXamlIlNode registration)
{ {
@ -114,7 +114,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
return XamlILNodeEmitResult.Void(1); return XamlILNodeEmitResult.Void(1);
} }
return default; return null;
} }
} }
} }

5
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaBindingExtensionTransformer.cs

@ -4,14 +4,11 @@ using XamlX;
using XamlX.Ast; using XamlX.Ast;
using XamlX.Transform; using XamlX.Transform;
using XamlParseException = XamlX.XamlParseException;
namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
{ {
class XamlBindingsTransformException : XamlTransformException class XamlBindingsTransformException : XamlTransformException
{ {
public XamlBindingsTransformException(string message, IXamlLineInfo lineInfo, Exception innerException = null) public XamlBindingsTransformException(string message, IXamlLineInfo lineInfo, Exception? innerException = null)
: base(message, lineInfo, innerException) : base(message, lineInfo, innerException)
{ {
} }

32
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlBindingPathParser.cs

@ -1,15 +1,13 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using System.Text;
using Avalonia.Markup.Parsers; using Avalonia.Markup.Parsers;
using Avalonia.Utilities; using Avalonia.Utilities;
using XamlX;
using XamlX.Ast; using XamlX.Ast;
using XamlX.Transform; using XamlX.Transform;
using XamlX.Transform.Transformers; using XamlX.Transform.Transformers;
using XamlX.TypeSystem; using XamlX.TypeSystem;
using XamlParseException = XamlX.XamlParseException;
namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
{ {
@ -81,11 +79,11 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
return node; return node;
} }
private static BindingExpressionGrammar.INode ConvertLongFormPropertiesToBindingExpressionNode( private static BindingExpressionGrammar.INode? ConvertLongFormPropertiesToBindingExpressionNode(
AstTransformationContext context, AstTransformationContext context,
XamlAstObjectNode binding) XamlAstObjectNode binding)
{ {
BindingExpressionGrammar.INode convertedNode = null; BindingExpressionGrammar.INode? convertedNode = null;
var syntheticCompiledBindingProperties = binding.Children.OfType<XamlAstXamlPropertyValueNode>() var syntheticCompiledBindingProperties = binding.Children.OfType<XamlAstXamlPropertyValueNode>()
.Where(v => v.Property is AvaloniaSyntheticCompiledBindingProperty) .Where(v => v.Property is AvaloniaSyntheticCompiledBindingProperty)
@ -195,17 +193,15 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
if (treeType == "Visual") if (treeType == "Visual")
{ {
convertedNode = new VisualAncestorBindingExpressionNode convertedNode = new VisualAncestorBindingExpressionNode(ancestorType!)
{ {
Type = ancestorType,
Level = ancestorLevel Level = ancestorLevel
}; };
} }
else if (treeType == "Logical") else if (treeType == "Logical")
{ {
convertedNode = new LogicalAncestorBindingExpressionNode convertedNode = new LogicalAncestorBindingExpressionNode(ancestorType!)
{ {
Type = ancestorType,
Level = ancestorLevel Level = ancestorLevel
}; };
} }
@ -238,7 +234,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
throw new XamlBindingsTransformException("TargetType has to be set on ControlTemplate or it should be defined inside of a Style.", binding); throw new XamlBindingsTransformException("TargetType has to be set on ControlTemplate or it should be defined inside of a Style.", binding);
} }
convertedNode = new TemplatedParentBindingExpressionNode { Type = parentType }; convertedNode = new TemplatedParentBindingExpressionNode(parentType);
} }
else else
{ {
@ -260,8 +256,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
private static bool GetRelativeSourceObjectFromAssignment( private static bool GetRelativeSourceObjectFromAssignment(
AstTransformationContext context, AstTransformationContext context,
XamlAstXamlPropertyValueNode relativeSourceProperty, XamlAstXamlPropertyValueNode? relativeSourceProperty,
out XamlAstObjectNode relativeSourceObject) [NotNullWhen(true)] out XamlAstObjectNode? relativeSourceObject)
{ {
relativeSourceObject = null; relativeSourceObject = null;
if (relativeSourceProperty is null) if (relativeSourceProperty is null)
@ -320,20 +316,20 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
} }
} }
class VisualAncestorBindingExpressionNode : BindingExpressionGrammar.INode class VisualAncestorBindingExpressionNode(IXamlType type) : BindingExpressionGrammar.INode
{ {
public IXamlType Type { get; set; } public IXamlType Type { get; set; } = type;
public int Level { get; set; } public int Level { get; set; }
} }
class LogicalAncestorBindingExpressionNode : BindingExpressionGrammar.INode class LogicalAncestorBindingExpressionNode(IXamlType type) : BindingExpressionGrammar.INode
{ {
public IXamlType Type { get; set; } public IXamlType Type { get; set; } = type;
public int Level { get; set; } public int Level { get; set; }
} }
class TemplatedParentBindingExpressionNode : BindingExpressionGrammar.INode class TemplatedParentBindingExpressionNode(IXamlType type) : BindingExpressionGrammar.INode
{ {
public IXamlType Type { get; set; } public IXamlType Type { get; set; } = type;
} }
} }

12
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlBindingPathTransformer.cs

@ -14,7 +14,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
{ {
if (node is XamlAstConstructableObjectNode binding && binding.Type.GetClrType().Equals(context.GetAvaloniaTypes().CompiledBindingExtension)) if (node is XamlAstConstructableObjectNode binding && binding.Type.GetClrType().Equals(context.GetAvaloniaTypes().CompiledBindingExtension))
{ {
IXamlType startType = null; IXamlType? startType = null;
var sourceProperty = binding.Children.OfType<XamlPropertyAssignmentNode>().FirstOrDefault(c => c.Property.Name == "Source"); var sourceProperty = binding.Children.OfType<XamlPropertyAssignmentNode>().FirstOrDefault(c => c.Property.Name == "Source");
var dataTypeProperty = binding.Children.OfType<XamlPropertyAssignmentNode>().FirstOrDefault(c => c.Property.Name == "DataType"); var dataTypeProperty = binding.Children.OfType<XamlPropertyAssignmentNode>().FirstOrDefault(c => c.Property.Name == "DataType");
if (sourceProperty?.Values.Count is 1) if (sourceProperty?.Values.Count is 1)
@ -23,11 +23,11 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
switch (sourceValue) switch (sourceValue)
{ {
case XamlAstTextNode textNode: case XamlAstTextNode textNode:
startType = textNode.Type?.GetClrType(); startType = textNode.Type.GetClrType();
break; break;
case XamlMarkupExtensionNode extension: case XamlMarkupExtensionNode extension:
startType = extension.Type?.GetClrType(); startType = extension.Type.GetClrType();
//let's try to infer StaticResource type from parent resources in xaml //let's try to infer StaticResource type from parent resources in xaml
if (extension.Value.Type.GetClrType().FullName == "Avalonia.Markup.Xaml.MarkupExtensions.StaticResourceExtension" && if (extension.Value.Type.GetClrType().FullName == "Avalonia.Markup.Xaml.MarkupExtensions.StaticResourceExtension" &&
@ -47,7 +47,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
string getResourceValue_xKey(XamlPropertyAssignmentNode node) string getResourceValue_xKey(XamlPropertyAssignmentNode node)
=> node.Values.Count == 2 && node.Values[0] is XamlAstTextNode t ? t.Text : ""; => node.Values.Count == 2 && node.Values[0] is XamlAstTextNode t ? t.Text : "";
IXamlType getResourceValue_Type(XamlPropertyAssignmentNode node, IXamlType xamlType) IXamlType? getResourceValue_Type(XamlPropertyAssignmentNode node, IXamlType? xamlType)
=> node.Values.Count == 2 ? node.Values[1].Type.GetClrType() : xamlType; => node.Values.Count == 2 ? node.Values[1].Type.GetClrType() : xamlType;
IEnumerable<XamlPropertyAssignmentNode> getResourceValues(IXamlAstNode node) IEnumerable<XamlPropertyAssignmentNode> getResourceValues(IXamlAstNode node)
@ -85,7 +85,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
.Where(o => styledElement.IsAssignableFrom(o.Type.GetClrType())) .Where(o => styledElement.IsAssignableFrom(o.Type.GetClrType()))
.Select(o => o.Children.FirstOrDefault(p => matchProperty(p, styledElement, "Resources"))) .Select(o => o.Children.FirstOrDefault(p => matchProperty(p, styledElement, "Resources")))
.Where(r => r != null) .Where(r => r != null)
.SelectMany(r => getResourceValues(r)) .SelectMany(r => getResourceValues(r!))
.FirstOrDefault(r => getResourceValue_xKey(r) == key); .FirstOrDefault(r => getResourceValue_xKey(r) == key);
if (resource != null) if (resource != null)
@ -96,7 +96,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
break; break;
case XamlStaticExtensionNode staticExtension: case XamlStaticExtensionNode staticExtension:
startType = staticExtension.Type?.GetClrType(); startType = staticExtension.Type.GetClrType();
break; break;
} }
} }

2
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlClassesPropertyResolver.cs

@ -49,7 +49,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
{ {
emitter emitter
.Stloc(value.Local) .Stloc(value.Local)
.EmitCall(_types.StyledElementClassesProperty.Getter) .EmitCall(_types.StyledElementClassesProperty.Getter!)
.Ldstr(_className) .Ldstr(_className)
.Ldloc(value.Local) .Ldloc(value.Local)
.EmitCall(_types.Classes.GetMethod(new FindMethodMethodSignature("Set", .EmitCall(_types.Classes.GetMethod(new FindMethodMethodSignature("Set",

24
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlDataContextTypeTransformer.cs

@ -12,7 +12,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
{ {
class XamlDataContextException : XamlTransformException class XamlDataContextException : XamlTransformException
{ {
public XamlDataContextException(string message, IXamlLineInfo lineInfo, Exception innerException = null) public XamlDataContextException(string message, IXamlLineInfo lineInfo, Exception? innerException = null)
: base(message, lineInfo, innerException) : base(message, lineInfo, innerException)
{ {
} }
@ -30,8 +30,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
if (node is XamlAstConstructableObjectNode on) if (node is XamlAstConstructableObjectNode on)
{ {
AvaloniaXamlIlDataContextTypeMetadataNode inferredDataContextTypeNode = null; AvaloniaXamlIlDataContextTypeMetadataNode? inferredDataContextTypeNode = null;
AvaloniaXamlIlDataContextTypeMetadataNode directiveDataContextTypeNode = null; AvaloniaXamlIlDataContextTypeMetadataNode? directiveDataContextTypeNode = null;
for (int i = 0; i < on.Children.Count; ++i) for (int i = 0; i < on.Children.Count; ++i)
{ {
@ -81,13 +81,13 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
// Infer data type from collection binding on a control that displays items. // Infer data type from collection binding on a control that displays items.
var property = context.ParentNodes().OfType<XamlPropertyAssignmentNode>().FirstOrDefault(); var property = context.ParentNodes().OfType<XamlPropertyAssignmentNode>().FirstOrDefault();
var attributeType = context.GetAvaloniaTypes().InheritDataTypeFromItemsAttribute; var attributeType = context.GetAvaloniaTypes().InheritDataTypeFromItemsAttribute;
var attribute = property?.Property?.GetClrProperty().CustomAttributes var attribute = property?.Property.GetClrProperty().CustomAttributes
.FirstOrDefault(a => a.Type == attributeType); .FirstOrDefault(a => a.Type == attributeType);
if (attribute is not null) if (attribute is not null)
{ {
var propertyName = (string)attribute.Parameters.First(); var propertyName = (string?)attribute.Parameters.First();
XamlAstConstructableObjectNode parentObject; XamlAstConstructableObjectNode? parentObject;
if (attribute.Properties.TryGetValue("AncestorType", out var type) if (attribute.Properties.TryGetValue("AncestorType", out var type)
&& type is IXamlType xamlType) && type is IXamlType xamlType)
{ {
@ -99,7 +99,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
parentObject = context.ParentNodes().OfType<XamlAstConstructableObjectNode>().FirstOrDefault(); parentObject = context.ParentNodes().OfType<XamlAstConstructableObjectNode>().FirstOrDefault();
} }
if (parentObject != null) if (parentObject != null && !string.IsNullOrEmpty(propertyName))
{ {
inferredDataContextTypeNode = InferDataContextOfPresentedItem(context, on, parentObject, propertyName); inferredDataContextTypeNode = InferDataContextOfPresentedItem(context, on, parentObject, propertyName);
} }
@ -122,7 +122,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
return node; return node;
} }
private static AvaloniaXamlIlDataContextTypeMetadataNode InferDataContextOfPresentedItem( private static AvaloniaXamlIlDataContextTypeMetadataNode? InferDataContextOfPresentedItem(
AstTransformationContext context, XamlAstConstructableObjectNode on, AstTransformationContext context, XamlAstConstructableObjectNode on,
XamlAstConstructableObjectNode parentObject, string propertyName) XamlAstConstructableObjectNode parentObject, string propertyName)
{ {
@ -135,7 +135,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
return null; return null;
} }
IXamlType itemsCollectionType = null; IXamlType? itemsCollectionType = null;
if (context.GetAvaloniaTypes().IBinding.IsAssignableFrom(parentItemsValue.Type.GetClrType())) if (context.GetAvaloniaTypes().IBinding.IsAssignableFrom(parentItemsValue.Type.GetClrType()))
{ {
if (parentItemsValue.Type.GetClrType().Equals(context.GetAvaloniaTypes().CompiledBindingExtension) if (parentItemsValue.Type.GetClrType().Equals(context.GetAvaloniaTypes().CompiledBindingExtension)
@ -217,7 +217,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
[DebuggerDisplay("DataType = {DataContextType}")] [DebuggerDisplay("DataType = {DataContextType}")]
class AvaloniaXamlIlDataContextTypeMetadataNode : XamlValueWithSideEffectNodeBase class AvaloniaXamlIlDataContextTypeMetadataNode : XamlValueWithSideEffectNodeBase
{ {
public virtual IXamlType DataContextType { get; } public IXamlType DataContextType { get; }
public AvaloniaXamlIlDataContextTypeMetadataNode(IXamlAstValueNode value, IXamlType targetType) public AvaloniaXamlIlDataContextTypeMetadataNode(IXamlAstValueNode value, IXamlType targetType)
: base(value, value) : base(value, value)
@ -230,10 +230,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
class AvaloniaXamlIlUninferrableDataContextMetadataNode : AvaloniaXamlIlDataContextTypeMetadataNode class AvaloniaXamlIlUninferrableDataContextMetadataNode : AvaloniaXamlIlDataContextTypeMetadataNode
{ {
public AvaloniaXamlIlUninferrableDataContextMetadataNode(IXamlAstValueNode value) public AvaloniaXamlIlUninferrableDataContextMetadataNode(IXamlAstValueNode value)
: base(value, null) : base(value, XamlPseudoType.Unknown)
{ {
} }
public override IXamlType DataContextType => XamlPseudoType.Unknown;
} }
} }

6
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlDeferredResourceTransformer.cs

@ -28,7 +28,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
new XamlDirectCallPropertySetter(types.ResourceDictionaryDeferredAdd), new XamlDirectCallPropertySetter(types.ResourceDictionaryDeferredAdd),
}; };
} }
else if (pa.Property.Name == "Resources" && pa.Property.Getter.ReturnType.Equals(types.IResourceDictionary) else if (pa.Property.Name == "Resources" && pa.Property.Getter?.ReturnType.Equals(types.IResourceDictionary) == true
&& ShouldBeDeferred(pa.Values[1])) && ShouldBeDeferred(pa.Values[1]))
{ {
pa.Values[1] = new XamlDeferredContentNode(pa.Values[1], types.XamlIlTypes.Object, context.Configuration); pa.Values[1] = new XamlDeferredContentNode(pa.Values[1], types.XamlIlTypes.Object, context.Configuration);
@ -132,7 +132,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
emitter.EmitCall(_adder, true); emitter.EmitCall(_adder, true);
} }
public bool Equals(AdderSetter other) public bool Equals(AdderSetter? other)
{ {
if (ReferenceEquals(null, other)) if (ReferenceEquals(null, other))
return false; return false;
@ -142,7 +142,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
return _getter.Equals(other._getter) && _adder.Equals(other._adder); return _getter.Equals(other._getter) && _adder.Equals(other._adder);
} }
public override bool Equals(object obj) public override bool Equals(object? obj)
=> Equals(obj as AdderSetter); => Equals(obj as AdderSetter);
public override int GetHashCode() public override int GetHashCode()

4
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlEnsureResourceDictionaryCapacityTransformer.cs

@ -70,8 +70,8 @@ internal sealed class AvaloniaXamlIlEnsureResourceDictionaryCapacityTransformer
{ {
"Content" when node.Property.DeclaringType == types.ResourceDictionary "Content" when node.Property.DeclaringType == types.ResourceDictionary
=> new ResourcesInfo(ResourcesMode.ResourceDictionaryContent, null) { Count = 1 }, => new ResourcesInfo(ResourcesMode.ResourceDictionaryContent, null) { Count = 1 },
"Resources" when types.IResourceDictionary.IsAssignableFrom(node.Property.Getter.ReturnType) "Resources" when node.Property.Getter is { } getter && types.IResourceDictionary.IsAssignableFrom(getter.ReturnType)
=> new ResourcesInfo(ResourcesMode.ElementResources, node.Property.Getter) { Count = 1 }, => new ResourcesInfo(ResourcesMode.ElementResources, getter) { Count = 1 },
_ _
=> default => default
}; };

33
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlOptionMarkupExtensionTransformer.cs

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using System.Reflection.Emit; using System.Reflection.Emit;
using XamlX; using XamlX;
@ -25,9 +26,9 @@ internal class AvaloniaXamlIlOptionMarkupExtensionTransformer : IXamlAstTransfor
var optionAttribute = context.GetAvaloniaTypes().MarkupExtensionOptionAttribute; var optionAttribute = context.GetAvaloniaTypes().MarkupExtensionOptionAttribute;
var defaultOptionAttribute = context.GetAvaloniaTypes().MarkupExtensionDefaultOptionAttribute; var defaultOptionAttribute = context.GetAvaloniaTypes().MarkupExtensionDefaultOptionAttribute;
var typeArgument = type.GenericArguments?.FirstOrDefault(); var typeArgument = type.GenericArguments.FirstOrDefault();
IXamlAstValueNode defaultValue = null; IXamlAstValueNode? defaultValue = null;
var values = new List<OptionsMarkupExtensionBranch>(); var values = new List<OptionsMarkupExtensionBranch>();
if (objectNode.Arguments.FirstOrDefault() is { } argument) if (objectNode.Arguments.FirstOrDefault() is { } argument)
@ -64,7 +65,7 @@ internal class AvaloniaXamlIlOptionMarkupExtensionTransformer : IXamlAstTransfor
var optionsPropNode = onObj.Children.OfType<XamlAstXamlPropertyValueNode>() var optionsPropNode = onObj.Children.OfType<XamlAstXamlPropertyValueNode>()
.SingleOrDefault(v => v.Property.GetClrProperty().Name == "Options") .SingleOrDefault(v => v.Property.GetClrProperty().Name == "Options")
?.Values.Single(); ?.Values.Single();
var options = (optionsPropNode as XamlAstTextNode)?.Text?.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries) var options = (optionsPropNode as XamlAstTextNode)?.Text.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries)
?? Array.Empty<string>(); ?? Array.Empty<string>();
if (options.Length == 0) if (options.Length == 0)
{ {
@ -128,8 +129,8 @@ internal class AvaloniaXamlIlOptionMarkupExtensionTransformer : IXamlAstTransfor
throw new XamlTransformException("MarkupExtension option must not be null", li); throw new XamlTransformException("MarkupExtension option must not be null", li);
} }
var optionAsString = option.ToString(); var optionAsString = option.ToString() ?? string.Empty;
IXamlAstValueNode optionNode = null; IXamlAstValueNode? optionNode = null;
foreach (var method in methods) foreach (var method in methods)
{ {
try try
@ -184,7 +185,7 @@ internal class AvaloniaXamlIlOptionMarkupExtensionTransformer : IXamlAstTransfor
IXamlAstValueNode TransformNode( IXamlAstValueNode TransformNode(
IReadOnlyCollection<IXamlAstValueNode> values, IReadOnlyCollection<IXamlAstValueNode> values,
IXamlType suggestedType, IXamlType? suggestedType,
IXamlLineInfo line) IXamlLineInfo line)
{ {
if (suggestedType is not null) if (suggestedType is not null)
@ -212,7 +213,7 @@ internal class AvaloniaXamlIlOptionMarkupExtensionTransformer : IXamlAstTransfor
public OptionsMarkupExtensionNode( public OptionsMarkupExtensionNode(
XamlMarkupExtensionNode original, XamlMarkupExtensionNode original,
OptionsMarkupExtensionBranch[] branches, OptionsMarkupExtensionBranch[] branches,
IXamlAstValueNode defaultNode, IXamlAstValueNode? defaultNode,
IXamlType contextParameter) IXamlType contextParameter)
: base( : base(
original.Value, original.Value,
@ -232,9 +233,9 @@ internal class AvaloniaXamlIlOptionMarkupExtensionTransformer : IXamlAstTransfor
base.VisitChildren(visitor); base.VisitChildren(visitor);
} }
public bool ConvertToReturnType(AstTransformationContext context, IXamlType type, out OptionsMarkupExtensionNode res) public bool ConvertToReturnType(AstTransformationContext context, IXamlType type, [NotNullWhen(true)] out OptionsMarkupExtensionNode? res)
{ {
IXamlAstValueNode convertedDefaultNode = null; IXamlAstValueNode? convertedDefaultNode = null;
if (ProvideValue.ExtensionNodeContainer.DefaultNode is { } defaultNode) if (ProvideValue.ExtensionNodeContainer.DefaultNode is { } defaultNode)
{ {
@ -255,7 +256,7 @@ internal class AvaloniaXamlIlOptionMarkupExtensionTransformer : IXamlAstTransfor
return false; return false;
} }
res = new OptionsMarkupExtensionNode(this, convertedBranches, convertedDefaultNode, _contextParameter); res = new OptionsMarkupExtensionNode(this, convertedBranches!, convertedDefaultNode, _contextParameter);
return true; return true;
} }
} }
@ -264,19 +265,19 @@ internal class AvaloniaXamlIlOptionMarkupExtensionTransformer : IXamlAstTransfor
{ {
public OptionsMarkupExtensionNodesContainer( public OptionsMarkupExtensionNodesContainer(
OptionsMarkupExtensionBranch[] branches, OptionsMarkupExtensionBranch[] branches,
IXamlAstValueNode defaultNode) : base(branches.FirstOrDefault()?.Value ?? defaultNode) IXamlAstValueNode? defaultNode) : base((branches.FirstOrDefault()?.Value ?? defaultNode)!)
{ {
Branches = branches; Branches = branches;
DefaultNode = defaultNode; DefaultNode = defaultNode;
} }
public OptionsMarkupExtensionBranch[] Branches { get; } public OptionsMarkupExtensionBranch[] Branches { get; }
public IXamlAstValueNode DefaultNode { get; private set; } public IXamlAstValueNode? DefaultNode { get; private set; }
public override void VisitChildren(IXamlAstVisitor visitor) public override void VisitChildren(IXamlAstVisitor visitor)
{ {
VisitList(Branches, visitor); VisitList(Branches, visitor);
DefaultNode = (IXamlAstValueNode)DefaultNode?.Visit(visitor); DefaultNode = (IXamlAstValueNode?)DefaultNode?.Visit(visitor);
} }
public IXamlType GetReturnType() public IXamlType GetReturnType()
@ -351,7 +352,7 @@ internal class AvaloniaXamlIlOptionMarkupExtensionTransformer : IXamlAstTransfor
// - markup ext "@this" instance (always) // - markup ext "@this" instance (always)
// We always pop context from the stack, as this method decide by itself either context is needed. // We always pop context from the stack, as this method decide by itself either context is needed.
// We store "@this" as a local variable. But only if any conditional method is an instance method. // We store "@this" as a local variable. But only if any conditional method is an instance method.
IXamlLocal @this = null; IXamlLocal? @this = null;
if (Parameters.Count > 0) if (Parameters.Count > 0)
{ {
codeGen.Pop(); codeGen.Pop();
@ -377,7 +378,7 @@ internal class AvaloniaXamlIlOptionMarkupExtensionTransformer : IXamlAstTransfor
} }
if (!branch.ConditionMethod.IsStatic) if (!branch.ConditionMethod.IsStatic)
{ {
codeGen.Ldloc(@this); codeGen.Ldloc(@this!);
} }
context.Emit(branch.Option, codeGen, branch.Option.Type.GetClrType()); context.Emit(branch.Option, codeGen, branch.Option.Type.GetClrType());
codeGen.EmitCall(branch.ConditionMethod); codeGen.EmitCall(branch.ConditionMethod);
@ -402,7 +403,7 @@ internal class AvaloniaXamlIlOptionMarkupExtensionTransformer : IXamlAstTransfor
codeGen.MarkLabel(ret); codeGen.MarkLabel(ret);
} }
public bool Equals(IXamlMethod other) => ReferenceEquals(this, other); public bool Equals(IXamlMethod? other) => ReferenceEquals(this, other);
} }
} }

35
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlPropertyPathTransformer.cs

@ -14,7 +14,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
{ {
class XamlPropertyPathException : XamlTransformException class XamlPropertyPathException : XamlTransformException
{ {
public XamlPropertyPathException(string message, IXamlLineInfo lineInfo, Exception innerException = null) public XamlPropertyPathException(string message, IXamlLineInfo lineInfo, Exception? innerException = null)
: base(message, lineInfo, innerException) : base(message, lineInfo, innerException)
{ {
} }
@ -50,7 +50,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
} }
var elements = new List<IXamlIlPropertyPathElementNode>(); var elements = new List<IXamlIlPropertyPathElementNode>();
IXamlType currentType = parentScope.TargetType.GetClrType(); var currentType = parentScope.TargetType.GetClrType();
var expectProperty = true; var expectProperty = true;
@ -58,13 +58,13 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
var expectTraversal = false; var expectTraversal = false;
var types = context.GetAvaloniaTypes(); var types = context.GetAvaloniaTypes();
IXamlType GetType(string ns, string name) IXamlType GetType(string? ns, string name)
{ {
return TypeReferenceResolver.ResolveType(context, $"{ns}:{name}", false, return TypeReferenceResolver.ResolveType(context, $"{ns}:{name}", false,
text, true).GetClrType(); text, true).GetClrType();
} }
void HandleProperty(string name, string typeNamespace, string typeName) void HandleProperty(string name, string? typeNamespace, string? typeName)
{ {
if(!expectProperty || currentType == null) if(!expectProperty || currentType == null)
throw new XamlPropertyPathException("Unexpected property node", text); throw new XamlPropertyPathException("Unexpected property node", text);
@ -72,7 +72,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
var propertySearchType = var propertySearchType =
typeName != null ? GetType(typeNamespace, typeName) : currentType; typeName != null ? GetType(typeNamespace, typeName) : currentType;
IXamlIlPropertyPathElementNode prop = null; IXamlIlPropertyPathElementNode? prop = null;
var avaloniaPropertyFieldName = name + "Property"; var avaloniaPropertyFieldName = name + "Property";
var avaloniaPropertyField = propertySearchType.GetAllFields().FirstOrDefault(f => var avaloniaPropertyField = propertySearchType.GetAllFields().FirstOrDefault(f =>
f.IsStatic && f.IsPublic && f.Name == avaloniaPropertyFieldName); f.IsStatic && f.IsPublic && f.Name == avaloniaPropertyFieldName);
@ -84,7 +84,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
else else
{ {
var clrProperty = propertySearchType.GetAllProperties().FirstOrDefault(p => p.Name == name); var clrProperty = propertySearchType.GetAllProperties().FirstOrDefault(p => p.Name == name);
prop = new XamlIClrPropertyPathElementNode(clrProperty); if (clrProperty is not null)
prop = new XamlIClrPropertyPathElementNode(clrProperty);
} }
if (prop == null) if (prop == null)
@ -151,7 +152,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
interface IXamlIlPropertyPathElementNode interface IXamlIlPropertyPathElementNode
{ {
void Emit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen); void Emit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen);
IXamlType Type { get; } IXamlType? Type { get; }
} }
class XamlIlChildTraversalPropertyPathElementNode : IXamlIlPropertyPathElementNode class XamlIlChildTraversalPropertyPathElementNode : IXamlIlPropertyPathElementNode
@ -159,9 +160,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
public void Emit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen) public void Emit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen)
=> codeGen.EmitCall( => codeGen.EmitCall(
context.GetAvaloniaTypes() context.GetAvaloniaTypes()
.PropertyPathBuilder.FindMethod(m => m.Name == "ChildTraversal")); .PropertyPathBuilder.GetMethod(m => m.Name == "ChildTraversal"));
public IXamlType Type => null; public IXamlType? Type => null;
} }
class XamlIlAvaloniaPropertyPropertyPathElementNode : IXamlIlPropertyPathElementNode class XamlIlAvaloniaPropertyPropertyPathElementNode : IXamlIlPropertyPathElementNode
@ -178,7 +179,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
=> codeGen => codeGen
.Ldsfld(_field) .Ldsfld(_field)
.EmitCall(context.GetAvaloniaTypes() .EmitCall(context.GetAvaloniaTypes()
.PropertyPathBuilder.FindMethod(m => m.Name == "Property")); .PropertyPathBuilder.GetMethod(m => m.Name == "Property"));
public IXamlType Type { get; } public IXamlType Type { get; }
} }
@ -198,10 +199,10 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
.Emit(context, codeGen, _property); .Emit(context, codeGen, _property);
codeGen.EmitCall(context.GetAvaloniaTypes() codeGen.EmitCall(context.GetAvaloniaTypes()
.PropertyPathBuilder.FindMethod(m => m.Name == "Property")); .PropertyPathBuilder.GetMethod(m => m.Name == "Property"));
} }
public IXamlType Type => _property.Getter?.ReturnType ?? _property.Setter?.Parameters[0]; public IXamlType Type => _property.PropertyType;
} }
class XamlIlCastPropertyPathElementNode : IXamlIlPropertyPathElementNode class XamlIlCastPropertyPathElementNode : IXamlIlPropertyPathElementNode
@ -220,7 +221,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
codeGen codeGen
.Ldtype(_type) .Ldtype(_type)
.EmitCall(context.GetAvaloniaTypes() .EmitCall(context.GetAvaloniaTypes()
.PropertyPathBuilder.FindMethod(m => m.Name == (_ensureType ? "EnsureType" : "Cast"))); .PropertyPathBuilder.GetMethod(m => m.Name == (_ensureType ? "EnsureType" : "Cast")));
} }
public IXamlType Type => _type; public IXamlType Type => _type;
@ -241,14 +242,14 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
} }
public IXamlAstTypeReference Type { get; } public IXamlAstTypeReference Type { get; }
public IXamlType PropertyType => _elements.LastOrDefault()?.Type; public IXamlType? PropertyType => _elements.LastOrDefault()?.Type;
public XamlILNodeEmitResult Emit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen) public XamlILNodeEmitResult Emit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen)
{ {
codeGen codeGen
.Newobj(_types.PropertyPathBuilder.FindConstructor()); .Newobj(_types.PropertyPathBuilder.GetConstructor());
foreach(var e in _elements) foreach(var e in _elements)
e.Emit(context, codeGen); e.Emit(context, codeGen);
codeGen.EmitCall(_types.PropertyPathBuilder.FindMethod(m => m.Name == "Build")); codeGen.EmitCall(_types.PropertyPathBuilder.GetMethod(m => m.Name == "Build"));
return XamlILNodeEmitResult.Type(0, _types.PropertyPath); return XamlILNodeEmitResult.Type(0, _types.PropertyPath);
} }
} }
@ -256,6 +257,6 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
interface IXamlIlPropertyPathNode : IXamlAstValueNode interface IXamlIlPropertyPathNode : IXamlAstValueNode
{ {
IXamlType PropertyType { get; } IXamlType? PropertyType { get; }
} }
} }

4
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlReorderClassesPropertiesTransformer.cs

@ -9,8 +9,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
{ {
if (node is XamlAstObjectNode obj) if (node is XamlAstObjectNode obj)
{ {
IXamlAstNode classesNode = null; IXamlAstNode? classesNode = null;
IXamlAstNode firstSingleClassNode = null; IXamlAstNode? firstSingleClassNode = null;
var types = context.GetAvaloniaTypes(); var types = context.GetAvaloniaTypes();
foreach (var child in obj.Children) foreach (var child in obj.Children)
{ {

4
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlRootObjectScopeTransformer.cs

@ -19,7 +19,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
mnode.Manipulation = new XamlManipulationGroupNode(mnode, mnode.Manipulation = new XamlManipulationGroupNode(mnode,
new[] new[]
{ {
mnode.Manipulation, mnode.Manipulation!,
new HandleRootObjectScopeNode(mnode, context.GetAvaloniaTypes()) new HandleRootObjectScopeNode(mnode, context.GetAvaloniaTypes())
}); });
} }
@ -37,7 +37,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
} }
internal class Emitter : IXamlILAstNodeEmitter internal class Emitter : IXamlILAstNodeEmitter
{ {
public XamlILNodeEmitResult Emit(IXamlAstNode node, XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen) public XamlILNodeEmitResult? Emit(IXamlAstNode node, XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen)
{ {
if (!(node is HandleRootObjectScopeNode)) if (!(node is HandleRootObjectScopeNode))
{ {

72
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSelectorTransformer.cs

@ -15,7 +15,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
{ {
internal class XamlSelectorsTransformException : XamlTransformException internal class XamlSelectorsTransformException : XamlTransformException
{ {
public XamlSelectorsTransformException(string message, IXamlLineInfo lineInfo, Exception innerException = null) public XamlSelectorsTransformException(string message, IXamlLineInfo lineInfo, Exception? innerException = null)
: base(message, lineInfo, innerException) : base(message, lineInfo, innerException)
{ {
} }
@ -46,14 +46,14 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
if (!(pn.Values[0] is XamlAstTextNode tn)) if (!(pn.Values[0] is XamlAstTextNode tn))
throw new XamlSelectorsTransformException("Selector property should be a text node", node); throw new XamlSelectorsTransformException("Selector property should be a text node", node);
var selectorType = pn.Property.GetClrProperty().Getter.ReturnType; var selectorType = pn.Property.GetClrProperty().Getter!.ReturnType;
var initialNode = new XamlIlSelectorInitialNode(node, selectorType); var initialNode = new XamlIlSelectorInitialNode(node, selectorType);
var avaloniaAttachedPropertyT = context.GetAvaloniaTypes().AvaloniaAttachedPropertyT; var avaloniaAttachedPropertyT = context.GetAvaloniaTypes().AvaloniaAttachedPropertyT;
XamlIlSelectorNode Create(IEnumerable<SelectorGrammar.ISyntax> syntax, XamlIlSelectorNode Create(IEnumerable<SelectorGrammar.ISyntax> syntax,
Func<string, string, XamlAstClrTypeReference> typeResolver) Func<string, string, XamlAstClrTypeReference> typeResolver)
{ {
XamlIlSelectorNode result = initialNode; XamlIlSelectorNode result = initialNode;
XamlIlOrSelectorNode results = null; XamlIlOrSelectorNode? results = null;
foreach (var i in syntax) foreach (var i in syntax)
{ {
switch (i) switch (i)
@ -73,7 +73,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
break; break;
case SelectorGrammar.PropertySyntax property: case SelectorGrammar.PropertySyntax property:
{ {
var type = result?.TargetType; var type = result.TargetType;
if (type == null) if (type == null)
throw new XamlTransformException("Property selectors must be applied to a type.", node); throw new XamlTransformException("Property selectors must be applied to a type.", node);
@ -96,7 +96,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
} }
case SelectorGrammar.AttachedPropertySyntax attachedProperty: case SelectorGrammar.AttachedPropertySyntax attachedProperty:
{ {
var targetType = result?.TargetType; var targetType = result.TargetType;
if (targetType == null) if (targetType == null)
{ {
throw new XamlTransformException("Attached Property selectors must be applied to a type.",node); throw new XamlTransformException("Attached Property selectors must be applied to a type.",node);
@ -172,7 +172,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
} }
} }
if (results != null && result != null) if (results != null)
{ {
results.Add(result); results.Add(result);
} }
@ -191,14 +191,13 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
} }
var selector = Create(parsed, (p, n) var selector = Create(parsed, (p, n)
=> TypeReferenceResolver.ResolveType(context, $"{p}:{n}", true, node, true) => TypeReferenceResolver.ResolveType(context, $"{p}:{n}", true, node, true));
?? new XamlAstClrTypeReference(node, XamlPseudoType.Unknown, false));
pn.Values[0] = selector; pn.Values[0] = selector;
var templateType = GetLastTemplateTypeFromSelector(selector); var templateType = GetLastTemplateTypeFromSelector(selector);
var styleNode = new AvaloniaXamlIlTargetTypeMetadataNode(on, var styleNode = new AvaloniaXamlIlTargetTypeMetadataNode(on,
new XamlAstClrTypeReference(selector, selector.TargetType, false), new XamlAstClrTypeReference(selector, selector.TargetType!, false),
AvaloniaXamlIlTargetTypeMetadataNode.ScopeTypes.Style); AvaloniaXamlIlTargetTypeMetadataNode.ScopeTypes.Style);
return templateType switch return templateType switch
@ -210,7 +209,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
}; };
} }
private static IXamlType GetLastTemplateTypeFromSelector(XamlIlSelectorNode node) private static IXamlType? GetLastTemplateTypeFromSelector(XamlIlSelectorNode? node)
{ {
while (node is not null) while (node is not null)
{ {
@ -219,7 +218,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
SelectorType: XamlIlCombinatorSelector.CombinatorSelectorType.Template SelectorType: XamlIlCombinatorSelector.CombinatorSelectorType.Template
}) })
{ {
return node.Previous.TargetType; return node.Previous?.TargetType;
} }
node = node.Previous; node = node.Previous;
} }
@ -230,15 +229,15 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
abstract class XamlIlSelectorNode : XamlAstNode, IXamlAstValueNode, IXamlAstEmitableNode<IXamlILEmitter, XamlILNodeEmitResult> abstract class XamlIlSelectorNode : XamlAstNode, IXamlAstValueNode, IXamlAstEmitableNode<IXamlILEmitter, XamlILNodeEmitResult>
{ {
internal XamlIlSelectorNode Previous { get; } internal XamlIlSelectorNode? Previous { get; }
public abstract IXamlType TargetType { get; } public abstract IXamlType? TargetType { get; }
public XamlIlSelectorNode(XamlIlSelectorNode previous, public XamlIlSelectorNode(XamlIlSelectorNode? previous,
IXamlLineInfo info = null, IXamlLineInfo? info = null,
IXamlType selectorType = null) : base(info ?? previous) IXamlType? selectorType = null) : base((info ?? previous)!)
{ {
Previous = previous; Previous = previous;
Type = selectorType == null ? previous.Type : new XamlAstClrTypeReference(this, selectorType, false); Type = selectorType == null ? previous!.Type : new XamlAstClrTypeReference(this, selectorType, false);
} }
public IXamlAstTypeReference Type { get; } public IXamlAstTypeReference Type { get; }
@ -256,7 +255,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
protected void EmitCall(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen, Func<IXamlMethod, bool> method) protected void EmitCall(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen, Func<IXamlMethod, bool> method)
{ {
var selectors = context.Configuration.TypeSystem.GetType("Avalonia.Styling.Selectors"); var selectors = context.Configuration.TypeSystem.GetType("Avalonia.Styling.Selectors");
var found = selectors.FindMethod(m => m.IsStatic && m.Parameters.Count > 0 && method(m)); var found = selectors.GetMethod(m => m.IsStatic && m.Parameters.Count > 0 && method(m));
codeGen.EmitCall(found); codeGen.EmitCall(found);
} }
} }
@ -268,7 +267,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
{ {
} }
public override IXamlType TargetType => null; public override IXamlType? TargetType => null;
protected override void DoEmit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen) => codeGen.Ldnull(); protected override void DoEmit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen) => codeGen.Ldnull();
} }
@ -310,7 +309,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
} }
public override IXamlType TargetType => Previous?.TargetType; public override IXamlType? TargetType => Previous?.TargetType;
protected override void DoEmit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen) protected override void DoEmit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen)
{ {
codeGen.Ldstr(String); codeGen.Ldstr(String);
@ -336,7 +336,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
} }
public CombinatorSelectorType SelectorType => _type; public CombinatorSelectorType SelectorType => _type;
public override IXamlType TargetType => null; public override IXamlType? TargetType => null;
protected override void DoEmit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen) protected override void DoEmit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen)
{ {
var name = _type.ToString(); var name = _type.ToString();
@ -354,7 +354,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
Argument = argument; Argument = argument;
} }
public override IXamlType TargetType => Previous?.TargetType; public override IXamlType? TargetType => Previous?.TargetType;
protected override void DoEmit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen) protected override void DoEmit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen)
{ {
context.Emit(Argument, codeGen, Type.GetClrType()); context.Emit(Argument, codeGen, Type.GetClrType());
@ -382,7 +383,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
_type = type; _type = type;
} }
public override IXamlType TargetType => Previous?.TargetType; public override IXamlType? TargetType => Previous?.TargetType;
protected override void DoEmit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen) protected override void DoEmit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen)
{ {
codeGen.Ldc_I4(_step); codeGen.Ldc_I4(_step);
@ -406,12 +408,13 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
public IXamlProperty Property { get; set; } public IXamlProperty Property { get; set; }
public IXamlAstValueNode Value { get; set; } public IXamlAstValueNode Value { get; set; }
public override IXamlType TargetType => Previous?.TargetType; public override IXamlType? TargetType => Previous?.TargetType;
protected override void DoEmit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen) protected override void DoEmit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen)
{ {
if (!XamlIlAvaloniaPropertyHelper.Emit(context, codeGen, Property)) if (!XamlIlAvaloniaPropertyHelper.Emit(context, codeGen, Property))
throw new XamlX.XamlLoadException( throw new XamlX.XamlLoadException(
$"{Property.Name} of {(Property.Setter ?? Property.Getter).DeclaringType.GetFqn()} doesn't seem to be an AvaloniaProperty", $"{Property.Name} of {Property.DeclaringType.GetFqn()} doesn't seem to be an AvaloniaProperty",
this); this);
context.Emit(Value, codeGen, context.Configuration.WellKnownTypes.Object); context.Emit(Value, codeGen, context.Configuration.WellKnownTypes.Object);
EmitCall(context, codeGen, EmitCall(context, codeGen,
@ -437,7 +440,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
public IXamlField PropertyFiled { get; set; } public IXamlField PropertyFiled { get; set; }
public IXamlAstValueNode Value { get; set; } public IXamlAstValueNode Value { get; set; }
public override IXamlType TargetType => Previous?.TargetType; public override IXamlType? TargetType => Previous?.TargetType;
protected override void DoEmit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen) protected override void DoEmit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen)
{ {
codeGen.Ldsfld(PropertyFiled); codeGen.Ldsfld(PropertyFiled);
@ -462,25 +466,25 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
_selectors.Add(node); _selectors.Add(node);
} }
public override IXamlType TargetType public override IXamlType? TargetType
{ {
get get
{ {
IXamlType result = null; IXamlType? result = null;
foreach (var selector in _selectors) foreach (var selector in _selectors)
{ {
if (selector.TargetType == null) if (selector.TargetType is not { } targetType)
{ {
return null; return null;
} }
else if (result == null) else if (result == null)
{ {
result = selector.TargetType; result = targetType;
} }
else else
{ {
while (!result.IsAssignableFrom(selector.TargetType)) while (result is not null && !result.IsAssignableFrom(selector.TargetType))
{ {
result = result.BaseType; result = result.BaseType;
} }
@ -500,11 +504,11 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
_selectors[0].Emit(context, codeGen); _selectors[0].Emit(context, codeGen);
return; return;
} }
var listType = context.Configuration.TypeSystem.FindType("System.Collections.Generic.List`1") var listType = context.Configuration.TypeSystem.GetType("System.Collections.Generic.List`1")
.MakeGenericType(base.Type.GetClrType()); .MakeGenericType(base.Type.GetClrType());
var add = listType.FindMethod("Add", context.Configuration.WellKnownTypes.Void, false, Type.GetClrType()); var add = listType.GetMethod("Add", context.Configuration.WellKnownTypes.Void, false, Type.GetClrType());
codeGen codeGen
.Newobj(listType.FindConstructor()); .Newobj(listType.GetConstructor());
foreach (var s in _selectors) foreach (var s in _selectors)
{ {
codeGen.Dup(); codeGen.Dup();

26
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs

@ -12,7 +12,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
{ {
class XamlStyleTransformException : XamlTransformException class XamlStyleTransformException : XamlTransformException
{ {
public XamlStyleTransformException(string message, IXamlLineInfo lineInfo, Exception innerException = null) public XamlStyleTransformException(string message, IXamlLineInfo lineInfo, Exception? innerException = null)
: base(message, lineInfo, innerException) : base(message, lineInfo, innerException)
{ {
} }
@ -26,8 +26,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
&& on.Type.GetClrType().FullName == "Avalonia.Styling.Setter")) && on.Type.GetClrType().FullName == "Avalonia.Styling.Setter"))
return node; return node;
IXamlType targetType = null; IXamlType? targetType = null;
IXamlLineInfo lineInfo = null;
var avaloniaTypes = context.GetAvaloniaTypes(); var avaloniaTypes = context.GetAvaloniaTypes();
@ -39,7 +38,6 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
{ {
targetType = styleParent.TargetType.GetClrType() targetType = styleParent.TargetType.GetClrType()
?? throw new XamlStyleTransformException("Can not find parent Style Selector or ControlTemplate TargetType. If setter is not part of the style, you can set x:SetterTargetType directive on its parent.", node); ?? throw new XamlStyleTransformException("Can not find parent Style Selector or ControlTemplate TargetType. If setter is not part of the style, you can set x:SetterTargetType directive on its parent.", node);
lineInfo = on;
} }
if (targetType == null) if (targetType == null)
@ -47,13 +45,12 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
throw new XamlStyleTransformException("Could not determine target type of Setter", node); throw new XamlStyleTransformException("Could not determine target type of Setter", node);
} }
IXamlType propType = null; IXamlType? propType;
IXamlIlAvaloniaPropertyNode avaloniaPropertyNode = null;
var property = @on.Children.OfType<XamlAstXamlPropertyValueNode>() var property = @on.Children.OfType<XamlAstXamlPropertyValueNode>()
.FirstOrDefault(x => x.Property.GetClrProperty().Name == "Property"); .FirstOrDefault(x => x.Property.GetClrProperty().Name == "Property");
if (property != null) if (property != null)
{ {
avaloniaPropertyNode = property.Values.OfType<IXamlIlAvaloniaPropertyNode>().FirstOrDefault(); var avaloniaPropertyNode = property.Values.OfType<IXamlIlAvaloniaPropertyNode>().FirstOrDefault();
if (avaloniaPropertyNode is null) if (avaloniaPropertyNode is null)
{ {
var propertyName = property.Values.OfType<XamlAstTextNode>().FirstOrDefault()?.Text; var propertyName = property.Values.OfType<XamlAstTextNode>().FirstOrDefault()?.Text;
@ -61,7 +58,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
throw new XamlStyleTransformException("Setter.Property must be a string.", node); throw new XamlStyleTransformException("Setter.Property must be a string.", node);
avaloniaPropertyNode = XamlIlAvaloniaPropertyHelper.CreateNode(context, propertyName, avaloniaPropertyNode = XamlIlAvaloniaPropertyHelper.CreateNode(context, propertyName,
new XamlAstClrTypeReference(lineInfo, targetType, false), property.Values[0]); new XamlAstClrTypeReference(on, targetType, false), property.Values[0]);
property.Values = new List<IXamlAstValueNode> {avaloniaPropertyNode}; property.Values = new List<IXamlAstValueNode> {avaloniaPropertyNode};
} }
@ -90,9 +87,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
&& XamlTransformHelpers.TryGetCorrectlyTypedValue(context, textValue, && XamlTransformHelpers.TryGetCorrectlyTypedValue(context, textValue,
propType, out _)) propType, out _))
{ {
var setterValueProperty = new SetterValueProperty( var setterValueProperty = new SetterValueProperty(
(IXamlLineInfo)valueProperty?.Property ?? textValue, (IXamlLineInfo?)valueProperty?.Property ?? textValue,
on.Type.GetClrType(), propType, avaloniaTypes); on.Type.GetClrType(), propType, avaloniaTypes);
if (valueProperty is not null) if (valueProperty is not null)
{ {
@ -116,8 +112,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
// but we have better validation in runtime for TemplatedBinding. // but we have better validation in runtime for TemplatedBinding.
// See Correctly_Resolve_TemplateBinding_In_Theme_Detached_Template test. // See Correctly_Resolve_TemplateBinding_In_Theme_Detached_Template test.
if (!avaloniaTypes.ITemplateOfControl.IsAssignableFrom(propType) if (!avaloniaTypes.ITemplateOfControl.IsAssignableFrom(propType)
&& on.Children.OfType<XamlAstObjectNode>()?.FirstOrDefault() is { } valueObj && on.Children.OfType<XamlAstObjectNode>().FirstOrDefault() is { } valueObj
&& avaloniaTypes.ITemplateOfControl.IsAssignableFrom(valueObj?.Type.GetClrType())) && avaloniaTypes.ITemplateOfControl.IsAssignableFrom(valueObj.Type.GetClrType()))
{ {
on.Children[on.Children.IndexOf(valueObj)] = new AvaloniaXamlIlTargetTypeMetadataNode(valueObj, on.Children[on.Children.IndexOf(valueObj)] = new AvaloniaXamlIlTargetTypeMetadataNode(valueObj,
new XamlAstClrTypeReference(on, targetType, false), new XamlAstClrTypeReference(on, targetType, false),
@ -169,10 +165,10 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
}; };
} }
private bool Equals(XamlIlDirectCallPropertySetter other) private bool Equals(XamlIlDirectCallPropertySetter? other)
=> Equals(_method, other._method) && Equals(_type, other._type); => other is not null && Equals(_method, other._method) && Equals(_type, other._type);
public override bool Equals(object obj) public override bool Equals(object? obj)
=> Equals(obj as XamlIlDirectCallPropertySetter); => Equals(obj as XamlIlDirectCallPropertySetter);
public override int GetHashCode() public override int GetHashCode()

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

@ -24,7 +24,8 @@ internal class AvaloniaXamlIlThemeVariantProviderTransformer : IXamlAstTransform
var themeDictionariesColl = avTypes.IDictionaryT.MakeGenericType(avTypes.ThemeVariant, avTypes.IThemeVariantProvider); var themeDictionariesColl = avTypes.IDictionaryT.MakeGenericType(avTypes.ThemeVariant, avTypes.IThemeVariantProvider);
if (context.ParentNodes().FirstOrDefault() is not XamlAstXamlPropertyValueNode propertyValueNode if (context.ParentNodes().FirstOrDefault() is not XamlAstXamlPropertyValueNode propertyValueNode
|| !themeDictionariesColl.IsAssignableFrom(propertyValueNode.Property.GetClrProperty().Getter.ReturnType)) || propertyValueNode.Property.GetClrProperty().Getter is not { } getter
|| !themeDictionariesColl.IsAssignableFrom(getter.ReturnType))
{ {
return node; return node;
} }

14
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlTransformInstanceAttachedProperties.cs

@ -30,7 +30,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
if (clrProp != null if (clrProp != null
&& (clrProp.Getter?.IsStatic == false || clrProp.Setter?.IsStatic == false)) && (clrProp.Getter?.IsStatic == false || clrProp.Setter?.IsStatic == false))
{ {
var declaringType = (clrProp.Getter ?? clrProp.Setter)?.DeclaringType; var declaringType = clrProp.DeclaringType;
var avaloniaPropertyFieldName = prop.Name + "Property"; var avaloniaPropertyFieldName = prop.Name + "Property";
var avaloniaPropertyField = declaringType.Fields.FirstOrDefault(f => f.IsStatic && f.Name == avaloniaPropertyFieldName); var avaloniaPropertyField = declaringType.Fields.FirstOrDefault(f => f.IsStatic && f.Name == avaloniaPropertyFieldName);
if (avaloniaPropertyField != null) if (avaloniaPropertyField != null)
@ -52,10 +52,10 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
if (avaloniaPropertyType == null) if (avaloniaPropertyType == null)
return node; return node;
if (avaloniaPropertyType.GenericArguments?.Count > 1) if (avaloniaPropertyType.GenericArguments.Count > 1)
return node; return node;
var propertyType = avaloniaPropertyType.GenericArguments?.Count == 1 ? var propertyType = avaloniaPropertyType.GenericArguments.Count == 1 ?
avaloniaPropertyType.GenericArguments[0] : avaloniaPropertyType.GenericArguments[0] :
context.Configuration.WellKnownTypes.Object; context.Configuration.WellKnownTypes.Object;
@ -97,8 +97,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
_avaloniaPropertyType = avaloniaPropertyType; _avaloniaPropertyType = avaloniaPropertyType;
// XamlIl doesn't support generic methods yet // XamlIl doesn't support generic methods yet
if (_avaloniaPropertyType.GenericArguments?.Count > 0) if (_avaloniaPropertyType.GenericArguments.Count > 0)
_avaloniaPropertyType = _avaloniaPropertyType.BaseType; _avaloniaPropertyType = _avaloniaPropertyType.BaseType!;
_avaloniaObject = avaloniaObject; _avaloniaObject = avaloniaObject;
_field = field; _field = field;
@ -173,9 +173,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
public IXamlMethod MakeGenericMethod(IReadOnlyList<IXamlType> typeArguments) public IXamlMethod MakeGenericMethod(IReadOnlyList<IXamlType> typeArguments)
=> throw new System.NotSupportedException(); => throw new System.NotSupportedException();
public bool Equals(IXamlMethod? other) =>
public bool Equals(IXamlMethod other) =>
other is GetterMethod m && m.Name == Name && m.DeclaringType.Equals(DeclaringType); other is GetterMethod m && m.Name == Name && m.DeclaringType.Equals(DeclaringType);
public IXamlType ReturnType => Parent.PropertyType; public IXamlType ReturnType => Parent.PropertyType;
public IReadOnlyList<IXamlType> Parameters { get; } public IReadOnlyList<IXamlType> Parameters { get; }

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

@ -28,7 +28,6 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
public IXamlType IDisposable { get; } public IXamlType IDisposable { get; }
public IXamlType ICommand { get; } public IXamlType ICommand { get; }
public XamlTypeWellKnownTypes XamlIlTypes { get; } public XamlTypeWellKnownTypes XamlIlTypes { get; }
public XamlLanguageTypeMappings XamlIlMappings { get; }
public IXamlType Transitions { get; } public IXamlType Transitions { get; }
public IXamlType AssignBindingAttribute { get; } public IXamlType AssignBindingAttribute { get; }
public IXamlType DependsOnAttribute { get; } public IXamlType DependsOnAttribute { get; }
@ -143,12 +142,12 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
internal InteractivityWellKnownTypes(TransformerConfiguration cfg) internal InteractivityWellKnownTypes(TransformerConfiguration cfg)
{ {
var ts = cfg.TypeSystem; var ts = cfg.TypeSystem;
Interactive = ts.FindType("Avalonia.Interactivity.Interactive"); Interactive = ts.GetType("Avalonia.Interactivity.Interactive");
RoutedEvent = ts.FindType("Avalonia.Interactivity.RoutedEvent"); RoutedEvent = ts.GetType("Avalonia.Interactivity.RoutedEvent");
RoutedEventArgs = ts.FindType("Avalonia.Interactivity.RoutedEventArgs"); RoutedEventArgs = ts.GetType("Avalonia.Interactivity.RoutedEventArgs");
var eventHanlderT = ts.FindType("System.EventHandler`1"); var eventHanlderT = ts.GetType("System.EventHandler`1");
RoutedEventHandler = eventHanlderT.MakeGenericType(RoutedEventArgs); RoutedEventHandler = eventHanlderT.MakeGenericType(RoutedEventArgs);
AddHandler = Interactive.FindMethod(m => m.IsPublic AddHandler = Interactive.GetMethod(m => m.IsPublic
&& !m.IsStatic && !m.IsStatic
&& m.Name == "AddHandler" && m.Name == "AddHandler"
&& m.Parameters.Count == 4 && m.Parameters.Count == 4
@ -157,15 +156,15 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
&& m.Parameters[2].IsEnum && m.Parameters[2].IsEnum
&& m.Parameters[3].Equals(cfg.WellKnownTypes.Boolean) && m.Parameters[3].Equals(cfg.WellKnownTypes.Boolean)
); );
AddHandlerT = Interactive.FindMethod(m => m.IsPublic AddHandlerT = Interactive.GetMethod(m => m.IsPublic
&& !m.IsStatic && !m.IsStatic
&& m.Name == "AddHandler" && m.Name == "AddHandler"
&& m.Parameters.Count == 4 && m.Parameters.Count == 4
&& RoutedEvent.IsAssignableFrom(m.Parameters[0]) && RoutedEvent.IsAssignableFrom(m.Parameters[0])
&& m.Parameters[0].GenericArguments?.Count == 1 // This is specific this case workaround to check is generic method && m.Parameters[0].GenericArguments.Count == 1 // This is specific this case workaround to check is generic method
&& (cfg.WellKnownTypes.Delegate).IsAssignableFrom(m.Parameters[1]) && (cfg.WellKnownTypes.Delegate).IsAssignableFrom(m.Parameters[1])
&& m.Parameters[2].IsEnum && m.Parameters[2].IsEnum
&& m.Parameters[3].Equals(cfg.WellKnownTypes.Boolean) == true && m.Parameters[3].Equals(cfg.WellKnownTypes.Boolean)
); );
} }
@ -186,7 +185,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
AvaloniaAttachedPropertyT = cfg.TypeSystem.GetType("Avalonia.AttachedProperty`1"); AvaloniaAttachedPropertyT = cfg.TypeSystem.GetType("Avalonia.AttachedProperty`1");
BindingPriority = cfg.TypeSystem.GetType("Avalonia.Data.BindingPriority"); BindingPriority = cfg.TypeSystem.GetType("Avalonia.Data.BindingPriority");
AvaloniaObjectSetStyledPropertyValue = AvaloniaObject AvaloniaObjectSetStyledPropertyValue = AvaloniaObject
.FindMethod(m => m.IsPublic && !m.IsStatic && m.Name == "SetValue" .GetMethod(m => m.IsPublic && !m.IsStatic && m.Name == "SetValue"
&& m.Parameters.Count == 3 && m.Parameters.Count == 3
&& m.Parameters[0].Name == "StyledProperty`1" && m.Parameters[0].Name == "StyledProperty`1"
&& m.Parameters[2].Equals(BindingPriority)); && m.Parameters[2].Equals(BindingPriority));
@ -205,7 +204,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
AvaloniaListAttribute = cfg.TypeSystem.GetType("Avalonia.Metadata.AvaloniaListAttribute"); AvaloniaListAttribute = cfg.TypeSystem.GetType("Avalonia.Metadata.AvaloniaListAttribute");
AvaloniaList = cfg.TypeSystem.GetType("Avalonia.Collections.AvaloniaList`1"); AvaloniaList = cfg.TypeSystem.GetType("Avalonia.Collections.AvaloniaList`1");
OnExtensionType = cfg.TypeSystem.GetType("Avalonia.Markup.Xaml.MarkupExtensions.On"); OnExtensionType = cfg.TypeSystem.GetType("Avalonia.Markup.Xaml.MarkupExtensions.On");
AvaloniaObjectBindMethod = AvaloniaObjectExtensions.FindMethod("Bind", IDisposable, false, AvaloniaObject, AvaloniaObjectBindMethod = AvaloniaObjectExtensions.GetMethod("Bind", IDisposable, false, AvaloniaObject,
AvaloniaProperty, AvaloniaProperty,
IBinding, cfg.WellKnownTypes.Object); IBinding, cfg.WellKnownTypes.Object);
UnsetValueType = cfg.TypeSystem.GetType("Avalonia.UnsetValueType"); UnsetValueType = cfg.TypeSystem.GetType("Avalonia.UnsetValueType");
@ -230,7 +229,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
NameScopeSetNameScope = NameScope.GetMethod(new FindMethodMethodSignature("SetNameScope", NameScopeSetNameScope = NameScope.GetMethod(new FindMethodMethodSignature("SetNameScope",
XamlIlTypes.Void, StyledElement, INameScope) XamlIlTypes.Void, StyledElement, INameScope)
{ IsStatic = true }); { IsStatic = true });
AvaloniaObjectSetValueMethod = AvaloniaObject.FindMethod("SetValue", IDisposable, AvaloniaObjectSetValueMethod = AvaloniaObject.GetMethod("SetValue", IDisposable,
false, AvaloniaProperty, XamlIlTypes.Object, BindingPriority); false, AvaloniaProperty, XamlIlTypes.Object, BindingPriority);
IPropertyInfo = cfg.TypeSystem.GetType("Avalonia.Data.Core.IPropertyInfo"); IPropertyInfo = cfg.TypeSystem.GetType("Avalonia.Data.Core.IPropertyInfo");
ClrPropertyInfo = cfg.TypeSystem.GetType("Avalonia.Data.Core.ClrPropertyInfo"); ClrPropertyInfo = cfg.TypeSystem.GetType("Avalonia.Data.Core.ClrPropertyInfo");
@ -292,7 +291,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
StyledElementClassesProperty = StyledElementClassesProperty =
StyledElement.Properties.First(x => x.Name == "Classes" && x.PropertyType.Equals(Classes)); StyledElement.Properties.First(x => x.Name == "Classes" && x.PropertyType.Equals(Classes));
ClassesBindMethod = cfg.TypeSystem.GetType("Avalonia.StyledElementExtensions") ClassesBindMethod = cfg.TypeSystem.GetType("Avalonia.StyledElementExtensions")
.FindMethod("BindClass", IDisposable, false, StyledElement, .GetMethod("BindClass", IDisposable, false, StyledElement,
cfg.WellKnownTypes.String, cfg.WellKnownTypes.String,
IBinding, cfg.WellKnownTypes.Object); IBinding, cfg.WellKnownTypes.Object);
@ -311,10 +310,10 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
MergeResourceInclude = cfg.TypeSystem.GetType("Avalonia.Markup.Xaml.Styling.MergeResourceInclude"); MergeResourceInclude = cfg.TypeSystem.GetType("Avalonia.Markup.Xaml.Styling.MergeResourceInclude");
IResourceDictionary = cfg.TypeSystem.GetType("Avalonia.Controls.IResourceDictionary"); IResourceDictionary = cfg.TypeSystem.GetType("Avalonia.Controls.IResourceDictionary");
ResourceDictionary = cfg.TypeSystem.GetType("Avalonia.Controls.ResourceDictionary"); ResourceDictionary = cfg.TypeSystem.GetType("Avalonia.Controls.ResourceDictionary");
ResourceDictionaryDeferredAdd = ResourceDictionary.FindMethod("AddDeferred", XamlIlTypes.Void, true, XamlIlTypes.Object, ResourceDictionaryDeferredAdd = ResourceDictionary.GetMethod("AddDeferred", XamlIlTypes.Void, true, XamlIlTypes.Object,
cfg.TypeSystem.GetType("Avalonia.Controls.IDeferredContent")); cfg.TypeSystem.GetType("Avalonia.Controls.IDeferredContent"));
ResourceDictionaryEnsureCapacity = ResourceDictionary.FindMethod("EnsureCapacity", XamlIlTypes.Void, true, XamlIlTypes.Int32); ResourceDictionaryEnsureCapacity = ResourceDictionary.GetMethod("EnsureCapacity", XamlIlTypes.Void, true, XamlIlTypes.Int32);
ResourceDictionaryGetCount = ResourceDictionary.FindMethod("get_Count", XamlIlTypes.Int32, true); ResourceDictionaryGetCount = ResourceDictionary.GetMethod("get_Count", XamlIlTypes.Int32, true);
IThemeVariantProvider = cfg.TypeSystem.GetType("Avalonia.Controls.IThemeVariantProvider"); IThemeVariantProvider = cfg.TypeSystem.GetType("Avalonia.Controls.IThemeVariantProvider");
UriKind = cfg.TypeSystem.GetType("System.UriKind"); UriKind = cfg.TypeSystem.GetType("System.UriKind");
UriConstructor = Uri.GetConstructor(new List<IXamlType>() { cfg.WellKnownTypes.String, UriKind }); UriConstructor = Uri.GetConstructor(new List<IXamlType>() { cfg.WellKnownTypes.String, UriKind });

2
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Visitors/NameScopeRegistrationVisitor.cs

@ -25,7 +25,7 @@ internal class NameScopeRegistrationVisitor : Dictionary<string, (IXamlType type
&& node is AvaloniaNameScopeRegistrationXamlIlNode nameScopeRegistration && node is AvaloniaNameScopeRegistrationXamlIlNode nameScopeRegistration
&& nameScopeRegistration.Name is XamlAstTextNode textNode) && nameScopeRegistration.Name is XamlAstTextNode textNode)
{ {
this[textNode.Text] = (nameScopeRegistration.TargetType, textNode); this[textNode.Text] = (nameScopeRegistration.TargetType ?? XamlPseudoType.Unknown, textNode);
} }
return node; return node;

43
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs

@ -51,9 +51,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
public static bool Emit(XamlIlEmitContext context, IXamlILEmitter emitter, IXamlProperty property) public static bool Emit(XamlIlEmitContext context, IXamlILEmitter emitter, IXamlProperty property)
{ {
var type = (property.Getter ?? property.Setter).DeclaringType;
var name = property.Name + "Property"; var name = property.Name + "Property";
var found = type.Fields.FirstOrDefault(f => f.IsStatic && f.Name == name); var found = property.DeclaringType.Fields.FirstOrDefault(f => f.IsStatic && f.Name == name);
if (found == null) if (found == null)
return false; return false;
@ -225,11 +224,13 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
AvaloniaXamlIlWellKnownTypes types, AvaloniaXamlIlWellKnownTypes types,
IXamlType declaringType, IXamlType declaringType,
IXamlField avaloniaProperty, IXamlField avaloniaProperty,
bool allowNull) bool allowNull,
IReadOnlyList<IXamlType> parameters)
{ {
Types = types; Types = types;
AvaloniaProperty = avaloniaProperty; AvaloniaProperty = avaloniaProperty;
TargetType = declaringType; TargetType = declaringType;
Parameters = parameters;
BinderParameters = new PropertySetterBinderParameters BinderParameters = new PropertySetterBinderParameters
{ {
AllowXNull = allowNull, AllowXNull = allowNull,
@ -241,7 +242,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
public PropertySetterBinderParameters BinderParameters { get; } public PropertySetterBinderParameters BinderParameters { get; }
public IReadOnlyList<IXamlType> Parameters { get; set; } public IReadOnlyList<IXamlType> Parameters { get; }
public IReadOnlyList<IXamlCustomAttribute> CustomAttributes => Array.Empty<IXamlCustomAttribute>(); public IReadOnlyList<IXamlCustomAttribute> CustomAttributes => Array.Empty<IXamlCustomAttribute>();
public abstract void Emit(IXamlILEmitter emitter); public abstract void Emit(IXamlILEmitter emitter);
@ -251,7 +252,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
IXamlILEmitter emitter, IXamlILEmitter emitter,
IReadOnlyList<IXamlAstValueNode> arguments); IReadOnlyList<IXamlAstValueNode> arguments);
public bool Equals(AvaloniaPropertyCustomSetter other) public bool Equals(AvaloniaPropertyCustomSetter? other)
{ {
if (ReferenceEquals(null, other)) if (ReferenceEquals(null, other))
return false; return false;
@ -261,7 +262,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
return GetType() == other.GetType() && AvaloniaProperty.Equals(other.AvaloniaProperty); return GetType() == other.GetType() && AvaloniaProperty.Equals(other.AvaloniaProperty);
} }
public override bool Equals(object obj) public override bool Equals(object? obj)
=> Equals(obj as AvaloniaPropertyCustomSetter); => Equals(obj as AvaloniaPropertyCustomSetter);
public override int GetHashCode() public override int GetHashCode()
@ -270,11 +271,12 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
class BindingSetter : AvaloniaPropertyCustomSetter class BindingSetter : AvaloniaPropertyCustomSetter
{ {
public BindingSetter(AvaloniaXamlIlWellKnownTypes types, public BindingSetter(
AvaloniaXamlIlWellKnownTypes types,
IXamlType declaringType, IXamlType declaringType,
IXamlField avaloniaProperty) : base(types, declaringType, avaloniaProperty, false) IXamlField avaloniaProperty)
: base(types, declaringType, avaloniaProperty, false, [types.IBinding])
{ {
Parameters = new[] { types.IBinding };
} }
public override void Emit(IXamlILEmitter emitter) public override void Emit(IXamlILEmitter emitter)
@ -307,11 +309,12 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
class BindingWithPrioritySetter : AvaloniaPropertyCustomSetter class BindingWithPrioritySetter : AvaloniaPropertyCustomSetter
{ {
public BindingWithPrioritySetter(AvaloniaXamlIlWellKnownTypes types, public BindingWithPrioritySetter(
AvaloniaXamlIlWellKnownTypes types,
IXamlType declaringType, IXamlType declaringType,
IXamlField avaloniaProperty) : base(types, declaringType, avaloniaProperty, false) IXamlField avaloniaProperty)
: base(types, declaringType, avaloniaProperty, false, [types.BindingPriority, types.IBinding])
{ {
Parameters = new[] { types.BindingPriority, types.IBinding };
} }
public override void Emit(IXamlILEmitter emitter) public override void Emit(IXamlILEmitter emitter)
@ -345,11 +348,13 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
class SetValueWithPrioritySetter : AvaloniaPropertyCustomSetter class SetValueWithPrioritySetter : AvaloniaPropertyCustomSetter
{ {
public SetValueWithPrioritySetter(AvaloniaXamlIlWellKnownTypes types, IXamlType declaringType, IXamlField avaloniaProperty, public SetValueWithPrioritySetter(
AvaloniaXamlIlWellKnownTypes types,
IXamlType declaringType,
IXamlField avaloniaProperty,
IXamlType propertyType) IXamlType propertyType)
: base(types, declaringType, avaloniaProperty, propertyType.AcceptsNull()) : base(types, declaringType, avaloniaProperty, propertyType.AcceptsNull(), [types.BindingPriority, propertyType])
{ {
Parameters = new[] { types.BindingPriority, propertyType };
} }
public override void Emit(IXamlILEmitter emitter) public override void Emit(IXamlILEmitter emitter)
@ -393,10 +398,12 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
class UnsetValueSetter : AvaloniaPropertyCustomSetter class UnsetValueSetter : AvaloniaPropertyCustomSetter
{ {
public UnsetValueSetter(AvaloniaXamlIlWellKnownTypes types, IXamlType declaringType, IXamlField avaloniaProperty) public UnsetValueSetter(
: base(types, declaringType, avaloniaProperty, false) AvaloniaXamlIlWellKnownTypes types,
IXamlType declaringType,
IXamlField avaloniaProperty)
: base(types, declaringType, avaloniaProperty, false, [types.UnsetValueType])
{ {
Parameters = new[] { types.UnsetValueType };
} }
public override void Emit(IXamlILEmitter codegen) public override void Emit(IXamlILEmitter codegen)

99
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlBindingPathHelper.cs

@ -21,7 +21,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
{ {
public static IXamlType UpdateCompiledBindingExtension(AstTransformationContext context, XamlAstConstructableObjectNode binding, Func<IXamlType> startTypeResolver, IXamlType selfType) public static IXamlType UpdateCompiledBindingExtension(AstTransformationContext context, XamlAstConstructableObjectNode binding, Func<IXamlType> startTypeResolver, IXamlType selfType)
{ {
IXamlType bindingResultType = null; IXamlType? bindingResultType;
if (binding.Arguments.Count > 0 && binding.Arguments[0] is ParsedBindingPathNode bindingPath) if (binding.Arguments.Count > 0 && binding.Arguments[0] is ParsedBindingPathNode bindingPath)
{ {
var transformed = TransformBindingPath( var transformed = TransformBindingPath(
@ -90,8 +90,12 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
if (GetPropertyType(context, parentNode) == context.GetAvaloniaTypes().ICommand && lastElement is XamlIlClrMethodPathElementNode methodPathElement) if (GetPropertyType(context, parentNode) == context.GetAvaloniaTypes().ICommand && lastElement is XamlIlClrMethodPathElementNode methodPathElement)
{ {
IXamlMethod executeMethod = methodPathElement.Method; var executeMethod = methodPathElement.Method;
IXamlMethod canExecuteMethod = executeMethod.DeclaringType.FindMethod(new FindMethodMethodSignature($"Can{executeMethod.Name}", context.Configuration.WellKnownTypes.Boolean, context.Configuration.WellKnownTypes.Object)); var canExecuteMethod = executeMethod.DeclaringType.FindMethod(new FindMethodMethodSignature(
$"Can{executeMethod.Name}",
context.Configuration.WellKnownTypes.Boolean,
context.Configuration.WellKnownTypes.Object));
List<string> dependsOnProperties = new(); List<string> dependsOnProperties = new();
if (canExecuteMethod is not null) if (canExecuteMethod is not null)
{ {
@ -99,7 +103,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
{ {
if (attr.Type == context.GetAvaloniaTypes().DependsOnAttribute) if (attr.Type == context.GetAvaloniaTypes().DependsOnAttribute)
{ {
dependsOnProperties.Add((string)attr.Parameters[0]); dependsOnProperties.Add((string)attr.Parameters[0]!);
} }
} }
} }
@ -110,7 +114,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
return transformed; return transformed;
} }
private static IXamlType GetPropertyType(AstTransformationContext context, XamlPropertyAssignmentNode node) private static IXamlType? GetPropertyType(AstTransformationContext context, XamlPropertyAssignmentNode node)
{ {
var setterType = context.GetAvaloniaTypes().Setter; var setterType = context.GetAvaloniaTypes().Setter;
@ -126,11 +130,11 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
.FirstOrDefault(x => x.Property.GetClrProperty().Name == "Property"); .FirstOrDefault(x => x.Property.GetClrProperty().Name == "Property");
var property = propertyAssignment?.Values.FirstOrDefault() as IXamlIlAvaloniaPropertyNode; var property = propertyAssignment?.Values.FirstOrDefault() as IXamlIlAvaloniaPropertyNode;
if (property.AvaloniaPropertyType is { } propertyType) if (property?.AvaloniaPropertyType is { } propertyType)
return propertyType; return propertyType;
} }
return node.Property?.Getter?.ReturnType; return node.Property.Getter?.ReturnType;
} }
private static XamlIlBindingPathNode TransformBindingPath(AstTransformationContext context, IXamlLineInfo lineInfo, Func<IXamlType> startTypeResolver, IXamlType selfType, IEnumerable<BindingExpressionGrammar.INode> bindingExpression) private static XamlIlBindingPathNode TransformBindingPath(AstTransformationContext context, IXamlLineInfo lineInfo, Func<IXamlType> startTypeResolver, IXamlType selfType, IEnumerable<BindingExpressionGrammar.INode> bindingExpression)
@ -150,7 +154,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
case BindingExpressionGrammar.StreamNode _: case BindingExpressionGrammar.StreamNode _:
{ {
IXamlType targetType = targetTypeResolver(); IXamlType targetType = targetTypeResolver();
IXamlType observableType; IXamlType? observableType;
if (targetType.GenericTypeDefinition?.Equals(context.Configuration.TypeSystem.FindType("System.IObservable`1")) == true) if (targetType.GenericTypeDefinition?.Equals(context.Configuration.TypeSystem.FindType("System.IObservable`1")) == true)
{ {
observableType = targetType; observableType = targetType;
@ -165,10 +169,13 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
nodes.Add(new XamlIlStreamObservablePathElementNode(observableType.GenericArguments[0])); nodes.Add(new XamlIlStreamObservablePathElementNode(observableType.GenericArguments[0]));
break; break;
} }
bool foundTask = false; bool foundTask = false;
var taskType = context.Configuration.TypeSystem.GetType("System.Threading.Tasks.Task`1");
for (var currentType = targetType; currentType != null; currentType = currentType.BaseType) for (var currentType = targetType; currentType != null; currentType = currentType.BaseType)
{ {
if (currentType.GenericTypeDefinition.Equals(context.Configuration.TypeSystem.GetType("System.Threading.Tasks.Task`1"))) if (currentType.GenericTypeDefinition?.Equals(taskType) == true)
{ {
foundTask = true; foundTask = true;
nodes.Add(new XamlIlStreamTaskPathElementNode(currentType.GenericArguments[0])); nodes.Add(new XamlIlStreamTaskPathElementNode(currentType.GenericArguments[0]));
@ -216,13 +223,13 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
break; break;
} }
IXamlProperty property = null; IXamlProperty? property = null;
foreach (var currentType in TraverseTypeHierarchy(targetType)) foreach (var currentType in TraverseTypeHierarchy(targetType))
{ {
var defaultMemberAttribute = currentType.CustomAttributes.FirstOrDefault(x => x.Type.Namespace == "System.Reflection" && x.Type.Name == "DefaultMemberAttribute"); var defaultMemberAttribute = currentType.CustomAttributes.FirstOrDefault(x => x.Type.Namespace == "System.Reflection" && x.Type.Name == "DefaultMemberAttribute");
if (defaultMemberAttribute != null) if (defaultMemberAttribute != null)
{ {
property = currentType.GetAllProperties().FirstOrDefault(x => x.Name == (string)defaultMemberAttribute.Parameters[0]); property = currentType.GetAllProperties().FirstOrDefault(x => x.Name == (string)defaultMemberAttribute.Parameters[0]!);
break; break;
} }
} }
@ -255,8 +262,17 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
} }
case BindingExpressionGrammar.AttachedPropertyNameNode attachedProp: case BindingExpressionGrammar.AttachedPropertyNameNode attachedProp:
var avaloniaPropertyFieldName = attachedProp.PropertyName + "Property"; var avaloniaPropertyFieldName = attachedProp.PropertyName + "Property";
var avaloniaPropertyField = GetType(attachedProp.Namespace, attachedProp.TypeName).GetAllFields().FirstOrDefault(f => var propertyOwnerType = GetType(attachedProp.Namespace, attachedProp.TypeName);
var avaloniaPropertyField = propertyOwnerType.GetAllFields().FirstOrDefault(f =>
f.IsStatic && f.IsPublic && f.Name == avaloniaPropertyFieldName); f.IsStatic && f.IsPublic && f.Name == avaloniaPropertyFieldName);
if (avaloniaPropertyField is null)
{
throw new XamlTransformException(
$"Unable to find {avaloniaPropertyFieldName} field on type {propertyOwnerType.GetFullName()}",
lineInfo);
}
nodes.Add(new XamlIlAvaloniaPropertyPropertyPathElementNode(avaloniaPropertyField, nodes.Add(new XamlIlAvaloniaPropertyPropertyPathElementNode(avaloniaPropertyField,
XamlIlAvaloniaPropertyHelper.GetAvaloniaPropertyType(avaloniaPropertyField, context.GetAvaloniaTypes(), lineInfo))); XamlIlAvaloniaPropertyHelper.GetAvaloniaPropertyType(avaloniaPropertyField, context.GetAvaloniaTypes(), lineInfo)));
break; break;
@ -305,7 +321,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
} }
break; break;
case BindingExpressionGrammar.NameNode elementName: case BindingExpressionGrammar.NameNode elementName:
IXamlType elementType = null; IXamlType? elementType = null;
foreach (var deferredContent in context.ParentNodes().OfType<NestedScopeMetadataNode>()) foreach (var deferredContent in context.ParentNodes().OfType<NestedScopeMetadataNode>())
{ {
elementType = ScopeRegistrationFinder.GetTargetType(deferredContent, elementName.Name); elementType = ScopeRegistrationFinder.GetTargetType(deferredContent, elementName.Name);
@ -340,7 +356,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
return new XamlIlBindingPathNode(lineInfo, context.GetAvaloniaTypes().CompiledBindingPath, transformNodes, nodes); return new XamlIlBindingPathNode(lineInfo, context.GetAvaloniaTypes().CompiledBindingPath, transformNodes, nodes);
IXamlType GetType(string ns, string name) IXamlType GetType(string? ns, string? name)
{ {
return TypeReferenceResolver.ResolveType(context, $"{ns}:{name}", false, return TypeReferenceResolver.ResolveType(context, $"{ns}:{name}", false,
lineInfo, true).GetClrType(); lineInfo, true).GetClrType();
@ -403,9 +419,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
string Name { get; } string Name { get; }
IXamlType TargetType { get; set; } IXamlType? TargetType { get; set; }
public static IXamlType GetTargetType(IXamlAstNode namescopeRoot, string name) public static IXamlType? GetTargetType(IXamlAstNode namescopeRoot, string name)
{ {
// If we start from the nested scope - skip it. // If we start from the nested scope - skip it.
if (namescopeRoot is NestedScopeMetadataNode scope) if (namescopeRoot is NestedScopeMetadataNode scope)
@ -468,7 +484,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
public void Emit(XamlIlEmitContext context, IXamlILEmitter codeGen) public void Emit(XamlIlEmitContext context, IXamlILEmitter codeGen)
{ {
codeGen.EmitCall(context.GetAvaloniaTypes().CompiledBindingPathBuilder.FindMethod(m => m.Name == "Not")); codeGen.EmitCall(context.GetAvaloniaTypes().CompiledBindingPathBuilder.GetMethod(m => m.Name == "Not"));
} }
} }
@ -483,7 +499,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
public void Emit(XamlIlEmitContext context, IXamlILEmitter codeGen) public void Emit(XamlIlEmitContext context, IXamlILEmitter codeGen)
{ {
codeGen.EmitCall(context.GetAvaloniaTypes().CompiledBindingPathBuilder.FindMethod(m => m.Name == "StreamObservable").MakeGenericMethod(new[] { Type })); codeGen.EmitCall(context.GetAvaloniaTypes().CompiledBindingPathBuilder.GetMethod(m => m.Name == "StreamObservable").MakeGenericMethod(new[] { Type }));
} }
} }
@ -498,7 +514,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
public void Emit(XamlIlEmitContext context, IXamlILEmitter codeGen) public void Emit(XamlIlEmitContext context, IXamlILEmitter codeGen)
{ {
codeGen.EmitCall(context.GetAvaloniaTypes().CompiledBindingPathBuilder.FindMethod(m => m.Name == "StreamTask").MakeGenericMethod(new[] { Type })); codeGen.EmitCall(context.GetAvaloniaTypes().CompiledBindingPathBuilder.GetMethod(m => m.Name == "StreamTask").MakeGenericMethod(new[] { Type }));
} }
} }
@ -513,7 +529,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
public void Emit(XamlIlEmitContext context, IXamlILEmitter codeGen) public void Emit(XamlIlEmitContext context, IXamlILEmitter codeGen)
{ {
codeGen.EmitCall(context.GetAvaloniaTypes().CompiledBindingPathBuilder.FindMethod(m => m.Name == "Self")); codeGen.EmitCall(context.GetAvaloniaTypes().CompiledBindingPathBuilder.GetMethod(m => m.Name == "Self"));
} }
} }
@ -533,7 +549,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
{ {
codeGen.Ldtype(Type) codeGen.Ldtype(Type)
.Ldc_I4(_level) .Ldc_I4(_level)
.EmitCall(context.GetAvaloniaTypes().CompiledBindingPathBuilder.FindMethod(m => m.Name == "Ancestor")); .EmitCall(context.GetAvaloniaTypes().CompiledBindingPathBuilder.GetMethod(m => m.Name == "Ancestor"));
} }
} }
@ -553,7 +569,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
{ {
codeGen.Ldtype(Type) codeGen.Ldtype(Type)
.Ldc_I4(_level) .Ldc_I4(_level)
.EmitCall(context.GetAvaloniaTypes().CompiledBindingPathBuilder.FindMethod(m => m.Name == "VisualAncestor")); .EmitCall(context.GetAvaloniaTypes().CompiledBindingPathBuilder.GetMethod(m => m.Name == "VisualAncestor"));
} }
} }
@ -578,7 +594,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
.Ldloc(context.ContextLocal) .Ldloc(context.ContextLocal)
.Ldfld(scopeField) .Ldfld(scopeField)
.Ldstr(_name) .Ldstr(_name)
.EmitCall(context.GetAvaloniaTypes().CompiledBindingPathBuilder.FindMethod(m => m.Name == "ElementName")); .EmitCall(context.GetAvaloniaTypes().CompiledBindingPathBuilder.GetMethod(m => m.Name == "ElementName"));
} }
} }
@ -594,7 +610,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
public void Emit(XamlIlEmitContext context, IXamlILEmitter codeGen) public void Emit(XamlIlEmitContext context, IXamlILEmitter codeGen)
{ {
codeGen codeGen
.EmitCall(context.GetAvaloniaTypes().CompiledBindingPathBuilder.FindMethod(m => m.Name == "TemplatedParent")); .EmitCall(context.GetAvaloniaTypes().CompiledBindingPathBuilder.GetMethod(m => m.Name == "TemplatedParent"));
} }
} }
@ -614,7 +630,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
context.Configuration.GetExtra<XamlIlPropertyInfoAccessorFactoryEmitter>() context.Configuration.GetExtra<XamlIlPropertyInfoAccessorFactoryEmitter>()
.EmitLoadAvaloniaPropertyAccessorFactory(context, codeGen); .EmitLoadAvaloniaPropertyAccessorFactory(context, codeGen);
codeGen.EmitCall(context.GetAvaloniaTypes() codeGen.EmitCall(context.GetAvaloniaTypes()
.CompiledBindingPathBuilder.FindMethod(m => m.Name == "Property")); .CompiledBindingPathBuilder.GetMethod(m => m.Name == "Property"));
} }
public IXamlType Type { get; } public IXamlType Type { get; }
@ -639,10 +655,10 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
codeGen codeGen
.EmitCall(context.GetAvaloniaTypes() .EmitCall(context.GetAvaloniaTypes()
.CompiledBindingPathBuilder.FindMethod(m => m.Name == "Property")); .CompiledBindingPathBuilder.GetMethod(m => m.Name == "Property"));
} }
public IXamlType Type => _property.Getter?.ReturnType ?? _property.Setter?.Parameters[0]; public IXamlType Type => _property.PropertyType;
} }
class XamlIlClrMethodPathElementNode : IXamlIlBindingPathElementNode class XamlIlClrMethodPathElementNode : IXamlIlBindingPathElementNode
@ -659,7 +675,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
public void Emit(XamlIlEmitContext context, IXamlILEmitter codeGen) public void Emit(XamlIlEmitContext context, IXamlILEmitter codeGen)
{ {
IXamlTypeBuilder<IXamlILEmitter> newDelegateTypeBuilder = null; IXamlTypeBuilder<IXamlILEmitter>? newDelegateTypeBuilder = null;
IXamlType specificDelegateType; IXamlType specificDelegateType;
if (Method.ReturnType == context.Configuration.WellKnownTypes.Void && Method.Parameters.Count == 0) if (Method.ReturnType == context.Configuration.WellKnownTypes.Void && Method.Parameters.Count == 0)
{ {
@ -696,7 +712,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
.Ldtoken(Method) .Ldtoken(Method)
.Ldtoken(specificDelegateType) .Ldtoken(specificDelegateType)
.EmitCall(context.GetAvaloniaTypes() .EmitCall(context.GetAvaloniaTypes()
.CompiledBindingPathBuilder.FindMethod(m => m.Name == "Method")); .CompiledBindingPathBuilder.GetMethod(m => m.Name == "Method"));
newDelegateTypeBuilder?.CreateType(); newDelegateTypeBuilder?.CreateType();
} }
@ -705,10 +721,14 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
class XamlIlClrMethodAsCommandPathElementNode : IXamlIlBindingPathElementNode class XamlIlClrMethodAsCommandPathElementNode : IXamlIlBindingPathElementNode
{ {
private readonly IXamlMethod _executeMethod; private readonly IXamlMethod _executeMethod;
private readonly IXamlMethod _canExecuteMethod; private readonly IXamlMethod? _canExecuteMethod;
private readonly IReadOnlyList<string> _dependsOnProperties; private readonly IReadOnlyList<string> _dependsOnProperties;
public XamlIlClrMethodAsCommandPathElementNode(IXamlType iCommandType, IXamlMethod executeMethod, IXamlMethod canExecuteMethod, IReadOnlyList<string> dependsOnProperties) public XamlIlClrMethodAsCommandPathElementNode(
IXamlType iCommandType,
IXamlMethod executeMethod,
IXamlMethod? canExecuteMethod,
IReadOnlyList<string> dependsOnProperties)
{ {
Type = iCommandType; Type = iCommandType;
_executeMethod = executeMethod; _executeMethod = executeMethod;
@ -716,7 +736,6 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
_dependsOnProperties = dependsOnProperties; _dependsOnProperties = dependsOnProperties;
} }
public IXamlType Type { get; } public IXamlType Type { get; }
public void Emit(XamlIlEmitContext context, IXamlILEmitter codeGen) public void Emit(XamlIlEmitContext context, IXamlILEmitter codeGen)
@ -770,7 +789,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
codeGen codeGen
.EmitCall(context.GetAvaloniaTypes() .EmitCall(context.GetAvaloniaTypes()
.CompiledBindingPathBuilder.FindMethod(m => m.Name == "Command")); .CompiledBindingPathBuilder.GetMethod(m => m.Name == "Command"));
} }
} }
@ -810,10 +829,10 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
} }
codeGen.EmitCall(context.GetAvaloniaTypes() codeGen.EmitCall(context.GetAvaloniaTypes()
.CompiledBindingPathBuilder.FindMethod(m => m.Name == "Property")); .CompiledBindingPathBuilder.GetMethod(m => m.Name == "Property"));
} }
public IXamlType Type => _property.Getter?.ReturnType ?? _property.Setter?.Parameters[0]; public IXamlType Type => _property.PropertyType;
} }
class XamlIlArrayIndexerPathElementNode : IXamlIlBindingPathElementNode class XamlIlArrayIndexerPathElementNode : IXamlIlBindingPathElementNode
@ -853,10 +872,10 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
codeGen.Ldloc(indices) codeGen.Ldloc(indices)
.Ldtype(Type) .Ldtype(Type)
.EmitCall(context.GetAvaloniaTypes() .EmitCall(context.GetAvaloniaTypes()
.CompiledBindingPathBuilder.FindMethod(m => m.Name == "ArrayElement")); .CompiledBindingPathBuilder.GetMethod(m => m.Name == "ArrayElement"));
} }
public IXamlType Type => _arrayType.ArrayElementType; public IXamlType Type => _arrayType.ArrayElementType!;
} }
class TypeCastPathElementNode : IXamlIlBindingPathElementNode class TypeCastPathElementNode : IXamlIlBindingPathElementNode
@ -870,7 +889,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
public void Emit(XamlIlEmitContext context, IXamlILEmitter codeGen) public void Emit(XamlIlEmitContext context, IXamlILEmitter codeGen)
{ {
codeGen.EmitCall(context.GetAvaloniaTypes().CompiledBindingPathBuilder.FindMethod(m => m.Name == "TypeCast").MakeGenericMethod(new[] { Type })); codeGen.EmitCall(context.GetAvaloniaTypes().CompiledBindingPathBuilder.GetMethod(m => m.Name == "TypeCast").MakeGenericMethod(new[] { Type }));
} }
} }
@ -906,7 +925,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
// of 1 to indicate that we don't want TemplatedParent compatibility hacks enabled. // of 1 to indicate that we don't want TemplatedParent compatibility hacks enabled.
codeGen codeGen
.Ldc_I4(1) .Ldc_I4(1)
.Newobj(types.CompiledBindingPathBuilder.FindConstructor(new() { intType })); .Newobj(types.CompiledBindingPathBuilder.GetConstructor(new() { intType }));
foreach (var transform in _transformElements) foreach (var transform in _transformElements)
{ {
@ -918,7 +937,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
element.Emit(context, codeGen); element.Emit(context, codeGen);
} }
codeGen.EmitCall(types.CompiledBindingPathBuilder.FindMethod(m => m.Name == "Build")); codeGen.EmitCall(types.CompiledBindingPathBuilder.GetMethod(m => m.Name == "Build"));
return XamlILNodeEmitResult.Type(0, types.CompiledBindingPath); return XamlILNodeEmitResult.Type(0, types.CompiledBindingPath);
} }

23
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlClrPropertyInfoHelper.cs

@ -3,7 +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.Transform;
using XamlX.TypeSystem; using XamlX.TypeSystem;
using XamlX.IL; using XamlX.IL;
using XamlX.Emit; using XamlX.Emit;
@ -22,9 +21,12 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
_builder = builder; _builder = builder;
} }
static string GetKey(IXamlProperty property, string indexerArgumentsKey) static string GetKey(IXamlProperty property, string? indexerArgumentsKey)
{ {
var baseKey = property.Getter.DeclaringType.GetFullName() + "." + property.Name; var declaringType = (property.Getter ?? property.Setter)?.DeclaringType
?? throw new InvalidOperationException($"Couldn't get declaring type for property {property}");
var baseKey = declaringType.GetFullName() + "." + property.Name;
if (indexerArgumentsKey is null) if (indexerArgumentsKey is null)
{ {
@ -34,9 +36,14 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
return baseKey + $"[{indexerArgumentsKey}]"; return baseKey + $"[{indexerArgumentsKey}]";
} }
public IXamlType Emit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen, IXamlProperty property, IReadOnlyCollection<IXamlAstValueNode> indexerArguments = null, string indexerArgumentsKey = null) public IXamlType Emit(
XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context,
IXamlILEmitter codeGen,
IXamlProperty property,
IReadOnlyCollection<IXamlAstValueNode>? indexerArguments = null,
string? indexerArgumentsKey = null)
{ {
indexerArguments = indexerArguments ?? Array.Empty<IXamlAstValueNode>(); indexerArguments ??= [];
var types = context.GetAvaloniaTypes(); var types = context.GetAvaloniaTypes();
IXamlMethod Get() IXamlMethod Get()
{ {
@ -83,7 +90,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
new[] {types.XamlIlTypes.Object}, name + "!Getter", XamlVisibility.Private, true, false); new[] {types.XamlIlTypes.Object}, name + "!Getter", XamlVisibility.Private, true, false);
if (getter != null) if (getter != null)
{ {
Load(property.Getter, getter.Generator, !property.Getter.IsStatic); Load(property.Getter!, getter.Generator, !property.Getter!.IsStatic);
getter.Generator.EmitCall(property.Getter); getter.Generator.EmitCall(property.Getter);
if (property.Getter.ReturnType.IsValueType) if (property.Getter.ReturnType.IsValueType)
@ -98,7 +105,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
name + "!Setter", XamlVisibility.Private, true, false); name + "!Setter", XamlVisibility.Private, true, false);
if (setter != null) if (setter != null)
{ {
Load(property.Setter, setter.Generator, !property.Getter.IsStatic); Load(property.Setter!, setter.Generator, !property.Setter!.IsStatic);
setter.Generator.Ldarg(1); setter.Generator.Ldarg(1);
@ -128,7 +135,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
.MarkLabel(cacheMiss) .MarkLabel(cacheMiss)
.Ldstr(property.Name); .Ldstr(property.Name);
void EmitFunc(IXamlILEmitter emitter, IXamlMethod method, IXamlType del) void EmitFunc(IXamlILEmitter emitter, IXamlMethod? method, IXamlType del)
{ {
if (method == null) if (method == null)
emitter.Ldnull(); emitter.Ldnull();

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

@ -17,7 +17,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
{ {
private const string IndexerClosureFactoryMethodName = "CreateAccessor"; private const string IndexerClosureFactoryMethodName = "CreateAccessor";
private readonly IXamlTypeBuilder<IXamlILEmitter> _indexerClosureTypeBuilder; private readonly IXamlTypeBuilder<IXamlILEmitter> _indexerClosureTypeBuilder;
private IXamlType _indexerClosureType; private IXamlType? _indexerClosureType;
public XamlIlPropertyInfoAccessorFactoryEmitter(IXamlTypeBuilder<IXamlILEmitter> indexerClosureType) public XamlIlPropertyInfoAccessorFactoryEmitter(IXamlTypeBuilder<IXamlILEmitter> indexerClosureType)
{ {
_indexerClosureTypeBuilder = indexerClosureType; _indexerClosureTypeBuilder = indexerClosureType;
@ -57,7 +57,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
} }
context.Emit(value, codeGen, intType); context.Emit(value, codeGen, intType);
codeGen.Newobj(_indexerClosureType.FindConstructor(new List<IXamlType> { intType })); codeGen.Newobj(_indexerClosureType.GetConstructor(new List<IXamlType> { intType }));
EmitLoadPropertyAccessorFactory(context, codeGen, _indexerClosureType, IndexerClosureFactoryMethodName, isStatic: false); EmitLoadPropertyAccessorFactory(context, codeGen, _indexerClosureType, IndexerClosureFactoryMethodName, isStatic: false);
return EmitCreateAccessorFactoryDelegate(context, codeGen); return EmitCreateAccessorFactoryDelegate(context, codeGen);
} }

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

@ -54,10 +54,10 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
var convertedValue = gen.DefineLocal(context.Configuration.WellKnownTypes.Object); var convertedValue = gen.DefineLocal(context.Configuration.WellKnownTypes.Object);
gen.Ldtype(executeMethod.Parameters[0]) gen.Ldtype(executeMethod.Parameters[0])
.Ldarg(1) .Ldarg(1)
.EmitCall(context.Configuration.WellKnownTypes.CultureInfo.FindMethod(m => m.Name == "get_CurrentCulture")) .EmitCall(context.Configuration.WellKnownTypes.CultureInfo.GetMethod(m => m.Name == "get_CurrentCulture"))
.Ldloca(convertedValue) .Ldloca(convertedValue)
.EmitCall( .EmitCall(
context.GetAvaloniaTypes().TypeUtilities.FindMethod(m => m.Name == "TryConvert"), context.GetAvaloniaTypes().TypeUtilities.GetMethod(m => m.Name == "TryConvert"),
swallowResult: true) swallowResult: true)
.Ldloc(convertedValue) .Ldloc(convertedValue)
.Unbox_Any(executeMethod.Parameters[0]); .Unbox_Any(executeMethod.Parameters[0]);

2
src/Markup/Avalonia.Markup.Xaml.Loader/xamlil.github

@ -1 +1 @@
Subproject commit 941dafce490ffd21178f4493a7f0425e9d478e60 Subproject commit 14fed0cb0666a9b3f71cb635cf61eb6010d4ff64

2
src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs

@ -361,7 +361,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.Runtime
{ {
return new RootServiceProvider(new NameScope(), null); return new RootServiceProvider(new NameScope(), null);
} }
public static IServiceProvider CreateRootServiceProviderV3(IServiceProvider parentServiceProvider) public static IServiceProvider CreateRootServiceProviderV3(IServiceProvider? parentServiceProvider)
{ {
return new RootServiceProvider(new NameScope(), parentServiceProvider); return new RootServiceProvider(new NameScope(), parentServiceProvider);
} }

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

@ -14,11 +14,12 @@
<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="..\..\..\src\Markup\Avalonia.Markup.Xaml.Loader\CompilerDynamicDependencies.cs" />
<Compile Include="..\..\..\src\Avalonia.Base\Metadata\NullableAttributes.cs" Link="Compatibility\NullableAttributes.cs" /> <Compile Include="..\..\..\src\Avalonia.Base\Compatibility\NullableAttributes.cs" Link="Compatibility\NullableAttributes.cs" />
<Compile Include="..\..\..\src\Avalonia.Base\Compatibility\TrimmingAttributes.cs" Link="Compatibility\TrimmingAttributes.cs" /> <Compile Include="..\..\..\src\Avalonia.Base\Compatibility\TrimmingAttributes.cs" Link="Compatibility\TrimmingAttributes.cs" />
<Compile Include="..\..\..\src\Shared\IsExternalInit.cs" Link="Compatibility\IsExternalInit.cs" /> <Compile Include="..\..\..\src\Shared\IsExternalInit.cs" Link="Compatibility\IsExternalInit.cs" />
</ItemGroup> </ItemGroup>
<Import Project="..\..\..\src\Markup\Avalonia.Markup.Xaml.Loader\IncludeXamlIlSre.props" /> <Import Project="..\..\..\src\Markup\Avalonia.Markup.Xaml.Loader\IncludeXamlIlSre.props" />
<Import Project="..\..\..\build\DevAnalyzers.props" /> <Import Project="..\..\..\build\DevAnalyzers.props" />
<Import Project="..\..\..\build\TrimmingEnable.props" /> <Import Project="..\..\..\build\TrimmingEnable.props" />
<Import Project="..\..\..\build\NullableEnable.props" />
</Project> </Project>

6
src/tools/Avalonia.Designer.HostApp/DesignXamlLoader.cs

@ -19,11 +19,11 @@ class DesignXamlLoader : AvaloniaXamlLoader.IRuntimeXamlLoader
return AvaloniaXamlIlRuntimeCompiler.Load(document, configuration); return AvaloniaXamlIlRuntimeCompiler.Load(document, configuration);
} }
private void PreloadDepsAssemblies(Assembly targetAssembly) private void PreloadDepsAssemblies(Assembly? targetAssembly)
{ {
// Assemblies loaded in memory (e.g. single file) return empty string from Location. // Assemblies loaded in memory (e.g. single file) return empty string from Location.
// In these cases, don't try probing next to the assembly. // In these cases, don't try probing next to the assembly.
var assemblyLocation = targetAssembly.Location; var assemblyLocation = targetAssembly?.Location;
if (string.IsNullOrEmpty(assemblyLocation)) if (string.IsNullOrEmpty(assemblyLocation))
{ {
return; return;
@ -32,7 +32,7 @@ class DesignXamlLoader : AvaloniaXamlLoader.IRuntimeXamlLoader
var depsJsonFile = Path.ChangeExtension(assemblyLocation, ".deps.json"); var depsJsonFile = Path.ChangeExtension(assemblyLocation, ".deps.json");
if (!File.Exists(depsJsonFile)) if (!File.Exists(depsJsonFile))
{ {
var sameDir = Path.GetDirectoryName(depsJsonFile); var sameDir = Path.GetDirectoryName(depsJsonFile)!;
var fallbackDepsFiles = Directory.GetFiles(sameDir, "*.deps.json"); var fallbackDepsFiles = Directory.GetFiles(sameDir, "*.deps.json");
if (fallbackDepsFiles.Length == 1) if (fallbackDepsFiles.Length == 1)
{ {

12
src/tools/Avalonia.Generators/Avalonia.Generators.csproj

@ -8,6 +8,7 @@
<IncludeSymbols>false</IncludeSymbols> <IncludeSymbols>false</IncludeSymbols>
<IsRoslynComponent>true</IsRoslynComponent> <IsRoslynComponent>true</IsRoslynComponent>
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules> <EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
<Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
@ -16,20 +17,21 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<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" Visible="False" /> <Compile Include="../../Shared/IsExternalInit.cs" Link="IsExternalInit.cs" Visible="False" />
<Compile Include="..\..\Avalonia.Base\Compatibility\TrimmingAttributes.cs" Link="TrimmingAttributes.cs" Visible="False" /> <Compile Include="../../Avalonia.Base/Compatibility/TrimmingAttributes.cs" Link="TrimmingAttributes.cs" Visible="False" />
<Compile Include="../../Avalonia.Base/Compatibility/NullableAttributes.cs" Link="TrimmingAttributes.cs" Visible="False" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" /> <None Include="$(OutputPath)/$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
</ItemGroup> </ItemGroup>
<ItemGroup Label="InternalsVisibleTo"> <ItemGroup Label="InternalsVisibleTo">
<InternalsVisibleTo Include="Avalonia.Generators.Tests, PublicKey=$(AvaloniaPublicKey)" /> <InternalsVisibleTo Include="Avalonia.Generators.Tests, PublicKey=$(AvaloniaPublicKey)" />
</ItemGroup> </ItemGroup>
<Import Project="..\..\..\build\TrimmingEnable.props" /> <Import Project="../../../build/TrimmingEnable.props" />
</Project> </Project>

2
src/tools/Avalonia.Generators/Common/Domain/IViewResolver.cs

@ -5,7 +5,7 @@ namespace Avalonia.Generators.Common.Domain;
internal interface IViewResolver internal interface IViewResolver
{ {
ResolvedView ResolveView(string xaml); ResolvedView? ResolveView(string xaml);
} }
internal record ResolvedView(string ClassName, IXamlType XamlType, string Namespace, XamlDocument Xaml); internal record ResolvedView(string ClassName, IXamlType XamlType, string Namespace, XamlDocument Xaml);

16
src/tools/Avalonia.Generators/Common/XamlXViewResolver.cs

@ -14,18 +14,18 @@ internal class XamlXViewResolver : IViewResolver, IXamlAstVisitor
private readonly RoslynTypeSystem _typeSystem; private readonly RoslynTypeSystem _typeSystem;
private readonly MiniCompiler _compiler; private readonly MiniCompiler _compiler;
private readonly bool _checkTypeValidity; private readonly bool _checkTypeValidity;
private readonly Action<string> _onTypeInvalid; private readonly Action<string>? _onTypeInvalid;
private readonly Action<Exception> _onUnhandledError; private readonly Action<Exception>? _onUnhandledError;
private ResolvedView _resolvedClass; private ResolvedView? _resolvedClass;
private XamlDocument _xaml; private XamlDocument? _xaml;
public XamlXViewResolver( public XamlXViewResolver(
RoslynTypeSystem typeSystem, RoslynTypeSystem typeSystem,
MiniCompiler compiler, MiniCompiler compiler,
bool checkTypeValidity = false, bool checkTypeValidity = false,
Action<string> onTypeInvalid = null, Action<string>? onTypeInvalid = null,
Action<Exception> onUnhandledError = null) Action<Exception>? onUnhandledError = null)
{ {
_checkTypeValidity = checkTypeValidity; _checkTypeValidity = checkTypeValidity;
_onTypeInvalid = onTypeInvalid; _onTypeInvalid = onTypeInvalid;
@ -34,7 +34,7 @@ internal class XamlXViewResolver : IViewResolver, IXamlAstVisitor
_compiler = compiler; _compiler = compiler;
} }
public ResolvedView ResolveView(string xaml) public ResolvedView? ResolveView(string xaml)
{ {
try try
{ {
@ -86,7 +86,7 @@ internal class XamlXViewResolver : IViewResolver, IXamlAstVisitor
var nameSpace = string.Join(".", split.Take(split.Length - 1)); var nameSpace = string.Join(".", split.Take(split.Length - 1));
var className = split.Last(); var className = split.Last();
_resolvedClass = new ResolvedView(className, clrType, nameSpace, _xaml); _resolvedClass = new ResolvedView(className, clrType, nameSpace, _xaml!);
return node; return node;
} }
} }

63
src/tools/Avalonia.Generators/Compiler/RoslynTypeSystem.cs

@ -28,18 +28,18 @@ internal class RoslynTypeSystem : IXamlTypeSystem
public IEnumerable<IXamlAssembly> Assemblies => _assemblies; public IEnumerable<IXamlAssembly> Assemblies => _assemblies;
public IXamlAssembly FindAssembly(string name) => public IXamlAssembly? FindAssembly(string name) =>
Assemblies Assemblies
.FirstOrDefault(a => string.Equals(a.Name, name, StringComparison.OrdinalIgnoreCase)); .FirstOrDefault(a => string.Equals(a.Name, name, StringComparison.OrdinalIgnoreCase));
[UnconditionalSuppressMessage("Trimming", "IL2092", Justification = TrimmingMessages.Roslyn)] [UnconditionalSuppressMessage("Trimming", "IL2092", Justification = TrimmingMessages.Roslyn)]
public IXamlType FindType(string name) => public IXamlType? FindType(string name) =>
_assemblies _assemblies
.Select(assembly => assembly.FindType(name)) .Select(assembly => assembly.FindType(name))
.FirstOrDefault(type => type != null); .FirstOrDefault(type => type != null);
[UnconditionalSuppressMessage("Trimming", "IL2092", Justification = TrimmingMessages.Roslyn)] [UnconditionalSuppressMessage("Trimming", "IL2092", Justification = TrimmingMessages.Roslyn)]
public IXamlType FindType(string name, string assembly) => public IXamlType? FindType(string name, string assembly) =>
_assemblies _assemblies
.Select(assemblyInstance => assemblyInstance.FindType(name)) .Select(assemblyInstance => assemblyInstance.FindType(name))
.FirstOrDefault(type => type != null); .FirstOrDefault(type => type != null);
@ -62,7 +62,7 @@ internal class RoslynAssembly : IXamlAssembly
.Select(data => new RoslynAttribute(data, this)) .Select(data => new RoslynAttribute(data, this))
.ToList(); .ToList();
public IXamlType FindType(string fullName) public IXamlType? FindType(string fullName)
{ {
var type = _symbol.GetTypeByMetadataName(fullName); var type = _symbol.GetTypeByMetadataName(fullName);
return type is null ? null : new RoslynType(type, this); return type is null ? null : new RoslynType(type, this);
@ -84,14 +84,14 @@ internal class RoslynAttribute : IXamlCustomAttribute
other is RoslynAttribute attribute && other is RoslynAttribute attribute &&
_data == attribute._data; _data == attribute._data;
public IXamlType Type => new RoslynType(_data.AttributeClass, _assembly); public IXamlType Type => new RoslynType(_data.AttributeClass!, _assembly);
public List<object> Parameters => public List<object?> Parameters =>
_data.ConstructorArguments _data.ConstructorArguments
.Select(argument => argument.Value) .Select(argument => argument.Value)
.ToList(); .ToList();
public Dictionary<string, object> Properties => public Dictionary<string, object?> Properties =>
_data.NamedArguments.ToDictionary( _data.NamedArguments.ToDictionary(
pair => pair.Key, pair => pair.Key,
pair => pair.Value.Value); pair => pair.Value.Value);
@ -132,7 +132,7 @@ internal class RoslynType : IXamlType
public bool IsNestedPrivate => _symbol.DeclaredAccessibility == Accessibility.Private; public bool IsNestedPrivate => _symbol.DeclaredAccessibility == Accessibility.Private;
public IXamlType DeclaringType => public IXamlType? DeclaringType =>
_symbol.ContainingType is { } containingType ? new RoslynType(containingType, _assembly) : null; _symbol.ContainingType is { } containingType ? new RoslynType(containingType, _assembly) : null;
public IReadOnlyList<IXamlProperty> Properties => public IReadOnlyList<IXamlProperty> Properties =>
@ -142,18 +142,18 @@ internal class RoslynType : IXamlType
.Select(property => new RoslynProperty(property, _assembly)) .Select(property => new RoslynProperty(property, _assembly))
.ToList(); .ToList();
public IReadOnlyList<IXamlEventInfo> Events { get; } = new List<IXamlEventInfo>(); public IReadOnlyList<IXamlEventInfo> Events => [];
public IReadOnlyList<IXamlField> Fields { get; } = new List<IXamlField>(); public IReadOnlyList<IXamlField> Fields => [];
public IReadOnlyList<IXamlMethod> Methods { get; } = new List<IXamlMethod>(); public IReadOnlyList<IXamlMethod> Methods => [];
public IReadOnlyList<IXamlConstructor> Constructors => public IReadOnlyList<IXamlConstructor> Constructors =>
_symbol.Constructors _symbol.Constructors
.Select(method => new RoslynConstructor(method, _assembly)) .Select(method => new RoslynConstructor(method, _assembly))
.ToList(); .ToList();
public IReadOnlyList<IXamlCustomAttribute> CustomAttributes { get; } = Array.Empty<IXamlCustomAttribute>(); public IReadOnlyList<IXamlCustomAttribute> CustomAttributes => [];
public IReadOnlyList<IXamlType> GenericArguments { get; private set; } = new List<IXamlType>(); public IReadOnlyList<IXamlType> GenericArguments { get; private set; } = new List<IXamlType>();
@ -169,15 +169,15 @@ internal class RoslynType : IXamlType
public bool IsArray => false; public bool IsArray => false;
public IXamlType ArrayElementType { get; } = null; public IXamlType? ArrayElementType => null;
public IXamlType MakeArrayType(int dimensions) => null; public IXamlType MakeArrayType(int dimensions) => throw new NotSupportedException();
public IXamlType BaseType => _symbol.BaseType == null ? null : new RoslynType(_symbol.BaseType, _assembly); public IXamlType? BaseType => _symbol.BaseType is { } baseType ? new RoslynType(baseType, _assembly) : null;
public bool IsValueType { get; } = false; public bool IsValueType => false;
public bool IsEnum { get; } = false; public bool IsEnum => false;
public IReadOnlyList<IXamlType> Interfaces => public IReadOnlyList<IXamlType> Interfaces =>
_symbol.AllInterfaces _symbol.AllInterfaces
@ -186,9 +186,9 @@ internal class RoslynType : IXamlType
public bool IsInterface => _symbol.IsAbstract; public bool IsInterface => _symbol.IsAbstract;
public IXamlType GetEnumUnderlyingType() => null; public IXamlType GetEnumUnderlyingType() => throw new NotSupportedException();
public IReadOnlyList<IXamlType> GenericParameters { get; } = new List<IXamlType>(); public IReadOnlyList<IXamlType> GenericParameters => [];
public bool IsFunctionPointer => false; public bool IsFunctionPointer => false;
} }
@ -217,6 +217,10 @@ internal class RoslynConstructor : IXamlConstructor
.Select(parameter => new RoslynParameter(_assembly, parameter).ParameterType) .Select(parameter => new RoslynParameter(_assembly, parameter).ParameterType)
.ToList(); .ToList();
public string Name => _symbol.Name;
public IXamlType DeclaringType => new RoslynType(_symbol.ContainingType, _assembly);
public IXamlParameterInfo GetParameterInfo(int index) => new RoslynParameter(_assembly, _symbol.Parameters[index]); public IXamlParameterInfo GetParameterInfo(int index) => new RoslynParameter(_assembly, _symbol.Parameters[index]);
} }
@ -237,18 +241,20 @@ internal class RoslynProperty : IXamlProperty
public string Name => _symbol.Name; public string Name => _symbol.Name;
public IXamlType DeclaringType => new RoslynType(_symbol.ContainingType, _assembly);
public IXamlType PropertyType => public IXamlType PropertyType =>
_symbol.Type is INamedTypeSymbol namedTypeSymbol _symbol.Type is INamedTypeSymbol namedTypeSymbol
? new RoslynType(namedTypeSymbol, _assembly) ? new RoslynType(namedTypeSymbol, _assembly)
: null; : XamlPseudoType.Unknown;
public IXamlMethod Getter => _symbol.GetMethod == null ? null : new RoslynMethod(_symbol.GetMethod, _assembly); public IXamlMethod? Getter => _symbol.GetMethod == null ? null : new RoslynMethod(_symbol.GetMethod, _assembly);
public IXamlMethod Setter => _symbol.SetMethod == null ? null : new RoslynMethod(_symbol.SetMethod, _assembly); public IXamlMethod? Setter => _symbol.SetMethod == null ? null : new RoslynMethod(_symbol.SetMethod, _assembly);
public IReadOnlyList<IXamlCustomAttribute> CustomAttributes { get; } = Array.Empty<IXamlCustomAttribute>(); public IReadOnlyList<IXamlCustomAttribute> CustomAttributes => [];
public IReadOnlyList<IXamlType> IndexerParameters { get; } = new List<IXamlType>(); public IReadOnlyList<IXamlType> IndexerParameters => [];
} }
internal class RoslynParameter : IXamlParameterInfo internal class RoslynParameter : IXamlParameterInfo
@ -298,10 +304,11 @@ internal class RoslynMethod : IXamlMethod
_symbol.Parameters.Select(parameter => new RoslynParameter(_assembly, parameter).ParameterType) _symbol.Parameters.Select(parameter => new RoslynParameter(_assembly, parameter).ParameterType)
.ToList(); .ToList();
public IXamlType DeclaringType => new RoslynType((INamedTypeSymbol)_symbol.ReceiverType, _assembly); public IXamlType DeclaringType => new RoslynType(_symbol.ContainingType, _assembly);
public IXamlMethod MakeGenericMethod(IReadOnlyList<IXamlType> typeArguments) => null; public IXamlMethod MakeGenericMethod(IReadOnlyList<IXamlType> typeArguments) => throw new NotSupportedException();
public IReadOnlyList<IXamlCustomAttribute> CustomAttributes => [];
public IReadOnlyList<IXamlCustomAttribute> CustomAttributes { get; } = Array.Empty<IXamlCustomAttribute>();
public IXamlParameterInfo GetParameterInfo(int index) => new RoslynParameter(_assembly, _symbol.Parameters[index]); public IXamlParameterInfo GetParameterInfo(int index) => new RoslynParameter(_assembly, _symbol.Parameters[index]);
} }

2
src/tools/Avalonia.Generators/GeneratorContextExtensions.cs

@ -29,7 +29,7 @@ internal static class GeneratorContextExtensions
$"Avalonia x:Name generator was unable to generate names for type '{typeName}'. " + $"Avalonia x:Name generator was unable to generate names for type '{typeName}'. " +
$"The type '{typeName}' does not exist in the assembly."); $"The type '{typeName}' does not exist in the assembly.");
private static void Report(this GeneratorExecutionContext context, string id, string title, string message = null, string description = null) => private static void Report(this GeneratorExecutionContext context, string id, string title, string? message = null, string? description = null) =>
context.ReportDiagnostic( context.ReportDiagnostic(
Diagnostic.Create( Diagnostic.Create(
new DiagnosticDescriptor( new DiagnosticDescriptor(

2
src/tools/Avalonia.Generators/NameGenerator/AvaloniaNameSourceGenerator.cs

@ -57,7 +57,7 @@ public class AvaloniaNameSourceGenerator : ISourceGenerator
&& sourceItemGroup == "AvaloniaXaml"); && sourceItemGroup == "AvaloniaXaml");
} }
private static INameGenerator CreateNameGenerator(GeneratorExecutionContext context) private static INameGenerator? CreateNameGenerator(GeneratorExecutionContext context)
{ {
var options = new GeneratorOptions(context); var options = new GeneratorOptions(context);
if (!options.AvaloniaNameGeneratorIsEnabled) if (!options.AvaloniaNameGeneratorIsEnabled)

3
tests/Avalonia.Generators.Tests/InitializeComponent/InitializeComponentTests.cs

@ -44,11 +44,12 @@ public class InitializeComponentTests
var xaml = await View.Load(markup); var xaml = await View.Load(markup);
var classInfo = classResolver.ResolveView(xaml); var classInfo = classResolver.ResolveView(xaml);
Assert.NotNull(classInfo);
var nameResolver = new XamlXNameResolver(); var nameResolver = new XamlXNameResolver();
var names = nameResolver.ResolveNames(classInfo.Xaml); var names = nameResolver.ResolveNames(classInfo.Xaml);
var generator = new InitializeComponentCodeGenerator(types, devToolsMode); var generator = new InitializeComponentCodeGenerator(types, devToolsMode);
var generatorVersion = typeof(InitializeComponentCodeGenerator).Assembly.GetName().Version.ToString(); var generatorVersion = typeof(InitializeComponentCodeGenerator).Assembly.GetName().Version?.ToString();
var code = generator var code = generator
.GenerateCode("SampleView", "Sample.App", classInfo.XamlType, names) .GenerateCode("SampleView", "Sample.App", classInfo.XamlType, names)

3
tests/Avalonia.Generators.Tests/OnlyProperties/OnlyPropertiesTests.cs

@ -37,11 +37,12 @@ public class OnlyPropertiesTests
var xaml = await View.Load(markup); var xaml = await View.Load(markup);
var classInfo = classResolver.ResolveView(xaml); var classInfo = classResolver.ResolveView(xaml);
Assert.NotNull(classInfo);
var nameResolver = new XamlXNameResolver(); var nameResolver = new XamlXNameResolver();
var names = nameResolver.ResolveNames(classInfo.Xaml); var names = nameResolver.ResolveNames(classInfo.Xaml);
var generator = new OnlyPropertiesCodeGenerator(); var generator = new OnlyPropertiesCodeGenerator();
var generatorVersion = typeof(OnlyPropertiesCodeGenerator).Assembly.GetName().Version.ToString(); var generatorVersion = typeof(OnlyPropertiesCodeGenerator).Assembly.GetName().Version?.ToString();
var code = generator var code = generator
.GenerateCode("SampleView", "Sample.App", classInfo.XamlType, names) .GenerateCode("SampleView", "Sample.App", classInfo.XamlType, names)

1
tests/Avalonia.Generators.Tests/XamlXClassResolverTests.cs

@ -34,6 +34,7 @@ public class XamlXClassResolverTests
MiniCompiler.CreateDefault(types, MiniCompiler.AvaloniaXmlnsDefinitionAttribute)); MiniCompiler.CreateDefault(types, MiniCompiler.AvaloniaXmlnsDefinitionAttribute));
var resolvedClass = resolver.ResolveView(xaml); var resolvedClass = resolver.ResolveView(xaml);
Assert.NotNull(resolvedClass);
Assert.Equal(className, resolvedClass.ClassName); Assert.Equal(className, resolvedClass.ClassName);
Assert.Equal(nameSpace, resolvedClass.Namespace); Assert.Equal(nameSpace, resolvedClass.Namespace);
} }

1
tests/Avalonia.Generators.Tests/XamlXNameResolverTests.cs

@ -135,6 +135,7 @@ public class XamlXNameResolverTests
MiniCompiler.AvaloniaXmlnsDefinitionAttribute)); MiniCompiler.AvaloniaXmlnsDefinitionAttribute));
var classInfo = classResolver.ResolveView(xaml); var classInfo = classResolver.ResolveView(xaml);
Assert.NotNull(classInfo);
var nameResolver = new XamlXNameResolver(); var nameResolver = new XamlXNameResolver();
return nameResolver.ResolveNames(classInfo.Xaml); return nameResolver.ResolveNames(classInfo.Xaml);
} }

Loading…
Cancel
Save