Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Trimming] Add ILC compilation test of all assemblies #22328

Merged
merged 7 commits into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/Compatibility/Core/src/iOS/NativeBindingService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

namespace Microsoft.Maui.Controls.Compatibility.Platform.iOS
{
[Preserve(AllMembers = true)]
class NativeBindingService : INativeBindingService
{
[RequiresUnreferencedCode(TrimmerConstants.StringPathBindingWarning, Url = TrimmerConstants.ExpressionBasedBindingsDocsUrl)]
Expand Down
4 changes: 2 additions & 2 deletions src/Controls/src/Core/Effect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ internal Effect()
public static Effect Resolve(string name)
{
Effect result = null;
if (Internals.Registrar.Effects.TryGetValue(name, out Type effectType))
if (Internals.Registrar.Effects.TryGetValue(name, out var effectType))
{
result = (Effect)DependencyResolver.ResolveOrCreate(effectType);
result = (Effect)DependencyResolver.ResolveOrCreate(effectType.Type);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This missing analyzer warning is tracked by dotnet/runtime#101734.

}

if (result == null)
Expand Down
6 changes: 5 additions & 1 deletion src/Controls/src/Core/ExportEffectAttribute.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#nullable disable
using System;
using System.Diagnostics.CodeAnalysis;

namespace Microsoft.Maui.Controls
{
Expand All @@ -10,7 +11,9 @@ namespace Microsoft.Maui.Controls
public sealed class ExportEffectAttribute : Attribute
{
/// <include file="../../docs/Microsoft.Maui.Controls/ExportEffectAttribute.xml" path="//Member[@MemberName='.ctor']/Docs/*" />
public ExportEffectAttribute(Type effectType, string uniqueName)
public ExportEffectAttribute(
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type effectType,
string uniqueName)
{
if (uniqueName.IndexOf(".", StringComparison.Ordinal) != -1)
throw new ArgumentException("uniqueName must not contain a .");
Expand All @@ -20,6 +23,7 @@ public ExportEffectAttribute(Type effectType, string uniqueName)

internal string Id { get; private set; }

[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)]
internal Type Type { get; private set; }
}
}
21 changes: 18 additions & 3 deletions src/Controls/src/Core/Registrar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,19 @@ static Registrar()
Registered = new Registrar<IRegisterable>();
}

internal static Dictionary<string, Type> Effects { get; } = new(StringComparer.Ordinal);
internal struct EffectType
{
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)]
public readonly Type Type;

public EffectType(
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type type)
{
Type = type;
}
}

internal static Dictionary<string, EffectType> Effects { get; } = new(StringComparer.Ordinal);

internal static Dictionary<string, IList<StylePropertyAttribute>> StyleProperties => LazyStyleProperties.Value;

Expand Down Expand Up @@ -394,9 +406,12 @@ public static void RegisterEffects(string resolutionName, ExportEffectAttribute[
}
}

public static void RegisterEffect(string resolutionName, string id, Type effectType)
public static void RegisterEffect(
string resolutionName,
string id,
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type effectType)
{
Effects[resolutionName + "." + id] = effectType;
Effects[resolutionName + "." + id] = new(effectType);
}

/// <include file="../../docs/Microsoft.Maui.Controls.Internals/Registrar.xml" path="//Member[@MemberName='RegisterAll'][1]/Docs/*" />
Expand Down
27 changes: 16 additions & 11 deletions src/Controls/src/Xaml/MarkupExtensions/BindingExtension.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using Microsoft.Maui.Controls.Internals;

namespace Microsoft.Maui.Controls.Xaml
Expand All @@ -21,18 +22,9 @@ public sealed class BindingExtension : IMarkupExtension<BindingBase>

