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