/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/Test/Core/TargetFrameworkUtil.cs
447 строк
20 KB
Jan Jones
Unsafe evolution: explicit layout (#83974)
16 июн 2026, 21:49
Не верифицирован
16 июн 2026, 21:49
e5b5cce
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. #nullable disable using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.Linq; using System.IO; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Test.Utilities; using Basic.Reference.Assemblies; using Microsoft.CodeAnalysis.CodeGen; using System.Reflection; using System.Collections.Concurrent; using static TestReferences; namespace Roslyn.Test.Utilities { public enum TargetFramework { /// <summary> /// Explicit pick a target framework that has no references /// </summary> Empty, NetStandard20, /// <summary> /// The latest .NET Core target framework /// </summary> NetCoreApp, /// <summary> /// The latest .NET Framework /// </summary> NetFramework, /// <summary> /// This will be <see cref="NetCoreApp" /> when running on .NET Core and <see cref="NetFramework"/> /// when running on .NET Framework. /// </summary> NetLatest, // Eventually these will be deleted and replaced with NetStandard20. Short term this creates the "standard" // API set across desktop and coreclr. It's also helpful because there are no null annotations hence error // messages have consistent signatures across .NET Core / Framework tests. Standard, StandardAndCSharp, StandardAndVBRuntime, /// <summary> /// Compat framework for the default set of references many vb compilations get. /// </summary> DefaultVb, /// <summary> /// Used for building tests against WinRT scenarios /// </summary> WinRT, // The flavors of mscorlib we support + extending them with LINQ and dynamic. Mscorlib40, Mscorlib40Extended, Mscorlib40AndSystemCore, Mscorlib40AndVBRuntime, Mscorlib46, Mscorlib46Extended, Mscorlib461, Mscorlib461Extended, Mscorlib461AndCSharp, Mscorlib461AndVBRuntime, /// <summary> /// Minimal set of required types (<see cref="NetFx.Minimal.mincorlib"/>). /// </summary> Minimal, /// <summary> /// Minimal set of required types and Task implementation (<see cref="NetFx.Minimal.minasync"/>). /// </summary> MinimalAsync, Net50, Net60, Net70, Net80, Net90, Net100, Net110, } /// <summary> /// This type holds the reference information for the latest .NET Core platform. Tests /// targeting .NET core specifically should use the references here. As the platform moves /// forward these will be moved to target the latest .NET Core supported by the compiler /// </summary> public static class NetCoreApp { public static ImmutableArray<Net70.ReferenceInfo> AllReferenceInfos { get; } = ImmutableArray.CreateRange(Net70.ReferenceInfos.All); public static ImmutableArray<MetadataReference> References { get; } = ImmutableArray.CreateRange<MetadataReference>(Net70.References.All); public static PortableExecutableReference netstandard { get; } = Net70.References.netstandard; public static PortableExecutableReference mscorlib { get; } = Net70.References.mscorlib; public static PortableExecutableReference SystemRuntime { get; } = Net70.References.SystemRuntime; } /// <summary> /// This type holds the reference information for the latest .NET Framework. These should be /// used by tests that are specific to .NET Framework. This moves forward much more rarely but /// when it does move forward these will change /// </summary> public static class NetFramework { private static ImmutableArray<MetadataReference> s_references; /// <summary> /// This is the full set of references provided by default on the .NET Framework TFM /// </summary> /// <remarks> /// Need to special case tuples until we move to net472 /// </remarks> public static ImmutableArray<MetadataReference> References { get { if (s_references.IsDefault) { s_references = [.. Net461.References.All, Net461.ExtraReferences.SystemValueTuple]; } return s_references; } } /// <summary> /// This is a limited set of references on this .NET Framework TFM. This should be avoided in new code /// as it represents the way reference hookup used to work. /// </summary> /// <remarks> /// Need to special case tuples until we move to net472 /// </remarks> public static ImmutableArray<MetadataReference> Standard { get; } = [ Net461.References.mscorlib, Net461.References.System, Net461.References.SystemCore, Net461.References.SystemData, Net461.References.SystemRuntime, Net461.ExtraReferences.SystemValueTuple ]; public static PortableExecutableReference mscorlib { get; } = Net461.References.mscorlib; public static PortableExecutableReference System { get; } = Net461.References.System; public static PortableExecutableReference SystemRuntime { get; } = Net461.References.SystemRuntime; public static PortableExecutableReference SystemCore { get; } = Net461.References.SystemCore; public static PortableExecutableReference SystemData { get; } = Net461.References.SystemData; public static PortableExecutableReference SystemThreadingTasks { get; } = Net461.References.SystemThreadingTasks; public static PortableExecutableReference SystemXml { get; } = Net461.References.SystemXml; public static PortableExecutableReference SystemValueTuple { get; } = Net461.ExtraReferences.SystemValueTuple; public static PortableExecutableReference MicrosoftCSharp { get; } = Net461.References.MicrosoftCSharp; public static PortableExecutableReference MicrosoftVisualBasic { get; } = Net461.References.MicrosoftVisualBasic; } public static class TargetFrameworkUtil { private static readonly ConcurrentDictionary<string, ImmutableArray<PortableExecutableReference>> s_dynamicReferenceMap = new ConcurrentDictionary<string, ImmutableArray<PortableExecutableReference>>(StringComparer.Ordinal); public static ImmutableArray<MetadataReference> NetLatest => RuntimeUtilities.IsCoreClrRuntime ? NetCoreApp.References : NetFramework.References; public static ImmutableArray<MetadataReference> StandardReferences => RuntimeUtilities.IsCoreClrRuntime ? NetStandard20References : NetFramework.Standard; public static MetadataReference StandardCSharpReference => RuntimeUtilities.IsCoreClrRuntime ? NetStandard20.ExtraReferences.MicrosoftCSharp : NetFramework.MicrosoftCSharp; public static MetadataReference StandardVisualBasicReference => RuntimeUtilities.IsCoreClrRuntime ? NetStandard20.ExtraReferences.MicrosoftVisualBasic : NetFramework.MicrosoftVisualBasic; public static ImmutableArray<MetadataReference> StandardAndCSharpReferences => StandardReferences.Add(StandardCSharpReference); public static ImmutableArray<MetadataReference> StandardAndVBRuntimeReferences => StandardReferences.Add(StandardVisualBasicReference); /* * ⚠ Dev note ⚠: properties in TestBase are backed by Lazy<T>. Avoid changes to the following properties * which would force the initialization of these properties in the static constructor, since the stack traces * for a TypeLoadException are missing important information for resolving problems if/when they occur. * https://github.com/dotnet/roslyn/issues/25961 */ public static ImmutableArray<MetadataReference> WinRTReferences => [ .. TestBase.WinRtRefs ]; public static ImmutableArray<MetadataReference> MinimalReferences => [ TestBase.MinCorlibRef ]; public static ImmutableArray<MetadataReference> MinimalAsyncReferences => [ TestBase.MinAsyncCorlibRef ]; /* * ⚠ Dev note ⚠: TestBase properties end here. */ public static ImmutableArray<MetadataReference> Mscorlib45ExtendedReferences { get; } = [ NetFramework.mscorlib, NetFramework.System, NetFramework.SystemCore, NetFramework.SystemRuntime, NetFramework.SystemValueTuple, ]; public static ImmutableArray<MetadataReference> Mscorlib46ExtendedReferences { get; } = [ Net461.References.mscorlib, Net461.References.System, Net461.References.SystemCore, Net461.References.SystemRuntime, Net461.ExtraReferences.SystemValueTuple, ]; public static ImmutableArray<MetadataReference> Mscorlib40References { get; } = [ Net40.References.mscorlib ]; public static ImmutableArray<MetadataReference> Mscorlib40ExtendedReferences { get; } = [ Net40.References.mscorlib, Net40.References.System, Net40.References.SystemCore ]; public static ImmutableArray<MetadataReference> Mscorlib40andSystemCoreReferences { get; } = [ Net40.References.mscorlib, Net40.References.SystemCore ]; public static ImmutableArray<MetadataReference> Mscorlib40andVBRuntimeReferences { get; } = [ Net40.References.mscorlib, Net40.References.System, Net40.References.MicrosoftVisualBasic ]; public static ImmutableArray<MetadataReference> Mscorlib45References { get; } = [ NetFramework.mscorlib ]; public static ImmutableArray<MetadataReference> Mscorlib46References { get; } = [ Net461.References.mscorlib ]; public static ImmutableArray<MetadataReference> Mscorlib461References { get; } = [ Net461.References.mscorlib ]; public static ImmutableArray<MetadataReference> Mscorlib461ExtendedReferences { get; } = [ Net461.References.mscorlib, Net461.References.System, Net461.References.SystemCore, Net461.References.SystemRuntime, Net461.ExtraReferences.SystemValueTuple, ]; public static ImmutableArray<MetadataReference> Mscorlib461AndCSharpReferences { get; } = [ Net461.References.mscorlib, Net461.References.SystemCore, Net461.References.MicrosoftCSharp ]; public static ImmutableArray<MetadataReference> Mscorlib461AndVBRuntimeReferences { get; } = [ Net461.References.mscorlib, Net461.References.System, Net461.References.MicrosoftVisualBasic ]; public static ImmutableArray<MetadataReference> NetStandard20References { get; } = [ NetStandard20.References.netstandard, NetStandard20.References.mscorlib, NetStandard20.References.SystemRuntime, NetStandard20.References.SystemCore, NetStandard20.References.SystemDynamicRuntime, NetStandard20.References.SystemLinq, NetStandard20.References.SystemLinqExpressions ]; public static ImmutableArray<MetadataReference> DefaultVbReferences { get; } = [ NetFramework.mscorlib, NetFramework.System, NetFramework.SystemCore, NetFramework.MicrosoftVisualBasic ]; #if DEBUG static TargetFrameworkUtil() { // Asserts to ensure these two values keep in sync Debug.Assert(GetReferences(TargetFramework.NetCoreApp).SequenceEqual(NetCoreApp.References)); Debug.Assert(GetReferences(TargetFramework.NetFramework).SequenceEqual(NetFramework.References)); } #endif public static ImmutableArray<MetadataReference> GetReferences(TargetFramework targetFramework) => targetFramework switch { // Primary // Note: NetCoreApp should behave like latest Core TFM TargetFramework.Empty => ImmutableArray<MetadataReference>.Empty, TargetFramework.NetStandard20 => NetStandard20References, TargetFramework.Net50 => ImmutableArray.CreateRange<MetadataReference>(LoadDynamicReferences("Net50")), TargetFramework.Net60 => ImmutableArray.CreateRange<MetadataReference>(LoadDynamicReferences("Net60")), TargetFramework.NetCoreApp or TargetFramework.Net70 => ImmutableArray.CreateRange<MetadataReference>(Net70.References.All), TargetFramework.Net80 => ImmutableArray.CreateRange<MetadataReference>(LoadDynamicReferences("Net80")), TargetFramework.Net90 => ImmutableArray.CreateRange<MetadataReference>(LoadDynamicReferences("Net90")), TargetFramework.Net100 => ImmutableArray.CreateRange<MetadataReference>(LoadDynamicReferences("Net100")), TargetFramework.Net110 => ImmutableArray.CreateRange<MetadataReference>(LoadDynamicReferences("Net110")), TargetFramework.NetFramework => NetFramework.References, TargetFramework.NetLatest => NetLatest, TargetFramework.Standard => StandardReferences, // Legacy we should be phasing out TargetFramework.Mscorlib40 => Mscorlib40References, TargetFramework.Mscorlib40Extended => Mscorlib40ExtendedReferences, TargetFramework.Mscorlib40AndSystemCore => Mscorlib40andSystemCoreReferences, TargetFramework.Mscorlib40AndVBRuntime => Mscorlib40andVBRuntimeReferences, TargetFramework.Mscorlib46 => Mscorlib46References, TargetFramework.Mscorlib46Extended => Mscorlib46ExtendedReferences, TargetFramework.Mscorlib461 => Mscorlib46References, TargetFramework.Mscorlib461Extended => Mscorlib461ExtendedReferences, TargetFramework.Mscorlib461AndCSharp => Mscorlib461AndCSharpReferences, TargetFramework.Mscorlib461AndVBRuntime => Mscorlib461AndVBRuntimeReferences, TargetFramework.WinRT => WinRTReferences, TargetFramework.StandardAndCSharp => StandardAndCSharpReferences, TargetFramework.StandardAndVBRuntime => StandardAndVBRuntimeReferences, TargetFramework.DefaultVb => DefaultVbReferences, TargetFramework.Minimal => MinimalReferences, TargetFramework.MinimalAsync => MinimalAsyncReferences, _ => throw new InvalidOperationException($"Unexpected target framework {targetFramework}"), }; public static ImmutableArray<MetadataReference> GetReferences(TargetFramework tf, IEnumerable<MetadataReference> additionalReferences) { var references = GetReferences(tf); if (additionalReferences == null) { return references; } checkForDuplicateReferences(); return references.AddRange(additionalReferences); // Check to see if there are any duplicate references. This guards against tests inadvertently passing multiple copies of // say System.Core to the tests and implicitly depending on the higher one to win. The few tests which actually mean to // pass multiple versions of a DLL should manually construct the reference list and not use this helper. void checkForDuplicateReferences() { var nameSet = new HashSet<string>(getNames(references), StringComparer.OrdinalIgnoreCase); foreach (var r in additionalReferences) { if (references.Contains(r)) { throw new Exception($"Duplicate reference detected {r.Display}"); } var name = getName(r); if (name != null && !nameSet.Add(name)) { throw new Exception($"Duplicate reference detected {r.Display} - {name}"); } } } IEnumerable<string> getNames(IEnumerable<MetadataReference> e) { foreach (var r in e) { var name = getName(r); if (name != null) { yield return name; } } } string getName(MetadataReference m) { if (m is PortableExecutableReference p && p.GetMetadata() is AssemblyMetadata assemblyMetadata) { try { var identity = assemblyMetadata.GetAssembly().Identity; return identity?.Name; } catch (BadImageFormatException) { // Happens when a native image is incorrectly passed as a PE. return null; } } return null; } } public static IEnumerable<MetadataReference> GetReferencesWithout(TargetFramework targetFramework, params string[] excludeReferenceNames) => GetReferences(targetFramework) .Where(x => !(x is PortableExecutableReference pe && excludeReferenceNames.Contains(pe.FilePath))); /// <summary> /// Many of our reference assemblies are only used by a subset of compiler unit tests. Having a PackageReference /// to the assemblies here would cause them to be deployed to every unit test we write though. These are non-trivial /// in size (4+ MB) and we have ~50 test projects so this adds up fast. To keep size down we just add /// PackageReference on the few projects that and dynamically load here. /// </summary> private static ImmutableArray<PortableExecutableReference> LoadDynamicReferences(string targetFrameworkName) { var assemblyName = $"Basic.Reference.Assemblies.{targetFrameworkName}"; if (s_dynamicReferenceMap.TryGetValue(assemblyName, out var references)) { return references; } try { var name = new AssemblyName(assemblyName); var assembly = Assembly.Load(name); var type = assembly.GetType(assemblyName, throwOnError: true); var prop = type.GetProperty("All", BindingFlags.Public | BindingFlags.Static); if (prop is null) { type = assembly.GetType(assemblyName + "+References", throwOnError: true); prop = type.GetProperty("All", BindingFlags.Public | BindingFlags.Static); } var obj = prop.GetGetMethod().Invoke(obj: null, parameters: null); references = ((IEnumerable<PortableExecutableReference>)obj).ToImmutableArray(); // This method can de called in parallel. Who wins this TryAdd isn't important, it's the same // values. _ = s_dynamicReferenceMap.TryAdd(assemblyName, references); return references; } catch (Exception ex) { var message = $"Error loading {assemblyName}. Make sure the test project has a <PackageReference> for this assembly"; throw new Exception(message, ex); } } } }