diff --git a/dotnet/src/InternalUtilities/src/Schema/JsonSchemaMapper.ReflectionHelpers.cs b/dotnet/src/InternalUtilities/src/Schema/JsonSchemaMapper.ReflectionHelpers.cs index 11dc0c6d85b7..c26df61cb447 100644 --- a/dotnet/src/InternalUtilities/src/Schema/JsonSchemaMapper.ReflectionHelpers.cs +++ b/dotnet/src/InternalUtilities/src/Schema/JsonSchemaMapper.ReflectionHelpers.cs @@ -170,16 +170,16 @@ private static FieldInfo GetPrivateFieldWithPotentiallyTrimmedMetadata(this Type { public ParameterLookupKey(string name, Type type) { - Name = name; - Type = type; + this.Name = name; + this.Type = type; } public string Name { get; } public Type Type { get; } - public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Name); - public bool Equals(ParameterLookupKey other) => Type == other.Type && string.Equals(Name, other.Name, StringComparison.OrdinalIgnoreCase); - public override bool Equals(object? obj) => obj is ParameterLookupKey key && Equals(key); + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(this.Name); + public bool Equals(ParameterLookupKey other) => this.Type == other.Type && string.Equals(this.Name, other.Name, StringComparison.OrdinalIgnoreCase); + public override bool Equals(object? obj) => obj is ParameterLookupKey key && this.Equals(key); } // Resolves the deserialization constructor for a type using logic copied from diff --git a/dotnet/src/InternalUtilities/src/Schema/JsonSchemaMapper.cs b/dotnet/src/InternalUtilities/src/Schema/JsonSchemaMapper.cs index 55e7763b786f..620d98a0ecab 100644 --- a/dotnet/src/InternalUtilities/src/Schema/JsonSchemaMapper.cs +++ b/dotnet/src/InternalUtilities/src/Schema/JsonSchemaMapper.cs @@ -578,42 +578,42 @@ private ref struct GenerationState public GenerationState(JsonSchemaMapperConfiguration configuration) { - _configuration = configuration; - _nullabilityInfoContext = configuration.ReferenceTypeNullability is ReferenceTypeNullability.Annotated ? new() : null; - _generatedTypePaths = configuration.AllowSchemaReferences ? new() : null; - _currentPath = configuration.AllowSchemaReferences ? new() : null; - _currentDepth = 0; + this._configuration = configuration; + this._nullabilityInfoContext = configuration.ReferenceTypeNullability is ReferenceTypeNullability.Annotated ? new() : null; + this._generatedTypePaths = configuration.AllowSchemaReferences ? new() : null; + this._currentPath = configuration.AllowSchemaReferences ? new() : null; + this._currentDepth = 0; } - public readonly JsonSchemaMapperConfiguration Configuration => _configuration; - public readonly NullabilityInfoContext? NullabilityInfoContext => _nullabilityInfoContext; - public readonly int CurrentDepth => _currentDepth; + public readonly JsonSchemaMapperConfiguration Configuration => this._configuration; + public readonly NullabilityInfoContext? NullabilityInfoContext => this._nullabilityInfoContext; + public readonly int CurrentDepth => this._currentDepth; public void Push(string nodeId) { - if (_currentDepth == Configuration.MaxDepth) + if (this._currentDepth == this.Configuration.MaxDepth) { ThrowHelpers.ThrowInvalidOperationException_MaxDepthReached(); } - _currentDepth++; + this._currentDepth++; - if (Configuration.AllowSchemaReferences) + if (this.Configuration.AllowSchemaReferences) { - Debug.Assert(_currentPath is not null); - _currentPath!.Add(nodeId); + Debug.Assert(this._currentPath is not null); + this._currentPath!.Add(nodeId); } } public void Pop() { - Debug.Assert(_currentDepth > 0); - _currentDepth--; + Debug.Assert(this._currentDepth > 0); + this._currentDepth--; - if (Configuration.AllowSchemaReferences) + if (this.Configuration.AllowSchemaReferences) { - Debug.Assert(_currentPath is not null); - _currentPath!.RemoveAt(_currentPath.Count - 1); + Debug.Assert(this._currentPath is not null); + this._currentPath!.RemoveAt(this._currentPath.Count - 1); } } @@ -622,13 +622,13 @@ public void Pop() /// public readonly void RegisterTypePath(Type type, Type? parentNullableOfT, JsonConverter? customConverter, bool isNullableReferenceType, JsonNumberHandling? customNumberHandling) { - if (Configuration.AllowSchemaReferences) + if (this.Configuration.AllowSchemaReferences) { - Debug.Assert(_currentPath is not null); - Debug.Assert(_generatedTypePaths is not null); + Debug.Assert(this._currentPath is not null); + Debug.Assert(this._generatedTypePaths is not null); - string pointer = _currentDepth == 0 ? "#" : "#/" + string.Join("/", _currentPath); - _generatedTypePaths!.Add((parentNullableOfT ?? type, customConverter, isNullableReferenceType, customNumberHandling), pointer); + string pointer = this._currentDepth == 0 ? "#" : "#/" + string.Join("/", this._currentPath); + this._generatedTypePaths!.Add((parentNullableOfT ?? type, customConverter, isNullableReferenceType, customNumberHandling), pointer); } } @@ -637,10 +637,10 @@ public readonly void RegisterTypePath(Type type, Type? parentNullableOfT, JsonCo /// public readonly bool TryGetGeneratedSchemaPath(Type type, Type? parentNullableOfT, JsonConverter? customConverter, bool isNullableReferenceType, JsonNumberHandling? customNumberHandling, [NotNullWhen(true)] out string? value) { - if (Configuration.AllowSchemaReferences) + if (this.Configuration.AllowSchemaReferences) { - Debug.Assert(_generatedTypePaths is not null); - return _generatedTypePaths!.TryGetValue((parentNullableOfT ?? type, customConverter, isNullableReferenceType, customNumberHandling), out value); + Debug.Assert(this._generatedTypePaths is not null); + return this._generatedTypePaths!.TryGetValue((parentNullableOfT ?? type, customConverter, isNullableReferenceType, customNumberHandling), out value); } value = null; @@ -810,9 +810,9 @@ private readonly struct SimpleTypeJsonSchema { public SimpleTypeJsonSchema(JsonSchemaType schemaType, string? format = null, string? pattern = null) { - SchemaType = schemaType; - Format = format; - Pattern = pattern; + this.SchemaType = schemaType; + this.Format = format; + this.Pattern = pattern; } public JsonSchemaType SchemaType { get; } diff --git a/dotnet/src/InternalUtilities/src/Schema/JsonSchemaMapperConfiguration.cs b/dotnet/src/InternalUtilities/src/Schema/JsonSchemaMapperConfiguration.cs index 2bffb91b0e0c..1eab0ebe70dc 100644 --- a/dotnet/src/InternalUtilities/src/Schema/JsonSchemaMapperConfiguration.cs +++ b/dotnet/src/InternalUtilities/src/Schema/JsonSchemaMapperConfiguration.cs @@ -78,7 +78,7 @@ class JsonSchemaMapperConfiguration /// public int MaxDepth { - get => _maxDepth; + get => this._maxDepth; init { if (value < 0) @@ -87,7 +87,7 @@ public int MaxDepth static void Throw() => throw new ArgumentOutOfRangeException(nameof(value)); } - _maxDepth = value; + this._maxDepth = value; } } } diff --git a/dotnet/src/InternalUtilities/src/Schema/Polyfills/NullabilityInfo.cs b/dotnet/src/InternalUtilities/src/Schema/Polyfills/NullabilityInfo.cs index 395aa7a3d158..7a922302948e 100644 --- a/dotnet/src/InternalUtilities/src/Schema/Polyfills/NullabilityInfo.cs +++ b/dotnet/src/InternalUtilities/src/Schema/Polyfills/NullabilityInfo.cs @@ -3,70 +3,69 @@ #if !NET6_0_OR_GREATER using System.Diagnostics.CodeAnalysis; -namespace System.Reflection +namespace System.Reflection; + +/// +/// A class that represents nullability info. +/// +[ExcludeFromCodeCoverage] +internal sealed class NullabilityInfo { - /// - /// A class that represents nullability info. - /// - [ExcludeFromCodeCoverage] - internal sealed class NullabilityInfo + internal NullabilityInfo(Type type, NullabilityState readState, NullabilityState writeState, + NullabilityInfo? elementType, NullabilityInfo[] typeArguments) { - internal NullabilityInfo(Type type, NullabilityState readState, NullabilityState writeState, - NullabilityInfo? elementType, NullabilityInfo[] typeArguments) - { - Type = type; - ReadState = readState; - WriteState = writeState; - ElementType = elementType; - GenericTypeArguments = typeArguments; - } + this.Type = type; + this.ReadState = readState; + this.WriteState = writeState; + this.ElementType = elementType; + this.GenericTypeArguments = typeArguments; + } - /// - /// The of the member or generic parameter - /// to which this NullabilityInfo belongs. - /// - public Type Type { get; } + /// + /// The of the member or generic parameter + /// to which this NullabilityInfo belongs. + /// + public Type Type { get; } - /// - /// The nullability read state of the member. - /// - public NullabilityState ReadState { get; internal set; } + /// + /// The nullability read state of the member. + /// + public NullabilityState ReadState { get; internal set; } - /// - /// The nullability write state of the member. - /// - public NullabilityState WriteState { get; internal set; } + /// + /// The nullability write state of the member. + /// + public NullabilityState WriteState { get; internal set; } - /// - /// If the member type is an array, gives the of the elements of the array, null otherwise. - /// - public NullabilityInfo? ElementType { get; } + /// + /// If the member type is an array, gives the of the elements of the array, null otherwise. + /// + public NullabilityInfo? ElementType { get; } - /// - /// If the member type is a generic type, gives the array of for each type parameter. - /// - public NullabilityInfo[] GenericTypeArguments { get; } - } + /// + /// If the member type is a generic type, gives the array of for each type parameter. + /// + public NullabilityInfo[] GenericTypeArguments { get; } +} +/// +/// An enum that represents nullability state. +/// +internal enum NullabilityState +{ /// - /// An enum that represents nullability state. + /// Nullability context not enabled (oblivious) /// - internal enum NullabilityState - { - /// - /// Nullability context not enabled (oblivious) - /// - Unknown, + Unknown, - /// - /// Non nullable value or reference type - /// - NotNull, + /// + /// Non nullable value or reference type + /// + NotNull, - /// - /// Nullable value or reference type - /// - Nullable, - } + /// + /// Nullable value or reference type + /// + Nullable, } #endif diff --git a/dotnet/src/InternalUtilities/src/Schema/Polyfills/NullabilityInfoContext.cs b/dotnet/src/InternalUtilities/src/Schema/Polyfills/NullabilityInfoContext.cs index 14f24e7fd722..554ba71e339d 100644 --- a/dotnet/src/InternalUtilities/src/Schema/Polyfills/NullabilityInfoContext.cs +++ b/dotnet/src/InternalUtilities/src/Schema/Polyfills/NullabilityInfoContext.cs @@ -7,664 +7,663 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; -namespace System.Reflection +namespace System.Reflection; + +/// +/// Provides APIs for populating nullability information/context from reflection members: +/// , , and . +/// +[ExcludeFromCodeCoverage] +internal sealed class NullabilityInfoContext { - /// - /// Provides APIs for populating nullability information/context from reflection members: - /// , , and . - /// - [ExcludeFromCodeCoverage] - internal sealed class NullabilityInfoContext - { - private const string CompilerServicesNameSpace = "System.Runtime.CompilerServices"; - private readonly Dictionary _publicOnlyModules = []; - private readonly Dictionary _context = []; + private const string CompilerServicesNameSpace = "System.Runtime.CompilerServices"; + private readonly Dictionary _publicOnlyModules = []; + private readonly Dictionary _context = []; - internal static bool IsSupported { get; } = - AppContext.TryGetSwitch("System.Reflection.NullabilityInfoContext.IsSupported", out bool isSupported) ? isSupported : true; + internal static bool IsSupported { get; } = + AppContext.TryGetSwitch("System.Reflection.NullabilityInfoContext.IsSupported", out bool isSupported) ? isSupported : true; - [Flags] - private enum NotAnnotatedStatus - { - None = 0x0, // no restriction, all members annotated - Private = 0x1, // private members not annotated - Internal = 0x2, // internal members not annotated - } + [Flags] + private enum NotAnnotatedStatus + { + None = 0x0, // no restriction, all members annotated + Private = 0x1, // private members not annotated + Internal = 0x2, // internal members not annotated + } - private NullabilityState? GetNullableContext(MemberInfo? memberInfo) + private NullabilityState? GetNullableContext(MemberInfo? memberInfo) + { + while (memberInfo is not null) { - while (memberInfo is not null) + if (this._context.TryGetValue(memberInfo, out NullabilityState state)) { - if (_context.TryGetValue(memberInfo, out NullabilityState state)) - { - return state; - } + return state; + } - foreach (CustomAttributeData attribute in memberInfo.GetCustomAttributesData()) + foreach (CustomAttributeData attribute in memberInfo.GetCustomAttributesData()) + { + if (attribute.AttributeType.Name == "NullableContextAttribute" && + attribute.AttributeType.Namespace == CompilerServicesNameSpace && + attribute.ConstructorArguments.Count == 1) { - if (attribute.AttributeType.Name == "NullableContextAttribute" && - attribute.AttributeType.Namespace == CompilerServicesNameSpace && - attribute.ConstructorArguments.Count == 1) - { - state = TranslateByte(attribute.ConstructorArguments[0].Value); - _context.Add(memberInfo, state); - return state; - } + state = TranslateByte(attribute.ConstructorArguments[0].Value); + this._context.Add(memberInfo, state); + return state; } - - memberInfo = memberInfo.DeclaringType; } - return null; + memberInfo = memberInfo.DeclaringType; } - /// - /// Populates for the given . - /// If the nullablePublicOnly feature is set for an assembly, like it does in .NET SDK, the private and/or internal member's - /// nullability attributes are omitted, in this case the API will return NullabilityState.Unknown state. - /// - /// The parameter which nullability info gets populated. - /// If the parameterInfo parameter is null. - /// . - public NullabilityInfo Create(ParameterInfo parameterInfo) - { - EnsureIsSupported(); - - IList attributes = parameterInfo.GetCustomAttributesData(); - NullableAttributeStateParser parser = parameterInfo.Member is MethodBase method && IsPrivateOrInternalMethodAndAnnotationDisabled(method) - ? NullableAttributeStateParser.Unknown - : CreateParser(attributes); - NullabilityInfo nullability = GetNullabilityInfo(parameterInfo.Member, parameterInfo.ParameterType, parser); + return null; + } - if (nullability.ReadState != NullabilityState.Unknown) - { - CheckParameterMetadataType(parameterInfo, nullability); - } + /// + /// Populates for the given . + /// If the nullablePublicOnly feature is set for an assembly, like it does in .NET SDK, the private and/or internal member's + /// nullability attributes are omitted, in this case the API will return NullabilityState.Unknown state. + /// + /// The parameter which nullability info gets populated. + /// If the parameterInfo parameter is null. + /// . + public NullabilityInfo Create(ParameterInfo parameterInfo) + { + EnsureIsSupported(); - CheckNullabilityAttributes(nullability, attributes); - return nullability; - } + IList attributes = parameterInfo.GetCustomAttributesData(); + NullableAttributeStateParser parser = parameterInfo.Member is MethodBase method && this.IsPrivateOrInternalMethodAndAnnotationDisabled(method) + ? NullableAttributeStateParser.Unknown + : CreateParser(attributes); + NullabilityInfo nullability = this.GetNullabilityInfo(parameterInfo.Member, parameterInfo.ParameterType, parser); - private void CheckParameterMetadataType(ParameterInfo parameter, NullabilityInfo nullability) + if (nullability.ReadState != NullabilityState.Unknown) { - ParameterInfo? metaParameter; - MemberInfo metaMember; + this.CheckParameterMetadataType(parameterInfo, nullability); + } - switch (parameter.Member) - { - case ConstructorInfo ctor: - var metaCtor = (ConstructorInfo)GetMemberMetadataDefinition(ctor); - metaMember = metaCtor; - metaParameter = GetMetaParameter(metaCtor, parameter); - break; - - case MethodInfo method: - MethodInfo metaMethod = GetMethodMetadataDefinition(method); - metaMember = metaMethod; - metaParameter = string.IsNullOrEmpty(parameter.Name) ? metaMethod.ReturnParameter : GetMetaParameter(metaMethod, parameter); - break; + CheckNullabilityAttributes(nullability, attributes); + return nullability; + } - default: - return; - } + private void CheckParameterMetadataType(ParameterInfo parameter, NullabilityInfo nullability) + { + ParameterInfo? metaParameter; + MemberInfo metaMember; - if (metaParameter is not null) - { - CheckGenericParameters(nullability, metaMember, metaParameter.ParameterType, parameter.Member.ReflectedType); - } + switch (parameter.Member) + { + case ConstructorInfo ctor: + var metaCtor = (ConstructorInfo)GetMemberMetadataDefinition(ctor); + metaMember = metaCtor; + metaParameter = GetMetaParameter(metaCtor, parameter); + break; + + case MethodInfo method: + MethodInfo metaMethod = GetMethodMetadataDefinition(method); + metaMember = metaMethod; + metaParameter = string.IsNullOrEmpty(parameter.Name) ? metaMethod.ReturnParameter : GetMetaParameter(metaMethod, parameter); + break; + + default: + return; } - private static ParameterInfo? GetMetaParameter(MethodBase metaMethod, ParameterInfo parameter) + if (metaParameter is not null) { - var parameters = metaMethod.GetParameters(); - for (int i = 0; i < parameters.Length; i++) - { - if (parameter.Position == i && - parameter.Name == parameters[i].Name) - { - return parameters[i]; - } - } - - return null; + this.CheckGenericParameters(nullability, metaMember, metaParameter.ParameterType, parameter.Member.ReflectedType); } + } - private static MethodInfo GetMethodMetadataDefinition(MethodInfo method) + private static ParameterInfo? GetMetaParameter(MethodBase metaMethod, ParameterInfo parameter) + { + var parameters = metaMethod.GetParameters(); + for (int i = 0; i < parameters.Length; i++) { - if (method.IsGenericMethod && !method.IsGenericMethodDefinition) + if (parameter.Position == i && + parameter.Name == parameters[i].Name) { - method = method.GetGenericMethodDefinition(); + return parameters[i]; } - - return (MethodInfo)GetMemberMetadataDefinition(method); } - private static void CheckNullabilityAttributes(NullabilityInfo nullability, IList attributes) + return null; + } + + private static MethodInfo GetMethodMetadataDefinition(MethodInfo method) + { + if (method.IsGenericMethod && !method.IsGenericMethodDefinition) { - var codeAnalysisReadState = NullabilityState.Unknown; - var codeAnalysisWriteState = NullabilityState.Unknown; + method = method.GetGenericMethodDefinition(); + } + + return (MethodInfo)GetMemberMetadataDefinition(method); + } + + private static void CheckNullabilityAttributes(NullabilityInfo nullability, IList attributes) + { + var codeAnalysisReadState = NullabilityState.Unknown; + var codeAnalysisWriteState = NullabilityState.Unknown; - foreach (CustomAttributeData attribute in attributes) + foreach (CustomAttributeData attribute in attributes) + { + if (attribute.AttributeType.Namespace == "System.Diagnostics.CodeAnalysis") { - if (attribute.AttributeType.Namespace == "System.Diagnostics.CodeAnalysis") + if (attribute.AttributeType.Name == "NotNullAttribute") { - if (attribute.AttributeType.Name == "NotNullAttribute") - { - codeAnalysisReadState = NullabilityState.NotNull; - } - else if ((attribute.AttributeType.Name == "MaybeNullAttribute" || - attribute.AttributeType.Name == "MaybeNullWhenAttribute") && - codeAnalysisReadState == NullabilityState.Unknown && - !IsValueTypeOrValueTypeByRef(nullability.Type)) - { - codeAnalysisReadState = NullabilityState.Nullable; - } - else if (attribute.AttributeType.Name == "DisallowNullAttribute") - { - codeAnalysisWriteState = NullabilityState.NotNull; - } - else if (attribute.AttributeType.Name == "AllowNullAttribute" && - codeAnalysisWriteState == NullabilityState.Unknown && + codeAnalysisReadState = NullabilityState.NotNull; + } + else if ((attribute.AttributeType.Name == "MaybeNullAttribute" || + attribute.AttributeType.Name == "MaybeNullWhenAttribute") && + codeAnalysisReadState == NullabilityState.Unknown && !IsValueTypeOrValueTypeByRef(nullability.Type)) - { - codeAnalysisWriteState = NullabilityState.Nullable; - } + { + codeAnalysisReadState = NullabilityState.Nullable; + } + else if (attribute.AttributeType.Name == "DisallowNullAttribute") + { + codeAnalysisWriteState = NullabilityState.NotNull; + } + else if (attribute.AttributeType.Name == "AllowNullAttribute" && + codeAnalysisWriteState == NullabilityState.Unknown && + !IsValueTypeOrValueTypeByRef(nullability.Type)) + { + codeAnalysisWriteState = NullabilityState.Nullable; } - } - - if (codeAnalysisReadState != NullabilityState.Unknown) - { - nullability.ReadState = codeAnalysisReadState; - } - - if (codeAnalysisWriteState != NullabilityState.Unknown) - { - nullability.WriteState = codeAnalysisWriteState; } } - /// - /// Populates for the given . - /// If the nullablePublicOnly feature is set for an assembly, like it does in .NET SDK, the private and/or internal member's - /// nullability attributes are omitted, in this case the API will return NullabilityState.Unknown state. - /// - /// The parameter which nullability info gets populated. - /// If the propertyInfo parameter is null. - /// . - public NullabilityInfo Create(PropertyInfo propertyInfo) + if (codeAnalysisReadState != NullabilityState.Unknown) { - EnsureIsSupported(); + nullability.ReadState = codeAnalysisReadState; + } - MethodInfo? getter = propertyInfo.GetGetMethod(true); - MethodInfo? setter = propertyInfo.GetSetMethod(true); - bool annotationsDisabled = (getter is null || IsPrivateOrInternalMethodAndAnnotationDisabled(getter)) - && (setter is null || IsPrivateOrInternalMethodAndAnnotationDisabled(setter)); - NullableAttributeStateParser parser = annotationsDisabled ? NullableAttributeStateParser.Unknown : CreateParser(propertyInfo.GetCustomAttributesData()); - NullabilityInfo nullability = GetNullabilityInfo(propertyInfo, propertyInfo.PropertyType, parser); + if (codeAnalysisWriteState != NullabilityState.Unknown) + { + nullability.WriteState = codeAnalysisWriteState; + } + } - if (getter is not null) - { - CheckNullabilityAttributes(nullability, getter.ReturnParameter.GetCustomAttributesData()); - } - else - { - nullability.ReadState = NullabilityState.Unknown; - } + /// + /// Populates for the given . + /// If the nullablePublicOnly feature is set for an assembly, like it does in .NET SDK, the private and/or internal member's + /// nullability attributes are omitted, in this case the API will return NullabilityState.Unknown state. + /// + /// The parameter which nullability info gets populated. + /// If the propertyInfo parameter is null. + /// . + public NullabilityInfo Create(PropertyInfo propertyInfo) + { + EnsureIsSupported(); - if (setter is not null) - { - CheckNullabilityAttributes(nullability, setter.GetParameters().Last().GetCustomAttributesData()); - } - else - { - nullability.WriteState = NullabilityState.Unknown; - } + MethodInfo? getter = propertyInfo.GetGetMethod(true); + MethodInfo? setter = propertyInfo.GetSetMethod(true); + bool annotationsDisabled = (getter is null || this.IsPrivateOrInternalMethodAndAnnotationDisabled(getter)) + && (setter is null || this.IsPrivateOrInternalMethodAndAnnotationDisabled(setter)); + NullableAttributeStateParser parser = annotationsDisabled ? NullableAttributeStateParser.Unknown : CreateParser(propertyInfo.GetCustomAttributesData()); + NullabilityInfo nullability = this.GetNullabilityInfo(propertyInfo, propertyInfo.PropertyType, parser); - return nullability; + if (getter is not null) + { + CheckNullabilityAttributes(nullability, getter.ReturnParameter.GetCustomAttributesData()); } - - private bool IsPrivateOrInternalMethodAndAnnotationDisabled(MethodBase method) + else { - if ((method.IsPrivate || method.IsFamilyAndAssembly || method.IsAssembly) && - IsPublicOnly(method.IsPrivate, method.IsFamilyAndAssembly, method.IsAssembly, method.Module)) - { - return true; - } - - return false; + nullability.ReadState = NullabilityState.Unknown; } - /// - /// Populates for the given . - /// If the nullablePublicOnly feature is set for an assembly, like it does in .NET SDK, the private and/or internal member's - /// nullability attributes are omitted, in this case the API will return NullabilityState.Unknown state. - /// - /// The parameter which nullability info gets populated. - /// If the eventInfo parameter is null. - /// . - public NullabilityInfo Create(EventInfo eventInfo) + if (setter is not null) { - EnsureIsSupported(); - - return GetNullabilityInfo(eventInfo, eventInfo.EventHandlerType!, CreateParser(eventInfo.GetCustomAttributesData())); + CheckNullabilityAttributes(nullability, setter.GetParameters().Last().GetCustomAttributesData()); } - - /// - /// Populates for the given - /// If the nullablePublicOnly feature is set for an assembly, like it does in .NET SDK, the private and/or internal member's - /// nullability attributes are omitted, in this case the API will return NullabilityState.Unknown state. - /// - /// The parameter which nullability info gets populated. - /// If the fieldInfo parameter is null. - /// . - public NullabilityInfo Create(FieldInfo fieldInfo) + else { - EnsureIsSupported(); - - IList attributes = fieldInfo.GetCustomAttributesData(); - NullableAttributeStateParser parser = IsPrivateOrInternalFieldAndAnnotationDisabled(fieldInfo) ? NullableAttributeStateParser.Unknown : CreateParser(attributes); - NullabilityInfo nullability = GetNullabilityInfo(fieldInfo, fieldInfo.FieldType, parser); - CheckNullabilityAttributes(nullability, attributes); - return nullability; + nullability.WriteState = NullabilityState.Unknown; } - private static void EnsureIsSupported() + return nullability; + } + + private bool IsPrivateOrInternalMethodAndAnnotationDisabled(MethodBase method) + { + if ((method.IsPrivate || method.IsFamilyAndAssembly || method.IsAssembly) && + this.IsPublicOnly(method.IsPrivate, method.IsFamilyAndAssembly, method.IsAssembly, method.Module)) { - if (!IsSupported) - { - throw new InvalidOperationException("NullabilityInfoContext is not supported"); - } + return true; } - private bool IsPrivateOrInternalFieldAndAnnotationDisabled(FieldInfo fieldInfo) - { - if ((fieldInfo.IsPrivate || fieldInfo.IsFamilyAndAssembly || fieldInfo.IsAssembly) && - IsPublicOnly(fieldInfo.IsPrivate, fieldInfo.IsFamilyAndAssembly, fieldInfo.IsAssembly, fieldInfo.Module)) - { - return true; - } + return false; + } - return false; - } + /// + /// Populates for the given . + /// If the nullablePublicOnly feature is set for an assembly, like it does in .NET SDK, the private and/or internal member's + /// nullability attributes are omitted, in this case the API will return NullabilityState.Unknown state. + /// + /// The parameter which nullability info gets populated. + /// If the eventInfo parameter is null. + /// . + public NullabilityInfo Create(EventInfo eventInfo) + { + EnsureIsSupported(); - private bool IsPublicOnly(bool isPrivate, bool isFamilyAndAssembly, bool isAssembly, Module module) - { - if (!_publicOnlyModules.TryGetValue(module, out NotAnnotatedStatus value)) - { - value = PopulateAnnotationInfo(module.GetCustomAttributesData()); - _publicOnlyModules.Add(module, value); - } + return this.GetNullabilityInfo(eventInfo, eventInfo.EventHandlerType!, CreateParser(eventInfo.GetCustomAttributesData())); + } - if (value == NotAnnotatedStatus.None) - { - return false; - } + /// + /// Populates for the given + /// If the nullablePublicOnly feature is set for an assembly, like it does in .NET SDK, the private and/or internal member's + /// nullability attributes are omitted, in this case the API will return NullabilityState.Unknown state. + /// + /// The parameter which nullability info gets populated. + /// If the fieldInfo parameter is null. + /// . + public NullabilityInfo Create(FieldInfo fieldInfo) + { + EnsureIsSupported(); - if (((isPrivate || isFamilyAndAssembly) && value.HasFlag(NotAnnotatedStatus.Private)) || - (isAssembly && value.HasFlag(NotAnnotatedStatus.Internal))) - { - return true; - } + IList attributes = fieldInfo.GetCustomAttributesData(); + NullableAttributeStateParser parser = this.IsPrivateOrInternalFieldAndAnnotationDisabled(fieldInfo) ? NullableAttributeStateParser.Unknown : CreateParser(attributes); + NullabilityInfo nullability = this.GetNullabilityInfo(fieldInfo, fieldInfo.FieldType, parser); + CheckNullabilityAttributes(nullability, attributes); + return nullability; + } - return false; + private static void EnsureIsSupported() + { + if (!IsSupported) + { + throw new InvalidOperationException("NullabilityInfoContext is not supported"); } + } - private static NotAnnotatedStatus PopulateAnnotationInfo(IList customAttributes) + private bool IsPrivateOrInternalFieldAndAnnotationDisabled(FieldInfo fieldInfo) + { + if ((fieldInfo.IsPrivate || fieldInfo.IsFamilyAndAssembly || fieldInfo.IsAssembly) && + this.IsPublicOnly(fieldInfo.IsPrivate, fieldInfo.IsFamilyAndAssembly, fieldInfo.IsAssembly, fieldInfo.Module)) { - foreach (CustomAttributeData attribute in customAttributes) - { - if (attribute.AttributeType.Name == "NullablePublicOnlyAttribute" && - attribute.AttributeType.Namespace == CompilerServicesNameSpace && - attribute.ConstructorArguments.Count == 1) - { - if (attribute.ConstructorArguments[0].Value is bool boolValue && boolValue) - { - return NotAnnotatedStatus.Internal | NotAnnotatedStatus.Private; - } - else - { - return NotAnnotatedStatus.Private; - } - } - } - - return NotAnnotatedStatus.None; + return true; } - private NullabilityInfo GetNullabilityInfo(MemberInfo memberInfo, Type type, NullableAttributeStateParser parser) - { - int index = 0; - NullabilityInfo nullability = GetNullabilityInfo(memberInfo, type, parser, ref index); + return false; + } - if (nullability.ReadState != NullabilityState.Unknown) - { - TryLoadGenericMetaTypeNullability(memberInfo, nullability); - } + private bool IsPublicOnly(bool isPrivate, bool isFamilyAndAssembly, bool isAssembly, Module module) + { + if (!this._publicOnlyModules.TryGetValue(module, out NotAnnotatedStatus value)) + { + value = PopulateAnnotationInfo(module.GetCustomAttributesData()); + this._publicOnlyModules.Add(module, value); + } - return nullability; + if (value == NotAnnotatedStatus.None) + { + return false; } - private NullabilityInfo GetNullabilityInfo(MemberInfo memberInfo, Type type, NullableAttributeStateParser parser, ref int index) + if (((isPrivate || isFamilyAndAssembly) && value.HasFlag(NotAnnotatedStatus.Private)) || + (isAssembly && value.HasFlag(NotAnnotatedStatus.Internal))) { - NullabilityState state = NullabilityState.Unknown; - NullabilityInfo? elementState = null; - NullabilityInfo[] genericArgumentsState = []; - Type underlyingType = type; + return true; + } - if (underlyingType.IsByRef || underlyingType.IsPointer) - { - underlyingType = underlyingType.GetElementType()!; - } + return false; + } - if (underlyingType.IsValueType) + private static NotAnnotatedStatus PopulateAnnotationInfo(IList customAttributes) + { + foreach (CustomAttributeData attribute in customAttributes) + { + if (attribute.AttributeType.Name == "NullablePublicOnlyAttribute" && + attribute.AttributeType.Namespace == CompilerServicesNameSpace && + attribute.ConstructorArguments.Count == 1) { - if (Nullable.GetUnderlyingType(underlyingType) is { } nullableUnderlyingType) + if (attribute.ConstructorArguments[0].Value is bool boolValue && boolValue) { - underlyingType = nullableUnderlyingType; - state = NullabilityState.Nullable; + return NotAnnotatedStatus.Internal | NotAnnotatedStatus.Private; } else { - state = NullabilityState.NotNull; - } - - if (underlyingType.IsGenericType) - { - ++index; - } - } - else - { - if (!parser.ParseNullableState(index++, ref state) - && GetNullableContext(memberInfo) is { } contextState) - { - state = contextState; - } - - if (underlyingType.IsArray) - { - elementState = GetNullabilityInfo(memberInfo, underlyingType.GetElementType()!, parser, ref index); + return NotAnnotatedStatus.Private; } } + } - if (underlyingType.IsGenericType) - { - Type[] genericArguments = underlyingType.GetGenericArguments(); - genericArgumentsState = new NullabilityInfo[genericArguments.Length]; + return NotAnnotatedStatus.None; + } - for (int i = 0; i < genericArguments.Length; i++) - { - genericArgumentsState[i] = GetNullabilityInfo(memberInfo, genericArguments[i], parser, ref index); - } - } + private NullabilityInfo GetNullabilityInfo(MemberInfo memberInfo, Type type, NullableAttributeStateParser parser) + { + int index = 0; + NullabilityInfo nullability = this.GetNullabilityInfo(memberInfo, type, parser, ref index); - return new NullabilityInfo(type, state, state, elementState, genericArgumentsState); + if (nullability.ReadState != NullabilityState.Unknown) + { + this.TryLoadGenericMetaTypeNullability(memberInfo, nullability); } - private static NullableAttributeStateParser CreateParser(IList customAttributes) - { - foreach (CustomAttributeData attribute in customAttributes) - { - if (attribute.AttributeType.Name == "NullableAttribute" && - attribute.AttributeType.Namespace == CompilerServicesNameSpace && - attribute.ConstructorArguments.Count == 1) - { - return new NullableAttributeStateParser(attribute.ConstructorArguments[0].Value); - } - } + return nullability; + } + + private NullabilityInfo GetNullabilityInfo(MemberInfo memberInfo, Type type, NullableAttributeStateParser parser, ref int index) + { + NullabilityState state = NullabilityState.Unknown; + NullabilityInfo? elementState = null; + NullabilityInfo[] genericArgumentsState = []; + Type underlyingType = type; - return new NullableAttributeStateParser(null); + if (underlyingType.IsByRef || underlyingType.IsPointer) + { + underlyingType = underlyingType.GetElementType()!; } - private void TryLoadGenericMetaTypeNullability(MemberInfo memberInfo, NullabilityInfo nullability) + if (underlyingType.IsValueType) { - MemberInfo? metaMember = GetMemberMetadataDefinition(memberInfo); - Type? metaType = null; - if (metaMember is FieldInfo field) + if (Nullable.GetUnderlyingType(underlyingType) is { } nullableUnderlyingType) { - metaType = field.FieldType; + underlyingType = nullableUnderlyingType; + state = NullabilityState.Nullable; } - else if (metaMember is PropertyInfo property) + else { - metaType = GetPropertyMetaType(property); + state = NullabilityState.NotNull; } - if (metaType is not null) + if (underlyingType.IsGenericType) { - CheckGenericParameters(nullability, metaMember!, metaType, memberInfo.ReflectedType); + ++index; } } - - private static MemberInfo GetMemberMetadataDefinition(MemberInfo member) + else { - Type? type = member.DeclaringType; - if ((type is not null) && type.IsGenericType && !type.IsGenericTypeDefinition) + if (!parser.ParseNullableState(index++, ref state) + && this.GetNullableContext(memberInfo) is { } contextState) { - return NullabilityInfoHelpers.GetMemberWithSameMetadataDefinitionAs(type.GetGenericTypeDefinition(), member); + state = contextState; } - return member; + if (underlyingType.IsArray) + { + elementState = this.GetNullabilityInfo(memberInfo, underlyingType.GetElementType()!, parser, ref index); + } } - private static Type GetPropertyMetaType(PropertyInfo property) + if (underlyingType.IsGenericType) { - if (property.GetGetMethod(true) is MethodInfo method) + Type[] genericArguments = underlyingType.GetGenericArguments(); + genericArgumentsState = new NullabilityInfo[genericArguments.Length]; + + for (int i = 0; i < genericArguments.Length; i++) { - return method.ReturnType; + genericArgumentsState[i] = this.GetNullabilityInfo(memberInfo, genericArguments[i], parser, ref index); } - - return property.GetSetMethod(true)!.GetParameters()[0].ParameterType; } - private void CheckGenericParameters(NullabilityInfo nullability, MemberInfo metaMember, Type metaType, Type? reflectedType) + return new NullabilityInfo(type, state, state, elementState, genericArgumentsState); + } + + private static NullableAttributeStateParser CreateParser(IList customAttributes) + { + foreach (CustomAttributeData attribute in customAttributes) { - if (metaType.IsGenericParameter) + if (attribute.AttributeType.Name == "NullableAttribute" && + attribute.AttributeType.Namespace == CompilerServicesNameSpace && + attribute.ConstructorArguments.Count == 1) { - if (nullability.ReadState == NullabilityState.NotNull) - { - TryUpdateGenericParameterNullability(nullability, metaType, reflectedType); - } + return new NullableAttributeStateParser(attribute.ConstructorArguments[0].Value); } - else if (metaType.ContainsGenericParameters) - { - if (nullability.GenericTypeArguments.Length > 0) - { - Type[] genericArguments = metaType.GetGenericArguments(); + } - for (int i = 0; i < genericArguments.Length; i++) - { - CheckGenericParameters(nullability.GenericTypeArguments[i], metaMember, genericArguments[i], reflectedType); - } - } - else if (nullability.ElementType is { } elementNullability && metaType.IsArray) - { - CheckGenericParameters(elementNullability, metaMember, metaType.GetElementType()!, reflectedType); - } + return new NullableAttributeStateParser(null); + } - // We could also follow this branch for metaType.IsPointer, but since pointers must be unmanaged this - // will be a no-op regardless - else if (metaType.IsByRef) - { - CheckGenericParameters(nullability, metaMember, metaType.GetElementType()!, reflectedType); - } - } + private void TryLoadGenericMetaTypeNullability(MemberInfo memberInfo, NullabilityInfo nullability) + { + MemberInfo? metaMember = GetMemberMetadataDefinition(memberInfo); + Type? metaType = null; + if (metaMember is FieldInfo field) + { + metaType = field.FieldType; + } + else if (metaMember is PropertyInfo property) + { + metaType = GetPropertyMetaType(property); } - private bool TryUpdateGenericParameterNullability(NullabilityInfo nullability, Type genericParameter, Type? reflectedType) + if (metaType is not null) { - Debug.Assert(genericParameter.IsGenericParameter); + this.CheckGenericParameters(nullability, metaMember!, metaType, memberInfo.ReflectedType); + } + } - if (reflectedType is not null - && !genericParameter.IsGenericMethodParameter() - && TryUpdateGenericTypeParameterNullabilityFromReflectedType(nullability, genericParameter, reflectedType, reflectedType)) - { - return true; - } + private static MemberInfo GetMemberMetadataDefinition(MemberInfo member) + { + Type? type = member.DeclaringType; + if ((type is not null) && type.IsGenericType && !type.IsGenericTypeDefinition) + { + return NullabilityInfoHelpers.GetMemberWithSameMetadataDefinitionAs(type.GetGenericTypeDefinition(), member); + } + + return member; + } + + private static Type GetPropertyMetaType(PropertyInfo property) + { + if (property.GetGetMethod(true) is MethodInfo method) + { + return method.ReturnType; + } + + return property.GetSetMethod(true)!.GetParameters()[0].ParameterType; + } - if (IsValueTypeOrValueTypeByRef(nullability.Type)) + private void CheckGenericParameters(NullabilityInfo nullability, MemberInfo metaMember, Type metaType, Type? reflectedType) + { + if (metaType.IsGenericParameter) + { + if (nullability.ReadState == NullabilityState.NotNull) { - return true; + this.TryUpdateGenericParameterNullability(nullability, metaType, reflectedType); } + } + else if (metaType.ContainsGenericParameters) + { + if (nullability.GenericTypeArguments.Length > 0) + { + Type[] genericArguments = metaType.GetGenericArguments(); - var state = NullabilityState.Unknown; - if (CreateParser(genericParameter.GetCustomAttributesData()).ParseNullableState(0, ref state)) + for (int i = 0; i < genericArguments.Length; i++) + { + this.CheckGenericParameters(nullability.GenericTypeArguments[i], metaMember, genericArguments[i], reflectedType); + } + } + else if (nullability.ElementType is { } elementNullability && metaType.IsArray) { - nullability.ReadState = state; - nullability.WriteState = state; - return true; + this.CheckGenericParameters(elementNullability, metaMember, metaType.GetElementType()!, reflectedType); } - if (GetNullableContext(genericParameter) is { } contextState) + // We could also follow this branch for metaType.IsPointer, but since pointers must be unmanaged this + // will be a no-op regardless + else if (metaType.IsByRef) { - nullability.ReadState = contextState; - nullability.WriteState = contextState; - return true; + this.CheckGenericParameters(nullability, metaMember, metaType.GetElementType()!, reflectedType); } - - return false; } + } + + private bool TryUpdateGenericParameterNullability(NullabilityInfo nullability, Type genericParameter, Type? reflectedType) + { + Debug.Assert(genericParameter.IsGenericParameter); - private bool TryUpdateGenericTypeParameterNullabilityFromReflectedType(NullabilityInfo nullability, Type genericParameter, Type context, Type reflectedType) + if (reflectedType is not null + && !genericParameter.IsGenericMethodParameter() + && this.TryUpdateGenericTypeParameterNullabilityFromReflectedType(nullability, genericParameter, reflectedType, reflectedType)) { - Debug.Assert(genericParameter.IsGenericParameter && !genericParameter.IsGenericMethodParameter()); + return true; + } - Type contextTypeDefinition = context.IsGenericType && !context.IsGenericTypeDefinition ? context.GetGenericTypeDefinition() : context; - if (genericParameter.DeclaringType == contextTypeDefinition) - { - return false; - } + if (IsValueTypeOrValueTypeByRef(nullability.Type)) + { + return true; + } - Type? baseType = contextTypeDefinition.BaseType; - if (baseType is null) - { - return false; - } + var state = NullabilityState.Unknown; + if (CreateParser(genericParameter.GetCustomAttributesData()).ParseNullableState(0, ref state)) + { + nullability.ReadState = state; + nullability.WriteState = state; + return true; + } - if (!baseType.IsGenericType - || (baseType.IsGenericTypeDefinition ? baseType : baseType.GetGenericTypeDefinition()) != genericParameter.DeclaringType) - { - return TryUpdateGenericTypeParameterNullabilityFromReflectedType(nullability, genericParameter, baseType, reflectedType); - } + if (this.GetNullableContext(genericParameter) is { } contextState) + { + nullability.ReadState = contextState; + nullability.WriteState = contextState; + return true; + } - Type[] genericArguments = baseType.GetGenericArguments(); - Type genericArgument = genericArguments[genericParameter.GenericParameterPosition]; - if (genericArgument.IsGenericParameter) - { - return TryUpdateGenericParameterNullability(nullability, genericArgument, reflectedType); - } + return false; + } - NullableAttributeStateParser parser = CreateParser(contextTypeDefinition.GetCustomAttributesData()); - int nullabilityStateIndex = 1; // start at 1 since index 0 is the type itself - for (int i = 0; i < genericParameter.GenericParameterPosition; i++) - { - nullabilityStateIndex += CountNullabilityStates(genericArguments[i]); - } + private bool TryUpdateGenericTypeParameterNullabilityFromReflectedType(NullabilityInfo nullability, Type genericParameter, Type context, Type reflectedType) + { + Debug.Assert(genericParameter.IsGenericParameter && !genericParameter.IsGenericMethodParameter()); - return TryPopulateNullabilityInfo(nullability, parser, ref nullabilityStateIndex); + Type contextTypeDefinition = context.IsGenericType && !context.IsGenericTypeDefinition ? context.GetGenericTypeDefinition() : context; + if (genericParameter.DeclaringType == contextTypeDefinition) + { + return false; + } - static int CountNullabilityStates(Type type) - { - Type underlyingType = Nullable.GetUnderlyingType(type) ?? type; - if (underlyingType.IsGenericType) - { - int count = 1; - foreach (Type genericArgument in underlyingType.GetGenericArguments()) - { - count += CountNullabilityStates(genericArgument); - } + Type? baseType = contextTypeDefinition.BaseType; + if (baseType is null) + { + return false; + } - return count; - } + if (!baseType.IsGenericType + || (baseType.IsGenericTypeDefinition ? baseType : baseType.GetGenericTypeDefinition()) != genericParameter.DeclaringType) + { + return this.TryUpdateGenericTypeParameterNullabilityFromReflectedType(nullability, genericParameter, baseType, reflectedType); + } - if (underlyingType.HasElementType) - { - return (underlyingType.IsArray ? 1 : 0) + CountNullabilityStates(underlyingType.GetElementType()!); - } + Type[] genericArguments = baseType.GetGenericArguments(); + Type genericArgument = genericArguments[genericParameter.GenericParameterPosition]; + if (genericArgument.IsGenericParameter) + { + return this.TryUpdateGenericParameterNullability(nullability, genericArgument, reflectedType); + } - return type.IsValueType ? 0 : 1; - } + NullableAttributeStateParser parser = CreateParser(contextTypeDefinition.GetCustomAttributesData()); + int nullabilityStateIndex = 1; // start at 1 since index 0 is the type itself + for (int i = 0; i < genericParameter.GenericParameterPosition; i++) + { + nullabilityStateIndex += CountNullabilityStates(genericArguments[i]); } -#pragma warning disable SA1204 // Static elements should appear before instance elements - private static bool TryPopulateNullabilityInfo(NullabilityInfo nullability, NullableAttributeStateParser parser, ref int index) -#pragma warning restore SA1204 // Static elements should appear before instance elements + return TryPopulateNullabilityInfo(nullability, parser, ref nullabilityStateIndex); + + static int CountNullabilityStates(Type type) { - bool isValueType = IsValueTypeOrValueTypeByRef(nullability.Type); - if (!isValueType) + Type underlyingType = Nullable.GetUnderlyingType(type) ?? type; + if (underlyingType.IsGenericType) { - var state = NullabilityState.Unknown; - if (!parser.ParseNullableState(index, ref state)) + int count = 1; + foreach (Type genericArgument in underlyingType.GetGenericArguments()) { - return false; + count += CountNullabilityStates(genericArgument); } - nullability.ReadState = state; - nullability.WriteState = state; + return count; } - if (!isValueType || (Nullable.GetUnderlyingType(nullability.Type) ?? nullability.Type).IsGenericType) + if (underlyingType.HasElementType) { - index++; + return (underlyingType.IsArray ? 1 : 0) + CountNullabilityStates(underlyingType.GetElementType()!); } - if (nullability.GenericTypeArguments.Length > 0) - { - foreach (NullabilityInfo genericTypeArgumentNullability in nullability.GenericTypeArguments) - { - TryPopulateNullabilityInfo(genericTypeArgumentNullability, parser, ref index); - } - } - else if (nullability.ElementType is { } elementTypeNullability) + return type.IsValueType ? 0 : 1; + } + } + +#pragma warning disable SA1204 // Static elements should appear before instance elements + private static bool TryPopulateNullabilityInfo(NullabilityInfo nullability, NullableAttributeStateParser parser, ref int index) +#pragma warning restore SA1204 // Static elements should appear before instance elements + { + bool isValueType = IsValueTypeOrValueTypeByRef(nullability.Type); + if (!isValueType) + { + var state = NullabilityState.Unknown; + if (!parser.ParseNullableState(index, ref state)) { - TryPopulateNullabilityInfo(elementTypeNullability, parser, ref index); + return false; } - return true; + nullability.ReadState = state; + nullability.WriteState = state; } - private static NullabilityState TranslateByte(object? value) + if (!isValueType || (Nullable.GetUnderlyingType(nullability.Type) ?? nullability.Type).IsGenericType) { - return value is byte b ? TranslateByte(b) : NullabilityState.Unknown; + index++; } - private static NullabilityState TranslateByte(byte b) => - b switch + if (nullability.GenericTypeArguments.Length > 0) + { + foreach (NullabilityInfo genericTypeArgumentNullability in nullability.GenericTypeArguments) { - 1 => NullabilityState.NotNull, - 2 => NullabilityState.Nullable, - _ => NullabilityState.Unknown - }; + TryPopulateNullabilityInfo(genericTypeArgumentNullability, parser, ref index); + } + } + else if (nullability.ElementType is { } elementTypeNullability) + { + TryPopulateNullabilityInfo(elementTypeNullability, parser, ref index); + } + + return true; + } - private static bool IsValueTypeOrValueTypeByRef(Type type) => - type.IsValueType || ((type.IsByRef || type.IsPointer) && type.GetElementType()!.IsValueType); + private static NullabilityState TranslateByte(object? value) + { + return value is byte b ? TranslateByte(b) : NullabilityState.Unknown; + } - private readonly struct NullableAttributeStateParser + private static NullabilityState TranslateByte(byte b) => + b switch { - private static readonly object UnknownByte = (byte)0; + 1 => NullabilityState.NotNull, + 2 => NullabilityState.Nullable, + _ => NullabilityState.Unknown + }; - private readonly object? _nullableAttributeArgument; + private static bool IsValueTypeOrValueTypeByRef(Type type) => + type.IsValueType || ((type.IsByRef || type.IsPointer) && type.GetElementType()!.IsValueType); - public NullableAttributeStateParser(object? nullableAttributeArgument) - { - this._nullableAttributeArgument = nullableAttributeArgument; - } + private readonly struct NullableAttributeStateParser + { + private static readonly object UnknownByte = (byte)0; - public static NullableAttributeStateParser Unknown => new(UnknownByte); + private readonly object? _nullableAttributeArgument; - public bool ParseNullableState(int index, ref NullabilityState state) - { - switch (this._nullableAttributeArgument) - { - case byte b: - state = TranslateByte(b); - return true; - case ReadOnlyCollection args - when index < args.Count && args[index].Value is byte elementB: - state = TranslateByte(elementB); - return true; - default: - return false; - } + public NullableAttributeStateParser(object? nullableAttributeArgument) + { + this._nullableAttributeArgument = nullableAttributeArgument; + } + + public static NullableAttributeStateParser Unknown => new(UnknownByte); + + public bool ParseNullableState(int index, ref NullabilityState state) + { + switch (this._nullableAttributeArgument) + { + case byte b: + state = TranslateByte(b); + return true; + case ReadOnlyCollection args + when index < args.Count && args[index].Value is byte elementB: + state = TranslateByte(elementB); + return true; + default: + return false; } } } diff --git a/dotnet/src/InternalUtilities/src/Schema/Polyfills/NullabilityInfoHelpers.cs b/dotnet/src/InternalUtilities/src/Schema/Polyfills/NullabilityInfoHelpers.cs index 31c891fb4595..61e7afb9cff5 100644 --- a/dotnet/src/InternalUtilities/src/Schema/Polyfills/NullabilityInfoHelpers.cs +++ b/dotnet/src/InternalUtilities/src/Schema/Polyfills/NullabilityInfoHelpers.cs @@ -3,41 +3,40 @@ #if !NET6_0_OR_GREATER using System.Diagnostics.CodeAnalysis; -namespace System.Reflection +namespace System.Reflection; + +/// +/// Polyfills for System.Private.CoreLib internals. +/// +[ExcludeFromCodeCoverage] +internal static class NullabilityInfoHelpers { - /// - /// Polyfills for System.Private.CoreLib internals. - /// - [ExcludeFromCodeCoverage] - internal static class NullabilityInfoHelpers + public static MemberInfo GetMemberWithSameMetadataDefinitionAs(Type type, MemberInfo member) { - public static MemberInfo GetMemberWithSameMetadataDefinitionAs(Type type, MemberInfo member) + const BindingFlags all = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance; + foreach (var info in type.GetMembers(all)) { - const BindingFlags all = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance; - foreach (var info in type.GetMembers(all)) + if (info.HasSameMetadataDefinitionAs(member)) { - if (info.HasSameMetadataDefinitionAs(member)) - { - return info; - } + return info; } - - throw new MissingMemberException(type.FullName, member.Name); } - // https://github.com/dotnet/runtime/blob/main/src/coreclr/System.Private.CoreLib/src/System/Reflection/MemberInfo.Internal.cs - public static bool HasSameMetadataDefinitionAs(this MemberInfo target, MemberInfo other) - { - return target.MetadataToken == other.MetadataToken && - target.Module.Equals(other.Module); - } + throw new MissingMemberException(type.FullName, member.Name); + } - // https://github.com/dotnet/runtime/issues/23493 - public static bool IsGenericMethodParameter(this Type target) - { - return target.IsGenericParameter && - target.DeclaringMethod is not null; - } + // https://github.com/dotnet/runtime/blob/main/src/coreclr/System.Private.CoreLib/src/System/Reflection/MemberInfo.Internal.cs + public static bool HasSameMetadataDefinitionAs(this MemberInfo target, MemberInfo other) + { + return target.MetadataToken == other.MetadataToken && + target.Module.Equals(other.Module); + } + + // https://github.com/dotnet/runtime/issues/23493 + public static bool IsGenericMethodParameter(this Type target) + { + return target.IsGenericParameter && + target.DeclaringMethod is not null; } } #endif