Adding polysharp properly

This commit is contained in:
Phil Scott 2024-11-20 08:49:40 -05:00 committed by Patrik Svensson
parent c7c3ebdf57
commit e1d21e7e61
4 changed files with 100 additions and 5 deletions

View File

@ -9,6 +9,7 @@
<PackageVersion Include="IsExternalInit" Version="1.0.3" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="9.0.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageVersion Include="PolySharp" Version="1.14.1" />
<PackageVersion Include="Shouldly" Version="4.2.1" />
<PackageVersion Include="Spectre.Verify.Extensions" Version="22.3.2-preview.0.1" />
<PackageVersion Include="Verify.Xunit" Version="28.2.1" />

View File

@ -2,6 +2,11 @@ namespace Spectre.Console;
internal static class TypeConverterHelper
{
internal const DynamicallyAccessedMemberTypes ConverterAnnotation = DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicFields;
internal static bool IsGetConverterSupported =>
!AppContext.TryGetSwitch("Spectre.Console.TypeConverterHelper.IsGetConverterSupported ", out var enabled) || enabled;
public static string ConvertToString<T>(T input)
{
var result = GetTypeConverter<T>().ConvertToInvariantString(input);
@ -51,7 +56,7 @@ internal static class TypeConverterHelper
public static TypeConverter GetTypeConverter<T>()
{
var converter = TypeDescriptor.GetConverter(typeof(T));
var converter = GetConverter();
if (converter != null)
{
return converter;
@ -72,5 +77,91 @@ internal static class TypeConverterHelper
}
throw new InvalidOperationException("Could not find type converter");
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2087", Justification = "Feature switches are not currently supported in the analyzer")]
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026", Justification = "Feature switches are not currently supported in the analyzer")]
static TypeConverter? GetConverter()
{
if (!IsGetConverterSupported)
{
return GetIntrinsicConverter(typeof(T));
}
return TypeDescriptor.GetConverter(typeof(T));
}
}
private delegate TypeConverter FuncWithDam([DynamicallyAccessedMembers(ConverterAnnotation)] Type type);
private static readonly Dictionary<Type, FuncWithDam> _intrinsicConverters;
static TypeConverterHelper()
{
_intrinsicConverters = new()
{
[typeof(bool)] = _ => new BooleanConverter(),
[typeof(byte)] = _ => new ByteConverter(),
[typeof(sbyte)] = _ => new SByteConverter(),
[typeof(char)] = _ => new CharConverter(),
[typeof(double)] = _ => new DoubleConverter(),
[typeof(string)] = _ => new StringConverter(),
[typeof(int)] = _ => new Int32Converter(),
[typeof(short)] = _ => new Int16Converter(),
[typeof(long)] = _ => new Int64Converter(),
[typeof(float)] = _ => new SingleConverter(),
[typeof(ushort)] = _ => new UInt16Converter(),
[typeof(uint)] = _ => new UInt32Converter(),
[typeof(ulong)] = _ => new UInt64Converter(),
[typeof(object)] = _ => new TypeConverter(),
[typeof(CultureInfo)] = _ => new CultureInfoConverter(),
[typeof(DateTime)] = _ => new DateTimeConverter(),
[typeof(DateTimeOffset)] = _ => new DateTimeOffsetConverter(),
[typeof(decimal)] = _ => new DecimalConverter(),
[typeof(TimeSpan)] = _ => new TimeSpanConverter(),
[typeof(Guid)] = _ => new GuidConverter(),
[typeof(Uri)] = _ => new UriTypeConverter(),
[typeof(Array)] = _ => new ArrayConverter(),
[typeof(ICollection)] = _ => new CollectionConverter(),
[typeof(Enum)] = CreateEnumConverter(),
#if !NETSTANDARD2_0
[typeof(Int128)] = _ => new Int128Converter(),
[typeof(Half)] = _ => new HalfConverter(),
[typeof(UInt128)] = _ => new UInt128Converter(),
[typeof(DateOnly)] = _ => new DateOnlyConverter(),
[typeof(TimeOnly)] = _ => new TimeOnlyConverter(),
[typeof(Version)] = _ => new VersionConverter(),
#endif
};
}
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2111", Justification = "Delegate reflection is safe for all usages in this type.")]
private static FuncWithDam CreateEnumConverter() => ([DynamicallyAccessedMembers(ConverterAnnotation)] Type type) => new EnumConverter(type);
/// <summary>
/// A highly-constrained version of <see cref="TypeDescriptor.GetConverter(Type)" /> that only returns intrinsic converters.
/// </summary>
private static TypeConverter? GetIntrinsicConverter([DynamicallyAccessedMembers(ConverterAnnotation)] Type type)
{
if (type.IsArray)
{
type = typeof(Array);
}
if (typeof(ICollection).IsAssignableFrom(type))
{
type = typeof(ICollection);
}
if (type.IsEnum)
{
type = typeof(Enum);
}
if (_intrinsicConverters.TryGetValue(type, out var factory))
{
return factory(type);
}
return null;
}
}

View File

@ -23,7 +23,7 @@
<PackageReference Include="Wcwidth.Sources">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="PolySharp" Version="1.14.1">
<PackageReference Include="PolySharp">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>

View File

@ -1,12 +1,15 @@
namespace Spectre.Console;
#pragma warning disable IL2026,IL2070,IL2075,IL3050
// ExceptionFormatter relies heavily on reflection of types unknown until runtime.
// We'll suppress these warnings, but alert the user this method is not supported.
[UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2026:RequiresUnreferencedCode")]
[UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2070:RequiresUnreferencedCode")]
[UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2075:RequiresUnreferencedCode")]
[RequiresDynamicCode(AotWarning)]
internal static class ExceptionFormatter
{
public const string AotWarning = "ExceptionFormatter is currently not supported for AOT.";
[RequiresDynamicCode(ExceptionFormatter.AotWarning)]
public static IRenderable Format(Exception exception, ExceptionSettings settings)
{
if (exception is null)