diff --git a/src/Adapter/MSTestAdapter.PlatformServices/AssemblyResolver.cs b/src/Adapter/MSTestAdapter.PlatformServices/AssemblyResolver.cs
index 345e8a2a27..7f92518fde 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/AssemblyResolver.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/AssemblyResolver.cs
@@ -307,15 +307,13 @@ private static
///
/// The path of the assembly.
/// The loaded .
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:Members attributed with RequiresUnreferencedCode may break when trimming", Justification = "AssemblyResolver is part of the legacy reflection-mode loader and is not used in source-generator / Native AOT execution mode.")]
#if NETFRAMEWORK
protected virtual
#else
private static
#endif
- // This whole class is not used in source generator mode.
-#pragma warning disable IL2026 // Members attributed with RequiresUnreferencedCode may break when trimming
Assembly LoadAssemblyFrom(string path) => Assembly.LoadFrom(path);
-#pragma warning restore IL2026 // Members attributed with RequiresUnreferencedCode may break when trimming
#if NETFRAMEWORK
///
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Extensions/MethodInfoExtensions.cs b/src/Adapter/MSTestAdapter.PlatformServices/Extensions/MethodInfoExtensions.cs
index 99ebd885cc..aba95115cf 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Extensions/MethodInfoExtensions.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Extensions/MethodInfoExtensions.cs
@@ -240,6 +240,8 @@ private static void InferGenerics(Type parameterType, Type argumentType, List<(T
//
// [DataRow(0, "Hello")]
// public void TestMethod(T2 p0, T1, p1) { }
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2060:Call to 'System.Reflection.MethodInfo.MakeGenericMethod' can not be statically analyzed.", Justification = "Generic test methods with substituted type arguments are part of MSTest's reflection-mode adapter. Native AOT support relies on MSTest source-generated metadata, not on this code path.")]
+ [UnconditionalSuppressMessage("Aot", "IL3050:Avoid calling members annotated with 'RequiresDynamicCodeAttribute' when publishing as Native AOT", Justification = "Generic test methods with substituted type arguments are part of MSTest's reflection-mode adapter. Native AOT support relies on MSTest source-generated metadata, not on this code path.")]
private static MethodInfo ConstructGenericMethod(MethodInfo methodInfo, object?[]? arguments)
{
DebugEx.Assert(methodInfo.IsGenericMethod, "ConstructGenericMethod should only be called for a generic method.");
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Helpers/DataSerializationHelper.cs b/src/Adapter/MSTestAdapter.PlatformServices/Helpers/DataSerializationHelper.cs
index c7c980e9fd..b848f88591 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Helpers/DataSerializationHelper.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Helpers/DataSerializationHelper.cs
@@ -12,6 +12,11 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers;
internal static class DataSerializationHelper
{
+ private const string DataContractSerializationJustification =
+ "Data contract serialization is used for cross-process VSTest payloads. " +
+ "This should be safe as long as our generator mentions getting fields / properties of the target type. " +
+ "https://github.com/dotnet/runtime/issues/71350#issuecomment-1168140551";
+
private static readonly ConcurrentDictionary SerializerCache = new();
private static readonly DataContractJsonSerializerSettings SerializerSettings = new()
{
@@ -30,6 +35,8 @@ internal static class DataSerializationHelper
///
/// Data array to serialize.
/// Serialized array.
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:Members attributed with RequiresUnreferencedCode may break when trimming", Justification = DataContractSerializationJustification)]
+ [UnconditionalSuppressMessage("Aot", "IL3050:Avoid calling members annotated with 'RequiresDynamicCodeAttribute' when publishing as Native AOT", Justification = DataContractSerializationJustification)]
public static string?[]? Serialize(object?[]? data)
{
if (data == null)
@@ -61,14 +68,7 @@ internal static class DataSerializationHelper
#endif
using var memoryStream = new MemoryStream();
- // This should be safe as long as our generator mentions
- // getting fields / properties of the target type. https://github.com/dotnet/runtime/issues/71350#issuecomment-1168140551
- // Not the best solution, maybe we can replace this with System.Text.Json, but the we need one generator calling the other.
-#pragma warning disable IL3050 // IL3050: Avoid calling members annotated with 'RequiresDynamicCodeAttribute' when publishing as Native AOT
-#pragma warning disable IL2026 // IL2026: Members attributed with RequiresUnreferencedCode may break when trimming
serializer.WriteObject(memoryStream, data[i]);
-#pragma warning restore IL3050 // IL3050: Avoid calling members annotated with 'RequiresDynamicCodeAttribute' when publishing as Native AOT
-#pragma warning restore IL2026 // IL2026: Members attributed with RequiresUnreferencedCode may break when trimming
byte[] serializerData = memoryStream.ToArray();
serializedData[dataIndex] = Encoding.UTF8.GetString(serializerData, 0, serializerData.Length);
@@ -82,6 +82,8 @@ internal static class DataSerializationHelper
///
/// Serialized data array to deserialize.
/// Deserialized array.
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:Members attributed with RequiresUnreferencedCode may break when trimming", Justification = DataContractSerializationJustification)]
+ [UnconditionalSuppressMessage("Aot", "IL3050:Avoid calling members annotated with 'RequiresDynamicCodeAttribute' when publishing as Native AOT", Justification = DataContractSerializationJustification)]
public static object?[]? Deserialize(string?[]? serializedData)
{
if (serializedData == null || serializedData.Length % 2 != 0)
@@ -111,14 +113,7 @@ internal static class DataSerializationHelper
byte[] serializedDataBytes = Encoding.UTF8.GetBytes(serializedValue);
using var memoryStream = new MemoryStream(serializedDataBytes);
- // This should be safe as long as our generator mentions
- // getting fields / properties of the target type. https://github.com/dotnet/runtime/issues/71350#issuecomment-1168140551
- // Not the best solution, maybe we can replace this with System.Text.Json, but the we need one generator calling the other.
-#pragma warning disable IL3050 // IL3050: Avoid calling members annotated with 'RequiresDynamicCodeAttribute' when publishing as Native AOT
-#pragma warning disable IL2026 // IL2026: Members attributed with RequiresUnreferencedCode may break when trimming
data[i] = serializer.ReadObject(memoryStream);
-#pragma warning restore IL3050 // IL3050: Avoid calling members annotated with 'RequiresDynamicCodeAttribute' when publishing as Native AOT
-#pragma warning restore IL2026 // IL2026: Members attributed with RequiresUnreferencedCode may break when trimming
// For some reason, we don't get SerializationSurrogateProvider.GetDeserializedObject to be called by .NET runtime.
// So we manually call it.
data[i] = SerializationSurrogateProvider.GetDeserializedObject(data[i]!);
@@ -128,26 +123,20 @@ internal static class DataSerializationHelper
}
private static DataContractJsonSerializer GetSerializer(string assemblyQualifiedName)
- => SerializerCache.GetOrAdd(
- assemblyQualifiedName,
- // This should be safe as long as our generator mentions
- // getting fields / properties of the target type. https://github.com/dotnet/runtime/issues/71350#issuecomment-1168140551
- // Not the best solution, maybe we can replace this with System.Text.Json, but the we need one generator calling the other.
-#pragma warning disable IL3050 // IL3050: Avoid calling members annotated with 'RequiresDynamicCodeAttribute' when publishing as Native AOT
-#pragma warning disable IL2026 // IL2026: Members attributed with RequiresUnreferencedCode may break when trimming
- _ => new DataContractJsonSerializer(PlatformServiceProvider.Instance.ReflectionOperations.GetType(assemblyQualifiedName) ?? typeof(object), SerializerSettings));
-#pragma warning restore IL3050 // IL3050: Avoid calling members annotated with 'RequiresDynamicCodeAttribute' when publishing as Native AOT
-#pragma warning restore IL2026 // IL2026: Members attributed with RequiresUnreferencedCode may break when trimming
+ => SerializerCache.GetOrAdd(assemblyQualifiedName, CreateSerializerForAssemblyQualifiedName);
private static DataContractJsonSerializer GetSerializer(Type type)
- => SerializerCache.GetOrAdd(
- type.AssemblyQualifiedName!,
- // This should be safe as long as our generator mentions
- // getting fields / properties of the target type. https://github.com/dotnet/runtime/issues/71350#issuecomment-1168140551
- // Not the best solution, maybe we can replace this with System.Text.Json, but the we need one generator calling the other.
-#pragma warning disable IL3050 // IL3050: Avoid calling members annotated with 'RequiresDynamicCodeAttribute' when publishing as Native AOT
-#pragma warning disable IL2026 // IL2026: Members attributed with RequiresUnreferencedCode may break when trimming
- _ => new DataContractJsonSerializer(type, SerializerSettings));
+ => SerializerCache.GetOrAdd(type.AssemblyQualifiedName!, _ => CreateSerializerForType(type));
+
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:Members attributed with RequiresUnreferencedCode may break when trimming", Justification = DataContractSerializationJustification)]
+ [UnconditionalSuppressMessage("Aot", "IL3050:Avoid calling members annotated with 'RequiresDynamicCodeAttribute' when publishing as Native AOT", Justification = DataContractSerializationJustification)]
+ private static DataContractJsonSerializer CreateSerializerForAssemblyQualifiedName(string assemblyQualifiedName)
+ => new(PlatformServiceProvider.Instance.ReflectionOperations.GetType(assemblyQualifiedName) ?? typeof(object), SerializerSettings);
+
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:Members attributed with RequiresUnreferencedCode may break when trimming", Justification = DataContractSerializationJustification)]
+ [UnconditionalSuppressMessage("Aot", "IL3050:Avoid calling members annotated with 'RequiresDynamicCodeAttribute' when publishing as Native AOT", Justification = DataContractSerializationJustification)]
+ private static DataContractJsonSerializer CreateSerializerForType(Type type)
+ => new(type, SerializerSettings);
[DataContract]
private sealed class SurrogatedDateOnly
@@ -235,6 +224,4 @@ public Type GetSurrogateType(Type type)
return type;
}
}
-#pragma warning restore IL3050 // IL3050: Avoid calling members annotated with 'RequiresDynamicCodeAttribute' when publishing as Native AOT
-#pragma warning restore IL2026 // IL2026: Members attributed with RequiresUnreferencedCode may break when trimming
}
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Helpers/ManagedNameHelper.cs b/src/Adapter/MSTestAdapter.PlatformServices/Helpers/ManagedNameHelper.cs
index e60eb80e27..8c871c4c7c 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Helpers/ManagedNameHelper.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Helpers/ManagedNameHelper.cs
@@ -112,6 +112,7 @@ public static void GetManagedNameAndHierarchy(MethodBase method, out string mana
/// More information about and can be found in
/// the RFC.
///
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:Members attributed with RequiresUnreferencedCode may break when trimming", Justification = "Reflection-based name resolution is used by the legacy VSTest bridge for managed-name lookup. Native AOT support relies on MSTest source-generated reflection metadata, not on this code path.")]
public static MethodInfo GetMethod(Assembly assembly, string managedTypeName, string managedMethodName)
{
Type type = assembly.GetType(managedTypeName, throwOnError: false, ignoreCase: false)
@@ -128,6 +129,7 @@ public static MethodInfo GetMethod(Assembly assembly, string managedTypeName, st
return method ?? throw new InvalidManagedNameException();
}
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:'this' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method.", Justification = "Reflection-based name resolution is used by the legacy VSTest bridge for managed-name lookup. Native AOT support relies on MSTest source-generated reflection metadata, not on this code path.")]
private static MethodInfo? FindMethod(Type type, string methodName, int methodArity, string[]? parameterTypes)
{
bool Filter(MemberInfo mbr, object? param)
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/ReflectionOperations.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/ReflectionOperations.cs
index 4cb8ce6729..c9745dd68f 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Services/ReflectionOperations.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/ReflectionOperations.cs
@@ -48,47 +48,50 @@ internal sealed class ReflectionOperations : MarshalByRefObject, IReflectionOper
public object[] GetCustomAttributes(Assembly assembly, Type type)
=> assembly.GetCustomAttributes(type, inherit: true);
-#pragma warning disable IL2070 // this' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to 'target method'.
-#pragma warning disable IL2026 // Members attributed with RequiresUnreferencedCode may break when trimming
-#pragma warning disable IL2067 // 'target parameter' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to 'target method'.
-#pragma warning disable IL2057 // Unrecognized value passed to the typeName parameter of 'System.Type.GetType(String)'
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:'this' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method.", Justification = "Reflection-based discovery/execution is the MSTest reflection-mode adapter path. Native AOT support relies on MSTest source-generated reflection metadata, not on this code path.")]
public ConstructorInfo[] GetDeclaredConstructors(Type classType)
=> classType.GetConstructors(DeclaredOnlyLookup);
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:'this' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method.", Justification = "Reflection-based discovery/execution is the MSTest reflection-mode adapter path. Native AOT support relies on MSTest source-generated reflection metadata, not on this code path.")]
public MethodInfo[] GetDeclaredMethods(Type classType)
=> classType.GetMethods(DeclaredOnlyLookup);
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:'this' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method.", Justification = "Reflection-based discovery/execution is the MSTest reflection-mode adapter path. Native AOT support relies on MSTest source-generated reflection metadata, not on this code path.")]
public PropertyInfo[] GetDeclaredProperties(Type type)
=> type.GetProperties(DeclaredOnlyLookup);
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:Members attributed with RequiresUnreferencedCode may break when trimming", Justification = "Reflection-based discovery/execution is the MSTest reflection-mode adapter path. Native AOT support relies on MSTest source-generated reflection metadata, not on this code path.")]
public Type[] GetDefinedTypes(Assembly assembly)
=> assembly.GetTypes();
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:'this' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method.", Justification = "Reflection-based discovery/execution is the MSTest reflection-mode adapter path. Native AOT support relies on MSTest source-generated reflection metadata, not on this code path.")]
public MethodInfo[] GetRuntimeMethods(Type type)
=> type.GetMethods(Everything);
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:'this' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method.", Justification = "Reflection-based discovery/execution is the MSTest reflection-mode adapter path. Native AOT support relies on MSTest source-generated reflection metadata, not on this code path.")]
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2067:'target parameter' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method.", Justification = "Reflection-based discovery/execution is the MSTest reflection-mode adapter path. Native AOT support relies on MSTest source-generated reflection metadata, not on this code path.")]
public MethodInfo? GetRuntimeMethod(Type declaringType, string methodName, Type[] parameters, bool includeNonPublic)
=> includeNonPublic
? declaringType.GetMethod(methodName, Everything, null, parameters, null)
: declaringType.GetMethod(methodName, parameters);
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:'this' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method.", Justification = "Reflection-based discovery/execution is the MSTest reflection-mode adapter path. Native AOT support relies on MSTest source-generated reflection metadata, not on this code path.")]
public PropertyInfo? GetRuntimeProperty(Type classType, string testContextPropertyName, bool includeNonPublic)
=> includeNonPublic
? classType.GetProperty(testContextPropertyName, Everything)
: classType.GetProperty(testContextPropertyName);
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2057:Unrecognized value passed to the typeName parameter of 'System.Type.GetType(String)'.", Justification = "Reflection-based discovery/execution is the MSTest reflection-mode adapter path. Native AOT support relies on MSTest source-generated reflection metadata, not on this code path.")]
public Type? GetType(string typeName)
=> Type.GetType(typeName);
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:Members attributed with RequiresUnreferencedCode may break when trimming", Justification = "Reflection-based discovery/execution is the MSTest reflection-mode adapter path. Native AOT support relies on MSTest source-generated reflection metadata, not on this code path.")]
public Type? GetType(Assembly assembly, string typeName)
=> assembly.GetType(typeName);
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2067:'target parameter' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method.", Justification = "Reflection-based discovery/execution is the MSTest reflection-mode adapter path. Native AOT support relies on MSTest source-generated reflection metadata, not on this code path.")]
public object? CreateInstance(Type type, object?[] parameters)
=> Activator.CreateInstance(type, parameters);
-#pragma warning restore IL2070 // this' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to 'target method'.
-#pragma warning restore IL2026 // Members attributed with RequiresUnreferencedCode may break when trimming
-#pragma warning restore IL2067 // 'target parameter' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to 'target method'.
-#pragma warning restore IL2057 // Unrecognized value passed to the typeName parameter of 'System.Type.GetType(String)'
///
/// Checks to see if a member or type is decorated with the given attribute, or an attribute that derives from it. e.g. [MyTestClass] from [TestClass] will match if you look for [TestClass]. The inherit parameter does not impact this checking.
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/TestSourceHost.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/TestSourceHost.cs
index 0e8c0c8be6..60f818f82f 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Services/TestSourceHost.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/TestSourceHost.cs
@@ -350,6 +350,7 @@ internal string GetTargetFrameworkVersionString(string sourceFileName)
///
/// A list of path.
///
+ [UnconditionalSuppressMessage("SingleFile", "IL3000:Avoid accessing Assembly file path when publishing as a single file", Justification = "Assembly.Location is explicitly checked for empty before use; in single-file/Native AOT scenarios it returns empty and the affected blocks are skipped.")]
internal virtual List GetResolutionPaths(string sourceFileName, bool isPortableMode)
{
List resolutionPaths =
@@ -380,7 +381,6 @@ internal virtual List GetResolutionPaths(string sourceFileName, bool isP
// We check for the empty path, and in single file mode, or on source gen mode we don't allow
// loading dependencies than from the current folder, which is what the default loader handles by itself.
-#pragma warning disable IL3000 // Avoid accessing Assembly file path when publishing as a single file
if (!string.IsNullOrEmpty(typeof(TestSourceHost).Assembly.Location))
{
// Adding adapter folder to resolution paths
@@ -398,7 +398,6 @@ internal virtual List GetResolutionPaths(string sourceFileName, bool isP
resolutionPaths.Add(Path.GetDirectoryName(typeof(AssemblyHelper).Assembly.Location)!);
}
}
-#pragma warning restore IL3000 // Avoid accessing Assembly file path when publishing as a single file
return resolutionPaths;
}
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/TestMethodFilter.cs b/src/Adapter/MSTestAdapter.PlatformServices/TestMethodFilter.cs
index 33f554a96c..481220ad0c 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/TestMethodFilter.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/TestMethodFilter.cs
@@ -117,6 +117,7 @@ internal TestProperty PropertyProvider(string propertyName)
/// Discovery context.
/// The logger to log exception messages too.
/// Filter expression.
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2072:'target parameter' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method.", Justification = "GetTestCaseFilter is part of the VSTest discovery contract on the concrete DiscoveryContext type; the runtime guarantees the method exists on supported hosts.")]
private ITestCaseFilterExpression? GetTestCaseFilterFromDiscoveryContext(IDiscoveryContext context, IMessageLogger logger)
{
try
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentUtilityBase.cs b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentUtilityBase.cs
index f86755558b..dd6918a934 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentUtilityBase.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentUtilityBase.cs
@@ -136,6 +136,7 @@ public static string GetTestResultsDirectory(IRunContext? runContext) => !String
/// The deployment directory.
/// Root results directory.
/// Returns a list of deployment warnings.
+ [UnconditionalSuppressMessage("SingleFile", "IL3000:Avoid accessing Assembly file path when publishing as a single file", Justification = "Deployment is a reflection-mode/legacy adapter feature; in single-file/Native AOT scenarios Assembly.Location returns an empty string and the comparison falls through without error.")]
protected IEnumerable Deploy(IList deploymentItems, string testSourceHandler, string deploymentDirectory, string resultsDirectory)
{
Ensure.NotNullOrWhiteSpace(deploymentDirectory);
@@ -194,9 +195,7 @@ protected IEnumerable Deploy(IList deploymentItems, stri
// Ignore the test platform files.
string tempFile = Path.GetFileName(fileToDeploy);
// We throw when we run in source gen mode.
-#pragma warning disable IL3000 // Avoid accessing Assembly file path when publishing as a single file
string assemblyName = Path.GetFileName(GetType().Assembly.Location);
-#pragma warning restore IL3000 // Avoid accessing Assembly file path when publishing as a single file
if (tempFile.Equals(assemblyName, StringComparison.OrdinalIgnoreCase))
{
continue;
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/SynchronizedSingleSessionVSTestAndTestAnywhereAdapter.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/SynchronizedSingleSessionVSTestAndTestAnywhereAdapter.cs
index e2d903229e..977788a3d8 100644
--- a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/SynchronizedSingleSessionVSTestAndTestAnywhereAdapter.cs
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/SynchronizedSingleSessionVSTestAndTestAnywhereAdapter.cs
@@ -149,9 +149,7 @@ protected sealed override Task ExecuteRequestAsync(TestExecutionRequest request,
CancellationToken cancellationToken)
=> ExecuteRequestWithRequestCountGuardAsync(async () =>
{
-#pragma warning disable IL3000 // Avoid accessing Assembly file path when publishing as a single file
string[] testAssemblyPaths = [.. _getTestAssemblies().Select(GetAssemblyPath)];
-#pragma warning restore IL3000 // Avoid accessing Assembly file path when publishing as a single file
switch (request)
{
case DiscoverTestExecutionRequest discoverRequest:
@@ -184,12 +182,10 @@ public void Dispose()
/// returns an empty string (e.g. on Android CoreCLR
/// where assemblies are memory-mapped).
///
-#pragma warning disable IL3000 // Avoid accessing Assembly file path when publishing as a single file
+ [UnconditionalSuppressMessage("SingleFile", "IL3000:Avoid accessing Assembly file path when publishing as a single file", Justification = "Empty Assembly.Location is handled explicitly by falling back to the assembly simple name; see method body.")]
internal static string GetAssemblyPath(Assembly assembly)
{
-#pragma warning disable IL3000 // Avoid accessing Assembly file path when publishing as a single file
string location = assembly.Location;
-#pragma warning restore IL3000 // Avoid accessing Assembly file path when publishing as a single file
if (!string.IsNullOrEmpty(location))
{
return location;
@@ -204,7 +200,6 @@ internal static string GetAssemblyPath(Assembly assembly)
return name + ".dll";
}
-#pragma warning restore IL3000 // Avoid accessing Assembly file path when publishing as a single file
private async Task ExecuteRequestWithRequestCountGuardAsync(Func asyncFunc)
{
diff --git a/src/TestFramework/TestFramework/Internal/ReflectionTestMethodInfo.cs b/src/TestFramework/TestFramework/Internal/ReflectionTestMethodInfo.cs
index 6eee7ba64e..8d2ffd3632 100644
--- a/src/TestFramework/TestFramework/Internal/ReflectionTestMethodInfo.cs
+++ b/src/TestFramework/TestFramework/Internal/ReflectionTestMethodInfo.cs
@@ -47,6 +47,12 @@ public ReflectionTestMethodInfo(MethodInfo methodInfo, string? displayName)
public override bool IsDefined(Type attributeType, bool inherit) => _methodInfo.IsDefined(attributeType, inherit);
+#if NET5_0_OR_GREATER
+ [RequiresUnreferencedCode("The native code for the generic method instantiation might not be available at runtime.")]
+#endif
+#if NET7_0_OR_GREATER
+ [RequiresDynamicCode("The native code for the generic method instantiation might not be available at runtime.")]
+#endif
public override MethodInfo MakeGenericMethod(params Type[] typeArguments) => new ReflectionTestMethodInfo(_methodInfo.MakeGenericMethod(typeArguments), DisplayName);
public override Type[] GetGenericArguments() => _methodInfo.GetGenericArguments();
diff --git a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/TrimTests.cs b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/TrimTests.cs
index 7fe25eae29..cfd469dded 100644
--- a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/TrimTests.cs
+++ b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/TrimTests.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using Microsoft.Testing.Platform.Acceptance.IntegrationTests;
+using Microsoft.Testing.Platform.Acceptance.IntegrationTests.Helpers;
namespace MSTest.Acceptance.IntegrationTests;
@@ -61,5 +62,109 @@ await DotnetCli.RunAsync(
cancellationToken: TestContext.CancellationToken);
}
+ // Source code for a project that references MSTest.TestAdapter (the reflection-mode adapter)
+ // and runs trim analysis with TrimmerRootAssembly to scan the full surface of the assemblies
+ // we own. Used by Publish_WithTestAdapter_DoesNotSurfaceWarningsFromSuppressedSources.
+ //
+ // Note: We do not enable TreatWarningsAsErrors here because the reflection-mode adapter still
+ // depends on the vstest Microsoft.TestPlatform.ObjectModel submodule and on
+ // System.Private.DataContractSerialization internals, both of which emit trim warnings that
+ // are outside this repo's control. The test instead asserts that specific source files we
+ // suppressed in this repo no longer appear in publish output.
+ private const string TrimAnalysisWithTestAdapterSourceCode = """
+#file MSTestTrimAnalysisWithTestAdapter.csproj
+
+
+ $TargetFramework$
+ Exe
+ true
+ true
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#file UnitTest1.cs
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace MyTests;
+
+[TestClass]
+public class UnitTest1
+{
+ [TestMethod]
+ public void TestMethod1()
+ {
+ }
+}
+""";
+
+ [TestMethod]
+ [DynamicData(nameof(TargetFrameworks.NetForDynamicData), typeof(TargetFrameworks))]
+ public async Task Publish_WithTestAdapter_DoesNotSurfaceWarningsFromSuppressedSources(string tfm)
+ {
+ // Regression test for the suppressions added in https://github.com/microsoft/testfx/pull/8686.
+ //
+ // Before that PR, the listed source files emitted trim warnings (IL20xx/IL30xx) when a
+ // downstream consumer published a trimmed project that referenced MSTest.TestAdapter.
+ // The original C# `#pragma warning disable ILxxxx` directives in those files only
+ // silenced the compile-time warning during MSTest's own build; they did NOT propagate to
+ // the IL, so the linker still emitted the warnings at the consumer's publish time.
+ //
+ // After converting those pragmas to [UnconditionalSuppressMessage] / [RequiresUnreferencedCode]
+ // / [RequiresDynamicCode] attributes, the suppressions are honored by the IL trimmer and
+ // these source-file references should no longer appear in publish output.
+ using TestAsset generator = await TestAsset.GenerateAssetAsync(
+ $"MSTestTrimAnalysisWithTestAdapter_{tfm}",
+ TrimAnalysisWithTestAdapterSourceCode
+ .PatchCodeWithReplace("$MicrosoftTestingPlatformVersion$", MicrosoftTestingPlatformVersion)
+ .PatchCodeWithReplace("$MSTestVersion$", MSTestVersion)
+ .PatchCodeWithReplace("$TargetFramework$", tfm),
+ addPublicFeeds: true);
+
+ // Do NOT pass warnAsError: true here. The reflection-mode adapter still depends on the
+ // vstest Microsoft.TestPlatform.ObjectModel submodule and on System.Private.DataContractSerialization
+ // internals, both of which emit trim warnings that are outside this repo's control. Promoting them
+ // to errors would fail the publish with NETSDK1144 before we get a chance to inspect the warning list.
+ DotnetMuxerResult result = await DotnetCli.RunAsync(
+ $"publish {generator.TargetAssetPath} -r {RID} -f {tfm}",
+ warnAsError: false,
+ cancellationToken: TestContext.CancellationToken);
+
+ // Files in MSTest's own source whose trim warnings are suppressed by this PR.
+ // The trimmer includes source file paths in its IL2xxx/IL3xxx warnings, so the absence
+ // of these file names in publish output is evidence that the suppression attributes work.
+ string[] suppressedSourceFiles =
+ [
+ "TestSourceHost.cs",
+ "DeploymentUtilityBase.cs",
+ "ReflectionOperations.cs",
+ "AssemblyResolver.cs",
+ "DataSerializationHelper.cs",
+ "ManagedNameHelper.cs",
+ "MethodInfoExtensions.cs",
+ "TestMethodFilter.cs",
+ "SynchronizedSingleSessionVSTestAndTestAnywhereAdapter.cs",
+ "ReflectionTestMethodInfo.cs",
+ ];
+
+ foreach (string fileName in suppressedSourceFiles)
+ {
+ result.AssertOutputDoesNotContain(fileName);
+ }
+ }
+
public TestContext TestContext { get; set; }
}