Make AOT-incompatible code paths a no-op at runtime in MTP/Native AOT mode#8688
Open
Evangelink wants to merge 4 commits into
Open
Make AOT-incompatible code paths a no-op at runtime in MTP/Native AOT mode#8688Evangelink wants to merge 4 commits into
Evangelink wants to merge 4 commits into
Conversation
… mode
This change introduces two targeted improvements that reduce the trim/AOT
warning surface for the MSTest adapter when consumers enable
`PublishTrimmed=true` or `PublishAot=true` and pull MSTest in via MTP.
1. Centralize `Assembly.Location` handling in a new internal
`AssemblyFileLocator` helper. Previously, every call site that needed
the path or directory of an on-disk assembly carried its own
`#pragma warning disable IL3000` (or relied on an IL3000 attribute
suppression) and re-implemented the single-file/Native AOT fallback to
`AppContext.BaseDirectory` or the assembly simple name. The helper
gives one place to suppress IL3000 with a meaningful justification and
one place to maintain the fallback logic. Updated call sites:
- `TestSourceHost.SetContext` (WIN_UI branch),
- `TestSourceHost.GetAppBaseAsPerPlatform` (NETFRAMEWORK),
- `TestSourceHost.GetResolutionPaths` (NET, !WINDOWS_UWP and NETFRAMEWORK),
- `DeploymentUtilityBase.Deploy` (filtering the adapter assembly out
of the deployment loop).
2. Skip the AssemblyResolver registration and `DataSerializationHelper`
work at runtime in Native AOT. `RuntimeFeature.IsDynamicCodeSupported`
is the established AOT-detection signal in this codebase (already used by
`TestApplication` and `AppInsightsTelemetryProviderExtensions`). When
it is `false`:
- `TestSourceHost.SetupHost` no longer constructs `AssemblyResolver`
(its `AssemblyLoadContext.Resolving` hook can never fire under NAOT).
This also lets the trimmer drop `GetResolutionPaths` and the resolver
class from the published binary.
- `DataSerializationHelper.Serialize` / `Deserialize` throw a
descriptive `NotSupportedException` instead of attempting
`DataContractJsonSerializer`-based serialization (which requires
dynamic code). In MTP mode the in-process `TestMethod.ActualData` is
used for parameterized arguments and these methods are not reached at
runtime; the throw is a safety net plus a trimmer hint.
The trimmer treats `RuntimeFeature.IsDynamicCodeSupported` as a constant
`false` substitution during NAOT publish, so the gated branches (and the
unreferenced `AssemblyResolver` / DataContract code paths) are statically
removed from the published binary.
This PR is independent of microsoft#8686 (which is the pragma-to-attribute
conversion for the same warnings) but the two changes overlap on
`TestSourceHost.cs` and `DataSerializationHelper.cs`; expect a merge
conflict between them.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Reduces the trim/Native AOT warning surface (and runtime reachability) of AOT-incompatible adapter code paths when MSTest is used via Microsoft.Testing.Platform (MTP), by centralizing Assembly.Location handling and gating unsupported behaviors at runtime.
Changes:
- Added
AssemblyFileLocatorto centralizeAssembly.Locationaccess (single-file/NAOT-safe fallbacks + IL3000 suppression). - Updated
TestSourceHostandDeploymentUtilityBaseto useAssemblyFileLocatorinstead of directAssembly.Locationaccess / IL3000 pragmas. - Gated
AssemblyResolvercreation andDataSerializationHelper.Serialize/DeserializeonRuntimeFeature.IsDynamicCodeSupported, turning AOT-incompatible paths into no-ops/throws in AOT scenarios.
Show a summary per file
| File | Description |
|---|---|
| src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentUtilityBase.cs | Uses AssemblyFileLocator to avoid direct Assembly.Location access in deployment filtering logic. |
| src/Adapter/MSTestAdapter.PlatformServices/Services/TestSourceHost.cs | Skips resolver setup in AOT scenarios; replaces Assembly.Location usage with centralized helper/fallbacks. |
| src/Adapter/MSTestAdapter.PlatformServices/Helpers/DataSerializationHelper.cs | Throws NotSupportedException when dynamic code isn’t supported (AOT) to prevent DataContract-based serialization usage. |
| src/Adapter/MSTestAdapter.PlatformServices/Helpers/AssemblyFileLocator.cs | New helper encapsulating Assembly.Location access and AOT/single-file fallbacks with IL3000 suppressions. |
Copilot's findings
- Files reviewed: 4/4 changed files
- Comments generated: 3
…e AOT" RuntimeFeature.IsDynamicCodeSupported is false for any AOT-like runtime without a JIT or interpreter (Native AOT, Mono iOS AOT, Blazor WebAssembly AOT, …), not exclusively Native AOT. Update doc comments, exception messages, and the in-source rationale in TestSourceHost to describe the actual condition being checked. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…n netfx/uap `RuntimeFeature.IsDynamicCodeSupported` is .NET Core/5+ only, so the `<see cref=...>` references in the XML docs fail to resolve when the project builds for net462 and uap10.0.16299. Switch to `<c>...</c>` literals to keep the documentation readable on all target frameworks without requiring conditional compilation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Both comments referenced 'source gen mode', but the actual code paths check for Assembly.Location being empty (single-file / Native AOT scenarios). Reworded to describe the real behavior to avoid confusing future maintainers. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Two targeted runtime improvements that reduce the trim/AOT warning surface for
MSTest.TestAdapterwhen consumers enable trimming or Native AOT through Microsoft.Testing.Platform (MTP):1.
AssemblyFileLocator— single place to handleAssembly.LocationNew
internal statichelper inMSTestAdapter.PlatformServices/Helpers/AssemblyFileLocator.cswith three members:TryGetLocation(Assembly) -> string?— returnsnullwhenAssembly.Locationis empty (single-file / Native AOT case).GetDirectoryOrAppContextBase(Assembly)— falls back toAppContext.BaseDirectory.GetFileNameOrSimpleName(Assembly)— falls back to<simpleName>.dll.Each member carries a single
[UnconditionalSuppressMessage("SingleFile", "IL3000")]with a meaningful justification. This removes the#pragma warning disable IL3000blocks scattered across call sites:TestSourceHost.SetContext(WIN_UIbranch)TestSourceHost.GetAppBaseAsPerPlatform(NETFRAMEWORK)TestSourceHost.GetResolutionPaths(bothNET && !WINDOWS_UWPandNETFRAMEWORK)DeploymentUtilityBase.Deploy2. Skip
AssemblyResolverandDataSerializationHelperwork in Native AOTGate the relevant code on
RuntimeFeature.IsDynamicCodeSupported— the established AOT-detection signal already used byTestApplicationandAppInsightsTelemetryProviderExtensionsin this codebase:TestSourceHost.SetupHost(NET && !WINDOWS_UWP) no longer constructsAssemblyResolverwhen running under NAOT. ItsAssemblyLoadContext.Resolvinghook can never fire in NAOT anyway. The trimmer can now dropGetResolutionPathsand the whole resolver class.DataSerializationHelper.Serialize/DeserializethrowNotSupportedExceptionunder NAOT with a clear message pointing users to MTP mode (whereTestMethod.ActualDatais used in-process). In practice these methods are not reached in MTP at runtime — discovery setsActualDatadirectly. The throw is a safety net plus a trimmer hint.The trimmer treats
RuntimeFeature.IsDynamicCodeSupportedas a constantfalsesubstitution during NAOT publish, so the gated branches and their transitive dependencies are statically removed from the published binary.Why
PR #8586 enables an integration test that publishes MSTest with
PublishAot=true+TreatWarningsAsErrors=true. The pragma-to-attribute PR (#8686) silences the warnings; this PR goes further by making the code actually safe / no-op at runtime in NAOT, so consumers using MSTest in MTP-only mode get a smaller and more correct published binary.Independence from #8686
This PR branches from
mainand is independent of #8686. The two PRs touchTestSourceHost.csandDataSerializationHelper.csin different ways, so expect merge conflicts; whichever lands first will need the other rebased.Validation
dotnet build src/Adapter/MSTestAdapter.PlatformServices/MSTestAdapter.PlatformServices.csproj -c Release -f net8.0— 0 warnings / 0 errors.dotnet build ... -f net462— 0 warnings / 0 errors (the new NAOT guards are#if NET-fenced so netfx is unaffected).The same acceptance test added in #8686 (
Publish_WithTestAdapter_DoesNotSurfaceWarningsFromSuppressedSources) would benefit from these changes by removing additional warnings from theTestSourceHostandDeploymentUtilityBasesurfaces, and by letting the trimmer drop theAssemblyResolverentirely.