BindingBase IMarkupExtension<BindingBase>.ProvideValue(IServiceProvider serviceProvider)
{
if (TypedBinding == null)
if (TypedBinding is null)
{
#pragma warning disable IL2026 // Using member 'Microsoft.Maui.Controls.Binding.Binding(String, BindingMode, IValueConverter, Object, String, Object)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Using bindings with string paths is not trim safe. Use expression-based binding instead.
// This code is only reachable in XamlC compiled code when there is a missing x:DataType and the binding could not be compiled.
// In that case, we produce a warning that the binding could not be compiled.
return new Binding(Path, Mode, Converter, ConverterParameter, StringFormat, Source)
{
UpdateSourceEventName = UpdateSourceEventName,
FallbackValue = FallbackValue,
TargetNullValue = TargetNullValue,
};
#pragma warning restore IL2026
return CreateBinding();
}

TypedBinding.Mode = Mode;
Expand All @@ -44,6 +36,19 @@ BindingBase IMarkupExtension<BindingBase>.ProvideValue(IServiceProvider serviceP
TypedBinding.FallbackValue = FallbackValue;
TypedBinding.TargetNullValue = TargetNullValue;
return TypedBinding;

[UnconditionalSuppressMessage("TrimAnalysis", "IL2026",
Justification = "This code is only reachable in XamlC compiled code when there is a missing x:DataType and the binding could not be compiled. " +
"In that case, we produce a warning that the binding could not be compiled.")]
BindingBase CreateBinding()
{
return new Binding(Path, Mode, Converter, ConverterParameter, StringFormat, Source)
{
UpdateSourceEventName = UpdateSourceEventName,
FallbackValue = FallbackValue,
TargetNullValue = TargetNullValue,
};
}
}

object IMarkupExtension.ProvideValue(IServiceProvider serviceProvider)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
using System;
using System.Diagnostics.CodeAnalysis;

namespace Microsoft.Maui.Controls.Xaml
{
[ContentProperty(nameof(TypeName))]
[ProvideCompiled("Microsoft.Maui.Controls.Build.Tasks.DataTemplateExtension")]
[RequiresUnreferencedCode(TrimmerConstants.XamlRuntimeParsingNotSupportedWarning)]
public sealed class DataTemplateExtension : IMarkupExtension<DataTemplate>
{
public string TypeName { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ public void GetHandlerFromContainer()
public void GetEffectFromContainer()
{
string effectName = "anEffect";
Internals.Registrar.Effects[effectName] = typeof(MockEffect);
Internals.Registrar.Effects[effectName] = new Registrar.EffectType(typeof(MockEffect));
var effect = new MockEffect();
_container.Register(typeof(MockEffect), effect);
var result = Effect.Resolve(effectName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -282,12 +282,57 @@ public void PublishNativeAOT(string id, string framework, string runtimeIdentifi
Assert.IsTrue(DotnetInternal.New(id, projectDir, DotNetCurrent),
$"Unable to create template {id}. Check test output for errors.");

var extendedBuildProps = BuildProps;
extendedBuildProps.Add("PublishAot=true");
extendedBuildProps.Add("PublishAotUsingRuntimePack=true"); // TODO: This parameter will become obsolete https://github.com/dotnet/runtime/issues/87060 in net9
extendedBuildProps.Add("_IsPublishing=true"); // This makes 'dotnet build -r iossimulator-x64' equivalent to 'dotnet publish -r iossimulator-x64'
extendedBuildProps.Add("IlcTreatWarningsAsErrors=false");
extendedBuildProps.Add("TrimmerSingleWarn=false");
var extendedBuildProps = PrepareNativeAotBuildProps();

string binLogFilePath = $"publish-{DateTime.UtcNow.ToFileTimeUtc()}.binlog";
Assert.IsTrue(DotnetInternal.Build(projectFile, "Release", framework: framework, properties: extendedBuildProps, runtimeIdentifier: runtimeIdentifier, binlogPath: binLogFilePath),
$"Project {Path.GetFileName(projectFile)} failed to build. Check test output/attachments for errors.");

var actualWarnings = BuildWarningsUtilities.ReadNativeAOTWarningsFromBinLog(binLogFilePath);
actualWarnings.AssertNoWarnings();
}

[Test]
[TestCase("maui", $"{DotNetCurrent}-ios", "ios-arm64")]
[TestCase("maui", $"{DotNetCurrent}-ios", "iossimulator-arm64")]
[TestCase("maui", $"{DotNetCurrent}-ios", "iossimulator-x64")]
[TestCase("maui", $"{DotNetCurrent}-maccatalyst", "maccatalyst-arm64")]
[TestCase("maui", $"{DotNetCurrent}-maccatalyst", "maccatalyst-x64")]
public void PublishNativeAOTRootAllMauiAssemblies(string id, string framework, string runtimeIdentifier)
{
// This test follows the following guide: https://devblogs.microsoft.com/dotnet/creating-aot-compatible-libraries/#publishing-a-test-application-for-aot
if (!TestEnvironment.IsMacOS)
Assert.Ignore("Publishing a MAUI iOS app with NativeAOT is only supported on a host MacOS system.");

var projectDir = TestDirectory;
var projectFile = Path.Combine(projectDir, $"{Path.GetFileName(projectDir)}.csproj");

Assert.IsTrue(DotnetInternal.New(id, projectDir, DotNetCurrent),
$"Unable to create template {id}. Check test output for errors.");

var extendedBuildProps = PrepareNativeAotBuildProps();
FileUtilities.ReplaceInFile(projectFile,
"</Project>",
"""
<ItemGroup>
<PackageReference Include="Microsoft.Maui.Controls.Foldable" Version="$(MauiVersion)" />
<PackageReference Include="Microsoft.Maui.Controls.Maps" Version="$(MauiVersion)" />
<PackageReference Include="Microsoft.Maui.Graphics.Skia" Version="$(MauiVersion)" />
</ItemGroup>
<ItemGroup>
<TrimmerRootAssembly Include="Microsoft.Maui" />
<TrimmerRootAssembly Include="Microsoft.Maui.Controls" />
<TrimmerRootAssembly Include="Microsoft.Maui.Controls.Compatibility" />
<TrimmerRootAssembly Include="Microsoft.Maui.Controls.Foldable" />
<TrimmerRootAssembly Include="Microsoft.Maui.Controls.Maps" />
<TrimmerRootAssembly Include="Microsoft.Maui.Controls.Xaml" />
<TrimmerRootAssembly Include="Microsoft.Maui.Essentials" />
<TrimmerRootAssembly Include="Microsoft.Maui.Graphics" />
<TrimmerRootAssembly Include="Microsoft.Maui.Graphics.Skia" />
<TrimmerRootAssembly Include="Microsoft.Maui.Maps" />
</ItemGroup>
</Project>
""");

string binLogFilePath = $"publish-{DateTime.UtcNow.ToFileTimeUtc()}.binlog";
Assert.IsTrue(DotnetInternal.Build(projectFile, "Release", framework: framework, properties: extendedBuildProps, runtimeIdentifier: runtimeIdentifier, binlogPath: binLogFilePath),
Expand All @@ -297,6 +342,17 @@ public void PublishNativeAOT(string id, string framework, string runtimeIdentifi
actualWarnings.AssertNoWarnings();
}

private List<string> PrepareNativeAotBuildProps()
{
var extendedBuildProps = new List<string>(BuildProps);
extendedBuildProps.Add("PublishAot=true");
extendedBuildProps.Add("PublishAotUsingRuntimePack=true"); // TODO: This parameter will become obsolete https://github.com/dotnet/runtime/issues/87060 in net9
extendedBuildProps.Add("_IsPublishing=true"); // This makes 'dotnet build -r iossimulator-x64' equivalent to 'dotnet publish -r iossimulator-x64'
extendedBuildProps.Add("IlcTreatWarningsAsErrors=false");
extendedBuildProps.Add("TrimmerSingleWarn=false");
return extendedBuildProps;
}

[Test]
[TestCase("maui", DotNetCurrent, "Release")]
public void PublishUnpackaged(string id, string framework, string config)
Expand Down
Loading