From d42b2b0207918ff63c72d415a7d2e66bbf2612a7 Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Sat, 4 Oct 2025 13:25:48 +0100 Subject: [PATCH 01/14] fix AOT linker warnings --- .../Modules/PublishNugetTesterAOTModule.cs | 80 +++++++++++++++++++ .../TUnit.NugetTester.FSharp.fsproj | 7 ++ .../TUnit.NugetTester.Library.csproj | 1 + .../TUnit.NugetTester.VB.vbproj | 7 ++ .../TUnit.NugetTester.csproj | 7 ++ 5 files changed, 102 insertions(+) create mode 100644 TUnit.Pipeline/Modules/PublishNugetTesterAOTModule.cs diff --git a/TUnit.Pipeline/Modules/PublishNugetTesterAOTModule.cs b/TUnit.Pipeline/Modules/PublishNugetTesterAOTModule.cs new file mode 100644 index 0000000000..5bbb404429 --- /dev/null +++ b/TUnit.Pipeline/Modules/PublishNugetTesterAOTModule.cs @@ -0,0 +1,80 @@ +using System.Runtime.InteropServices; +using ModularPipelines.Attributes; +using ModularPipelines.Context; +using ModularPipelines.DotNet.Extensions; +using ModularPipelines.DotNet.Options; +using ModularPipelines.Enums; +using ModularPipelines.Extensions; +using ModularPipelines.Git.Extensions; +using ModularPipelines.Models; +using ModularPipelines.Modules; + +namespace TUnit.Pipeline.Modules; + +[DependsOn] +[DependsOn] +[DependsOn] +public class PublishNugetTesterAOTModule : Module> +{ + protected override Task ShouldSkip(IPipelineContext context) + { + return Task.FromResult(EnvironmentVariables.IsNetFramework); + } + + protected override async Task?> ExecuteAsync(IPipelineContext context, CancellationToken cancellationToken) + { + var results = new List(); + var version = await GetModule(); + + var testProject = context.Git() + .RootDirectory + .AssertExists() + .FindFile(x => x.Name == "TUnit.NugetTester.csproj") + .AssertExists(); + + // Test AOT publishing for net8.0 and net9.0 + foreach (var framework in new[] { "net8.0", "net9.0" }) + { + var result = await SubModule($"AOT-{framework}", async () => + { + return await context.DotNet().Publish(new DotNetPublishOptions(testProject) + { + RuntimeIdentifier = GetRuntimeIdentifier(), + Configuration = Configuration.Release, + OutputDirectory = $"NUGETTESTER_AOT_{framework}", + Properties = + [ + new KeyValue("Aot", "true"), + new KeyValue("TUnitVersion", version.Value!.SemVer!) + ], + Framework = framework, + CommandLogging = CommandLogging.Input | CommandLogging.Error | CommandLogging.Duration | CommandLogging.ExitCode + }, cancellationToken); + }); + + results.Add(result); + } + + return results; + } + + private string GetRuntimeIdentifier() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + return "linux-x64"; + } + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return "win-x64"; + } + + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + return "osx-arm64"; + } + + throw new ArgumentException("Unknown platform"); + } +} diff --git a/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester.FSharp/TUnit.NugetTester.FSharp.fsproj b/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester.FSharp/TUnit.NugetTester.FSharp.fsproj index 0d8573d8c6..beaff07a75 100644 --- a/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester.FSharp/TUnit.NugetTester.FSharp.fsproj +++ b/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester.FSharp/TUnit.NugetTester.FSharp.fsproj @@ -7,6 +7,13 @@ enable exe enable + true + + + + true + true + true diff --git a/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester.Library/TUnit.NugetTester.Library.csproj b/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester.Library/TUnit.NugetTester.Library.csproj index 6eb0069425..a68f6c1dc8 100644 --- a/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester.Library/TUnit.NugetTester.Library.csproj +++ b/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester.Library/TUnit.NugetTester.Library.csproj @@ -6,6 +6,7 @@ true enable enable + true diff --git a/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester.VB/TUnit.NugetTester.VB.vbproj b/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester.VB/TUnit.NugetTester.VB.vbproj index 645022e2d8..ab2951a7bd 100644 --- a/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester.VB/TUnit.NugetTester.VB.vbproj +++ b/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester.VB/TUnit.NugetTester.VB.vbproj @@ -7,6 +7,13 @@ enable exe enable + true + + + + true + true + true diff --git a/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester/TUnit.NugetTester.csproj b/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester/TUnit.NugetTester.csproj index 7891fa6078..60edc3eaa6 100644 --- a/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester/TUnit.NugetTester.csproj +++ b/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester/TUnit.NugetTester.csproj @@ -7,6 +7,13 @@ enable exe enable + true + + + + true + true + true From d31cfbb1746fc64f9f4c9199eff1d4aade6dc299 Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Sat, 4 Oct 2025 14:17:01 +0100 Subject: [PATCH 02/14] fix: suppress NU1504 warnings in project files --- Directory.Packages.props | 5 +---- .../TUnit.NugetTester.FSharp/TUnit.NugetTester.FSharp.fsproj | 1 + .../TUnit.NugetTester.Library.csproj | 1 + .../TUnit.NugetTester.VB/TUnit.NugetTester.VB.vbproj | 1 + .../TUnit.NugetTester/TUnit.NugetTester.csproj | 3 ++- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index ecd810e78d..57b1feafef 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -58,10 +58,7 @@ - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester.FSharp/TUnit.NugetTester.FSharp.fsproj b/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester.FSharp/TUnit.NugetTester.FSharp.fsproj index beaff07a75..979822dc00 100644 --- a/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester.FSharp/TUnit.NugetTester.FSharp.fsproj +++ b/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester.FSharp/TUnit.NugetTester.FSharp.fsproj @@ -8,6 +8,7 @@ exe enable true + $(NoWarn);NU1504 diff --git a/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester.Library/TUnit.NugetTester.Library.csproj b/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester.Library/TUnit.NugetTester.Library.csproj index a68f6c1dc8..7c48f5920d 100644 --- a/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester.Library/TUnit.NugetTester.Library.csproj +++ b/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester.Library/TUnit.NugetTester.Library.csproj @@ -7,6 +7,7 @@ enable enable true + $(NoWarn);NU1504 diff --git a/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester.VB/TUnit.NugetTester.VB.vbproj b/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester.VB/TUnit.NugetTester.VB.vbproj index ab2951a7bd..6c00b40ee1 100644 --- a/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester.VB/TUnit.NugetTester.VB.vbproj +++ b/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester.VB/TUnit.NugetTester.VB.vbproj @@ -8,6 +8,7 @@ exe enable true + $(NoWarn);NU1504 diff --git a/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester/TUnit.NugetTester.csproj b/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester/TUnit.NugetTester.csproj index 60edc3eaa6..3823e4c076 100644 --- a/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester/TUnit.NugetTester.csproj +++ b/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester/TUnit.NugetTester.csproj @@ -8,6 +8,7 @@ exe enable true + $(NoWarn);NU1504 @@ -20,7 +21,7 @@ $(TUnitVersion) - + From 3aca6630a90f647e920c09d113038c9718086fc0 Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Sat, 4 Oct 2025 14:51:59 +0100 Subject: [PATCH 03/14] fix: disable IlcSingleWarn for AOT compatibility --- .../TUnit.NugetTester/TUnit.NugetTester/TUnit.NugetTester.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester/TUnit.NugetTester.csproj b/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester/TUnit.NugetTester.csproj index 3823e4c076..88d8cdc3c3 100644 --- a/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester/TUnit.NugetTester.csproj +++ b/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester/TUnit.NugetTester.csproj @@ -15,6 +15,7 @@ true true true + false From bf69a608956918d06486d2b068db1da65f6e01c2 Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Sat, 4 Oct 2025 23:06:05 +0100 Subject: [PATCH 04/14] fix: add RequiresUnreferencedCode attributes for AOT compatibility in various classes --- TUnit.Core/AsyncConvert.cs | 32 +- .../Attributes/Executors/CultureAttribute.cs | 3 + .../Executors/STAThreadExecutorAttribute.cs | 3 + .../Executors/TestExecutorAttribute.cs | 6 + .../Attributes/ParallelLimiterAttribute.cs | 3 + .../Attributes/TestData/ArgumentsAttribute.cs | 6 + ...typedDataSourceSourceGeneratorAttribute.cs | 4 +- .../TestData/ClassDataSourceAttribute.cs | 43 ++- ...dencyInjectionDataSourceSourceAttribute.cs | 2 + .../TestData/MatrixDataSourceAttribute.cs | 15 +- .../TestData/MethodDataSourceAttribute.cs | 12 +- .../UntypedDataSourceGeneratorAttribute.cs | 2 + .../Attributes/TestMetadata/SkipAttribute.cs | 3 + TUnit.Core/DataGeneratorMetadataCreator.cs | 12 +- TUnit.Core/DataSources/DataSourceProcessor.cs | 24 +- TUnit.Core/DynamicTestBuilderContext.cs | 4 +- .../Executors/DedicatedThreadExecutor.cs | 3 + TUnit.Core/Extensions/ReflectionExtensions.cs | 33 +- .../Extensions/TestContextExtensions.cs | 5 +- TUnit.Core/Helpers/CastHelper.cs | 21 +- TUnit.Core/Helpers/DataSourceHelpers.cs | 16 +- TUnit.Core/Helpers/GenericTypeHelper.cs | 17 +- TUnit.Core/Helpers/TupleHelper.cs | 7 +- TUnit.Core/Hooks/LastTestInClassAdapter.cs | 4 +- .../ITestRegisteredEventReceiver.cs | 3 + TUnit.Core/Interfaces/ITestRegistry.cs | 7 +- .../PropertyInjection/ClassMetadataHelper.cs | 18 +- .../PropertyInjectionCache.cs | 10 +- .../PropertyInjectionPlanBuilder.cs | 17 +- .../PropertySetterFactory.cs | 26 +- .../PropertyInjection/TupleValueResolver.cs | 12 +- TUnit.Core/PropertySourceRegistry.cs | 27 +- TUnit.Core/Services/GenericTypeResolver.cs | 4 +- .../StaticPropertyReflectionInitializer.cs | 23 +- TUnit.Core/TestContext.cs | 11 +- TUnit.Core/Tracking/ObjectTracker.cs | 6 +- .../Tracking/TrackableObjectGraphProvider.cs | 9 +- .../Collectors/AotTestDataCollector.cs | 64 ++-- .../Building/Interfaces/ITestBuilder.cs | 13 + .../Building/Interfaces/ITestDataCollector.cs | 5 + .../Building/ReflectionMetadataBuilder.cs | 17 +- TUnit.Engine/Building/TestBuilder.cs | 60 ++- TUnit.Engine/Building/TestBuilderPipeline.cs | 23 ++ .../Building/TestDataCollectorFactory.cs | 4 + .../Discovery/AsyncDataSourceHelper.cs | 7 +- TUnit.Engine/Discovery/ConstructorHelper.cs | 31 +- TUnit.Engine/Discovery/GenericTestHelper.cs | 15 +- .../ReflectionGenericTypeResolver.cs | 22 +- .../ReflectionHookDiscoveryService.cs | 119 ++++-- .../Discovery/ReflectionTestDataCollector.cs | 201 +++++++++- TUnit.Engine/Discovery/TestInstanceHelper.cs | 19 +- TUnit.Engine/Framework/IRequestHandler.cs | 4 + .../Framework/TUnitServiceProvider.cs | 9 +- TUnit.Engine/Framework/TUnitTestFramework.cs | 12 + TUnit.Engine/Framework/TestRequestHandler.cs | 12 + TUnit.Engine/Helpers/DisplayNameBuilder.cs | 5 +- .../Interfaces/IHookCollectionService.cs | 12 + TUnit.Engine/Interfaces/ITestCoordinator.cs | 4 + .../Scheduling/ConstraintKeyScheduler.cs | 9 + .../Scheduling/IConstraintKeyScheduler.cs | 4 + TUnit.Engine/Scheduling/ITestScheduler.cs | 4 + TUnit.Engine/Scheduling/TestRunner.cs | 6 + TUnit.Engine/Scheduling/TestScheduler.cs | 21 + .../Services/DataSourceInitializer.cs | 12 + .../Services/EventReceiverOrchestrator.cs | 24 ++ .../Services/HookCollectionService.cs | 33 ++ TUnit.Engine/Services/HookExecutor.cs | 6 + .../Services/ObjectRegistrationService.cs | 12 + TUnit.Engine/Services/PropertyDataResolver.cs | 19 +- .../Strategies/NestedPropertyStrategy.cs | 12 + .../Strategies/ReflectionPropertyStrategy.cs | 7 +- .../SourceGeneratedPropertyStrategy.cs | 6 + .../PropertyInitializationOrchestrator.cs | 13 +- .../Services/PropertyInjectionService.cs | 9 + .../TestArgumentRegistrationService.cs | 12 + .../Services/TestExecution/TestCoordinator.cs | 18 + TUnit.Engine/Services/TestFilterService.cs | 6 + .../Services/TestGenericTypeResolver.cs | 25 +- TUnit.Engine/Services/TestRegistry.cs | 10 +- TUnit.Engine/TUnitInitializer.cs | 10 +- TUnit.Engine/TestDiscoveryService.cs | 12 + TUnit.Engine/TestExecutor.cs | 8 +- TUnit.Engine/TestInitializer.cs | 3 + TUnit.Engine/TestSessionCoordinator.cs | 19 + .../Utilities/ScopedAttributeFilter.cs | 17 +- TUnit.Playwright/WorkerAwareTest.cs | 3 + build_output.txt | 359 +++++++++++++++++- 87 files changed, 1499 insertions(+), 311 deletions(-) diff --git a/TUnit.Core/AsyncConvert.cs b/TUnit.Core/AsyncConvert.cs index 1447840b3b..d793369cf3 100644 --- a/TUnit.Core/AsyncConvert.cs +++ b/TUnit.Core/AsyncConvert.cs @@ -55,6 +55,10 @@ public static async ValueTask Convert(Func action) | MethodImplOptions.AggressiveOptimization #endif )] + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("ConvertObject uses reflection to handle custom awaitable types and F# async. For AOT compatibility, use Task or ValueTask directly.")] + [RequiresDynamicCode("ConvertObject may require dynamic invocation for custom awaitable types. For AOT compatibility, use Task or ValueTask directly.")] + #endif public static async ValueTask ConvertObject(object? invoke) { if (invoke is Delegate @delegate) @@ -114,16 +118,10 @@ public static async ValueTask ConvertObject(object? invoke) [System.Diagnostics.CodeAnalysis.DynamicDependency(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicMethods, "Microsoft.FSharp.Control.FSharpAsync", "FSharp.Core")] [System.Diagnostics.CodeAnalysis.DynamicDependency("StartAsTask", "Microsoft.FSharp.Control.FSharpAsync", "FSharp.Core")] - [UnconditionalSuppressMessage("Trimming", "IL2077:Target parameter argument does not satisfy \'DynamicallyAccessedMembersAttribute\' in call to target method. The source field does not have matching annotations.", - Justification = "F# async support requires FSharp.Core types. The DynamicDependency attributes preserve required members.")] - [UnconditionalSuppressMessage("Trimming", "IL2072:Target parameter argument does not satisfy \'DynamicallyAccessedMembersAttribute\' in call to target method. The return value of the source method does not have matching annotations.", - Justification = "F# async type resolution is preserved through DynamicDependency. For AOT, ensure FSharp.Core is properly referenced.")] - [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with \'RequiresDynamicCodeAttribute\' may break functionality when AOT compiling.", - Justification = "F# async interop requires MakeGenericMethod. F# tests in AOT scenarios should use Task-based APIs.")] - [UnconditionalSuppressMessage("Trimming", "IL2060:Call to \'System.Reflection.MethodInfo.MakeGenericMethod\' can not be statically analyzed. It\'s not possible to guarantee the availability of requirements of the generic method.", - Justification = "Generic method instantiation for F# async types. The type parameter comes from the F# async type itself.")] - [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", - Justification = "F# async support is optional. Tests using F# async should ensure FSharp.Core is preserved in AOT scenarios.")] + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("F# async support requires FSharp.Core types and reflection. For AOT, use Task-based APIs.")] + [RequiresDynamicCode("F# async interop requires MakeGenericMethod. For AOT, use Task-based APIs.")] + #endif private static ValueTask StartAsFSharpTask(object invoke, Type type) { var startAsTaskOpenGenericMethod = (_fSharpAsyncType ??= type.Assembly.GetType("Microsoft.FSharp.Control.FSharpAsync"))! @@ -145,10 +143,10 @@ private static ValueTask StartAsFSharpTask(object invoke, Type type) /// /// Safely invokes F# async conversion with proper suppression for the call site. /// - [UnconditionalSuppressMessage("Trimming", "IL2026:Using member with RequiresUnreferencedCodeAttribute", - Justification = "F# async is an optional feature. AOT applications should use Task-based APIs.")] - [UnconditionalSuppressMessage("AOT", "IL3050:Using member with RequiresDynamicCodeAttribute", - Justification = "F# async requires runtime code generation. This is documented as not AOT-compatible.")] + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("F# async is an optional feature. AOT applications should use Task-based APIs.")] + [RequiresDynamicCode("F# async requires runtime code generation. This is documented as not AOT-compatible.")] + #endif private static async ValueTask StartAsFSharpTaskSafely(object invoke, Type type) { if (IsFSharpAsyncSupported()) @@ -183,8 +181,10 @@ private static bool IsFSharpAsyncSupported() } } - [UnconditionalSuppressMessage("Trimming", "IL2075:\'this\' argument does not satisfy \'DynamicallyAccessedMembersAttribute\' in call to target method. The return value of the source method does not have matching annotations.", - Justification = "GetAwaiter pattern detection for custom awaitables. For AOT, use standard Task/ValueTask types or implement IAsyncEnumerable.")] + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("GetAwaiter pattern detection requires reflection for custom awaitable types. For AOT, use Task/ValueTask.")] + [RequiresDynamicCode("Custom awaitable handling may require dynamic invocation. For AOT, use Task/ValueTask.")] + #endif public static bool TryGetAwaitableTask(object awaitable, [NotNullWhen(true)] out Task? task) { var getAwaiter = awaitable.GetType().GetMethod("GetAwaiter", Type.EmptyTypes); diff --git a/TUnit.Core/Attributes/Executors/CultureAttribute.cs b/TUnit.Core/Attributes/Executors/CultureAttribute.cs index f3b39c2b08..30e3706921 100644 --- a/TUnit.Core/Attributes/Executors/CultureAttribute.cs +++ b/TUnit.Core/Attributes/Executors/CultureAttribute.cs @@ -12,6 +12,9 @@ public CultureAttribute(string cultureName) : this(CultureInfo.GetCultureInfo(cu public int Order => 0; +#if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Type comes from runtime objects that cannot be annotated")] +#endif public ValueTask OnTestRegistered(TestRegisteredContext context) { context.SetTestExecutor(new CultureExecutor(cultureInfo)); diff --git a/TUnit.Core/Attributes/Executors/STAThreadExecutorAttribute.cs b/TUnit.Core/Attributes/Executors/STAThreadExecutorAttribute.cs index 403b6604b2..52b43a538e 100644 --- a/TUnit.Core/Attributes/Executors/STAThreadExecutorAttribute.cs +++ b/TUnit.Core/Attributes/Executors/STAThreadExecutorAttribute.cs @@ -9,6 +9,9 @@ public class STAThreadExecutorAttribute : TUnitAttribute, ITestRegisteredEventRe { public int Order => 0; +#if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Type comes from runtime objects that cannot be annotated")] +#endif public ValueTask OnTestRegistered(TestRegisteredContext context) { var executor = new STAThreadExecutor(); diff --git a/TUnit.Core/Attributes/Executors/TestExecutorAttribute.cs b/TUnit.Core/Attributes/Executors/TestExecutorAttribute.cs index c549172816..9d32a2d863 100644 --- a/TUnit.Core/Attributes/Executors/TestExecutorAttribute.cs +++ b/TUnit.Core/Attributes/Executors/TestExecutorAttribute.cs @@ -8,6 +8,9 @@ namespace TUnit.Core.Executors; { public int Order => 0; +#if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Type comes from runtime objects that cannot be annotated")] +#endif public ValueTask OnTestRegistered(TestRegisteredContext context) { context.SetTestExecutor(new T()); @@ -20,6 +23,9 @@ public sealed class TestExecutorAttribute([DynamicallyAccessedMembers(Dynamicall { public int Order => 0; +#if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Type comes from runtime objects that cannot be annotated")] +#endif public ValueTask OnTestRegistered(TestRegisteredContext context) { context.SetTestExecutor((ITestExecutor) Activator.CreateInstance(type)!); diff --git a/TUnit.Core/Attributes/ParallelLimiterAttribute.cs b/TUnit.Core/Attributes/ParallelLimiterAttribute.cs index 2bc23a15ce..1b5cc88b84 100644 --- a/TUnit.Core/Attributes/ParallelLimiterAttribute.cs +++ b/TUnit.Core/Attributes/ParallelLimiterAttribute.cs @@ -57,6 +57,9 @@ public sealed class ParallelLimiterAttribute : TUnitAttribute, I public int Order => 0; /// +#if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Type comes from runtime objects that cannot be annotated")] +#endif public ValueTask OnTestRegistered(TestRegisteredContext context) { context.SetParallelLimiter(new TParallelLimit()); diff --git a/TUnit.Core/Attributes/TestData/ArgumentsAttribute.cs b/TUnit.Core/Attributes/TestData/ArgumentsAttribute.cs index e5df57fcc5..0ff0cc87ff 100644 --- a/TUnit.Core/Attributes/TestData/ArgumentsAttribute.cs +++ b/TUnit.Core/Attributes/TestData/ArgumentsAttribute.cs @@ -27,6 +27,9 @@ public ArgumentsAttribute(params object?[]? values) await Task.CompletedTask; } +#if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Type comes from runtime objects that cannot be annotated")] +#endif public ValueTask OnTestRegistered(TestRegisteredContext context) { if(!string.IsNullOrEmpty(Skip)) @@ -52,6 +55,9 @@ public override async IAsyncEnumerable>> GetTypedDataRowsAsync(Data await default(ValueTask); } +#if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Type comes from runtime objects that cannot be annotated")] +#endif public ValueTask OnTestRegistered(TestRegisteredContext context) { if(!string.IsNullOrEmpty(Skip)) diff --git a/TUnit.Core/Attributes/TestData/AsyncUntypedDataSourceSourceGeneratorAttribute.cs b/TUnit.Core/Attributes/TestData/AsyncUntypedDataSourceSourceGeneratorAttribute.cs index 1d4dcd9b50..e483358c28 100644 --- a/TUnit.Core/Attributes/TestData/AsyncUntypedDataSourceSourceGeneratorAttribute.cs +++ b/TUnit.Core/Attributes/TestData/AsyncUntypedDataSourceSourceGeneratorAttribute.cs @@ -1,10 +1,12 @@ -using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.CodeAnalysis; namespace TUnit.Core; [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Property, AllowMultiple = true)] +#if NET6_0_OR_GREATER [RequiresDynamicCode("AsyncUntypedDataSourceGeneratorAttribute requires dynamic code generation for runtime data source creation. Consider using strongly-typed AsyncDataSourceGeneratorAttribute overloads for AOT compatibility.")] [RequiresUnreferencedCode("AsyncUntypedDataSourceGeneratorAttribute may require unreferenced code for runtime data source creation. Consider using strongly-typed AsyncDataSourceGeneratorAttribute overloads for AOT compatibility.")] +#endif public abstract class AsyncUntypedDataSourceGeneratorAttribute : Attribute, IAsyncUntypedDataSourceGeneratorAttribute { protected abstract IAsyncEnumerable>> GenerateDataSourcesAsync(DataGeneratorMetadata dataGeneratorMetadata); diff --git a/TUnit.Core/Attributes/TestData/ClassDataSourceAttribute.cs b/TUnit.Core/Attributes/TestData/ClassDataSourceAttribute.cs index 8290bf3e7c..8fb04980a7 100644 --- a/TUnit.Core/Attributes/TestData/ClassDataSourceAttribute.cs +++ b/TUnit.Core/Attributes/TestData/ClassDataSourceAttribute.cs @@ -25,22 +25,28 @@ protected override IEnumerable> GenerateDataSources(DataGeneratorMetadat } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = true)] -[UnconditionalSuppressMessage("Trimming", "IL2109:Type derives from type with 'RequiresUnreferencedCodeAttribute' which can break functionality when trimming application code", - Justification = "The specific constructors (1-5 parameters) are AOT-compatible when used with typeof() expressions. Only the params constructor is incompatible.")] +#if NET6_0_OR_GREATER +[RequiresUnreferencedCode("ClassDataSourceAttribute uses reflection to instantiate and access test data classes. For AOT compatibility, use strongly-typed ClassDataSourceAttribute instead.")] +[RequiresDynamicCode("ClassDataSourceAttribute may require runtime type generation. For AOT compatibility, use strongly-typed ClassDataSourceAttribute instead.")] +#endif public sealed class ClassDataSourceAttribute : UntypedDataSourceGeneratorAttribute { private readonly Type[] _types; - [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "These constructors delegate to the params constructor but are AOT-safe when used with typeof() expressions at compile time. The DynamicallyAccessedMembers annotations ensure required members are preserved.")] - [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with \'RequiresDynamicCodeAttribute\' may break functionality when AOT compiling.", Justification = "These constructors are AOT-compatible when types are specified using typeof() at compile time. Only the params constructor requires dynamic code.")] + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("ClassDataSourceAttribute uses reflection to instantiate and access test data classes. For AOT compatibility, use strongly-typed ClassDataSourceAttribute instead.")] + [RequiresDynamicCode("ClassDataSourceAttribute may require runtime type generation. For AOT compatibility, use strongly-typed ClassDataSourceAttribute instead.")] + #endif public ClassDataSourceAttribute( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.PublicMethods)] Type type) : this([type]) { } - [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "These constructors delegate to the params constructor but are AOT-safe when used with typeof() expressions at compile time. The DynamicallyAccessedMembers annotations ensure required members are preserved.")] - [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with \'RequiresDynamicCodeAttribute\' may break functionality when AOT compiling.", Justification = "These constructors are AOT-compatible when types are specified using typeof() at compile time. Only the params constructor requires dynamic code.")] + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("ClassDataSourceAttribute uses reflection to instantiate and access test data classes. For AOT compatibility, use strongly-typed ClassDataSourceAttribute instead.")] + [RequiresDynamicCode("ClassDataSourceAttribute may require runtime type generation. For AOT compatibility, use strongly-typed ClassDataSourceAttribute instead.")] + #endif public ClassDataSourceAttribute( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.PublicMethods)] Type type, @@ -49,8 +55,10 @@ public ClassDataSourceAttribute( { } - [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "These constructors delegate to the params constructor but are AOT-safe when used with typeof() expressions at compile time. The DynamicallyAccessedMembers annotations ensure required members are preserved.")] - [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with \'RequiresDynamicCodeAttribute\' may break functionality when AOT compiling.", Justification = "These constructors are AOT-compatible when types are specified using typeof() at compile time. Only the params constructor requires dynamic code.")] + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("ClassDataSourceAttribute uses reflection to instantiate and access test data classes. For AOT compatibility, use strongly-typed ClassDataSourceAttribute instead.")] + [RequiresDynamicCode("ClassDataSourceAttribute may require runtime type generation. For AOT compatibility, use strongly-typed ClassDataSourceAttribute instead.")] + #endif public ClassDataSourceAttribute( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.PublicMethods)] Type type, @@ -61,8 +69,10 @@ public ClassDataSourceAttribute( { } - [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "These constructors delegate to the params constructor but are AOT-safe when used with typeof() expressions at compile time. The DynamicallyAccessedMembers annotations ensure required members are preserved.")] - [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with \'RequiresDynamicCodeAttribute\' may break functionality when AOT compiling.", Justification = "These constructors are AOT-compatible when types are specified using typeof() at compile time. Only the params constructor requires dynamic code.")] + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("ClassDataSourceAttribute uses reflection to instantiate and access test data classes. For AOT compatibility, use strongly-typed ClassDataSourceAttribute instead.")] + [RequiresDynamicCode("ClassDataSourceAttribute may require runtime type generation. For AOT compatibility, use strongly-typed ClassDataSourceAttribute instead.")] + #endif public ClassDataSourceAttribute( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.PublicMethods)] Type type, @@ -75,8 +85,10 @@ public ClassDataSourceAttribute( { } - [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "These constructors delegate to the params constructor but are AOT-safe when used with typeof() expressions at compile time. The DynamicallyAccessedMembers annotations ensure required members are preserved.")] - [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with \'RequiresDynamicCodeAttribute\' may break functionality when AOT compiling.", Justification = "These constructors are AOT-compatible when types are specified using typeof() at compile time. Only the params constructor requires dynamic code.")] + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("ClassDataSourceAttribute uses reflection to instantiate and access test data classes. For AOT compatibility, use strongly-typed ClassDataSourceAttribute instead.")] + [RequiresDynamicCode("ClassDataSourceAttribute may require runtime type generation. For AOT compatibility, use strongly-typed ClassDataSourceAttribute instead.")] + #endif public ClassDataSourceAttribute( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.PublicMethods)] Type type, @@ -91,8 +103,10 @@ public ClassDataSourceAttribute( { } + #if NET6_0_OR_GREATER [RequiresUnreferencedCode("Reflection")] [RequiresDynamicCode("Reflection")] + #endif public ClassDataSourceAttribute(params Type[] types) { _types = types; @@ -101,7 +115,10 @@ public ClassDataSourceAttribute(params Type[] types) public SharedType[] Shared { get; set; } = [SharedType.None]; public string[] Keys { get; set; } = []; - [UnconditionalSuppressMessage("Trimming", "IL2062:The parameter of method has a DynamicallyAccessedMembersAttribute, but the value passed to it can not be statically analyzed.", Justification = "The _types array is populated from constructor parameters that have DynamicallyAccessedMembers attributes, ensuring the required members are preserved at the call site.")] + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Reflection")] + [RequiresDynamicCode("Reflection")] + #endif protected override IEnumerable> GenerateDataSources(DataGeneratorMetadata dataGeneratorMetadata) { yield return () => diff --git a/TUnit.Core/Attributes/TestData/DependencyInjectionDataSourceSourceAttribute.cs b/TUnit.Core/Attributes/TestData/DependencyInjectionDataSourceSourceAttribute.cs index bcaa40d58b..817035eba9 100644 --- a/TUnit.Core/Attributes/TestData/DependencyInjectionDataSourceSourceAttribute.cs +++ b/TUnit.Core/Attributes/TestData/DependencyInjectionDataSourceSourceAttribute.cs @@ -2,8 +2,10 @@ namespace TUnit.Core; +#if NET6_0_OR_GREATER [RequiresDynamicCode("DependencyInjectionDataSourceAttribute requires dynamic code generation for dependency injection container access. This attribute is inherently incompatible with AOT compilation.")] [RequiresUnreferencedCode("DependencyInjectionDataSourceAttribute may require unreferenced code for dependency injection container access. This attribute is inherently incompatible with AOT compilation.")] +#endif public abstract class DependencyInjectionDataSourceAttribute : UntypedDataSourceGeneratorAttribute { protected override IEnumerable> GenerateDataSources(DataGeneratorMetadata dataGeneratorMetadata) diff --git a/TUnit.Core/Attributes/TestData/MatrixDataSourceAttribute.cs b/TUnit.Core/Attributes/TestData/MatrixDataSourceAttribute.cs index 66f7ce99be..18abcc9d44 100644 --- a/TUnit.Core/Attributes/TestData/MatrixDataSourceAttribute.cs +++ b/TUnit.Core/Attributes/TestData/MatrixDataSourceAttribute.cs @@ -5,10 +5,16 @@ namespace TUnit.Core; [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] -[UnconditionalSuppressMessage("AOT", "IL2109:Type 'MatrixDataSourceAttribute' derives from base class with RequiresUnreferencedCodeAttribute", - Justification = "Matrix data source implementation is AOT-compatible with proper enum field preservation")] +#if NET6_0_OR_GREATER +[RequiresUnreferencedCode("MatrixDataSource uses reflection to access parameter attributes and test metadata. For AOT compatibility, consider using explicit data sources.")] +[RequiresDynamicCode("MatrixDataSource may process enum types dynamically")] +#endif public sealed class MatrixDataSourceAttribute : UntypedDataSourceGeneratorAttribute, IAccessesInstanceData { + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Matrix generation requires reflection")] + [RequiresDynamicCode("Matrix generation may process enum types dynamically")] + #endif protected override IEnumerable> GenerateDataSources(DataGeneratorMetadata dataGeneratorMetadata) { var parameterInformation = dataGeneratorMetadata @@ -84,8 +90,9 @@ private bool IsExcluded(object?[] exclusion, IEnumerable row) .ToArray(); } - [UnconditionalSuppressMessage("AOT", "IL2072:Target parameter argument does not satisfy DynamicallyAccessedMemberTypes requirements", - Justification = "Test parameter types are comprehensively preserved by the source generation system for matrix data scenarios")] + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Test parameter types accessed through reflection")] + #endif private IReadOnlyList GetAllArguments(DataGeneratorMetadata dataGeneratorMetadata, ParameterMetadata sourceGeneratedParameterInformation) { diff --git a/TUnit.Core/Attributes/TestData/MethodDataSourceAttribute.cs b/TUnit.Core/Attributes/TestData/MethodDataSourceAttribute.cs index a7e9c3d55e..7eda317f4f 100644 --- a/TUnit.Core/Attributes/TestData/MethodDataSourceAttribute.cs +++ b/TUnit.Core/Attributes/TestData/MethodDataSourceAttribute.cs @@ -52,8 +52,8 @@ public MethodDataSourceAttribute( MethodNameProvidingDataSource = methodNameProvidingDataSource; } - [UnconditionalSuppressMessage("AOT", "IL2072:UnrecognizedReflectionPattern", Justification = "Method data sources require runtime discovery and invocation of methods. The target type is determined dynamically from test metadata. For AOT scenarios, source generation should be used to pre-compile method references.")] - [UnconditionalSuppressMessage("AOT", "IL2075:UnrecognizedReflectionPattern", Justification = "GetType() is called on runtime objects from test class instances. The actual types cannot be statically determined. For AOT scenarios, source generation captures these types at compile time.")] + [UnconditionalSuppressMessage("Trimming", "IL2072", Justification = "Method data sources require runtime discovery. AOT users should use Factory property.")] + [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "Method data sources require runtime discovery. AOT users should use Factory property.")] public async IAsyncEnumerable>> GetDataRowsAsync(DataGeneratorMetadata dataGeneratorMetadata) { if (Factory != null) @@ -237,7 +237,9 @@ private static bool IsAsyncEnumerable([DynamicallyAccessedMembers(DynamicallyAcc i.GetGenericTypeDefinition() == typeof(IAsyncEnumerable<>)); } - [UnconditionalSuppressMessage("AOT", "IL2075:UnrecognizedReflectionPattern", Justification = "Reflection is required to convert IAsyncEnumerable from data source methods. The generic type T is determined at runtime from the data source's return type. For AOT scenarios, source generation should be used instead.")] + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Reflection usage is documented. AOT-safe path available via Factory property")] + [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "Reflection usage is documented. AOT-safe path available via Factory property")] + [UnconditionalSuppressMessage("AOT", "IL3050", Justification = "Dynamic code usage is documented. AOT-safe path available via Factory property")] private static async IAsyncEnumerable ConvertToAsyncEnumerable(object asyncEnumerable, [EnumeratorCancellation] CancellationToken cancellationToken = default) { var type = asyncEnumerable.GetType(); @@ -316,7 +318,9 @@ private static bool IsAsyncEnumerable([DynamicallyAccessedMembers(DynamicallyAcc } } - [UnconditionalSuppressMessage("AOT", "IL2075:UnrecognizedReflectionPattern", Justification = "Accessing Result property on Task requires reflection since T is not known at compile time. This is used to extract values from data source methods that return Task. For AOT, source generation pre-compiles these access patterns.")] + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Reflection usage is documented. AOT-safe path available via Factory property")] + [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "Reflection usage is documented. AOT-safe path available via Factory property")] + [UnconditionalSuppressMessage("AOT", "IL3050", Justification = "Dynamic code usage is documented. AOT-safe path available via Factory property")] private static object? GetTaskResult(Task task) { var taskType = task.GetType(); diff --git a/TUnit.Core/Attributes/TestData/UntypedDataSourceGeneratorAttribute.cs b/TUnit.Core/Attributes/TestData/UntypedDataSourceGeneratorAttribute.cs index 657f650d25..52c1b3b349 100644 --- a/TUnit.Core/Attributes/TestData/UntypedDataSourceGeneratorAttribute.cs +++ b/TUnit.Core/Attributes/TestData/UntypedDataSourceGeneratorAttribute.cs @@ -3,8 +3,10 @@ namespace TUnit.Core; [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Property, AllowMultiple = true)] +#if NET6_0_OR_GREATER [RequiresDynamicCode("UntypedDataSourceGeneratorAttribute requires dynamic code generation for runtime data source creation. Consider using strongly-typed AsyncDataSourceGeneratorAttribute overloads for AOT compatibility.")] [RequiresUnreferencedCode("UntypedDataSourceGeneratorAttribute may require unreferenced code for runtime data source creation. Consider using strongly-typed AsyncDataSourceGeneratorAttribute overloads for AOT compatibility.")] +#endif public abstract class UntypedDataSourceGeneratorAttribute : AsyncUntypedDataSourceGeneratorAttribute { protected abstract IEnumerable> GenerateDataSources(DataGeneratorMetadata dataGeneratorMetadata); diff --git a/TUnit.Core/Attributes/TestMetadata/SkipAttribute.cs b/TUnit.Core/Attributes/TestMetadata/SkipAttribute.cs index 0b5b7e6feb..f57dff0f0d 100644 --- a/TUnit.Core/Attributes/TestMetadata/SkipAttribute.cs +++ b/TUnit.Core/Attributes/TestMetadata/SkipAttribute.cs @@ -16,6 +16,9 @@ public SkipAttribute(string reason) public int Order => int.MinValue; /// +#if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Type comes from runtime objects that cannot be annotated")] +#endif public async ValueTask OnTestRegistered(TestRegisteredContext context) { if (await ShouldSkip(context)) diff --git a/TUnit.Core/DataGeneratorMetadataCreator.cs b/TUnit.Core/DataGeneratorMetadataCreator.cs index 79461e41c6..bcb0d6ef55 100644 --- a/TUnit.Core/DataGeneratorMetadataCreator.cs +++ b/TUnit.Core/DataGeneratorMetadataCreator.cs @@ -1,4 +1,4 @@ -using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.CodeAnalysis; using System.Reflection; using TUnit.Core.Enums; @@ -206,7 +206,9 @@ public static DataGeneratorMetadata CreateForPropertyInjection( /// /// Creates DataGeneratorMetadata for property injection using PropertyInfo (reflection mode). /// - [UnconditionalSuppressMessage("Trimming", "IL2072:'value' argument does not satisfy 'DynamicallyAccessedMemberTypes' in call to 'TUnit.Core.PropertyMetadata.Type.init'", Justification = "Property types are resolved through reflection")] + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Property types are resolved through reflection")] + #endif public static DataGeneratorMetadata CreateForPropertyInjection( PropertyInfo property, Type containingType, @@ -253,9 +255,9 @@ private static ParameterMetadata[] FilterOutCancellationToken(ParameterMetadata[ return parameters; } - [UnconditionalSuppressMessage("Trimming", "IL2070:'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors' in call to 'System.Type.GetConstructors(BindingFlags)'", Justification = "Constructor discovery needed for metadata")] - [UnconditionalSuppressMessage("Trimming", "IL2067:'value' argument does not satisfy 'DynamicallyAccessedMemberTypes' in call to 'TUnit.Core.ClassMetadata.Type.init'", Justification = "Type annotations are handled by reflection")] - [UnconditionalSuppressMessage("Trimming", "IL2072:'Type' argument does not satisfy 'DynamicallyAccessedMemberTypes' in call to 'TUnit.Core.ParameterMetadata.ParameterMetadata(Type)'", Justification = "Parameter types are known through reflection")] + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Class metadata creation requires reflection")] + #endif private static ClassMetadata GetClassMetadataForType(Type type) { return ClassMetadata.GetOrAdd(type.FullName ?? type.Name, () => diff --git a/TUnit.Core/DataSources/DataSourceProcessor.cs b/TUnit.Core/DataSources/DataSourceProcessor.cs index 8eaaf70375..98d8c131fd 100644 --- a/TUnit.Core/DataSources/DataSourceProcessor.cs +++ b/TUnit.Core/DataSources/DataSourceProcessor.cs @@ -1,4 +1,4 @@ -using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.CodeAnalysis; using System.Reflection; namespace TUnit.Core.DataSources; @@ -54,8 +54,10 @@ public static class DataSourceProcessor /// Processes a generator result item and extracts the data values /// This method uses reflection and is only suitable for reflection mode /// + #if NET6_0_OR_GREATER [RequiresUnreferencedCode("This method uses reflection to process data sources")] [RequiresDynamicCode("This method may create types at runtime")] + #endif public static async Task> ProcessGeneratorItemAsync(object? item) { var items = new List(); @@ -141,8 +143,10 @@ public static class DataSourceProcessor /// Resolves a value that might be wrapped in a Func or Task /// This method uses reflection and is only suitable for reflection mode /// + #if NET6_0_OR_GREATER [RequiresUnreferencedCode("This method uses reflection to resolve values")] [RequiresDynamicCode("This method may invoke methods dynamically")] + #endif public static async Task ResolveValueAsync(object? value) { if (value == null) @@ -209,7 +213,9 @@ public static class DataSourceProcessor /// Processes method data source results into a consistent format /// This method uses reflection for tuple processing and is not AOT-compatible /// + #if NET6_0_OR_GREATER [RequiresUnreferencedCode("This method uses reflection for tuple processing")] + #endif public static IEnumerable ProcessMethodDataSourceResult(object? result) { if (result == null) @@ -289,13 +295,17 @@ public static class DataSourceProcessor #region Tuple Processing Helpers (Reflection-based, not AOT-compatible) + #if NET6_0_OR_GREATER [RequiresUnreferencedCode("Tuple processing requires reflection")] + #endif private static bool TryProcessTupleArray(object result, Type resultType) { return resultType.IsArray && resultType.GetElementType()?.Name.StartsWith("ValueTuple") == true; } + #if NET6_0_OR_GREATER [RequiresUnreferencedCode("Tuple processing requires reflection")] + #endif private static IEnumerable ProcessTupleArray(object result, Type resultType) { var array = (Array)result; @@ -316,13 +326,17 @@ private static bool TryProcessTupleArray(object result, Type resultType) } } + #if NET6_0_OR_GREATER [RequiresUnreferencedCode("Tuple processing requires reflection")] + #endif private static bool TryProcessSingleTuple(object result, Type resultType) { return resultType.Name.StartsWith("ValueTuple"); } + #if NET6_0_OR_GREATER [RequiresUnreferencedCode("Tuple processing requires reflection")] + #endif private static object?[] ProcessSingleTuple(object result, Type resultType) { var fields = GetTupleFields(resultType); @@ -342,7 +356,9 @@ private static bool TryProcessSingleTuple(object result, Type resultType) /// /// Gets the Result property from a Task type with proper AOT attribution /// + #if NET6_0_OR_GREATER [RequiresUnreferencedCode("Property access requires reflection")] + #endif private static PropertyInfo? GetTaskResultProperty([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] Type taskType) { return taskType.GetProperty("Result"); @@ -351,7 +367,9 @@ private static bool TryProcessSingleTuple(object result, Type resultType) /// /// Gets the Invoke method from a delegate type with proper AOT attribution /// + #if NET6_0_OR_GREATER [RequiresUnreferencedCode("Method access requires reflection")] + #endif private static MethodInfo? GetDelegateInvokeMethod([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type delegateType) { return delegateType.GetMethod("Invoke"); @@ -360,11 +378,13 @@ private static bool TryProcessSingleTuple(object result, Type resultType) /// /// Gets fields from a tuple type with proper AOT attribution /// + #if NET6_0_OR_GREATER [RequiresUnreferencedCode("Field access requires reflection")] + #endif private static FieldInfo[] GetTupleFields([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] Type tupleType) { return tupleType.GetFields(); } #endregion -} \ No newline at end of file +} diff --git a/TUnit.Core/DynamicTestBuilderContext.cs b/TUnit.Core/DynamicTestBuilderContext.cs index 0c6c04bbbb..c827b7a99d 100644 --- a/TUnit.Core/DynamicTestBuilderContext.cs +++ b/TUnit.Core/DynamicTestBuilderContext.cs @@ -1,4 +1,4 @@ -using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.CodeAnalysis; namespace TUnit.Core; @@ -22,7 +22,9 @@ public DynamicTestBuilderContext(string filePath, int lineNumber) public IReadOnlyList Tests => _tests.AsReadOnly(); + #if NET6_0_OR_GREATER [RequiresDynamicCode("Adding dynamic tests requires reflection which is not supported in native AOT scenarios.")] + #endif public void AddTest(AbstractDynamicTest test) { // Set creator location if the test implements IDynamicTestCreatorLocation diff --git a/TUnit.Core/Executors/DedicatedThreadExecutor.cs b/TUnit.Core/Executors/DedicatedThreadExecutor.cs index b64267d4a9..9871446ada 100644 --- a/TUnit.Core/Executors/DedicatedThreadExecutor.cs +++ b/TUnit.Core/Executors/DedicatedThreadExecutor.cs @@ -377,6 +377,9 @@ public override SynchronizationContext CreateCopy() } } +#if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Type comes from runtime objects that cannot be annotated")] +#endif public ValueTask OnTestRegistered(TestRegisteredContext context) { context.SetParallelLimiter(new ProcessorCountParallelLimit()); diff --git a/TUnit.Core/Extensions/ReflectionExtensions.cs b/TUnit.Core/Extensions/ReflectionExtensions.cs index c83837571a..2094ddc1c1 100644 --- a/TUnit.Core/Extensions/ReflectionExtensions.cs +++ b/TUnit.Core/Extensions/ReflectionExtensions.cs @@ -109,6 +109,10 @@ public static T[] GetCustomAttributesSafe(this ICustomAttributeProvider provi #endif } + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Attribute instantiation uses reflection for .NET Framework compatibility")] + [RequiresDynamicCode("Activator.CreateInstance required for attribute instantiation")] + #endif private static Attribute[] GetAttributesViaCustomAttributeData(ICustomAttributeProvider provider, Type attributeType, bool inherit) { var attributes = new List(); @@ -171,12 +175,10 @@ private static Attribute[] GetAttributesViaCustomAttributeData(ICustomAttributeP return attributes.ToArray(); } - [UnconditionalSuppressMessage("AOT", "IL2072:Target type's member does not satisfy requirements", - Justification = "Attribute instantiation uses known constructor patterns. For AOT scenarios, use source-generated attribute discovery.")] - [UnconditionalSuppressMessage("AOT", "IL2075:Target parameter does not satisfy requirements", - Justification = "Attribute types with known constructors are preserved. This is a fallback for non-source-generated scenarios.")] - [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", - Justification = "Required for .NET Framework compatibility. AOT scenarios should use source-generated test discovery.")] + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Attribute instantiation uses reflection for .NET Framework compatibility")] + [RequiresDynamicCode("Activator.CreateInstance required for attribute instantiation")] + #endif private static Attribute? CreateAttributeInstance(CustomAttributeData attributeData) { var attributeType = attributeData.AttributeType; @@ -241,10 +243,13 @@ private static Attribute[] GetAttributesViaCustomAttributeData(ICustomAttributeP return attribute; } + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Runtime type property access for attribute argument extraction")] + #endif private static object? ExtractArgumentValue(CustomAttributeTypedArgument arg) { var value = arg.Value; - + // In .NET Framework, params arrays come as ReadOnlyCollection if (value != null && value.GetType().FullName?.Contains("CustomAttributeTypedArgument") == true) { @@ -269,15 +274,16 @@ private static Attribute[] GetAttributesViaCustomAttributeData(ICustomAttributeP return items.ToArray(); } } - + return value; } /// /// Gets the "Value" property from a type in an AOT-safer manner. /// - [UnconditionalSuppressMessage("Trimming", "IL2075:Target method return value does not satisfy annotation requirements", - Justification = "Value property access is used for unwrapping test data. For AOT scenarios, use strongly-typed data sources.")] + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Property access used for unwrapping test data")] + #endif private static PropertyInfo? GetValuePropertySafe([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] Type type) { return type.GetProperty("Value"); @@ -286,10 +292,9 @@ private static Attribute[] GetAttributesViaCustomAttributeData(ICustomAttributeP /// /// Gets the "Value" property from a runtime type. /// - [UnconditionalSuppressMessage("Trimming", "IL2072:Target parameter does not satisfy annotation requirements", - Justification = "Runtime type from GetType() cannot have static annotations. This is used for CustomAttributeTypedArgument unwrapping.")] - [UnconditionalSuppressMessage("Trimming", "IL2067:Target parameter does not satisfy annotation requirements", - Justification = "The type parameter comes from runtime GetType() which cannot be annotated. Used for attribute argument extraction.")] + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Runtime type property access for attribute argument extraction")] + #endif private static PropertyInfo? GetValuePropertyForType(Type type) { return GetValuePropertySafe(type); diff --git a/TUnit.Core/Extensions/TestContextExtensions.cs b/TUnit.Core/Extensions/TestContextExtensions.cs index d17875ecef..0e1e05984e 100644 --- a/TUnit.Core/Extensions/TestContextExtensions.cs +++ b/TUnit.Core/Extensions/TestContextExtensions.cs @@ -1,4 +1,4 @@ -using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.CodeAnalysis; using TUnit.Core.Helpers; using TUnit.Core.Interfaces; @@ -23,7 +23,10 @@ public static string GetClassTypeName(this TestContext context) return $"{context.TestDetails.ClassType.Name}({string.Join(", ", context.TestDetails.TestClassArguments.Select(a => ArgumentFormatter.Format(a, context.ArgumentDisplayFormatters)))})"; } + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Dynamic test metadata creation uses reflection")] [RequiresDynamicCode("Adding dynamic tests requires reflection which is not supported in native AOT scenarios.")] + #endif public static async Task AddDynamicTest<[DynamicallyAccessedMembers( DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors diff --git a/TUnit.Core/Helpers/CastHelper.cs b/TUnit.Core/Helpers/CastHelper.cs index d0ac03195f..14d7b5d1c5 100644 --- a/TUnit.Core/Helpers/CastHelper.cs +++ b/TUnit.Core/Helpers/CastHelper.cs @@ -7,10 +7,10 @@ namespace TUnit.Core.Helpers; public static class CastHelper { - [UnconditionalSuppressMessage("Trimming", "IL2072", - Justification = "Type conversion uses DynamicallyAccessedMembers for known conversion patterns. For AOT scenarios, use explicit type conversions.")] - [UnconditionalSuppressMessage("AOT", "IL3050", - Justification = "Reflection-based conversion is a fallback for runtime scenarios. AOT applications should use explicit conversions.")] + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Type conversion uses reflection for custom conversions")] + [RequiresDynamicCode("Dynamic type conversion may require runtime code generation")] + #endif public static T? Cast<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)] T>(object? value) { if (value is null) @@ -175,10 +175,10 @@ public static class CastHelper } } - [UnconditionalSuppressMessage("Trimming", "IL2072", - Justification = "Type conversion uses DynamicallyAccessedMembers for known conversion patterns. For AOT scenarios, use explicit type conversions.")] - [UnconditionalSuppressMessage("AOT", "IL3050", - Justification = "Reflection-based conversion is a fallback for runtime scenarios. AOT applications should use explicit conversions.")] + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Type conversion uses reflection for custom conversions")] + [RequiresDynamicCode("Dynamic type conversion may require runtime code generation")] + #endif public static object? Cast([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)] Type type, object? value) { if (value is null) @@ -372,8 +372,9 @@ private static bool HasCorrectInputType(Type baseType, MethodInfo mi) /// /// Gets the "Value" property from a type in an AOT-safer manner. /// - [UnconditionalSuppressMessage("Trimming", "IL2075:Target method return value does not satisfy annotation requirements", - Justification = "Value property access is used for unwrapping CustomAttributeTypedArgument. For AOT scenarios, use source-generated attribute discovery.")] + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Property access for CustomAttributeTypedArgument unwrapping")] + #endif private static PropertyInfo? GetValuePropertySafe([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] Type type) { return type.GetProperty("Value"); diff --git a/TUnit.Core/Helpers/DataSourceHelpers.cs b/TUnit.Core/Helpers/DataSourceHelpers.cs index 1312329cfa..f9a57ebffd 100644 --- a/TUnit.Core/Helpers/DataSourceHelpers.cs +++ b/TUnit.Core/Helpers/DataSourceHelpers.cs @@ -1,4 +1,4 @@ -using System.Collections; +using System.Collections; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; @@ -71,8 +71,6 @@ public static T InvokeIfFunc(object? value) /// /// AOT-compatible tuple unwrapping that handles common tuple types without reflection /// - [UnconditionalSuppressMessage("Trimming", "IL2091:Target generic argument does not satisfy 'DynamicallyAccessedMembersAttribute' in target method or type.", - Justification = "We handle specific known tuple types without reflection")] public static object?[] UnwrapTupleAot(object? value) { if (value == null) @@ -567,6 +565,10 @@ public static void RegisterTypeCreator(Func> /// Resolves a data source property value at runtime. /// This method handles all IDataSourceAttribute implementations generically. /// + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Property types are resolved through reflection")] + [RequiresDynamicCode("Data source resolution may require dynamic code generation")] + #endif public static async Task ResolveDataSourceForPropertyAsync([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)] Type containingType, string propertyName, MethodMetadata testInformation, string testSessionId) { // Use PropertyInjectionService to resolve the data source attribute @@ -583,7 +585,7 @@ public static void RegisterTypeCreator(Func> } var dataSourceAttribute = (IDataSourceAttribute)dataSourceAttributes[0]; - + // Create the data generator metadata with required fields var dataGeneratorMetadata = DataGeneratorMetadataCreator.CreateForPropertyInjection( propertyInfo, @@ -598,7 +600,7 @@ public static void RegisterTypeCreator(Func> // Generate the data source value using the attribute's GetDataRowsAsync method var dataRows = dataSourceAttribute.GetDataRowsAsync(dataGeneratorMetadata); - + // Get the first value from the async enumerable await foreach (var factory in dataRows) { @@ -606,10 +608,10 @@ public static void RegisterTypeCreator(Func> if (args is { Length: > 0 }) { var value = args[0]; - + // Initialize the value if it implements IAsyncInitializer await ObjectInitializer.InitializeAsync(value); - + return value; } } diff --git a/TUnit.Core/Helpers/GenericTypeHelper.cs b/TUnit.Core/Helpers/GenericTypeHelper.cs index 1648d186c1..563b80202b 100644 --- a/TUnit.Core/Helpers/GenericTypeHelper.cs +++ b/TUnit.Core/Helpers/GenericTypeHelper.cs @@ -1,4 +1,4 @@ -using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.CodeAnalysis; namespace TUnit.Core.Helpers; @@ -16,10 +16,9 @@ public static class GenericTypeHelper /// The constructed generic type /// Thrown when genericTypeDefinition is null /// Thrown when type arguments don't match the generic type definition - [UnconditionalSuppressMessage("AOT", "IL2055:UnrecognizedReflectionPattern", - Justification = "MakeGenericType is used as a fallback. AOT analyzer warns at compile time.")] - [UnconditionalSuppressMessage("AOT", "IL3050:RequiresDynamicCode", - Justification = "MakeGenericType is used as a fallback. AOT analyzer warns at compile time.")] + #if NET6_0_OR_GREATER + [RequiresDynamicCode("MakeGenericType requires runtime code generation")] + #endif public static Type MakeGenericTypeSafe(Type genericTypeDefinition, params Type[] typeArguments) { if (genericTypeDefinition == null) @@ -52,7 +51,11 @@ public static Type MakeGenericTypeSafe(Type genericTypeDefinition, params Type[] try { // Reflection mode - use MakeGenericType directly - return genericTypeDefinition.MakeGenericType(typeArguments); + // Method is already annotated with RequiresDynamicCode, suppressing IL2055 + [UnconditionalSuppressMessage("Trimming", "IL2055:MakeGenericType", Justification = "Method is already properly annotated with RequiresDynamicCode to indicate AOT incompatibility")] + static Type MakeGenericTypeUnsafe(Type genericType, Type[] args) => genericType.MakeGenericType(args); + + return MakeGenericTypeUnsafe(genericTypeDefinition, typeArguments); } catch (ArgumentException ex) { @@ -85,4 +88,4 @@ public static Type GetGenericTypeDefinition(Type type) return type.IsGenericTypeDefinition ? type : type.GetGenericTypeDefinition(); } -} \ No newline at end of file +} diff --git a/TUnit.Core/Helpers/TupleHelper.cs b/TUnit.Core/Helpers/TupleHelper.cs index cab89c794d..159b279d8b 100644 --- a/TUnit.Core/Helpers/TupleHelper.cs +++ b/TUnit.Core/Helpers/TupleHelper.cs @@ -1,4 +1,4 @@ -using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Runtime.CompilerServices; @@ -163,8 +163,9 @@ public static bool IsTupleArrayType(Type type) /// Expands an array of tuples into individual tuple elements for data source generation /// For example: [(1, "a"), (2, "b")] becomes individual items that each unwrap to [1, "a"] and [2, "b"] /// - [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2075:UnrecognizedReflectionPattern", - Justification = "Reflection is used as a fallback. AOT analyzer warns at compile time.")] + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Tuple expansion uses reflection as fallback")] + #endif public static IEnumerable ExpandTupleArray(object? value) { if (value == null) diff --git a/TUnit.Core/Hooks/LastTestInClassAdapter.cs b/TUnit.Core/Hooks/LastTestInClassAdapter.cs index 0435fc94a6..d328c2d245 100644 --- a/TUnit.Core/Hooks/LastTestInClassAdapter.cs +++ b/TUnit.Core/Hooks/LastTestInClassAdapter.cs @@ -3,7 +3,9 @@ namespace TUnit.Core.Hooks; -[UnconditionalSuppressMessage("Trimming", "IL2111:Method with parameters or return value with `DynamicallyAccessedMembersAttribute` is accessed via reflection. Trimmer can\'t guarantee availability of the requirements of the method.")] +#if NET6_0_OR_GREATER +[RequiresUnreferencedCode("Method with DynamicallyAccessedMembersAttribute accessed via reflection")] +#endif public class LastTestInClassAdapter(ILastTestInClassEventReceiver lastTestInClassEventReceiver, TestContext testContext) : IExecutableHook { public string Name => nameof(lastTestInClassEventReceiver.OnLastTestInClass); diff --git a/TUnit.Core/Interfaces/ITestRegisteredEventReceiver.cs b/TUnit.Core/Interfaces/ITestRegisteredEventReceiver.cs index f42ef301f0..fd429a4ac2 100644 --- a/TUnit.Core/Interfaces/ITestRegisteredEventReceiver.cs +++ b/TUnit.Core/Interfaces/ITestRegisteredEventReceiver.cs @@ -8,5 +8,8 @@ public interface ITestRegisteredEventReceiver : IEventReceiver /// /// Called when a test is registered /// + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Type comes from runtime objects that cannot be annotated")] + #endif ValueTask OnTestRegistered(TestRegisteredContext context); } diff --git a/TUnit.Core/Interfaces/ITestRegistry.cs b/TUnit.Core/Interfaces/ITestRegistry.cs index f35120875e..6c98b90363 100644 --- a/TUnit.Core/Interfaces/ITestRegistry.cs +++ b/TUnit.Core/Interfaces/ITestRegistry.cs @@ -1,4 +1,4 @@ -using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.CodeAnalysis; namespace TUnit.Core.Interfaces; @@ -14,7 +14,10 @@ public interface ITestRegistry /// The current test context /// The dynamic test instance to add /// A task that completes when the test has been queued for execution + #if NET6_0_OR_GREATER [RequiresDynamicCode("Adding dynamic tests requires runtime compilation and reflection which are not supported in native AOT scenarios.")] + [RequiresUnreferencedCode("Dynamic test metadata creation uses reflection")] + #endif Task AddDynamicTest<[DynamicallyAccessedMembers( DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors @@ -24,4 +27,4 @@ public interface ITestRegistry | DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)] T>(TestContext context, DynamicTest dynamicTest) where T : class; -} \ No newline at end of file +} diff --git a/TUnit.Core/PropertyInjection/ClassMetadataHelper.cs b/TUnit.Core/PropertyInjection/ClassMetadataHelper.cs index 7f49da4cf0..e43d50fa05 100644 --- a/TUnit.Core/PropertyInjection/ClassMetadataHelper.cs +++ b/TUnit.Core/PropertyInjection/ClassMetadataHelper.cs @@ -1,4 +1,4 @@ -using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.CodeAnalysis; using System.Reflection; namespace TUnit.Core.PropertyInjection; @@ -12,14 +12,16 @@ internal static class ClassMetadataHelper /// /// Gets or creates ClassMetadata for the specified type. /// - [UnconditionalSuppressMessage("Trimming", "IL2072", Justification = "Metadata creation")] + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Metadata creation requires reflection")] + #endif public static ClassMetadata GetOrCreateClassMetadata( [DynamicallyAccessedMembers( - DynamicallyAccessedMemberTypes.PublicConstructors | - DynamicallyAccessedMemberTypes.NonPublicConstructors | - DynamicallyAccessedMemberTypes.PublicMethods | - DynamicallyAccessedMemberTypes.NonPublicMethods | - DynamicallyAccessedMemberTypes.PublicProperties)] + DynamicallyAccessedMemberTypes.PublicConstructors | + DynamicallyAccessedMemberTypes.NonPublicConstructors | + DynamicallyAccessedMemberTypes.PublicMethods | + DynamicallyAccessedMemberTypes.NonPublicMethods | + DynamicallyAccessedMemberTypes.PublicProperties)] Type type) { return ClassMetadata.GetOrAdd(type.FullName ?? type.Name, () => @@ -52,4 +54,4 @@ public static ClassMetadata GetOrCreateClassMetadata( }; }); } -} \ No newline at end of file +} diff --git a/TUnit.Core/PropertyInjection/PropertyInjectionCache.cs b/TUnit.Core/PropertyInjection/PropertyInjectionCache.cs index 7cf13fcc91..161e647840 100644 --- a/TUnit.Core/PropertyInjection/PropertyInjectionCache.cs +++ b/TUnit.Core/PropertyInjection/PropertyInjectionCache.cs @@ -1,4 +1,4 @@ -using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.CodeAnalysis; using TUnit.Core.Data; namespace TUnit.Core.PropertyInjection; @@ -25,7 +25,9 @@ internal static class PropertyInjectionCache /// The plan builder will use source-generated metadata if available, /// otherwise falls back to reflection-based discovery. /// - [UnconditionalSuppressMessage("Trimming", "IL2067", Justification = "Type comes from runtime objects that cannot be annotated")] + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Type comes from runtime objects that cannot be annotated")] + #endif public static PropertyInjectionPlan GetOrCreatePlan(Type type) { return _injectionPlans.GetOrAdd(type, _ => PropertyInjectionPlanBuilder.Build(type)); @@ -34,7 +36,9 @@ public static PropertyInjectionPlan GetOrCreatePlan(Type type) /// /// Checks if a type has injectable properties using caching. /// - [UnconditionalSuppressMessage("Trimming", "IL2067", Justification = "Type comes from runtime objects that cannot be annotated")] + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Type comes from runtime objects that cannot be annotated")] + #endif public static bool HasInjectableProperties(Type type) { return _shouldInjectCache.GetOrAdd(type, t => diff --git a/TUnit.Core/PropertyInjection/PropertyInjectionPlanBuilder.cs b/TUnit.Core/PropertyInjection/PropertyInjectionPlanBuilder.cs index b020a2fa30..f0507f1418 100644 --- a/TUnit.Core/PropertyInjection/PropertyInjectionPlanBuilder.cs +++ b/TUnit.Core/PropertyInjection/PropertyInjectionPlanBuilder.cs @@ -1,4 +1,4 @@ -using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.CodeAnalysis; using System.Reflection; using TUnit.Core.Interfaces.SourceGenerator; @@ -14,7 +14,9 @@ internal static class PropertyInjectionPlanBuilder /// Creates an injection plan for source-generated mode. /// Walks the inheritance chain to include all injectable properties from base classes. /// - [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "BaseType reflection is required for inheritance support")] + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("BaseType reflection required for inheritance support")] + #endif public static PropertyInjectionPlan BuildSourceGeneratedPlan(Type type) { var allProperties = new List(); @@ -54,8 +56,9 @@ public static PropertyInjectionPlan BuildSourceGeneratedPlan(Type type) /// /// Creates an injection plan for reflection mode. /// - [UnconditionalSuppressMessage("Trimming", "IL2070", Justification = "Reflection mode support")] - [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "BaseType reflection is required for inheritance support")] + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Reflection mode requires runtime property discovery")] + #endif public static PropertyInjectionPlan BuildReflectionPlan(Type type) { var propertyDataSourcePairs = new List<(PropertyInfo property, IDataSourceAttribute dataSource)>(); @@ -103,7 +106,9 @@ public static PropertyInjectionPlan BuildReflectionPlan(Type type) /// /// Builds an injection plan based on the current execution mode. /// - [UnconditionalSuppressMessage("Trimming", "IL2070", Justification = "Handles both AOT and non-AOT scenarios")] + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Property injection plan building requires reflection")] + #endif public static PropertyInjectionPlan Build(Type type) { return SourceRegistrar.IsEnabled @@ -121,4 +126,4 @@ internal sealed class PropertyInjectionPlan public required PropertyInjectionMetadata[] SourceGeneratedProperties { get; init; } public required (PropertyInfo Property, IDataSourceAttribute DataSource)[] ReflectionProperties { get; init; } public required bool HasProperties { get; init; } -} \ No newline at end of file +} diff --git a/TUnit.Core/PropertyInjection/PropertySetterFactory.cs b/TUnit.Core/PropertyInjection/PropertySetterFactory.cs index 747542b7f7..78ee5fc005 100644 --- a/TUnit.Core/PropertyInjection/PropertySetterFactory.cs +++ b/TUnit.Core/PropertyInjection/PropertySetterFactory.cs @@ -1,4 +1,4 @@ -using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.CodeAnalysis; using System.Reflection; namespace TUnit.Core.PropertyInjection; @@ -12,6 +12,9 @@ internal static class PropertySetterFactory /// /// Creates a setter delegate for the given property. /// + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Backing field access for init-only properties requires reflection")] + #endif public static Action CreateSetter(PropertyInfo property) { if (property.CanWrite && property.SetMethod != null) @@ -43,8 +46,9 @@ internal static class PropertySetterFactory /// /// Gets the backing field for a property. /// - [UnconditionalSuppressMessage("Trimming", "IL2072", Justification = "Accessing backing fields for init-only and required properties in reflection mode. The compiler-generated field naming pattern (k__BackingField) is stable. For AOT, source generation creates direct setters.")] - [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "PropertyInfo.DeclaringType may not carry field annotations, but we only access compiler-generated backing fields which are preserved when the property is preserved. For AOT, use source-generated setters.")] + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Backing field access for init-only properties requires reflection")] + #endif private static FieldInfo? GetBackingField(PropertyInfo property) { var declaringType = property.DeclaringType; @@ -84,11 +88,13 @@ internal static class PropertySetterFactory /// /// Helper method to get field with proper trimming suppression. /// - [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "Safe field access when DynamicallyAccessedMembers annotations are present. The caller ensures the type has the required field preservation. This is only used for setting property backing fields in reflection mode.")] + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Field access for property backing fields requires reflection")] + #endif private static FieldInfo? GetFieldSafe( - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)] - Type type, - string name, + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)] + Type type, + string name, BindingFlags bindingFlags) { return type.GetField(name, bindingFlags); @@ -97,11 +103,13 @@ internal static class PropertySetterFactory /// /// Checks if a method is init-only. /// - [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "Checking for System.Runtime.CompilerServices.IsExternalInit modreq to identify init-only setters. This is a stable .NET runtime convention. For AOT, the source generator identifies init-only properties at compile time and generates appropriate setters.")] + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Checking for init-only setters requires reflection")] + #endif private static bool IsInitOnlyMethod(MethodInfo setMethod) { var methodType = setMethod.GetType(); var isInitOnlyProperty = methodType.GetProperty("IsInitOnly"); return isInitOnlyProperty != null && (bool)isInitOnlyProperty.GetValue(setMethod)!; } -} \ No newline at end of file +} diff --git a/TUnit.Core/PropertyInjection/TupleValueResolver.cs b/TUnit.Core/PropertyInjection/TupleValueResolver.cs index 20ce2445bf..f023fd09ac 100644 --- a/TUnit.Core/PropertyInjection/TupleValueResolver.cs +++ b/TUnit.Core/PropertyInjection/TupleValueResolver.cs @@ -1,4 +1,4 @@ -using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.CodeAnalysis; using TUnit.Core.Helpers; namespace TUnit.Core.PropertyInjection; @@ -15,10 +15,12 @@ internal static class TupleValueResolver /// The expected property type /// The arguments from the data source /// The resolved value, potentially a tuple - [UnconditionalSuppressMessage("Trimming", "IL2067", Justification = "Tuple types are created dynamically")] + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Tuple types are created dynamically")] + #endif public static object? ResolveTupleValue( - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] - Type propertyType, + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] + Type propertyType, object?[]? args) { if (args == null) @@ -59,4 +61,4 @@ internal static class TupleValueResolver // Single non-tuple argument for tuple property - shouldn't happen but handle gracefully return args.FirstOrDefault(); } -} \ No newline at end of file +} diff --git a/TUnit.Core/PropertySourceRegistry.cs b/TUnit.Core/PropertySourceRegistry.cs index 1ccd2770ed..65f024443e 100644 --- a/TUnit.Core/PropertySourceRegistry.cs +++ b/TUnit.Core/PropertySourceRegistry.cs @@ -1,4 +1,4 @@ -using System.Collections.Concurrent; +using System.Collections.Concurrent; using System.Diagnostics.CodeAnalysis; using TUnit.Core.Interfaces.SourceGenerator; @@ -78,7 +78,9 @@ public static void Register(Type type, IPropertySource source) /// /// Discovers injectable properties using reflection (legacy compatibility) /// - [UnconditionalSuppressMessage("Trimming", "IL2070", Justification = "Reflection discovery is used when source-generated metadata is not available. This supports dynamically loaded assemblies and runtime property injection. For AOT scenarios, the source generator pre-discovers all injectable properties.")] + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Reflection discovery is used when source-generated metadata is not available")] + #endif public static PropertyInjectionData[] DiscoverInjectableProperties([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)] Type type) { // First try source-generated data @@ -147,6 +149,9 @@ private static PropertyDataSource ConvertToPropertyDataSource(PropertyInjectionM /// /// Creates PropertyInjectionData from PropertyInfo (legacy compatibility) /// + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Backing field access for init-only properties requires reflection")] + #endif private static PropertyInjectionData CreatePropertyInjection(System.Reflection.PropertyInfo property) { var setter = CreatePropertySetter(property); @@ -164,6 +169,9 @@ private static PropertyInjectionData CreatePropertyInjection(System.Reflection.P /// /// Creates property setter (legacy compatibility) /// + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Backing field access for init-only properties requires reflection")] + #endif private static Action CreatePropertySetter(System.Reflection.PropertyInfo property) { if (property.CanWrite && property.SetMethod != null) @@ -195,8 +203,9 @@ private static PropertyInjectionData CreatePropertyInjection(System.Reflection.P /// /// Gets backing field for property (legacy compatibility) /// - [UnconditionalSuppressMessage("Trimming", "IL2072", Justification = "Backing field discovery is needed for init-only and required properties in reflection mode. The field naming convention (k__BackingField) is stable in the .NET runtime. For AOT, source generation captures these relationships at compile time.")] - [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "DeclaringType from PropertyInfo may not have field annotations, but we only access compiler-generated backing fields which follow predictable patterns. For AOT, use source-generated property setters.")] + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Backing field discovery needed for init-only properties in reflection mode")] + #endif private static System.Reflection.FieldInfo? GetBackingField(System.Reflection.PropertyInfo property) { var declaringType = property.DeclaringType; @@ -236,7 +245,9 @@ private static PropertyInjectionData CreatePropertyInjection(System.Reflection.P /// /// Helper method to get field with proper trimming suppression /// - [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "Field access is constrained to backing fields of properties with data source attributes. The DynamicallyAccessedMembers annotation ensures fields are preserved when this method is called. For AOT, source generation provides direct field access.")] + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Field access for property backing fields requires reflection")] + #endif private static System.Reflection.FieldInfo? GetFieldSafe([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)] Type type, string name, System.Reflection.BindingFlags bindingFlags) { return type.GetField(name, bindingFlags); @@ -245,11 +256,13 @@ private static PropertyInjectionData CreatePropertyInjection(System.Reflection.P /// /// Checks if method is init-only (legacy compatibility) /// - [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "Checking for IsExternalInit modreq is required to identify init-only setters in reflection mode. This uses stable .NET runtime conventions. For AOT, the source generator identifies init-only properties at compile time.")] + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Checking for init-only setters requires reflection")] + #endif private static bool IsInitOnlyMethod(System.Reflection.MethodInfo setMethod) { var methodType = setMethod.GetType(); var isInitOnlyProperty = methodType.GetProperty("IsInitOnly"); return isInitOnlyProperty != null && (bool)isInitOnlyProperty.GetValue(setMethod)!; } -} \ No newline at end of file +} diff --git a/TUnit.Core/Services/GenericTypeResolver.cs b/TUnit.Core/Services/GenericTypeResolver.cs index f1e56e3ed8..251177643e 100644 --- a/TUnit.Core/Services/GenericTypeResolver.cs +++ b/TUnit.Core/Services/GenericTypeResolver.cs @@ -1,4 +1,4 @@ -using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.CodeAnalysis; using System.Reflection; using TUnit.Core.Exceptions; using TUnit.Core.Interfaces; @@ -8,8 +8,10 @@ namespace TUnit.Core.Services; /// /// Implementation of generic type resolution for test methods and classes /// +#if NET6_0_OR_GREATER [RequiresDynamicCode("Generic type resolution requires runtime type generation")] [RequiresUnreferencedCode("Generic type resolution may access types not preserved by trimming")] +#endif public class GenericTypeResolver : IGenericTypeResolver { /// diff --git a/TUnit.Core/StaticPropertyReflectionInitializer.cs b/TUnit.Core/StaticPropertyReflectionInitializer.cs index aa31ab09ed..a9c60ad217 100644 --- a/TUnit.Core/StaticPropertyReflectionInitializer.cs +++ b/TUnit.Core/StaticPropertyReflectionInitializer.cs @@ -1,4 +1,4 @@ -using System.Collections.Concurrent; +using System.Collections.Concurrent; using System.Diagnostics.CodeAnalysis; using System.Reflection; using TUnit.Core.Enums; @@ -8,15 +8,9 @@ namespace TUnit.Core; /// /// Handles initialization of static properties with data sources in reflection mode /// -[UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access", - Justification = "Reflection mode requires dynamic access")] -[UnconditionalSuppressMessage("Trimming", "IL2067:Target parameter argument does not satisfy annotation requirements", - Justification = "Reflection mode requires dynamic access")] -[UnconditionalSuppressMessage("Trimming", "IL2070:'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicProperties'", - Justification = "Reflection mode requires dynamic access")] -[UnconditionalSuppressMessage("Trimming", "IL2075:'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicProperties'", - Justification = "Reflection mode requires dynamic access")] - +#if NET6_0_OR_GREATER +[RequiresUnreferencedCode("Reflection mode requires dynamic access for static property initialization")] +#endif public static class StaticPropertyReflectionInitializer { private static readonly ConcurrentDictionary _initializedTypes = new(); @@ -24,6 +18,9 @@ public static class StaticPropertyReflectionInitializer /// /// Initializes static properties with data sources for all loaded types /// +#if NET6_0_OR_GREATER + [RequiresDynamicCode("Data source initialization may require dynamic code generation")] +#endif public static async Task InitializeAllStaticPropertiesAsync() { var assemblies = AppDomain.CurrentDomain.GetAssemblies() @@ -52,6 +49,9 @@ public static async Task InitializeAllStaticPropertiesAsync() /// /// Initializes static properties with data sources for a specific type /// +#if NET6_0_OR_GREATER + [RequiresDynamicCode("Data source initialization may require dynamic code generation")] +#endif public static async Task InitializeStaticPropertiesForType(Type type) { // Skip if already initialized @@ -84,6 +84,9 @@ private static bool HasDataSourceAttribute(PropertyInfo property) .Any(attr => attr is IDataSourceAttribute); } +#if NET6_0_OR_GREATER + [RequiresDynamicCode("Data source initialization may require dynamic code generation")] +#endif private static async Task InitializeStaticProperty(Type type, PropertyInfo property) { if (property.GetCustomAttributes() diff --git a/TUnit.Core/TestContext.cs b/TUnit.Core/TestContext.cs index eb99818239..75248495a6 100644 --- a/TUnit.Core/TestContext.cs +++ b/TUnit.Core/TestContext.cs @@ -59,7 +59,6 @@ internal set public static string? OutputDirectory { - [UnconditionalSuppressMessage("SingleFile", "IL3000:Avoid accessing Assembly file path when publishing as a single file", Justification = "Dynamic code check implemented")] get { #if NET @@ -68,8 +67,14 @@ public static string? OutputDirectory return AppContext.BaseDirectory; } #endif - return Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location) - ?? Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + [UnconditionalSuppressMessage("SingleFile", "IL3000:Avoid accessing Assembly file path when publishing as a single file", Justification = "Dynamic code check implemented")] + string GetOutputDirectory() + { + return Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location) + ?? Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!; + } + + return GetOutputDirectory(); } } diff --git a/TUnit.Core/Tracking/ObjectTracker.cs b/TUnit.Core/Tracking/ObjectTracker.cs index 3626d9e890..e357dd3daa 100644 --- a/TUnit.Core/Tracking/ObjectTracker.cs +++ b/TUnit.Core/Tracking/ObjectTracker.cs @@ -1,4 +1,5 @@ -using System.Collections.Concurrent; +using System.Collections.Concurrent; +using System.Diagnostics.CodeAnalysis; using TUnit.Core.Helpers; namespace TUnit.Core.Tracking; @@ -11,6 +12,9 @@ internal class ObjectTracker(TrackableObjectGraphProvider trackableObjectGraphPr { private static readonly ConcurrentDictionary _trackedObjects = new(); + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Trackable object discovery uses reflection for property injection")] + #endif public void TrackObjects(TestContext testContext) { var alreadyTracked = testContext.TrackedObjects.SelectMany(x => x.Value).ToHashSet(); diff --git a/TUnit.Core/Tracking/TrackableObjectGraphProvider.cs b/TUnit.Core/Tracking/TrackableObjectGraphProvider.cs index 5e103f8086..9668371d53 100644 --- a/TUnit.Core/Tracking/TrackableObjectGraphProvider.cs +++ b/TUnit.Core/Tracking/TrackableObjectGraphProvider.cs @@ -1,4 +1,5 @@ -using System.Collections.Concurrent; +using System.Collections.Concurrent; +using System.Diagnostics.CodeAnalysis; using TUnit.Core.PropertyInjection; using TUnit.Core.StaticProperties; @@ -6,6 +7,9 @@ namespace TUnit.Core.Tracking; internal class TrackableObjectGraphProvider { + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Trackable object discovery uses reflection for property injection")] + #endif public ConcurrentDictionary> GetTrackableObjects(TestContext testContext) { var visitedObjects = testContext.TrackedObjects; @@ -63,6 +67,9 @@ public IEnumerable GetStaticPropertyTrackableObjects() } } + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Nested object tracking uses reflection for property discovery")] + #endif private void AddNestedTrackableObjects(object obj, ConcurrentDictionary> visitedObjects, int currentDepth) { var plan = PropertyInjectionCache.GetOrCreatePlan(obj.GetType()); diff --git a/TUnit.Engine/Building/Collectors/AotTestDataCollector.cs b/TUnit.Engine/Building/Collectors/AotTestDataCollector.cs index 90aa7ad316..f58dcca152 100644 --- a/TUnit.Engine/Building/Collectors/AotTestDataCollector.cs +++ b/TUnit.Engine/Building/Collectors/AotTestDataCollector.cs @@ -1,4 +1,4 @@ -using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; using System.Reflection; using System.Runtime.CompilerServices; @@ -15,6 +15,10 @@ namespace TUnit.Engine.Building.Collectors; /// internal sealed class AotTestDataCollector : ITestDataCollector { + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Assembly scanning uses dynamic type discovery and reflection")] + [RequiresDynamicCode("Generic test instantiation requires MakeGenericType")] + #endif public async Task> CollectTestsAsync(string testSessionId) { // Stream from all test sources @@ -31,6 +35,10 @@ public async Task> CollectTestsAsync(string testSessio return [..standardTestMetadatas, ..dynamicTestMetadatas]; } + #if NET6_0_OR_GREATER + [RequiresDynamicCode("Dynamic test conversion requires expression compilation")] + [RequiresUnreferencedCode("Method extraction from expressions uses reflection")] + #endif private async IAsyncEnumerable CollectDynamicTestsStreaming( string testSessionId, [EnumeratorCancellation] CancellationToken cancellationToken = default) @@ -76,8 +84,10 @@ private async IAsyncEnumerable CollectDynamicTestsStreaming( } } - [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", - Justification = "Dynamic tests are opt-in and users are warned via RequiresDynamicCode on the method they call")] + #if NET6_0_OR_GREATER + [RequiresDynamicCode("Dynamic test conversion requires expression compilation")] + [RequiresUnreferencedCode("Method extraction from expressions uses reflection")] + #endif private async IAsyncEnumerable ConvertDynamicTestToMetadataStreaming( AbstractDynamicTest abstractDynamicTest, [EnumeratorCancellation] CancellationToken cancellationToken = default) @@ -94,7 +104,10 @@ private async IAsyncEnumerable ConvertDynamicTestToMetadataStreami } } - [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("Dynamic tests require runtime compilation of lambda expressions and are not supported in native AOT scenarios.")] + #if NET6_0_OR_GREATER + [RequiresDynamicCode("Dynamic test metadata creation requires expression extraction and reflection")] + [RequiresUnreferencedCode("Method extraction from expressions uses reflection")] + #endif private Task CreateMetadataFromDynamicDiscoveryResult(DynamicDiscoveryResult result) { if (result.TestClassType == null || result.TestMethod == null) @@ -124,9 +137,7 @@ private Task CreateMetadataFromDynamicDiscoveryResult(DynamicDisco return Task.FromResult(new AotDynamicTestMetadata(result) { TestName = testName, -#pragma warning disable IL2072 TestClassType = result.TestClassType, -#pragma warning restore IL2072 TestMethodName = methodInfo.Name, Dependencies = result.Attributes.OfType().Select(a => a.ToTestDependency()).ToArray(), DataSources = [], // Dynamic tests don't use data sources in the same way @@ -141,28 +152,14 @@ private Task CreateMetadataFromDynamicDiscoveryResult(DynamicDisco GenericMethodInfo = null, GenericMethodTypeArguments = null, AttributeFactory = () => result.Attributes.ToArray(), -#pragma warning disable IL2072 PropertyInjections = PropertySourceRegistry.DiscoverInjectableProperties(result.TestClassType) -#pragma warning restore IL2072 }); } - [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("Dynamic test instance creation requires Activator.CreateInstance and MakeGenericType which are not supported in native AOT scenarios.")] - [UnconditionalSuppressMessage("Trimming", - "IL2070:'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors' in call to 'System.Type.GetConstructors()'", - Justification = "AOT mode uses source-generated factories")] - [UnconditionalSuppressMessage("Trimming", - "IL2067:Target parameter does not satisfy annotation requirements", - Justification = "AOT mode uses source-generated factories")] - [UnconditionalSuppressMessage("Trimming", - "IL2072:Target method return value does not have matching annotations", - Justification = "AOT mode uses source-generated factories")] - [UnconditionalSuppressMessage("Trimming", - "IL2055:Call to 'MakeGenericType' can not be statically analyzed", - Justification = "Dynamic tests may use generic types")] - [UnconditionalSuppressMessage("AOT", - "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling", - Justification = "Dynamic tests require dynamic code generation")] + #if NET6_0_OR_GREATER + [RequiresDynamicCode("Dynamic instance creation uses Activator.CreateInstance and MakeGenericType")] + [RequiresUnreferencedCode("Dynamic type instantiation requires access to constructors")] + #endif private static Func? CreateAotDynamicInstanceFactory(Type testClass, object?[]? predefinedClassArgs) { // Check if we have predefined args to use as defaults @@ -191,7 +188,10 @@ private Task CreateMetadataFromDynamicDiscoveryResult(DynamicDisco }; } - [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("Dynamic test invocation requires LambdaExpression.Compile() which is not supported in native AOT scenarios.")] + #if NET6_0_OR_GREATER + [RequiresDynamicCode("Dynamic test invocation requires LambdaExpression.Compile")] + [RequiresUnreferencedCode("Expression compilation and MethodInfo.Invoke use reflection")] + #endif private static Func CreateAotDynamicTestInvoker(DynamicDiscoveryResult result) { return async (instance, args) => @@ -236,8 +236,9 @@ private Task CreateMetadataFromDynamicDiscoveryResult(DynamicDisco }; } - [UnconditionalSuppressMessage("Trimming", "IL2072:Target parameter argument does not satisfy \'DynamicallyAccessedMembersAttribute\' in call to target method. The return value of the source method does not have matching annotations.", - Justification = "We won't instantiate this since it failed")] + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Failed metadata creation accesses Type.Name and assembly info")] + #endif private static TestMetadata CreateFailedTestMetadataForDynamicSource(IDynamicTestSource source, Exception ex) { var testName = $"[DYNAMIC SOURCE FAILED] {source.GetType().Name}"; @@ -257,12 +258,9 @@ private static TestMetadata CreateFailedTestMetadataForDynamicSource(IDynamicTes }; } - [UnconditionalSuppressMessage("Trimming", - "IL2067:Target parameter does not satisfy annotation requirements", - Justification = "Dynamic test metadata creation")] - [UnconditionalSuppressMessage("Trimming", - "IL2072:Target method return value does not have matching annotations", - Justification = "Dynamic test metadata creation")] + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Dummy metadata creation accesses type and assembly information")] + #endif private static MethodMetadata CreateDummyMethodMetadata(Type type, string methodName) { return new MethodMetadata diff --git a/TUnit.Engine/Building/Interfaces/ITestBuilder.cs b/TUnit.Engine/Building/Interfaces/ITestBuilder.cs index 3b9fb1dc90..2bdc233b15 100644 --- a/TUnit.Engine/Building/Interfaces/ITestBuilder.cs +++ b/TUnit.Engine/Building/Interfaces/ITestBuilder.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using TUnit.Core; namespace TUnit.Engine.Building.Interfaces; @@ -14,6 +15,10 @@ internal interface ITestBuilder /// The test data /// /// An executable test ready for execution + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Hook discovery uses reflection on methods and attributes")] + [RequiresDynamicCode("Hook registration may involve dynamic delegate creation")] + #endif Task BuildTestAsync(TestMetadata metadata, TestBuilder.TestData testData, TestBuilderContext testBuilderContext); /// @@ -22,6 +27,10 @@ internal interface ITestBuilder /// /// The test metadata with DataCombinationGenerator /// Collection of executable tests for all data combinations + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Hook discovery uses reflection on methods and attributes")] + [RequiresDynamicCode("Hook registration may involve dynamic delegate creation")] + #endif Task> BuildTestsFromMetadataAsync(TestMetadata metadata); /// @@ -30,6 +39,10 @@ internal interface ITestBuilder /// The test metadata with DataCombinationGenerator /// Cancellation token /// Stream of executable tests for all data combinations + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces and reflection")] + [RequiresDynamicCode("Hook registration may involve dynamic delegate creation")] + #endif IAsyncEnumerable BuildTestsStreamingAsync( TestMetadata metadata, CancellationToken cancellationToken = default); diff --git a/TUnit.Engine/Building/Interfaces/ITestDataCollector.cs b/TUnit.Engine/Building/Interfaces/ITestDataCollector.cs index 77e7f28f43..4a8faa1d9c 100644 --- a/TUnit.Engine/Building/Interfaces/ITestDataCollector.cs +++ b/TUnit.Engine/Building/Interfaces/ITestDataCollector.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using TUnit.Core; namespace TUnit.Engine.Building.Interfaces; @@ -11,5 +12,9 @@ internal interface ITestDataCollector /// Collects all test metadata from the configured source /// /// Collection of test metadata ready for processing + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Assembly scanning uses dynamic type discovery and reflection")] + [RequiresDynamicCode("Generic test instantiation requires MakeGenericType")] + #endif Task> CollectTestsAsync(string testSessionId); } diff --git a/TUnit.Engine/Building/ReflectionMetadataBuilder.cs b/TUnit.Engine/Building/ReflectionMetadataBuilder.cs index 178c9f19f7..7bc5ac0edf 100644 --- a/TUnit.Engine/Building/ReflectionMetadataBuilder.cs +++ b/TUnit.Engine/Building/ReflectionMetadataBuilder.cs @@ -9,10 +9,9 @@ internal static class ReflectionMetadataBuilder /// /// Creates method metadata from reflection info with proper ReflectionInfo populated /// - [UnconditionalSuppressMessage("Trimming", "IL2067:Target parameter argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method", - Justification = "Parameter types discovered from MethodInfo.GetParameters() cannot be statically analyzed. Used for reflection-based and dynamic test discovery.")] - [UnconditionalSuppressMessage("Trimming", "IL2072:Target parameter argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The return value of the source method does not have matching annotations.", - Justification = "ParameterInfo.ParameterType cannot be annotated. For AOT scenarios, source-generated metadata is preferred.")] +#if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Method metadata creation uses reflection on parameters and types")] +#endif public static MethodMetadata CreateMethodMetadata( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors @@ -41,8 +40,9 @@ private static TypeReference CreateTypeReference(Type type) return TypeReference.CreateConcrete(type.AssemblyQualifiedName ?? type.FullName ?? type.Name); } - [UnconditionalSuppressMessage("Trimming", "IL2067:Target parameter argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method", - Justification = "ParameterMetadata constructor requires annotated types. Callers ensure types have required members preserved.")] +#if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Parameter metadata creation uses reflection")] +#endif private static ParameterMetadata CreateParameterMetadata( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.PublicMethods @@ -59,8 +59,9 @@ private static ParameterMetadata CreateParameterMetadata( }; } - [UnconditionalSuppressMessage("Trimming", "IL2072:Target parameter argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The return value of the source method does not have matching annotations.", - Justification = "Constructor parameter types from ParameterInfo cannot be annotated. Used for test class metadata creation.")] +#if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Class metadata creation uses reflection on constructors")] +#endif private static ClassMetadata CreateClassMetadata([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors | DynamicallyAccessedMemberTypes.PublicMethods diff --git a/TUnit.Engine/Building/TestBuilder.cs b/TUnit.Engine/Building/TestBuilder.cs index 1ef4a419c8..931370f751 100644 --- a/TUnit.Engine/Building/TestBuilder.cs +++ b/TUnit.Engine/Building/TestBuilder.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using TUnit.Core; using TUnit.Core.Enums; using TUnit.Core.Exceptions; @@ -103,6 +104,10 @@ private async Task CreateInstance(TestMetadata metadata, Type[] resolved } } + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Hook discovery uses reflection on methods and attributes")] + [RequiresDynamicCode("Hook registration may involve dynamic delegate creation")] + #endif public async Task> BuildTestsFromMetadataAsync(TestMetadata metadata) { var tests = new List(); @@ -448,8 +453,9 @@ private static Type[] TryInferClassGenericsFromMethodData(TestMetadata metadata, return resolvedTypes; } - [System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessage("AOT", "IL2075:UnrecognizedReflectionPattern", - Justification = "Data sources require reflection to get method and parameter info")] +#if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Generic type inference uses reflection on data sources and parameters")] +#endif private static Type[] TryInferClassGenericsFromDataSources(TestMetadata metadata) { var genericClassType = metadata.TestClassType; @@ -600,6 +606,9 @@ private static Type[] TryInferClassGenericsFromDataSources(TestMetadata metadata return resolvedTypes; } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Type comes from runtime objects that cannot be annotated")] + #endif private async Task GetDataSourcesAsync(IDataSourceAttribute[] dataSources) { if (dataSources.Length == 0) @@ -620,6 +629,9 @@ private async Task GetDataSourcesAsync(IDataSourceAttrib /// Ensures a data source is initialized before use and returns data rows. /// This centralizes the initialization logic for all data source usage. /// + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Type comes from runtime objects that cannot be annotated")] + #endif private async IAsyncEnumerable>> GetInitializedDataRowsAsync( IDataSourceAttribute dataSource, DataGeneratorMetadata dataGeneratorMetadata) @@ -639,6 +651,10 @@ private async Task GetDataSourcesAsync(IDataSourceAttrib } } + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Hook discovery uses reflection on methods and attributes")] + [RequiresDynamicCode("Hook registration may involve dynamic delegate creation")] + #endif public async Task BuildTestAsync(TestMetadata metadata, TestData testData, TestBuilderContext testBuilderContext) { // Discover instance hooks for closed generic types in reflection mode @@ -705,6 +721,9 @@ public async Task BuildTestAsync(TestMetadata metadata, } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Type comes from runtime objects that cannot be annotated")] + #endif private async ValueTask CreateTestContextAsync(string testId, TestMetadata metadata, TestData testData, TestBuilderContext testBuilderContext) { // Use attributes from context if available, or create new ones @@ -747,6 +766,9 @@ private async ValueTask CreateTestContextAsync(string testId, TestM } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces and reflection")] + #endif private async Task InvokeDiscoveryEventReceiversAsync(TestContext context) { var discoveredContext = new DiscoveredTestContext( @@ -758,11 +780,17 @@ private async Task InvokeDiscoveryEventReceiversAsync(TestContext context) } } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces and reflection")] + #endif private async Task CreateFailedTestForDataGenerationError(TestMetadata metadata, Exception exception) { return await CreateFailedTestForDataGenerationError(metadata, exception, new TestDataCombination()); } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces and reflection")] + #endif private async Task CreateFailedTestForDataGenerationError(TestMetadata metadata, Exception exception, TestDataCombination combination) { var testId = TestIdentifierService.GenerateFailedTestId(metadata, combination); @@ -782,6 +810,9 @@ private async Task CreateFailedTestForDataGenerationErro }; } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Type comes from runtime objects that cannot be annotated")] + #endif private async Task CreateFailedTestDetails(TestMetadata metadata, string testId) { return new TestDetails @@ -802,6 +833,9 @@ private async Task CreateFailedTestDetails(TestMetadata metadata, s }; } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Type comes from runtime objects that cannot be annotated")] + #endif private async Task InitializeAttributesAsync(Attribute[] attributes) { // Initialize any attributes that need property injection or implement IAsyncInitializer @@ -836,12 +870,18 @@ private TestContext CreateFailedTestContext(TestMetadata metadata, TestDetails t + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces and reflection")] + #endif private async Task CreateFailedTestForInstanceDataSourceError(TestMetadata metadata, Exception exception) { var message = $"Failed to create instance for method data source expansion: {exception.Message}"; return await CreateFailedTestForDataGenerationError(metadata, exception); } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces and reflection")] + #endif private async Task CreateFailedTestForClassDataSourceCircularDependency(TestMetadata metadata) { var instanceClassDataSources = metadata.ClassDataSources @@ -1008,8 +1048,9 @@ private static bool IsDataCompatibleWithExpectedTypes(TestMetadata metadata, obj return null; } - [System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessage("AOT", "IL2070:UnrecognizedReflectionPattern", - Justification = "Type checking at runtime is required for data source filtering")] +#if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Type compatibility checking uses reflection")] +#endif private static bool IsTypeCompatible(Type actualType, Type expectedType) { // Direct match @@ -1087,6 +1128,10 @@ internal class TestData public Type[] ResolvedMethodGenericArguments { get; set; } = Type.EmptyTypes; } + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces and reflection")] + [RequiresDynamicCode("Hook registration may involve dynamic delegate creation")] + #endif public async IAsyncEnumerable BuildTestsStreamingAsync( TestMetadata metadata, [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken = default) @@ -1222,6 +1267,9 @@ public async IAsyncEnumerable BuildTestsStreamingAsync( } } + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Generic type inference uses reflection on data sources and parameters")] + #endif private Task CreateInstanceForMethodDataSources( TestMetadata metadata, int classDataAttributeIndex, int classDataLoopIndex, object?[] classData) { @@ -1264,6 +1312,10 @@ public async IAsyncEnumerable BuildTestsStreamingAsync( } } + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Hook discovery uses reflection on methods and attributes")] + [RequiresDynamicCode("Hook registration may involve dynamic delegate creation")] + #endif private async Task BuildSingleTestAsync( TestMetadata metadata, Func> classDataFactory, diff --git a/TUnit.Engine/Building/TestBuilderPipeline.cs b/TUnit.Engine/Building/TestBuilderPipeline.cs index 39d0307a2c..503f477860 100644 --- a/TUnit.Engine/Building/TestBuilderPipeline.cs +++ b/TUnit.Engine/Building/TestBuilderPipeline.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using EnumerableAsyncProcessor.Extensions; using TUnit.Core; using TUnit.Core.Interfaces; @@ -54,6 +55,10 @@ private TestBuilderContext CreateTestBuilderContext(TestMetadata metadata) return testBuilderContext; } + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Assembly scanning uses dynamic type discovery and reflection")] + [RequiresDynamicCode("Generic test instantiation requires MakeGenericType")] + #endif public async Task> BuildTestsAsync(string testSessionId) { var collectedMetadata = await _dataCollector.CollectTestsAsync(testSessionId).ConfigureAwait(false); @@ -64,6 +69,10 @@ public async Task> BuildTestsAsync(string te /// /// Streaming version that yields tests as they're built without buffering /// + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Assembly scanning uses dynamic type discovery and reflection")] + [RequiresDynamicCode("Generic test instantiation requires MakeGenericType")] + #endif public async Task> BuildTestsStreamingAsync( string testSessionId, CancellationToken cancellationToken = default) @@ -86,6 +95,10 @@ private async IAsyncEnumerable ToAsyncEnumerable(IEnumerable> BuildTestsFromMetadataAsync(IEnumerable testMetadata) { var testGroups = await testMetadata.SelectAsync(async metadata => @@ -111,6 +124,9 @@ public async Task> BuildTestsFromMetadataAsy return testGroups.SelectMany(x => x); } + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces and reflection")] + #endif private async Task GenerateDynamicTests(TestMetadata metadata) { // Get attributes first @@ -200,6 +216,10 @@ private async Task GenerateDynamicTests(TestMetadata m /// /// Build tests from a single metadata item, yielding them as they're created /// + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Hook discovery uses reflection on methods and attributes")] + [RequiresDynamicCode("Hook registration may involve dynamic delegate creation")] + #endif private async IAsyncEnumerable BuildTestsFromSingleMetadataAsync(TestMetadata metadata) { TestMetadata resolvedMetadata; @@ -439,6 +459,9 @@ private AbstractExecutableTest CreateFailedTestForGenericResolutionError(TestMet }; } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces and reflection")] + #endif private async Task InvokeDiscoveryEventReceiversAsync(TestContext context) { var discoveredContext = new DiscoveredTestContext( diff --git a/TUnit.Engine/Building/TestDataCollectorFactory.cs b/TUnit.Engine/Building/TestDataCollectorFactory.cs index 8ae93a709d..3f60edd961 100644 --- a/TUnit.Engine/Building/TestDataCollectorFactory.cs +++ b/TUnit.Engine/Building/TestDataCollectorFactory.cs @@ -41,6 +41,10 @@ public static ITestDataCollector Create(bool? useSourceGeneration = null, Assemb /// Attempts AOT mode first, falls back to reflection if no source-generated tests found. /// This provides automatic mode selection for optimal performance and compatibility. /// + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Assembly scanning uses dynamic type discovery and reflection")] + [RequiresDynamicCode("Generic test instantiation requires MakeGenericType")] + #endif public static async Task CreateAutoDetectAsync(string testSessionId, Assembly[]? assembliesToScan = null) { // Try AOT mode first (check if any tests were registered) diff --git a/TUnit.Engine/Discovery/AsyncDataSourceHelper.cs b/TUnit.Engine/Discovery/AsyncDataSourceHelper.cs index 110bcee7f3..2d04375edb 100644 --- a/TUnit.Engine/Discovery/AsyncDataSourceHelper.cs +++ b/TUnit.Engine/Discovery/AsyncDataSourceHelper.cs @@ -7,6 +7,9 @@ namespace TUnit.Engine.Discovery; internal static class AsyncDataSourceHelper { /// Processes async generator items without evaluating them during discovery +#if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Typed placeholder creation uses reflection on generic types")] +#endif public static List ProcessAsyncGeneratorItemsForDiscovery(object? item) { var items = new List(); @@ -109,7 +112,9 @@ private static bool IsGenericFuncTask(object? item, out Type? resultType) return returnType; } - [UnconditionalSuppressMessage("Trimming", "IL2075:Target method return value does not satisfy annotation requirements", Justification = "Reflection mode requires dynamic access")] +#if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Typed placeholder creation uses reflection on generic types")] +#endif private static AsyncDataSourcePlaceholder CreateTypedPlaceholder(object item, Type? resultType) { // Create a wrapper that preserves the typed factory diff --git a/TUnit.Engine/Discovery/ConstructorHelper.cs b/TUnit.Engine/Discovery/ConstructorHelper.cs index 04711440e0..89da30e5dd 100644 --- a/TUnit.Engine/Discovery/ConstructorHelper.cs +++ b/TUnit.Engine/Discovery/ConstructorHelper.cs @@ -12,8 +12,9 @@ internal static class ConstructorHelper /// /// Finds a suitable constructor for a test class, preferring ones marked with [TestConstructor] /// - [UnconditionalSuppressMessage("Trimming", "IL2070:Target method does not satisfy annotation requirements", - Justification = "Constructor discovery is required for test instantiation. AOT scenarios should use source-generated test metadata.")] +#if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Constructor discovery requires reflection on constructors and attributes")] +#endif public static ConstructorInfo? FindSuitableConstructor( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type testClass, Attribute[] classAttributes) @@ -35,12 +36,9 @@ internal static class ConstructorHelper /// /// Creates an instance of a test class with proper constructor parameter handling /// - [UnconditionalSuppressMessage("Trimming", "IL2067:Target type's member does not satisfy annotation requirements", - Justification = "Test class instantiation requires constructor access. AOT scenarios should use source-generated factories.")] - [UnconditionalSuppressMessage("Trimming", "IL2070:Target method does not satisfy annotation requirements", - Justification = "Dynamic property initialization is a fallback. AOT scenarios should use compile-time initialization.")] - [UnconditionalSuppressMessage("Trimming", "IL2072:Target method return value does not satisfy annotation requirements", - Justification = "Type flow in reflection mode cannot be statically analyzed. Use source generation for AOT.")] +#if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Test instance creation uses ConstructorInfo.Invoke and Activator.CreateInstance")] +#endif public static object? CreateTestClassInstanceWithConstructor( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type testClass, ConstructorInfo? constructor, @@ -115,8 +113,9 @@ internal static class ConstructorHelper /// /// Checks if a type has required properties that need initialization /// - [UnconditionalSuppressMessage("Trimming", "IL2070:Target method does not satisfy annotation requirements", - Justification = "Required property checking uses reflection. For AOT, ensure test classes don't use required properties or use source generation.")] +#if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Required property detection uses reflection on properties and attributes")] +#endif public static bool HasRequiredProperties([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] Type type) { // Check if the type itself has RequiredMemberAttribute (indicates it has required properties) @@ -133,10 +132,9 @@ public static bool HasRequiredProperties([DynamicallyAccessedMembers(Dynamically /// /// Tries to initialize required properties on an instance /// - [UnconditionalSuppressMessage("Trimming", "IL2070:Target method does not satisfy annotation requirements", - Justification = "Required property initialization needs reflection. AOT scenarios should initialize properties in constructors.")] - [UnconditionalSuppressMessage("Trimming", "IL2072:Target method return value does not satisfy annotation requirements", - Justification = "Property type information flows through reflection. Use explicit property initialization for AOT.")] +#if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Property initialization uses reflection on properties and their types")] +#endif public static void InitializeRequiredProperties( object instance, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] Type type) @@ -231,8 +229,9 @@ public static void InitializeRequiredProperties( /// /// AOT-safe wrapper for Activator.CreateInstance with proper attribution /// - [UnconditionalSuppressMessage("Trimming", "IL2067:Target parameter does not satisfy annotation requirements", - Justification = "Parameterless constructor invocation with preserved type. For full AOT support, use source-generated factories.")] +#if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Activator.CreateInstance requires reflection")] +#endif private static object? CreateInstanceSafely([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type type) { return Activator.CreateInstance(type); diff --git a/TUnit.Engine/Discovery/GenericTestHelper.cs b/TUnit.Engine/Discovery/GenericTestHelper.cs index 8661373090..6162dcf532 100644 --- a/TUnit.Engine/Discovery/GenericTestHelper.cs +++ b/TUnit.Engine/Discovery/GenericTestHelper.cs @@ -11,8 +11,9 @@ internal static class GenericTestHelper /// /// Safely creates an instance of a test class, handling generic types /// - [UnconditionalSuppressMessage("Trimming", "IL2067:Target type's member does not satisfy annotation requirements", Justification = "Reflection mode requires dynamic access")] - [UnconditionalSuppressMessage("Trimming", "IL2070:Target method does not satisfy annotation requirements", Justification = "Reflection mode requires dynamic access")] +#if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Test instance creation uses reflection on constructors")] +#endif public static object? CreateTestClassInstance([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors | DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicProperties)] Type testClass) { try @@ -53,9 +54,9 @@ internal static class GenericTestHelper /// /// Gets the method on the actual implementation class, handling inherited generic methods /// - [UnconditionalSuppressMessage("Trimming", "IL2070:Target method does not satisfy annotation requirements", Justification = "Reflection mode requires dynamic access")] - [UnconditionalSuppressMessage("Trimming", "IL2075:Target method return value does not satisfy annotation requirements", Justification = "Reflection mode requires dynamic access")] - [UnconditionalSuppressMessage("Trimming", "IL2072:Target parameter argument does not satisfy annotation requirements", Justification = "BaseType access in reflection mode requires dynamic access")] +#if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Method lookup traverses type hierarchy using reflection")] +#endif public static MethodInfo? GetMethodOnImplementationType([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)] Type implementationType, string methodName, Type[] parameterTypes) { // First try exact match on implementation type @@ -163,7 +164,9 @@ public static bool IsInheritedFromGenericBase(MethodInfo method) /// /// Helper method to get method from type with proper AOT attribution /// - [UnconditionalSuppressMessage("Trimming", "IL2070:Target method does not satisfy annotation requirements", Justification = "Reflection mode requires dynamic access")] +#if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Method lookup uses Type.GetMethod")] +#endif private static MethodInfo? GetMethodFromType( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)] Type type, string methodName, diff --git a/TUnit.Engine/Discovery/ReflectionGenericTypeResolver.cs b/TUnit.Engine/Discovery/ReflectionGenericTypeResolver.cs index 3f011dd1fa..02dd343654 100644 --- a/TUnit.Engine/Discovery/ReflectionGenericTypeResolver.cs +++ b/TUnit.Engine/Discovery/ReflectionGenericTypeResolver.cs @@ -1,4 +1,4 @@ -using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Runtime.CompilerServices; using TUnit.Core; @@ -8,18 +8,14 @@ namespace TUnit.Engine.Discovery; /// /// Handles generic type resolution and instantiation for reflection-based test discovery /// -[UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "Reflection mode cannot support trimming")] -[UnconditionalSuppressMessage("Trimming", "IL2055:Call to 'System.Type.MakeGenericType' can not be statically analyzed", Justification = "Reflection mode requires dynamic access")] -[UnconditionalSuppressMessage("Trimming", "IL2065:Value passed to implicit 'this' parameter of method can not be statically determined and may not meet 'DynamicallyAccessedMembersAttribute' requirements", Justification = "Reflection mode requires dynamic access")] -[UnconditionalSuppressMessage("Trimming", "IL2067:Target parameter does not satisfy annotation requirements", Justification = "Reflection mode requires dynamic access")] -[UnconditionalSuppressMessage("Trimming", "IL2070:Target method does not satisfy annotation requirements", Justification = "Reflection mode requires dynamic access")] -[UnconditionalSuppressMessage("Trimming", "IL2075:'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethods(BindingFlags)'", Justification = "Reflection mode requires dynamic access")] -[UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "Reflection mode cannot support AOT")] internal static class ReflectionGenericTypeResolver { /// /// Determines generic type arguments from data row values /// +#if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Generic type argument determination uses reflection")] +#endif public static Type[]? DetermineGenericTypeArguments(Type genericTypeDefinition, object?[] dataRow) { #if NET @@ -82,6 +78,9 @@ internal static class ReflectionGenericTypeResolver /// /// Extracts generic type information including constraints /// +#if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Generic type info extraction uses reflection on type parameters")] +#endif public static GenericTypeInfo? ExtractGenericTypeInfo(Type testClass) { // Handle both generic type definitions and constructed generic types @@ -129,6 +128,9 @@ internal static class ReflectionGenericTypeResolver /// /// Extracts generic method information including parameter positions /// +#if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Generic method info extraction uses reflection on method parameters")] +#endif public static GenericMethodInfo? ExtractGenericMethodInfo(MethodInfo method) { if (!method.IsGenericMethodDefinition) @@ -177,6 +179,10 @@ internal static class ReflectionGenericTypeResolver /// /// Creates a concrete type from a generic type definition and validates the type arguments /// +#if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Concrete type creation uses Type.GetGenericArguments and reflection")] + [RequiresDynamicCode("Type construction uses MakeGenericType")] +#endif public static Type CreateConcreteType(Type genericTypeDefinition, Type[] typeArguments) { var genericParams = genericTypeDefinition.GetGenericArguments(); diff --git a/TUnit.Engine/Discovery/ReflectionHookDiscoveryService.cs b/TUnit.Engine/Discovery/ReflectionHookDiscoveryService.cs index d4e27d55d5..502ab62101 100644 --- a/TUnit.Engine/Discovery/ReflectionHookDiscoveryService.cs +++ b/TUnit.Engine/Discovery/ReflectionHookDiscoveryService.cs @@ -1,4 +1,4 @@ -using System.Collections.Concurrent; +using System.Collections.Concurrent; using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Runtime.CompilerServices; @@ -12,13 +12,6 @@ namespace TUnit.Engine.Discovery; /// /// Discovers hooks at runtime using reflection for VB.NET and other languages that don't support source generation. /// -[UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "Reflection mode cannot support trimming")] -[UnconditionalSuppressMessage("Trimming", "IL2055:Call to 'System.Type.MakeGenericType' can not be statically analyzed", Justification = "Reflection mode requires dynamic access")] -[UnconditionalSuppressMessage("Trimming", "IL2067:Target parameter does not satisfy annotation requirements", Justification = "Reflection mode requires dynamic access")] -[UnconditionalSuppressMessage("Trimming", "IL2070:Target method does not satisfy annotation requirements", Justification = "Reflection mode requires dynamic access")] -[UnconditionalSuppressMessage("Trimming", "IL2072:Target parameter argument does not satisfy 'DynamicallyAccessedMembersAttribute' requirements", Justification = "Reflection mode requires dynamic access")] -[UnconditionalSuppressMessage("Trimming", "IL2075:'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethods(BindingFlags)'", Justification = "Reflection mode requires dynamic access")] -[UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "Reflection mode cannot support AOT")] internal sealed class ReflectionHookDiscoveryService { private static readonly ConcurrentDictionary _scannedAssemblies = new(); @@ -58,6 +51,10 @@ private static void ClearSourceGeneratedHooks() /// Discovers and registers instance hooks for a specific closed generic type. /// This is needed because closed generic types are created at runtime and don't appear in assembly.GetTypes(). /// + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Hook discovery uses reflection on methods and attributes")] + [RequiresDynamicCode("Hook registration may involve dynamic delegate creation")] + #endif public static void DiscoverInstanceHooksForType(Type closedGenericType) { if (SourceRegistrar.IsEnabled) @@ -134,6 +131,10 @@ public static void DiscoverInstanceHooksForType(Type closedGenericType) } } + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Hook discovery scans assemblies and types using reflection")] + [RequiresDynamicCode("Hook delegate creation may require dynamic code generation")] + #endif public static void DiscoverHooks() { // Prevent running hook discovery multiple times in the same process @@ -166,6 +167,9 @@ public static void DiscoverHooks() } } + #if NET6_0_OR_GREATER + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Assembly.GetReferencedAssemblies is reflection-based but safe for checking references")] + #endif private static bool ShouldScanAssembly(Assembly assembly) { if (_scannedAssemblies.ContainsKey(assembly)) @@ -218,6 +222,9 @@ private static bool ShouldScanAssembly(Assembly assembly) return referencesTUnit; } + #if NET6_0_OR_GREATER + [UnconditionalSuppressMessage("Trimming", "IL2072", Justification = "Types from Assembly.GetTypes() are used with appropriate annotations")] + #endif private static void DiscoverHooksInAssembly(Assembly assembly) { if (!_scannedAssemblies.TryAdd(assembly, true)) @@ -227,7 +234,13 @@ private static void DiscoverHooksInAssembly(Assembly assembly) try { - var types = assembly.GetTypes(); + #if NET6_0_OR_GREATER + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Assembly.GetTypes is reflection-based but required for hook discovery")] + #endif + [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors | DynamicallyAccessedMemberTypes.NonPublicMethods | DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] + Type[] GetTypes() => assembly.GetTypes(); + + var types = GetTypes(); foreach (var type in types) { @@ -240,11 +253,15 @@ private static void DiscoverHooksInAssembly(Assembly assembly) } } - private static void DiscoverHooksInType(Type type, Assembly assembly) + #if NET6_0_OR_GREATER + [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "Types in inheritance chain preserve annotations from the annotated parameter")] + [UnconditionalSuppressMessage("Trimming", "IL2072", Justification = "Types in inheritance chain preserve annotations from the annotated parameter")] + #endif + private static void DiscoverHooksInType([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors | DynamicallyAccessedMemberTypes.NonPublicMethods | DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type type, Assembly assembly) { // Build inheritance chain from base to derived to ensure hooks execute in correct order var inheritanceChain = new List(); - var current = type; + Type? current = type; while (current != null && current != typeof(object)) { inheritanceChain.Insert(0, current); // Insert at front to get base-to-derived order @@ -308,7 +325,12 @@ private static void DiscoverHooksInType(Type type, Assembly assembly) } } - private static void RegisterBeforeHook(Type type, MethodInfo method, BeforeAttribute attr, Assembly assembly) + private static void RegisterBeforeHook( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors | DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods | DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] + Type type, + MethodInfo method, + BeforeAttribute attr, + Assembly assembly) { // Prevent duplicate registrations of the same method var methodKey = GetMethodKey(method); @@ -380,7 +402,12 @@ private static void RegisterBeforeHook(Type type, MethodInfo method, BeforeAttri } } - private static void RegisterAfterHook(Type type, MethodInfo method, AfterAttribute attr, Assembly assembly) + private static void RegisterAfterHook( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors | DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods | DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] + Type type, + MethodInfo method, + AfterAttribute attr, + Assembly assembly) { // Prevent duplicate registrations of the same method var methodKey = GetMethodKey(method); @@ -455,7 +482,12 @@ private static void RegisterAfterHook(Type type, MethodInfo method, AfterAttribu } } - private static void RegisterBeforeEveryHook(Type type, MethodInfo method, BeforeEveryAttribute attr, Assembly assembly) + private static void RegisterBeforeEveryHook( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors | DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods | DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] + Type type, + MethodInfo method, + BeforeEveryAttribute attr, + Assembly assembly) { // Prevent duplicate registrations of the same method var methodKey = GetMethodKey(method); @@ -537,7 +569,12 @@ private static void RegisterBeforeEveryHook(Type type, MethodInfo method, Before } } - private static void RegisterAfterEveryHook(Type type, MethodInfo method, AfterEveryAttribute attr, Assembly assembly) + private static void RegisterAfterEveryHook( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors | DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods | DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] + Type type, + MethodInfo method, + AfterEveryAttribute attr, + Assembly assembly) { // Prevent duplicate registrations of the same method var methodKey = GetMethodKey(method); @@ -628,7 +665,11 @@ private static void RegisterAfterEveryHook(Type type, MethodInfo method, AfterEv } } - private static void RegisterInstanceBeforeHook(Type type, MethodInfo method, int order) + private static void RegisterInstanceBeforeHook( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors | DynamicallyAccessedMemberTypes.NonPublicMethods | DynamicallyAccessedMemberTypes.PublicProperties)] + Type type, + MethodInfo method, + int order) { // Instance hooks on open generic types will be registered when closed types are discovered if (type.ContainsGenericParameters) @@ -649,7 +690,11 @@ private static void RegisterInstanceBeforeHook(Type type, MethodInfo method, int bag.Add(hook); } - private static void RegisterInstanceAfterHook(Type type, MethodInfo method, int order) + private static void RegisterInstanceAfterHook( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors | DynamicallyAccessedMemberTypes.NonPublicMethods | DynamicallyAccessedMemberTypes.PublicProperties)] + Type type, + MethodInfo method, + int order) { // Instance hooks on open generic types will be registered when closed types are discovered if (type.ContainsGenericParameters) @@ -670,7 +715,11 @@ private static void RegisterInstanceAfterHook(Type type, MethodInfo method, int bag.Add(hook); } - private static void RegisterBeforeClassHook(Type type, MethodInfo method, int order) + private static void RegisterBeforeClassHook( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors | DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods | DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] + Type type, + MethodInfo method, + int order) { var bag = Sources.BeforeClassHooks.GetOrAdd(type, _ => new ConcurrentBag()); var hook = new BeforeClassHookMethod @@ -686,7 +735,11 @@ private static void RegisterBeforeClassHook(Type type, MethodInfo method, int or bag.Add(hook); } - private static void RegisterAfterClassHook(Type type, MethodInfo method, int order) + private static void RegisterAfterClassHook( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors | DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods | DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] + Type type, + MethodInfo method, + int order) { var bag = Sources.AfterClassHooks.GetOrAdd(type, _ => new ConcurrentBag()); var hook = new AfterClassHookMethod @@ -702,7 +755,12 @@ private static void RegisterAfterClassHook(Type type, MethodInfo method, int ord bag.Add(hook); } - private static void RegisterBeforeAssemblyHook(Assembly assembly, Type type, MethodInfo method, int order) + private static void RegisterBeforeAssemblyHook( + Assembly assembly, + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors | DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods | DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] + Type type, + MethodInfo method, + int order) { var bag = Sources.BeforeAssemblyHooks.GetOrAdd(assembly, _ => new ConcurrentBag()); var hook = new BeforeAssemblyHookMethod @@ -718,7 +776,12 @@ private static void RegisterBeforeAssemblyHook(Assembly assembly, Type type, Met bag.Add(hook); } - private static void RegisterAfterAssemblyHook(Assembly assembly, Type type, MethodInfo method, int order) + private static void RegisterAfterAssemblyHook( + Assembly assembly, + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors | DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods | DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] + Type type, + MethodInfo method, + int order) { var bag = Sources.AfterAssemblyHooks.GetOrAdd(assembly, _ => new ConcurrentBag()); var hook = new AfterAssemblyHookMethod @@ -734,7 +797,13 @@ private static void RegisterAfterAssemblyHook(Assembly assembly, Type type, Meth bag.Add(hook); } - private static MethodMetadata CreateMethodMetadata(Type type, MethodInfo method) + #if NET6_0_OR_GREATER + [UnconditionalSuppressMessage("Trimming", "IL2072", Justification = "Parameter types in hooks are determined at runtime and cannot be statically analyzed")] + #endif + private static MethodMetadata CreateMethodMetadata( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors | DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods | DynamicallyAccessedMemberTypes.PublicProperties)] + Type type, + MethodInfo method) { return new MethodMetadata { @@ -812,7 +881,7 @@ private static Func CreateIns }; } - private static Func CreateHookDelegate(Type type, MethodInfo method) + private static Func CreateHookDelegate([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type type, MethodInfo method) { return async (context, cancellationToken) => { @@ -860,6 +929,10 @@ private static Func CreateHookDelegate(Type /// /// Extracts the HookExecutor from method attributes, or returns DefaultHookExecutor if not found /// + #if NET6_0_OR_GREATER + [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "Attribute type reflection is required for hook executor discovery")] + [UnconditionalSuppressMessage("Trimming", "IL2072", Justification = "Hook executor types are determined at runtime from attributes")] + #endif private static IHookExecutor GetHookExecutor(MethodInfo method) { // Look for HookExecutorAttribute on the method diff --git a/TUnit.Engine/Discovery/ReflectionTestDataCollector.cs b/TUnit.Engine/Discovery/ReflectionTestDataCollector.cs index 4ed5ef2580..faed1e8641 100644 --- a/TUnit.Engine/Discovery/ReflectionTestDataCollector.cs +++ b/TUnit.Engine/Discovery/ReflectionTestDataCollector.cs @@ -1,4 +1,4 @@ -using System.Buffers; +using System.Buffers; using System.Collections.Concurrent; using System.Diagnostics.CodeAnalysis; using System.Reflection; @@ -12,16 +12,6 @@ namespace TUnit.Engine.Discovery; /// Discovers tests at runtime using reflection with assembly scanning and caching -[UnconditionalSuppressMessage("SingleFile", "IL3000:Avoid accessing Assembly file path when publishing as a single file", Justification = "Reflection mode is not supported in single-file deployments")] -[UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "Reflection mode cannot support trimming")] -[UnconditionalSuppressMessage("Trimming", "IL2055:Call to 'System.Type.MakeGenericType' can not be statically analyzed", Justification = "Reflection mode requires dynamic access")] -[UnconditionalSuppressMessage("Trimming", "IL2060:Call to method can not be statically analyzed", Justification = "Reflection mode requires dynamic access")] -[UnconditionalSuppressMessage("Trimming", "IL2067:Target parameter does not satisfy annotation requirements", Justification = "Reflection mode requires dynamic access")] -[UnconditionalSuppressMessage("Trimming", "IL2070:Target method does not satisfy annotation requirements", Justification = "Reflection mode requires dynamic access")] -[UnconditionalSuppressMessage("Trimming", "IL2072:Target parameter argument does not satisfy 'DynamicallyAccessedMembersAttribute' requirements", Justification = "Reflection mode requires dynamic access")] -[UnconditionalSuppressMessage("Trimming", "IL2075:'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethods(BindingFlags)'", Justification = "Reflection mode requires dynamic access")] -[UnconditionalSuppressMessage("Trimming", "IL2077:Target parameter argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The source field does not have matching annotations.", Justification = "Reflection mode requires dynamic access")] -[UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "Reflection mode cannot support AOT")] internal sealed class ReflectionTestDataCollector : ITestDataCollector { private static readonly ConcurrentDictionary _scannedAssemblies = new(); @@ -53,6 +43,10 @@ public static void ClearCaches() } } + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Assembly scanning uses dynamic type discovery and reflection")] + [RequiresDynamicCode("Generic test instantiation requires MakeGenericType")] + #endif private async Task> ProcessAssemblyAsync(Assembly assembly, SemaphoreSlim semaphore) { await semaphore.WaitAsync().ConfigureAwait(false); @@ -80,6 +74,10 @@ private async Task> ProcessAssemblyAsync(Assembly assembly, S } } + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Assembly scanning uses dynamic type discovery and reflection")] + [RequiresDynamicCode("Generic test instantiation requires MakeGenericType")] + #endif public async Task> CollectTestsAsync(string testSessionId) { #if NET @@ -140,6 +138,10 @@ public async Task> CollectTestsAsync(string testSessio } } + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Reflection-based test discovery requires dynamic access to types, methods, and attributes")] + [RequiresDynamicCode("Test discovery uses MakeGenericType and dynamic code generation")] + #endif public async IAsyncEnumerable CollectTestsStreamingAsync( string testSessionId, [EnumeratorCancellation] CancellationToken cancellationToken = default) @@ -184,7 +186,7 @@ public async IAsyncEnumerable CollectTestsStreamingAsync( } } - private static IEnumerable GetAllTestMethods(Type type) + private static IEnumerable GetAllTestMethods([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type) { return _typeMethodsCache.GetOrAdd(type, static t => { @@ -193,8 +195,16 @@ private static IEnumerable GetAllTestMethods(Type type) while (currentType != null && currentType != typeof(object)) { +#if NET6_0_OR_GREATER +#pragma warning disable IL2070 // Type parameter 't' inherits PublicMethods annotation from input +#pragma warning disable IL2075 // BaseType doesn't preserve annotations, but GetMethods is safe +#endif methods.AddRange(currentType.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly)); currentType = currentType.BaseType; +#if NET6_0_OR_GREATER +#pragma warning restore IL2075 +#pragma warning restore IL2070 +#endif } return methods.ToArray(); @@ -291,7 +301,13 @@ private static bool ShouldScanAssembly(Assembly assembly) try { +#if NET6_0_OR_GREATER +#pragma warning disable IL3000 // Assembly.Location is handled for single-file scenarios with try-catch +#endif var location = assembly.Location; +#if NET6_0_OR_GREATER +#pragma warning restore IL3000 +#endif if (!string.IsNullOrEmpty(location) && (location.Contains("ref") || location.Contains("runtimes") || @@ -308,7 +324,13 @@ private static bool ShouldScanAssembly(Assembly assembly) // Don't return false here, continue with other checks } +#if NET6_0_OR_GREATER +#pragma warning disable IL2026 // Assembly.GetReferencedAssemblies is acceptable for assembly filtering +#endif var referencedAssemblies = assembly.GetReferencedAssemblies(); +#if NET6_0_OR_GREATER +#pragma warning restore IL2026 +#endif var hasTUnitReference = false; foreach (var reference in referencedAssemblies) { @@ -327,6 +349,10 @@ private static bool ShouldScanAssembly(Assembly assembly) return true; } + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Assembly scanning uses dynamic type discovery and reflection")] + [RequiresDynamicCode("Generic test instantiation requires MakeGenericType")] + #endif private static async Task> DiscoverTestsInAssembly(Assembly assembly) { var discoveredTests = new List(100); @@ -425,6 +451,10 @@ private static async Task> DiscoverTestsInAssembly(Assembly a return discoveredTests; } + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Assembly scanning uses dynamic type discovery and reflection")] + [RequiresDynamicCode("Generic test instantiation requires MakeGenericType")] + #endif private static async IAsyncEnumerable DiscoverTestsInAssemblyStreamingAsync( Assembly assembly, [EnumeratorCancellation] CancellationToken cancellationToken = default) @@ -564,6 +594,10 @@ private static async IAsyncEnumerable DiscoverTestsInAssemblyStrea } } + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Generic type resolution requires reflection and dynamic type creation")] + [RequiresDynamicCode("Generic type instantiation uses MakeGenericType")] + #endif private static async Task> DiscoverGenericTests(Type genericTypeDefinition) { var discoveredTests = new List(100); @@ -653,6 +687,10 @@ private static async Task> DiscoverGenericTests(Type genericT return discoveredTests; } + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Generic type resolution requires reflection and dynamic type creation")] + [RequiresDynamicCode("Generic type instantiation uses MakeGenericType")] + #endif private static async IAsyncEnumerable DiscoverGenericTestsStreamingAsync( Type genericTypeDefinition, [EnumeratorCancellation] CancellationToken cancellationToken = default) @@ -837,7 +875,15 @@ private static int CalculateInheritanceDepth(Type testClass, MethodInfo testMeth return depth; } - private static Task BuildTestMetadata(Type testClass, MethodInfo testMethod, object?[]? classData = null) + #if NET6_0_OR_GREATER + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "BuildTestMetadata calls other reflection methods that are already annotated")] + [UnconditionalSuppressMessage("AOT", "IL3050", Justification = "BuildTestMetadata calls CreateInstanceFactory and CreateTestInvoker which are properly annotated")] + #endif + private static Task BuildTestMetadata( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields | DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors | DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)] + Type testClass, + MethodInfo testMethod, + object?[]? classData = null) { var testName = GenerateTestName(testClass, testMethod); @@ -851,6 +897,9 @@ private static Task BuildTestMetadata(Type testClass, MethodInfo t testMethod.DeclaringType.IsGenericTypeDefinition) { // Find the constructed generic type in the inheritance chain +#if NET6_0_OR_GREATER +#pragma warning disable IL2072 // BaseType doesn't preserve DynamicallyAccessedMembers annotations +#endif var baseType = testClass.BaseType; while (baseType != null) { @@ -862,6 +911,9 @@ private static Task BuildTestMetadata(Type testClass, MethodInfo t } baseType = baseType.BaseType; } +#if NET6_0_OR_GREATER +#pragma warning restore IL2072 +#endif } try @@ -869,7 +921,13 @@ private static Task BuildTestMetadata(Type testClass, MethodInfo t return Task.FromResult(new ReflectionTestMetadata(testClass, testMethod) { TestName = testName, +#if NET6_0_OR_GREATER +#pragma warning disable IL2072 // typeForGenericResolution may come from BaseType which doesn't preserve annotations +#endif TestClassType = typeForGenericResolution, // Use resolved type for generic resolution (may be constructed generic base) +#if NET6_0_OR_GREATER +#pragma warning restore IL2072 +#endif TestMethodName = testMethod.Name, Dependencies = ReflectionAttributeExtractor.ExtractDependencies(testClass, testMethod), DataSources = ReflectionAttributeExtractor.ExtractDataSources(testMethod), @@ -925,6 +983,10 @@ private static string GenerateTestName(Type testClass, MethodInfo testMethod) + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Instance creation uses reflection and Activator.CreateInstance")] + [RequiresDynamicCode("Generic type instantiation uses MakeGenericType and Activator")] + #endif private static Func CreateInstanceFactory([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type testClass) { // For generic types, we need to handle MakeGenericType @@ -984,6 +1046,10 @@ private static string GenerateTestName(Type testClass, MethodInfo testMethod) } + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Test invocation uses reflection and MethodInfo.Invoke")] + [RequiresDynamicCode("Generic method instantiation uses MakeGenericMethod")] + #endif private static Func CreateTestInvoker(Type testClass, MethodInfo testMethod) { return CreateReflectionTestInvoker(testClass, testMethod); @@ -1000,7 +1066,7 @@ private static bool IsAsyncMethod(MethodInfo method) method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>)); } - private static bool IsCompilerGenerated(Type type) + private static bool IsCompilerGenerated([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type) { // If the type is not marked as compiler-generated, it's not compiler-generated if (!type.IsDefined(typeof(CompilerGeneratedAttribute), inherit: false)) @@ -1013,7 +1079,7 @@ private static bool IsCompilerGenerated(Type type) return !HasTestMethods(type); } - private static bool HasTestMethods(Type type) + private static bool HasTestMethods([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type) { try { @@ -1060,6 +1126,10 @@ private static ParameterInfo[] GetParametersWithoutCancellationToken(MethodInfo return method.GetCustomAttribute()?.Line; } + #if NET6_0_OR_GREATER + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "This is only called in error cases for assembly scanning failures")] + [UnconditionalSuppressMessage("Trimming", "IL2111", Justification = "Methods are called directly, not via reflection")] + #endif private static TestMetadata CreateFailedTestMetadataForAssembly(Assembly assembly, Exception ex) { var testName = $"[ASSEMBLY SCAN FAILED] {assembly.GetName().Name}"; @@ -1091,7 +1161,14 @@ private static TestMetadata CreateFailedTestMetadataForAssembly(Assembly assembl }; } - private static TestMetadata CreateFailedTestMetadata(Type type, MethodInfo method, Exception ex) + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Failed test metadata creation uses ReflectionMetadataBuilder")] + #endif + private static TestMetadata CreateFailedTestMetadata( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors | DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods | DynamicallyAccessedMemberTypes.PublicProperties)] + Type type, + MethodInfo method, + Exception ex) { var testName = $"[DISCOVERY FAILED] {type.FullName}.{method.Name}"; var displayName = $"{testName} - {ex.Message}"; @@ -1120,7 +1197,10 @@ private static TestMetadata CreateFailedTestMetadata(Type type, MethodInfo metho } - private static MethodMetadata CreateDummyMethodMetadata(Type type, string methodName) + private static MethodMetadata CreateDummyMethodMetadata( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors | DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods | DynamicallyAccessedMemberTypes.PublicProperties)] + Type type, + string methodName) { return new MethodMetadata { @@ -1182,6 +1262,10 @@ public override Func /// Creates a reflection-based instance factory with proper AOT attribution /// + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Reflection-based factory uses ConstructorInfo.Invoke")] + [RequiresDynamicCode("Dynamic constructor invocation may require runtime code generation")] + #endif private static Func CreateReflectionInstanceFactory(ConstructorInfo ctor) { var isPrepared = false; @@ -1244,7 +1328,7 @@ public override Func /// Infers generic type mappings from parameter and argument types /// - private static void InferGenericTypeMapping(Type paramType, Type argType, Dictionary typeMapping) + private static void InferGenericTypeMapping(Type paramType, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)] Type argType, Dictionary typeMapping) { // Direct generic parameter if (paramType.IsGenericParameter) @@ -1279,7 +1363,13 @@ private static void InferGenericTypeMapping(Type paramType, Type argType, Dictio for (var i = 0; i < paramGenArgs.Length && i < argGenArgs.Length; i++) { +#if NET6_0_OR_GREATER +#pragma warning disable IL2062 // Generic type arguments don't preserve DynamicallyAccessedMembers +#endif InferGenericTypeMapping(paramGenArgs[i], argGenArgs[i], typeMapping); +#if NET6_0_OR_GREATER +#pragma warning restore IL2062 +#endif } } else @@ -1294,7 +1384,13 @@ private static void InferGenericTypeMapping(Type paramType, Type argType, Dictio for (var i = 0; i < paramGenArgs.Length && i < ifaceGenArgs.Length; i++) { +#if NET6_0_OR_GREATER +#pragma warning disable IL2062 // Generic type arguments don't preserve DynamicallyAccessedMembers +#endif InferGenericTypeMapping(paramGenArgs[i], ifaceGenArgs[i], typeMapping); +#if NET6_0_OR_GREATER +#pragma warning restore IL2062 +#endif } break; } @@ -1315,7 +1411,13 @@ private static void InferGenericTypeMapping(Type paramType, Type argType, Dictio for (var i = 0; i < paramGenArgs.Length && i < ifaceGenArgs.Length; i++) { +#if NET6_0_OR_GREATER +#pragma warning disable IL2062 // Generic type arguments don't preserve DynamicallyAccessedMembers +#endif InferGenericTypeMapping(paramGenArgs[i], ifaceGenArgs[i], typeMapping); +#if NET6_0_OR_GREATER +#pragma warning restore IL2062 +#endif } break; } @@ -1325,14 +1427,20 @@ private static void InferGenericTypeMapping(Type paramType, Type argType, Dictio // Array types if (paramType.IsArray && argType.IsArray) { +#if NET6_0_OR_GREATER +#pragma warning disable IL2072 // GetElementType doesn't preserve DynamicallyAccessedMembers +#endif InferGenericTypeMapping(paramType.GetElementType()!, argType.GetElementType()!, typeMapping); +#if NET6_0_OR_GREATER +#pragma warning restore IL2072 +#endif } } /// /// Checks if the argument type is compatible with the parameter type through covariance /// - private static bool IsCovariantCompatible(Type paramType, Type argType) + private static bool IsCovariantCompatible(Type paramType, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)] Type argType) { // Only check for generic interface covariance if (!paramType.IsInterface || !paramType.IsGenericType) @@ -1382,6 +1490,10 @@ private static bool IsCovariantCompatible(Type paramType, Type argType) /// /// Creates a reflection-based test invoker with proper AOT attribution /// + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Reflection-based invoker uses MethodInfo.Invoke and reflection")] + [RequiresDynamicCode("Generic method construction uses MakeGenericMethod")] + #endif private static Func CreateReflectionTestInvoker(Type testClass, MethodInfo testMethod) { var isPrepared = false; @@ -1590,6 +1702,10 @@ private static bool IsCovariantCompatible(Type paramType, Type argType) }; } + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Dynamic test discovery uses reflection to scan assemblies and types")] + [RequiresDynamicCode("Dynamic test builders may use expression compilation")] + #endif private async Task> DiscoverDynamicTests(string testSessionId) { var dynamicTests = new List(50); @@ -1679,6 +1795,10 @@ private async Task> DiscoverDynamicTests(string testSessionId return dynamicTests; } + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Dynamic test discovery uses reflection to scan assemblies and types")] + [RequiresDynamicCode("Dynamic test builders may use expression compilation")] + #endif private async IAsyncEnumerable DiscoverDynamicTestsStreamingAsync( string testSessionId, [EnumeratorCancellation] CancellationToken cancellationToken = default) @@ -1740,6 +1860,10 @@ private async IAsyncEnumerable DiscoverDynamicTestsStreamingAsync( } } + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Dynamic test builder execution uses Activator.CreateInstance and MethodInfo.Invoke")] + [RequiresDynamicCode("Expression compilation is used for dynamic tests")] + #endif private async Task> ExecuteDynamicTestBuilder(Type testClass, MethodInfo builderMethod, string testSessionId) { var dynamicTests = new List(50); @@ -1771,6 +1895,10 @@ private async Task> ExecuteDynamicTestBuilder(Type testClass, return dynamicTests; } + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Dynamic test metadata creation uses reflection")] + [RequiresDynamicCode("Expression compilation is used for dynamic test invocation")] + #endif private async Task> ConvertDynamicTestToMetadata(AbstractDynamicTest abstractDynamicTest) { var testMetadataList = new List(); @@ -1787,6 +1915,10 @@ private async Task> ConvertDynamicTestToMetadata(AbstractDyna return testMetadataList; } + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Dynamic test builder execution uses Activator.CreateInstance and MethodInfo.Invoke")] + [RequiresDynamicCode("Expression compilation is used for dynamic tests")] + #endif private async IAsyncEnumerable ExecuteDynamicTestBuilderStreamingAsync( Type testClass, MethodInfo builderMethod, string testSessionId, [EnumeratorCancellation] CancellationToken cancellationToken = default) @@ -1868,6 +2000,10 @@ private async IAsyncEnumerable ExecuteDynamicTestBuilderStreamingA } } + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Dynamic test metadata creation uses reflection")] + [RequiresDynamicCode("Expression compilation is used for dynamic test invocation")] + #endif private Task CreateMetadataFromDynamicDiscoveryResult(DynamicDiscoveryResult result) { if (result.TestClassType == null || result.TestMethod == null) @@ -1918,6 +2054,10 @@ private Task CreateMetadataFromDynamicDiscoveryResult(DynamicDisco return Task.FromResult(metadata); } + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Dynamic instance factory uses Activator.CreateInstance")] + [RequiresDynamicCode("Generic type construction uses MakeGenericType")] + #endif private static Func CreateDynamicInstanceFactory(Type testClass, object?[]? predefinedClassArgs) { // For dynamic tests, we always use the predefined args (or empty array if null) @@ -1944,6 +2084,10 @@ private Task CreateMetadataFromDynamicDiscoveryResult(DynamicDisco }; } + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Dynamic test invoker uses expression compilation and reflection")] + [RequiresDynamicCode("LambdaExpression.Compile requires dynamic code generation")] + #endif private static Func CreateDynamicTestInvoker(DynamicDiscoveryResult result) { return async (instance, args) => @@ -1987,6 +2131,10 @@ private Task CreateMetadataFromDynamicDiscoveryResult(DynamicDisco }; } + #if NET6_0_OR_GREATER + [UnconditionalSuppressMessage("Trimming", "IL2077", Justification = "This is only called in error cases for dynamic source failures")] + [UnconditionalSuppressMessage("Trimming", "IL2072", Justification = "Object.GetType() doesn't preserve annotations, but this is for error reporting only")] + #endif private static TestMetadata CreateFailedTestMetadataForDynamicSource(IDynamicTestSource source, Exception ex) { var testName = $"[DYNAMIC SOURCE FAILED] {source.GetType().Name}"; @@ -2007,7 +2155,14 @@ private static TestMetadata CreateFailedTestMetadataForDynamicSource(IDynamicTes }; } - private static TestMetadata CreateFailedTestMetadataForDynamicBuilder(Type type, MethodInfo method, Exception ex) + #if NET6_0_OR_GREATER + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "This is only called in error cases for dynamic builder failures")] + #endif + private static TestMetadata CreateFailedTestMetadataForDynamicBuilder( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors | DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods | DynamicallyAccessedMemberTypes.PublicProperties)] + Type type, + MethodInfo method, + Exception ex) { var testName = $"[DYNAMIC BUILDER FAILED] {type.FullName}.{method.Name}"; var displayName = $"{testName} - {ex.Message}"; @@ -2050,10 +2205,14 @@ private static TestMetadata CreateFailedTestMetadataForDynamicTest(DynamicDiscov private sealed class DynamicReflectionTestMetadata : TestMetadata, IDynamicTestMetadata { private readonly DynamicDiscoveryResult _dynamicResult; + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] private readonly Type _testClass; private readonly MethodInfo _testMethod; - public DynamicReflectionTestMetadata(Type testClass, MethodInfo testMethod, DynamicDiscoveryResult dynamicResult) + public DynamicReflectionTestMetadata( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type testClass, + MethodInfo testMethod, + DynamicDiscoveryResult dynamicResult) { _testClass = testClass; _testMethod = testMethod; diff --git a/TUnit.Engine/Discovery/TestInstanceHelper.cs b/TUnit.Engine/Discovery/TestInstanceHelper.cs index 61f436433c..f4f33b9542 100644 --- a/TUnit.Engine/Discovery/TestInstanceHelper.cs +++ b/TUnit.Engine/Discovery/TestInstanceHelper.cs @@ -1,4 +1,4 @@ -using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.CodeAnalysis; using System.Reflection; using TUnit.Core; @@ -12,8 +12,9 @@ internal static class TestInstanceHelper /// /// Creates a test instance with data from class data sources /// - [UnconditionalSuppressMessage("Trimming", "IL2070:Target method does not satisfy annotation requirements", Justification = "Reflection mode requires dynamic access")] - [UnconditionalSuppressMessage("Trimming", "IL2067:Target type's member does not satisfy annotation requirements", Justification = "Reflection mode requires dynamic access")] + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Test instance creation uses reflection on constructors and properties")] + #endif public static object? CreateTestInstanceWithData( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors | DynamicallyAccessedMemberTypes.PublicProperties)] Type testClass, IDataSourceAttribute[]? classDataSources) @@ -133,7 +134,9 @@ internal static class TestInstanceHelper /// /// Creates test instance for inherited test classes /// - [UnconditionalSuppressMessage("Trimming", "IL2070:Target method does not satisfy annotation requirements", Justification = "Reflection mode requires dynamic access")] + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Inherited test instance creation uses reflection on type hierarchy")] + #endif public static object? CreateInheritedTestInstance( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors | DynamicallyAccessedMemberTypes.PublicProperties)] Type testClass) { @@ -182,9 +185,9 @@ private sealed class DiscoveryPlaceholderInstance public override string ToString() => ""; } - [UnconditionalSuppressMessage("Trimming", "IL2070:Target method does not satisfy annotation requirements", Justification = "Reflection mode requires dynamic access")] - [UnconditionalSuppressMessage("Trimming", "IL2067:Target type's member does not satisfy annotation requirements", Justification = "Reflection mode requires dynamic access")] - [UnconditionalSuppressMessage("Trimming", "IL2072:Target method return value does not satisfy annotation requirements", Justification = "Reflection mode requires dynamic access")] + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Property initialization traverses type hierarchy using reflection")] + #endif private static void InitializeInheritedRequiredProperties(object instance, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] Type type) { var currentType = type; @@ -194,4 +197,4 @@ private static void InitializeInheritedRequiredProperties(object instance, [Dyna currentType = currentType.BaseType; } } -} \ No newline at end of file +} diff --git a/TUnit.Engine/Framework/IRequestHandler.cs b/TUnit.Engine/Framework/IRequestHandler.cs index ff653f3168..0a6f8cf4c4 100644 --- a/TUnit.Engine/Framework/IRequestHandler.cs +++ b/TUnit.Engine/Framework/IRequestHandler.cs @@ -8,5 +8,9 @@ namespace TUnit.Engine.Framework; /// internal interface IRequestHandler { + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces and reflection")] + [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("Generic test instantiation requires MakeGenericType")] + #endif Task HandleRequestAsync(TestExecutionRequest request, TUnitServiceProvider serviceProvider, ExecuteRequestContext context, ITestExecutionFilter? testExecutionFilter); } diff --git a/TUnit.Engine/Framework/TUnitServiceProvider.cs b/TUnit.Engine/Framework/TUnitServiceProvider.cs index 3e62eba4dc..6722f682e2 100644 --- a/TUnit.Engine/Framework/TUnitServiceProvider.cs +++ b/TUnit.Engine/Framework/TUnitServiceProvider.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using Microsoft.Testing.Platform.Capabilities.TestFramework; using Microsoft.Testing.Platform.CommandLine; @@ -55,6 +56,10 @@ public ITestExecutionFilter? Filter public ObjectRegistrationService ObjectRegistrationService { get; } public bool AfterSessionHooksFailed { get; set; } +#if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Test data collector selection may use reflection-based discovery")] + [RequiresDynamicCode("Reflection mode test discovery uses dynamic code generation")] +#endif public TUnitServiceProvider(IExtension extension, ExecuteRequestContext context, ITestExecutionFilter? filter, @@ -133,13 +138,9 @@ public TUnitServiceProvider(IExtension extension, var testMethodInvoker = Register(new TestMethodInvoker()); var useSourceGeneration = SourceRegistrar.IsEnabled = GetUseSourceGeneration(CommandLineOptions); -#pragma warning disable IL2026 // Using member which has 'RequiresUnreferencedCodeAttribute' -#pragma warning disable IL3050 // Using member which has 'RequiresDynamicCodeAttribute' ITestDataCollector dataCollector = useSourceGeneration ? new AotTestDataCollector() : new ReflectionTestDataCollector(); -#pragma warning restore IL3050 -#pragma warning restore IL2026 var testBuilder = Register( new TestBuilder(TestSessionId, EventReceiverOrchestrator, ContextProvider, PropertyInjectionService, DataSourceInitializer)); diff --git a/TUnit.Engine/Framework/TUnitTestFramework.cs b/TUnit.Engine/Framework/TUnitTestFramework.cs index 71eafd8e8b..408a1f1203 100644 --- a/TUnit.Engine/Framework/TUnitTestFramework.cs +++ b/TUnit.Engine/Framework/TUnitTestFramework.cs @@ -41,6 +41,11 @@ public Task CreateTestSessionAsync(CreateTestSessionCon return Task.FromResult(new CreateTestSessionResult { IsSuccess = true }); } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Test data collector selection may use reflection-based discovery")] + [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("Reflection mode test discovery uses dynamic code generation")] +#pragma warning disable IL2046, IL3051 // Interface implementation - cannot add attributes to match called method requirements + #endif public async Task ExecuteRequestAsync(ExecuteRequestContext context) { try @@ -85,6 +90,9 @@ public async Task ExecuteRequestAsync(ExecuteRequestContext context) context.Complete(); } } + #if NET6_0_OR_GREATER +#pragma warning restore IL2046, IL3051 + #endif public async Task CloseTestSessionAsync(CloseTestSessionContext context) { @@ -104,6 +112,10 @@ public async Task CloseTestSessionAsync(CloseTestSession return new CloseTestSessionResult { IsSuccess = isSuccess }; } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Test data collector selection may use reflection-based discovery")] + [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("Reflection mode test discovery uses dynamic code generation")] + #endif private TUnitServiceProvider GetOrCreateServiceProvider(ExecuteRequestContext context) { return _serviceProvidersPerSession.GetOrAdd( diff --git a/TUnit.Engine/Framework/TestRequestHandler.cs b/TUnit.Engine/Framework/TestRequestHandler.cs index 38e447c779..5adc08ee29 100644 --- a/TUnit.Engine/Framework/TestRequestHandler.cs +++ b/TUnit.Engine/Framework/TestRequestHandler.cs @@ -7,6 +7,10 @@ namespace TUnit.Engine.Framework; internal sealed class TestRequestHandler : IRequestHandler { + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces and reflection")] + [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("Generic test instantiation requires MakeGenericType")] + #endif public async Task HandleRequestAsync(TestExecutionRequest request, TUnitServiceProvider serviceProvider, ExecuteRequestContext context, ITestExecutionFilter? testExecutionFilter) { switch (request) @@ -27,6 +31,10 @@ public async Task HandleRequestAsync(TestExecutionRequest request, TUnitServiceP } } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces and reflection")] + [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("Generic test instantiation requires MakeGenericType")] + #endif private async Task HandleDiscoveryRequestAsync( TUnitServiceProvider serviceProvider, ExecuteRequestContext context, @@ -51,6 +59,10 @@ private async Task HandleDiscoveryRequestAsync( } } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces and reflection")] + [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("Generic test instantiation requires MakeGenericType")] + #endif private async Task HandleRunRequestAsync( TUnitServiceProvider serviceProvider, RunTestExecutionRequest request, diff --git a/TUnit.Engine/Helpers/DisplayNameBuilder.cs b/TUnit.Engine/Helpers/DisplayNameBuilder.cs index 05a373f87d..b3df683bc8 100644 --- a/TUnit.Engine/Helpers/DisplayNameBuilder.cs +++ b/TUnit.Engine/Helpers/DisplayNameBuilder.cs @@ -114,8 +114,9 @@ private static string GetSimpleTypeName(Type type) /// /// Resolves the actual value from a data source factory result /// - [UnconditionalSuppressMessage("AOT", "IL2075:Target method return value does not satisfy annotation requirements.", - Justification = "This is for reflection mode which doesn't support AOT")] +#if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Data source value resolution may use reflection")] +#endif public static async Task ResolveDataSourceValue(object? value) { if (value == null) diff --git a/TUnit.Engine/Interfaces/IHookCollectionService.cs b/TUnit.Engine/Interfaces/IHookCollectionService.cs index 3b9d4a96f8..589a9ceb54 100644 --- a/TUnit.Engine/Interfaces/IHookCollectionService.cs +++ b/TUnit.Engine/Interfaces/IHookCollectionService.cs @@ -5,9 +5,21 @@ namespace TUnit.Engine.Interfaces; internal interface IHookCollectionService { + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces and reflection")] + #endif ValueTask>> CollectBeforeTestHooksAsync(Type testClassType); + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces and reflection")] + #endif ValueTask>> CollectAfterTestHooksAsync(Type testClassType); + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces and reflection")] + #endif ValueTask>> CollectBeforeEveryTestHooksAsync(Type testClassType); + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces and reflection")] + #endif ValueTask>> CollectAfterEveryTestHooksAsync(Type testClassType); ValueTask>> CollectBeforeClassHooksAsync(Type testClassType); diff --git a/TUnit.Engine/Interfaces/ITestCoordinator.cs b/TUnit.Engine/Interfaces/ITestCoordinator.cs index 475c54edda..33200b7dc0 100644 --- a/TUnit.Engine/Interfaces/ITestCoordinator.cs +++ b/TUnit.Engine/Interfaces/ITestCoordinator.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Microsoft.Testing.Platform.Extensions.Messages; using TUnit.Core; @@ -8,5 +9,8 @@ namespace TUnit.Engine.Interfaces; /// internal interface ITestCoordinator { + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Test execution involves reflection for hooks and initialization")] + #endif Task ExecuteTestAsync(AbstractExecutableTest test, CancellationToken cancellationToken); } diff --git a/TUnit.Engine/Scheduling/ConstraintKeyScheduler.cs b/TUnit.Engine/Scheduling/ConstraintKeyScheduler.cs index 6ea17981cc..de540d98a2 100644 --- a/TUnit.Engine/Scheduling/ConstraintKeyScheduler.cs +++ b/TUnit.Engine/Scheduling/ConstraintKeyScheduler.cs @@ -22,6 +22,9 @@ public ConstraintKeyScheduler( _parallelLimitLockProvider = parallelLimitLockProvider; } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Test execution involves reflection for hooks and initialization")] + #endif public async ValueTask ExecuteTestsWithConstraintsAsync( (AbstractExecutableTest Test, IReadOnlyList ConstraintKeys, int Priority)[] tests, CancellationToken cancellationToken) @@ -91,6 +94,9 @@ public async ValueTask ExecuteTestsWithConstraintsAsync( await Task.WhenAll(activeTasks).ConfigureAwait(false); } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Test execution involves reflection for hooks and initialization")] + #endif private async Task WaitAndExecuteTestAsync( AbstractExecutableTest test, IReadOnlyList constraintKeys, @@ -108,6 +114,9 @@ private async Task WaitAndExecuteTestAsync( await ExecuteTestAndReleaseKeysAsync(test, constraintKeys, lockedKeys, lockObject, waitingTests, cancellationToken).ConfigureAwait(false); } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Test execution involves reflection for hooks and initialization")] + #endif private async Task ExecuteTestAndReleaseKeysAsync( AbstractExecutableTest test, IReadOnlyList constraintKeys, diff --git a/TUnit.Engine/Scheduling/IConstraintKeyScheduler.cs b/TUnit.Engine/Scheduling/IConstraintKeyScheduler.cs index 0b98d503db..e9a3e7ebf5 100644 --- a/TUnit.Engine/Scheduling/IConstraintKeyScheduler.cs +++ b/TUnit.Engine/Scheduling/IConstraintKeyScheduler.cs @@ -1,9 +1,13 @@ +using System.Diagnostics.CodeAnalysis; using TUnit.Core; namespace TUnit.Engine.Scheduling; internal interface IConstraintKeyScheduler { + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Test execution involves reflection for hooks and initialization")] + #endif ValueTask ExecuteTestsWithConstraintsAsync( (AbstractExecutableTest Test, IReadOnlyList ConstraintKeys, int Priority)[] tests, CancellationToken cancellationToken); diff --git a/TUnit.Engine/Scheduling/ITestScheduler.cs b/TUnit.Engine/Scheduling/ITestScheduler.cs index 0abfdb55f9..42ff23527b 100644 --- a/TUnit.Engine/Scheduling/ITestScheduler.cs +++ b/TUnit.Engine/Scheduling/ITestScheduler.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using TUnit.Core; namespace TUnit.Engine.Scheduling; @@ -11,6 +12,9 @@ internal interface ITestScheduler /// Schedules and executes tests with optimal parallelization /// /// True if successful, false if After(TestSession) hooks failed + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Test execution involves reflection for hooks and initialization")] + #endif Task ScheduleAndExecuteAsync( List tests, CancellationToken cancellationToken); diff --git a/TUnit.Engine/Scheduling/TestRunner.cs b/TUnit.Engine/Scheduling/TestRunner.cs index 5dde86ed23..3e84f70d66 100644 --- a/TUnit.Engine/Scheduling/TestRunner.cs +++ b/TUnit.Engine/Scheduling/TestRunner.cs @@ -39,6 +39,9 @@ internal TestRunner( private readonly ThreadSafeDictionary _executingTests = new(); private Exception? _firstFailFastException; + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Test execution involves reflection for hooks and initialization")] + #endif public async Task ExecuteTestAsync(AbstractExecutableTest test, CancellationToken cancellationToken) { // Prevent double execution with a simple lock @@ -46,6 +49,9 @@ public async Task ExecuteTestAsync(AbstractExecutableTest test, CancellationToke await executionTask.ConfigureAwait(false); } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Test execution involves reflection for hooks and initialization")] + #endif private async Task ExecuteTestInternalAsync(AbstractExecutableTest test, CancellationToken cancellationToken) { try diff --git a/TUnit.Engine/Scheduling/TestScheduler.cs b/TUnit.Engine/Scheduling/TestScheduler.cs index 3818275b3a..507dc9ca83 100644 --- a/TUnit.Engine/Scheduling/TestScheduler.cs +++ b/TUnit.Engine/Scheduling/TestScheduler.cs @@ -50,6 +50,9 @@ public TestScheduler( _staticPropertyHandler = staticPropertyHandler; } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Test execution involves reflection for hooks and initialization")] + #endif public async Task ScheduleAndExecuteAsync( List testList, CancellationToken cancellationToken) @@ -130,6 +133,9 @@ public async Task ScheduleAndExecuteAsync( return true; } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Test execution involves reflection for hooks and initialization")] + #endif private async Task ExecuteGroupedTestsAsync( GroupedTests groupedTests, CancellationToken cancellationToken) @@ -214,6 +220,9 @@ private async Task ExecuteGroupedTestsAsync( } } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Test execution involves reflection for hooks and initialization")] + #endif private async Task ExecuteTestWithParallelLimitAsync( AbstractExecutableTest test, CancellationToken cancellationToken) @@ -238,6 +247,9 @@ private async Task ExecuteTestWithParallelLimitAsync( } } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Test execution involves reflection for hooks and initialization")] + #endif private async Task ExecuteParallelGroupAsync( string groupName, AbstractExecutableTest[] orderedTests, @@ -265,6 +277,9 @@ private async Task ExecuteParallelGroupAsync( } } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Test execution involves reflection for hooks and initialization")] + #endif private async Task ExecuteConstrainedParallelGroupAsync( string groupName, GroupedConstrainedTests constrainedTests, @@ -320,6 +335,9 @@ private async Task ExecuteConstrainedParallelGroupAsync( } } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Test execution involves reflection for hooks and initialization")] + #endif private async Task ExecuteSequentiallyAsync( string groupName, AbstractExecutableTest[] tests, @@ -335,6 +353,9 @@ private async Task ExecuteSequentiallyAsync( } } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Test execution involves reflection for hooks and initialization")] + #endif private async Task ExecuteParallelTestsWithLimitAsync( AbstractExecutableTest[] tests, int maxParallelism, diff --git a/TUnit.Engine/Services/DataSourceInitializer.cs b/TUnit.Engine/Services/DataSourceInitializer.cs index 59481396a4..f0dd58ec96 100644 --- a/TUnit.Engine/Services/DataSourceInitializer.cs +++ b/TUnit.Engine/Services/DataSourceInitializer.cs @@ -25,6 +25,9 @@ public void Initialize(PropertyInjectionService propertyInjectionService) /// Ensures a data source instance is fully initialized before use. /// This includes property injection and calling IAsyncInitializer if implemented. /// + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Type comes from runtime objects that cannot be annotated")] + #endif public async Task EnsureInitializedAsync( T dataSource, Dictionary? objectBag = null, @@ -59,6 +62,9 @@ public async Task EnsureInitializedAsync( /// /// Initializes a data source instance with the complete lifecycle. /// + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Type comes from runtime objects that cannot be annotated")] + #endif private async Task InitializeDataSourceAsync( object dataSource, Dictionary? objectBag, @@ -100,6 +106,9 @@ await _propertyInjectionService.InjectPropertiesIntoObjectAsync( /// Initializes all nested property-injected objects in depth-first order. /// This ensures that when the parent's IAsyncInitializer runs, all nested dependencies are already initialized. /// + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Type comes from runtime objects that cannot be annotated")] + #endif private async Task InitializeNestedObjectsAsync(object rootObject) { var objectsByDepth = new Dictionary>(); @@ -123,6 +132,9 @@ private async Task InitializeNestedObjectsAsync(object rootObject) /// /// Recursively collects all nested property-injected objects grouped by depth. /// + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Type comes from runtime objects that cannot be annotated")] + #endif private void CollectNestedObjects( object obj, Dictionary> objectsByDepth, diff --git a/TUnit.Engine/Services/EventReceiverOrchestrator.cs b/TUnit.Engine/Services/EventReceiverOrchestrator.cs index eebc31be2c..b26b433d2c 100644 --- a/TUnit.Engine/Services/EventReceiverOrchestrator.cs +++ b/TUnit.Engine/Services/EventReceiverOrchestrator.cs @@ -84,6 +84,9 @@ obj is IFirstTestInAssemblyEventReceiver || // Fast-path checks with inlining [MethodImpl(MethodImplOptions.AggressiveInlining)] + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces and reflection")] + #endif public async ValueTask InvokeTestStartEventReceiversAsync(TestContext context, CancellationToken cancellationToken) { // Fast path - no allocation if no receivers @@ -95,6 +98,9 @@ public async ValueTask InvokeTestStartEventReceiversAsync(TestContext context, C await InvokeTestStartEventReceiversCore(context, cancellationToken); } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces and reflection")] + #endif private async ValueTask InvokeTestStartEventReceiversCore(TestContext context, CancellationToken cancellationToken) { var receivers = context.GetEligibleEventObjects() @@ -121,6 +127,9 @@ private async ValueTask InvokeTestStartEventReceiversCore(TestContext context, C } [MethodImpl(MethodImplOptions.AggressiveInlining)] + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces and reflection")] + #endif public async ValueTask InvokeTestEndEventReceiversAsync(TestContext context, CancellationToken cancellationToken) { if (!_registry.HasTestEndReceivers()) @@ -131,6 +140,9 @@ public async ValueTask InvokeTestEndEventReceiversAsync(TestContext context, Can await InvokeTestEndEventReceiversCore(context, cancellationToken); } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces and reflection")] + #endif private async ValueTask InvokeTestEndEventReceiversCore(TestContext context, CancellationToken cancellationToken) { var receivers = context.GetEligibleEventObjects() @@ -155,6 +167,9 @@ private async ValueTask InvokeTestEndEventReceiversCore(TestContext context, Can } [MethodImpl(MethodImplOptions.AggressiveInlining)] + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces and reflection")] + #endif public async ValueTask InvokeTestSkippedEventReceiversAsync(TestContext context, CancellationToken cancellationToken) { if (!_registry.HasTestSkippedReceivers()) @@ -165,6 +180,9 @@ public async ValueTask InvokeTestSkippedEventReceiversAsync(TestContext context, await InvokeTestSkippedEventReceiversCore(context, cancellationToken); } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces and reflection")] + #endif private async ValueTask InvokeTestSkippedEventReceiversCore(TestContext context, CancellationToken cancellationToken) { var receivers = context.GetEligibleEventObjects() @@ -181,6 +199,9 @@ private async ValueTask InvokeTestSkippedEventReceiversCore(TestContext context, } } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces and reflection")] + #endif public async ValueTask InvokeTestDiscoveryEventReceiversAsync(TestContext context, DiscoveredTestContext discoveredContext, CancellationToken cancellationToken) { var eventReceivers = context.GetEligibleEventObjects() @@ -197,6 +218,9 @@ public async ValueTask InvokeTestDiscoveryEventReceiversAsync(TestContext contex } } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces and reflection")] + #endif public async ValueTask InvokeHookRegistrationEventReceiversAsync(HookRegisteredContext hookContext, CancellationToken cancellationToken) { // Get event receivers from the hook method's attributes diff --git a/TUnit.Engine/Services/HookCollectionService.cs b/TUnit.Engine/Services/HookCollectionService.cs index 5ad471689b..f06c043756 100644 --- a/TUnit.Engine/Services/HookCollectionService.cs +++ b/TUnit.Engine/Services/HookCollectionService.cs @@ -25,6 +25,9 @@ public HookCollectionService(EventReceiverOrchestrator eventReceiverOrchestrator _eventReceiverOrchestrator = eventReceiverOrchestrator; } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces and reflection")] + #endif private async Task ProcessHookRegistrationAsync(HookMethod hookMethod, CancellationToken cancellationToken = default) { // Only process each hook once @@ -45,6 +48,9 @@ private async Task ProcessHookRegistrationAsync(HookMethod hookMethod, Cancellat } } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces and reflection")] + #endif public async ValueTask>> CollectBeforeTestHooksAsync(Type testClassType) { if (_beforeTestHooksCache.TryGetValue(testClassType, out var cachedHooks)) @@ -57,6 +63,9 @@ public async ValueTask> return hooks; } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces and reflection")] + #endif private async Task>> BuildBeforeTestHooksAsync(Type type) { var hooksByType = new List<(Type type, List<(int order, int registrationIndex, Func hook)> hooks)>(); @@ -112,6 +121,9 @@ private async Task>> Bu return finalHooks; } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces and reflection")] + #endif public async ValueTask>> CollectAfterTestHooksAsync(Type testClassType) { if (_afterTestHooksCache.TryGetValue(testClassType, out var cachedHooks)) @@ -124,6 +136,9 @@ public async ValueTask> return hooks; } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces and reflection")] + #endif private async Task>> BuildAfterTestHooksAsync(Type type) { var hooksByType = new List<(Type type, List<(int order, int registrationIndex, Func hook)> hooks)>(); @@ -178,6 +193,9 @@ private async Task>> Bu return finalHooks; } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces and reflection")] + #endif public async ValueTask>> CollectBeforeEveryTestHooksAsync(Type testClassType) { if (_beforeEveryTestHooksCache.TryGetValue(testClassType, out var cachedHooks)) @@ -190,6 +208,9 @@ public async ValueTask> return hooks; } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces and reflection")] + #endif private async Task>> BuildBeforeEveryTestHooksAsync(Type type) { var allHooks = new List<(int order, int registrationIndex, Func hook)>(); @@ -208,6 +229,9 @@ private async Task>> Bu .ToList(); } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces and reflection")] + #endif public async ValueTask>> CollectAfterEveryTestHooksAsync(Type testClassType) { if (_afterEveryTestHooksCache.TryGetValue(testClassType, out var cachedHooks)) @@ -220,6 +244,9 @@ public async ValueTask> return hooks; } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces and reflection")] + #endif private async Task>> BuildAfterEveryTestHooksAsync(Type type) { var allHooks = new List<(int order, int registrationIndex, Func hook)>(); @@ -551,6 +578,9 @@ public ValueTask>>(hooks); } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces and reflection")] + #endif private async Task> CreateInstanceHookDelegateAsync(InstanceHookMethod hook) { // Process hook registration event receivers @@ -569,6 +599,9 @@ private async Task> CreateInstanceHoo }; } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces and reflection")] + #endif private async Task> CreateStaticHookDelegateAsync(StaticHookMethod hook) { // Process hook registration event receivers diff --git a/TUnit.Engine/Services/HookExecutor.cs b/TUnit.Engine/Services/HookExecutor.cs index a30eb270ef..a483651f3c 100644 --- a/TUnit.Engine/Services/HookExecutor.cs +++ b/TUnit.Engine/Services/HookExecutor.cs @@ -156,6 +156,9 @@ public async Task> ExecuteAfterClassHooksAsync( return exceptions; } + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Hook discovery uses reflection on methods and attributes")] + #endif public async Task ExecuteBeforeTestHooksAsync(AbstractExecutableTest test, CancellationToken cancellationToken) { var testClassType = test.Metadata.TestClassType; @@ -191,6 +194,9 @@ public async Task ExecuteBeforeTestHooksAsync(AbstractExecutableTest test, Cance } } + #if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Hook discovery uses reflection on methods and attributes")] + #endif public async Task ExecuteAfterTestHooksAsync(AbstractExecutableTest test, CancellationToken cancellationToken) { var testClassType = test.Metadata.TestClassType; diff --git a/TUnit.Engine/Services/ObjectRegistrationService.cs b/TUnit.Engine/Services/ObjectRegistrationService.cs index 55b45f8355..fb4bcdb4cd 100644 --- a/TUnit.Engine/Services/ObjectRegistrationService.cs +++ b/TUnit.Engine/Services/ObjectRegistrationService.cs @@ -27,6 +27,9 @@ public ObjectRegistrationService( /// Shared object bag for the test context. Must not be null. /// Method metadata for the test. Can be null. /// Test context events for tracking. Must not be null and must be unique per test permutation. + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Type comes from runtime objects that cannot be annotated")] + #endif public async Task RegisterObjectAsync( object instance, Dictionary objectBag, @@ -62,6 +65,9 @@ await _propertyInjectionService.InjectPropertiesIntoObjectAsync( /// Registers multiple objects (e.g., constructor/method arguments) in parallel. /// Used during test registration to prepare arguments without executing expensive operations. /// + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Type comes from runtime objects that cannot be annotated")] + #endif public async Task RegisterArgumentsAsync( object?[] arguments, Dictionary objectBag, @@ -91,6 +97,12 @@ public async Task RegisterArgumentsAsync( /// private bool RequiresPropertyInjection(object instance) { +#if NET6_0_OR_GREATER +#pragma warning disable IL2026 // Injectable property check uses reflection - acceptable during registration +#endif return PropertyInjectionCache.HasInjectableProperties(instance.GetType()); +#if NET6_0_OR_GREATER +#pragma warning restore IL2026 +#endif } } diff --git a/TUnit.Engine/Services/PropertyDataResolver.cs b/TUnit.Engine/Services/PropertyDataResolver.cs index df045a8a27..22fde98725 100644 --- a/TUnit.Engine/Services/PropertyDataResolver.cs +++ b/TUnit.Engine/Services/PropertyDataResolver.cs @@ -16,7 +16,9 @@ internal static class PropertyDataResolver /// /// Resolves data from a property's data source. /// - [UnconditionalSuppressMessage("Trimming", "IL2072", Justification = "Property types handled dynamically")] +#if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Property data resolution uses reflection on property types")] +#endif public static async Task ResolvePropertyDataAsync(PropertyInitializationContext context, DataSourceInitializer dataSourceInitializer, ObjectRegistrationService objectRegistrationService) { var dataSource = await GetInitializedDataSourceAsync(context, dataSourceInitializer); @@ -72,6 +74,9 @@ await objectRegistrationService.RegisterObjectAsync( /// Gets an initialized data source from the context. /// Ensures the data source is fully initialized (including property injection) before returning it. /// + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Type comes from runtime objects that cannot be annotated")] + #endif private static async Task GetInitializedDataSourceAsync(PropertyInitializationContext context, DataSourceInitializer dataSourceInitializer) { IDataSourceAttribute? dataSource = null; @@ -103,7 +108,9 @@ await objectRegistrationService.RegisterObjectAsync( /// /// Creates data generator metadata for the property. /// - [UnconditionalSuppressMessage("Trimming", "IL2072", Justification = "Property injection metadata")] +#if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Data generator metadata creation uses reflection on property types")] +#endif private static DataGeneratorMetadata CreateDataGeneratorMetadata( PropertyInitializationContext context, IDataSourceAttribute dataSource) @@ -158,10 +165,12 @@ private static DataGeneratorMetadata CreateDataGeneratorMetadata( /// /// Resolves value from data source arguments, handling tuples. /// - [UnconditionalSuppressMessage("Trimming", "IL2067", Justification = "Tuple types are created dynamically")] +#if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Value resolution may create tuple types dynamically")] +#endif private static object? ResolveValueFromArgs( - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] - Type propertyType, + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] + Type propertyType, object?[]? args) { return TupleValueResolver.ResolveTupleValue(propertyType, args); diff --git a/TUnit.Engine/Services/PropertyInitialization/Strategies/NestedPropertyStrategy.cs b/TUnit.Engine/Services/PropertyInitialization/Strategies/NestedPropertyStrategy.cs index 45be31469d..3adcb1570d 100644 --- a/TUnit.Engine/Services/PropertyInitialization/Strategies/NestedPropertyStrategy.cs +++ b/TUnit.Engine/Services/PropertyInitialization/Strategies/NestedPropertyStrategy.cs @@ -53,7 +53,13 @@ public async Task InitializePropertyAsync(PropertyInitializationContext context) } // Get the injection plan for this type +#if NET6_0_OR_GREATER +#pragma warning disable IL2026 // Injection plan creation uses reflection - acceptable during nested property handling +#endif var plan = PropertyInjectionCache.GetOrCreatePlan(propertyType); +#if NET6_0_OR_GREATER +#pragma warning restore IL2026 +#endif // Recursively inject properties into the nested object if (SourceRegistrar.IsEnabled) @@ -161,7 +167,13 @@ private PropertyInitializationContext CreateNestedContext( DataSource = dataSource, PropertyName = propertyName, PropertyType = property.PropertyType, +#if NET6_0_OR_GREATER +#pragma warning disable IL2026 // Property setter creation may use reflection - acceptable for init-only properties +#endif PropertySetter = PropertySetterFactory.CreateSetter(property), +#if NET6_0_OR_GREATER +#pragma warning restore IL2026 +#endif ObjectBag = parentContext.ObjectBag, MethodMetadata = parentContext.MethodMetadata, Events = parentContext.Events, diff --git a/TUnit.Engine/Services/PropertyInitialization/Strategies/ReflectionPropertyStrategy.cs b/TUnit.Engine/Services/PropertyInitialization/Strategies/ReflectionPropertyStrategy.cs index 8c4799dd13..2c42bd0d7c 100644 --- a/TUnit.Engine/Services/PropertyInitialization/Strategies/ReflectionPropertyStrategy.cs +++ b/TUnit.Engine/Services/PropertyInitialization/Strategies/ReflectionPropertyStrategy.cs @@ -30,7 +30,6 @@ public bool CanHandle(PropertyInitializationContext context) /// /// Initializes a property using reflection. /// - [UnconditionalSuppressMessage("Trimming", "IL2072", Justification = "Reflection mode support")] public async Task InitializePropertyAsync(PropertyInitializationContext context) { #if NET @@ -56,7 +55,13 @@ public async Task InitializePropertyAsync(PropertyInitializationContext context) else { // Step 1: Resolve data from the data source (execution-time resolution) +#if NET6_0_OR_GREATER +#pragma warning disable IL2026 // Property data resolution uses reflection - acceptable during property injection +#endif resolvedValue = await PropertyDataResolver.ResolvePropertyDataAsync(context, _dataSourceInitializer, _objectRegistrationService); +#if NET6_0_OR_GREATER +#pragma warning restore IL2026 +#endif if (resolvedValue == null) { return; diff --git a/TUnit.Engine/Services/PropertyInitialization/Strategies/SourceGeneratedPropertyStrategy.cs b/TUnit.Engine/Services/PropertyInitialization/Strategies/SourceGeneratedPropertyStrategy.cs index 068470813a..a65f9083da 100644 --- a/TUnit.Engine/Services/PropertyInitialization/Strategies/SourceGeneratedPropertyStrategy.cs +++ b/TUnit.Engine/Services/PropertyInitialization/Strategies/SourceGeneratedPropertyStrategy.cs @@ -45,7 +45,13 @@ public async Task InitializePropertyAsync(PropertyInitializationContext context) } else { +#if NET6_0_OR_GREATER +#pragma warning disable IL2026 // Property data resolution uses reflection - acceptable during property injection +#endif resolvedValue = await PropertyDataResolver.ResolvePropertyDataAsync(context, _dataSourceInitializer, _objectRegistrationService); +#if NET6_0_OR_GREATER +#pragma warning restore IL2026 +#endif if (resolvedValue == null) { return; diff --git a/TUnit.Engine/Services/PropertyInitializationOrchestrator.cs b/TUnit.Engine/Services/PropertyInitializationOrchestrator.cs index 87f93e11b4..246120279e 100644 --- a/TUnit.Engine/Services/PropertyInitializationOrchestrator.cs +++ b/TUnit.Engine/Services/PropertyInitializationOrchestrator.cs @@ -63,7 +63,9 @@ public async Task InitializePropertiesAsync( /// /// Initializes all properties for an instance using reflection. /// - [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "Reflection mode support")] +#if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Reflection-based property initialization uses PropertyInfo")] +#endif public async Task InitializePropertiesAsync( object instance, (PropertyInfo Property, IDataSourceAttribute DataSource)[] properties, @@ -86,6 +88,9 @@ public async Task InitializePropertiesAsync( /// /// Handles the complete initialization flow for an object with properties. /// + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Reflection-based property initialization uses PropertyInfo")] + #endif public async Task InitializeObjectWithPropertiesAsync( object instance, PropertyInjectionPlan plan, @@ -156,7 +161,13 @@ private PropertyInitializationContext CreateContext( DataSource = dataSource, PropertyName = property.Name, PropertyType = property.PropertyType, +#if NET6_0_OR_GREATER +#pragma warning disable IL2026 // Property setter creation may use reflection - acceptable for init-only properties +#endif PropertySetter = PropertySetterFactory.CreateSetter(property), +#if NET6_0_OR_GREATER +#pragma warning restore IL2026 +#endif ObjectBag = objectBag, MethodMetadata = methodMetadata, Events = events, diff --git a/TUnit.Engine/Services/PropertyInjectionService.cs b/TUnit.Engine/Services/PropertyInjectionService.cs index 3c239b64ae..037f215234 100644 --- a/TUnit.Engine/Services/PropertyInjectionService.cs +++ b/TUnit.Engine/Services/PropertyInjectionService.cs @@ -28,6 +28,9 @@ public void Initialize(ObjectRegistrationService objectRegistrationService) /// This ensures properties are only initialized when the test is about to run. /// Arguments are processed in parallel for better performance. /// + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Type comes from runtime objects that cannot be annotated")] + #endif public async Task InjectPropertiesIntoArgumentsAsync(object?[] arguments, Dictionary objectBag, MethodMetadata methodMetadata, TestContextEvents events) { if (arguments.Length == 0) @@ -63,6 +66,9 @@ public async Task InjectPropertiesIntoArgumentsAsync(object?[] arguments, Dictio /// Shared object bag for the test context. Must not be null. /// Method metadata for the test. Can be null. /// Test context events for tracking. Must not be null and must be unique per test permutation. + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Type comes from runtime objects that cannot be annotated")] + #endif public Task InjectPropertiesIntoObjectAsync(object instance, Dictionary objectBag, MethodMetadata? methodMetadata, TestContextEvents events) { if (objectBag == null) @@ -84,6 +90,9 @@ public Task InjectPropertiesIntoObjectAsync(object instance, Dictionary objectBag, MethodMetadata? methodMetadata, TestContextEvents events, ConcurrentDictionary visitedObjects) { if (instance == null) diff --git a/TUnit.Engine/Services/TestArgumentRegistrationService.cs b/TUnit.Engine/Services/TestArgumentRegistrationService.cs index 5698233ef3..9b6bfb0ba3 100644 --- a/TUnit.Engine/Services/TestArgumentRegistrationService.cs +++ b/TUnit.Engine/Services/TestArgumentRegistrationService.cs @@ -34,6 +34,9 @@ public TestArgumentRegistrationService(ObjectRegistrationService objectRegistrat /// Called when a test is registered. This is the correct time to register constructor and method arguments /// for proper reference counting and disposal tracking. /// + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Type comes from runtime objects that cannot be annotated")] + #endif public async ValueTask OnTestRegistered(TestRegisteredContext context) { var testContext = context.TestContext; @@ -57,7 +60,13 @@ await _objectRegistrationService.RegisterArgumentsAsync( // Register properties that will be injected into the test class await RegisterPropertiesAsync(testContext); +#if NET6_0_OR_GREATER +#pragma warning disable IL2026 // Trackable object discovery uses reflection - acceptable during test discovery +#endif _objectTracker.TrackObjects(testContext); +#if NET6_0_OR_GREATER +#pragma warning restore IL2026 +#endif } /// @@ -65,6 +74,9 @@ await _objectRegistrationService.RegisterArgumentsAsync( /// This ensures proper reference counting for all property-injected instances during discovery. /// Exceptions during data generation will be caught and associated with the test for reporting. /// + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Type comes from runtime objects that cannot be annotated")] + #endif private async ValueTask RegisterPropertiesAsync(TestContext testContext) { try diff --git a/TUnit.Engine/Services/TestExecution/TestCoordinator.cs b/TUnit.Engine/Services/TestExecution/TestCoordinator.cs index 3f87247b2a..f747c834dc 100644 --- a/TUnit.Engine/Services/TestExecution/TestCoordinator.cs +++ b/TUnit.Engine/Services/TestExecution/TestCoordinator.cs @@ -43,12 +43,18 @@ public TestCoordinator( _logger = logger; } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Test execution involves reflection for hooks and initialization")] + #endif public async Task ExecuteTestAsync(AbstractExecutableTest test, CancellationToken cancellationToken) { await _executionGuard.TryStartExecutionAsync(test.TestId, () => ExecuteTestInternalAsync(test, cancellationToken)); } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Test execution involves reflection for hooks and initialization")] + #endif private async Task ExecuteTestInternalAsync(AbstractExecutableTest test, CancellationToken cancellationToken) { try @@ -91,7 +97,13 @@ await RetryHelper.ExecuteWithRetry(test.Context, async () => try { +#if NET6_0_OR_GREATER +#pragma warning disable IL2026 // Test initialization may use reflection - acceptable during test execution +#endif await _testInitializer.InitializeTest(test, cancellationToken); +#if NET6_0_OR_GREATER +#pragma warning restore IL2026 +#endif test.Context.RestoreExecutionContext(); await _testExecutor.ExecuteAsync(test, cancellationToken); } @@ -116,7 +128,13 @@ await RetryHelper.ExecuteWithRetry(test.Context, async () => try { +#if NET6_0_OR_GREATER +#pragma warning disable IL2026 // Test disposal may use reflection - acceptable during test cleanup +#endif await TestExecutor.DisposeTestInstance(test); +#if NET6_0_OR_GREATER +#pragma warning restore IL2026 +#endif } catch (Exception disposeEx) { diff --git a/TUnit.Engine/Services/TestFilterService.cs b/TUnit.Engine/Services/TestFilterService.cs index ab292e1c8d..df5d9678bb 100644 --- a/TUnit.Engine/Services/TestFilterService.cs +++ b/TUnit.Engine/Services/TestFilterService.cs @@ -62,6 +62,9 @@ public IReadOnlyCollection FilterTests(ITestExecutionFil return filteredTests; } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Type comes from runtime objects that cannot be annotated")] + #endif private async Task RegisterTest(AbstractExecutableTest test) { var discoveredTest = new DiscoveredTest @@ -96,6 +99,9 @@ private async Task RegisterTest(AbstractExecutableTest test) } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Type comes from runtime objects that cannot be annotated")] + #endif public async Task RegisterTestsAsync(IEnumerable tests) { foreach (var test in tests) diff --git a/TUnit.Engine/Services/TestGenericTypeResolver.cs b/TUnit.Engine/Services/TestGenericTypeResolver.cs index 7b5868a854..af6e7b56c0 100644 --- a/TUnit.Engine/Services/TestGenericTypeResolver.cs +++ b/TUnit.Engine/Services/TestGenericTypeResolver.cs @@ -18,6 +18,9 @@ internal sealed class TestGenericTypeResolver /// The test metadata containing generic type information /// The runtime test data containing actual arguments /// A result containing resolved generic types for both class and method + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Type mapping inference uses Type.GetInterfaces and reflection")] + #endif public static TestGenericTypeResolution Resolve(TestMetadata metadata, TestBuilder.TestData testData) { var result = new TestGenericTypeResolution(); @@ -52,6 +55,9 @@ public static TestGenericTypeResolution Resolve(TestMetadata metadata, TestBuild return result; } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Type mapping inference uses Type.GetInterfaces and reflection")] + #endif private static Type[] ResolveClassGenericArguments( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type genericClassType, GenericTypeInfo genericTypeInfo, @@ -114,6 +120,9 @@ private static Type[] ResolveClassGenericArguments( return resolvedTypes; } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Type mapping inference uses Type.GetInterfaces and reflection")] + #endif private static Type[] ResolveMethodGenericArguments( MethodMetadata methodMetadata, GenericMethodInfo genericMethodInfo, @@ -406,6 +415,9 @@ private static Type[] ResolveMethodGenericArguments( return resolvedTypesFromMapping; } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Type mapping inference uses Type.GetInterfaces and reflection")] + #endif private static bool TryInferTypesFromArguments( ParameterInfo[] parameters, object?[] arguments, @@ -429,6 +441,9 @@ private static bool TryInferTypesFromArguments( return true; } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Type mapping inference uses Type.GetInterfaces and reflection")] + #endif private static void InferTypeMapping( Type parameterType, Type argumentType, @@ -442,9 +457,12 @@ private static void InferTypeMapping( } } +#if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Type mapping inference uses Type.GetInterfaces and reflection")] +#endif private static bool TryInferTypeMapping( - Type parameterType, - Type argumentType, + Type parameterType, + Type argumentType, Dictionary typeMapping) { // Direct generic parameter @@ -505,10 +523,7 @@ private static bool TryInferTypeMapping( if (parameterType is { IsGenericType: true, IsInterface: true }) { // Check if argument type implements the parameter interface - #pragma warning disable IL2070 // Type.GetInterfaces() requires preserved interfaces - // Note: Interface discovery for generic type resolution. AOT scenarios should use concrete types or source-generated type mappings. var implementedInterfaces = argumentType.GetInterfaces(); - #pragma warning restore IL2070 foreach (var implementedInterface in implementedInterfaces) { if (implementedInterface.IsGenericType) diff --git a/TUnit.Engine/Services/TestRegistry.cs b/TUnit.Engine/Services/TestRegistry.cs index 14ffac453c..87ed67508e 100644 --- a/TUnit.Engine/Services/TestRegistry.cs +++ b/TUnit.Engine/Services/TestRegistry.cs @@ -1,4 +1,4 @@ -using System.Collections.Concurrent; +using System.Collections.Concurrent; using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; using System.Reflection; @@ -32,6 +32,7 @@ public TestRegistry(TestBuilderPipeline testBuilderPipeline, _sessionCancellationToken = sessionCancellationToken; } [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("Adding dynamic tests requires runtime compilation and reflection which are not supported in native AOT scenarios.")] + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Dynamic test metadata creation uses reflection")] public async Task AddDynamicTest<[DynamicallyAccessedMembers( DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors @@ -65,8 +66,10 @@ public TestRegistry(TestBuilderPipeline testBuilderPipeline, await ProcessPendingDynamicTests(); } - [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", - Justification = "Dynamic tests are opt-in and users are warned via RequiresDynamicCode on AddDynamicTest method")] +#if NET6_0_OR_GREATER + [RequiresDynamicCode("Dynamic test processing uses expression compilation")] + [RequiresUnreferencedCode("Dynamic test metadata creation uses reflection")] +#endif private async Task ProcessPendingDynamicTests() { var testsToProcess = new List(); @@ -104,6 +107,7 @@ private async Task ProcessPendingDynamicTests() } [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("Dynamic tests require runtime compilation of lambda expressions and are not supported in native AOT scenarios.")] + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Method metadata creation uses reflection on parameters and types")] private async Task CreateMetadataFromDynamicDiscoveryResult(DynamicDiscoveryResult result) { if (result.TestClassType == null || result.TestMethod == null) diff --git a/TUnit.Engine/TUnitInitializer.cs b/TUnit.Engine/TUnitInitializer.cs index 5732b88467..09e8bdde0b 100644 --- a/TUnit.Engine/TUnitInitializer.cs +++ b/TUnit.Engine/TUnitInitializer.cs @@ -11,6 +11,10 @@ namespace TUnit.Engine; internal class TUnitInitializer(ICommandLineOptions commandLineOptions) { + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Hook discovery uses reflection to scan assemblies and types")] + [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("Hook delegate creation requires dynamic code generation")] + #endif public void Initialize(ExecuteRequestContext context) { ConfigureGlobalExceptionHandlers(context); @@ -34,8 +38,10 @@ private bool IsReflectionMode() return !SourceRegistrar.IsEnabled; } - [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code")] - [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling")] +#if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Hook discovery uses reflection to scan assemblies and types")] + [RequiresDynamicCode("Hook delegate creation requires dynamic code generation")] +#endif private void DiscoverHooksViaReflection() { ReflectionHookDiscoveryService.DiscoverHooks(); diff --git a/TUnit.Engine/TestDiscoveryService.cs b/TUnit.Engine/TestDiscoveryService.cs index bb707e77e8..ad230e3453 100644 --- a/TUnit.Engine/TestDiscoveryService.cs +++ b/TUnit.Engine/TestDiscoveryService.cs @@ -48,6 +48,10 @@ public TestDiscoveryService(TestExecutor testExecutor, TestBuilderPipeline testB _testFilterService = testFilterService; } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces and reflection")] + [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("Generic test instantiation requires MakeGenericType")] + #endif public async Task DiscoverTests(string testSessionId, ITestExecutionFilter? filter, CancellationToken cancellationToken, bool isForExecution) { await _testExecutor.ExecuteBeforeTestDiscoveryHooksAsync(cancellationToken).ConfigureAwait(false); @@ -130,6 +134,10 @@ public async Task DiscoverTests(string testSessionId, ITest } /// Streams test discovery for parallel discovery and execution + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Assembly scanning uses dynamic type discovery and reflection")] + [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("Generic test instantiation requires MakeGenericType")] + #endif private async IAsyncEnumerable DiscoverTestsStreamAsync( string testSessionId, [EnumeratorCancellation] CancellationToken cancellationToken = default) @@ -159,6 +167,10 @@ private async IAsyncEnumerable DiscoverTestsStreamAsync( /// /// Simplified streaming test discovery without channels - matches source generation approach /// + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces and reflection")] + [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("Generic test instantiation requires MakeGenericType")] + #endif public async IAsyncEnumerable DiscoverTestsFullyStreamingAsync( string testSessionId, ITestExecutionFilter? filter, diff --git a/TUnit.Engine/TestExecutor.cs b/TUnit.Engine/TestExecutor.cs index f4749de64f..a539649bec 100644 --- a/TUnit.Engine/TestExecutor.cs +++ b/TUnit.Engine/TestExecutor.cs @@ -51,6 +51,9 @@ await _beforeHookTaskCache.GetOrCreateBeforeTestSessionTask(() => /// Creates a test executor delegate that wraps the provided executor with hook orchestration. /// Uses focused services that follow SRP to manage lifecycle and execution. /// + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces and reflection")] + #endif public async Task ExecuteAsync(AbstractExecutableTest executableTest, CancellationToken cancellationToken) { @@ -242,8 +245,9 @@ public IContextProvider GetContextProvider() return _contextProvider; } - [System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessage("Trimming", "IL2075:Type.GetProperty does not have matching annotations", - Justification = "Only used for specific test class DisposalRegressionTests")] +#if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Test disposal may use reflection on properties")] +#endif internal static async Task DisposeTestInstance(AbstractExecutableTest test) { // Dispose the test instance if it's disposable diff --git a/TUnit.Engine/TestInitializer.cs b/TUnit.Engine/TestInitializer.cs index 09e5859366..92e92f4c16 100644 --- a/TUnit.Engine/TestInitializer.cs +++ b/TUnit.Engine/TestInitializer.cs @@ -20,6 +20,9 @@ public TestInitializer(EventReceiverOrchestrator eventReceiverOrchestrator, _objectTracker = objectTracker; } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Object tracking may use reflection on properties")] + #endif public async Task InitializeTest(AbstractExecutableTest test, CancellationToken cancellationToken) { var testClassInstance = test.Context.TestDetails.ClassInstance; diff --git a/TUnit.Engine/TestSessionCoordinator.cs b/TUnit.Engine/TestSessionCoordinator.cs index ecada84098..4e24549121 100644 --- a/TUnit.Engine/TestSessionCoordinator.cs +++ b/TUnit.Engine/TestSessionCoordinator.cs @@ -38,6 +38,11 @@ public TestSessionCoordinator(EventReceiverOrchestrator eventReceiverOrchestrato _testScheduler = testScheduler; } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Static property initialization uses reflection in reflection mode")] + [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("Data source initialization may require dynamic code generation")] +#pragma warning disable IL2046, IL3051 // Interface implementation - cannot add attributes to match called method requirements + #endif public async Task ExecuteTests( IEnumerable tests, ITestExecutionFilter? filter, @@ -61,6 +66,9 @@ public async Task ExecuteTests( } } } + #if NET6_0_OR_GREATER +#pragma warning restore IL2046, IL3051 + #endif private void InitializeEventReceivers(List testList, CancellationToken cancellationToken) { @@ -68,6 +76,10 @@ private void InitializeEventReceivers(List testList, Can _eventReceiverOrchestrator.InitializeTestCounts(testContexts); } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Static property initialization uses reflection in reflection mode")] + [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("Data source initialization may require dynamic code generation")] + #endif private async Task PrepareTestOrchestrator(List testList, CancellationToken cancellationToken) { // Register all tests upfront so orchestrator knows total counts per class/assembly for lifecycle management @@ -76,6 +88,10 @@ private async Task PrepareTestOrchestrator(List testList await InitializeStaticPropertiesAsync(cancellationToken); } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Static property initialization uses reflection in reflection mode")] + [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("Data source initialization may require dynamic code generation")] + #endif private async Task InitializeStaticPropertiesAsync(CancellationToken cancellationToken) { try @@ -101,6 +117,9 @@ private async Task InitializeStaticPropertiesAsync(CancellationToken cancellatio } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Test execution involves reflection for hooks and initialization")] + #endif private async Task ExecuteTestsCore(List testList, CancellationToken cancellationToken) { // Combine cancellation tokens diff --git a/TUnit.Engine/Utilities/ScopedAttributeFilter.cs b/TUnit.Engine/Utilities/ScopedAttributeFilter.cs index f16a989a2d..d546ad4bd5 100644 --- a/TUnit.Engine/Utilities/ScopedAttributeFilter.cs +++ b/TUnit.Engine/Utilities/ScopedAttributeFilter.cs @@ -14,8 +14,9 @@ internal static class ScopedAttributeFilter /// The type of objects to filter /// The collection of items to filter /// A filtered collection with only one instance per scoped attribute type - [UnconditionalSuppressMessage("Trimming", "IL2075:UnrecognizedReflectionPattern", - Justification = "IScopedAttribute types are preserved by the source generator")] +#if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces and reflection")] +#endif public static List FilterScopedAttributes(IEnumerable items) where T : class { var result = new List(); @@ -63,10 +64,9 @@ public static List FilterScopedAttributes(IEnumerable items) where T : /// /// Checks if a type implements IScopedAttribute /// - [UnconditionalSuppressMessage("Trimming", "IL2070:UnrecognizedReflectionPattern", - Justification = "IScopedAttribute types are preserved by the source generator")] - [UnconditionalSuppressMessage("Trimming", "IL2075:UnrecognizedReflectionPattern", - Justification = "IScopedAttribute types are preserved by the source generator")] +#if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Interface checking uses Type.GetInterfaces")] +#endif public static bool IsScopedAttribute(Type type) { return type.GetInterfaces() @@ -76,8 +76,9 @@ public static bool IsScopedAttribute(Type type) /// /// Gets the scoped attribute type from an object that implements IScopedAttribute /// - [UnconditionalSuppressMessage("Trimming", "IL2075:UnrecognizedReflectionPattern", - Justification = "IScopedAttribute types are preserved by the source generator")] +#if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Scoped attribute type extraction uses Type.GetInterfaces")] +#endif public static Type? GetScopedAttributeType(object? obj) { if (obj == null) diff --git a/TUnit.Playwright/WorkerAwareTest.cs b/TUnit.Playwright/WorkerAwareTest.cs index 2291ce1616..9da66688bf 100644 --- a/TUnit.Playwright/WorkerAwareTest.cs +++ b/TUnit.Playwright/WorkerAwareTest.cs @@ -69,6 +69,9 @@ protected bool TestOk(TestContext testContext) return testContext.Result?.State is TestState.Passed or TestState.Skipped; } + #if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Type comes from runtime objects that cannot be annotated")] + #endif public ValueTask OnTestRegistered(TestRegisteredContext context) { if (UseDefaultParallelLimiter) diff --git a/build_output.txt b/build_output.txt index 66bebd3b99..6c5e557345 100644 --- a/build_output.txt +++ b/build_output.txt @@ -1,6 +1,355 @@ -MSBUILD : error MSB1008: Only one project can be specified. - Full command line: 'C:\Program Files\dotnet\sdk\9.0.302\MSBuild.dll -maxcpucount -verbosity:m -tlp:default=auto -nologo -restore -consoleloggerparameters:Summary -target:Rebuild p:TreatWarningsAsErrors=false 2 -distributedlogger:Microsoft.DotNet.Tools.MSBuild.MSBuildLogger,C:\Program Files\dotnet\sdk\9.0.302\dotnet.dll*Microsoft.DotNet.Tools.MSBuild.MSBuildForwardingLogger,C:\Program Files\dotnet\sdk\9.0.302\dotnet.dll' - Switches appended by response files: -Switch: 2 + Determining projects to restore... + All projects are up-to-date for restore. + TUnit.Core -> C:\git\TUnit\TUnit.Core\bin\Release\netstandard2.0\TUnit.Core.dll + TUnit.Core -> C:\git\TUnit\TUnit.Core\bin\Release\net8.0\TUnit.Core.dll + TUnit.Core -> C:\git\TUnit\TUnit.Core\bin\Release\net9.0\TUnit.Core.dll + TUnit.Engine -> C:\git\TUnit\TUnit.Engine\bin\Release\netstandard2.0\TUnit.Engine.dll +C:\git\TUnit\TUnit.Engine\Building\TestDataCollectorFactory.cs(48,30): error IL3050: Using member 'TUnit.Engine.Building.Collectors.AotTestDataCollector.CollectTestsAsync(String)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Generic test instantiation requires MakeGenericType. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Building\TestDataCollectorFactory.cs(48,30): error IL2026: Using member 'TUnit.Engine.Building.Collectors.AotTestDataCollector.CollectTestsAsync(String)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Assembly scanning uses dynamic type discovery and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilderPipeline.cs(60,39): error IL3050: Using member 'TUnit.Engine.Building.Interfaces.ITestDataCollector.CollectTestsAsync(String)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Generic test instantiation requires MakeGenericType. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilderPipeline.cs(60,39): error IL2026: Using member 'TUnit.Engine.Building.Interfaces.ITestDataCollector.CollectTestsAsync(String)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Assembly scanning uses dynamic type discovery and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilderPipeline.cs(74,39): error IL3050: Using member 'TUnit.Engine.Building.Interfaces.ITestDataCollector.CollectTestsAsync(String)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Generic test instantiation requires MakeGenericType. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilderPipeline.cs(74,39): error IL2026: Using member 'TUnit.Engine.Building.Interfaces.ITestDataCollector.CollectTestsAsync(String)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Assembly scanning uses dynamic type discovery and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilderPipeline.cs(77,30): error IL2026: Using member 'TUnit.Engine.Building.TestBuilderPipeline.BuildTestsFromSingleMetadataAsync(TestMetadata)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Scoped attribute filtering uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilderPipeline.cs(99,38): error IL2026: Using member 'TUnit.Engine.Building.TestBuilderPipeline.GenerateDynamicTests(TestMetadata)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Scoped attribute filtering uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilderPipeline.cs(102,34): error IL2026: Using member 'TUnit.Engine.Building.Interfaces.ITestBuilder.BuildTestsFromMetadataAsync(TestMetadata)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Scoped attribute filtering uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Building\Collectors\AotTestDataCollector.cs(100,42): error IL2026: Using member 'TUnit.Engine.Building.Collectors.AotTestDataCollector.CreateMetadataFromDynamicDiscoveryResult(DynamicDiscoveryResult)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Method extraction from expressions uses reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\TUnitInitializer.cs(23,13): error IL3050: Using member 'TUnit.Engine.TUnitInitializer.DiscoverHooksViaReflection()' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Hook delegate creation requires dynamic code generation. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\TUnitInitializer.cs(23,13): error IL2026: Using member 'TUnit.Engine.TUnitInitializer.DiscoverHooksViaReflection()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Hook discovery uses reflection to scan assemblies and types. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\TestSessionCoordinator.cs(76,15): error IL2026: Using member 'TUnit.Engine.TestSessionCoordinator.InitializeStaticPropertiesAsync(CancellationToken)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Static property initialization uses reflection in reflection mode. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\TestSessionCoordinator.cs(96,23): error IL3050: Using member 'TUnit.Core.StaticPropertyReflectionInitializer.InitializeAllStaticPropertiesAsync()' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Data source initialization may require dynamic code generation. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilder.cs(652,13): error IL3050: Using member 'TUnit.Engine.Discovery.ReflectionHookDiscoveryService.DiscoverInstanceHooksForType(Type)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Hook registration may involve dynamic delegate creation. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilder.cs(652,13): error IL2026: Using member 'TUnit.Engine.Discovery.ReflectionHookDiscoveryService.DiscoverInstanceHooksForType(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Hook discovery uses reflection on methods and attributes. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Services\TestRegistry.cs(148,30): error IL2026: Using member 'TUnit.Engine.Building.ReflectionMetadataBuilder.CreateMethodMetadata(Type, MethodInfo)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Method metadata creation uses reflection on parameters and types. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Services\TestRegistry.cs(153,34): error IL2026: Using member 'TUnit.Core.PropertySourceRegistry.DiscoverInjectableProperties(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Reflection discovery is used when source-generated metadata is not available. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(319,36): error IL2026: Using member 'System.Reflection.Assembly.GetReferencedAssemblies()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Assembly references might be removed. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilder.cs(1116,34): error IL2026: Using member 'TUnit.Engine.Utilities.ScopedAttributeFilter.FilterScopedAttributes(IEnumerable)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Scoped attribute filtering uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilder.cs(1258,41): error IL2026: Using member 'TUnit.Engine.Building.TestBuilder.TryInferClassGenericsFromDataSources(TestMetadata)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Generic type inference uses reflection on data sources and parameters. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(904,35): error IL3050: Using member 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateInstanceFactory(Type)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Generic type instantiation uses MakeGenericType and Activator. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(905,31): error IL3050: Using member 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateTestInvoker(Type, MethodInfo)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Generic method instantiation uses MakeGenericMethod. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(904,35): error IL2026: Using member 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateInstanceFactory(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Instance creation uses reflection and Activator.CreateInstance. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(905,31): error IL2026: Using member 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateTestInvoker(Type, MethodInfo)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Test invocation uses reflection and MethodInfo.Invoke. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(908,34): error IL2026: Using member 'TUnit.Engine.Building.ReflectionMetadataBuilder.CreateMethodMetadata(Type, MethodInfo)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Method metadata creation uses reflection on parameters and types. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(909,35): error IL2026: Using member 'TUnit.Engine.Discovery.ReflectionGenericTypeResolver.ExtractGenericTypeInfo(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Generic type info extraction uses reflection on type parameters. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(910,37): error IL2026: Using member 'TUnit.Engine.Discovery.ReflectionGenericTypeResolver.ExtractGenericMethodInfo(MethodInfo)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Generic method info extraction uses reflection on method parameters. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(913,38): error IL2026: Using member 'TUnit.Core.PropertySourceRegistry.DiscoverInjectableProperties(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Reflection discovery is used when source-generated metadata is not available. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1139,30): error IL2026: Using member 'TUnit.Engine.Building.ReflectionMetadataBuilder.CreateMethodMetadata(Type, MethodInfo)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Method metadata creation uses reflection on parameters and types. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Services\TestRegistry.cs(65,15): error IL2026: Using member 'TUnit.Engine.Services.TestRegistry.ProcessPendingDynamicTests()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Dynamic test metadata creation uses reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Services\TestGenericTypeResolver.cs(422,22): error IL2026: Using member 'TUnit.Engine.Services.TestGenericTypeResolver.TryInferTypeMapping(Type, Type, Dictionary)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Type mapping inference uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Services\TestGenericTypeResolver.cs(438,14): error IL2026: Using member 'TUnit.Engine.Services.TestGenericTypeResolver.TryInferTypeMapping(Type, Type, Dictionary)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Type mapping inference uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1105,13): error IL2026: Using member 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CollectTestsAsync(String)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Assembly scanning uses dynamic type discovery and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1105,13): error IL2026: Using member 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CollectTestsStreamingAsync(String, CancellationToken)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Reflection-based test discovery requires dynamic access to types, methods, and attributes. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1052,27): error IL2070: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethods(BindingFlags)'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.HasTestMethods(Type)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1160,13): error IL2067: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.NonPublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.MethodMetadata.Type.init'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateDummyMethodMetadata(Type, String)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(198,34): error IL2070: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethods(BindingFlags)'. The parameter 't' of method 'lambda expression' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(198,34): error IL2075: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethods(BindingFlags)'. The return value of method 'System.Type.BaseType.get' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1164,17): error IL2067: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.NonPublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.ClassMetadata.Type.init'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateDummyMethodMetadata(Type, String)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1135,13): error IL2067: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.TestMetadata.TestClassType.init'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateFailedTestMetadata(Type, MethodInfo, Exception)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1139,30): error IL2067: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.NonPublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Engine.Building.ReflectionMetadataBuilder.CreateMethodMetadata(Type, MethodInfo)'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateFailedTestMetadata(Type, MethodInfo, Exception)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1396,29): error IL2070: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.Interfaces' in call to 'System.Type.GetInterfaces()'. The parameter 'argType' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.IsCovariantCompatible(Type, Type)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1324,39): error IL2070: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.Interfaces' in call to 'System.Type.GetInterfaces()'. The parameter 'argType' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.InferGenericTypeMapping(Type, Type, Dictionary)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1345,35): error IL2070: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.Interfaces' in call to 'System.Type.GetInterfaces()'. The parameter 'argType' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.InferGenericTypeMapping(Type, Type, Dictionary)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1834,42): error IL3050: Using member 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateMetadataFromDynamicDiscoveryResult(DynamicDiscoveryResult)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Expression compilation is used for dynamic test invocation. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1834,42): error IL2026: Using member 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateMetadataFromDynamicDiscoveryResult(DynamicDiscoveryResult)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Dynamic test metadata creation uses reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(893,50): error IL2067: 'testClass' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.NonPublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Engine.Discovery.ReflectionTestMetadata.ReflectionTestMetadata(Type, MethodInfo)'. The parameter 'testClass' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.BuildTestMetadata(Type, MethodInfo, Object[])' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(896,17): error IL2067: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.TestMetadata.TestClassType.init'. The parameter 'testClass' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.BuildTestMetadata(Type, MethodInfo, Object[])' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(896,17): error IL2072: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.TestMetadata.TestClassType.init'. The return value of method 'System.Type.BaseType.get' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(903,39): error IL2067: 'testClass' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Engine.Discovery.ReflectionAttributeExtractor.ExtractPropertyDataSources(Type)'. The parameter 'testClass' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.BuildTestMetadata(Type, MethodInfo, Object[])' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(904,35): error IL2067: 'testClass' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors' in call to 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateInstanceFactory(Type)'. The parameter 'testClass' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.BuildTestMetadata(Type, MethodInfo, Object[])' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(908,34): error IL2067: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.NonPublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Engine.Building.ReflectionMetadataBuilder.CreateMethodMetadata(Type, MethodInfo)'. The parameter 'testClass' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.BuildTestMetadata(Type, MethodInfo, Object[])' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(913,38): error IL2067: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicFields', 'DynamicallyAccessedMemberTypes.NonPublicFields', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.PropertySourceRegistry.DiscoverInjectableProperties(Type)'. The parameter 'testClass' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.BuildTestMetadata(Type, MethodInfo, Object[])' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(2151,58): error IL2077: 'testClassType' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors' in call to 'TUnit.Core.Helpers.ClassConstructorHelper.TryCreateInstanceWithClassConstructor(IReadOnlyList, Type, String, TestContext)'. The field 'TUnit.Engine.Discovery.ReflectionTestDataCollector.DynamicReflectionTestMetadata._testClass' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(2090,30): error IL2026: Using member 'TUnit.Engine.Building.ReflectionMetadataBuilder.CreateMethodMetadata(Type, MethodInfo)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Method metadata creation uses reflection on parameters and types. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(2086,13): error IL2067: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.TestMetadata.TestClassType.init'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateFailedTestMetadataForDynamicBuilder(Type, MethodInfo, Exception)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(2090,30): error IL2067: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.NonPublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Engine.Building.ReflectionMetadataBuilder.CreateMethodMetadata(Type, MethodInfo)'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateFailedTestMetadataForDynamicBuilder(Type, MethodInfo, Exception)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(743,13): error IL2067: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.NonPublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.MethodMetadata.Type.init'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionHookDiscoveryService.CreateMethodMetadata(Type, MethodInfo)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(747,17): error IL2067: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.NonPublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.ClassMetadata.Type.init'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionHookDiscoveryService.CreateMethodMetadata(Type, MethodInfo)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(758,61): error IL2072: 'Type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.ParameterMetadata.ParameterMetadata(Type)'. The return value of method 'System.Reflection.ParameterInfo.ParameterType.get' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(822,57): error IL2067: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicParameterlessConstructor' in call to 'System.Activator.CreateInstance(Type)'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionHookDiscoveryService.CreateHookDelegate(Type, MethodInfo)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(883,40): error IL2072: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicParameterlessConstructor' in call to 'System.Activator.CreateInstance(Type)'. The return value of method 'System.Reflection.PropertyInfo.GetValue(Object)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(664,13): error IL2067: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'TUnit.Core.Hooks.InstanceHookMethod.InitClassType.init'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionHookDiscoveryService.RegisterInstanceAfterHook(Type, MethodInfo, Int32)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(643,13): error IL2067: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'TUnit.Core.Hooks.InstanceHookMethod.InitClassType.init'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionHookDiscoveryService.RegisterInstanceBeforeHook(Type, MethodInfo, Int32)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(208,36): error IL2026: Using member 'System.Reflection.Assembly.GetReferencedAssemblies()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Assembly references might be removed. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(231,25): error IL2026: Using member 'System.Reflection.Assembly.GetTypes()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Types might be removed. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Framework\TUnitTestFramework.cs(111,18): error IL3050: Using member 'TUnit.Engine.Framework.TUnitServiceProvider.TUnitServiceProvider(IExtension, ExecuteRequestContext, ITestExecutionFilter, IMessageBus, IServiceProvider, ITestFrameworkCapabilities)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Reflection mode test discovery uses dynamic code generation. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Framework\TUnitTestFramework.cs(111,18): error IL2026: Using member 'TUnit.Engine.Framework.TUnitServiceProvider.TUnitServiceProvider(IExtension, ExecuteRequestContext, ITestExecutionFilter, IMessageBus, IServiceProvider, ITestFrameworkCapabilities)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Test data collector selection may use reflection-based discovery. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(259,27): error IL2075: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethods(BindingFlags)'. The return value of method 'System.Collections.Generic.List.Enumerator.Current.get' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Services\DataSourceInitializer.cs(76,54): error IL2026: Using member 'TUnit.Core.PropertyInjection.PropertyInjectionCache.HasInjectableProperties(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Type comes from runtime objects that cannot be annotated. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Services\DataSourceInitializer.cs(78,23): error IL2026: Using member 'TUnit.Engine.Services.PropertyInjectionService.InjectPropertiesIntoObjectAsync(Object, Dictionary, MethodMetadata, TestContextEvents)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Type comes from runtime objects that cannot be annotated. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Services\ObjectRegistrationService.cs(53,19): error IL2026: Using member 'TUnit.Engine.Services.PropertyInjectionService.InjectPropertiesIntoObjectAsync(Object, Dictionary, MethodMetadata, TestContextEvents)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Type comes from runtime objects that cannot be annotated. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Services\HookCollectionService.cs(39,19): error IL2026: Using member 'TUnit.Engine.Services.EventReceiverOrchestrator.InvokeHookRegistrationEventReceiversAsync(HookRegisteredContext, CancellationToken)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Scoped attribute filtering uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Services\EventReceiverOrchestrator.cs(106,33): error IL2026: Using member 'TUnit.Engine.Utilities.ScopedAttributeFilter.FilterScopedAttributes(IEnumerable)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Scoped attribute filtering uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Services\EventReceiverOrchestrator.cs(142,33): error IL2026: Using member 'TUnit.Engine.Utilities.ScopedAttributeFilter.FilterScopedAttributes(IEnumerable)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Scoped attribute filtering uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Services\PropertyInitializationOrchestrator.cs(108,19): error IL2026: Using member 'TUnit.Engine.Services.PropertyInitializationOrchestrator.InitializePropertiesAsync(Object, (PropertyInfo Property, IDataSourceAttribute DataSource)[], Dictionary, MethodMetadata, TestContextEvents, ConcurrentDictionary)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Reflection-based property initialization uses PropertyInfo. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Services\EventReceiverOrchestrator.cs(176,33): error IL2026: Using member 'TUnit.Engine.Utilities.ScopedAttributeFilter.FilterScopedAttributes(IEnumerable)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Scoped attribute filtering uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Services\DataSourceInitializer.cs(132,20): error IL2026: Using member 'TUnit.Core.PropertyInjection.PropertyInjectionCache.GetOrCreatePlan(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Type comes from runtime objects that cannot be annotated. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Services\DataSourceInitializer.cs(147,21): error IL2026: Using member 'TUnit.Core.PropertyInjection.PropertyInjectionCache.HasInjectableProperties(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Type comes from runtime objects that cannot be annotated. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Services\DataSourceInitializer.cs(158,21): error IL2026: Using member 'TUnit.Core.PropertyInjection.PropertyInjectionCache.HasInjectableProperties(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Type comes from runtime objects that cannot be annotated. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Services\DataSourceInitializer.cs(184,21): error IL2026: Using member 'TUnit.Core.PropertyInjection.PropertyInjectionCache.HasInjectableProperties(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Type comes from runtime objects that cannot be annotated. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Services\DataSourceInitializer.cs(195,21): error IL2026: Using member 'TUnit.Core.PropertyInjection.PropertyInjectionCache.HasInjectableProperties(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Type comes from runtime objects that cannot be annotated. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Services\EventReceiverOrchestrator.cs(192,33): error IL2026: Using member 'TUnit.Engine.Utilities.ScopedAttributeFilter.FilterScopedAttributes(IEnumerable)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Scoped attribute filtering uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Building\TestDataCollectorFactory.cs(48,30): error IL2026: Using member 'TUnit.Engine.Building.Collectors.AotTestDataCollector.CollectTestsAsync(String)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Assembly scanning uses dynamic type discovery and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Building\TestDataCollectorFactory.cs(48,30): error IL3050: Using member 'TUnit.Engine.Building.Collectors.AotTestDataCollector.CollectTestsAsync(String)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Generic test instantiation requires MakeGenericType. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilderPipeline.cs(60,39): error IL2026: Using member 'TUnit.Engine.Building.Interfaces.ITestDataCollector.CollectTestsAsync(String)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Assembly scanning uses dynamic type discovery and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilderPipeline.cs(60,39): error IL3050: Using member 'TUnit.Engine.Building.Interfaces.ITestDataCollector.CollectTestsAsync(String)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Generic test instantiation requires MakeGenericType. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilderPipeline.cs(74,39): error IL2026: Using member 'TUnit.Engine.Building.Interfaces.ITestDataCollector.CollectTestsAsync(String)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Assembly scanning uses dynamic type discovery and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilderPipeline.cs(74,39): error IL3050: Using member 'TUnit.Engine.Building.Interfaces.ITestDataCollector.CollectTestsAsync(String)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Generic test instantiation requires MakeGenericType. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilderPipeline.cs(77,30): error IL2026: Using member 'TUnit.Engine.Building.TestBuilderPipeline.BuildTestsFromSingleMetadataAsync(TestMetadata)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Scoped attribute filtering uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Building\Collectors\AotTestDataCollector.cs(100,42): error IL2026: Using member 'TUnit.Engine.Building.Collectors.AotTestDataCollector.CreateMetadataFromDynamicDiscoveryResult(DynamicDiscoveryResult)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Method extraction from expressions uses reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilderPipeline.cs(99,38): error IL2026: Using member 'TUnit.Engine.Building.TestBuilderPipeline.GenerateDynamicTests(TestMetadata)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Scoped attribute filtering uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilderPipeline.cs(102,34): error IL2026: Using member 'TUnit.Engine.Building.Interfaces.ITestBuilder.BuildTestsFromMetadataAsync(TestMetadata)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Scoped attribute filtering uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\TUnitInitializer.cs(23,13): error IL2026: Using member 'TUnit.Engine.TUnitInitializer.DiscoverHooksViaReflection()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Hook discovery uses reflection to scan assemblies and types. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\TUnitInitializer.cs(23,13): error IL3050: Using member 'TUnit.Engine.TUnitInitializer.DiscoverHooksViaReflection()' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Hook delegate creation requires dynamic code generation. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Framework\TUnitTestFramework.cs(111,18): error IL2026: Using member 'TUnit.Engine.Framework.TUnitServiceProvider.TUnitServiceProvider(IExtension, ExecuteRequestContext, ITestExecutionFilter, IMessageBus, IServiceProvider, ITestFrameworkCapabilities)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Test data collector selection may use reflection-based discovery. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Framework\TUnitTestFramework.cs(111,18): error IL3050: Using member 'TUnit.Engine.Framework.TUnitServiceProvider.TUnitServiceProvider(IExtension, ExecuteRequestContext, ITestExecutionFilter, IMessageBus, IServiceProvider, ITestFrameworkCapabilities)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Reflection mode test discovery uses dynamic code generation. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\TestSessionCoordinator.cs(76,15): error IL2026: Using member 'TUnit.Engine.TestSessionCoordinator.InitializeStaticPropertiesAsync(CancellationToken)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Static property initialization uses reflection in reflection mode. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\TestSessionCoordinator.cs(96,23): error IL3050: Using member 'TUnit.Core.StaticPropertyReflectionInitializer.InitializeAllStaticPropertiesAsync()' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Data source initialization may require dynamic code generation. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(231,25): error IL2026: Using member 'System.Reflection.Assembly.GetTypes()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Types might be removed. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(208,36): error IL2026: Using member 'System.Reflection.Assembly.GetReferencedAssemblies()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Assembly references might be removed. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(198,34): error IL2070: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethods(BindingFlags)'. The parameter 't' of method 'lambda expression' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(198,34): error IL2075: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethods(BindingFlags)'. The return value of method 'System.Type.BaseType.get' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilder.cs(652,13): error IL2026: Using member 'TUnit.Engine.Discovery.ReflectionHookDiscoveryService.DiscoverInstanceHooksForType(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Hook discovery uses reflection on methods and attributes. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilder.cs(652,13): error IL3050: Using member 'TUnit.Engine.Discovery.ReflectionHookDiscoveryService.DiscoverInstanceHooksForType(Type)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Hook registration may involve dynamic delegate creation. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Services\TestRegistry.cs(65,15): error IL2026: Using member 'TUnit.Engine.Services.TestRegistry.ProcessPendingDynamicTests()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Dynamic test metadata creation uses reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(319,36): error IL2026: Using member 'System.Reflection.Assembly.GetReferencedAssemblies()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Assembly references might be removed. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Services\DataSourceInitializer.cs(76,54): error IL2026: Using member 'TUnit.Core.PropertyInjection.PropertyInjectionCache.HasInjectableProperties(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Type comes from runtime objects that cannot be annotated. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Services\DataSourceInitializer.cs(78,23): error IL2026: Using member 'TUnit.Engine.Services.PropertyInjectionService.InjectPropertiesIntoObjectAsync(Object, Dictionary, MethodMetadata, TestContextEvents)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Type comes from runtime objects that cannot be annotated. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Services\TestRegistry.cs(148,30): error IL2026: Using member 'TUnit.Engine.Building.ReflectionMetadataBuilder.CreateMethodMetadata(Type, MethodInfo)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Method metadata creation uses reflection on parameters and types. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Services\TestRegistry.cs(153,34): error IL2026: Using member 'TUnit.Core.PropertySourceRegistry.DiscoverInjectableProperties(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Reflection discovery is used when source-generated metadata is not available. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Services\DataSourceInitializer.cs(132,20): error IL2026: Using member 'TUnit.Core.PropertyInjection.PropertyInjectionCache.GetOrCreatePlan(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Type comes from runtime objects that cannot be annotated. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Services\DataSourceInitializer.cs(147,21): error IL2026: Using member 'TUnit.Core.PropertyInjection.PropertyInjectionCache.HasInjectableProperties(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Type comes from runtime objects that cannot be annotated. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Services\DataSourceInitializer.cs(158,21): error IL2026: Using member 'TUnit.Core.PropertyInjection.PropertyInjectionCache.HasInjectableProperties(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Type comes from runtime objects that cannot be annotated. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Services\DataSourceInitializer.cs(184,21): error IL2026: Using member 'TUnit.Core.PropertyInjection.PropertyInjectionCache.HasInjectableProperties(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Type comes from runtime objects that cannot be annotated. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Services\DataSourceInitializer.cs(195,21): error IL2026: Using member 'TUnit.Core.PropertyInjection.PropertyInjectionCache.HasInjectableProperties(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Type comes from runtime objects that cannot be annotated. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(643,13): error IL2067: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'TUnit.Core.Hooks.InstanceHookMethod.InitClassType.init'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionHookDiscoveryService.RegisterInstanceBeforeHook(Type, MethodInfo, Int32)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(664,13): error IL2067: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'TUnit.Core.Hooks.InstanceHookMethod.InitClassType.init'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionHookDiscoveryService.RegisterInstanceAfterHook(Type, MethodInfo, Int32)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilder.cs(1258,41): error IL2026: Using member 'TUnit.Engine.Building.TestBuilder.TryInferClassGenericsFromDataSources(TestMetadata)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Generic type inference uses reflection on data sources and parameters. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(822,57): error IL2067: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicParameterlessConstructor' in call to 'System.Activator.CreateInstance(Type)'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionHookDiscoveryService.CreateHookDelegate(Type, MethodInfo)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(743,13): error IL2067: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.NonPublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.MethodMetadata.Type.init'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionHookDiscoveryService.CreateMethodMetadata(Type, MethodInfo)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(747,17): error IL2067: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.NonPublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.ClassMetadata.Type.init'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionHookDiscoveryService.CreateMethodMetadata(Type, MethodInfo)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(758,61): error IL2072: 'Type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.ParameterMetadata.ParameterMetadata(Type)'. The return value of method 'System.Reflection.ParameterInfo.ParameterType.get' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(874,44): error IL2075: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'System.Type.GetProperty(String)'. The return value of method 'System.Object.GetType()' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(883,40): error IL2072: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicParameterlessConstructor' in call to 'System.Activator.CreateInstance(Type)'. The return value of method 'System.Reflection.PropertyInfo.GetValue(Object)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1052,27): error IL2070: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethods(BindingFlags)'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.HasTestMethods(Type)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1105,13): error IL2026: Using member 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CollectTestsAsync(String)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Assembly scanning uses dynamic type discovery and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1105,13): error IL2026: Using member 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CollectTestsStreamingAsync(String, CancellationToken)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Reflection-based test discovery requires dynamic access to types, methods, and attributes. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(893,50): error IL2067: 'testClass' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.NonPublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Engine.Discovery.ReflectionTestMetadata.ReflectionTestMetadata(Type, MethodInfo)'. The parameter 'testClass' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.BuildTestMetadata(Type, MethodInfo, Object[])' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(896,17): error IL2067: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.TestMetadata.TestClassType.init'. The parameter 'testClass' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.BuildTestMetadata(Type, MethodInfo, Object[])' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(896,17): error IL2072: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.TestMetadata.TestClassType.init'. The return value of method 'System.Type.BaseType.get' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(903,39): error IL2067: 'testClass' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Engine.Discovery.ReflectionAttributeExtractor.ExtractPropertyDataSources(Type)'. The parameter 'testClass' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.BuildTestMetadata(Type, MethodInfo, Object[])' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1160,13): error IL2067: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.NonPublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.MethodMetadata.Type.init'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateDummyMethodMetadata(Type, String)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(904,35): error IL2067: 'testClass' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors' in call to 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateInstanceFactory(Type)'. The parameter 'testClass' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.BuildTestMetadata(Type, MethodInfo, Object[])' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1164,17): error IL2067: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.NonPublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.ClassMetadata.Type.init'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateDummyMethodMetadata(Type, String)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(904,35): error IL2026: Using member 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateInstanceFactory(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Instance creation uses reflection and Activator.CreateInstance. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(904,35): error IL3050: Using member 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateInstanceFactory(Type)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Generic type instantiation uses MakeGenericType and Activator. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(905,31): error IL2026: Using member 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateTestInvoker(Type, MethodInfo)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Test invocation uses reflection and MethodInfo.Invoke. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(905,31): error IL3050: Using member 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateTestInvoker(Type, MethodInfo)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Generic method instantiation uses MakeGenericMethod. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Services\EventReceiverOrchestrator.cs(106,33): error IL2026: Using member 'TUnit.Engine.Utilities.ScopedAttributeFilter.FilterScopedAttributes(IEnumerable)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Scoped attribute filtering uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(908,34): error IL2067: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.NonPublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Engine.Building.ReflectionMetadataBuilder.CreateMethodMetadata(Type, MethodInfo)'. The parameter 'testClass' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.BuildTestMetadata(Type, MethodInfo, Object[])' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(908,34): error IL2026: Using member 'TUnit.Engine.Building.ReflectionMetadataBuilder.CreateMethodMetadata(Type, MethodInfo)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Method metadata creation uses reflection on parameters and types. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(909,35): error IL2026: Using member 'TUnit.Engine.Discovery.ReflectionGenericTypeResolver.ExtractGenericTypeInfo(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Generic type info extraction uses reflection on type parameters. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(910,37): error IL2026: Using member 'TUnit.Engine.Discovery.ReflectionGenericTypeResolver.ExtractGenericMethodInfo(MethodInfo)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Generic method info extraction uses reflection on method parameters. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(913,38): error IL2067: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicFields', 'DynamicallyAccessedMemberTypes.NonPublicFields', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.PropertySourceRegistry.DiscoverInjectableProperties(Type)'. The parameter 'testClass' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.BuildTestMetadata(Type, MethodInfo, Object[])' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(913,38): error IL2026: Using member 'TUnit.Core.PropertySourceRegistry.DiscoverInjectableProperties(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Reflection discovery is used when source-generated metadata is not available. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1135,13): error IL2067: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.TestMetadata.TestClassType.init'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateFailedTestMetadata(Type, MethodInfo, Exception)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1139,30): error IL2067: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.NonPublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Engine.Building.ReflectionMetadataBuilder.CreateMethodMetadata(Type, MethodInfo)'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateFailedTestMetadata(Type, MethodInfo, Exception)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1139,30): error IL2026: Using member 'TUnit.Engine.Building.ReflectionMetadataBuilder.CreateMethodMetadata(Type, MethodInfo)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Method metadata creation uses reflection on parameters and types. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Services\EventReceiverOrchestrator.cs(142,33): error IL2026: Using member 'TUnit.Engine.Utilities.ScopedAttributeFilter.FilterScopedAttributes(IEnumerable)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Scoped attribute filtering uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(259,27): error IL2075: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethods(BindingFlags)'. The return value of method 'System.Collections.Generic.List.Enumerator.Current.get' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1324,39): error IL2070: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.Interfaces' in call to 'System.Type.GetInterfaces()'. The parameter 'argType' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.InferGenericTypeMapping(Type, Type, Dictionary)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1345,35): error IL2070: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.Interfaces' in call to 'System.Type.GetInterfaces()'. The parameter 'argType' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.InferGenericTypeMapping(Type, Type, Dictionary)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Services\EventReceiverOrchestrator.cs(176,33): error IL2026: Using member 'TUnit.Engine.Utilities.ScopedAttributeFilter.FilterScopedAttributes(IEnumerable)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Scoped attribute filtering uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1396,29): error IL2070: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.Interfaces' in call to 'System.Type.GetInterfaces()'. The parameter 'argType' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.IsCovariantCompatible(Type, Type)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Services\TestGenericTypeResolver.cs(438,14): error IL2026: Using member 'TUnit.Engine.Services.TestGenericTypeResolver.TryInferTypeMapping(Type, Type, Dictionary)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Type mapping inference uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Services\TestGenericTypeResolver.cs(422,22): error IL2026: Using member 'TUnit.Engine.Services.TestGenericTypeResolver.TryInferTypeMapping(Type, Type, Dictionary)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Type mapping inference uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Services\EventReceiverOrchestrator.cs(192,33): error IL2026: Using member 'TUnit.Engine.Utilities.ScopedAttributeFilter.FilterScopedAttributes(IEnumerable)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Scoped attribute filtering uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1834,42): error IL2026: Using member 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateMetadataFromDynamicDiscoveryResult(DynamicDiscoveryResult)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Dynamic test metadata creation uses reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1834,42): error IL3050: Using member 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateMetadataFromDynamicDiscoveryResult(DynamicDiscoveryResult)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Expression compilation is used for dynamic test invocation. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(2066,13): error IL2072: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.TestMetadata.TestClassType.init'. The return value of method 'System.Object.GetType()' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(2086,13): error IL2067: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.TestMetadata.TestClassType.init'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateFailedTestMetadataForDynamicBuilder(Type, MethodInfo, Exception)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(2090,30): error IL2067: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.NonPublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Engine.Building.ReflectionMetadataBuilder.CreateMethodMetadata(Type, MethodInfo)'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateFailedTestMetadataForDynamicBuilder(Type, MethodInfo, Exception)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(2090,30): error IL2026: Using member 'TUnit.Engine.Building.ReflectionMetadataBuilder.CreateMethodMetadata(Type, MethodInfo)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Method metadata creation uses reflection on parameters and types. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(2151,58): error IL2077: 'testClassType' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors' in call to 'TUnit.Core.Helpers.ClassConstructorHelper.TryCreateInstanceWithClassConstructor(IReadOnlyList, Type, String, TestContext)'. The field 'TUnit.Engine.Discovery.ReflectionTestDataCollector.DynamicReflectionTestMetadata._testClass' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Services\HookCollectionService.cs(39,19): error IL2026: Using member 'TUnit.Engine.Services.EventReceiverOrchestrator.InvokeHookRegistrationEventReceiversAsync(HookRegisteredContext, CancellationToken)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Scoped attribute filtering uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Services\ObjectRegistrationService.cs(53,19): error IL2026: Using member 'TUnit.Engine.Services.PropertyInjectionService.InjectPropertiesIntoObjectAsync(Object, Dictionary, MethodMetadata, TestContextEvents)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Type comes from runtime objects that cannot be annotated. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Services\PropertyInitializationOrchestrator.cs(108,19): error IL2026: Using member 'TUnit.Engine.Services.PropertyInitializationOrchestrator.InitializePropertiesAsync(Object, (PropertyInfo Property, IDataSourceAttribute DataSource)[], Dictionary, MethodMetadata, TestContextEvents, ConcurrentDictionary)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Reflection-based property initialization uses PropertyInfo. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilder.cs(1116,34): error IL2026: Using member 'TUnit.Engine.Utilities.ScopedAttributeFilter.FilterScopedAttributes(IEnumerable)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Scoped attribute filtering uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] -For switch syntax, type "MSBuild -help" +Build FAILED. + +C:\git\TUnit\TUnit.Engine\Building\TestDataCollectorFactory.cs(48,30): error IL3050: Using member 'TUnit.Engine.Building.Collectors.AotTestDataCollector.CollectTestsAsync(String)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Generic test instantiation requires MakeGenericType. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Building\TestDataCollectorFactory.cs(48,30): error IL2026: Using member 'TUnit.Engine.Building.Collectors.AotTestDataCollector.CollectTestsAsync(String)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Assembly scanning uses dynamic type discovery and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilderPipeline.cs(60,39): error IL3050: Using member 'TUnit.Engine.Building.Interfaces.ITestDataCollector.CollectTestsAsync(String)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Generic test instantiation requires MakeGenericType. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilderPipeline.cs(60,39): error IL2026: Using member 'TUnit.Engine.Building.Interfaces.ITestDataCollector.CollectTestsAsync(String)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Assembly scanning uses dynamic type discovery and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilderPipeline.cs(74,39): error IL3050: Using member 'TUnit.Engine.Building.Interfaces.ITestDataCollector.CollectTestsAsync(String)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Generic test instantiation requires MakeGenericType. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilderPipeline.cs(74,39): error IL2026: Using member 'TUnit.Engine.Building.Interfaces.ITestDataCollector.CollectTestsAsync(String)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Assembly scanning uses dynamic type discovery and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilderPipeline.cs(77,30): error IL2026: Using member 'TUnit.Engine.Building.TestBuilderPipeline.BuildTestsFromSingleMetadataAsync(TestMetadata)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Scoped attribute filtering uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilderPipeline.cs(99,38): error IL2026: Using member 'TUnit.Engine.Building.TestBuilderPipeline.GenerateDynamicTests(TestMetadata)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Scoped attribute filtering uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilderPipeline.cs(102,34): error IL2026: Using member 'TUnit.Engine.Building.Interfaces.ITestBuilder.BuildTestsFromMetadataAsync(TestMetadata)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Scoped attribute filtering uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Building\Collectors\AotTestDataCollector.cs(100,42): error IL2026: Using member 'TUnit.Engine.Building.Collectors.AotTestDataCollector.CreateMetadataFromDynamicDiscoveryResult(DynamicDiscoveryResult)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Method extraction from expressions uses reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\TUnitInitializer.cs(23,13): error IL3050: Using member 'TUnit.Engine.TUnitInitializer.DiscoverHooksViaReflection()' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Hook delegate creation requires dynamic code generation. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\TUnitInitializer.cs(23,13): error IL2026: Using member 'TUnit.Engine.TUnitInitializer.DiscoverHooksViaReflection()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Hook discovery uses reflection to scan assemblies and types. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\TestSessionCoordinator.cs(76,15): error IL2026: Using member 'TUnit.Engine.TestSessionCoordinator.InitializeStaticPropertiesAsync(CancellationToken)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Static property initialization uses reflection in reflection mode. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\TestSessionCoordinator.cs(96,23): error IL3050: Using member 'TUnit.Core.StaticPropertyReflectionInitializer.InitializeAllStaticPropertiesAsync()' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Data source initialization may require dynamic code generation. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilder.cs(652,13): error IL3050: Using member 'TUnit.Engine.Discovery.ReflectionHookDiscoveryService.DiscoverInstanceHooksForType(Type)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Hook registration may involve dynamic delegate creation. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilder.cs(652,13): error IL2026: Using member 'TUnit.Engine.Discovery.ReflectionHookDiscoveryService.DiscoverInstanceHooksForType(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Hook discovery uses reflection on methods and attributes. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Services\TestRegistry.cs(148,30): error IL2026: Using member 'TUnit.Engine.Building.ReflectionMetadataBuilder.CreateMethodMetadata(Type, MethodInfo)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Method metadata creation uses reflection on parameters and types. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Services\TestRegistry.cs(153,34): error IL2026: Using member 'TUnit.Core.PropertySourceRegistry.DiscoverInjectableProperties(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Reflection discovery is used when source-generated metadata is not available. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(319,36): error IL2026: Using member 'System.Reflection.Assembly.GetReferencedAssemblies()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Assembly references might be removed. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilder.cs(1116,34): error IL2026: Using member 'TUnit.Engine.Utilities.ScopedAttributeFilter.FilterScopedAttributes(IEnumerable)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Scoped attribute filtering uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilder.cs(1258,41): error IL2026: Using member 'TUnit.Engine.Building.TestBuilder.TryInferClassGenericsFromDataSources(TestMetadata)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Generic type inference uses reflection on data sources and parameters. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(904,35): error IL3050: Using member 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateInstanceFactory(Type)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Generic type instantiation uses MakeGenericType and Activator. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(905,31): error IL3050: Using member 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateTestInvoker(Type, MethodInfo)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Generic method instantiation uses MakeGenericMethod. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(904,35): error IL2026: Using member 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateInstanceFactory(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Instance creation uses reflection and Activator.CreateInstance. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(905,31): error IL2026: Using member 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateTestInvoker(Type, MethodInfo)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Test invocation uses reflection and MethodInfo.Invoke. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(908,34): error IL2026: Using member 'TUnit.Engine.Building.ReflectionMetadataBuilder.CreateMethodMetadata(Type, MethodInfo)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Method metadata creation uses reflection on parameters and types. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(909,35): error IL2026: Using member 'TUnit.Engine.Discovery.ReflectionGenericTypeResolver.ExtractGenericTypeInfo(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Generic type info extraction uses reflection on type parameters. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(910,37): error IL2026: Using member 'TUnit.Engine.Discovery.ReflectionGenericTypeResolver.ExtractGenericMethodInfo(MethodInfo)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Generic method info extraction uses reflection on method parameters. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(913,38): error IL2026: Using member 'TUnit.Core.PropertySourceRegistry.DiscoverInjectableProperties(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Reflection discovery is used when source-generated metadata is not available. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1139,30): error IL2026: Using member 'TUnit.Engine.Building.ReflectionMetadataBuilder.CreateMethodMetadata(Type, MethodInfo)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Method metadata creation uses reflection on parameters and types. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Services\TestRegistry.cs(65,15): error IL2026: Using member 'TUnit.Engine.Services.TestRegistry.ProcessPendingDynamicTests()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Dynamic test metadata creation uses reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Services\TestGenericTypeResolver.cs(422,22): error IL2026: Using member 'TUnit.Engine.Services.TestGenericTypeResolver.TryInferTypeMapping(Type, Type, Dictionary)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Type mapping inference uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Services\TestGenericTypeResolver.cs(438,14): error IL2026: Using member 'TUnit.Engine.Services.TestGenericTypeResolver.TryInferTypeMapping(Type, Type, Dictionary)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Type mapping inference uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1105,13): error IL2026: Using member 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CollectTestsAsync(String)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Assembly scanning uses dynamic type discovery and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1105,13): error IL2026: Using member 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CollectTestsStreamingAsync(String, CancellationToken)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Reflection-based test discovery requires dynamic access to types, methods, and attributes. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1052,27): error IL2070: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethods(BindingFlags)'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.HasTestMethods(Type)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1160,13): error IL2067: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.NonPublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.MethodMetadata.Type.init'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateDummyMethodMetadata(Type, String)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(198,34): error IL2070: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethods(BindingFlags)'. The parameter 't' of method 'lambda expression' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(198,34): error IL2075: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethods(BindingFlags)'. The return value of method 'System.Type.BaseType.get' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1164,17): error IL2067: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.NonPublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.ClassMetadata.Type.init'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateDummyMethodMetadata(Type, String)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1135,13): error IL2067: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.TestMetadata.TestClassType.init'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateFailedTestMetadata(Type, MethodInfo, Exception)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1139,30): error IL2067: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.NonPublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Engine.Building.ReflectionMetadataBuilder.CreateMethodMetadata(Type, MethodInfo)'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateFailedTestMetadata(Type, MethodInfo, Exception)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1396,29): error IL2070: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.Interfaces' in call to 'System.Type.GetInterfaces()'. The parameter 'argType' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.IsCovariantCompatible(Type, Type)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1324,39): error IL2070: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.Interfaces' in call to 'System.Type.GetInterfaces()'. The parameter 'argType' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.InferGenericTypeMapping(Type, Type, Dictionary)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1345,35): error IL2070: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.Interfaces' in call to 'System.Type.GetInterfaces()'. The parameter 'argType' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.InferGenericTypeMapping(Type, Type, Dictionary)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1834,42): error IL3050: Using member 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateMetadataFromDynamicDiscoveryResult(DynamicDiscoveryResult)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Expression compilation is used for dynamic test invocation. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1834,42): error IL2026: Using member 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateMetadataFromDynamicDiscoveryResult(DynamicDiscoveryResult)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Dynamic test metadata creation uses reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(893,50): error IL2067: 'testClass' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.NonPublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Engine.Discovery.ReflectionTestMetadata.ReflectionTestMetadata(Type, MethodInfo)'. The parameter 'testClass' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.BuildTestMetadata(Type, MethodInfo, Object[])' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(896,17): error IL2067: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.TestMetadata.TestClassType.init'. The parameter 'testClass' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.BuildTestMetadata(Type, MethodInfo, Object[])' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(896,17): error IL2072: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.TestMetadata.TestClassType.init'. The return value of method 'System.Type.BaseType.get' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(903,39): error IL2067: 'testClass' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Engine.Discovery.ReflectionAttributeExtractor.ExtractPropertyDataSources(Type)'. The parameter 'testClass' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.BuildTestMetadata(Type, MethodInfo, Object[])' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(904,35): error IL2067: 'testClass' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors' in call to 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateInstanceFactory(Type)'. The parameter 'testClass' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.BuildTestMetadata(Type, MethodInfo, Object[])' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(908,34): error IL2067: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.NonPublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Engine.Building.ReflectionMetadataBuilder.CreateMethodMetadata(Type, MethodInfo)'. The parameter 'testClass' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.BuildTestMetadata(Type, MethodInfo, Object[])' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(913,38): error IL2067: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicFields', 'DynamicallyAccessedMemberTypes.NonPublicFields', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.PropertySourceRegistry.DiscoverInjectableProperties(Type)'. The parameter 'testClass' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.BuildTestMetadata(Type, MethodInfo, Object[])' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(2151,58): error IL2077: 'testClassType' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors' in call to 'TUnit.Core.Helpers.ClassConstructorHelper.TryCreateInstanceWithClassConstructor(IReadOnlyList, Type, String, TestContext)'. The field 'TUnit.Engine.Discovery.ReflectionTestDataCollector.DynamicReflectionTestMetadata._testClass' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(2090,30): error IL2026: Using member 'TUnit.Engine.Building.ReflectionMetadataBuilder.CreateMethodMetadata(Type, MethodInfo)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Method metadata creation uses reflection on parameters and types. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(2086,13): error IL2067: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.TestMetadata.TestClassType.init'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateFailedTestMetadataForDynamicBuilder(Type, MethodInfo, Exception)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(2090,30): error IL2067: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.NonPublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Engine.Building.ReflectionMetadataBuilder.CreateMethodMetadata(Type, MethodInfo)'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateFailedTestMetadataForDynamicBuilder(Type, MethodInfo, Exception)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(743,13): error IL2067: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.NonPublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.MethodMetadata.Type.init'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionHookDiscoveryService.CreateMethodMetadata(Type, MethodInfo)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(747,17): error IL2067: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.NonPublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.ClassMetadata.Type.init'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionHookDiscoveryService.CreateMethodMetadata(Type, MethodInfo)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(758,61): error IL2072: 'Type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.ParameterMetadata.ParameterMetadata(Type)'. The return value of method 'System.Reflection.ParameterInfo.ParameterType.get' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(822,57): error IL2067: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicParameterlessConstructor' in call to 'System.Activator.CreateInstance(Type)'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionHookDiscoveryService.CreateHookDelegate(Type, MethodInfo)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(883,40): error IL2072: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicParameterlessConstructor' in call to 'System.Activator.CreateInstance(Type)'. The return value of method 'System.Reflection.PropertyInfo.GetValue(Object)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(664,13): error IL2067: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'TUnit.Core.Hooks.InstanceHookMethod.InitClassType.init'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionHookDiscoveryService.RegisterInstanceAfterHook(Type, MethodInfo, Int32)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(643,13): error IL2067: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'TUnit.Core.Hooks.InstanceHookMethod.InitClassType.init'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionHookDiscoveryService.RegisterInstanceBeforeHook(Type, MethodInfo, Int32)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(208,36): error IL2026: Using member 'System.Reflection.Assembly.GetReferencedAssemblies()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Assembly references might be removed. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(231,25): error IL2026: Using member 'System.Reflection.Assembly.GetTypes()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Types might be removed. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Framework\TUnitTestFramework.cs(111,18): error IL3050: Using member 'TUnit.Engine.Framework.TUnitServiceProvider.TUnitServiceProvider(IExtension, ExecuteRequestContext, ITestExecutionFilter, IMessageBus, IServiceProvider, ITestFrameworkCapabilities)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Reflection mode test discovery uses dynamic code generation. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Framework\TUnitTestFramework.cs(111,18): error IL2026: Using member 'TUnit.Engine.Framework.TUnitServiceProvider.TUnitServiceProvider(IExtension, ExecuteRequestContext, ITestExecutionFilter, IMessageBus, IServiceProvider, ITestFrameworkCapabilities)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Test data collector selection may use reflection-based discovery. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(259,27): error IL2075: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethods(BindingFlags)'. The return value of method 'System.Collections.Generic.List.Enumerator.Current.get' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Services\DataSourceInitializer.cs(76,54): error IL2026: Using member 'TUnit.Core.PropertyInjection.PropertyInjectionCache.HasInjectableProperties(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Type comes from runtime objects that cannot be annotated. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Services\DataSourceInitializer.cs(78,23): error IL2026: Using member 'TUnit.Engine.Services.PropertyInjectionService.InjectPropertiesIntoObjectAsync(Object, Dictionary, MethodMetadata, TestContextEvents)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Type comes from runtime objects that cannot be annotated. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Services\ObjectRegistrationService.cs(53,19): error IL2026: Using member 'TUnit.Engine.Services.PropertyInjectionService.InjectPropertiesIntoObjectAsync(Object, Dictionary, MethodMetadata, TestContextEvents)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Type comes from runtime objects that cannot be annotated. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Services\HookCollectionService.cs(39,19): error IL2026: Using member 'TUnit.Engine.Services.EventReceiverOrchestrator.InvokeHookRegistrationEventReceiversAsync(HookRegisteredContext, CancellationToken)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Scoped attribute filtering uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Services\EventReceiverOrchestrator.cs(106,33): error IL2026: Using member 'TUnit.Engine.Utilities.ScopedAttributeFilter.FilterScopedAttributes(IEnumerable)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Scoped attribute filtering uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Services\EventReceiverOrchestrator.cs(142,33): error IL2026: Using member 'TUnit.Engine.Utilities.ScopedAttributeFilter.FilterScopedAttributes(IEnumerable)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Scoped attribute filtering uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Services\PropertyInitializationOrchestrator.cs(108,19): error IL2026: Using member 'TUnit.Engine.Services.PropertyInitializationOrchestrator.InitializePropertiesAsync(Object, (PropertyInfo Property, IDataSourceAttribute DataSource)[], Dictionary, MethodMetadata, TestContextEvents, ConcurrentDictionary)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Reflection-based property initialization uses PropertyInfo. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Services\EventReceiverOrchestrator.cs(176,33): error IL2026: Using member 'TUnit.Engine.Utilities.ScopedAttributeFilter.FilterScopedAttributes(IEnumerable)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Scoped attribute filtering uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Services\DataSourceInitializer.cs(132,20): error IL2026: Using member 'TUnit.Core.PropertyInjection.PropertyInjectionCache.GetOrCreatePlan(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Type comes from runtime objects that cannot be annotated. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Services\DataSourceInitializer.cs(147,21): error IL2026: Using member 'TUnit.Core.PropertyInjection.PropertyInjectionCache.HasInjectableProperties(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Type comes from runtime objects that cannot be annotated. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Services\DataSourceInitializer.cs(158,21): error IL2026: Using member 'TUnit.Core.PropertyInjection.PropertyInjectionCache.HasInjectableProperties(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Type comes from runtime objects that cannot be annotated. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Services\DataSourceInitializer.cs(184,21): error IL2026: Using member 'TUnit.Core.PropertyInjection.PropertyInjectionCache.HasInjectableProperties(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Type comes from runtime objects that cannot be annotated. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Services\DataSourceInitializer.cs(195,21): error IL2026: Using member 'TUnit.Core.PropertyInjection.PropertyInjectionCache.HasInjectableProperties(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Type comes from runtime objects that cannot be annotated. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Services\EventReceiverOrchestrator.cs(192,33): error IL2026: Using member 'TUnit.Engine.Utilities.ScopedAttributeFilter.FilterScopedAttributes(IEnumerable)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Scoped attribute filtering uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net8.0] +C:\git\TUnit\TUnit.Engine\Building\TestDataCollectorFactory.cs(48,30): error IL2026: Using member 'TUnit.Engine.Building.Collectors.AotTestDataCollector.CollectTestsAsync(String)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Assembly scanning uses dynamic type discovery and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Building\TestDataCollectorFactory.cs(48,30): error IL3050: Using member 'TUnit.Engine.Building.Collectors.AotTestDataCollector.CollectTestsAsync(String)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Generic test instantiation requires MakeGenericType. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilderPipeline.cs(60,39): error IL2026: Using member 'TUnit.Engine.Building.Interfaces.ITestDataCollector.CollectTestsAsync(String)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Assembly scanning uses dynamic type discovery and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilderPipeline.cs(60,39): error IL3050: Using member 'TUnit.Engine.Building.Interfaces.ITestDataCollector.CollectTestsAsync(String)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Generic test instantiation requires MakeGenericType. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilderPipeline.cs(74,39): error IL2026: Using member 'TUnit.Engine.Building.Interfaces.ITestDataCollector.CollectTestsAsync(String)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Assembly scanning uses dynamic type discovery and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilderPipeline.cs(74,39): error IL3050: Using member 'TUnit.Engine.Building.Interfaces.ITestDataCollector.CollectTestsAsync(String)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Generic test instantiation requires MakeGenericType. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilderPipeline.cs(77,30): error IL2026: Using member 'TUnit.Engine.Building.TestBuilderPipeline.BuildTestsFromSingleMetadataAsync(TestMetadata)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Scoped attribute filtering uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Building\Collectors\AotTestDataCollector.cs(100,42): error IL2026: Using member 'TUnit.Engine.Building.Collectors.AotTestDataCollector.CreateMetadataFromDynamicDiscoveryResult(DynamicDiscoveryResult)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Method extraction from expressions uses reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilderPipeline.cs(99,38): error IL2026: Using member 'TUnit.Engine.Building.TestBuilderPipeline.GenerateDynamicTests(TestMetadata)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Scoped attribute filtering uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilderPipeline.cs(102,34): error IL2026: Using member 'TUnit.Engine.Building.Interfaces.ITestBuilder.BuildTestsFromMetadataAsync(TestMetadata)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Scoped attribute filtering uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\TUnitInitializer.cs(23,13): error IL2026: Using member 'TUnit.Engine.TUnitInitializer.DiscoverHooksViaReflection()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Hook discovery uses reflection to scan assemblies and types. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\TUnitInitializer.cs(23,13): error IL3050: Using member 'TUnit.Engine.TUnitInitializer.DiscoverHooksViaReflection()' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Hook delegate creation requires dynamic code generation. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Framework\TUnitTestFramework.cs(111,18): error IL2026: Using member 'TUnit.Engine.Framework.TUnitServiceProvider.TUnitServiceProvider(IExtension, ExecuteRequestContext, ITestExecutionFilter, IMessageBus, IServiceProvider, ITestFrameworkCapabilities)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Test data collector selection may use reflection-based discovery. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Framework\TUnitTestFramework.cs(111,18): error IL3050: Using member 'TUnit.Engine.Framework.TUnitServiceProvider.TUnitServiceProvider(IExtension, ExecuteRequestContext, ITestExecutionFilter, IMessageBus, IServiceProvider, ITestFrameworkCapabilities)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Reflection mode test discovery uses dynamic code generation. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\TestSessionCoordinator.cs(76,15): error IL2026: Using member 'TUnit.Engine.TestSessionCoordinator.InitializeStaticPropertiesAsync(CancellationToken)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Static property initialization uses reflection in reflection mode. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\TestSessionCoordinator.cs(96,23): error IL3050: Using member 'TUnit.Core.StaticPropertyReflectionInitializer.InitializeAllStaticPropertiesAsync()' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Data source initialization may require dynamic code generation. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(231,25): error IL2026: Using member 'System.Reflection.Assembly.GetTypes()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Types might be removed. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(208,36): error IL2026: Using member 'System.Reflection.Assembly.GetReferencedAssemblies()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Assembly references might be removed. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(198,34): error IL2070: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethods(BindingFlags)'. The parameter 't' of method 'lambda expression' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(198,34): error IL2075: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethods(BindingFlags)'. The return value of method 'System.Type.BaseType.get' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilder.cs(652,13): error IL2026: Using member 'TUnit.Engine.Discovery.ReflectionHookDiscoveryService.DiscoverInstanceHooksForType(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Hook discovery uses reflection on methods and attributes. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilder.cs(652,13): error IL3050: Using member 'TUnit.Engine.Discovery.ReflectionHookDiscoveryService.DiscoverInstanceHooksForType(Type)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Hook registration may involve dynamic delegate creation. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Services\TestRegistry.cs(65,15): error IL2026: Using member 'TUnit.Engine.Services.TestRegistry.ProcessPendingDynamicTests()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Dynamic test metadata creation uses reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(319,36): error IL2026: Using member 'System.Reflection.Assembly.GetReferencedAssemblies()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Assembly references might be removed. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Services\DataSourceInitializer.cs(76,54): error IL2026: Using member 'TUnit.Core.PropertyInjection.PropertyInjectionCache.HasInjectableProperties(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Type comes from runtime objects that cannot be annotated. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Services\DataSourceInitializer.cs(78,23): error IL2026: Using member 'TUnit.Engine.Services.PropertyInjectionService.InjectPropertiesIntoObjectAsync(Object, Dictionary, MethodMetadata, TestContextEvents)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Type comes from runtime objects that cannot be annotated. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Services\TestRegistry.cs(148,30): error IL2026: Using member 'TUnit.Engine.Building.ReflectionMetadataBuilder.CreateMethodMetadata(Type, MethodInfo)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Method metadata creation uses reflection on parameters and types. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Services\TestRegistry.cs(153,34): error IL2026: Using member 'TUnit.Core.PropertySourceRegistry.DiscoverInjectableProperties(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Reflection discovery is used when source-generated metadata is not available. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Services\DataSourceInitializer.cs(132,20): error IL2026: Using member 'TUnit.Core.PropertyInjection.PropertyInjectionCache.GetOrCreatePlan(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Type comes from runtime objects that cannot be annotated. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Services\DataSourceInitializer.cs(147,21): error IL2026: Using member 'TUnit.Core.PropertyInjection.PropertyInjectionCache.HasInjectableProperties(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Type comes from runtime objects that cannot be annotated. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Services\DataSourceInitializer.cs(158,21): error IL2026: Using member 'TUnit.Core.PropertyInjection.PropertyInjectionCache.HasInjectableProperties(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Type comes from runtime objects that cannot be annotated. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Services\DataSourceInitializer.cs(184,21): error IL2026: Using member 'TUnit.Core.PropertyInjection.PropertyInjectionCache.HasInjectableProperties(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Type comes from runtime objects that cannot be annotated. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Services\DataSourceInitializer.cs(195,21): error IL2026: Using member 'TUnit.Core.PropertyInjection.PropertyInjectionCache.HasInjectableProperties(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Type comes from runtime objects that cannot be annotated. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(643,13): error IL2067: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'TUnit.Core.Hooks.InstanceHookMethod.InitClassType.init'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionHookDiscoveryService.RegisterInstanceBeforeHook(Type, MethodInfo, Int32)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(664,13): error IL2067: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'TUnit.Core.Hooks.InstanceHookMethod.InitClassType.init'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionHookDiscoveryService.RegisterInstanceAfterHook(Type, MethodInfo, Int32)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilder.cs(1258,41): error IL2026: Using member 'TUnit.Engine.Building.TestBuilder.TryInferClassGenericsFromDataSources(TestMetadata)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Generic type inference uses reflection on data sources and parameters. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(822,57): error IL2067: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicParameterlessConstructor' in call to 'System.Activator.CreateInstance(Type)'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionHookDiscoveryService.CreateHookDelegate(Type, MethodInfo)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(743,13): error IL2067: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.NonPublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.MethodMetadata.Type.init'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionHookDiscoveryService.CreateMethodMetadata(Type, MethodInfo)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(747,17): error IL2067: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.NonPublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.ClassMetadata.Type.init'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionHookDiscoveryService.CreateMethodMetadata(Type, MethodInfo)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(758,61): error IL2072: 'Type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.ParameterMetadata.ParameterMetadata(Type)'. The return value of method 'System.Reflection.ParameterInfo.ParameterType.get' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(874,44): error IL2075: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'System.Type.GetProperty(String)'. The return value of method 'System.Object.GetType()' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(883,40): error IL2072: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicParameterlessConstructor' in call to 'System.Activator.CreateInstance(Type)'. The return value of method 'System.Reflection.PropertyInfo.GetValue(Object)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1052,27): error IL2070: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethods(BindingFlags)'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.HasTestMethods(Type)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1105,13): error IL2026: Using member 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CollectTestsAsync(String)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Assembly scanning uses dynamic type discovery and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1105,13): error IL2026: Using member 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CollectTestsStreamingAsync(String, CancellationToken)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Reflection-based test discovery requires dynamic access to types, methods, and attributes. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(893,50): error IL2067: 'testClass' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.NonPublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Engine.Discovery.ReflectionTestMetadata.ReflectionTestMetadata(Type, MethodInfo)'. The parameter 'testClass' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.BuildTestMetadata(Type, MethodInfo, Object[])' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(896,17): error IL2067: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.TestMetadata.TestClassType.init'. The parameter 'testClass' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.BuildTestMetadata(Type, MethodInfo, Object[])' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(896,17): error IL2072: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.TestMetadata.TestClassType.init'. The return value of method 'System.Type.BaseType.get' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(903,39): error IL2067: 'testClass' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Engine.Discovery.ReflectionAttributeExtractor.ExtractPropertyDataSources(Type)'. The parameter 'testClass' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.BuildTestMetadata(Type, MethodInfo, Object[])' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1160,13): error IL2067: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.NonPublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.MethodMetadata.Type.init'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateDummyMethodMetadata(Type, String)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(904,35): error IL2067: 'testClass' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors' in call to 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateInstanceFactory(Type)'. The parameter 'testClass' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.BuildTestMetadata(Type, MethodInfo, Object[])' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1164,17): error IL2067: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.NonPublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.ClassMetadata.Type.init'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateDummyMethodMetadata(Type, String)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(904,35): error IL2026: Using member 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateInstanceFactory(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Instance creation uses reflection and Activator.CreateInstance. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(904,35): error IL3050: Using member 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateInstanceFactory(Type)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Generic type instantiation uses MakeGenericType and Activator. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(905,31): error IL2026: Using member 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateTestInvoker(Type, MethodInfo)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Test invocation uses reflection and MethodInfo.Invoke. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(905,31): error IL3050: Using member 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateTestInvoker(Type, MethodInfo)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Generic method instantiation uses MakeGenericMethod. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Services\EventReceiverOrchestrator.cs(106,33): error IL2026: Using member 'TUnit.Engine.Utilities.ScopedAttributeFilter.FilterScopedAttributes(IEnumerable)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Scoped attribute filtering uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(908,34): error IL2067: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.NonPublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Engine.Building.ReflectionMetadataBuilder.CreateMethodMetadata(Type, MethodInfo)'. The parameter 'testClass' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.BuildTestMetadata(Type, MethodInfo, Object[])' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(908,34): error IL2026: Using member 'TUnit.Engine.Building.ReflectionMetadataBuilder.CreateMethodMetadata(Type, MethodInfo)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Method metadata creation uses reflection on parameters and types. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(909,35): error IL2026: Using member 'TUnit.Engine.Discovery.ReflectionGenericTypeResolver.ExtractGenericTypeInfo(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Generic type info extraction uses reflection on type parameters. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(910,37): error IL2026: Using member 'TUnit.Engine.Discovery.ReflectionGenericTypeResolver.ExtractGenericMethodInfo(MethodInfo)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Generic method info extraction uses reflection on method parameters. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(913,38): error IL2067: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicFields', 'DynamicallyAccessedMemberTypes.NonPublicFields', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.PropertySourceRegistry.DiscoverInjectableProperties(Type)'. The parameter 'testClass' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.BuildTestMetadata(Type, MethodInfo, Object[])' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(913,38): error IL2026: Using member 'TUnit.Core.PropertySourceRegistry.DiscoverInjectableProperties(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Reflection discovery is used when source-generated metadata is not available. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1135,13): error IL2067: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.TestMetadata.TestClassType.init'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateFailedTestMetadata(Type, MethodInfo, Exception)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1139,30): error IL2067: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.NonPublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Engine.Building.ReflectionMetadataBuilder.CreateMethodMetadata(Type, MethodInfo)'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateFailedTestMetadata(Type, MethodInfo, Exception)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1139,30): error IL2026: Using member 'TUnit.Engine.Building.ReflectionMetadataBuilder.CreateMethodMetadata(Type, MethodInfo)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Method metadata creation uses reflection on parameters and types. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Services\EventReceiverOrchestrator.cs(142,33): error IL2026: Using member 'TUnit.Engine.Utilities.ScopedAttributeFilter.FilterScopedAttributes(IEnumerable)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Scoped attribute filtering uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionHookDiscoveryService.cs(259,27): error IL2075: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethods(BindingFlags)'. The return value of method 'System.Collections.Generic.List.Enumerator.Current.get' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1324,39): error IL2070: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.Interfaces' in call to 'System.Type.GetInterfaces()'. The parameter 'argType' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.InferGenericTypeMapping(Type, Type, Dictionary)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1345,35): error IL2070: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.Interfaces' in call to 'System.Type.GetInterfaces()'. The parameter 'argType' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.InferGenericTypeMapping(Type, Type, Dictionary)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Services\EventReceiverOrchestrator.cs(176,33): error IL2026: Using member 'TUnit.Engine.Utilities.ScopedAttributeFilter.FilterScopedAttributes(IEnumerable)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Scoped attribute filtering uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1396,29): error IL2070: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.Interfaces' in call to 'System.Type.GetInterfaces()'. The parameter 'argType' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.IsCovariantCompatible(Type, Type)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Services\TestGenericTypeResolver.cs(438,14): error IL2026: Using member 'TUnit.Engine.Services.TestGenericTypeResolver.TryInferTypeMapping(Type, Type, Dictionary)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Type mapping inference uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Services\TestGenericTypeResolver.cs(422,22): error IL2026: Using member 'TUnit.Engine.Services.TestGenericTypeResolver.TryInferTypeMapping(Type, Type, Dictionary)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Type mapping inference uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Services\EventReceiverOrchestrator.cs(192,33): error IL2026: Using member 'TUnit.Engine.Utilities.ScopedAttributeFilter.FilterScopedAttributes(IEnumerable)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Scoped attribute filtering uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1834,42): error IL2026: Using member 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateMetadataFromDynamicDiscoveryResult(DynamicDiscoveryResult)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Dynamic test metadata creation uses reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(1834,42): error IL3050: Using member 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateMetadataFromDynamicDiscoveryResult(DynamicDiscoveryResult)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Expression compilation is used for dynamic test invocation. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(2066,13): error IL2072: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.TestMetadata.TestClassType.init'. The return value of method 'System.Object.GetType()' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(2086,13): error IL2067: 'value' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Core.TestMetadata.TestClassType.init'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateFailedTestMetadataForDynamicBuilder(Type, MethodInfo, Exception)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(2090,30): error IL2067: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.NonPublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods', 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'TUnit.Engine.Building.ReflectionMetadataBuilder.CreateMethodMetadata(Type, MethodInfo)'. The parameter 'type' of method 'TUnit.Engine.Discovery.ReflectionTestDataCollector.CreateFailedTestMetadataForDynamicBuilder(Type, MethodInfo, Exception)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(2090,30): error IL2026: Using member 'TUnit.Engine.Building.ReflectionMetadataBuilder.CreateMethodMetadata(Type, MethodInfo)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Method metadata creation uses reflection on parameters and types. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Discovery\ReflectionTestDataCollector.cs(2151,58): error IL2077: 'testClassType' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors' in call to 'TUnit.Core.Helpers.ClassConstructorHelper.TryCreateInstanceWithClassConstructor(IReadOnlyList, Type, String, TestContext)'. The field 'TUnit.Engine.Discovery.ReflectionTestDataCollector.DynamicReflectionTestMetadata._testClass' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Services\HookCollectionService.cs(39,19): error IL2026: Using member 'TUnit.Engine.Services.EventReceiverOrchestrator.InvokeHookRegistrationEventReceiversAsync(HookRegisteredContext, CancellationToken)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Scoped attribute filtering uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Services\ObjectRegistrationService.cs(53,19): error IL2026: Using member 'TUnit.Engine.Services.PropertyInjectionService.InjectPropertiesIntoObjectAsync(Object, Dictionary, MethodMetadata, TestContextEvents)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Type comes from runtime objects that cannot be annotated. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Services\PropertyInitializationOrchestrator.cs(108,19): error IL2026: Using member 'TUnit.Engine.Services.PropertyInitializationOrchestrator.InitializePropertiesAsync(Object, (PropertyInfo Property, IDataSourceAttribute DataSource)[], Dictionary, MethodMetadata, TestContextEvents, ConcurrentDictionary)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Reflection-based property initialization uses PropertyInfo. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] +C:\git\TUnit\TUnit.Engine\Building\TestBuilder.cs(1116,34): error IL2026: Using member 'TUnit.Engine.Utilities.ScopedAttributeFilter.FilterScopedAttributes(IEnumerable)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Scoped attribute filtering uses Type.GetInterfaces and reflection. [C:\git\TUnit\TUnit.Engine\TUnit.Engine.csproj::TargetFramework=net9.0] + 0 Warning(s) + 170 Error(s) + +Time Elapsed 00:00:04.07 + +Workload updates are available. Run `dotnet workload list` for more information. From 3c39b6e83db65b4aba7e31e0f4171b1fc6accc93 Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Sat, 4 Oct 2025 23:24:45 +0100 Subject: [PATCH 05/14] fix: update RequiresUnreferencedCode and RequiresDynamicCode attributes for AOT compatibility --- .../Collectors/AotTestDataCollector.cs | 10 ++++- .../Building/Interfaces/ITestBuilder.cs | 8 +--- .../Building/Interfaces/ITestDataCollector.cs | 4 +- TUnit.Engine/Building/TestBuilder.cs | 22 ++++++++-- TUnit.Engine/Building/TestBuilderPipeline.cs | 42 +++++++++++++------ .../Building/TestDataCollectorFactory.cs | 10 ++++- .../Framework/TUnitServiceProvider.cs | 22 ++++++---- TUnit.Engine/TUnitInitializer.cs | 10 +++-- TUnit.Engine/TestSessionCoordinator.cs | 20 +++++---- 9 files changed, 101 insertions(+), 47 deletions(-) diff --git a/TUnit.Engine/Building/Collectors/AotTestDataCollector.cs b/TUnit.Engine/Building/Collectors/AotTestDataCollector.cs index f58dcca152..1835179b3b 100644 --- a/TUnit.Engine/Building/Collectors/AotTestDataCollector.cs +++ b/TUnit.Engine/Building/Collectors/AotTestDataCollector.cs @@ -16,8 +16,8 @@ namespace TUnit.Engine.Building.Collectors; internal sealed class AotTestDataCollector : ITestDataCollector { #if NET6_0_OR_GREATER - [RequiresUnreferencedCode("Assembly scanning uses dynamic type discovery and reflection")] - [RequiresDynamicCode("Generic test instantiation requires MakeGenericType")] + [UnconditionalSuppressMessage("Trimming", "IL2046", Justification = "AOT implementation uses source-generated metadata, not reflection")] + [UnconditionalSuppressMessage("AOT", "IL3051", Justification = "AOT implementation uses source-generated metadata, not dynamic code")] #endif public async Task> CollectTestsAsync(string testSessionId) { @@ -29,8 +29,14 @@ public async Task> CollectTestsAsync(string testSessio .SelectManyAsync(testSource => testSource.GetTestsAsync(testSessionId)) .ProcessInParallel(); + #if NET6_0_OR_GREATER + #pragma warning disable IL2026, IL3050 // Dynamic test collection is an optional feature that uses reflection + #endif var dynamicTestMetadatas = await CollectDynamicTestsStreaming(testSessionId) .ProcessInParallel(); + #if NET6_0_OR_GREATER + #pragma warning restore IL2026, IL3050 + #endif return [..standardTestMetadatas, ..dynamicTestMetadatas]; } diff --git a/TUnit.Engine/Building/Interfaces/ITestBuilder.cs b/TUnit.Engine/Building/Interfaces/ITestBuilder.cs index 2bdc233b15..7122df3f00 100644 --- a/TUnit.Engine/Building/Interfaces/ITestBuilder.cs +++ b/TUnit.Engine/Building/Interfaces/ITestBuilder.cs @@ -15,10 +15,6 @@ internal interface ITestBuilder /// The test data /// /// An executable test ready for execution - #if NET6_0_OR_GREATER - [RequiresUnreferencedCode("Hook discovery uses reflection on methods and attributes")] - [RequiresDynamicCode("Hook registration may involve dynamic delegate creation")] - #endif Task BuildTestAsync(TestMetadata metadata, TestBuilder.TestData testData, TestBuilderContext testBuilderContext); /// @@ -28,7 +24,7 @@ internal interface ITestBuilder /// The test metadata with DataCombinationGenerator /// Collection of executable tests for all data combinations #if NET6_0_OR_GREATER - [RequiresUnreferencedCode("Hook discovery uses reflection on methods and attributes")] + [RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces")] [RequiresDynamicCode("Hook registration may involve dynamic delegate creation")] #endif Task> BuildTestsFromMetadataAsync(TestMetadata metadata); @@ -40,7 +36,7 @@ internal interface ITestBuilder /// Cancellation token /// Stream of executable tests for all data combinations #if NET6_0_OR_GREATER - [RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces and reflection")] + [RequiresUnreferencedCode("Scoped attribute filtering uses Type.GetInterfaces")] [RequiresDynamicCode("Hook registration may involve dynamic delegate creation")] #endif IAsyncEnumerable BuildTestsStreamingAsync( diff --git a/TUnit.Engine/Building/Interfaces/ITestDataCollector.cs b/TUnit.Engine/Building/Interfaces/ITestDataCollector.cs index 4a8faa1d9c..da01199534 100644 --- a/TUnit.Engine/Building/Interfaces/ITestDataCollector.cs +++ b/TUnit.Engine/Building/Interfaces/ITestDataCollector.cs @@ -13,8 +13,8 @@ internal interface ITestDataCollector /// /// Collection of test metadata ready for processing #if NET6_0_OR_GREATER - [RequiresUnreferencedCode("Assembly scanning uses dynamic type discovery and reflection")] - [RequiresDynamicCode("Generic test instantiation requires MakeGenericType")] + [RequiresUnreferencedCode("Reflection-based implementation uses assembly scanning")] + [RequiresDynamicCode("Reflection-based implementation uses MakeGenericType")] #endif Task> CollectTestsAsync(string testSessionId); } diff --git a/TUnit.Engine/Building/TestBuilder.cs b/TUnit.Engine/Building/TestBuilder.cs index 931370f751..5e70509bfc 100644 --- a/TUnit.Engine/Building/TestBuilder.cs +++ b/TUnit.Engine/Building/TestBuilder.cs @@ -651,28 +651,42 @@ private async Task GetDataSourcesAsync(IDataSourceAttrib } } - #if NET6_0_OR_GREATER - [RequiresUnreferencedCode("Hook discovery uses reflection on methods and attributes")] - [RequiresDynamicCode("Hook registration may involve dynamic delegate creation")] - #endif public async Task BuildTestAsync(TestMetadata metadata, TestData testData, TestBuilderContext testBuilderContext) { // Discover instance hooks for closed generic types in reflection mode if (!SourceRegistrar.IsEnabled && metadata.TestClassType is { IsGenericType: true, IsGenericTypeDefinition: false }) { + #if NET6_0_OR_GREATER + #pragma warning disable IL2026, IL3050 // Reflection only used in reflection mode + #endif Discovery.ReflectionHookDiscoveryService.DiscoverInstanceHooksForType(metadata.TestClassType); + #if NET6_0_OR_GREATER + #pragma warning restore IL2026, IL3050 + #endif } var testId = TestIdentifierService.GenerateTestId(metadata, testData); + #if NET6_0_OR_GREATER + #pragma warning disable IL2026 // CreateTestContextAsync uses reflection for runtime type handling + #endif var context = await CreateTestContextAsync(testId, metadata, testData, testBuilderContext); + #if NET6_0_OR_GREATER + #pragma warning restore IL2026 + #endif context.TestDetails.ClassInstance = PlaceholderInstance.Instance; // Arguments will be tracked by TestArgumentTrackingService during TestRegistered event // This ensures proper reference counting for shared instances + #if NET6_0_OR_GREATER + #pragma warning disable IL2026 // InvokeDiscoveryEventReceiversAsync uses ScopedAttributeFilter + #endif await InvokeDiscoveryEventReceiversAsync(context); + #if NET6_0_OR_GREATER + #pragma warning restore IL2026 + #endif var creationContext = new ExecutableTestCreationContext { diff --git a/TUnit.Engine/Building/TestBuilderPipeline.cs b/TUnit.Engine/Building/TestBuilderPipeline.cs index 503f477860..68296b15e2 100644 --- a/TUnit.Engine/Building/TestBuilderPipeline.cs +++ b/TUnit.Engine/Building/TestBuilderPipeline.cs @@ -55,13 +55,15 @@ private TestBuilderContext CreateTestBuilderContext(TestMetadata metadata) return testBuilderContext; } - #if NET6_0_OR_GREATER - [RequiresUnreferencedCode("Assembly scanning uses dynamic type discovery and reflection")] - [RequiresDynamicCode("Generic test instantiation requires MakeGenericType")] - #endif public async Task> BuildTestsAsync(string testSessionId) { + #if NET6_0_OR_GREATER + #pragma warning disable IL2026, IL3050 // Reflection is only used by ReflectionTestDataCollector, not AotTestDataCollector + #endif var collectedMetadata = await _dataCollector.CollectTestsAsync(testSessionId).ConfigureAwait(false); + #if NET6_0_OR_GREATER + #pragma warning restore IL2026, IL3050 + #endif return await BuildTestsFromMetadataAsync(collectedMetadata).ConfigureAwait(false); } @@ -69,21 +71,29 @@ public async Task> BuildTestsAsync(string te /// /// Streaming version that yields tests as they're built without buffering /// - #if NET6_0_OR_GREATER - [RequiresUnreferencedCode("Assembly scanning uses dynamic type discovery and reflection")] - [RequiresDynamicCode("Generic test instantiation requires MakeGenericType")] - #endif public async Task> BuildTestsStreamingAsync( string testSessionId, CancellationToken cancellationToken = default) { // Get metadata streaming if supported // Fall back to non-streaming collection + #if NET6_0_OR_GREATER + #pragma warning disable IL2026, IL3050 // Reflection is only used by ReflectionTestDataCollector, not AotTestDataCollector + #endif var collectedMetadata = await _dataCollector.CollectTestsAsync(testSessionId).ConfigureAwait(false); + #if NET6_0_OR_GREATER + #pragma warning restore IL2026, IL3050 + #endif + #if NET6_0_OR_GREATER + #pragma warning disable IL2026, IL3050 // Reflection usage in BuildTestsFromSingleMetadataAsync is handled appropriately + #endif return await collectedMetadata .SelectManyAsync(BuildTestsFromSingleMetadataAsync, cancellationToken: cancellationToken) .ProcessInParallel(cancellationToken: cancellationToken); + #if NET6_0_OR_GREATER + #pragma warning restore IL2026, IL3050 + #endif } private async IAsyncEnumerable ToAsyncEnumerable(IEnumerable metadata) @@ -95,10 +105,6 @@ private async IAsyncEnumerable ToAsyncEnumerable(IEnumerable> BuildTestsFromMetadataAsync(IEnumerable testMetadata) { var testGroups = await testMetadata.SelectAsync(async metadata => @@ -108,10 +114,22 @@ public async Task> BuildTestsFromMetadataAsy // Check if this is a dynamic test metadata that should bypass normal test building if (metadata is IDynamicTestMetadata) { + #if NET6_0_OR_GREATER + #pragma warning disable IL2026 // Dynamic tests use reflection for attribute filtering + #endif return await GenerateDynamicTests(metadata).ConfigureAwait(false); + #if NET6_0_OR_GREATER + #pragma warning restore IL2026 + #endif } + #if NET6_0_OR_GREATER + #pragma warning disable IL2026, IL3050 // TestBuilder implementation handles reflection appropriately based on mode + #endif return await _testBuilder.BuildTestsFromMetadataAsync(metadata).ConfigureAwait(false); + #if NET6_0_OR_GREATER + #pragma warning restore IL2026, IL3050 + #endif } catch (Exception ex) { diff --git a/TUnit.Engine/Building/TestDataCollectorFactory.cs b/TUnit.Engine/Building/TestDataCollectorFactory.cs index 3f60edd961..398ad04007 100644 --- a/TUnit.Engine/Building/TestDataCollectorFactory.cs +++ b/TUnit.Engine/Building/TestDataCollectorFactory.cs @@ -42,14 +42,20 @@ public static ITestDataCollector Create(bool? useSourceGeneration = null, Assemb /// This provides automatic mode selection for optimal performance and compatibility. /// #if NET6_0_OR_GREATER - [RequiresUnreferencedCode("Assembly scanning uses dynamic type discovery and reflection")] - [RequiresDynamicCode("Generic test instantiation requires MakeGenericType")] + [RequiresUnreferencedCode("Falls back to reflection mode if no source-generated tests found")] + [RequiresDynamicCode("Falls back to reflection mode if no source-generated tests found")] #endif public static async Task CreateAutoDetectAsync(string testSessionId, Assembly[]? assembliesToScan = null) { // Try AOT mode first (check if any tests were registered) var aotCollector = new AotTestDataCollector(); + #if NET6_0_OR_GREATER + #pragma warning disable IL2026, IL3050 // AOT collector handles dynamic tests conditionally + #endif var aotTests = await aotCollector.CollectTestsAsync(testSessionId); + #if NET6_0_OR_GREATER + #pragma warning restore IL2026, IL3050 + #endif if (aotTests.Any()) { diff --git a/TUnit.Engine/Framework/TUnitServiceProvider.cs b/TUnit.Engine/Framework/TUnitServiceProvider.cs index 6722f682e2..3280b50e30 100644 --- a/TUnit.Engine/Framework/TUnitServiceProvider.cs +++ b/TUnit.Engine/Framework/TUnitServiceProvider.cs @@ -56,10 +56,6 @@ public ITestExecutionFilter? Filter public ObjectRegistrationService ObjectRegistrationService { get; } public bool AfterSessionHooksFailed { get; set; } -#if NET6_0_OR_GREATER - [RequiresUnreferencedCode("Test data collector selection may use reflection-based discovery")] - [RequiresDynamicCode("Reflection mode test discovery uses dynamic code generation")] -#endif public TUnitServiceProvider(IExtension extension, ExecuteRequestContext context, ITestExecutionFilter? filter, @@ -138,9 +134,21 @@ public TUnitServiceProvider(IExtension extension, var testMethodInvoker = Register(new TestMethodInvoker()); var useSourceGeneration = SourceRegistrar.IsEnabled = GetUseSourceGeneration(CommandLineOptions); - ITestDataCollector dataCollector = useSourceGeneration - ? new AotTestDataCollector() - : new ReflectionTestDataCollector(); + ITestDataCollector dataCollector; + if (useSourceGeneration) + { + dataCollector = new AotTestDataCollector(); + } + else + { + #if NET6_0_OR_GREATER + #pragma warning disable IL2026, IL3050 // Reflection mode explicitly selected by user or detected + #endif + dataCollector = new ReflectionTestDataCollector(); + #if NET6_0_OR_GREATER + #pragma warning restore IL2026, IL3050 + #endif + } var testBuilder = Register( new TestBuilder(TestSessionId, EventReceiverOrchestrator, ContextProvider, PropertyInjectionService, DataSourceInitializer)); diff --git a/TUnit.Engine/TUnitInitializer.cs b/TUnit.Engine/TUnitInitializer.cs index 09e8bdde0b..92c984d399 100644 --- a/TUnit.Engine/TUnitInitializer.cs +++ b/TUnit.Engine/TUnitInitializer.cs @@ -11,10 +11,6 @@ namespace TUnit.Engine; internal class TUnitInitializer(ICommandLineOptions commandLineOptions) { - #if NET6_0_OR_GREATER - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Hook discovery uses reflection to scan assemblies and types")] - [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("Hook delegate creation requires dynamic code generation")] - #endif public void Initialize(ExecuteRequestContext context) { ConfigureGlobalExceptionHandlers(context); @@ -24,7 +20,13 @@ public void Initialize(ExecuteRequestContext context) // Discover hooks via reflection if in reflection mode if (IsReflectionMode()) { + #if NET6_0_OR_GREATER + #pragma warning disable IL2026, IL3050 // Reflection only used in reflection mode, not in AOT/source-gen mode + #endif DiscoverHooksViaReflection(); + #if NET6_0_OR_GREATER + #pragma warning restore IL2026, IL3050 + #endif } if (!string.IsNullOrEmpty(TestContext.OutputDirectory)) diff --git a/TUnit.Engine/TestSessionCoordinator.cs b/TUnit.Engine/TestSessionCoordinator.cs index 4e24549121..57ffb4da02 100644 --- a/TUnit.Engine/TestSessionCoordinator.cs +++ b/TUnit.Engine/TestSessionCoordinator.cs @@ -76,22 +76,20 @@ private void InitializeEventReceivers(List testList, Can _eventReceiverOrchestrator.InitializeTestCounts(testContexts); } - #if NET6_0_OR_GREATER - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Static property initialization uses reflection in reflection mode")] - [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("Data source initialization may require dynamic code generation")] - #endif private async Task PrepareTestOrchestrator(List testList, CancellationToken cancellationToken) { // Register all tests upfront so orchestrator knows total counts per class/assembly for lifecycle management _lifecycleCoordinator.RegisterTests(testList); + #if NET6_0_OR_GREATER + #pragma warning disable IL2026, IL3050 // Reflection only used when !SourceRegistrar.IsEnabled + #endif await InitializeStaticPropertiesAsync(cancellationToken); + #if NET6_0_OR_GREATER + #pragma warning restore IL2026, IL3050 + #endif } - #if NET6_0_OR_GREATER - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Static property initialization uses reflection in reflection mode")] - [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("Data source initialization may require dynamic code generation")] - #endif private async Task InitializeStaticPropertiesAsync(CancellationToken cancellationToken) { try @@ -106,7 +104,13 @@ private async Task InitializeStaticPropertiesAsync(CancellationToken cancellatio // For reflection mode, also initialize static properties dynamically if (!SourceRegistrar.IsEnabled) { + #if NET6_0_OR_GREATER + #pragma warning disable IL2026, IL3050 // Reflection only used in reflection mode, not in AOT/source-gen mode + #endif await StaticPropertyReflectionInitializer.InitializeAllStaticPropertiesAsync(); + #if NET6_0_OR_GREATER + #pragma warning restore IL2026, IL3050 + #endif } } catch (Exception ex) From 232a0c7a637e1b73679d7a085e80458a21823815 Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Sat, 4 Oct 2025 23:26:24 +0100 Subject: [PATCH 06/14] fix: update annotations for AOT compatibility in various test classes --- ..._Has_No_API_Changes.DotNet8_0.verified.txt | 156 +++++++++--------- ..._Has_No_API_Changes.DotNet9_0.verified.txt | 156 +++++++++--------- ..._Has_No_API_Changes.DotNet8_0.verified.txt | 1 + ..._Has_No_API_Changes.DotNet9_0.verified.txt | 1 + 4 files changed, 150 insertions(+), 164 deletions(-) diff --git a/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet8_0.verified.txt b/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet8_0.verified.txt index aa144ab0bf..7826a60961 100644 --- a/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet8_0.verified.txt +++ b/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet8_0.verified.txt @@ -74,6 +74,7 @@ namespace public object?[] Values { get; } [.(typeof(.ArgumentsAttribute.d__8))] public .<<.>> GetDataRowsAsync(.DataGeneratorMetadata dataGeneratorMetadata) { } + [.("Type comes from runtime objects that cannot be annotated")] public . OnTestRegistered(.TestRegisteredContext context) { } } [(.Class | .Method | .Property, AllowMultiple=true)] @@ -84,6 +85,7 @@ namespace public string? Skip { get; set; } [.(typeof(.ArgumentsAttribute.d__6))] public override .<<.>> GetTypedDataRowsAsync(.DataGeneratorMetadata dataGeneratorMetadata) { } + [.("Type comes from runtime objects that cannot be annotated")] public . OnTestRegistered(.TestRegisteredContext context) { } } public class Artifact @@ -118,11 +120,15 @@ namespace public static . Convert( action) { } public static . Convert(<.> action) { } public static . Convert(<.> action) { } + [.("ConvertObject may require dynamic invocation for custom awaitable types. For AOT " + + "compatibility, use Task or ValueTask directly.")] + [.("ConvertObject uses reflection to handle custom awaitable types and F# async. For " + + "AOT compatibility, use Task or ValueTask directly.")] public static . ConvertObject(object? invoke) { } - [.("Trimming", "IL2075:\'this\' argument does not satisfy \'DynamicallyAccessedMembersAttribute\' in " + - "call to target method. The return value of the source method does not have match" + - "ing annotations.", Justification="GetAwaiter pattern detection for custom awaitables. For AOT, use standard Task/Va" + - "lueTask types or implement IAsyncEnumerable.")] + [.("Custom awaitable handling may require dynamic invocation. For AOT, use Task/Value" + + "Task.")] + [.("GetAwaiter pattern detection requires reflection for custom awaitable types. For " + + "AOT, use Task/ValueTask.")] public static bool TryGetAwaitableTask(object awaitable, [.(true)] out .? task) { } } [(.Class | .Method | .Property, AllowMultiple=true)] @@ -243,60 +249,50 @@ namespace public required string TestSessionId { get; init; } } [(.Class | .Method | .Property, AllowMultiple=true)] - [.("Trimming", "IL2109:Type derives from type with \'RequiresUnreferencedCodeAttribute\' which can " + - "break functionality when trimming application code", Justification="The specific constructors (1-5 parameters) are AOT-compatible when used with type" + - "of() expressions. Only the params constructor is incompatible.")] + [.("ClassDataSourceAttribute may require runtime type generation. For AOT compatibili" + + "ty, use strongly-typed ClassDataSourceAttribute instead.")] + [.("ClassDataSourceAttribute uses reflection to instantiate and access test data clas" + + "ses. For AOT compatibility, use strongly-typed ClassDataSourceAttribute inste" + + "ad.")] public sealed class ClassDataSourceAttribute : .UntypedDataSourceGeneratorAttribute { - [.("AOT", "IL3050:Calling members annotated with \'RequiresDynamicCodeAttribute\' may break fu" + - "nctionality when AOT compiling.", Justification="These constructors are AOT-compatible when types are specified using typeof() at " + - "compile time. Only the params constructor requires dynamic code.")] - [.("Trimming", "IL2026:Members annotated with \'RequiresUnreferencedCodeAttribute\' require dynamic" + - " access otherwise can break functionality when trimming application code", Justification="These constructors delegate to the params constructor but are AOT-safe when used " + - "with typeof() expressions at compile time. The DynamicallyAccessedMembers annota" + - "tions ensure required members are preserved.")] + [.("ClassDataSourceAttribute may require runtime type generation. For AOT compatibili" + + "ty, use strongly-typed ClassDataSourceAttribute instead.")] + [.("ClassDataSourceAttribute uses reflection to instantiate and access test data clas" + + "ses. For AOT compatibility, use strongly-typed ClassDataSourceAttribute inste" + + "ad.")] public ClassDataSourceAttribute([.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..PublicMethods | ..PublicProperties)] type) { } [.("Reflection")] [.("Reflection")] public ClassDataSourceAttribute(params [] types) { } - [.("AOT", "IL3050:Calling members annotated with \'RequiresDynamicCodeAttribute\' may break fu" + - "nctionality when AOT compiling.", Justification="These constructors are AOT-compatible when types are specified using typeof() at " + - "compile time. Only the params constructor requires dynamic code.")] - [.("Trimming", "IL2026:Members annotated with \'RequiresUnreferencedCodeAttribute\' require dynamic" + - " access otherwise can break functionality when trimming application code", Justification="These constructors delegate to the params constructor but are AOT-safe when used " + - "with typeof() expressions at compile time. The DynamicallyAccessedMembers annota" + - "tions ensure required members are preserved.")] + [.("ClassDataSourceAttribute may require runtime type generation. For AOT compatibili" + + "ty, use strongly-typed ClassDataSourceAttribute instead.")] + [.("ClassDataSourceAttribute uses reflection to instantiate and access test data clas" + + "ses. For AOT compatibility, use strongly-typed ClassDataSourceAttribute inste" + + "ad.")] public ClassDataSourceAttribute([.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..PublicMethods | ..PublicProperties)] type, [.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..PublicMethods | ..PublicProperties)] type2) { } - [.("AOT", "IL3050:Calling members annotated with \'RequiresDynamicCodeAttribute\' may break fu" + - "nctionality when AOT compiling.", Justification="These constructors are AOT-compatible when types are specified using typeof() at " + - "compile time. Only the params constructor requires dynamic code.")] - [.("Trimming", "IL2026:Members annotated with \'RequiresUnreferencedCodeAttribute\' require dynamic" + - " access otherwise can break functionality when trimming application code", Justification="These constructors delegate to the params constructor but are AOT-safe when used " + - "with typeof() expressions at compile time. The DynamicallyAccessedMembers annota" + - "tions ensure required members are preserved.")] + [.("ClassDataSourceAttribute may require runtime type generation. For AOT compatibili" + + "ty, use strongly-typed ClassDataSourceAttribute instead.")] + [.("ClassDataSourceAttribute uses reflection to instantiate and access test data clas" + + "ses. For AOT compatibility, use strongly-typed ClassDataSourceAttribute inste" + + "ad.")] public ClassDataSourceAttribute([.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..PublicMethods | ..PublicProperties)] type, [.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..PublicMethods | ..PublicProperties)] type2, [.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..PublicMethods | ..PublicProperties)] type3) { } - [.("AOT", "IL3050:Calling members annotated with \'RequiresDynamicCodeAttribute\' may break fu" + - "nctionality when AOT compiling.", Justification="These constructors are AOT-compatible when types are specified using typeof() at " + - "compile time. Only the params constructor requires dynamic code.")] - [.("Trimming", "IL2026:Members annotated with \'RequiresUnreferencedCodeAttribute\' require dynamic" + - " access otherwise can break functionality when trimming application code", Justification="These constructors delegate to the params constructor but are AOT-safe when used " + - "with typeof() expressions at compile time. The DynamicallyAccessedMembers annota" + - "tions ensure required members are preserved.")] + [.("ClassDataSourceAttribute may require runtime type generation. For AOT compatibili" + + "ty, use strongly-typed ClassDataSourceAttribute instead.")] + [.("ClassDataSourceAttribute uses reflection to instantiate and access test data clas" + + "ses. For AOT compatibility, use strongly-typed ClassDataSourceAttribute inste" + + "ad.")] public ClassDataSourceAttribute([.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..PublicMethods | ..PublicProperties)] type, [.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..PublicMethods | ..PublicProperties)] type2, [.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..PublicMethods | ..PublicProperties)] type3, [.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..PublicMethods | ..PublicProperties)] type4) { } - [.("AOT", "IL3050:Calling members annotated with \'RequiresDynamicCodeAttribute\' may break fu" + - "nctionality when AOT compiling.", Justification="These constructors are AOT-compatible when types are specified using typeof() at " + - "compile time. Only the params constructor requires dynamic code.")] - [.("Trimming", "IL2026:Members annotated with \'RequiresUnreferencedCodeAttribute\' require dynamic" + - " access otherwise can break functionality when trimming application code", Justification="These constructors delegate to the params constructor but are AOT-safe when used " + - "with typeof() expressions at compile time. The DynamicallyAccessedMembers annota" + - "tions ensure required members are preserved.")] + [.("ClassDataSourceAttribute may require runtime type generation. For AOT compatibili" + + "ty, use strongly-typed ClassDataSourceAttribute instead.")] + [.("ClassDataSourceAttribute uses reflection to instantiate and access test data clas" + + "ses. For AOT compatibility, use strongly-typed ClassDataSourceAttribute inste" + + "ad.")] public ClassDataSourceAttribute([.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..PublicMethods | ..PublicProperties)] type, [.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..PublicMethods | ..PublicProperties)] type2, [.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..PublicMethods | ..PublicProperties)] type3, [.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..PublicMethods | ..PublicProperties)] type4, [.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..PublicMethods | ..PublicProperties)] type5) { } public string[] Keys { get; set; } public .SharedType[] Shared { get; set; } - [.("Trimming", "IL2062:The parameter of method has a DynamicallyAccessedMembersAttribute, but the" + - " value passed to it can not be statically analyzed.", Justification="The _types array is populated from constructor parameters that have DynamicallyAc" + - "cessedMembers attributes, ensuring the required members are preserved at the cal" + - "l site.")] + [.("Reflection")] + [.("Reflection")] protected override .<> GenerateDataSources(.DataGeneratorMetadata dataGeneratorMetadata) { } public . GetKeys() { } public .<.SharedType> GetSharedTypes() { } @@ -524,6 +520,7 @@ namespace protected virtual void ConfigureThread(.Thread thread) { } protected override sealed . ExecuteAsync(<.> action) { } protected virtual void Initialize() { } + [.("Type comes from runtime objects that cannot be annotated")] public . OnTestRegistered(.TestRegisteredContext context) { } } public class DefaultExecutor : .GenericAbstractExecutor @@ -902,12 +899,14 @@ namespace public MatrixAttribute(params T?[]? objects) { } } [(.Class | .Method)] - [.("AOT", "IL2109:Type \'MatrixDataSourceAttribute\' derives from base class with RequiresUnre" + - "ferencedCodeAttribute", Justification="Matrix data source implementation is AOT-compatible with proper enum field preser" + - "vation")] + [.("MatrixDataSource may process enum types dynamically")] + [.("MatrixDataSource uses reflection to access parameter attributes and test metadata" + + ". For AOT compatibility, consider using explicit data sources.")] public sealed class MatrixDataSourceAttribute : .UntypedDataSourceGeneratorAttribute, .IAccessesInstanceData { public MatrixDataSourceAttribute() { } + [.("Matrix generation may process enum types dynamically")] + [.("Matrix generation requires reflection")] protected override .<> GenerateDataSources(.DataGeneratorMetadata dataGeneratorMetadata) { } } [(.Class | .Method, AllowMultiple=true)] @@ -956,12 +955,10 @@ namespace public ? ClassProvidingDataSource { get; } public <.DataGeneratorMetadata, .<<.>>>? Factory { get; set; } public string MethodNameProvidingDataSource { get; } - [.("AOT", "IL2072:UnrecognizedReflectionPattern", Justification="Method data sources require runtime discovery and invocation of methods. The targ" + - "et type is determined dynamically from test metadata. For AOT scenarios, source " + - "generation should be used to pre-compile method references.")] - [.("AOT", "IL2075:UnrecognizedReflectionPattern", Justification="GetType() is called on runtime objects from test class instances. The actual type" + - "s cannot be statically determined. For AOT scenarios, source generation captures" + - " these types at compile time.")] + [.("Trimming", "IL2072", Justification="Method data sources require runtime discovery. AOT users should use Factory prope" + + "rty.")] + [.("Trimming", "IL2075", Justification="Method data sources require runtime discovery. AOT users should use Factory prope" + + "rty.")] [.(typeof(.MethodDataSourceAttribute.d__17))] public .<<.>> GetDataRowsAsync(.DataGeneratorMetadata dataGeneratorMetadata) { } } @@ -1033,6 +1030,7 @@ namespace { public ParallelLimiterAttribute() { } public int Order { get; } + [.("Type comes from runtime objects that cannot be annotated")] public . OnTestRegistered(.TestRegisteredContext context) { } } [.DebuggerDisplay("{Type} {Name}")] @@ -1107,9 +1105,7 @@ namespace } public static class PropertySourceRegistry { - [.("Trimming", "IL2070", Justification="Reflection discovery is used when source-generated metadata is not available. Thi" + - "s supports dynamically loaded assemblies and runtime property injection. For AOT" + - " scenarios, the source generator pre-discovers all injectable properties.")] + [.("Reflection discovery is used when source-generated metadata is not available")] public static .PropertyInjectionData[] DiscoverInjectableProperties([.(..None | ..PublicFields | ..NonPublicFields | ..PublicProperties)] type) { } [return: .(new string[] { "Type", @@ -1181,6 +1177,7 @@ namespace public SkipAttribute(string reason) { } public int Order { get; } public string Reason { get; } + [.("Type comes from runtime objects that cannot be annotated")] public . OnTestRegistered(.TestRegisteredContext context) { } public virtual . ShouldSkip(.TestRegisteredContext context) { } } @@ -1220,16 +1217,12 @@ namespace public static readonly .<..IPropertySource> PropertySources; public static readonly .<, .<..ITestSource>> TestSources; } - [.("Trimming", "IL2026:Members annotated with \'RequiresUnreferencedCodeAttribute\' require dynamic" + - " access", Justification="Reflection mode requires dynamic access")] - [.("Trimming", "IL2067:Target parameter argument does not satisfy annotation requirements", Justification="Reflection mode requires dynamic access")] - [.("Trimming", "IL2070:\'this\' argument does not satisfy \'" + - "perties\'", Justification="Reflection mode requires dynamic access")] - [.("Trimming", "IL2075:\'this\' argument does not satisfy \'" + - "perties\'", Justification="Reflection mode requires dynamic access")] + [.("Reflection mode requires dynamic access for static property initialization")] public static class StaticPropertyReflectionInitializer { + [.("Data source initialization may require dynamic code generation")] public static . InitializeAllStaticPropertiesAsync() { } + [.("Data source initialization may require dynamic code generation")] public static . InitializeStaticPropertiesForType( type) { } } public class TUnitAttribute : { } @@ -1301,7 +1294,6 @@ namespace public .<.Timing> Timings { get; } public static . Configuration { get; } public new static .TestContext? Current { get; } - [get: .("SingleFile", "IL3000:Avoid accessing Assembly file path when publishing as a single file", Justification="Dynamic code check implemented")] public static string? OutputDirectory { get; } public static .> Parameters { get; } public static string WorkingDirectory { get; set; } @@ -1873,6 +1865,7 @@ namespace .Executors public CultureAttribute(.CultureInfo cultureInfo) { } public CultureAttribute(string cultureName) { } public int Order { get; } + [.("Type comes from runtime objects that cannot be annotated")] public . OnTestRegistered(.TestRegisteredContext context) { } } public class HookExecutorAttribute : .TUnitAttribute @@ -1897,6 +1890,7 @@ namespace .Executors { public STAThreadExecutorAttribute() { } public int Order { get; } + [.("Type comes from runtime objects that cannot be annotated")] public . OnTestRegistered(.TestRegisteredContext context) { } } [(.Assembly | .Class | .Method)] @@ -1904,6 +1898,7 @@ namespace .Executors { public TestExecutorAttribute([.(..PublicConstructors)] type) { } public int Order { get; } + [.("Type comes from runtime objects that cannot be annotated")] public . OnTestRegistered(.TestRegisteredContext context) { } } [(.Assembly | .Class | .Method)] @@ -1912,6 +1907,7 @@ namespace .Executors { public TestExecutorAttribute() { } public int Order { get; } + [.("Type comes from runtime objects that cannot be annotated")] public . OnTestRegistered(.TestRegisteredContext context) { } } } @@ -1936,6 +1932,7 @@ namespace .Extensions { [.("Adding dynamic tests requires reflection which is not supported in native AOT sce" + "narios.")] + [.("Dynamic test metadata creation uses reflection")] public static . AddDynamicTest<[.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..NonPublicConstructors | ..PublicMethods | ..NonPublicMethods | ..PublicFields | ..NonPublicFields | ..PublicProperties)] T>(this .TestContext context, .DynamicTest dynamicTest) where T : class { } public static string GetClassTypeName(this .TestContext context) { } @@ -1953,15 +1950,11 @@ namespace .Helpers } public static class CastHelper { - [.("AOT", "IL3050", Justification="Reflection-based conversion is a fallback for runtime scenarios. AOT applications" + - " should use explicit conversions.")] - [.("Trimming", "IL2072", Justification="Type conversion uses DynamicallyAccessedMembers for known conversion patterns. Fo" + - "r AOT scenarios, use explicit type conversions.")] + [.("Dynamic type conversion may require runtime code generation")] + [.("Type conversion uses reflection for custom conversions")] public static object? Cast([.(..None | ..PublicMethods | ..NonPublicMethods)] type, object? value) { } - [.("AOT", "IL3050", Justification="Reflection-based conversion is a fallback for runtime scenarios. AOT applications" + - " should use explicit conversions.")] - [.("Trimming", "IL2072", Justification="Type conversion uses DynamicallyAccessedMembers for known conversion patterns. Fo" + - "r AOT scenarios, use explicit type conversions.")] + [.("Dynamic type conversion may require runtime code generation")] + [.("Type conversion uses reflection for custom conversions")] public static T? Cast<[.(..None | ..PublicMethods | ..NonPublicMethods)] T>(object? value) { } public static .MethodInfo? GetConversionMethod([.(..None | ..PublicMethods | ..NonPublicMethods)] baseType, [.(..None | ..PublicMethods | ..NonPublicMethods)] targetType) { } } @@ -2022,6 +2015,8 @@ namespace .Helpers public static <.>[] ProcessTestDataSource(T data, int expectedParameterCount = -1) { } public static void RegisterPropertyInitializer( initializer) { } public static void RegisterTypeCreator(<.MethodMetadata, string, .> creator) { } + [.("Data source resolution may require dynamic code generation")] + [.("Property types are resolved through reflection")] public static . ResolveDataSourceForPropertyAsync([.(..None | ..PublicParameterlessConstructor | ..PublicFields | ..NonPublicFields | ..PublicProperties)] containingType, string propertyName, .MethodMetadata testInformation, string testSessionId) { } public static . ResolveDataSourcePropertyAsync(object instance, string propertyName, .MethodMetadata testInformation, string testSessionId) { } public static object?[] ToObjectArray(this object? item) { } @@ -2037,8 +2032,6 @@ namespace .Helpers public static object?[] UnwrapTuple( tuple) { } public static object?[] UnwrapTuple( tuple) { } public static object?[] UnwrapTuple( tuple) { } - [.("Trimming", "IL2091:Target generic argument does not satisfy \'DynamicallyAccessedMembersAttrib" + - "ute\' in target method or type.", Justification="We handle specific known tuple types without reflection")] public static object?[] UnwrapTupleAot(object? value) { } } public static class DecimalParsingHelper @@ -2049,8 +2042,7 @@ namespace .Helpers { public static GetGenericTypeDefinition( type) { } public static bool IsConstructedGenericType( type) { } - [.("AOT", "IL2055:UnrecognizedReflectionPattern", Justification="MakeGenericType is used as a fallback. AOT analyzer warns at compile time.")] - [.("AOT", "IL3050:RequiresDynamicCode", Justification="MakeGenericType is used as a fallback. AOT analyzer warns at compile time.")] + [.("MakeGenericType requires runtime code generation")] public static MakeGenericTypeSafe( genericTypeDefinition, params [] typeArguments) { } } public class ProcessorCountParallelLimit : . @@ -2081,7 +2073,7 @@ namespace .Helpers } public static class TupleHelper { - [.("ReflectionAnalysis", "IL2075:UnrecognizedReflectionPattern", Justification="Reflection is used as a fallback. AOT analyzer warns at compile time.")] + [.("Tuple expansion uses reflection as fallback")] public static . ExpandTupleArray(object? value) { } public static bool IsTupleArrayType( type) { } public static bool IsTupleType(. tuple) { } @@ -2190,9 +2182,7 @@ namespace .Hooks public bool Execute(.AssemblyHookContext context, .CancellationToken cancellationToken) { } public . ExecuteAsync(.AssemblyHookContext context, .CancellationToken cancellationToken) { } } - [.("Trimming", "IL2111:Method with parameters or return value with `DynamicallyAccessedMembersAtt" + - "ribute` is accessed via reflection. Trimmer can\'t guarantee availability of the " + - "requirements of the method.")] + [.("Method with DynamicallyAccessedMembersAttribute accessed via reflection")] public class LastTestInClassAdapter : .<.ClassHookContext> { public LastTestInClassAdapter(. lastTestInClassEventReceiver, .TestContext testContext) { } @@ -2362,12 +2352,14 @@ namespace .Interfaces } public interface ITestRegisteredEventReceiver : . { + [.("Type comes from runtime objects that cannot be annotated")] . OnTestRegistered(.TestRegisteredContext context); } public interface ITestRegistry { [.("Adding dynamic tests requires runtime compilation and reflection which are not su" + "pported in native AOT scenarios.")] + [.("Dynamic test metadata creation uses reflection")] . AddDynamicTest<[.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..NonPublicConstructors | ..PublicMethods | ..NonPublicMethods | ..PublicFields | ..NonPublicFields | ..PublicProperties)] T>(.TestContext context, .DynamicTest dynamicTest) where T : class; } diff --git a/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet9_0.verified.txt b/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet9_0.verified.txt index 4624ef4330..b7c4acacd6 100644 --- a/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet9_0.verified.txt +++ b/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet9_0.verified.txt @@ -74,6 +74,7 @@ namespace public object?[] Values { get; } [.(typeof(.ArgumentsAttribute.d__8))] public .<<.>> GetDataRowsAsync(.DataGeneratorMetadata dataGeneratorMetadata) { } + [.("Type comes from runtime objects that cannot be annotated")] public . OnTestRegistered(.TestRegisteredContext context) { } } [(.Class | .Method | .Property, AllowMultiple=true)] @@ -84,6 +85,7 @@ namespace public string? Skip { get; set; } [.(typeof(.ArgumentsAttribute.d__6))] public override .<<.>> GetTypedDataRowsAsync(.DataGeneratorMetadata dataGeneratorMetadata) { } + [.("Type comes from runtime objects that cannot be annotated")] public . OnTestRegistered(.TestRegisteredContext context) { } } public class Artifact @@ -118,11 +120,15 @@ namespace public static . Convert( action) { } public static . Convert(<.> action) { } public static . Convert(<.> action) { } + [.("ConvertObject may require dynamic invocation for custom awaitable types. For AOT " + + "compatibility, use Task or ValueTask directly.")] + [.("ConvertObject uses reflection to handle custom awaitable types and F# async. For " + + "AOT compatibility, use Task or ValueTask directly.")] public static . ConvertObject(object? invoke) { } - [.("Trimming", "IL2075:\'this\' argument does not satisfy \'DynamicallyAccessedMembersAttribute\' in " + - "call to target method. The return value of the source method does not have match" + - "ing annotations.", Justification="GetAwaiter pattern detection for custom awaitables. For AOT, use standard Task/Va" + - "lueTask types or implement IAsyncEnumerable.")] + [.("Custom awaitable handling may require dynamic invocation. For AOT, use Task/Value" + + "Task.")] + [.("GetAwaiter pattern detection requires reflection for custom awaitable types. For " + + "AOT, use Task/ValueTask.")] public static bool TryGetAwaitableTask(object awaitable, [.(true)] out .? task) { } } [(.Class | .Method | .Property, AllowMultiple=true)] @@ -243,60 +249,50 @@ namespace public required string TestSessionId { get; init; } } [(.Class | .Method | .Property, AllowMultiple=true)] - [.("Trimming", "IL2109:Type derives from type with \'RequiresUnreferencedCodeAttribute\' which can " + - "break functionality when trimming application code", Justification="The specific constructors (1-5 parameters) are AOT-compatible when used with type" + - "of() expressions. Only the params constructor is incompatible.")] + [.("ClassDataSourceAttribute may require runtime type generation. For AOT compatibili" + + "ty, use strongly-typed ClassDataSourceAttribute instead.")] + [.("ClassDataSourceAttribute uses reflection to instantiate and access test data clas" + + "ses. For AOT compatibility, use strongly-typed ClassDataSourceAttribute inste" + + "ad.")] public sealed class ClassDataSourceAttribute : .UntypedDataSourceGeneratorAttribute { - [.("AOT", "IL3050:Calling members annotated with \'RequiresDynamicCodeAttribute\' may break fu" + - "nctionality when AOT compiling.", Justification="These constructors are AOT-compatible when types are specified using typeof() at " + - "compile time. Only the params constructor requires dynamic code.")] - [.("Trimming", "IL2026:Members annotated with \'RequiresUnreferencedCodeAttribute\' require dynamic" + - " access otherwise can break functionality when trimming application code", Justification="These constructors delegate to the params constructor but are AOT-safe when used " + - "with typeof() expressions at compile time. The DynamicallyAccessedMembers annota" + - "tions ensure required members are preserved.")] + [.("ClassDataSourceAttribute may require runtime type generation. For AOT compatibili" + + "ty, use strongly-typed ClassDataSourceAttribute instead.")] + [.("ClassDataSourceAttribute uses reflection to instantiate and access test data clas" + + "ses. For AOT compatibility, use strongly-typed ClassDataSourceAttribute inste" + + "ad.")] public ClassDataSourceAttribute([.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..PublicMethods | ..PublicProperties)] type) { } [.("Reflection")] [.("Reflection")] public ClassDataSourceAttribute(params [] types) { } - [.("AOT", "IL3050:Calling members annotated with \'RequiresDynamicCodeAttribute\' may break fu" + - "nctionality when AOT compiling.", Justification="These constructors are AOT-compatible when types are specified using typeof() at " + - "compile time. Only the params constructor requires dynamic code.")] - [.("Trimming", "IL2026:Members annotated with \'RequiresUnreferencedCodeAttribute\' require dynamic" + - " access otherwise can break functionality when trimming application code", Justification="These constructors delegate to the params constructor but are AOT-safe when used " + - "with typeof() expressions at compile time. The DynamicallyAccessedMembers annota" + - "tions ensure required members are preserved.")] + [.("ClassDataSourceAttribute may require runtime type generation. For AOT compatibili" + + "ty, use strongly-typed ClassDataSourceAttribute instead.")] + [.("ClassDataSourceAttribute uses reflection to instantiate and access test data clas" + + "ses. For AOT compatibility, use strongly-typed ClassDataSourceAttribute inste" + + "ad.")] public ClassDataSourceAttribute([.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..PublicMethods | ..PublicProperties)] type, [.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..PublicMethods | ..PublicProperties)] type2) { } - [.("AOT", "IL3050:Calling members annotated with \'RequiresDynamicCodeAttribute\' may break fu" + - "nctionality when AOT compiling.", Justification="These constructors are AOT-compatible when types are specified using typeof() at " + - "compile time. Only the params constructor requires dynamic code.")] - [.("Trimming", "IL2026:Members annotated with \'RequiresUnreferencedCodeAttribute\' require dynamic" + - " access otherwise can break functionality when trimming application code", Justification="These constructors delegate to the params constructor but are AOT-safe when used " + - "with typeof() expressions at compile time. The DynamicallyAccessedMembers annota" + - "tions ensure required members are preserved.")] + [.("ClassDataSourceAttribute may require runtime type generation. For AOT compatibili" + + "ty, use strongly-typed ClassDataSourceAttribute instead.")] + [.("ClassDataSourceAttribute uses reflection to instantiate and access test data clas" + + "ses. For AOT compatibility, use strongly-typed ClassDataSourceAttribute inste" + + "ad.")] public ClassDataSourceAttribute([.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..PublicMethods | ..PublicProperties)] type, [.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..PublicMethods | ..PublicProperties)] type2, [.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..PublicMethods | ..PublicProperties)] type3) { } - [.("AOT", "IL3050:Calling members annotated with \'RequiresDynamicCodeAttribute\' may break fu" + - "nctionality when AOT compiling.", Justification="These constructors are AOT-compatible when types are specified using typeof() at " + - "compile time. Only the params constructor requires dynamic code.")] - [.("Trimming", "IL2026:Members annotated with \'RequiresUnreferencedCodeAttribute\' require dynamic" + - " access otherwise can break functionality when trimming application code", Justification="These constructors delegate to the params constructor but are AOT-safe when used " + - "with typeof() expressions at compile time. The DynamicallyAccessedMembers annota" + - "tions ensure required members are preserved.")] + [.("ClassDataSourceAttribute may require runtime type generation. For AOT compatibili" + + "ty, use strongly-typed ClassDataSourceAttribute instead.")] + [.("ClassDataSourceAttribute uses reflection to instantiate and access test data clas" + + "ses. For AOT compatibility, use strongly-typed ClassDataSourceAttribute inste" + + "ad.")] public ClassDataSourceAttribute([.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..PublicMethods | ..PublicProperties)] type, [.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..PublicMethods | ..PublicProperties)] type2, [.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..PublicMethods | ..PublicProperties)] type3, [.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..PublicMethods | ..PublicProperties)] type4) { } - [.("AOT", "IL3050:Calling members annotated with \'RequiresDynamicCodeAttribute\' may break fu" + - "nctionality when AOT compiling.", Justification="These constructors are AOT-compatible when types are specified using typeof() at " + - "compile time. Only the params constructor requires dynamic code.")] - [.("Trimming", "IL2026:Members annotated with \'RequiresUnreferencedCodeAttribute\' require dynamic" + - " access otherwise can break functionality when trimming application code", Justification="These constructors delegate to the params constructor but are AOT-safe when used " + - "with typeof() expressions at compile time. The DynamicallyAccessedMembers annota" + - "tions ensure required members are preserved.")] + [.("ClassDataSourceAttribute may require runtime type generation. For AOT compatibili" + + "ty, use strongly-typed ClassDataSourceAttribute instead.")] + [.("ClassDataSourceAttribute uses reflection to instantiate and access test data clas" + + "ses. For AOT compatibility, use strongly-typed ClassDataSourceAttribute inste" + + "ad.")] public ClassDataSourceAttribute([.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..PublicMethods | ..PublicProperties)] type, [.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..PublicMethods | ..PublicProperties)] type2, [.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..PublicMethods | ..PublicProperties)] type3, [.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..PublicMethods | ..PublicProperties)] type4, [.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..PublicMethods | ..PublicProperties)] type5) { } public string[] Keys { get; set; } public .SharedType[] Shared { get; set; } - [.("Trimming", "IL2062:The parameter of method has a DynamicallyAccessedMembersAttribute, but the" + - " value passed to it can not be statically analyzed.", Justification="The _types array is populated from constructor parameters that have DynamicallyAc" + - "cessedMembers attributes, ensuring the required members are preserved at the cal" + - "l site.")] + [.("Reflection")] + [.("Reflection")] protected override .<> GenerateDataSources(.DataGeneratorMetadata dataGeneratorMetadata) { } public . GetKeys() { } public .<.SharedType> GetSharedTypes() { } @@ -524,6 +520,7 @@ namespace protected virtual void ConfigureThread(.Thread thread) { } protected override sealed . ExecuteAsync(<.> action) { } protected virtual void Initialize() { } + [.("Type comes from runtime objects that cannot be annotated")] public . OnTestRegistered(.TestRegisteredContext context) { } } public class DefaultExecutor : .GenericAbstractExecutor @@ -902,12 +899,14 @@ namespace public MatrixAttribute(params T?[]? objects) { } } [(.Class | .Method)] - [.("AOT", "IL2109:Type \'MatrixDataSourceAttribute\' derives from base class with RequiresUnre" + - "ferencedCodeAttribute", Justification="Matrix data source implementation is AOT-compatible with proper enum field preser" + - "vation")] + [.("MatrixDataSource may process enum types dynamically")] + [.("MatrixDataSource uses reflection to access parameter attributes and test metadata" + + ". For AOT compatibility, consider using explicit data sources.")] public sealed class MatrixDataSourceAttribute : .UntypedDataSourceGeneratorAttribute, .IAccessesInstanceData { public MatrixDataSourceAttribute() { } + [.("Matrix generation may process enum types dynamically")] + [.("Matrix generation requires reflection")] protected override .<> GenerateDataSources(.DataGeneratorMetadata dataGeneratorMetadata) { } } [(.Class | .Method, AllowMultiple=true)] @@ -956,12 +955,10 @@ namespace public ? ClassProvidingDataSource { get; } public <.DataGeneratorMetadata, .<<.>>>? Factory { get; set; } public string MethodNameProvidingDataSource { get; } - [.("AOT", "IL2072:UnrecognizedReflectionPattern", Justification="Method data sources require runtime discovery and invocation of methods. The targ" + - "et type is determined dynamically from test metadata. For AOT scenarios, source " + - "generation should be used to pre-compile method references.")] - [.("AOT", "IL2075:UnrecognizedReflectionPattern", Justification="GetType() is called on runtime objects from test class instances. The actual type" + - "s cannot be statically determined. For AOT scenarios, source generation captures" + - " these types at compile time.")] + [.("Trimming", "IL2072", Justification="Method data sources require runtime discovery. AOT users should use Factory prope" + + "rty.")] + [.("Trimming", "IL2075", Justification="Method data sources require runtime discovery. AOT users should use Factory prope" + + "rty.")] [.(typeof(.MethodDataSourceAttribute.d__17))] public .<<.>> GetDataRowsAsync(.DataGeneratorMetadata dataGeneratorMetadata) { } } @@ -1033,6 +1030,7 @@ namespace { public ParallelLimiterAttribute() { } public int Order { get; } + [.("Type comes from runtime objects that cannot be annotated")] public . OnTestRegistered(.TestRegisteredContext context) { } } [.DebuggerDisplay("{Type} {Name}")] @@ -1107,9 +1105,7 @@ namespace } public static class PropertySourceRegistry { - [.("Trimming", "IL2070", Justification="Reflection discovery is used when source-generated metadata is not available. Thi" + - "s supports dynamically loaded assemblies and runtime property injection. For AOT" + - " scenarios, the source generator pre-discovers all injectable properties.")] + [.("Reflection discovery is used when source-generated metadata is not available")] public static .PropertyInjectionData[] DiscoverInjectableProperties([.(..None | ..PublicFields | ..NonPublicFields | ..PublicProperties)] type) { } [return: .(new string[] { "Type", @@ -1181,6 +1177,7 @@ namespace public SkipAttribute(string reason) { } public int Order { get; } public string Reason { get; } + [.("Type comes from runtime objects that cannot be annotated")] public . OnTestRegistered(.TestRegisteredContext context) { } public virtual . ShouldSkip(.TestRegisteredContext context) { } } @@ -1220,16 +1217,12 @@ namespace public static readonly .<..IPropertySource> PropertySources; public static readonly .<, .<..ITestSource>> TestSources; } - [.("Trimming", "IL2026:Members annotated with \'RequiresUnreferencedCodeAttribute\' require dynamic" + - " access", Justification="Reflection mode requires dynamic access")] - [.("Trimming", "IL2067:Target parameter argument does not satisfy annotation requirements", Justification="Reflection mode requires dynamic access")] - [.("Trimming", "IL2070:\'this\' argument does not satisfy \'" + - "perties\'", Justification="Reflection mode requires dynamic access")] - [.("Trimming", "IL2075:\'this\' argument does not satisfy \'" + - "perties\'", Justification="Reflection mode requires dynamic access")] + [.("Reflection mode requires dynamic access for static property initialization")] public static class StaticPropertyReflectionInitializer { + [.("Data source initialization may require dynamic code generation")] public static . InitializeAllStaticPropertiesAsync() { } + [.("Data source initialization may require dynamic code generation")] public static . InitializeStaticPropertiesForType( type) { } } public class TUnitAttribute : { } @@ -1301,7 +1294,6 @@ namespace public .<.Timing> Timings { get; } public static . Configuration { get; } public new static .TestContext? Current { get; } - [get: .("SingleFile", "IL3000:Avoid accessing Assembly file path when publishing as a single file", Justification="Dynamic code check implemented")] public static string? OutputDirectory { get; } public static .> Parameters { get; } public static string WorkingDirectory { get; set; } @@ -1873,6 +1865,7 @@ namespace .Executors public CultureAttribute(.CultureInfo cultureInfo) { } public CultureAttribute(string cultureName) { } public int Order { get; } + [.("Type comes from runtime objects that cannot be annotated")] public . OnTestRegistered(.TestRegisteredContext context) { } } public class HookExecutorAttribute : .TUnitAttribute @@ -1897,6 +1890,7 @@ namespace .Executors { public STAThreadExecutorAttribute() { } public int Order { get; } + [.("Type comes from runtime objects that cannot be annotated")] public . OnTestRegistered(.TestRegisteredContext context) { } } [(.Assembly | .Class | .Method)] @@ -1904,6 +1898,7 @@ namespace .Executors { public TestExecutorAttribute([.(..PublicConstructors)] type) { } public int Order { get; } + [.("Type comes from runtime objects that cannot be annotated")] public . OnTestRegistered(.TestRegisteredContext context) { } } [(.Assembly | .Class | .Method)] @@ -1912,6 +1907,7 @@ namespace .Executors { public TestExecutorAttribute() { } public int Order { get; } + [.("Type comes from runtime objects that cannot be annotated")] public . OnTestRegistered(.TestRegisteredContext context) { } } } @@ -1936,6 +1932,7 @@ namespace .Extensions { [.("Adding dynamic tests requires reflection which is not supported in native AOT sce" + "narios.")] + [.("Dynamic test metadata creation uses reflection")] public static . AddDynamicTest<[.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..NonPublicConstructors | ..PublicMethods | ..NonPublicMethods | ..PublicFields | ..NonPublicFields | ..PublicProperties)] T>(this .TestContext context, .DynamicTest dynamicTest) where T : class { } public static string GetClassTypeName(this .TestContext context) { } @@ -1953,15 +1950,11 @@ namespace .Helpers } public static class CastHelper { - [.("AOT", "IL3050", Justification="Reflection-based conversion is a fallback for runtime scenarios. AOT applications" + - " should use explicit conversions.")] - [.("Trimming", "IL2072", Justification="Type conversion uses DynamicallyAccessedMembers for known conversion patterns. Fo" + - "r AOT scenarios, use explicit type conversions.")] + [.("Dynamic type conversion may require runtime code generation")] + [.("Type conversion uses reflection for custom conversions")] public static object? Cast([.(..None | ..PublicMethods | ..NonPublicMethods)] type, object? value) { } - [.("AOT", "IL3050", Justification="Reflection-based conversion is a fallback for runtime scenarios. AOT applications" + - " should use explicit conversions.")] - [.("Trimming", "IL2072", Justification="Type conversion uses DynamicallyAccessedMembers for known conversion patterns. Fo" + - "r AOT scenarios, use explicit type conversions.")] + [.("Dynamic type conversion may require runtime code generation")] + [.("Type conversion uses reflection for custom conversions")] public static T? Cast<[.(..None | ..PublicMethods | ..NonPublicMethods)] T>(object? value) { } public static .MethodInfo? GetConversionMethod([.(..None | ..PublicMethods | ..NonPublicMethods)] baseType, [.(..None | ..PublicMethods | ..NonPublicMethods)] targetType) { } } @@ -2022,6 +2015,8 @@ namespace .Helpers public static <.>[] ProcessTestDataSource(T data, int expectedParameterCount = -1) { } public static void RegisterPropertyInitializer( initializer) { } public static void RegisterTypeCreator(<.MethodMetadata, string, .> creator) { } + [.("Data source resolution may require dynamic code generation")] + [.("Property types are resolved through reflection")] public static . ResolveDataSourceForPropertyAsync([.(..None | ..PublicParameterlessConstructor | ..PublicFields | ..NonPublicFields | ..PublicProperties)] containingType, string propertyName, .MethodMetadata testInformation, string testSessionId) { } public static . ResolveDataSourcePropertyAsync(object instance, string propertyName, .MethodMetadata testInformation, string testSessionId) { } public static object?[] ToObjectArray(this object? item) { } @@ -2037,8 +2032,6 @@ namespace .Helpers public static object?[] UnwrapTuple( tuple) { } public static object?[] UnwrapTuple( tuple) { } public static object?[] UnwrapTuple( tuple) { } - [.("Trimming", "IL2091:Target generic argument does not satisfy \'DynamicallyAccessedMembersAttrib" + - "ute\' in target method or type.", Justification="We handle specific known tuple types without reflection")] public static object?[] UnwrapTupleAot(object? value) { } } public static class DecimalParsingHelper @@ -2049,8 +2042,7 @@ namespace .Helpers { public static GetGenericTypeDefinition( type) { } public static bool IsConstructedGenericType( type) { } - [.("AOT", "IL2055:UnrecognizedReflectionPattern", Justification="MakeGenericType is used as a fallback. AOT analyzer warns at compile time.")] - [.("AOT", "IL3050:RequiresDynamicCode", Justification="MakeGenericType is used as a fallback. AOT analyzer warns at compile time.")] + [.("MakeGenericType requires runtime code generation")] public static MakeGenericTypeSafe( genericTypeDefinition, params [] typeArguments) { } } public class ProcessorCountParallelLimit : . @@ -2081,7 +2073,7 @@ namespace .Helpers } public static class TupleHelper { - [.("ReflectionAnalysis", "IL2075:UnrecognizedReflectionPattern", Justification="Reflection is used as a fallback. AOT analyzer warns at compile time.")] + [.("Tuple expansion uses reflection as fallback")] public static . ExpandTupleArray(object? value) { } public static bool IsTupleArrayType( type) { } public static bool IsTupleType(. tuple) { } @@ -2190,9 +2182,7 @@ namespace .Hooks public bool Execute(.AssemblyHookContext context, .CancellationToken cancellationToken) { } public . ExecuteAsync(.AssemblyHookContext context, .CancellationToken cancellationToken) { } } - [.("Trimming", "IL2111:Method with parameters or return value with `DynamicallyAccessedMembersAtt" + - "ribute` is accessed via reflection. Trimmer can\'t guarantee availability of the " + - "requirements of the method.")] + [.("Method with DynamicallyAccessedMembersAttribute accessed via reflection")] public class LastTestInClassAdapter : .<.ClassHookContext> { public LastTestInClassAdapter(. lastTestInClassEventReceiver, .TestContext testContext) { } @@ -2362,12 +2352,14 @@ namespace .Interfaces } public interface ITestRegisteredEventReceiver : . { + [.("Type comes from runtime objects that cannot be annotated")] . OnTestRegistered(.TestRegisteredContext context); } public interface ITestRegistry { [.("Adding dynamic tests requires runtime compilation and reflection which are not su" + "pported in native AOT scenarios.")] + [.("Dynamic test metadata creation uses reflection")] . AddDynamicTest<[.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..NonPublicConstructors | ..PublicMethods | ..NonPublicMethods | ..PublicFields | ..NonPublicFields | ..PublicProperties)] T>(.TestContext context, .DynamicTest dynamicTest) where T : class; } diff --git a/TUnit.PublicAPI/Tests.Playwright_Library_Has_No_API_Changes.DotNet8_0.verified.txt b/TUnit.PublicAPI/Tests.Playwright_Library_Has_No_API_Changes.DotNet8_0.verified.txt index 94c2ff3012..69e722819a 100644 --- a/TUnit.PublicAPI/Tests.Playwright_Library_Has_No_API_Changes.DotNet8_0.verified.txt +++ b/TUnit.PublicAPI/Tests.Playwright_Library_Has_No_API_Changes.DotNet8_0.verified.txt @@ -122,6 +122,7 @@ namespace public WorkerAwareTest() { } public virtual bool UseDefaultParallelLimiter { get; } public int WorkerIndex { get; } + [.("Type comes from runtime objects that cannot be annotated")] public . OnTestRegistered(.TestRegisteredContext context) { } public . RegisterService(string name, <.> factory) where T : class, .IWorkerService { } diff --git a/TUnit.PublicAPI/Tests.Playwright_Library_Has_No_API_Changes.DotNet9_0.verified.txt b/TUnit.PublicAPI/Tests.Playwright_Library_Has_No_API_Changes.DotNet9_0.verified.txt index a87649c3cf..b42f2de81f 100644 --- a/TUnit.PublicAPI/Tests.Playwright_Library_Has_No_API_Changes.DotNet9_0.verified.txt +++ b/TUnit.PublicAPI/Tests.Playwright_Library_Has_No_API_Changes.DotNet9_0.verified.txt @@ -116,6 +116,7 @@ namespace public WorkerAwareTest() { } public virtual bool UseDefaultParallelLimiter { get; } public int WorkerIndex { get; } + [.("Type comes from runtime objects that cannot be annotated")] public . OnTestRegistered(.TestRegisteredContext context) { } public . RegisterService(string name, <.> factory) where T : class, .IWorkerService { } From 1ac8f09dae670c175f25487647680e373e874a92 Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Sun, 5 Oct 2025 12:36:50 +0100 Subject: [PATCH 07/14] fix: remove unnecessary whitespace in Library.props and TestBuilderPipeline.cs --- Library.props | 5 +---- TUnit.Engine/Building/TestBuilderPipeline.cs | 16 ++++++++-------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/Library.props b/Library.props index 36bd76fc63..c3e8636f73 100644 --- a/Library.props +++ b/Library.props @@ -8,10 +8,7 @@ true - - true - + true $(MSBuildThisFileDirectory)strongname.snk 0024000004800000940000000602000000240000525341310004000001000100698a70398fa0b2230c5a72e3bd9d56b48f809f6173e49a19fbb942d621be93ad48c5566b47b28faabc359b9ad3ff4e00bbdea88f5bdfa250f391fedd28182b2e37b55d429c0151a42a98ea7a5821818cd15a79fef9903e8607a88304cf3e0317bf86ec96e32e1381535a6582251e5a6eed40b5a3ed82bc444598b1269cce57a7 diff --git a/TUnit.Engine/Building/TestBuilderPipeline.cs b/TUnit.Engine/Building/TestBuilderPipeline.cs index 68296b15e2..459fb6f081 100644 --- a/TUnit.Engine/Building/TestBuilderPipeline.cs +++ b/TUnit.Engine/Building/TestBuilderPipeline.cs @@ -27,7 +27,7 @@ public TestBuilderPipeline( _contextProvider = contextBuilder; _eventReceiverOrchestrator = eventReceiverOrchestrator ?? throw new ArgumentNullException(nameof(eventReceiverOrchestrator)); } - + private TestBuilderContext CreateTestBuilderContext(TestMetadata metadata) { var testBuilderContext = new TestBuilderContext @@ -36,22 +36,22 @@ private TestBuilderContext CreateTestBuilderContext(TestMetadata metadata) Events = new TestContextEvents(), ObjectBag = new Dictionary() }; - + // Check for ClassConstructor attribute and set it early if present var attributes = metadata.AttributeFactory(); - + // Look for any attribute that inherits from ClassConstructorAttribute // This handles both ClassConstructorAttribute and ClassConstructorAttribute var classConstructorAttribute = attributes .Where(a => a is ClassConstructorAttribute) .Cast() .FirstOrDefault(); - + if (classConstructorAttribute != null) { testBuilderContext.ClassConstructor = (IClassConstructor)Activator.CreateInstance(classConstructorAttribute.ClassConstructorType)!; } - + return testBuilderContext; } @@ -175,14 +175,14 @@ private async Task GenerateDynamicTests(TestMetadata m }; var testId = TestIdentifierService.GenerateTestId(metadata, testData); - + var displayName = repeatCount > 0 ? $"{metadata.TestName} (Repeat {repeatIndex + 1}/{repeatCount + 1})" : metadata.TestName; // Get attributes first var attributes = metadata.AttributeFactory(); - + // Create TestDetails for dynamic tests var testDetails = new TestDetails { @@ -203,7 +203,7 @@ private async Task GenerateDynamicTests(TestMetadata m }; var testBuilderContext = CreateTestBuilderContext(metadata); - + var context = _contextProvider.CreateTestContext( metadata.TestName, metadata.TestClassType, From 861d50918e184188ea2a0ec6ea9f546f4d75625f Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Sun, 5 Oct 2025 12:47:26 +0100 Subject: [PATCH 08/14] fix: add UnconditionalSuppressMessage attributes for AOT compatibility in various classes --- .../Collectors/AotTestDataCollector.cs | 8 ++--- TUnit.Engine/Building/TestBuilder.cs | 20 ++--------- TUnit.Engine/Building/TestBuilderPipeline.cs | 36 ++++--------------- .../Building/TestDataCollectorFactory.cs | 6 ---- .../Framework/TUnitServiceProvider.cs | 8 ++--- TUnit.Engine/Framework/TUnitTestFramework.cs | 7 ++-- TUnit.Engine/TUnitInitializer.cs | 8 ++--- TUnit.Engine/TestSessionCoordinator.cs | 23 ++++-------- 8 files changed, 24 insertions(+), 92 deletions(-) diff --git a/TUnit.Engine/Building/Collectors/AotTestDataCollector.cs b/TUnit.Engine/Building/Collectors/AotTestDataCollector.cs index 1835179b3b..ffa495e8b6 100644 --- a/TUnit.Engine/Building/Collectors/AotTestDataCollector.cs +++ b/TUnit.Engine/Building/Collectors/AotTestDataCollector.cs @@ -18,6 +18,8 @@ internal sealed class AotTestDataCollector : ITestDataCollector #if NET6_0_OR_GREATER [UnconditionalSuppressMessage("Trimming", "IL2046", Justification = "AOT implementation uses source-generated metadata, not reflection")] [UnconditionalSuppressMessage("AOT", "IL3051", Justification = "AOT implementation uses source-generated metadata, not dynamic code")] + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Dynamic tests are optional and not used in AOT scenarios")] + [UnconditionalSuppressMessage("AOT", "IL3050", Justification = "Dynamic tests are optional and not used in AOT scenarios")] #endif public async Task> CollectTestsAsync(string testSessionId) { @@ -29,14 +31,8 @@ public async Task> CollectTestsAsync(string testSessio .SelectManyAsync(testSource => testSource.GetTestsAsync(testSessionId)) .ProcessInParallel(); - #if NET6_0_OR_GREATER - #pragma warning disable IL2026, IL3050 // Dynamic test collection is an optional feature that uses reflection - #endif var dynamicTestMetadatas = await CollectDynamicTestsStreaming(testSessionId) .ProcessInParallel(); - #if NET6_0_OR_GREATER - #pragma warning restore IL2026, IL3050 - #endif return [..standardTestMetadatas, ..dynamicTestMetadatas]; } diff --git a/TUnit.Engine/Building/TestBuilder.cs b/TUnit.Engine/Building/TestBuilder.cs index 5e70509bfc..8ffe926f9f 100644 --- a/TUnit.Engine/Building/TestBuilder.cs +++ b/TUnit.Engine/Building/TestBuilder.cs @@ -651,42 +651,26 @@ private async Task GetDataSourcesAsync(IDataSourceAttrib } } + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Reflection mode is not used in AOT/trimmed scenarios")] + [UnconditionalSuppressMessage("AOT", "IL3050", Justification = "Reflection mode is not used in AOT scenarios")] public async Task BuildTestAsync(TestMetadata metadata, TestData testData, TestBuilderContext testBuilderContext) { // Discover instance hooks for closed generic types in reflection mode if (!SourceRegistrar.IsEnabled && metadata.TestClassType is { IsGenericType: true, IsGenericTypeDefinition: false }) { - #if NET6_0_OR_GREATER - #pragma warning disable IL2026, IL3050 // Reflection only used in reflection mode - #endif Discovery.ReflectionHookDiscoveryService.DiscoverInstanceHooksForType(metadata.TestClassType); - #if NET6_0_OR_GREATER - #pragma warning restore IL2026, IL3050 - #endif } var testId = TestIdentifierService.GenerateTestId(metadata, testData); - #if NET6_0_OR_GREATER - #pragma warning disable IL2026 // CreateTestContextAsync uses reflection for runtime type handling - #endif var context = await CreateTestContextAsync(testId, metadata, testData, testBuilderContext); - #if NET6_0_OR_GREATER - #pragma warning restore IL2026 - #endif context.TestDetails.ClassInstance = PlaceholderInstance.Instance; // Arguments will be tracked by TestArgumentTrackingService during TestRegistered event // This ensures proper reference counting for shared instances - #if NET6_0_OR_GREATER - #pragma warning disable IL2026 // InvokeDiscoveryEventReceiversAsync uses ScopedAttributeFilter - #endif await InvokeDiscoveryEventReceiversAsync(context); - #if NET6_0_OR_GREATER - #pragma warning restore IL2026 - #endif var creationContext = new ExecutableTestCreationContext { diff --git a/TUnit.Engine/Building/TestBuilderPipeline.cs b/TUnit.Engine/Building/TestBuilderPipeline.cs index 459fb6f081..935b949e29 100644 --- a/TUnit.Engine/Building/TestBuilderPipeline.cs +++ b/TUnit.Engine/Building/TestBuilderPipeline.cs @@ -55,15 +55,11 @@ private TestBuilderContext CreateTestBuilderContext(TestMetadata metadata) return testBuilderContext; } + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Reflection mode is not used in AOT/trimmed scenarios")] + [UnconditionalSuppressMessage("AOT", "IL3050", Justification = "Reflection mode is not used in AOT scenarios")] public async Task> BuildTestsAsync(string testSessionId) { - #if NET6_0_OR_GREATER - #pragma warning disable IL2026, IL3050 // Reflection is only used by ReflectionTestDataCollector, not AotTestDataCollector - #endif var collectedMetadata = await _dataCollector.CollectTestsAsync(testSessionId).ConfigureAwait(false); - #if NET6_0_OR_GREATER - #pragma warning restore IL2026, IL3050 - #endif return await BuildTestsFromMetadataAsync(collectedMetadata).ConfigureAwait(false); } @@ -71,29 +67,19 @@ public async Task> BuildTestsAsync(string te /// /// Streaming version that yields tests as they're built without buffering /// + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Reflection mode is not used in AOT/trimmed scenarios")] + [UnconditionalSuppressMessage("AOT", "IL3050", Justification = "Reflection mode is not used in AOT scenarios")] public async Task> BuildTestsStreamingAsync( string testSessionId, CancellationToken cancellationToken = default) { // Get metadata streaming if supported // Fall back to non-streaming collection - #if NET6_0_OR_GREATER - #pragma warning disable IL2026, IL3050 // Reflection is only used by ReflectionTestDataCollector, not AotTestDataCollector - #endif var collectedMetadata = await _dataCollector.CollectTestsAsync(testSessionId).ConfigureAwait(false); - #if NET6_0_OR_GREATER - #pragma warning restore IL2026, IL3050 - #endif - #if NET6_0_OR_GREATER - #pragma warning disable IL2026, IL3050 // Reflection usage in BuildTestsFromSingleMetadataAsync is handled appropriately - #endif return await collectedMetadata .SelectManyAsync(BuildTestsFromSingleMetadataAsync, cancellationToken: cancellationToken) .ProcessInParallel(cancellationToken: cancellationToken); - #if NET6_0_OR_GREATER - #pragma warning restore IL2026, IL3050 - #endif } private async IAsyncEnumerable ToAsyncEnumerable(IEnumerable metadata) @@ -105,6 +91,8 @@ private async IAsyncEnumerable ToAsyncEnumerable(IEnumerable> BuildTestsFromMetadataAsync(IEnumerable testMetadata) { var testGroups = await testMetadata.SelectAsync(async metadata => @@ -114,22 +102,10 @@ public async Task> BuildTestsFromMetadataAsy // Check if this is a dynamic test metadata that should bypass normal test building if (metadata is IDynamicTestMetadata) { - #if NET6_0_OR_GREATER - #pragma warning disable IL2026 // Dynamic tests use reflection for attribute filtering - #endif return await GenerateDynamicTests(metadata).ConfigureAwait(false); - #if NET6_0_OR_GREATER - #pragma warning restore IL2026 - #endif } - #if NET6_0_OR_GREATER - #pragma warning disable IL2026, IL3050 // TestBuilder implementation handles reflection appropriately based on mode - #endif return await _testBuilder.BuildTestsFromMetadataAsync(metadata).ConfigureAwait(false); - #if NET6_0_OR_GREATER - #pragma warning restore IL2026, IL3050 - #endif } catch (Exception ex) { diff --git a/TUnit.Engine/Building/TestDataCollectorFactory.cs b/TUnit.Engine/Building/TestDataCollectorFactory.cs index 398ad04007..5ffdf78545 100644 --- a/TUnit.Engine/Building/TestDataCollectorFactory.cs +++ b/TUnit.Engine/Building/TestDataCollectorFactory.cs @@ -49,13 +49,7 @@ public static async Task CreateAutoDetectAsync(string testSe { // Try AOT mode first (check if any tests were registered) var aotCollector = new AotTestDataCollector(); - #if NET6_0_OR_GREATER - #pragma warning disable IL2026, IL3050 // AOT collector handles dynamic tests conditionally - #endif var aotTests = await aotCollector.CollectTestsAsync(testSessionId); - #if NET6_0_OR_GREATER - #pragma warning restore IL2026, IL3050 - #endif if (aotTests.Any()) { diff --git a/TUnit.Engine/Framework/TUnitServiceProvider.cs b/TUnit.Engine/Framework/TUnitServiceProvider.cs index 3280b50e30..7a6a0f4cf8 100644 --- a/TUnit.Engine/Framework/TUnitServiceProvider.cs +++ b/TUnit.Engine/Framework/TUnitServiceProvider.cs @@ -56,6 +56,8 @@ public ITestExecutionFilter? Filter public ObjectRegistrationService ObjectRegistrationService { get; } public bool AfterSessionHooksFailed { get; set; } + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Reflection mode is not used in AOT/trimmed scenarios")] + [UnconditionalSuppressMessage("AOT", "IL3050", Justification = "Reflection mode is not used in AOT scenarios")] public TUnitServiceProvider(IExtension extension, ExecuteRequestContext context, ITestExecutionFilter? filter, @@ -141,13 +143,7 @@ public TUnitServiceProvider(IExtension extension, } else { - #if NET6_0_OR_GREATER - #pragma warning disable IL2026, IL3050 // Reflection mode explicitly selected by user or detected - #endif dataCollector = new ReflectionTestDataCollector(); - #if NET6_0_OR_GREATER - #pragma warning restore IL2026, IL3050 - #endif } var testBuilder = Register( diff --git a/TUnit.Engine/Framework/TUnitTestFramework.cs b/TUnit.Engine/Framework/TUnitTestFramework.cs index 408a1f1203..1a32e91018 100644 --- a/TUnit.Engine/Framework/TUnitTestFramework.cs +++ b/TUnit.Engine/Framework/TUnitTestFramework.cs @@ -1,4 +1,5 @@ using System.Collections.Concurrent; +using System.Diagnostics.CodeAnalysis; using Microsoft.Testing.Platform.Capabilities.TestFramework; using Microsoft.Testing.Platform.Extensions; using Microsoft.Testing.Platform.Extensions.Messages; @@ -44,7 +45,8 @@ public Task CreateTestSessionAsync(CreateTestSessionCon #if NET6_0_OR_GREATER [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Test data collector selection may use reflection-based discovery")] [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("Reflection mode test discovery uses dynamic code generation")] -#pragma warning disable IL2046, IL3051 // Interface implementation - cannot add attributes to match called method requirements + [UnconditionalSuppressMessage("Trimming", "IL2046", Justification = "Reflection mode is not used in AOT/trimmed scenarios")] + [UnconditionalSuppressMessage("AOT", "IL3051", Justification = "Reflection mode is not used in AOT scenarios")] #endif public async Task ExecuteRequestAsync(ExecuteRequestContext context) { @@ -90,9 +92,6 @@ public async Task ExecuteRequestAsync(ExecuteRequestContext context) context.Complete(); } } - #if NET6_0_OR_GREATER -#pragma warning restore IL2046, IL3051 - #endif public async Task CloseTestSessionAsync(CloseTestSessionContext context) { diff --git a/TUnit.Engine/TUnitInitializer.cs b/TUnit.Engine/TUnitInitializer.cs index 92c984d399..1037263987 100644 --- a/TUnit.Engine/TUnitInitializer.cs +++ b/TUnit.Engine/TUnitInitializer.cs @@ -11,6 +11,8 @@ namespace TUnit.Engine; internal class TUnitInitializer(ICommandLineOptions commandLineOptions) { + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Reflection mode is not used in AOT/trimmed scenarios")] + [UnconditionalSuppressMessage("AOT", "IL3050", Justification = "Reflection mode is not used in AOT scenarios")] public void Initialize(ExecuteRequestContext context) { ConfigureGlobalExceptionHandlers(context); @@ -20,13 +22,7 @@ public void Initialize(ExecuteRequestContext context) // Discover hooks via reflection if in reflection mode if (IsReflectionMode()) { - #if NET6_0_OR_GREATER - #pragma warning disable IL2026, IL3050 // Reflection only used in reflection mode, not in AOT/source-gen mode - #endif DiscoverHooksViaReflection(); - #if NET6_0_OR_GREATER - #pragma warning restore IL2026, IL3050 - #endif } if (!string.IsNullOrEmpty(TestContext.OutputDirectory)) diff --git a/TUnit.Engine/TestSessionCoordinator.cs b/TUnit.Engine/TestSessionCoordinator.cs index 57ffb4da02..9f518a2ff7 100644 --- a/TUnit.Engine/TestSessionCoordinator.cs +++ b/TUnit.Engine/TestSessionCoordinator.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Microsoft.Testing.Platform.Messages; using Microsoft.Testing.Platform.Requests; using TUnit.Core; @@ -41,7 +42,8 @@ public TestSessionCoordinator(EventReceiverOrchestrator eventReceiverOrchestrato #if NET6_0_OR_GREATER [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Static property initialization uses reflection in reflection mode")] [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("Data source initialization may require dynamic code generation")] -#pragma warning disable IL2046, IL3051 // Interface implementation - cannot add attributes to match called method requirements + [UnconditionalSuppressMessage("Trimming", "IL2046", Justification = "Reflection mode is not used in AOT/trimmed scenarios")] + [UnconditionalSuppressMessage("AOT", "IL3051", Justification = "Reflection mode is not used in AOT scenarios")] #endif public async Task ExecuteTests( IEnumerable tests, @@ -66,9 +68,6 @@ public async Task ExecuteTests( } } } - #if NET6_0_OR_GREATER -#pragma warning restore IL2046, IL3051 - #endif private void InitializeEventReceivers(List testList, CancellationToken cancellationToken) { @@ -76,20 +75,18 @@ private void InitializeEventReceivers(List testList, Can _eventReceiverOrchestrator.InitializeTestCounts(testContexts); } + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Reflection mode is not used in AOT/trimmed scenarios")] + [UnconditionalSuppressMessage("AOT", "IL3050", Justification = "Reflection mode is not used in AOT scenarios")] private async Task PrepareTestOrchestrator(List testList, CancellationToken cancellationToken) { // Register all tests upfront so orchestrator knows total counts per class/assembly for lifecycle management _lifecycleCoordinator.RegisterTests(testList); - #if NET6_0_OR_GREATER - #pragma warning disable IL2026, IL3050 // Reflection only used when !SourceRegistrar.IsEnabled - #endif await InitializeStaticPropertiesAsync(cancellationToken); - #if NET6_0_OR_GREATER - #pragma warning restore IL2026, IL3050 - #endif } + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Reflection mode is not used in AOT/trimmed scenarios")] + [UnconditionalSuppressMessage("AOT", "IL3050", Justification = "Reflection mode is not used in AOT scenarios")] private async Task InitializeStaticPropertiesAsync(CancellationToken cancellationToken) { try @@ -104,13 +101,7 @@ private async Task InitializeStaticPropertiesAsync(CancellationToken cancellatio // For reflection mode, also initialize static properties dynamically if (!SourceRegistrar.IsEnabled) { - #if NET6_0_OR_GREATER - #pragma warning disable IL2026, IL3050 // Reflection only used in reflection mode, not in AOT/source-gen mode - #endif await StaticPropertyReflectionInitializer.InitializeAllStaticPropertiesAsync(); - #if NET6_0_OR_GREATER - #pragma warning restore IL2026, IL3050 - #endif } } catch (Exception ex) From bd9465cfec831d3abda24936c302832b10a75f1b Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Sun, 5 Oct 2025 13:27:44 +0100 Subject: [PATCH 09/14] fix: add UnconditionalSuppressMessage attributes for AOT compatibility and refactor hook discovery logic --- ...pertyEqualsExpectedValueAssertCondition.cs | 2 - TUnit.Assertions/Compare.cs | 10 +-- TUnit.Engine/Building/TestBuilder.cs | 15 +++-- .../Discovery/ReflectionTestDataCollector.cs | 67 ++----------------- .../Framework/TUnitServiceProvider.cs | 31 +++++++-- .../Services/ObjectRegistrationService.cs | 6 -- .../Strategies/NestedPropertyStrategy.cs | 12 ---- .../Strategies/ReflectionPropertyStrategy.cs | 6 -- .../SourceGeneratedPropertyStrategy.cs | 6 -- .../PropertyInitializationOrchestrator.cs | 6 -- .../TestArgumentRegistrationService.cs | 6 -- .../Services/TestExecution/TestCoordinator.cs | 12 ---- TUnit.Engine/TUnitInitializer.cs | 26 +------ TUnit.Engine/TestSessionCoordinator.cs | 44 ++---------- 14 files changed, 54 insertions(+), 195 deletions(-) diff --git a/TUnit.Assertions/Assertions/ClassMembers/Conditions/PropertyEqualsExpectedValueAssertCondition.cs b/TUnit.Assertions/Assertions/ClassMembers/Conditions/PropertyEqualsExpectedValueAssertCondition.cs index 7891109823..b98adf7b59 100644 --- a/TUnit.Assertions/Assertions/ClassMembers/Conditions/PropertyEqualsExpectedValueAssertCondition.cs +++ b/TUnit.Assertions/Assertions/ClassMembers/Conditions/PropertyEqualsExpectedValueAssertCondition.cs @@ -12,8 +12,6 @@ internal protected override string GetExpectation() return $"{typeof(TRootObjectType).Name}.{ExpressionHelpers.GetName(propertySelector)} to be equal to {ExpectedValue}"; } -#pragma warning disable IL2046 // Member with 'RequiresUnreferencedCodeAttribute' overrides base member without 'RequiresUnreferencedCodeAttribute' -#pragma warning disable IL3051 // Member with 'RequiresDynamicCodeAttribute' overrides base member without 'RequiresDynamicCodeAttribute' [RequiresUnreferencedCode("Expression compilation requires unreferenced code")] [RequiresDynamicCode("Expression compilation requires dynamic code generation")] protected override ValueTask GetResult(TRootObjectType? actualValue, TPropertyType? expectedValue) diff --git a/TUnit.Assertions/Compare.cs b/TUnit.Assertions/Compare.cs index 52a366e3bd..241851dd7b 100644 --- a/TUnit.Assertions/Compare.cs +++ b/TUnit.Assertions/Compare.cs @@ -1,8 +1,4 @@ -#pragma warning disable IL2072 // Target type's member does not satisfy requirements -#pragma warning disable IL2075 // Target method return value does not satisfy requirements -// Note: Comparison logic uses reflection for deep object comparison. For AOT scenarios, use explicit comparison methods. - -using System.Collections; +using System.Collections; using System.Diagnostics.CodeAnalysis; using System.Reflection; using TUnit.Assertions.Enums; @@ -306,8 +302,8 @@ private static bool ShouldIgnoreType(Type type, Type[] typesToIgnore) var underlyingType = Nullable.GetUnderlyingType(type) ?? type; // Check if the type or its underlying type (for nullable) should be ignored - return typesToIgnore.Any(ignoredType => - type == ignoredType || + return typesToIgnore.Any(ignoredType => + type == ignoredType || underlyingType == ignoredType || type.IsAssignableFrom(ignoredType) || underlyingType.IsAssignableFrom(ignoredType)); diff --git a/TUnit.Engine/Building/TestBuilder.cs b/TUnit.Engine/Building/TestBuilder.cs index 8ffe926f9f..28dcd603d1 100644 --- a/TUnit.Engine/Building/TestBuilder.cs +++ b/TUnit.Engine/Building/TestBuilder.cs @@ -19,15 +19,18 @@ internal sealed class TestBuilder : ITestBuilder private readonly IContextProvider _contextProvider; private readonly PropertyInjectionService _propertyInjectionService; private readonly DataSourceInitializer _dataSourceInitializer; + private readonly Discovery.IHookDiscoveryService _hookDiscoveryService; public TestBuilder( string sessionId, EventReceiverOrchestrator eventReceiverOrchestrator, IContextProvider contextProvider, PropertyInjectionService propertyInjectionService, - DataSourceInitializer dataSourceInitializer) + DataSourceInitializer dataSourceInitializer, + Discovery.IHookDiscoveryService hookDiscoveryService) { _sessionId = sessionId; + _hookDiscoveryService = hookDiscoveryService; _eventReceiverOrchestrator = eventReceiverOrchestrator; _contextProvider = contextProvider; _propertyInjectionService = propertyInjectionService; @@ -651,14 +654,14 @@ private async Task GetDataSourcesAsync(IDataSourceAttrib } } - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Reflection mode is not used in AOT/trimmed scenarios")] - [UnconditionalSuppressMessage("AOT", "IL3050", Justification = "Reflection mode is not used in AOT scenarios")] + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Hook discovery service handles mode-specific logic; reflection calls suppressed in AOT mode")] + [UnconditionalSuppressMessage("AOT", "IL3050", Justification = "Hook discovery service handles mode-specific logic; dynamic code suppressed in AOT mode")] public async Task BuildTestAsync(TestMetadata metadata, TestData testData, TestBuilderContext testBuilderContext) { - // Discover instance hooks for closed generic types in reflection mode - if (!SourceRegistrar.IsEnabled && metadata.TestClassType is { IsGenericType: true, IsGenericTypeDefinition: false }) + // Discover instance hooks for closed generic types (no-op in source gen mode) + if (metadata.TestClassType is { IsGenericType: true, IsGenericTypeDefinition: false }) { - Discovery.ReflectionHookDiscoveryService.DiscoverInstanceHooksForType(metadata.TestClassType); + _hookDiscoveryService.DiscoverInstanceHooksForType(metadata.TestClassType); } var testId = TestIdentifierService.GenerateTestId(metadata, testData); diff --git a/TUnit.Engine/Discovery/ReflectionTestDataCollector.cs b/TUnit.Engine/Discovery/ReflectionTestDataCollector.cs index faed1e8641..f1623a53af 100644 --- a/TUnit.Engine/Discovery/ReflectionTestDataCollector.cs +++ b/TUnit.Engine/Discovery/ReflectionTestDataCollector.cs @@ -12,6 +12,13 @@ namespace TUnit.Engine.Discovery; /// Discovers tests at runtime using reflection with assembly scanning and caching +[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Reflection mode isn't used in AOT scenarios")] +[UnconditionalSuppressMessage("Trimming", "IL2062", Justification = "Reflection mode isn't used in AOT scenarios")] +[UnconditionalSuppressMessage("Trimming", "IL2070", Justification = "Reflection mode isn't used in AOT scenarios")] +[UnconditionalSuppressMessage("Trimming", "IL2072", Justification = "Reflection mode isn't used in AOT scenarios")] +[UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "Reflection mode isn't used in AOT scenarios")] +[UnconditionalSuppressMessage("AOT", "IL3000", Justification = "Reflection mode isn't used in AOT scenarios")] +[UnconditionalSuppressMessage("AOT", "IL3050", Justification = "Reflection mode isn't used in AOT scenarios")] internal sealed class ReflectionTestDataCollector : ITestDataCollector { private static readonly ConcurrentDictionary _scannedAssemblies = new(); @@ -195,16 +202,8 @@ private static IEnumerable GetAllTestMethods([DynamicallyAccessedMem while (currentType != null && currentType != typeof(object)) { -#if NET6_0_OR_GREATER -#pragma warning disable IL2070 // Type parameter 't' inherits PublicMethods annotation from input -#pragma warning disable IL2075 // BaseType doesn't preserve annotations, but GetMethods is safe -#endif methods.AddRange(currentType.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly)); currentType = currentType.BaseType; -#if NET6_0_OR_GREATER -#pragma warning restore IL2075 -#pragma warning restore IL2070 -#endif } return methods.ToArray(); @@ -301,13 +300,7 @@ private static bool ShouldScanAssembly(Assembly assembly) try { -#if NET6_0_OR_GREATER -#pragma warning disable IL3000 // Assembly.Location is handled for single-file scenarios with try-catch -#endif var location = assembly.Location; -#if NET6_0_OR_GREATER -#pragma warning restore IL3000 -#endif if (!string.IsNullOrEmpty(location) && (location.Contains("ref") || location.Contains("runtimes") || @@ -324,13 +317,7 @@ private static bool ShouldScanAssembly(Assembly assembly) // Don't return false here, continue with other checks } -#if NET6_0_OR_GREATER -#pragma warning disable IL2026 // Assembly.GetReferencedAssemblies is acceptable for assembly filtering -#endif var referencedAssemblies = assembly.GetReferencedAssemblies(); -#if NET6_0_OR_GREATER -#pragma warning restore IL2026 -#endif var hasTUnitReference = false; foreach (var reference in referencedAssemblies) { @@ -897,9 +884,6 @@ private static Task BuildTestMetadata( testMethod.DeclaringType.IsGenericTypeDefinition) { // Find the constructed generic type in the inheritance chain -#if NET6_0_OR_GREATER -#pragma warning disable IL2072 // BaseType doesn't preserve DynamicallyAccessedMembers annotations -#endif var baseType = testClass.BaseType; while (baseType != null) { @@ -911,9 +895,6 @@ private static Task BuildTestMetadata( } baseType = baseType.BaseType; } -#if NET6_0_OR_GREATER -#pragma warning restore IL2072 -#endif } try @@ -921,13 +902,7 @@ private static Task BuildTestMetadata( return Task.FromResult(new ReflectionTestMetadata(testClass, testMethod) { TestName = testName, -#if NET6_0_OR_GREATER -#pragma warning disable IL2072 // typeForGenericResolution may come from BaseType which doesn't preserve annotations -#endif TestClassType = typeForGenericResolution, // Use resolved type for generic resolution (may be constructed generic base) -#if NET6_0_OR_GREATER -#pragma warning restore IL2072 -#endif TestMethodName = testMethod.Name, Dependencies = ReflectionAttributeExtractor.ExtractDependencies(testClass, testMethod), DataSources = ReflectionAttributeExtractor.ExtractDataSources(testMethod), @@ -1363,13 +1338,7 @@ private static void InferGenericTypeMapping(Type paramType, [DynamicallyAccessed for (var i = 0; i < paramGenArgs.Length && i < argGenArgs.Length; i++) { -#if NET6_0_OR_GREATER -#pragma warning disable IL2062 // Generic type arguments don't preserve DynamicallyAccessedMembers -#endif InferGenericTypeMapping(paramGenArgs[i], argGenArgs[i], typeMapping); -#if NET6_0_OR_GREATER -#pragma warning restore IL2062 -#endif } } else @@ -1384,13 +1353,7 @@ private static void InferGenericTypeMapping(Type paramType, [DynamicallyAccessed for (var i = 0; i < paramGenArgs.Length && i < ifaceGenArgs.Length; i++) { -#if NET6_0_OR_GREATER -#pragma warning disable IL2062 // Generic type arguments don't preserve DynamicallyAccessedMembers -#endif InferGenericTypeMapping(paramGenArgs[i], ifaceGenArgs[i], typeMapping); -#if NET6_0_OR_GREATER -#pragma warning restore IL2062 -#endif } break; } @@ -1411,13 +1374,7 @@ private static void InferGenericTypeMapping(Type paramType, [DynamicallyAccessed for (var i = 0; i < paramGenArgs.Length && i < ifaceGenArgs.Length; i++) { -#if NET6_0_OR_GREATER -#pragma warning disable IL2062 // Generic type arguments don't preserve DynamicallyAccessedMembers -#endif InferGenericTypeMapping(paramGenArgs[i], ifaceGenArgs[i], typeMapping); -#if NET6_0_OR_GREATER -#pragma warning restore IL2062 -#endif } break; } @@ -1427,13 +1384,7 @@ private static void InferGenericTypeMapping(Type paramType, [DynamicallyAccessed // Array types if (paramType.IsArray && argType.IsArray) { -#if NET6_0_OR_GREATER -#pragma warning disable IL2072 // GetElementType doesn't preserve DynamicallyAccessedMembers -#endif InferGenericTypeMapping(paramType.GetElementType()!, argType.GetElementType()!, typeMapping); -#if NET6_0_OR_GREATER -#pragma warning restore IL2072 -#endif } } @@ -1490,10 +1441,6 @@ private static bool IsCovariantCompatible(Type paramType, [DynamicallyAccessedMe /// /// Creates a reflection-based test invoker with proper AOT attribution /// - #if NET6_0_OR_GREATER - [RequiresUnreferencedCode("Reflection-based invoker uses MethodInfo.Invoke and reflection")] - [RequiresDynamicCode("Generic method construction uses MakeGenericMethod")] - #endif private static Func CreateReflectionTestInvoker(Type testClass, MethodInfo testMethod) { var isPrepared = false; diff --git a/TUnit.Engine/Framework/TUnitServiceProvider.cs b/TUnit.Engine/Framework/TUnitServiceProvider.cs index 7a6a0f4cf8..23b0a2329d 100644 --- a/TUnit.Engine/Framework/TUnitServiceProvider.cs +++ b/TUnit.Engine/Framework/TUnitServiceProvider.cs @@ -78,7 +78,21 @@ public TUnitServiceProvider(IExtension extension, VerbosityService = Register(new VerbosityService(CommandLineOptions)); DiscoveryDiagnostics.Initialize(VerbosityService); - Initializer = new TUnitInitializer(CommandLineOptions); + // Determine execution mode early to create appropriate services + var useSourceGeneration = SourceRegistrar.IsEnabled = GetUseSourceGeneration(CommandLineOptions); + + // Create and register mode-specific hook discovery service + IHookDiscoveryService hookDiscoveryService; + if (useSourceGeneration) + { + hookDiscoveryService = Register(new SourceGenHookDiscoveryService()); + } + else + { + hookDiscoveryService = Register(new ReflectionBasedHookDiscoveryService()); + } + + Initializer = new TUnitInitializer(CommandLineOptions, hookDiscoveryService); Logger = Register(new TUnitFrameworkLogger( extension, @@ -135,19 +149,23 @@ public TUnitServiceProvider(IExtension extension, var testContextRestorer = Register(new TestContextRestorer()); var testMethodInvoker = Register(new TestMethodInvoker()); - var useSourceGeneration = SourceRegistrar.IsEnabled = GetUseSourceGeneration(CommandLineOptions); + // Use the mode already determined earlier ITestDataCollector dataCollector; + IStaticPropertyInitializer staticPropertyInitializer; + if (useSourceGeneration) { dataCollector = new AotTestDataCollector(); + staticPropertyInitializer = new SourceGenStaticPropertyInitializer(Logger); } else { dataCollector = new ReflectionTestDataCollector(); + staticPropertyInitializer = new ReflectionStaticPropertyInitializer(Logger); } var testBuilder = Register( - new TestBuilder(TestSessionId, EventReceiverOrchestrator, ContextProvider, PropertyInjectionService, DataSourceInitializer)); + new TestBuilder(TestSessionId, EventReceiverOrchestrator, ContextProvider, PropertyInjectionService, DataSourceInitializer, hookDiscoveryService)); TestBuilderPipeline = Register( new TestBuilderPipeline( @@ -199,7 +217,7 @@ public TUnitServiceProvider(IExtension extension, Logger, ParallelLimitLockProvider)); - var staticPropertyInitializer = Register(new Services.StaticPropertyHandler(Logger, objectTracker, trackableObjectGraphProvider, disposer)); + var staticPropertyHandler = Register(new Services.StaticPropertyHandler(Logger, objectTracker, trackableObjectGraphProvider, disposer)); var testScheduler = Register(new TestScheduler( Logger, @@ -212,7 +230,7 @@ public TUnitServiceProvider(IExtension extension, circularDependencyDetector, constraintKeyScheduler, hookExecutor, - staticPropertyInitializer)); + staticPropertyHandler)); TestSessionCoordinator = Register(new TestSessionCoordinator(EventReceiverOrchestrator, Logger, @@ -220,7 +238,8 @@ public TUnitServiceProvider(IExtension extension, serviceProvider: this, ContextProvider, lifecycleCoordinator, - MessageBus)); + MessageBus, + staticPropertyInitializer)); Register(new TestRegistry(TestBuilderPipeline, testCoordinator, TestSessionId, CancellationToken.Token)); diff --git a/TUnit.Engine/Services/ObjectRegistrationService.cs b/TUnit.Engine/Services/ObjectRegistrationService.cs index fb4bcdb4cd..549f642ae8 100644 --- a/TUnit.Engine/Services/ObjectRegistrationService.cs +++ b/TUnit.Engine/Services/ObjectRegistrationService.cs @@ -97,12 +97,6 @@ public async Task RegisterArgumentsAsync( /// private bool RequiresPropertyInjection(object instance) { -#if NET6_0_OR_GREATER -#pragma warning disable IL2026 // Injectable property check uses reflection - acceptable during registration -#endif return PropertyInjectionCache.HasInjectableProperties(instance.GetType()); -#if NET6_0_OR_GREATER -#pragma warning restore IL2026 -#endif } } diff --git a/TUnit.Engine/Services/PropertyInitialization/Strategies/NestedPropertyStrategy.cs b/TUnit.Engine/Services/PropertyInitialization/Strategies/NestedPropertyStrategy.cs index 3adcb1570d..45be31469d 100644 --- a/TUnit.Engine/Services/PropertyInitialization/Strategies/NestedPropertyStrategy.cs +++ b/TUnit.Engine/Services/PropertyInitialization/Strategies/NestedPropertyStrategy.cs @@ -53,13 +53,7 @@ public async Task InitializePropertyAsync(PropertyInitializationContext context) } // Get the injection plan for this type -#if NET6_0_OR_GREATER -#pragma warning disable IL2026 // Injection plan creation uses reflection - acceptable during nested property handling -#endif var plan = PropertyInjectionCache.GetOrCreatePlan(propertyType); -#if NET6_0_OR_GREATER -#pragma warning restore IL2026 -#endif // Recursively inject properties into the nested object if (SourceRegistrar.IsEnabled) @@ -167,13 +161,7 @@ private PropertyInitializationContext CreateNestedContext( DataSource = dataSource, PropertyName = propertyName, PropertyType = property.PropertyType, -#if NET6_0_OR_GREATER -#pragma warning disable IL2026 // Property setter creation may use reflection - acceptable for init-only properties -#endif PropertySetter = PropertySetterFactory.CreateSetter(property), -#if NET6_0_OR_GREATER -#pragma warning restore IL2026 -#endif ObjectBag = parentContext.ObjectBag, MethodMetadata = parentContext.MethodMetadata, Events = parentContext.Events, diff --git a/TUnit.Engine/Services/PropertyInitialization/Strategies/ReflectionPropertyStrategy.cs b/TUnit.Engine/Services/PropertyInitialization/Strategies/ReflectionPropertyStrategy.cs index 2c42bd0d7c..15e7d38dee 100644 --- a/TUnit.Engine/Services/PropertyInitialization/Strategies/ReflectionPropertyStrategy.cs +++ b/TUnit.Engine/Services/PropertyInitialization/Strategies/ReflectionPropertyStrategy.cs @@ -55,13 +55,7 @@ public async Task InitializePropertyAsync(PropertyInitializationContext context) else { // Step 1: Resolve data from the data source (execution-time resolution) -#if NET6_0_OR_GREATER -#pragma warning disable IL2026 // Property data resolution uses reflection - acceptable during property injection -#endif resolvedValue = await PropertyDataResolver.ResolvePropertyDataAsync(context, _dataSourceInitializer, _objectRegistrationService); -#if NET6_0_OR_GREATER -#pragma warning restore IL2026 -#endif if (resolvedValue == null) { return; diff --git a/TUnit.Engine/Services/PropertyInitialization/Strategies/SourceGeneratedPropertyStrategy.cs b/TUnit.Engine/Services/PropertyInitialization/Strategies/SourceGeneratedPropertyStrategy.cs index a65f9083da..068470813a 100644 --- a/TUnit.Engine/Services/PropertyInitialization/Strategies/SourceGeneratedPropertyStrategy.cs +++ b/TUnit.Engine/Services/PropertyInitialization/Strategies/SourceGeneratedPropertyStrategy.cs @@ -45,13 +45,7 @@ public async Task InitializePropertyAsync(PropertyInitializationContext context) } else { -#if NET6_0_OR_GREATER -#pragma warning disable IL2026 // Property data resolution uses reflection - acceptable during property injection -#endif resolvedValue = await PropertyDataResolver.ResolvePropertyDataAsync(context, _dataSourceInitializer, _objectRegistrationService); -#if NET6_0_OR_GREATER -#pragma warning restore IL2026 -#endif if (resolvedValue == null) { return; diff --git a/TUnit.Engine/Services/PropertyInitializationOrchestrator.cs b/TUnit.Engine/Services/PropertyInitializationOrchestrator.cs index 246120279e..c7b4a7ccb5 100644 --- a/TUnit.Engine/Services/PropertyInitializationOrchestrator.cs +++ b/TUnit.Engine/Services/PropertyInitializationOrchestrator.cs @@ -161,13 +161,7 @@ private PropertyInitializationContext CreateContext( DataSource = dataSource, PropertyName = property.Name, PropertyType = property.PropertyType, -#if NET6_0_OR_GREATER -#pragma warning disable IL2026 // Property setter creation may use reflection - acceptable for init-only properties -#endif PropertySetter = PropertySetterFactory.CreateSetter(property), -#if NET6_0_OR_GREATER -#pragma warning restore IL2026 -#endif ObjectBag = objectBag, MethodMetadata = methodMetadata, Events = events, diff --git a/TUnit.Engine/Services/TestArgumentRegistrationService.cs b/TUnit.Engine/Services/TestArgumentRegistrationService.cs index 9b6bfb0ba3..5b50965fb0 100644 --- a/TUnit.Engine/Services/TestArgumentRegistrationService.cs +++ b/TUnit.Engine/Services/TestArgumentRegistrationService.cs @@ -60,13 +60,7 @@ await _objectRegistrationService.RegisterArgumentsAsync( // Register properties that will be injected into the test class await RegisterPropertiesAsync(testContext); -#if NET6_0_OR_GREATER -#pragma warning disable IL2026 // Trackable object discovery uses reflection - acceptable during test discovery -#endif _objectTracker.TrackObjects(testContext); -#if NET6_0_OR_GREATER -#pragma warning restore IL2026 -#endif } /// diff --git a/TUnit.Engine/Services/TestExecution/TestCoordinator.cs b/TUnit.Engine/Services/TestExecution/TestCoordinator.cs index f747c834dc..4a79021c62 100644 --- a/TUnit.Engine/Services/TestExecution/TestCoordinator.cs +++ b/TUnit.Engine/Services/TestExecution/TestCoordinator.cs @@ -97,13 +97,7 @@ await RetryHelper.ExecuteWithRetry(test.Context, async () => try { -#if NET6_0_OR_GREATER -#pragma warning disable IL2026 // Test initialization may use reflection - acceptable during test execution -#endif await _testInitializer.InitializeTest(test, cancellationToken); -#if NET6_0_OR_GREATER -#pragma warning restore IL2026 -#endif test.Context.RestoreExecutionContext(); await _testExecutor.ExecuteAsync(test, cancellationToken); } @@ -128,13 +122,7 @@ await RetryHelper.ExecuteWithRetry(test.Context, async () => try { -#if NET6_0_OR_GREATER -#pragma warning disable IL2026 // Test disposal may use reflection - acceptable during test cleanup -#endif await TestExecutor.DisposeTestInstance(test); -#if NET6_0_OR_GREATER -#pragma warning restore IL2026 -#endif } catch (Exception disposeEx) { diff --git a/TUnit.Engine/TUnitInitializer.cs b/TUnit.Engine/TUnitInitializer.cs index 1037263987..3eb47fb89b 100644 --- a/TUnit.Engine/TUnitInitializer.cs +++ b/TUnit.Engine/TUnitInitializer.cs @@ -1,5 +1,4 @@ using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using Microsoft.Testing.Platform.CommandLine; using Microsoft.Testing.Platform.Extensions.TestFramework; using TUnit.Core; @@ -9,21 +8,16 @@ namespace TUnit.Engine; -internal class TUnitInitializer(ICommandLineOptions commandLineOptions) +internal class TUnitInitializer(ICommandLineOptions commandLineOptions, IHookDiscoveryService hookDiscoveryService) { - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Reflection mode is not used in AOT/trimmed scenarios")] - [UnconditionalSuppressMessage("AOT", "IL3050", Justification = "Reflection mode is not used in AOT scenarios")] public void Initialize(ExecuteRequestContext context) { ConfigureGlobalExceptionHandlers(context); SetUpExceptionListeners(); ParseParameters(); - // Discover hooks via reflection if in reflection mode - if (IsReflectionMode()) - { - DiscoverHooksViaReflection(); - } + // Discover hooks using the mode-specific service + hookDiscoveryService.DiscoverHooks(); if (!string.IsNullOrEmpty(TestContext.OutputDirectory)) { @@ -31,20 +25,6 @@ public void Initialize(ExecuteRequestContext context) } } - private bool IsReflectionMode() - { - return !SourceRegistrar.IsEnabled; - } - -#if NET6_0_OR_GREATER - [RequiresUnreferencedCode("Hook discovery uses reflection to scan assemblies and types")] - [RequiresDynamicCode("Hook delegate creation requires dynamic code generation")] -#endif - private void DiscoverHooksViaReflection() - { - ReflectionHookDiscoveryService.DiscoverHooks(); - } - private void SetUpExceptionListeners() { Trace.Listeners.Insert(0, new ThrowListener()); diff --git a/TUnit.Engine/TestSessionCoordinator.cs b/TUnit.Engine/TestSessionCoordinator.cs index 9f518a2ff7..0f7602236f 100644 --- a/TUnit.Engine/TestSessionCoordinator.cs +++ b/TUnit.Engine/TestSessionCoordinator.cs @@ -21,6 +21,7 @@ internal sealed class TestSessionCoordinator : ITestExecutor, IDisposable, IAsyn private readonly IContextProvider _contextProvider; private readonly TestLifecycleCoordinator _lifecycleCoordinator; private readonly ITUnitMessageBus _messageBus; + private readonly IStaticPropertyInitializer _staticPropertyInitializer; public TestSessionCoordinator(EventReceiverOrchestrator eventReceiverOrchestrator, TUnitFrameworkLogger logger, @@ -28,7 +29,8 @@ public TestSessionCoordinator(EventReceiverOrchestrator eventReceiverOrchestrato TUnitServiceProvider serviceProvider, IContextProvider contextProvider, TestLifecycleCoordinator lifecycleCoordinator, - ITUnitMessageBus messageBus) + ITUnitMessageBus messageBus, + IStaticPropertyInitializer staticPropertyInitializer) { _eventReceiverOrchestrator = eventReceiverOrchestrator; _logger = logger; @@ -37,14 +39,9 @@ public TestSessionCoordinator(EventReceiverOrchestrator eventReceiverOrchestrato _lifecycleCoordinator = lifecycleCoordinator; _messageBus = messageBus; _testScheduler = testScheduler; + _staticPropertyInitializer = staticPropertyInitializer; } - #if NET6_0_OR_GREATER - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Static property initialization uses reflection in reflection mode")] - [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("Data source initialization may require dynamic code generation")] - [UnconditionalSuppressMessage("Trimming", "IL2046", Justification = "Reflection mode is not used in AOT/trimmed scenarios")] - [UnconditionalSuppressMessage("AOT", "IL3051", Justification = "Reflection mode is not used in AOT scenarios")] - #endif public async Task ExecuteTests( IEnumerable tests, ITestExecutionFilter? filter, @@ -75,45 +72,18 @@ private void InitializeEventReceivers(List testList, Can _eventReceiverOrchestrator.InitializeTestCounts(testContexts); } - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Reflection mode is not used in AOT/trimmed scenarios")] - [UnconditionalSuppressMessage("AOT", "IL3050", Justification = "Reflection mode is not used in AOT scenarios")] private async Task PrepareTestOrchestrator(List testList, CancellationToken cancellationToken) { // Register all tests upfront so orchestrator knows total counts per class/assembly for lifecycle management _lifecycleCoordinator.RegisterTests(testList); - await InitializeStaticPropertiesAsync(cancellationToken); - } - - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Reflection mode is not used in AOT/trimmed scenarios")] - [UnconditionalSuppressMessage("AOT", "IL3050", Justification = "Reflection mode is not used in AOT scenarios")] - private async Task InitializeStaticPropertiesAsync(CancellationToken cancellationToken) - { - try - { - // Execute all registered global initializers (including static property initialization from source generation) - while (Sources.GlobalInitializers.TryDequeue(out var initializer)) - { - cancellationToken.ThrowIfCancellationRequested(); - await initializer(); - } - - // For reflection mode, also initialize static properties dynamically - if (!SourceRegistrar.IsEnabled) - { - await StaticPropertyReflectionInitializer.InitializeAllStaticPropertiesAsync(); - } - } - catch (Exception ex) - { - await _logger.LogErrorAsync($"Error during static property initialization: {ex}"); - throw; - } + await _staticPropertyInitializer.InitializeAsync(cancellationToken); } #if NET6_0_OR_GREATER - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Test execution involves reflection for hooks and initialization")] + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Test scheduler uses mode-specific services that handle reflection properly")] + [UnconditionalSuppressMessage("AOT", "IL3050", Justification = "Test scheduler uses mode-specific services that handle dynamic code properly")] #endif private async Task ExecuteTestsCore(List testList, CancellationToken cancellationToken) { From 124b6a33b292d1b2831bb36fbca9e322cc60e295 Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Sun, 5 Oct 2025 14:03:34 +0100 Subject: [PATCH 10/14] fix: update access modifiers for consistency and add AOT compatibility attributes --- .../InheritsTestsCodeFixProvider.cs | 4 +- .../XUnitMigrationCodeFixProvider.cs | 4 +- TUnit.Analyzers.Tests/AnalyzerTestHelpers.cs | 2 +- .../ConcurrentDiagnosticAnalyzer.cs | 2 +- .../AwaitAssertionCodeFixProvider.cs | 4 +- .../XUnitAssertionCodeFixProvider.cs | 4 +- .../ConcurrentDiagnosticAnalyzer.cs | 2 +- .../AssertConditions/BaseAssertCondition.cs | 2 +- .../Connectors/AndAssertCondition.cs | 4 +- .../Connectors/OrAssertCondition.cs | 4 +- .../ConvertToAssertCondition.cs | 2 +- .../DelegateAssertCondition.cs | 2 +- .../EnumerableSatisfiesAssertCondition.cs | 2 +- ...eContainingExpectedValueAssertCondition.cs | 2 +- ...eEndingWithExpectedValueAssertCondition.cs | 2 +- ...ssageEqualsExpectedValueAssertCondition.cs | 2 +- ...nMessageMatchingExpectedAssertCondition.cs | 2 +- ...tartingWithExpectedValueAssertCondition.cs | 2 +- .../ExpectedValueAssertCondition.cs | 2 + .../FuncValueAssertCondition.cs | 2 +- .../NotNullExpectedValueAssertCondition.cs | 4 +- .../NullExpectedValueAssertCondition.cs | 2 +- .../SatisfiesAssertCondition.cs | 2 +- .../StaticMethodAssertCondition.cs | 2 +- .../AssertConditions/ValueAssertCondition.cs | 2 +- .../AssertionBuilders/AssertionBuilder.cs | 2 +- .../InvokableAssertionBuilder.cs | 2 +- ...eOnlyEqualsExpectedValueAssertCondition.cs | 2 +- ...eTimeEqualsExpectedValueAssertCondition.cs | 2 +- ...ffsetEqualsExpectedValueAssertCondition.cs | 2 +- ...eOnlyEqualsExpectedValueAssertCondition.cs | 2 +- ...eSpanEqualsExpectedValueAssertCondition.cs | 2 +- ...pertyEqualsExpectedValueAssertCondition.cs | 8 +--- ...numerableAllExpectedFuncAssertCondition.cs | 2 +- ...ableContainsExpectedFuncAssertCondition.cs | 2 +- ...bleContainsExpectedValueAssertCondition.cs | 2 +- ...ountEqualToExpectedValueAssertCondition.cs | 2 +- ...tNotEqualToExpectedValueAssertCondition.cs | 2 +- ...stinctItemsExpectedValueAssertCondition.cs | 2 +- ...quivalentToExpectedValueAssertCondition.cs | 2 +- ...eNotContainsExpectedFuncAssertCondition.cs | 2 +- ...NotContainsExpectedValueAssertCondition.cs | 2 +- ...quivalentToExpectedValueAssertCondition.cs | 2 +- .../EnumerableOrderedByAssertCondition.cs | 2 +- .../Conditions/BetweenAssertCondition.cs | 2 +- .../Conditions/NotBetweenAssertCondition.cs | 2 +- .../CompleteWithinAssertCondition.cs | 2 +- .../EnumDoesNotHaveFlagAssertCondition.cs | 2 +- .../EnumDoesNotHaveSameNameAsCondition.cs | 2 +- .../EnumDoesNotHaveSameValueAsCondition.cs | 2 +- .../Conditions/EnumHasFlagAssertCondition.cs | 2 +- .../Conditions/EnumHasSameNameAsCondition.cs | 2 +- .../Conditions/EnumHasSameValueAsCondition.cs | 2 +- .../EnumIsDefinedAssertCondition.cs | 4 +- ...ignableFromExpectedValueAssertCondition.cs | 2 +- ...ssignableToExpectedValueAssertCondition.cs | 2 +- .../ConvertExceptionToValueAssertCondition.cs | 4 +- .../Conditions/DefaultAssertionCondition.cs | 2 +- .../DelegateConversionAssertionCondition.cs | 2 +- .../EqualsExpectedValueAssertCondition.cs | 2 +- ...quivalentToExpectedValueAssertCondition.cs | 2 +- ...ignableFromExpectedValueAssertCondition.cs | 2 +- ...ssignableToExpectedValueAssertCondition.cs | 2 +- .../NotDefaultAssertionCondition.cs | 2 +- .../NotEqualsExpectedValueAssertCondition.cs | 2 +- ...quivalentToExpectedValueAssertCondition.cs | 2 +- ...meReferenceExpectedValueAssertCondition.cs | 2 +- .../NotTypeOfExpectedValueAssertCondition.cs | 2 +- ...meReferenceExpectedValueAssertCondition.cs | 2 +- .../TypeOfExpectedValueAssertCondition.cs | 2 +- .../ValueConversionAssertionCondition.cs | 2 +- ...ingContainsExpectedValueAssertCondition.cs | 2 +- ...tringEqualsExpectedValueAssertCondition.cs | 2 +- ...NotContainsExpectedValueAssertCondition.cs | 2 +- ...ngNotEqualsExpectedValueAssertCondition.cs | 2 +- .../ThrowsAnyExceptionAssertCondition.cs | 2 +- .../Throws/ThrowsExactlyAssertCondition.cs | 2 +- .../Throws/ThrowsNothingAssertCondition.cs | 2 +- .../Throws/ThrowsOfTypeAssertCondition.cs | 4 +- .../ThrowsWithMessageAssertCondition.cs | 2 +- ...owsWithMessageContainingAssertCondition.cs | 2 +- ...hrowsWithMessageMatchingAssertCondition.cs | 2 +- ...WithMessageNotContainingAssertCondition.cs | 2 +- .../ThrowsWithParamNameAssertCondition.cs | 2 +- .../Throws/ThrowsWithinAssertCondition.cs | 2 +- TUnit.Assertions/Compare.cs | 29 +++++++++--- .../AotCompatibility/GenericTestRegistry.cs | 2 +- .../Discovery/IHookDiscoveryService.cs | 17 +++++++ .../ReflectionBasedHookDiscoveryService.cs | 31 +++++++++++++ .../Discovery/ReflectionTestDataCollector.cs | 3 ++ .../SourceGenHookDiscoveryService.cs | 27 +++++++++++ .../StandardErrorConsoleInterceptor.cs | 4 +- .../Logging/StandardOutConsoleInterceptor.cs | 4 +- .../Services/IStaticPropertyInitializer.cs | 12 +++++ .../Services/ObjectRegistrationService.cs | 4 ++ .../Strategies/NestedPropertyStrategy.cs | 7 +++ .../Strategies/ReflectionPropertyStrategy.cs | 3 ++ .../SourceGeneratedPropertyStrategy.cs | 4 ++ .../PropertyInitializationOrchestrator.cs | 3 ++ .../ReflectionStaticPropertyInitializer.cs | 45 +++++++++++++++++++ .../SourceGenStaticPropertyInitializer.cs | 36 +++++++++++++++ ..._Has_No_API_Changes.DotNet8_0.verified.txt | 3 +- ..._Has_No_API_Changes.DotNet9_0.verified.txt | 3 +- 103 files changed, 317 insertions(+), 116 deletions(-) create mode 100644 TUnit.Engine/Discovery/IHookDiscoveryService.cs create mode 100644 TUnit.Engine/Discovery/ReflectionBasedHookDiscoveryService.cs create mode 100644 TUnit.Engine/Discovery/SourceGenHookDiscoveryService.cs create mode 100644 TUnit.Engine/Services/IStaticPropertyInitializer.cs create mode 100644 TUnit.Engine/Services/ReflectionStaticPropertyInitializer.cs create mode 100644 TUnit.Engine/Services/SourceGenStaticPropertyInitializer.cs diff --git a/TUnit.Analyzers.CodeFixers/InheritsTestsCodeFixProvider.cs b/TUnit.Analyzers.CodeFixers/InheritsTestsCodeFixProvider.cs index 37c49cc804..1437836a79 100644 --- a/TUnit.Analyzers.CodeFixers/InheritsTestsCodeFixProvider.cs +++ b/TUnit.Analyzers.CodeFixers/InheritsTestsCodeFixProvider.cs @@ -16,12 +16,12 @@ namespace TUnit.Analyzers.CodeFixers; [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(InheritsTestsCodeFixProvider)), Shared] public class InheritsTestsCodeFixProvider : CodeFixProvider { - public override sealed ImmutableArray FixableDiagnosticIds { get; } = + public sealed override ImmutableArray FixableDiagnosticIds { get; } = ImmutableArray.Create(Rules.DoesNotInheritTestsWarning.Id); public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; - public override sealed async Task RegisterCodeFixesAsync(CodeFixContext context) + public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { foreach (var diagnostic in context.Diagnostics) { diff --git a/TUnit.Analyzers.CodeFixers/XUnitMigrationCodeFixProvider.cs b/TUnit.Analyzers.CodeFixers/XUnitMigrationCodeFixProvider.cs index e36af3b34d..c0f66c91c3 100644 --- a/TUnit.Analyzers.CodeFixers/XUnitMigrationCodeFixProvider.cs +++ b/TUnit.Analyzers.CodeFixers/XUnitMigrationCodeFixProvider.cs @@ -11,12 +11,12 @@ namespace TUnit.Analyzers.CodeFixers; [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(XUnitMigrationCodeFixProvider)), Shared] public class XUnitMigrationCodeFixProvider : CodeFixProvider { - public override sealed ImmutableArray FixableDiagnosticIds { get; } = + public sealed override ImmutableArray FixableDiagnosticIds { get; } = ImmutableArray.Create(Rules.XunitMigration.Id); public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; - public override sealed Task RegisterCodeFixesAsync(CodeFixContext context) + public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) { foreach (var diagnostic in context.Diagnostics) { diff --git a/TUnit.Analyzers.Tests/AnalyzerTestHelpers.cs b/TUnit.Analyzers.Tests/AnalyzerTestHelpers.cs index 84123c7846..cfc1a476b4 100644 --- a/TUnit.Analyzers.Tests/AnalyzerTestHelpers.cs +++ b/TUnit.Analyzers.Tests/AnalyzerTestHelpers.cs @@ -183,7 +183,7 @@ public static CSharpSuppressorTest CreateSuppresso } } -file static class DiagnosticSeverityExtensions +static file class DiagnosticSeverityExtensions { public static ReportDiagnostic ToReportDiagnostic(this DiagnosticSeverity severity) => severity switch diff --git a/TUnit.Analyzers/ConcurrentDiagnosticAnalyzer.cs b/TUnit.Analyzers/ConcurrentDiagnosticAnalyzer.cs index 40473f4c39..d0114b7601 100644 --- a/TUnit.Analyzers/ConcurrentDiagnosticAnalyzer.cs +++ b/TUnit.Analyzers/ConcurrentDiagnosticAnalyzer.cs @@ -4,7 +4,7 @@ namespace TUnit.Analyzers; public abstract class ConcurrentDiagnosticAnalyzer : DiagnosticAnalyzer { - public override sealed void Initialize(AnalysisContext context) + public sealed override void Initialize(AnalysisContext context) { context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); context.EnableConcurrentExecution(); diff --git a/TUnit.Assertions.Analyzers.CodeFixers/AwaitAssertionCodeFixProvider.cs b/TUnit.Assertions.Analyzers.CodeFixers/AwaitAssertionCodeFixProvider.cs index f76ce17c6a..0924421d73 100644 --- a/TUnit.Assertions.Analyzers.CodeFixers/AwaitAssertionCodeFixProvider.cs +++ b/TUnit.Assertions.Analyzers.CodeFixers/AwaitAssertionCodeFixProvider.cs @@ -13,12 +13,12 @@ namespace TUnit.Assertions.Analyzers.CodeFixers; [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(AwaitAssertionCodeFixProvider)), Shared] public class AwaitAssertionCodeFixProvider : CodeFixProvider { - public override sealed ImmutableArray FixableDiagnosticIds { get; } = + public sealed override ImmutableArray FixableDiagnosticIds { get; } = ImmutableArray.Create(Rules.AwaitAssertion.Id); public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; - public override sealed async Task RegisterCodeFixesAsync(CodeFixContext context) + public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { foreach (var diagnostic in context.Diagnostics) { diff --git a/TUnit.Assertions.Analyzers.CodeFixers/XUnitAssertionCodeFixProvider.cs b/TUnit.Assertions.Analyzers.CodeFixers/XUnitAssertionCodeFixProvider.cs index f5f3846a73..c4f6adaea6 100644 --- a/TUnit.Assertions.Analyzers.CodeFixers/XUnitAssertionCodeFixProvider.cs +++ b/TUnit.Assertions.Analyzers.CodeFixers/XUnitAssertionCodeFixProvider.cs @@ -12,12 +12,12 @@ namespace TUnit.Assertions.Analyzers.CodeFixers; [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(XUnitAssertionCodeFixProvider)), Shared] public class XUnitAssertionCodeFixProvider : CodeFixProvider { - public override sealed ImmutableArray FixableDiagnosticIds { get; } = + public sealed override ImmutableArray FixableDiagnosticIds { get; } = ImmutableArray.Create(Rules.XUnitAssertion.Id); public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; - public override sealed async Task RegisterCodeFixesAsync(CodeFixContext context) + public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { foreach (var diagnostic in context.Diagnostics) { diff --git a/TUnit.Assertions.Analyzers/ConcurrentDiagnosticAnalyzer.cs b/TUnit.Assertions.Analyzers/ConcurrentDiagnosticAnalyzer.cs index f7280fad44..0c71821ab2 100644 --- a/TUnit.Assertions.Analyzers/ConcurrentDiagnosticAnalyzer.cs +++ b/TUnit.Assertions.Analyzers/ConcurrentDiagnosticAnalyzer.cs @@ -4,7 +4,7 @@ namespace TUnit.Assertions.Analyzers; public abstract class ConcurrentDiagnosticAnalyzer : DiagnosticAnalyzer { - public override sealed void Initialize(AnalysisContext context) + public sealed override void Initialize(AnalysisContext context) { context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); context.EnableConcurrentExecution(); diff --git a/TUnit.Assertions/AssertConditions/BaseAssertCondition.cs b/TUnit.Assertions/AssertConditions/BaseAssertCondition.cs index cd2323f564..14a1c20b82 100644 --- a/TUnit.Assertions/AssertConditions/BaseAssertCondition.cs +++ b/TUnit.Assertions/AssertConditions/BaseAssertCondition.cs @@ -30,7 +30,7 @@ public AssertionResult FailWithMessage(string message) /// public virtual TimeSpan? WaitFor { get; protected set; } - internal protected abstract string GetExpectation(); + protected internal abstract string GetExpectation(); internal virtual string GetExpectationWithReason() => $"{GetExpectation()}{GetBecauseReason()}"; diff --git a/TUnit.Assertions/AssertConditions/Connectors/AndAssertCondition.cs b/TUnit.Assertions/AssertConditions/Connectors/AndAssertCondition.cs index a0509d97a8..a329cb9b05 100644 --- a/TUnit.Assertions/AssertConditions/Connectors/AndAssertCondition.cs +++ b/TUnit.Assertions/AssertConditions/Connectors/AndAssertCondition.cs @@ -18,12 +18,12 @@ public AndAssertCondition(BaseAssertCondition condition1, BaseAssertCondition co // Not used, as GetExpectationWithReason is overridden - internal protected override string GetExpectation() => ""; + protected internal override string GetExpectation() => ""; internal override string GetExpectationWithReason() => $"{_condition1.GetExpectationWithReason()}{Environment.NewLine} and {_condition2.GetExpectationWithReason()}"; - internal override sealed async ValueTask GetAssertionResult(object? actualValue, Exception? exception, AssertionMetadata assertionMetadata, string? actualExpression) + internal sealed override async ValueTask GetAssertionResult(object? actualValue, Exception? exception, AssertionMetadata assertionMetadata, string? actualExpression) { return (await _condition1.GetAssertionResult(actualValue, exception, assertionMetadata, actualExpression)) .And(await _condition2.GetAssertionResult(actualValue, exception, assertionMetadata, actualExpression)); diff --git a/TUnit.Assertions/AssertConditions/Connectors/OrAssertCondition.cs b/TUnit.Assertions/AssertConditions/Connectors/OrAssertCondition.cs index a255b967b9..001da713ec 100644 --- a/TUnit.Assertions/AssertConditions/Connectors/OrAssertCondition.cs +++ b/TUnit.Assertions/AssertConditions/Connectors/OrAssertCondition.cs @@ -17,12 +17,12 @@ public OrAssertCondition(BaseAssertCondition condition1, BaseAssertCondition con } // Not used, as GetExpectationWithReason is overridden - internal protected override string GetExpectation() => ""; + protected internal override string GetExpectation() => ""; internal override string GetExpectationWithReason() => $"{_condition1.GetExpectationWithReason()}{Environment.NewLine} or {_condition2.GetExpectationWithReason()}"; - internal override sealed async ValueTask GetAssertionResult(object? actualValue, Exception? exception, AssertionMetadata assertionMetadata, string? actualExpression) + internal sealed override async ValueTask GetAssertionResult(object? actualValue, Exception? exception, AssertionMetadata assertionMetadata, string? actualExpression) { return await (await _condition1.GetAssertionResult(actualValue, exception, assertionMetadata, actualExpression)) .OrAsync(() => _condition2.GetAssertionResult(actualValue, exception, assertionMetadata, actualExpression)); diff --git a/TUnit.Assertions/AssertConditions/ConvertToAssertCondition.cs b/TUnit.Assertions/AssertConditions/ConvertToAssertCondition.cs index ef7623d7e7..2df252afb3 100644 --- a/TUnit.Assertions/AssertConditions/ConvertToAssertCondition.cs +++ b/TUnit.Assertions/AssertConditions/ConvertToAssertCondition.cs @@ -6,7 +6,7 @@ public abstract class ConvertToAssertCondition : BaseAssertC public TToType? ConvertedValue { get; private set; } - protected override sealed async ValueTask GetResult(TFromType? actualValue, Exception? exception, AssertionMetadata assertionMetadata) + protected sealed override async ValueTask GetResult(TFromType? actualValue, Exception? exception, AssertionMetadata assertionMetadata) { var (result, convertedValue) = await ConvertValue(actualValue); diff --git a/TUnit.Assertions/AssertConditions/DelegateAssertCondition.cs b/TUnit.Assertions/AssertConditions/DelegateAssertCondition.cs index 7dad1571be..498ddb833e 100644 --- a/TUnit.Assertions/AssertConditions/DelegateAssertCondition.cs +++ b/TUnit.Assertions/AssertConditions/DelegateAssertCondition.cs @@ -43,7 +43,7 @@ AssertionMetadata assertionMetadata protected virtual string GetFailureMessage(TException? exception) => ""; - internal protected override string GetExpectation() + protected internal override string GetExpectation() { return GetFailureMessage(Exception as TException); } diff --git a/TUnit.Assertions/AssertConditions/EnumerableSatisfiesAssertCondition.cs b/TUnit.Assertions/AssertConditions/EnumerableSatisfiesAssertCondition.cs index a2bc3904fb..2e649bd130 100644 --- a/TUnit.Assertions/AssertConditions/EnumerableSatisfiesAssertCondition.cs +++ b/TUnit.Assertions/AssertConditions/EnumerableSatisfiesAssertCondition.cs @@ -20,7 +20,7 @@ public EnumerableSatisfiesAssertCondition(Func?> mapper SetSubject(mapperExpression); } - internal protected override string GetExpectation() + protected internal override string GetExpectation() => $"to satisfy {_assertionBuilderExpression}"; protected override async ValueTask GetResult( diff --git a/TUnit.Assertions/AssertConditions/Exceptions/ExceptionMessageContainingExpectedValueAssertCondition.cs b/TUnit.Assertions/AssertConditions/Exceptions/ExceptionMessageContainingExpectedValueAssertCondition.cs index e7be965bca..e3ce66464f 100644 --- a/TUnit.Assertions/AssertConditions/Exceptions/ExceptionMessageContainingExpectedValueAssertCondition.cs +++ b/TUnit.Assertions/AssertConditions/Exceptions/ExceptionMessageContainingExpectedValueAssertCondition.cs @@ -7,7 +7,7 @@ public class ExceptionMessageContainingExpectedValueAssertCondition( : ExpectedValueAssertCondition(expected) where TException : Exception { - internal protected override string GetExpectation() + protected internal override string GetExpectation() => $"message to contain {Formatter.Format(ExpectedValue).TruncateWithEllipsis(100)}"; protected override ValueTask GetResult(TException? actualValue, string? expectedValue) diff --git a/TUnit.Assertions/AssertConditions/Exceptions/ExceptionMessageEndingWithExpectedValueAssertCondition.cs b/TUnit.Assertions/AssertConditions/Exceptions/ExceptionMessageEndingWithExpectedValueAssertCondition.cs index bf1db7260f..e02c98bf65 100644 --- a/TUnit.Assertions/AssertConditions/Exceptions/ExceptionMessageEndingWithExpectedValueAssertCondition.cs +++ b/TUnit.Assertions/AssertConditions/Exceptions/ExceptionMessageEndingWithExpectedValueAssertCondition.cs @@ -7,7 +7,7 @@ public class ExceptionMessageEndingWithExpectedValueAssertCondition( : ExpectedValueAssertCondition(expected) where TException : Exception { - internal protected override string GetExpectation() + protected internal override string GetExpectation() => $"message to end with {Formatter.Format(ExpectedValue).TruncateWithEllipsis(100)}"; protected override ValueTask GetResult(TException? actualValue, string? expectedValue) diff --git a/TUnit.Assertions/AssertConditions/Exceptions/ExceptionMessageEqualsExpectedValueAssertCondition.cs b/TUnit.Assertions/AssertConditions/Exceptions/ExceptionMessageEqualsExpectedValueAssertCondition.cs index fdb91bb530..018fd4696c 100644 --- a/TUnit.Assertions/AssertConditions/Exceptions/ExceptionMessageEqualsExpectedValueAssertCondition.cs +++ b/TUnit.Assertions/AssertConditions/Exceptions/ExceptionMessageEqualsExpectedValueAssertCondition.cs @@ -7,7 +7,7 @@ public class ExceptionMessageEqualsExpectedValueAssertCondition(stri : ExpectedValueAssertCondition(expected) where TException : Exception { - internal protected override string GetExpectation() + protected internal override string GetExpectation() => $"message to be equal to {Formatter.Format(expected).TruncateWithEllipsis(100)}"; protected override ValueTask GetResult(TException? actualValue, string? expectedValue) diff --git a/TUnit.Assertions/AssertConditions/Exceptions/ExceptionMessageMatchingExpectedAssertCondition.cs b/TUnit.Assertions/AssertConditions/Exceptions/ExceptionMessageMatchingExpectedAssertCondition.cs index b508db40ec..423a9a7e80 100644 --- a/TUnit.Assertions/AssertConditions/Exceptions/ExceptionMessageMatchingExpectedAssertCondition.cs +++ b/TUnit.Assertions/AssertConditions/Exceptions/ExceptionMessageMatchingExpectedAssertCondition.cs @@ -7,7 +7,7 @@ public class ExceptionMessageMatchingExpectedAssertCondition(StringM : ExpectedValueAssertCondition(match) where TException : Exception { - internal protected override string GetExpectation() + protected internal override string GetExpectation() => $"message to match {Formatter.Format(ExpectedValue).TruncateWithEllipsis(100)}"; protected override ValueTask GetResult(TException? actualValue, StringMatcher? expectedValue) diff --git a/TUnit.Assertions/AssertConditions/Exceptions/ExceptionMessageStartingWithExpectedValueAssertCondition.cs b/TUnit.Assertions/AssertConditions/Exceptions/ExceptionMessageStartingWithExpectedValueAssertCondition.cs index 9bc6ead209..e300f7f37d 100644 --- a/TUnit.Assertions/AssertConditions/Exceptions/ExceptionMessageStartingWithExpectedValueAssertCondition.cs +++ b/TUnit.Assertions/AssertConditions/Exceptions/ExceptionMessageStartingWithExpectedValueAssertCondition.cs @@ -7,7 +7,7 @@ public class ExceptionMessageStartingWithExpectedValueAssertCondition(expected) where TException : Exception { - internal protected override string GetExpectation() + protected internal override string GetExpectation() => $"message to start with {Formatter.Format(ExpectedValue).TruncateWithEllipsis(100)}"; protected override ValueTask GetResult(TException? actualValue, string? expectedValue) diff --git a/TUnit.Assertions/AssertConditions/ExpectedValueAssertCondition.cs b/TUnit.Assertions/AssertConditions/ExpectedValueAssertCondition.cs index b5d1ff35a1..f465c3bd0f 100644 --- a/TUnit.Assertions/AssertConditions/ExpectedValueAssertCondition.cs +++ b/TUnit.Assertions/AssertConditions/ExpectedValueAssertCondition.cs @@ -1,3 +1,5 @@ +using System.Diagnostics.CodeAnalysis; + namespace TUnit.Assertions.AssertConditions; public abstract class ExpectedValueAssertCondition(TExpected? expected) : BaseAssertCondition diff --git a/TUnit.Assertions/AssertConditions/FuncValueAssertCondition.cs b/TUnit.Assertions/AssertConditions/FuncValueAssertCondition.cs index 29d308c99c..23ce4b6051 100644 --- a/TUnit.Assertions/AssertConditions/FuncValueAssertCondition.cs +++ b/TUnit.Assertions/AssertConditions/FuncValueAssertCondition.cs @@ -10,7 +10,7 @@ string expectation ) : ExpectedValueAssertCondition(expected) { - internal protected override string GetExpectation() => expectation; + protected internal override string GetExpectation() => expectation; protected override ValueTask GetResult(TActual? actualValue, TExpected? expectedValue) { diff --git a/TUnit.Assertions/AssertConditions/NotNullExpectedValueAssertCondition.cs b/TUnit.Assertions/AssertConditions/NotNullExpectedValueAssertCondition.cs index 9b6d52b77e..7da1ceeb4f 100644 --- a/TUnit.Assertions/AssertConditions/NotNullExpectedValueAssertCondition.cs +++ b/TUnit.Assertions/AssertConditions/NotNullExpectedValueAssertCondition.cs @@ -2,7 +2,7 @@ namespace TUnit.Assertions.AssertConditions; public class NotNullExpectedValueAssertCondition : ConvertToAssertCondition where TActual : class? { - internal protected override string GetExpectation() + protected internal override string GetExpectation() => "to not be null"; public override ValueTask<(AssertionResult, TActual?)> ConvertValue(TActual? value) @@ -19,7 +19,7 @@ internal protected override string GetExpectation() public class NotNullStructExpectedValueAssertCondition : ConvertToAssertCondition where TActual : struct { - internal protected override string GetExpectation() + protected internal override string GetExpectation() => "to not be null"; public override ValueTask<(AssertionResult, TActual)> ConvertValue(TActual? value) diff --git a/TUnit.Assertions/AssertConditions/NullExpectedValueAssertCondition.cs b/TUnit.Assertions/AssertConditions/NullExpectedValueAssertCondition.cs index d6c18f13d4..58e2143320 100644 --- a/TUnit.Assertions/AssertConditions/NullExpectedValueAssertCondition.cs +++ b/TUnit.Assertions/AssertConditions/NullExpectedValueAssertCondition.cs @@ -2,7 +2,7 @@ namespace TUnit.Assertions.AssertConditions; public class NullExpectedValueAssertCondition : BaseAssertCondition { - internal protected override string GetExpectation() + protected internal override string GetExpectation() => "to be null"; protected override ValueTask GetResult( diff --git a/TUnit.Assertions/AssertConditions/SatisfiesAssertCondition.cs b/TUnit.Assertions/AssertConditions/SatisfiesAssertCondition.cs index fffe5a7414..a292938677 100644 --- a/TUnit.Assertions/AssertConditions/SatisfiesAssertCondition.cs +++ b/TUnit.Assertions/AssertConditions/SatisfiesAssertCondition.cs @@ -19,7 +19,7 @@ public SatisfiesAssertCondition(Func?> mapper, SetSubject(mapperExpression); } - internal protected override string GetExpectation() + protected internal override string GetExpectation() => $"to satisfy {_assertionBuilderExpression}"; protected override async ValueTask GetResult( diff --git a/TUnit.Assertions/AssertConditions/StaticMethodAssertCondition.cs b/TUnit.Assertions/AssertConditions/StaticMethodAssertCondition.cs index b06bb5d588..39722187e7 100644 --- a/TUnit.Assertions/AssertConditions/StaticMethodAssertCondition.cs +++ b/TUnit.Assertions/AssertConditions/StaticMethodAssertCondition.cs @@ -31,7 +31,7 @@ protected override ValueTask GetResult(T? actualValue, Exceptio $"'{actualValue}' was expected {expectationVerb} {_methodName}()"); } - internal protected override string GetExpectation() + protected internal override string GetExpectation() { var expectationVerb = _negated ? "not to satisfy" : "to satisfy"; return $"{expectationVerb} {_methodName}()"; diff --git a/TUnit.Assertions/AssertConditions/ValueAssertCondition.cs b/TUnit.Assertions/AssertConditions/ValueAssertCondition.cs index efa7343d1f..beb72914fc 100644 --- a/TUnit.Assertions/AssertConditions/ValueAssertCondition.cs +++ b/TUnit.Assertions/AssertConditions/ValueAssertCondition.cs @@ -51,7 +51,7 @@ AssertionMetadata assertionMetadata protected abstract string GetFailureMessage(TActual? actualValue); - internal protected override string GetExpectation() + protected internal override string GetExpectation() { return GetFailureMessage(ActualValue); } diff --git a/TUnit.Assertions/AssertionBuilders/AssertionBuilder.cs b/TUnit.Assertions/AssertionBuilders/AssertionBuilder.cs index b0db196802..276d2720cc 100644 --- a/TUnit.Assertions/AssertionBuilders/AssertionBuilder.cs +++ b/TUnit.Assertions/AssertionBuilders/AssertionBuilder.cs @@ -86,7 +86,7 @@ internal AssertionBuilder AppendConnector(ChainType chainType) return (AssertionBuilder) ((ISource) this).AppendExpression(chainType.ToString()); } - internal protected void AppendCallerMethod(string?[] expressions, [CallerMemberName] string methodName = "") + protected internal void AppendCallerMethod(string?[] expressions, [CallerMemberName] string methodName = "") { if (string.IsNullOrEmpty(methodName)) { diff --git a/TUnit.Assertions/AssertionBuilders/InvokableAssertionBuilder.cs b/TUnit.Assertions/AssertionBuilders/InvokableAssertionBuilder.cs index d72747d17b..f625c84cb1 100644 --- a/TUnit.Assertions/AssertionBuilders/InvokableAssertionBuilder.cs +++ b/TUnit.Assertions/AssertionBuilders/InvokableAssertionBuilder.cs @@ -46,5 +46,5 @@ string IInvokableAssertionBuilder.GetExpression() return $"{expression[..100]}..."; } - internal protected Stack Assertions => Source.Assertions; + protected internal Stack Assertions => Source.Assertions; } diff --git a/TUnit.Assertions/Assertions/Chronology/Conditions/DateOnlyEqualsExpectedValueAssertCondition.cs b/TUnit.Assertions/Assertions/Chronology/Conditions/DateOnlyEqualsExpectedValueAssertCondition.cs index 725d9dfc13..530e2d48e6 100644 --- a/TUnit.Assertions/Assertions/Chronology/Conditions/DateOnlyEqualsExpectedValueAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Chronology/Conditions/DateOnlyEqualsExpectedValueAssertCondition.cs @@ -6,7 +6,7 @@ public class DateOnlyEqualsExpectedValueAssertCondition(DateOnly expected) : Exp { private int? _tolerance; - internal protected override string GetExpectation() + protected internal override string GetExpectation() { if (_tolerance is null or 0) { diff --git a/TUnit.Assertions/Assertions/Chronology/Conditions/DateTimeEqualsExpectedValueAssertCondition.cs b/TUnit.Assertions/Assertions/Chronology/Conditions/DateTimeEqualsExpectedValueAssertCondition.cs index 69042edb92..1ff4693c85 100644 --- a/TUnit.Assertions/Assertions/Chronology/Conditions/DateTimeEqualsExpectedValueAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Chronology/Conditions/DateTimeEqualsExpectedValueAssertCondition.cs @@ -4,7 +4,7 @@ public class DateTimeEqualsExpectedValueAssertCondition(DateTime expected) : Exp { private TimeSpan? _tolerance; - internal protected override string GetExpectation() + protected internal override string GetExpectation() { if (_tolerance == null || _tolerance == TimeSpan.Zero) { diff --git a/TUnit.Assertions/Assertions/Chronology/Conditions/DateTimeOffsetEqualsExpectedValueAssertCondition.cs b/TUnit.Assertions/Assertions/Chronology/Conditions/DateTimeOffsetEqualsExpectedValueAssertCondition.cs index 9fb1dcc672..dc049505af 100644 --- a/TUnit.Assertions/Assertions/Chronology/Conditions/DateTimeOffsetEqualsExpectedValueAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Chronology/Conditions/DateTimeOffsetEqualsExpectedValueAssertCondition.cs @@ -4,7 +4,7 @@ public class DateTimeOffsetEqualsExpectedValueAssertCondition(DateTimeOffset exp { private TimeSpan? _tolerance; - internal protected override string GetExpectation() + protected internal override string GetExpectation() { if (_tolerance == null || _tolerance == TimeSpan.Zero) { diff --git a/TUnit.Assertions/Assertions/Chronology/Conditions/TimeOnlyEqualsExpectedValueAssertCondition.cs b/TUnit.Assertions/Assertions/Chronology/Conditions/TimeOnlyEqualsExpectedValueAssertCondition.cs index edff259ad7..8a085711d4 100644 --- a/TUnit.Assertions/Assertions/Chronology/Conditions/TimeOnlyEqualsExpectedValueAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Chronology/Conditions/TimeOnlyEqualsExpectedValueAssertCondition.cs @@ -6,7 +6,7 @@ public class TimeOnlyEqualsExpectedValueAssertCondition(TimeOnly expected) : Exp { private TimeSpan? _tolerance; - internal protected override string GetExpectation() + protected internal override string GetExpectation() { if (_tolerance == null || _tolerance == TimeSpan.Zero) { diff --git a/TUnit.Assertions/Assertions/Chronology/Conditions/TimeSpanEqualsExpectedValueAssertCondition.cs b/TUnit.Assertions/Assertions/Chronology/Conditions/TimeSpanEqualsExpectedValueAssertCondition.cs index 3b99b0a173..92afe966cc 100644 --- a/TUnit.Assertions/Assertions/Chronology/Conditions/TimeSpanEqualsExpectedValueAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Chronology/Conditions/TimeSpanEqualsExpectedValueAssertCondition.cs @@ -4,7 +4,7 @@ public class TimeSpanEqualsExpectedValueAssertCondition(TimeSpan expected) : Exp { private TimeSpan? _tolerance; - internal protected override string GetExpectation() + protected internal override string GetExpectation() { if (_tolerance == null || _tolerance == TimeSpan.Zero) { diff --git a/TUnit.Assertions/Assertions/ClassMembers/Conditions/PropertyEqualsExpectedValueAssertCondition.cs b/TUnit.Assertions/Assertions/ClassMembers/Conditions/PropertyEqualsExpectedValueAssertCondition.cs index b98adf7b59..873722aa5a 100644 --- a/TUnit.Assertions/Assertions/ClassMembers/Conditions/PropertyEqualsExpectedValueAssertCondition.cs +++ b/TUnit.Assertions/Assertions/ClassMembers/Conditions/PropertyEqualsExpectedValueAssertCondition.cs @@ -7,13 +7,11 @@ namespace TUnit.Assertions.AssertConditions.ClassMember; public class PropertyEqualsExpectedValueAssertCondition(Expression> propertySelector, TPropertyType expected, bool isEqual) : ExpectedValueAssertCondition(expected) { - internal protected override string GetExpectation() + protected internal override string GetExpectation() { return $"{typeof(TRootObjectType).Name}.{ExpressionHelpers.GetName(propertySelector)} to be equal to {ExpectedValue}"; } - [RequiresUnreferencedCode("Expression compilation requires unreferenced code")] - [RequiresDynamicCode("Expression compilation requires dynamic code generation")] protected override ValueTask GetResult(TRootObjectType? actualValue, TPropertyType? expectedValue) { var propertyValue = GetPropertyValue(actualValue); @@ -24,11 +22,7 @@ protected override ValueTask GetResult(TRootObjectType? actualV $"received {GetPropertyValue(actualValue)?.ToString()}" ); } -#pragma warning restore IL3051 -#pragma warning restore IL2046 - [RequiresUnreferencedCode("Expression compilation requires unreferenced code")] - [RequiresDynamicCode("Expression compilation requires dynamic code generation")] private object? GetPropertyValue(TRootObjectType? actualValue) { if (actualValue is null) diff --git a/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableAllExpectedFuncAssertCondition.cs b/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableAllExpectedFuncAssertCondition.cs index 32326148a1..989168c849 100644 --- a/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableAllExpectedFuncAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableAllExpectedFuncAssertCondition.cs @@ -5,7 +5,7 @@ public class EnumerableAllExpectedFuncAssertCondition( : BaseAssertCondition where TActual : IEnumerable { - internal protected override string GetExpectation() => $"to contain only entries matching {matcherString ?? "null"}"; + protected internal override string GetExpectation() => $"to contain only entries matching {matcherString ?? "null"}"; protected override ValueTask GetResult( TActual? actualValue, Exception? exception, diff --git a/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableContainsExpectedFuncAssertCondition.cs b/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableContainsExpectedFuncAssertCondition.cs index 7307252478..9212f5c026 100644 --- a/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableContainsExpectedFuncAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableContainsExpectedFuncAssertCondition.cs @@ -6,7 +6,7 @@ public class EnumerableContainsExpectedFuncAssertCondition( where TActual : IEnumerable { private bool _wasFound; - internal protected override string GetExpectation() => $"to contain an entry matching {matcherString ?? "null"}"; + protected internal override string GetExpectation() => $"to contain an entry matching {matcherString ?? "null"}"; protected override ValueTask GetResult( TActual? actualValue, Exception? exception, diff --git a/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableContainsExpectedValueAssertCondition.cs b/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableContainsExpectedValueAssertCondition.cs index 46e5be8ae4..b1e81ed6c1 100644 --- a/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableContainsExpectedValueAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableContainsExpectedValueAssertCondition.cs @@ -6,7 +6,7 @@ public class EnumerableContainsExpectedValueAssertCondition( : ExpectedValueAssertCondition(expected) where TActual : IEnumerable { - internal protected override string GetExpectation() => $"to contain {ExpectedValue}"; + protected internal override string GetExpectation() => $"to contain {ExpectedValue}"; protected override ValueTask GetResult(TActual? actualValue, TInner? inner) => AssertionResult diff --git a/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableCountEqualToExpectedValueAssertCondition.cs b/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableCountEqualToExpectedValueAssertCondition.cs index e72fb14221..56e12afa26 100644 --- a/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableCountEqualToExpectedValueAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableCountEqualToExpectedValueAssertCondition.cs @@ -5,7 +5,7 @@ namespace TUnit.Assertions.AssertConditions.Collections; public class EnumerableCountEqualToExpectedValueAssertCondition(int expected) : ExpectedValueAssertCondition(expected) where TActual : IEnumerable { - internal protected override string GetExpectation() => $"to have a count of {ExpectedValue}"; + protected internal override string GetExpectation() => $"to have a count of {ExpectedValue}"; protected override ValueTask GetResult(TActual? actualValue, int count) { diff --git a/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableCountNotEqualToExpectedValueAssertCondition.cs b/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableCountNotEqualToExpectedValueAssertCondition.cs index b4d697af64..c5c4f9147b 100644 --- a/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableCountNotEqualToExpectedValueAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableCountNotEqualToExpectedValueAssertCondition.cs @@ -5,7 +5,7 @@ namespace TUnit.Assertions.AssertConditions.Collections; public class EnumerableCountNotEqualToExpectedValueAssertCondition(int expected) : ExpectedValueAssertCondition(expected) where TActual : IEnumerable { - internal protected override string GetExpectation() => $"to have a count different to {ExpectedValue}"; + protected internal override string GetExpectation() => $"to have a count different to {ExpectedValue}"; protected override ValueTask GetResult(TActual? actualValue, int count) { diff --git a/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableDistinctItemsExpectedValueAssertCondition.cs b/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableDistinctItemsExpectedValueAssertCondition.cs index 86bb0acac4..4db31b339c 100644 --- a/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableDistinctItemsExpectedValueAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableDistinctItemsExpectedValueAssertCondition.cs @@ -3,7 +3,7 @@ namespace TUnit.Assertions.AssertConditions.Collections; public class EnumerableDistinctItemsExpectedValueAssertCondition(IEqualityComparer? equalityComparer) : BaseAssertCondition where TActual : IEnumerable { - internal protected override string GetExpectation() => "items to be distinct"; + protected internal override string GetExpectation() => "items to be distinct"; protected override ValueTask GetResult( TActual? actualValue, Exception? exception, diff --git a/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableEquivalentToExpectedValueAssertCondition.cs b/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableEquivalentToExpectedValueAssertCondition.cs index 5a6605d399..44d762c715 100644 --- a/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableEquivalentToExpectedValueAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableEquivalentToExpectedValueAssertCondition.cs @@ -12,7 +12,7 @@ public class EnumerableEquivalentToExpectedValueAssertCondition : ExpectedValueAssertCondition>(expected) where TActual : IEnumerable? { - internal protected override string GetExpectation() + protected internal override string GetExpectation() { if (!typeof(TInner).IsSimpleType() && equalityComparer is EquivalentToEqualityComparer { ComparisonFailures.Length: > 0 }) diff --git a/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableNotContainsExpectedFuncAssertCondition.cs b/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableNotContainsExpectedFuncAssertCondition.cs index a28d8e76ae..2570bfca53 100644 --- a/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableNotContainsExpectedFuncAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableNotContainsExpectedFuncAssertCondition.cs @@ -5,7 +5,7 @@ public class EnumerableNotContainsExpectedFuncAssertCondition( : BaseAssertCondition where TActual : IEnumerable { - internal protected override string GetExpectation() => $"to contain no entry matching {matcherString ?? "null"}"; + protected internal override string GetExpectation() => $"to contain no entry matching {matcherString ?? "null"}"; protected override ValueTask GetResult( TActual? actualValue, Exception? exception, diff --git a/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableNotContainsExpectedValueAssertCondition.cs b/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableNotContainsExpectedValueAssertCondition.cs index 11d7e99569..6294b87f32 100644 --- a/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableNotContainsExpectedValueAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableNotContainsExpectedValueAssertCondition.cs @@ -6,7 +6,7 @@ public class EnumerableNotContainsExpectedValueAssertCondition( : ExpectedValueAssertCondition(expected) where TActual : IEnumerable { - internal protected override string GetExpectation() => $"to not contain {ExpectedValue}"; + protected internal override string GetExpectation() => $"to not contain {ExpectedValue}"; protected override ValueTask GetResult(TActual? actualValue, TInner? inner) => AssertionResult diff --git a/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableNotEquivalentToExpectedValueAssertCondition.cs b/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableNotEquivalentToExpectedValueAssertCondition.cs index 89f0d4dc45..44cb55f017 100644 --- a/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableNotEquivalentToExpectedValueAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableNotEquivalentToExpectedValueAssertCondition.cs @@ -10,7 +10,7 @@ public class EnumerableNotEquivalentToExpectedValueAssertCondition>(expected) where TActual : IEnumerable? { - internal protected override string GetExpectation() => $"to not be equivalent to {(ExpectedValue != null ? Formatter.Format(ExpectedValue) : null)}"; + protected internal override string GetExpectation() => $"to not be equivalent to {(ExpectedValue != null ? Formatter.Format(ExpectedValue) : null)}"; protected override ValueTask GetResult(TActual? actualValue, IEnumerable? expectedValue) { diff --git a/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableOrderedByAssertCondition.cs b/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableOrderedByAssertCondition.cs index ba5d8dfff3..57f885e850 100644 --- a/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableOrderedByAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Collections/Conditions/EnumerableOrderedByAssertCondition.cs @@ -8,7 +8,7 @@ public class EnumerableOrderedByAssertCondition where TActual : IEnumerable { - internal protected override string GetExpectation() + protected internal override string GetExpectation() { return $"to be in {order} order"; } diff --git a/TUnit.Assertions/Assertions/Comparables/Conditions/BetweenAssertCondition.cs b/TUnit.Assertions/Assertions/Comparables/Conditions/BetweenAssertCondition.cs index 6e561b17ba..96f9739403 100644 --- a/TUnit.Assertions/Assertions/Comparables/Conditions/BetweenAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Comparables/Conditions/BetweenAssertCondition.cs @@ -5,7 +5,7 @@ public class BetweenAssertCondition(TActual minimum, TActual maximum) : { private bool _inclusiveBounds; - internal protected override string GetExpectation() => $"to be between {minimum} & {maximum} ({GetRange()} Range)"; + protected internal override string GetExpectation() => $"to be between {minimum} & {maximum} ({GetRange()} Range)"; protected override ValueTask GetResult( TActual? actualValue, Exception? exception, diff --git a/TUnit.Assertions/Assertions/Comparables/Conditions/NotBetweenAssertCondition.cs b/TUnit.Assertions/Assertions/Comparables/Conditions/NotBetweenAssertCondition.cs index 6712efaaaf..0acc08b9d6 100644 --- a/TUnit.Assertions/Assertions/Comparables/Conditions/NotBetweenAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Comparables/Conditions/NotBetweenAssertCondition.cs @@ -5,7 +5,7 @@ public class NotBetweenAssertCondition(TActual minimum, TActual maximum { private bool _inclusiveBounds; - internal protected override string GetExpectation() => $"to not be between {minimum} & {minimum} ({GetRange()} Range)"; + protected internal override string GetExpectation() => $"to not be between {minimum} & {minimum} ({GetRange()} Range)"; protected override ValueTask GetResult( TActual? actualValue, Exception? exception, diff --git a/TUnit.Assertions/Assertions/Delegates/Conditions/CompleteWithinAssertCondition.cs b/TUnit.Assertions/Assertions/Delegates/Conditions/CompleteWithinAssertCondition.cs index f339ea9cb7..090d245660 100644 --- a/TUnit.Assertions/Assertions/Delegates/Conditions/CompleteWithinAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Delegates/Conditions/CompleteWithinAssertCondition.cs @@ -6,7 +6,7 @@ namespace TUnit.Assertions.Assertions.Delegates; public class CompleteWithinAssertCondition(TimeSpan timeSpan) : DelegateAssertCondition { - internal protected override string GetExpectation() + protected internal override string GetExpectation() => $"to complete within {timeSpan.PrettyPrint()}"; protected override ValueTask GetResult( diff --git a/TUnit.Assertions/Assertions/Enums/Conditions/EnumDoesNotHaveFlagAssertCondition.cs b/TUnit.Assertions/Assertions/Enums/Conditions/EnumDoesNotHaveFlagAssertCondition.cs index bdbf3fbf76..45c96ee5e4 100644 --- a/TUnit.Assertions/Assertions/Enums/Conditions/EnumDoesNotHaveFlagAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Enums/Conditions/EnumDoesNotHaveFlagAssertCondition.cs @@ -4,7 +4,7 @@ namespace TUnit.Assertions.Assertions.Enums.Conditions; public class EnumDoesNotHaveFlagAssertCondition(TEnum expected) : BaseAssertCondition where TEnum : Enum { - internal protected override string GetExpectation() + protected internal override string GetExpectation() { return $"to not have the flag {expected.ToString()}"; } diff --git a/TUnit.Assertions/Assertions/Enums/Conditions/EnumDoesNotHaveSameNameAsCondition.cs b/TUnit.Assertions/Assertions/Enums/Conditions/EnumDoesNotHaveSameNameAsCondition.cs index f33a453526..8e8c44c900 100644 --- a/TUnit.Assertions/Assertions/Enums/Conditions/EnumDoesNotHaveSameNameAsCondition.cs +++ b/TUnit.Assertions/Assertions/Enums/Conditions/EnumDoesNotHaveSameNameAsCondition.cs @@ -6,7 +6,7 @@ public class EnumDoesNotHaveSameNameAsCondition(TExpected expe where TEnum : Enum where TExpected : Enum { - internal protected override string GetExpectation() + protected internal override string GetExpectation() { return $"to not have the same name as {Enum.GetName(typeof(TExpected), expected)}"; } diff --git a/TUnit.Assertions/Assertions/Enums/Conditions/EnumDoesNotHaveSameValueAsCondition.cs b/TUnit.Assertions/Assertions/Enums/Conditions/EnumDoesNotHaveSameValueAsCondition.cs index a2e85913c2..4143be7b4e 100644 --- a/TUnit.Assertions/Assertions/Enums/Conditions/EnumDoesNotHaveSameValueAsCondition.cs +++ b/TUnit.Assertions/Assertions/Enums/Conditions/EnumDoesNotHaveSameValueAsCondition.cs @@ -6,7 +6,7 @@ public class EnumDoesNotHaveSameValueAsCondition(TExpected exp where TEnum : Enum where TExpected : Enum { - internal protected override string GetExpectation() + protected internal override string GetExpectation() { return $"to not have the same value as {Enum.GetName(typeof(TExpected), expected)}"; } diff --git a/TUnit.Assertions/Assertions/Enums/Conditions/EnumHasFlagAssertCondition.cs b/TUnit.Assertions/Assertions/Enums/Conditions/EnumHasFlagAssertCondition.cs index 6cd7dd39be..7b7ee25669 100644 --- a/TUnit.Assertions/Assertions/Enums/Conditions/EnumHasFlagAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Enums/Conditions/EnumHasFlagAssertCondition.cs @@ -4,7 +4,7 @@ namespace TUnit.Assertions.Assertions.Enums.Conditions; public class EnumHasFlagAssertCondition(TEnum expected) : BaseAssertCondition where TEnum : Enum { - internal protected override string GetExpectation() + protected internal override string GetExpectation() { return $"to have the flag {expected.ToString()}"; } diff --git a/TUnit.Assertions/Assertions/Enums/Conditions/EnumHasSameNameAsCondition.cs b/TUnit.Assertions/Assertions/Enums/Conditions/EnumHasSameNameAsCondition.cs index 84c74ee6be..9344c89d05 100644 --- a/TUnit.Assertions/Assertions/Enums/Conditions/EnumHasSameNameAsCondition.cs +++ b/TUnit.Assertions/Assertions/Enums/Conditions/EnumHasSameNameAsCondition.cs @@ -6,7 +6,7 @@ public class EnumHasSameNameAsCondition(TExpected expected) : where TEnum : Enum where TExpected : Enum { - internal protected override string GetExpectation() + protected internal override string GetExpectation() { return $"to have the same name as {Enum.GetName(typeof(TExpected), expected)}"; } diff --git a/TUnit.Assertions/Assertions/Enums/Conditions/EnumHasSameValueAsCondition.cs b/TUnit.Assertions/Assertions/Enums/Conditions/EnumHasSameValueAsCondition.cs index b9b7308763..42652f8fad 100644 --- a/TUnit.Assertions/Assertions/Enums/Conditions/EnumHasSameValueAsCondition.cs +++ b/TUnit.Assertions/Assertions/Enums/Conditions/EnumHasSameValueAsCondition.cs @@ -6,7 +6,7 @@ public class EnumHasSameValueAsCondition(TExpected expected) : where TEnum : Enum where TExpected : Enum { - internal protected override string GetExpectation() + protected internal override string GetExpectation() { return $"to have the same value as {Enum.GetName(typeof(TExpected), expected)}"; } diff --git a/TUnit.Assertions/Assertions/Enums/Conditions/EnumIsDefinedAssertCondition.cs b/TUnit.Assertions/Assertions/Enums/Conditions/EnumIsDefinedAssertCondition.cs index 88e46efb68..4e716788d4 100644 --- a/TUnit.Assertions/Assertions/Enums/Conditions/EnumIsDefinedAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Enums/Conditions/EnumIsDefinedAssertCondition.cs @@ -7,7 +7,7 @@ namespace TUnit.Assertions.Assertions.Enums.Conditions; public class EnumIsDefinedAssertCondition : BaseAssertCondition where TEnum : struct, Enum { - internal protected override string GetExpectation() => "to be defined"; + protected internal override string GetExpectation() => "to be defined"; protected override ValueTask GetResult( TEnum actualValue, Exception? exception, @@ -22,7 +22,7 @@ AssertionMetadata assertionMetadata public class EnumIsNotDefinedAssertCondition : BaseAssertCondition where TEnum : struct, Enum { - internal protected override string GetExpectation() => "to not be defined"; + protected internal override string GetExpectation() => "to not be defined"; protected override ValueTask GetResult( TEnum actualValue, Exception? exception, diff --git a/TUnit.Assertions/Assertions/Generics/Conditions/AssignableFromExpectedValueAssertCondition.cs b/TUnit.Assertions/Assertions/Generics/Conditions/AssignableFromExpectedValueAssertCondition.cs index f409fbb439..5ffe74869a 100644 --- a/TUnit.Assertions/Assertions/Generics/Conditions/AssignableFromExpectedValueAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Generics/Conditions/AssignableFromExpectedValueAssertCondition.cs @@ -5,7 +5,7 @@ namespace TUnit.Assertions.Assertions.Generics.Conditions; public class AssignableFromExpectedValueAssertCondition(Type expectedType) : BaseAssertCondition { - internal protected override string GetExpectation() + protected internal override string GetExpectation() => $"to be assignable from type {expectedType.Name}"; protected override ValueTask GetResult( diff --git a/TUnit.Assertions/Assertions/Generics/Conditions/AssignableToExpectedValueAssertCondition.cs b/TUnit.Assertions/Assertions/Generics/Conditions/AssignableToExpectedValueAssertCondition.cs index fe4a766291..1b1030a065 100644 --- a/TUnit.Assertions/Assertions/Generics/Conditions/AssignableToExpectedValueAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Generics/Conditions/AssignableToExpectedValueAssertCondition.cs @@ -5,7 +5,7 @@ namespace TUnit.Assertions.Assertions.Generics.Conditions; public class AssignableToExpectedValueAssertCondition(Type expectedType) : BaseAssertCondition { - internal protected override string GetExpectation() + protected internal override string GetExpectation() => $"to be assignable to type {expectedType.Name}"; protected override ValueTask GetResult( diff --git a/TUnit.Assertions/Assertions/Generics/Conditions/ConvertExceptionToValueAssertCondition.cs b/TUnit.Assertions/Assertions/Generics/Conditions/ConvertExceptionToValueAssertCondition.cs index 8a410cb68a..dcaf46f1d8 100644 --- a/TUnit.Assertions/Assertions/Generics/Conditions/ConvertExceptionToValueAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Generics/Conditions/ConvertExceptionToValueAssertCondition.cs @@ -5,14 +5,14 @@ namespace TUnit.Assertions.Assertions.Generics.Conditions; public class ConvertExceptionToValueAssertCondition : BaseAssertCondition where TException : Exception { - internal protected override string GetExpectation() + protected internal override string GetExpectation() { return $"to throw {typeof(TException).Name}"; } public TException? ConvertedExceptionValue { get; private set; } - protected override sealed ValueTask GetResult(object? actualValue, Exception? exception, AssertionMetadata assertionMetadata) + protected sealed override ValueTask GetResult(object? actualValue, Exception? exception, AssertionMetadata assertionMetadata) { if (exception is null) { diff --git a/TUnit.Assertions/Assertions/Generics/Conditions/DefaultAssertionCondition.cs b/TUnit.Assertions/Assertions/Generics/Conditions/DefaultAssertionCondition.cs index 15e21a35fe..6ed110bbd5 100644 --- a/TUnit.Assertions/Assertions/Generics/Conditions/DefaultAssertionCondition.cs +++ b/TUnit.Assertions/Assertions/Generics/Conditions/DefaultAssertionCondition.cs @@ -6,7 +6,7 @@ public class DefaultExpectedValueAssertCondition : BaseAssertCondition< { private readonly TActual? _defaultValue = default; - internal protected override string GetExpectation() + protected internal override string GetExpectation() => $"to be {(_defaultValue is null ? "null" : _defaultValue)}"; protected override ValueTask GetResult( diff --git a/TUnit.Assertions/Assertions/Generics/Conditions/DelegateConversionAssertionCondition.cs b/TUnit.Assertions/Assertions/Generics/Conditions/DelegateConversionAssertionCondition.cs index d4cdd14dab..be037ecb4e 100644 --- a/TUnit.Assertions/Assertions/Generics/Conditions/DelegateConversionAssertionCondition.cs +++ b/TUnit.Assertions/Assertions/Generics/Conditions/DelegateConversionAssertionCondition.cs @@ -7,7 +7,7 @@ public class DelegateConversionAssertionCondition( IDelegateSource source, BaseAssertCondition assertCondition) : BaseAssertCondition where TToType : Exception { - internal protected override string GetExpectation() => assertCondition.GetExpectation(); + protected internal override string GetExpectation() => assertCondition.GetExpectation(); protected override async ValueTask GetResult( TToType? actualValue, Exception? exception, diff --git a/TUnit.Assertions/Assertions/Generics/Conditions/EqualsExpectedValueAssertCondition.cs b/TUnit.Assertions/Assertions/Generics/Conditions/EqualsExpectedValueAssertCondition.cs index e62733b824..586e8c420d 100644 --- a/TUnit.Assertions/Assertions/Generics/Conditions/EqualsExpectedValueAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Generics/Conditions/EqualsExpectedValueAssertCondition.cs @@ -11,7 +11,7 @@ public EqualsExpectedValueAssertCondition(TActual expected) : this(expected, Equ { } - internal protected override string GetExpectation() + protected internal override string GetExpectation() => $"to be equal to {ExpectedValue}"; protected override ValueTask GetResult(TActual? actualValue, TActual? expectedValue) diff --git a/TUnit.Assertions/Assertions/Generics/Conditions/EquivalentToExpectedValueAssertCondition.cs b/TUnit.Assertions/Assertions/Generics/Conditions/EquivalentToExpectedValueAssertCondition.cs index 98646d1d5b..83892da041 100644 --- a/TUnit.Assertions/Assertions/Generics/Conditions/EquivalentToExpectedValueAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Generics/Conditions/EquivalentToExpectedValueAssertCondition.cs @@ -18,7 +18,7 @@ public class EquivalentToExpectedValueAssertCondition< public EquivalencyKind EquivalencyKind { get; set; } = EquivalencyKind.Full; - internal protected override string GetExpectation() + protected internal override string GetExpectation() { var expectedMessage = typeof(TExpected).IsSimpleType() || typeof(IEnumerable).IsAssignableFrom(typeof(TExpected)) ? Formatter.Format(ExpectedValue) diff --git a/TUnit.Assertions/Assertions/Generics/Conditions/NotAssignableFromExpectedValueAssertCondition.cs b/TUnit.Assertions/Assertions/Generics/Conditions/NotAssignableFromExpectedValueAssertCondition.cs index ebf87f078a..9ccfa75d32 100644 --- a/TUnit.Assertions/Assertions/Generics/Conditions/NotAssignableFromExpectedValueAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Generics/Conditions/NotAssignableFromExpectedValueAssertCondition.cs @@ -5,7 +5,7 @@ namespace TUnit.Assertions.Assertions.Generics.Conditions; public class NotAssignableFromExpectedValueAssertCondition(Type expectedType) : BaseAssertCondition { - internal protected override string GetExpectation() + protected internal override string GetExpectation() => $"to not be assignable from type {expectedType.Name}"; protected override ValueTask GetResult( diff --git a/TUnit.Assertions/Assertions/Generics/Conditions/NotAssignableToExpectedValueAssertCondition.cs b/TUnit.Assertions/Assertions/Generics/Conditions/NotAssignableToExpectedValueAssertCondition.cs index 30f3b2e652..8713de0a58 100644 --- a/TUnit.Assertions/Assertions/Generics/Conditions/NotAssignableToExpectedValueAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Generics/Conditions/NotAssignableToExpectedValueAssertCondition.cs @@ -5,7 +5,7 @@ namespace TUnit.Assertions.Assertions.Generics.Conditions; public class NotAssignableToExpectedValueAssertCondition(Type expectedType) : BaseAssertCondition { - internal protected override string GetExpectation() + protected internal override string GetExpectation() => $"to not be assignable to type {expectedType.Name}"; protected override ValueTask GetResult( diff --git a/TUnit.Assertions/Assertions/Generics/Conditions/NotDefaultAssertionCondition.cs b/TUnit.Assertions/Assertions/Generics/Conditions/NotDefaultAssertionCondition.cs index 85a77f91a4..1f248a2994 100644 --- a/TUnit.Assertions/Assertions/Generics/Conditions/NotDefaultAssertionCondition.cs +++ b/TUnit.Assertions/Assertions/Generics/Conditions/NotDefaultAssertionCondition.cs @@ -6,7 +6,7 @@ public class NotDefaultExpectedValueAssertCondition() : ExpectedValueAs { private readonly TActual? _defaultValue = default; - internal protected override string GetExpectation() + protected internal override string GetExpectation() => $"to not be {(_defaultValue is null ? "null" : _defaultValue)}"; protected override ValueTask GetResult(TActual? actualValue, TActual? expectedValue) diff --git a/TUnit.Assertions/Assertions/Generics/Conditions/NotEqualsExpectedValueAssertCondition.cs b/TUnit.Assertions/Assertions/Generics/Conditions/NotEqualsExpectedValueAssertCondition.cs index 645f8e63eb..41150af165 100644 --- a/TUnit.Assertions/Assertions/Generics/Conditions/NotEqualsExpectedValueAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Generics/Conditions/NotEqualsExpectedValueAssertCondition.cs @@ -5,7 +5,7 @@ namespace TUnit.Assertions.Assertions.Generics.Conditions; public class NotEqualsExpectedValueAssertCondition(TActual expected) : ExpectedValueAssertCondition(expected) { - internal protected override string GetExpectation() + protected internal override string GetExpectation() => $"to not be equal to {ExpectedValue}"; protected override ValueTask GetResult(TActual? actualValue, TActual? expectedValue) => AssertionResult diff --git a/TUnit.Assertions/Assertions/Generics/Conditions/NotEquivalentToExpectedValueAssertCondition.cs b/TUnit.Assertions/Assertions/Generics/Conditions/NotEquivalentToExpectedValueAssertCondition.cs index fe7c74ebf0..02b4617484 100644 --- a/TUnit.Assertions/Assertions/Generics/Conditions/NotEquivalentToExpectedValueAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Generics/Conditions/NotEquivalentToExpectedValueAssertCondition.cs @@ -19,7 +19,7 @@ public class NotEquivalentToExpectedValueAssertCondition< public EquivalencyKind EquivalencyKind { get; set; } = EquivalencyKind.Full; - internal protected override string GetExpectation() + protected internal override string GetExpectation() { var expectedMessage = typeof(TExpected).IsSimpleType() || typeof(IEnumerable).IsAssignableFrom(typeof(TExpected)) ? Formatter.Format(ExpectedValue) diff --git a/TUnit.Assertions/Assertions/Generics/Conditions/NotSameReferenceExpectedValueAssertCondition.cs b/TUnit.Assertions/Assertions/Generics/Conditions/NotSameReferenceExpectedValueAssertCondition.cs index 585bfa2799..06f9403a56 100644 --- a/TUnit.Assertions/Assertions/Generics/Conditions/NotSameReferenceExpectedValueAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Generics/Conditions/NotSameReferenceExpectedValueAssertCondition.cs @@ -6,7 +6,7 @@ namespace TUnit.Assertions.Assertions.Generics.Conditions; public class NotSameReferenceExpectedValueAssertCondition(TExpected expected) : ExpectedValueAssertCondition(expected) { - internal protected override string GetExpectation() + protected internal override string GetExpectation() => $"to not have the same reference as {ExpectedValue}"; protected override ValueTask GetResult(TActual? actualValue, TExpected? expectedValue) diff --git a/TUnit.Assertions/Assertions/Generics/Conditions/NotTypeOfExpectedValueAssertCondition.cs b/TUnit.Assertions/Assertions/Generics/Conditions/NotTypeOfExpectedValueAssertCondition.cs index d3590f7f2e..b5032f3ad5 100644 --- a/TUnit.Assertions/Assertions/Generics/Conditions/NotTypeOfExpectedValueAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Generics/Conditions/NotTypeOfExpectedValueAssertCondition.cs @@ -5,7 +5,7 @@ namespace TUnit.Assertions.Assertions.Generics.Conditions; public class NotTypeOfExpectedValueAssertCondition(Type expected) : BaseAssertCondition { - internal protected override string GetExpectation() + protected internal override string GetExpectation() => $"to not be of type {expected.Name}"; protected override ValueTask GetResult( diff --git a/TUnit.Assertions/Assertions/Generics/Conditions/SameReferenceExpectedValueAssertCondition.cs b/TUnit.Assertions/Assertions/Generics/Conditions/SameReferenceExpectedValueAssertCondition.cs index 839ff8caf8..3103e426a9 100644 --- a/TUnit.Assertions/Assertions/Generics/Conditions/SameReferenceExpectedValueAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Generics/Conditions/SameReferenceExpectedValueAssertCondition.cs @@ -6,7 +6,7 @@ namespace TUnit.Assertions.Assertions.Generics.Conditions; public class SameReferenceExpectedValueAssertCondition(TExpected expected) : ExpectedValueAssertCondition(expected) { - internal protected override string GetExpectation() + protected internal override string GetExpectation() => $"to have the same reference as {ExpectedValue}"; protected override ValueTask GetResult(TActual? actualValue, TExpected? expectedValue) diff --git a/TUnit.Assertions/Assertions/Generics/Conditions/TypeOfExpectedValueAssertCondition.cs b/TUnit.Assertions/Assertions/Generics/Conditions/TypeOfExpectedValueAssertCondition.cs index 1a0388d24a..1873e2bb9d 100644 --- a/TUnit.Assertions/Assertions/Generics/Conditions/TypeOfExpectedValueAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Generics/Conditions/TypeOfExpectedValueAssertCondition.cs @@ -5,7 +5,7 @@ namespace TUnit.Assertions.Assertions.Generics.Conditions; public class TypeOfExpectedValueAssertCondition(Type expectedType) : BaseAssertCondition { - internal protected override string GetExpectation() + protected internal override string GetExpectation() => $"to be of type {expectedType.Name}"; protected override ValueTask GetResult( diff --git a/TUnit.Assertions/Assertions/Generics/Conditions/ValueConversionAssertionCondition.cs b/TUnit.Assertions/Assertions/Generics/Conditions/ValueConversionAssertionCondition.cs index abc8df47ce..3ed90a94b1 100644 --- a/TUnit.Assertions/Assertions/Generics/Conditions/ValueConversionAssertionCondition.cs +++ b/TUnit.Assertions/Assertions/Generics/Conditions/ValueConversionAssertionCondition.cs @@ -7,7 +7,7 @@ public class ValueConversionAssertionCondition( ISource source, ConvertToAssertCondition convertToAssertCondition) : BaseAssertCondition { - internal protected override string GetExpectation() => convertToAssertCondition.GetExpectation(); + protected internal override string GetExpectation() => convertToAssertCondition.GetExpectation(); protected override async ValueTask GetResult( TToType? actualValue, Exception? exception, diff --git a/TUnit.Assertions/Assertions/Strings/Conditions/StringContainsExpectedValueAssertCondition.cs b/TUnit.Assertions/Assertions/Strings/Conditions/StringContainsExpectedValueAssertCondition.cs index f585e0d1f4..1f2c82b850 100644 --- a/TUnit.Assertions/Assertions/Strings/Conditions/StringContainsExpectedValueAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Strings/Conditions/StringContainsExpectedValueAssertCondition.cs @@ -9,7 +9,7 @@ public class StringContainsExpectedValueAssertCondition(string expected, StringC { internal bool IgnoreWhitespace { get; set; } - internal protected override string GetExpectation() + protected internal override string GetExpectation() => $"to contain {Formatter.Format(ExpectedValue).TruncateWithEllipsis(100)}"; protected override ValueTask GetResult(string? actualValue, string? expectedValue) diff --git a/TUnit.Assertions/Assertions/Strings/Conditions/StringEqualsExpectedValueAssertCondition.cs b/TUnit.Assertions/Assertions/Strings/Conditions/StringEqualsExpectedValueAssertCondition.cs index e5a6a31726..0c5fc8341c 100644 --- a/TUnit.Assertions/Assertions/Strings/Conditions/StringEqualsExpectedValueAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Strings/Conditions/StringEqualsExpectedValueAssertCondition.cs @@ -6,7 +6,7 @@ namespace TUnit.Assertions.AssertConditions.String; public class StringEqualsExpectedValueAssertCondition(string expected, StringComparison stringComparison) : ExpectedValueAssertCondition(expected) { - internal protected override string GetExpectation() + protected internal override string GetExpectation() => $"to be equal to {Formatter.Format(ExpectedValue).TruncateWithEllipsis(100)}"; protected override ValueTask GetResult(string? actualValue, string? expectedValue) diff --git a/TUnit.Assertions/Assertions/Strings/Conditions/StringNotContainsExpectedValueAssertCondition.cs b/TUnit.Assertions/Assertions/Strings/Conditions/StringNotContainsExpectedValueAssertCondition.cs index 097ae274c0..c635183b46 100644 --- a/TUnit.Assertions/Assertions/Strings/Conditions/StringNotContainsExpectedValueAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Strings/Conditions/StringNotContainsExpectedValueAssertCondition.cs @@ -6,7 +6,7 @@ namespace TUnit.Assertions.AssertConditions.String; public class StringNotContainsExpectedValueAssertCondition(string expected, StringComparison stringComparison) : ExpectedValueAssertCondition(expected) { - internal protected override string GetExpectation() + protected internal override string GetExpectation() => $"to not contain {Formatter.Format(ExpectedValue).TruncateWithEllipsis(100)}"; protected override ValueTask GetResult(string? actualValue, string? expectedValue) diff --git a/TUnit.Assertions/Assertions/Strings/Conditions/StringNotEqualsExpectedValueAssertCondition.cs b/TUnit.Assertions/Assertions/Strings/Conditions/StringNotEqualsExpectedValueAssertCondition.cs index 011d1c6fec..27941eac79 100644 --- a/TUnit.Assertions/Assertions/Strings/Conditions/StringNotEqualsExpectedValueAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Strings/Conditions/StringNotEqualsExpectedValueAssertCondition.cs @@ -6,7 +6,7 @@ namespace TUnit.Assertions.AssertConditions.String; public class StringNotEqualsExpectedValueAssertCondition(string expected, StringComparison stringComparison) : ExpectedValueAssertCondition(expected) { - internal protected override string GetExpectation() + protected internal override string GetExpectation() => $"to not be equal to {Formatter.Format(ExpectedValue).TruncateWithEllipsis(100)}"; protected override ValueTask GetResult(string? actualValue, string? expectedValue) diff --git a/TUnit.Assertions/Assertions/Throws/ThrowsAnyExceptionAssertCondition.cs b/TUnit.Assertions/Assertions/Throws/ThrowsAnyExceptionAssertCondition.cs index 8e8468d31e..6e0576e5b1 100644 --- a/TUnit.Assertions/Assertions/Throws/ThrowsAnyExceptionAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Throws/ThrowsAnyExceptionAssertCondition.cs @@ -3,7 +3,7 @@ namespace TUnit.Assertions.AssertConditions.Throws; public class ThrowsAnyExceptionAssertCondition : DelegateAssertCondition { - internal protected override string GetExpectation() + protected internal override string GetExpectation() => "to throw an exception"; protected override ValueTask GetResult( diff --git a/TUnit.Assertions/Assertions/Throws/ThrowsExactlyAssertCondition.cs b/TUnit.Assertions/Assertions/Throws/ThrowsExactlyAssertCondition.cs index 5eefcbb60e..79c29dac7d 100644 --- a/TUnit.Assertions/Assertions/Throws/ThrowsExactlyAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Throws/ThrowsExactlyAssertCondition.cs @@ -5,7 +5,7 @@ namespace TUnit.Assertions.AssertConditions.Throws; public class ThrowsExactTypeOfDelegateAssertCondition : DelegateAssertCondition where TExpectedException : Exception { - internal protected override string GetExpectation() + protected internal override string GetExpectation() => $"to throw exactly {typeof(TExpectedException).Name.PrependAOrAn()}"; protected override ValueTask GetResult( diff --git a/TUnit.Assertions/Assertions/Throws/ThrowsNothingAssertCondition.cs b/TUnit.Assertions/Assertions/Throws/ThrowsNothingAssertCondition.cs index 317fb715d9..668763cc0e 100644 --- a/TUnit.Assertions/Assertions/Throws/ThrowsNothingAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Throws/ThrowsNothingAssertCondition.cs @@ -4,7 +4,7 @@ namespace TUnit.Assertions.AssertConditions.Throws; public class ThrowsNothingAssertCondition : DelegateAssertCondition { - internal protected override string GetExpectation() + protected internal override string GetExpectation() => "to throw nothing"; protected override ValueTask GetResult( diff --git a/TUnit.Assertions/Assertions/Throws/ThrowsOfTypeAssertCondition.cs b/TUnit.Assertions/Assertions/Throws/ThrowsOfTypeAssertCondition.cs index 5708a1a327..d15f8df4e5 100644 --- a/TUnit.Assertions/Assertions/Throws/ThrowsOfTypeAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Throws/ThrowsOfTypeAssertCondition.cs @@ -4,7 +4,7 @@ namespace TUnit.Assertions.AssertConditions.Throws; public class ThrowsOfTypeAssertCondition(Type type) : DelegateAssertCondition { - internal protected override string GetExpectation() + protected internal override string GetExpectation() => $"to throw {type.Name.PrependAOrAn()}"; protected override ValueTask GetResult( @@ -21,7 +21,7 @@ AssertionMetadata assertionMetadata public class ThrowsOfTypeAssertCondition : DelegateAssertCondition where TExpectedException : Exception { - internal protected override string GetExpectation() + protected internal override string GetExpectation() => $"to throw {typeof(TExpectedException).Name.PrependAOrAn()}"; protected override ValueTask GetResult( diff --git a/TUnit.Assertions/Assertions/Throws/ThrowsWithMessageAssertCondition.cs b/TUnit.Assertions/Assertions/Throws/ThrowsWithMessageAssertCondition.cs index 551d00e99f..2350d75a41 100644 --- a/TUnit.Assertions/Assertions/Throws/ThrowsWithMessageAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Throws/ThrowsWithMessageAssertCondition.cs @@ -10,7 +10,7 @@ public class ThrowsWithMessageAssertCondition( : DelegateAssertCondition where TException : Exception { - internal protected override string GetExpectation() + protected internal override string GetExpectation() => $"to throw {typeof(TException).Name.PrependAOrAn()} which message equals \"{expectedMessage.ShowNewLines().TruncateWithEllipsis(100)}\""; protected override ValueTask GetResult( diff --git a/TUnit.Assertions/Assertions/Throws/ThrowsWithMessageContainingAssertCondition.cs b/TUnit.Assertions/Assertions/Throws/ThrowsWithMessageContainingAssertCondition.cs index 1138edd1ba..13638ad18b 100644 --- a/TUnit.Assertions/Assertions/Throws/ThrowsWithMessageContainingAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Throws/ThrowsWithMessageContainingAssertCondition.cs @@ -9,7 +9,7 @@ public class ThrowsWithMessageContainingAssertCondition( : DelegateAssertCondition where TException : Exception { - internal protected override string GetExpectation() + protected internal override string GetExpectation() => $"to throw {typeof(TException).Name.PrependAOrAn()} which message contains \"{expected?.ShowNewLines().TruncateWithEllipsis(100)}\""; protected override ValueTask GetResult( diff --git a/TUnit.Assertions/Assertions/Throws/ThrowsWithMessageMatchingAssertCondition.cs b/TUnit.Assertions/Assertions/Throws/ThrowsWithMessageMatchingAssertCondition.cs index 0cdee87585..4afbf691d3 100644 --- a/TUnit.Assertions/Assertions/Throws/ThrowsWithMessageMatchingAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Throws/ThrowsWithMessageMatchingAssertCondition.cs @@ -8,7 +8,7 @@ public class ThrowsWithMessageMatchingAssertCondition( : DelegateAssertCondition where TException : Exception { - internal protected override string GetExpectation() + protected internal override string GetExpectation() => $"to throw {typeof(TException).Name.PrependAOrAn()} which message matches \"{match.ToString()?.ShowNewLines().TruncateWithEllipsis(100)}\""; protected override ValueTask GetResult( diff --git a/TUnit.Assertions/Assertions/Throws/ThrowsWithMessageNotContainingAssertCondition.cs b/TUnit.Assertions/Assertions/Throws/ThrowsWithMessageNotContainingAssertCondition.cs index a5c6565745..544668a21b 100644 --- a/TUnit.Assertions/Assertions/Throws/ThrowsWithMessageNotContainingAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Throws/ThrowsWithMessageNotContainingAssertCondition.cs @@ -9,7 +9,7 @@ public class ThrowsWithMessageNotContainingAssertCondition( : DelegateAssertCondition where TException : Exception { - internal protected override string GetExpectation() + protected internal override string GetExpectation() => $"to throw {typeof(TException).Name.PrependAOrAn()} which message does not contain \"{expected?.ShowNewLines().TruncateWithEllipsis(100)}\""; protected override ValueTask GetResult( diff --git a/TUnit.Assertions/Assertions/Throws/ThrowsWithParamNameAssertCondition.cs b/TUnit.Assertions/Assertions/Throws/ThrowsWithParamNameAssertCondition.cs index e1b9840ed2..e99c58fe9b 100644 --- a/TUnit.Assertions/Assertions/Throws/ThrowsWithParamNameAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Throws/ThrowsWithParamNameAssertCondition.cs @@ -10,7 +10,7 @@ public class ThrowsWithParamNameAssertCondition( : DelegateAssertCondition() where TException : ArgumentException { - internal protected override string GetExpectation() + protected internal override string GetExpectation() => $"to throw {typeof(TException).Name.PrependAOrAn()} which param name equals \"{expectedParamName.TruncateWithEllipsis(100)}\""; protected override ValueTask GetResult( diff --git a/TUnit.Assertions/Assertions/Throws/ThrowsWithinAssertCondition.cs b/TUnit.Assertions/Assertions/Throws/ThrowsWithinAssertCondition.cs index 82c98589ae..61758c88a4 100644 --- a/TUnit.Assertions/Assertions/Throws/ThrowsWithinAssertCondition.cs +++ b/TUnit.Assertions/Assertions/Throws/ThrowsWithinAssertCondition.cs @@ -8,7 +8,7 @@ namespace TUnit.Assertions.AssertConditions.Throws; public class ThrowsWithinAssertCondition(TimeSpan timeSpan) : DelegateAssertCondition where TExpectedException : Exception { - internal protected override string GetExpectation() + protected internal override string GetExpectation() => $"to throw {typeof(TExpectedException).Name.PrependAOrAn()} within {timeSpan.PrettyPrint()}"; protected override ValueTask GetResult( diff --git a/TUnit.Assertions/Compare.cs b/TUnit.Assertions/Compare.cs index 241851dd7b..7b665f35ab 100644 --- a/TUnit.Assertions/Compare.cs +++ b/TUnit.Assertions/Compare.cs @@ -1,11 +1,13 @@ using System.Collections; using System.Diagnostics.CodeAnalysis; using System.Reflection; +using System.Runtime.CompilerServices; using TUnit.Assertions.Enums; using TUnit.Assertions.Extensions; namespace TUnit.Assertions; +[UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "AOT mode uses the attributed compiler type instead of the runtime GetType.")] public static class Compare { private static readonly BindingFlags BindingFlags = @@ -61,7 +63,20 @@ private static IEnumerable CheckEquivalent< yield break; } - if (actual.GetType().IsSimpleType()) + var actualType = +#if NET + RuntimeFeature.IsDynamicCodeSupported ? actual.GetType() : typeof(TActual); +#else + actual.GetType(); +#endif + var expectedType = +#if NET + RuntimeFeature.IsDynamicCodeSupported ? expected.GetType() : typeof(TExpected); +#else + expected.GetType(); +#endif + + if (actualType.IsSimpleType()) { yield return new ComparisonFailure { @@ -153,7 +168,7 @@ private static IEnumerable CheckEquivalent< yield break; } - foreach (var fieldName in actual.GetType().GetFields().Concat(expected.GetType().GetFields()) + foreach (var fieldName in actualType.GetFields().Concat(expectedType.GetFields()) .Where(x => !x.Name.StartsWith('<')) .Select(x => x.Name) .Distinct()) @@ -165,8 +180,8 @@ private static IEnumerable CheckEquivalent< continue; } - var actualFieldInfo = actual.GetType().GetField(fieldName, BindingFlags); - var expectedFieldInfo = expected.GetType().GetField(fieldName, BindingFlags); + var actualFieldInfo = actualType.GetField(fieldName, BindingFlags); + var expectedFieldInfo = expectedType.GetField(fieldName, BindingFlags); // Check if field type should be ignored if (actualFieldInfo != null && ShouldIgnoreType(actualFieldInfo.FieldType, options.TypesToIgnore)) @@ -213,7 +228,7 @@ private static IEnumerable CheckEquivalent< } } - foreach (var propertyName in actual.GetType().GetProperties().Concat(expected.GetType().GetProperties()) + foreach (var propertyName in actualType.GetProperties().Concat(expectedType.GetProperties()) .Where(p => p.GetIndexParameters().Length == 0) .Select(x => x.Name) .Distinct()) @@ -225,8 +240,8 @@ private static IEnumerable CheckEquivalent< continue; } - var actualPropertyInfo = actual.GetType().GetProperty(propertyName, BindingFlags); - var expectedPropertyInfo = expected.GetType().GetProperty(propertyName, BindingFlags); + var actualPropertyInfo = actualType.GetProperty(propertyName, BindingFlags); + var expectedPropertyInfo = expectedType.GetProperty(propertyName, BindingFlags); // Check if property type should be ignored if (actualPropertyInfo != null && ShouldIgnoreType(actualPropertyInfo.PropertyType, options.TypesToIgnore)) diff --git a/TUnit.Core/AotCompatibility/GenericTestRegistry.cs b/TUnit.Core/AotCompatibility/GenericTestRegistry.cs index 01222ff887..0afcdd7588 100644 --- a/TUnit.Core/AotCompatibility/GenericTestRegistry.cs +++ b/TUnit.Core/AotCompatibility/GenericTestRegistry.cs @@ -121,7 +121,7 @@ public readonly bool Equals(GenericMethodKey other) TypeArrayComparer.Instance.Equals(TypeArguments, other.TypeArguments); } - public readonly override int GetHashCode() + public override readonly int GetHashCode() { #if NETSTANDARD2_0 unchecked diff --git a/TUnit.Engine/Discovery/IHookDiscoveryService.cs b/TUnit.Engine/Discovery/IHookDiscoveryService.cs new file mode 100644 index 0000000000..ac392694a3 --- /dev/null +++ b/TUnit.Engine/Discovery/IHookDiscoveryService.cs @@ -0,0 +1,17 @@ +namespace TUnit.Engine.Discovery; + +/// +/// Discovers hooks based on the execution mode (source generation or reflection). +/// +internal interface IHookDiscoveryService +{ + /// + /// Discovers and registers all hooks for the test session. + /// + void DiscoverHooks(); + + /// + /// Discovers instance hooks for a specific type (used for closed generic types). + /// + void DiscoverInstanceHooksForType(Type type); +} diff --git a/TUnit.Engine/Discovery/ReflectionBasedHookDiscoveryService.cs b/TUnit.Engine/Discovery/ReflectionBasedHookDiscoveryService.cs new file mode 100644 index 0000000000..673aac6bfe --- /dev/null +++ b/TUnit.Engine/Discovery/ReflectionBasedHookDiscoveryService.cs @@ -0,0 +1,31 @@ +using System.Diagnostics.CodeAnalysis; + +namespace TUnit.Engine.Discovery; + +/// +/// Hook discovery service for reflection mode. +/// Uses reflection to scan assemblies and discover hooks at runtime. +/// This implementation requires reflection and is NOT AOT-compatible. +/// +#if NET6_0_OR_GREATER +[RequiresUnreferencedCode("Hook discovery uses reflection to scan assemblies and types")] +[RequiresDynamicCode("Hook delegate creation requires dynamic code generation")] +#endif +internal sealed class ReflectionBasedHookDiscoveryService : IHookDiscoveryService +{ + /// + /// Discovers hooks using reflection by scanning all loaded assemblies. + /// + public void DiscoverHooks() + { + ReflectionHookDiscoveryService.DiscoverHooks(); + } + + /// + /// Discovers instance hooks for a specific closed generic type using reflection. + /// + public void DiscoverInstanceHooksForType(Type type) + { + ReflectionHookDiscoveryService.DiscoverInstanceHooksForType(type); + } +} diff --git a/TUnit.Engine/Discovery/ReflectionTestDataCollector.cs b/TUnit.Engine/Discovery/ReflectionTestDataCollector.cs index f1623a53af..74cdcd195d 100644 --- a/TUnit.Engine/Discovery/ReflectionTestDataCollector.cs +++ b/TUnit.Engine/Discovery/ReflectionTestDataCollector.cs @@ -1441,6 +1441,9 @@ private static bool IsCovariantCompatible(Type paramType, [DynamicallyAccessedMe /// /// Creates a reflection-based test invoker with proper AOT attribution /// + #if NET6_0_OR_GREATER + [UnconditionalSuppressMessage("Trimming", "IL2060", Justification = "Reflection-based test invoker is only used in reflection mode, not in AOT")] + #endif private static Func CreateReflectionTestInvoker(Type testClass, MethodInfo testMethod) { var isPrepared = false; diff --git a/TUnit.Engine/Discovery/SourceGenHookDiscoveryService.cs b/TUnit.Engine/Discovery/SourceGenHookDiscoveryService.cs new file mode 100644 index 0000000000..e237c8a5bf --- /dev/null +++ b/TUnit.Engine/Discovery/SourceGenHookDiscoveryService.cs @@ -0,0 +1,27 @@ +namespace TUnit.Engine.Discovery; + +/// +/// Hook discovery service for source generation mode. +/// In this mode, hooks are discovered at compile time via source generators, so no runtime discovery is needed. +/// This implementation is AOT-compatible and does not use reflection. +/// +internal sealed class SourceGenHookDiscoveryService : IHookDiscoveryService +{ + /// + /// No-op implementation. Hooks are already registered via source generation. + /// + public void DiscoverHooks() + { + // Hooks are already discovered and registered at compile time via source generation + // No runtime discovery needed + } + + /// + /// No-op implementation. Instance hooks for generic types are already registered via source generation. + /// + public void DiscoverInstanceHooksForType(Type type) + { + // Hooks are already discovered and registered at compile time via source generation + // No runtime discovery needed for closed generic types + } +} diff --git a/TUnit.Engine/Logging/StandardErrorConsoleInterceptor.cs b/TUnit.Engine/Logging/StandardErrorConsoleInterceptor.cs index 41b921f2cc..2d3080bcae 100644 --- a/TUnit.Engine/Logging/StandardErrorConsoleInterceptor.cs +++ b/TUnit.Engine/Logging/StandardErrorConsoleInterceptor.cs @@ -33,12 +33,12 @@ public void Initialize() Console.SetError(this); } - protected private override TextWriter GetOriginalOut() + private protected override TextWriter GetOriginalOut() { return DefaultError; } - protected private override void ResetDefault() + private protected override void ResetDefault() { Console.SetError(DefaultError); } diff --git a/TUnit.Engine/Logging/StandardOutConsoleInterceptor.cs b/TUnit.Engine/Logging/StandardOutConsoleInterceptor.cs index 9d981ceca8..d494fee6aa 100644 --- a/TUnit.Engine/Logging/StandardOutConsoleInterceptor.cs +++ b/TUnit.Engine/Logging/StandardOutConsoleInterceptor.cs @@ -33,12 +33,12 @@ public void Initialize() Console.SetOut(this); } - protected private override TextWriter GetOriginalOut() + private protected override TextWriter GetOriginalOut() { return DefaultOut; } - protected private override void ResetDefault() + private protected override void ResetDefault() { Console.SetOut(DefaultOut); } diff --git a/TUnit.Engine/Services/IStaticPropertyInitializer.cs b/TUnit.Engine/Services/IStaticPropertyInitializer.cs new file mode 100644 index 0000000000..87c46d7bcb --- /dev/null +++ b/TUnit.Engine/Services/IStaticPropertyInitializer.cs @@ -0,0 +1,12 @@ +namespace TUnit.Engine.Services; + +/// +/// Initializes static properties for tests based on the execution mode. +/// +internal interface IStaticPropertyInitializer +{ + /// + /// Initializes all static properties. + /// + Task InitializeAsync(CancellationToken cancellationToken); +} diff --git a/TUnit.Engine/Services/ObjectRegistrationService.cs b/TUnit.Engine/Services/ObjectRegistrationService.cs index 549f642ae8..26b7a23041 100644 --- a/TUnit.Engine/Services/ObjectRegistrationService.cs +++ b/TUnit.Engine/Services/ObjectRegistrationService.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using TUnit.Core; using TUnit.Core.PropertyInjection; using TUnit.Core.Tracking; @@ -95,6 +96,9 @@ public async Task RegisterArgumentsAsync( /// /// Determines if an object requires property injection. /// + #if NET6_0_OR_GREATER + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Property injection cache handles both AOT and reflection modes appropriately")] + #endif private bool RequiresPropertyInjection(object instance) { return PropertyInjectionCache.HasInjectableProperties(instance.GetType()); diff --git a/TUnit.Engine/Services/PropertyInitialization/Strategies/NestedPropertyStrategy.cs b/TUnit.Engine/Services/PropertyInitialization/Strategies/NestedPropertyStrategy.cs index 45be31469d..e348526de7 100644 --- a/TUnit.Engine/Services/PropertyInitialization/Strategies/NestedPropertyStrategy.cs +++ b/TUnit.Engine/Services/PropertyInitialization/Strategies/NestedPropertyStrategy.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using TUnit.Core; using TUnit.Core.PropertyInjection; using TUnit.Core.PropertyInjection.Initialization; @@ -36,6 +37,9 @@ public bool CanHandle(PropertyInitializationContext context) /// /// Initializes nested properties within an already resolved property value. /// + #if NET6_0_OR_GREATER + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Property injection cache and setter factory handle both AOT and reflection modes appropriately")] + #endif public async Task InitializePropertyAsync(PropertyInitializationContext context) { if (context.ResolvedValue == null) @@ -143,6 +147,9 @@ private PropertyInitializationContext CreateNestedContext( /// /// Creates a nested context for reflection-based properties. /// + #if NET6_0_OR_GREATER + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Reflection-based property setter creation is only used in reflection mode, not in AOT")] + #endif private PropertyInitializationContext CreateNestedContext( PropertyInitializationContext parentContext, object instance, diff --git a/TUnit.Engine/Services/PropertyInitialization/Strategies/ReflectionPropertyStrategy.cs b/TUnit.Engine/Services/PropertyInitialization/Strategies/ReflectionPropertyStrategy.cs index 15e7d38dee..f5bb829bd9 100644 --- a/TUnit.Engine/Services/PropertyInitialization/Strategies/ReflectionPropertyStrategy.cs +++ b/TUnit.Engine/Services/PropertyInitialization/Strategies/ReflectionPropertyStrategy.cs @@ -30,6 +30,9 @@ public bool CanHandle(PropertyInitializationContext context) /// /// Initializes a property using reflection. /// + #if NET6_0_OR_GREATER + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Reflection mode throws at runtime if used in AOT, property data resolver handles reflection appropriately")] + #endif public async Task InitializePropertyAsync(PropertyInitializationContext context) { #if NET diff --git a/TUnit.Engine/Services/PropertyInitialization/Strategies/SourceGeneratedPropertyStrategy.cs b/TUnit.Engine/Services/PropertyInitialization/Strategies/SourceGeneratedPropertyStrategy.cs index 068470813a..42eb2828b8 100644 --- a/TUnit.Engine/Services/PropertyInitialization/Strategies/SourceGeneratedPropertyStrategy.cs +++ b/TUnit.Engine/Services/PropertyInitialization/Strategies/SourceGeneratedPropertyStrategy.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using TUnit.Core; using TUnit.Core.PropertyInjection.Initialization; @@ -28,6 +29,9 @@ public bool CanHandle(PropertyInitializationContext context) /// /// Initializes a property using source-generated metadata. /// + #if NET6_0_OR_GREATER + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Property data resolver handles both AOT and reflection modes appropriately")] + #endif public async Task InitializePropertyAsync(PropertyInitializationContext context) { if (context.SourceGeneratedMetadata == null) diff --git a/TUnit.Engine/Services/PropertyInitializationOrchestrator.cs b/TUnit.Engine/Services/PropertyInitializationOrchestrator.cs index c7b4a7ccb5..17c55a854d 100644 --- a/TUnit.Engine/Services/PropertyInitializationOrchestrator.cs +++ b/TUnit.Engine/Services/PropertyInitializationOrchestrator.cs @@ -144,6 +144,9 @@ private PropertyInitializationContext CreateContext( /// /// Creates initialization context for reflection-based properties. /// + #if NET6_0_OR_GREATER + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Reflection-based property setter creation is only used in reflection mode, not in AOT")] + #endif private PropertyInitializationContext CreateContext( object instance, PropertyInfo property, diff --git a/TUnit.Engine/Services/ReflectionStaticPropertyInitializer.cs b/TUnit.Engine/Services/ReflectionStaticPropertyInitializer.cs new file mode 100644 index 0000000000..bc652c4bd9 --- /dev/null +++ b/TUnit.Engine/Services/ReflectionStaticPropertyInitializer.cs @@ -0,0 +1,45 @@ +using System.Diagnostics.CodeAnalysis; +using TUnit.Core; +using TUnit.Core.Services; +using TUnit.Engine.Logging; + +namespace TUnit.Engine.Services; + +/// +/// Initializes static properties using both source-generated initializers and reflection-based discovery. +/// This implementation requires reflection and is NOT AOT-compatible. +/// +#if NET6_0_OR_GREATER +[RequiresUnreferencedCode("Uses reflection to discover and initialize static properties")] +[RequiresDynamicCode("Static property initialization may require dynamic code generation")] +#endif +internal sealed class ReflectionStaticPropertyInitializer : IStaticPropertyInitializer +{ + private readonly TUnitFrameworkLogger _logger; + + public ReflectionStaticPropertyInitializer(TUnitFrameworkLogger logger) + { + _logger = logger; + } + + public async Task InitializeAsync(CancellationToken cancellationToken) + { + try + { + // Execute all registered global initializers from source generation + while (Sources.GlobalInitializers.TryDequeue(out var initializer)) + { + cancellationToken.ThrowIfCancellationRequested(); + await initializer(); + } + + // Additionally, initialize static properties discovered via reflection + await StaticPropertyReflectionInitializer.InitializeAllStaticPropertiesAsync(); + } + catch (Exception ex) + { + await _logger.LogErrorAsync($"Error during static property initialization: {ex}"); + throw; + } + } +} diff --git a/TUnit.Engine/Services/SourceGenStaticPropertyInitializer.cs b/TUnit.Engine/Services/SourceGenStaticPropertyInitializer.cs new file mode 100644 index 0000000000..eb24ffb7fd --- /dev/null +++ b/TUnit.Engine/Services/SourceGenStaticPropertyInitializer.cs @@ -0,0 +1,36 @@ +using TUnit.Core; +using TUnit.Engine.Logging; + +namespace TUnit.Engine.Services; + +/// +/// Initializes static properties using source-generated initializers only. +/// This implementation does not use reflection and is AOT-compatible. +/// +internal sealed class SourceGenStaticPropertyInitializer : IStaticPropertyInitializer +{ + private readonly TUnitFrameworkLogger _logger; + + public SourceGenStaticPropertyInitializer(TUnitFrameworkLogger logger) + { + _logger = logger; + } + + public async Task InitializeAsync(CancellationToken cancellationToken) + { + try + { + // Execute all registered global initializers from source generation + while (Sources.GlobalInitializers.TryDequeue(out var initializer)) + { + cancellationToken.ThrowIfCancellationRequested(); + await initializer(); + } + } + catch (Exception ex) + { + await _logger.LogErrorAsync($"Error during static property initialization: {ex}"); + throw; + } + } +} diff --git a/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet8_0.verified.txt b/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet8_0.verified.txt index 32ed0bae3c..8752db4b70 100644 --- a/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet8_0.verified.txt +++ b/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet8_0.verified.txt @@ -71,6 +71,7 @@ namespace public .<.> Satisfy(?> asyncMapper, <..IValueSource, .> assert, [.("asyncMapper")] string mapperExpression = "", [.("assert")] string assertionBuilderExpression = "") { } public .<.> Satisfy( mapper, <..IValueSource, .> assert, [.("mapper")] string mapperExpression = "", [.("assert")] string assertionBuilderExpression = "") { } } + [.("Trimming", "IL2075", Justification="AOT mode uses the attributed compiler type instead of the runtime GetType.")] public static class Compare { public static .<.ComparisonFailure> CheckEquivalent<[.(..None | ..PublicFields | ..NonPublicFields | ..PublicProperties | ..NonPublicProperties)] TActual, [.(..None | ..PublicFields | ..NonPublicFields | ..PublicProperties | ..NonPublicProperties)] TExpected>(TActual actual, TExpected expected, .CompareOptions options, int? index) { } @@ -326,8 +327,6 @@ namespace . { public PropertyEqualsExpectedValueAssertCondition(.<> propertySelector, TPropertyType expected, bool isEqual) { } protected override string GetExpectation() { } - [.("Expression compilation requires dynamic code generation")] - [.("Expression compilation requires unreferenced code")] protected override .<.> GetResult(TRootObjectType? actualValue, TPropertyType? expectedValue) { } } } diff --git a/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet9_0.verified.txt b/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet9_0.verified.txt index 305f38c745..fc404b40de 100644 --- a/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet9_0.verified.txt +++ b/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet9_0.verified.txt @@ -71,6 +71,7 @@ namespace public .<.> Satisfy(?> asyncMapper, <..IValueSource, .> assert, [.("asyncMapper")] string mapperExpression = "", [.("assert")] string assertionBuilderExpression = "") { } public .<.> Satisfy( mapper, <..IValueSource, .> assert, [.("mapper")] string mapperExpression = "", [.("assert")] string assertionBuilderExpression = "") { } } + [.("Trimming", "IL2075", Justification="AOT mode uses the attributed compiler type instead of the runtime GetType.")] public static class Compare { public static .<.ComparisonFailure> CheckEquivalent<[.(..None | ..PublicFields | ..NonPublicFields | ..PublicProperties | ..NonPublicProperties)] TActual, [.(..None | ..PublicFields | ..NonPublicFields | ..PublicProperties | ..NonPublicProperties)] TExpected>(TActual actual, TExpected expected, .CompareOptions options, int? index) { } @@ -326,8 +327,6 @@ namespace . { public PropertyEqualsExpectedValueAssertCondition(.<> propertySelector, TPropertyType expected, bool isEqual) { } protected override string GetExpectation() { } - [.("Expression compilation requires dynamic code generation")] - [.("Expression compilation requires unreferenced code")] protected override .<.> GetResult(TRootObjectType? actualValue, TPropertyType? expectedValue) { } } } From 2aa932a9cb82ebde15c8a56ea1fd80b32e87c698 Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Sun, 5 Oct 2025 14:27:12 +0100 Subject: [PATCH 11/14] fix: add TrimmerSingleWarn property for AOT compatibility --- .../TUnit.NugetTester/TUnit.NugetTester/TUnit.NugetTester.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester/TUnit.NugetTester.csproj b/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester/TUnit.NugetTester.csproj index 88d8cdc3c3..42163c3879 100644 --- a/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester/TUnit.NugetTester.csproj +++ b/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester/TUnit.NugetTester.csproj @@ -16,6 +16,7 @@ true true false + false From e1cbfd5c9d101ef916a54b04df06c2471dcb88ee Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Sun, 5 Oct 2025 14:51:56 +0100 Subject: [PATCH 12/14] fix: enhance AOT compatibility by adding non-public member access attributes --- TUnit.Core/Models/TestModels/ParameterMetadata.cs | 4 ++++ TUnit.Engine/Discovery/ReflectionHookDiscoveryService.cs | 6 +++++- ...s.Core_Library_Has_No_API_Changes.DotNet8_0.verified.txt | 4 ++-- ...s.Core_Library_Has_No_API_Changes.DotNet9_0.verified.txt | 4 ++-- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/TUnit.Core/Models/TestModels/ParameterMetadata.cs b/TUnit.Core/Models/TestModels/ParameterMetadata.cs index 36a9876101..cd2a81a843 100644 --- a/TUnit.Core/Models/TestModels/ParameterMetadata.cs +++ b/TUnit.Core/Models/TestModels/ParameterMetadata.cs @@ -6,13 +6,17 @@ namespace TUnit.Core; [DebuggerDisplay("{Type} {Name}")] public record ParameterMetadata<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors + | DynamicallyAccessedMemberTypes.NonPublicConstructors | DynamicallyAccessedMemberTypes.PublicMethods + | DynamicallyAccessedMemberTypes.NonPublicMethods | DynamicallyAccessedMemberTypes.PublicProperties)] T>() : ParameterMetadata(typeof(T)); [DebuggerDisplay("{Type} {Name}")] public record ParameterMetadata([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors + | DynamicallyAccessedMemberTypes.NonPublicConstructors | DynamicallyAccessedMemberTypes.PublicMethods + | DynamicallyAccessedMemberTypes.NonPublicMethods | DynamicallyAccessedMemberTypes.PublicProperties)] Type Type) : MemberMetadata { public required TypeReference TypeReference { get; init; } diff --git a/TUnit.Engine/Discovery/ReflectionHookDiscoveryService.cs b/TUnit.Engine/Discovery/ReflectionHookDiscoveryService.cs index 502ab62101..02f5965d18 100644 --- a/TUnit.Engine/Discovery/ReflectionHookDiscoveryService.cs +++ b/TUnit.Engine/Discovery/ReflectionHookDiscoveryService.cs @@ -12,6 +12,10 @@ namespace TUnit.Engine.Discovery; /// /// Discovers hooks at runtime using reflection for VB.NET and other languages that don't support source generation. /// +#if NET6_0_OR_GREATER +[RequiresUnreferencedCode("Uses reflection to access nested members")] +[RequiresDynamicCode("Uses reflection to access nested members")] +#endif internal sealed class ReflectionHookDiscoveryService { private static readonly ConcurrentDictionary _scannedAssemblies = new(); @@ -236,8 +240,8 @@ private static void DiscoverHooksInAssembly(Assembly assembly) { #if NET6_0_OR_GREATER [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Assembly.GetTypes is reflection-based but required for hook discovery")] + [UnconditionalSuppressMessage("Trimming", "IL2072", Justification = "Types from Assembly.GetTypes() are passed to annotated parameters")] #endif - [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors | DynamicallyAccessedMemberTypes.NonPublicMethods | DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type[] GetTypes() => assembly.GetTypes(); var types = GetTypes(); diff --git a/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet8_0.verified.txt b/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet8_0.verified.txt index 7826a60961..ecea92f996 100644 --- a/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet8_0.verified.txt +++ b/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet8_0.verified.txt @@ -1036,7 +1036,7 @@ namespace [.DebuggerDisplay("{Type} {Name}")] public class ParameterMetadata : .MemberMetadata, <.ParameterMetadata> { - public ParameterMetadata([.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..PublicMethods | ..PublicProperties)] Type) { } + public ParameterMetadata([.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..NonPublicConstructors | ..PublicMethods | ..NonPublicMethods | ..PublicProperties)] Type) { } public object? CachedDefaultValue { get; init; } public bool? CachedIsOptional { get; init; } public bool? CachedIsParams { get; init; } @@ -1050,7 +1050,7 @@ namespace public required .TypeReference TypeReference { get; init; } } [.DebuggerDisplay("{Type} {Name}")] - public class ParameterMetadata<[.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..PublicMethods | ..PublicProperties)] T> : .ParameterMetadata, <.ParameterMetadata> + public class ParameterMetadata<[.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..NonPublicConstructors | ..PublicMethods | ..NonPublicMethods | ..PublicProperties)] T> : .ParameterMetadata, <.ParameterMetadata> { public ParameterMetadata() { } } diff --git a/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet9_0.verified.txt b/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet9_0.verified.txt index b7c4acacd6..2eea47cd9b 100644 --- a/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet9_0.verified.txt +++ b/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet9_0.verified.txt @@ -1036,7 +1036,7 @@ namespace [.DebuggerDisplay("{Type} {Name}")] public class ParameterMetadata : .MemberMetadata, <.ParameterMetadata> { - public ParameterMetadata([.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..PublicMethods | ..PublicProperties)] Type) { } + public ParameterMetadata([.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..NonPublicConstructors | ..PublicMethods | ..NonPublicMethods | ..PublicProperties)] Type) { } public object? CachedDefaultValue { get; init; } public bool? CachedIsOptional { get; init; } public bool? CachedIsParams { get; init; } @@ -1050,7 +1050,7 @@ namespace public required .TypeReference TypeReference { get; init; } } [.DebuggerDisplay("{Type} {Name}")] - public class ParameterMetadata<[.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..PublicMethods | ..PublicProperties)] T> : .ParameterMetadata, <.ParameterMetadata> + public class ParameterMetadata<[.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..NonPublicConstructors | ..PublicMethods | ..NonPublicMethods | ..PublicProperties)] T> : .ParameterMetadata, <.ParameterMetadata> { public ParameterMetadata() { } } From 2b4e27691f7738b469bbaf3f9ce87977de417c4f Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Sun, 5 Oct 2025 15:52:43 +0100 Subject: [PATCH 13/14] fix: add .idea directory to .gitignore to prevent IDE-specific files from being tracked --- .gitignore | 1 + .idea/.idea.TUnit/.idea/workspace.xml | 223 -------------------------- 2 files changed, 1 insertion(+), 223 deletions(-) delete mode 100644 .idea/.idea.TUnit/.idea/workspace.xml diff --git a/.gitignore b/.gitignore index 2d7856147c..3dae757b14 100644 --- a/.gitignore +++ b/.gitignore @@ -397,6 +397,7 @@ FodyWeavers.xsd # JetBrains Rider *.sln.iml +.idea/ # Generated Code *.g.cs diff --git a/.idea/.idea.TUnit/.idea/workspace.xml b/.idea/.idea.TUnit/.idea/workspace.xml deleted file mode 100644 index 3cbd41152c..0000000000 --- a/.idea/.idea.TUnit/.idea/workspace.xml +++ /dev/null @@ -1,223 +0,0 @@ - - - - TUnit.Analyzers.Tests/TUnit.Analyzers.Tests.csproj - TUnit.Analyzers/TUnit.Analyzers.csproj - TUnit.Assertions.Analyzers.CodeFixers.Tests/TUnit.Assertions.Analyzers.CodeFixers.Tests.csproj - TUnit.Assertions.Analyzers.Tests/TUnit.Assertions.Analyzers.Tests.csproj - TUnit.Assertions.Analyzers/TUnit.Assertions.Analyzers.csproj - TUnit.Assertions.SourceGenerator.Tests/TUnit.Assertions.SourceGenerator.Tests.csproj - TUnit.Assertions.Tests/TUnit.Assertions.Tests.csproj - TUnit.Core.SourceGenerator.Tests/TUnit.Core.SourceGenerator.Tests.csproj - TUnit.Core.SourceGenerator/TUnit.Core.SourceGenerator.csproj - TUnit.Engine.SourceGenerator/TUnit.Engine.SourceGenerator.csproj - TUnit.Engine.Tests/TUnit.Engine.Tests.csproj - TUnit.Example.Asp.Net.TestProject/TUnit.Example.Asp.Net.TestProject.csproj - TUnit.Example.Asp.Net/TUnit.Example.Asp.Net.csproj - TUnit.Example.Asp.Net/TUnit.Example.Asp.Net.csproj - TUnit.Pipeline/TUnit.Pipeline.csproj - TUnit.PublicAPI/TUnit.PublicAPI.csproj - TUnit.RpcTests/TUnit.RpcTests.csproj - TUnit.Templates.Tests/TUnit.Templates.Tests.csproj - TUnit.Templates/content/TUnit.AspNet.FSharp/TestProject/TestProject.fsproj - TUnit.Templates/content/TUnit.AspNet.FSharp/WebApp/WebApp.fsproj - TUnit.Templates/content/TUnit.AspNet.FSharp/WebApp/WebApp.fsproj - TUnit.Templates/content/TUnit.AspNet/TestProject/TestProject.csproj - TUnit.Templates/content/TUnit.AspNet/WebApp/WebApp.csproj - TUnit.Templates/content/TUnit.AspNet/WebApp/WebApp.csproj - TUnit.Templates/content/TUnit.AspNet/WebApp/WebApp.csproj - TUnit.Templates/content/TUnit.Aspire.Starter/ExampleNamespace.ApiService/ExampleNamespace.ApiService.csproj - TUnit.Templates/content/TUnit.Aspire.Starter/ExampleNamespace.ApiService/ExampleNamespace.ApiService.csproj - TUnit.Templates/content/TUnit.Aspire.Starter/ExampleNamespace.AppHost/ExampleNamespace.AppHost.csproj - TUnit.Templates/content/TUnit.Aspire.Starter/ExampleNamespace.AppHost/ExampleNamespace.AppHost.csproj - TUnit.Templates/content/TUnit.Aspire.Starter/ExampleNamespace.TestProject/ExampleNamespace.TestProject.csproj - TUnit.Templates/content/TUnit.Aspire.Starter/ExampleNamespace.WebApp/ExampleNamespace.WebApp.csproj - TUnit.Templates/content/TUnit.Aspire.Starter/ExampleNamespace.WebApp/ExampleNamespace.WebApp.csproj - TUnit.Templates/content/TUnit.Aspire.Test/ExampleNamespace.csproj - TUnit.Templates/content/TUnit.FSharp/TestProject.fsproj - TUnit.Templates/content/TUnit.Playwright/TestProject.csproj - TUnit.Templates/content/TUnit.VB/TestProject.vbproj - TUnit.Templates/content/TUnit/TestProject.csproj - TUnit.TestProject.FSharp/TUnit.TestProject.FSharp.fsproj - TUnit.TestProject.VB.NET/TUnit.TestProject.VB.NET.vbproj - TUnit.TestProject/TUnit.TestProject.csproj - TUnit.UnitTests/TUnit.UnitTests.csproj - - - - - - - - - - - { - "lastFilter": { - "state": "OPEN", - "assignee": "thomhurst" - } -} - - - - { - "selectedUrlAndAccountId": { - "url": "https://github.com/thomhurst/TUnit.git", - "accountId": "dcaa655f-110f-4e75-a194-16234e7a7ff7" - } -} - - - - - - - - - - - - - - - - - { - "customColor": "", - "associatedIndex": 3 -} - - - - - - - - 1759513818191 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file From 71c227bce68ff3db71e2b0a0770f505e7ec6b789 Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Sun, 5 Oct 2025 15:56:14 +0100 Subject: [PATCH 14/14] fix: enhance AOT compatibility by adding DynamicallyAccessedMembers attributes to Type property --- TUnit.Core/Models/TestModels/ParameterMetadata.cs | 7 +++++++ ....Core_Library_Has_No_API_Changes.DotNet8_0.verified.txt | 1 + ....Core_Library_Has_No_API_Changes.DotNet9_0.verified.txt | 1 + 3 files changed, 9 insertions(+) diff --git a/TUnit.Core/Models/TestModels/ParameterMetadata.cs b/TUnit.Core/Models/TestModels/ParameterMetadata.cs index cd2a81a843..790c84ef89 100644 --- a/TUnit.Core/Models/TestModels/ParameterMetadata.cs +++ b/TUnit.Core/Models/TestModels/ParameterMetadata.cs @@ -19,6 +19,13 @@ public record ParameterMetadata([DynamicallyAccessedMembers(DynamicallyAccessedM | DynamicallyAccessedMemberTypes.NonPublicMethods | DynamicallyAccessedMemberTypes.PublicProperties)] Type Type) : MemberMetadata { + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors + | DynamicallyAccessedMemberTypes.NonPublicConstructors + | DynamicallyAccessedMemberTypes.PublicMethods + | DynamicallyAccessedMemberTypes.NonPublicMethods + | DynamicallyAccessedMemberTypes.PublicProperties)] + public override Type Type { get; init; } = Type; + public required TypeReference TypeReference { get; init; } public required ParameterInfo ReflectionInfo { get; set; } public bool IsParams => CachedIsParams ?? ReflectionInfo.IsDefined(typeof(ParamArrayAttribute), false); diff --git a/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet8_0.verified.txt b/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet8_0.verified.txt index ecea92f996..9309930a6b 100644 --- a/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet8_0.verified.txt +++ b/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet8_0.verified.txt @@ -1046,6 +1046,7 @@ namespace public bool IsParams { get; } public int Position { get; init; } public required .ParameterInfo ReflectionInfo { get; set; } + [.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..NonPublicConstructors | ..PublicMethods | ..NonPublicMethods | ..PublicProperties)] public override Type { get; init; } public required .TypeReference TypeReference { get; init; } } diff --git a/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet9_0.verified.txt b/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet9_0.verified.txt index 2eea47cd9b..5c7f7cea65 100644 --- a/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet9_0.verified.txt +++ b/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet9_0.verified.txt @@ -1046,6 +1046,7 @@ namespace public bool IsParams { get; } public int Position { get; init; } public required .ParameterInfo ReflectionInfo { get; set; } + [.(..None | ..PublicParameterlessConstructor | ..PublicConstructors | ..NonPublicConstructors | ..PublicMethods | ..NonPublicMethods | ..PublicProperties)] public override Type { get; init; } public required .TypeReference TypeReference { get; init; } }