NullabilityInfoContext
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace System.Reflection
{
internal sealed class NullabilityInfoContext
{
[Flags]
private enum NotAnnotatedStatus
{
None = 0,
Private = 1,
Internal = 2
}
private readonly struct NullableAttributeStateParser
{
private static readonly object UnknownByte = (byte)0;
private readonly object _nullableAttributeArgument;
public static NullableAttributeStateParser Unknown => new NullableAttributeStateParser(UnknownByte);
public NullableAttributeStateParser(object nullableAttributeArgument)
{
_nullableAttributeArgument = nullableAttributeArgument;
}
public bool ParseNullableState(int index, ref System.Reflection.NullabilityState state)
{
object nullableAttributeArgument = _nullableAttributeArgument;
if (nullableAttributeArgument is byte) {
byte b = (byte)nullableAttributeArgument;
byte b2 = b;
state = TranslateByte(b2);
return true;
}
ReadOnlyCollection<CustomAttributeTypedArgument> readOnlyCollection = nullableAttributeArgument as ReadOnlyCollection<CustomAttributeTypedArgument>;
if (readOnlyCollection != null) {
ReadOnlyCollection<CustomAttributeTypedArgument> readOnlyCollection2 = readOnlyCollection;
if (index < readOnlyCollection2.Count) {
object value = readOnlyCollection2[index].Value;
if (value is byte) {
byte b3 = (byte)value;
state = TranslateByte(b3);
return true;
}
}
}
return false;
}
}
private const string CompilerServicesNameSpace = "System.Runtime.CompilerServices";
private readonly Dictionary<Module, NotAnnotatedStatus> _publicOnlyModules = new Dictionary<Module, NotAnnotatedStatus>();
private readonly Dictionary<MemberInfo, System.Reflection.NullabilityState> _context = new Dictionary<MemberInfo, System.Reflection.NullabilityState>();
private System.Reflection.NullabilityState? GetNullableContext(MemberInfo memberInfo)
{
while (memberInfo != (MemberInfo)null) {
if (_context.TryGetValue(memberInfo, out System.Reflection.NullabilityState value))
return value;
foreach (CustomAttributeData customAttributesDatum in memberInfo.GetCustomAttributesData()) {
if (customAttributesDatum.AttributeType.Name == "NullableContextAttribute" && customAttributesDatum.AttributeType.Namespace == "System.Runtime.CompilerServices" && customAttributesDatum.ConstructorArguments.Count == 1) {
value = TranslateByte(customAttributesDatum.ConstructorArguments[0].Value);
_context.Add(memberInfo, value);
return value;
}
}
memberInfo = memberInfo.DeclaringType;
}
return null;
}
public System.Reflection.NullabilityInfo Create(ParameterInfo parameterInfo)
{
System.ExceptionPolyfills.ThrowIfNull(parameterInfo, "parameterInfo");
IList<CustomAttributeData> customAttributesData = parameterInfo.GetCustomAttributesData();
MethodBase methodBase = parameterInfo.Member as MethodBase;
NullableAttributeStateParser parser = ((object)methodBase != null && IsPrivateOrInternalMethodAndAnnotationDisabled(methodBase)) ? NullableAttributeStateParser.Unknown : CreateParser(customAttributesData);
System.Reflection.NullabilityInfo nullabilityInfo = GetNullabilityInfo(parameterInfo.Member, parameterInfo.ParameterType, parser);
if (nullabilityInfo.ReadState != 0)
CheckParameterMetadataType(parameterInfo, nullabilityInfo);
CheckNullabilityAttributes(nullabilityInfo, customAttributesData);
return nullabilityInfo;
}
private void CheckParameterMetadataType(ParameterInfo parameter, System.Reflection.NullabilityInfo nullability)
{
MemberInfo member = parameter.Member;
ConstructorInfo constructorInfo = member as ConstructorInfo;
MemberInfo metaMember;
ParameterInfo parameterInfo;
if ((object)constructorInfo == null) {
MethodInfo methodInfo = member as MethodInfo;
if ((object)methodInfo == null)
return;
MethodInfo methodMetadataDefinition = GetMethodMetadataDefinition(methodInfo);
metaMember = methodMetadataDefinition;
parameterInfo = (string.IsNullOrEmpty(parameter.Name) ? methodMetadataDefinition.ReturnParameter : GetMetaParameter(methodMetadataDefinition, parameter));
} else
parameterInfo = GetMetaParameter((MethodBase)(metaMember = (ConstructorInfo)GetMemberMetadataDefinition(constructorInfo)), parameter);
if (parameterInfo != null)
CheckGenericParameters(nullability, metaMember, parameterInfo.ParameterType, parameter.Member.ReflectedType);
}
private static ParameterInfo GetMetaParameter(MethodBase metaMethod, ParameterInfo parameter)
{
ReadOnlySpan<ParameterInfo> parametersAsSpan = metaMethod.GetParametersAsSpan();
for (int i = 0; i < parametersAsSpan.Length; i++) {
if (parameter.Position == i && parameter.Name == parametersAsSpan[i].Name)
return parametersAsSpan[i];
}
return null;
}
private static MethodInfo GetMethodMetadataDefinition(MethodInfo method)
{
if (method.IsGenericMethod && !method.IsGenericMethodDefinition)
method = method.GetGenericMethodDefinition();
return (MethodInfo)GetMemberMetadataDefinition(method);
}
private static void CheckNullabilityAttributes(System.Reflection.NullabilityInfo nullability, IList<CustomAttributeData> attributes)
{
System.Reflection.NullabilityState nullabilityState = System.Reflection.NullabilityState.Unknown;
System.Reflection.NullabilityState nullabilityState2 = System.Reflection.NullabilityState.Unknown;
foreach (CustomAttributeData attribute in attributes) {
if (attribute.AttributeType.Namespace == "System.Diagnostics.CodeAnalysis") {
if (attribute.AttributeType.Name == "NotNullAttribute")
nullabilityState = System.Reflection.NullabilityState.NotNull;
else if ((attribute.AttributeType.Name == "MaybeNullAttribute" || attribute.AttributeType.Name == "MaybeNullWhenAttribute") && nullabilityState == System.Reflection.NullabilityState.Unknown && !IsValueTypeOrValueTypeByRef(nullability.Type)) {
nullabilityState = System.Reflection.NullabilityState.Nullable;
} else if (attribute.AttributeType.Name == "DisallowNullAttribute") {
nullabilityState2 = System.Reflection.NullabilityState.NotNull;
} else if (attribute.AttributeType.Name == "AllowNullAttribute" && nullabilityState2 == System.Reflection.NullabilityState.Unknown && !IsValueTypeOrValueTypeByRef(nullability.Type)) {
nullabilityState2 = System.Reflection.NullabilityState.Nullable;
}
}
}
if (nullabilityState != 0)
nullability.ReadState = nullabilityState;
if (nullabilityState2 != 0)
nullability.WriteState = nullabilityState2;
}
public System.Reflection.NullabilityInfo Create(PropertyInfo propertyInfo)
{
System.ExceptionPolyfills.ThrowIfNull(propertyInfo, "propertyInfo");
MethodInfo getMethod = propertyInfo.GetGetMethod(true);
MethodInfo setMethod = propertyInfo.GetSetMethod(true);
NullableAttributeStateParser parser = ((getMethod == (MethodInfo)null || IsPrivateOrInternalMethodAndAnnotationDisabled(getMethod)) && (setMethod == (MethodInfo)null || IsPrivateOrInternalMethodAndAnnotationDisabled(setMethod))) ? NullableAttributeStateParser.Unknown : CreateParser(propertyInfo.GetCustomAttributesData());
System.Reflection.NullabilityInfo nullabilityInfo = GetNullabilityInfo(propertyInfo, propertyInfo.PropertyType, parser);
if (getMethod != (MethodInfo)null)
CheckNullabilityAttributes(nullabilityInfo, getMethod.ReturnParameter.GetCustomAttributesData());
else
nullabilityInfo.ReadState = System.Reflection.NullabilityState.Unknown;
if (setMethod != (MethodInfo)null) {
ReadOnlySpan<ParameterInfo> parametersAsSpan = setMethod.GetParametersAsSpan();
ParameterInfo parameterInfo = parametersAsSpan[parametersAsSpan.Length - 1];
CheckNullabilityAttributes(nullabilityInfo, parameterInfo.GetCustomAttributesData());
} else
nullabilityInfo.WriteState = System.Reflection.NullabilityState.Unknown;
return nullabilityInfo;
}
private bool IsPrivateOrInternalMethodAndAnnotationDisabled(MethodBase method)
{
if ((method.IsPrivate || method.IsFamilyAndAssembly || method.IsAssembly) && IsPublicOnly(method.IsPrivate, method.IsFamilyAndAssembly, method.IsAssembly, method.Module))
return true;
return false;
}
public System.Reflection.NullabilityInfo Create(EventInfo eventInfo)
{
System.ExceptionPolyfills.ThrowIfNull(eventInfo, "eventInfo");
return GetNullabilityInfo(eventInfo, eventInfo.EventHandlerType, CreateParser(eventInfo.GetCustomAttributesData()));
}
public System.Reflection.NullabilityInfo Create(FieldInfo fieldInfo)
{
System.ExceptionPolyfills.ThrowIfNull(fieldInfo, "fieldInfo");
IList<CustomAttributeData> customAttributesData = fieldInfo.GetCustomAttributesData();
NullableAttributeStateParser parser = IsPrivateOrInternalFieldAndAnnotationDisabled(fieldInfo) ? NullableAttributeStateParser.Unknown : CreateParser(customAttributesData);
System.Reflection.NullabilityInfo nullabilityInfo = GetNullabilityInfo(fieldInfo, fieldInfo.FieldType, parser);
CheckNullabilityAttributes(nullabilityInfo, customAttributesData);
return nullabilityInfo;
}
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;
}
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);
}
if (value == NotAnnotatedStatus.None)
return false;
if (((isPrivate | isFamilyAndAssembly) && value.HasFlag(NotAnnotatedStatus.Private)) || (isAssembly && value.HasFlag(NotAnnotatedStatus.Internal)))
return true;
return false;
}
private static NotAnnotatedStatus PopulateAnnotationInfo(IList<CustomAttributeData> customAttributes)
{
foreach (CustomAttributeData customAttribute in customAttributes) {
if (customAttribute.AttributeType.Name == "NullablePublicOnlyAttribute" && customAttribute.AttributeType.Namespace == "System.Runtime.CompilerServices" && customAttribute.ConstructorArguments.Count == 1) {
object value = customAttribute.ConstructorArguments[0].Value;
bool flag = default(bool);
int num;
if (value is bool) {
flag = (bool)value;
num = 1;
} else
num = 0;
if ((num & (flag ? 1 : 0)) == 0)
return NotAnnotatedStatus.Private;
return NotAnnotatedStatus.Private | NotAnnotatedStatus.Internal;
}
}
return NotAnnotatedStatus.None;
}
private System.Reflection.NullabilityInfo GetNullabilityInfo(MemberInfo memberInfo, Type type, NullableAttributeStateParser parser)
{
int index = 0;
System.Reflection.NullabilityInfo nullabilityInfo = GetNullabilityInfo(memberInfo, type, parser, ref index);
if (nullabilityInfo.ReadState != 0)
TryLoadGenericMetaTypeNullability(memberInfo, nullabilityInfo);
return nullabilityInfo;
}
private System.Reflection.NullabilityInfo GetNullabilityInfo(MemberInfo memberInfo, Type type, NullableAttributeStateParser parser, ref int index)
{
System.Reflection.NullabilityState state = System.Reflection.NullabilityState.Unknown;
System.Reflection.NullabilityInfo elementType = null;
System.Reflection.NullabilityInfo[] array = Array.Empty<System.Reflection.NullabilityInfo>();
Type type2 = type;
if (type2.IsByRef || type2.IsPointer)
type2 = type2.GetElementType();
if (type2.IsValueType) {
Type underlyingType = Nullable.GetUnderlyingType(type2);
if ((object)underlyingType != null) {
type2 = underlyingType;
state = System.Reflection.NullabilityState.Nullable;
} else
state = System.Reflection.NullabilityState.NotNull;
if (type2.IsGenericType)
index++;
} else {
if (!parser.ParseNullableState(index++, ref state)) {
System.Reflection.NullabilityState? nullableContext = GetNullableContext(memberInfo);
if (nullableContext.HasValue) {
System.Reflection.NullabilityState valueOrDefault = nullableContext.GetValueOrDefault();
state = valueOrDefault;
}
}
if (type2.IsArray)
elementType = GetNullabilityInfo(memberInfo, type2.GetElementType(), parser, ref index);
}
if (type2.IsGenericType) {
Type[] genericArguments = type2.GetGenericArguments();
array = new System.Reflection.NullabilityInfo[genericArguments.Length];
for (int i = 0; i < genericArguments.Length; i++) {
array[i] = GetNullabilityInfo(memberInfo, genericArguments[i], parser, ref index);
}
}
return new System.Reflection.NullabilityInfo(type, state, state, elementType, array);
}
private static NullableAttributeStateParser CreateParser(IList<CustomAttributeData> customAttributes)
{
foreach (CustomAttributeData customAttribute in customAttributes) {
if (customAttribute.AttributeType.Name == "NullableAttribute" && customAttribute.AttributeType.Namespace == "System.Runtime.CompilerServices" && customAttribute.ConstructorArguments.Count == 1)
return new NullableAttributeStateParser(customAttribute.ConstructorArguments[0].Value);
}
return new NullableAttributeStateParser(null);
}
private void TryLoadGenericMetaTypeNullability(MemberInfo memberInfo, System.Reflection.NullabilityInfo nullability)
{
MemberInfo memberMetadataDefinition = GetMemberMetadataDefinition(memberInfo);
Type type = null;
FieldInfo fieldInfo = memberMetadataDefinition as FieldInfo;
if ((object)fieldInfo != null)
type = fieldInfo.FieldType;
else {
PropertyInfo propertyInfo = memberMetadataDefinition as PropertyInfo;
if ((object)propertyInfo != null)
type = GetPropertyMetaType(propertyInfo);
}
if (type != (Type)null)
CheckGenericParameters(nullability, memberMetadataDefinition, type, memberInfo.ReflectedType);
}
private static MemberInfo GetMemberMetadataDefinition(MemberInfo member)
{
Type declaringType = member.DeclaringType;
if (declaringType != (Type)null && declaringType.IsGenericType && !declaringType.IsGenericTypeDefinition)
return NetstandardHelpers.GetMemberWithSameMetadataDefinitionAs(declaringType.GetGenericTypeDefinition(), member);
return member;
}
private static Type GetPropertyMetaType(PropertyInfo property)
{
MethodInfo getMethod = property.GetGetMethod(true);
if ((object)getMethod != null)
return getMethod.ReturnType;
return property.GetSetMethod(true).GetParametersAsSpan()[0].ParameterType;
}
private void CheckGenericParameters(System.Reflection.NullabilityInfo nullability, MemberInfo metaMember, Type metaType, Type reflectedType)
{
if (metaType.IsGenericParameter) {
if (nullability.ReadState == System.Reflection.NullabilityState.NotNull)
TryUpdateGenericParameterNullability(nullability, metaType, reflectedType);
} 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 {
System.Reflection.NullabilityInfo elementType = nullability.ElementType;
if (elementType != null && metaType.IsArray)
CheckGenericParameters(elementType, metaMember, metaType.GetElementType(), reflectedType);
else if (metaType.IsByRef) {
CheckGenericParameters(nullability, metaMember, metaType.GetElementType(), reflectedType);
}
}
}
}
private bool TryUpdateGenericParameterNullability(System.Reflection.NullabilityInfo nullability, Type genericParameter, Type reflectedType)
{
if ((object)reflectedType != null && !genericParameter.IsGenericMethodParameter() && TryUpdateGenericTypeParameterNullabilityFromReflectedType(nullability, genericParameter, reflectedType, reflectedType))
return true;
if (IsValueTypeOrValueTypeByRef(nullability.Type))
return true;
System.Reflection.NullabilityState state = System.Reflection.NullabilityState.Unknown;
if (CreateParser(genericParameter.GetCustomAttributesData()).ParseNullableState(0, ref state)) {
nullability.ReadState = state;
nullability.WriteState = state;
return true;
}
System.Reflection.NullabilityState? nullableContext = GetNullableContext(genericParameter);
if (nullableContext.HasValue) {
System.Reflection.NullabilityState nullabilityState2 = nullability.WriteState = (nullability.ReadState = nullableContext.GetValueOrDefault());
return true;
}
return false;
}
private bool TryUpdateGenericTypeParameterNullabilityFromReflectedType(System.Reflection.NullabilityInfo nullability, Type genericParameter, Type context, Type reflectedType)
{
Type type = (context.IsGenericType && !context.IsGenericTypeDefinition) ? context.GetGenericTypeDefinition() : context;
if (genericParameter.DeclaringType == type)
return false;
Type baseType = type.BaseType;
if ((object)baseType == null)
return false;
if (!baseType.IsGenericType || (baseType.IsGenericTypeDefinition ? baseType : baseType.GetGenericTypeDefinition()) != genericParameter.DeclaringType)
return TryUpdateGenericTypeParameterNullabilityFromReflectedType(nullability, genericParameter, baseType, reflectedType);
Type[] genericArguments = baseType.GetGenericArguments();
Type type2 = genericArguments[genericParameter.GenericParameterPosition];
if (type2.IsGenericParameter)
return TryUpdateGenericParameterNullability(nullability, type2, reflectedType);
NullableAttributeStateParser parser = CreateParser(type.GetCustomAttributesData());
int index = 1;
for (int i = 0; i < genericParameter.GenericParameterPosition; i++) {
index += <TryUpdateGenericTypeParameterNullabilityFromReflectedType>g__CountNullabilityStates|25_0(genericArguments[i]);
}
return TryPopulateNullabilityInfo(nullability, parser, ref index);
}
private static bool TryPopulateNullabilityInfo(System.Reflection.NullabilityInfo nullability, NullableAttributeStateParser parser, ref int index)
{
bool flag = IsValueTypeOrValueTypeByRef(nullability.Type);
if (!flag) {
System.Reflection.NullabilityState state = System.Reflection.NullabilityState.Unknown;
if (!parser.ParseNullableState(index, ref state))
return false;
nullability.ReadState = state;
nullability.WriteState = state;
}
if (!flag || (Nullable.GetUnderlyingType(nullability.Type) ?? nullability.Type).IsGenericType)
index++;
if (nullability.GenericTypeArguments.Length != 0) {
System.Reflection.NullabilityInfo[] genericTypeArguments = nullability.GenericTypeArguments;
for (int i = 0; i < genericTypeArguments.Length; i++) {
TryPopulateNullabilityInfo(genericTypeArguments[i], parser, ref index);
}
} else {
System.Reflection.NullabilityInfo elementType = nullability.ElementType;
if (elementType != null)
TryPopulateNullabilityInfo(elementType, parser, ref index);
}
return true;
}
private static System.Reflection.NullabilityState TranslateByte(object value)
{
if (!(value is byte))
return System.Reflection.NullabilityState.Unknown;
byte b = (byte)value;
return TranslateByte(b);
}
private static System.Reflection.NullabilityState TranslateByte(byte b)
{
switch (b) {
case 1:
return System.Reflection.NullabilityState.NotNull;
case 2:
return System.Reflection.NullabilityState.Nullable;
default:
return System.Reflection.NullabilityState.Unknown;
}
}
private static bool IsValueTypeOrValueTypeByRef(Type type)
{
if (!type.IsValueType) {
if (type.IsByRef || type.IsPointer)
return type.GetElementType().IsValueType;
return false;
}
return true;
}
}
}