diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/NullabilityInfoContext.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/NullabilityInfoContext.cs index b2956b14e1bf98..8d3f9d862e888a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/NullabilityInfoContext.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/NullabilityInfoContext.cs @@ -69,10 +69,30 @@ public NullabilityInfo Create(ParameterInfo parameterInfo) { ArgumentNullException.ThrowIfNull(parameterInfo); + bool annotationsDisabled = false; + if (parameterInfo.Member is PropertyInfo propertyInfo) + { + // For property indexers, switch to the respective getter/setter parameter. + if (propertyInfo.GetGetMethod(true) is { } getter && !IsPrivateOrInternalMethodAndAnnotationDisabled(getter)) + { + parameterInfo = getter.GetParametersAsSpan()[parameterInfo.Position]; + } + else if (propertyInfo.GetSetMethod(true) is { } setter && !IsPrivateOrInternalMethodAndAnnotationDisabled(setter)) + { + parameterInfo = setter.GetParametersAsSpan()[parameterInfo.Position]; + } + else + { + annotationsDisabled = true; + } + } + else if (parameterInfo.Member is MethodBase method) + { + annotationsDisabled = IsPrivateOrInternalMethodAndAnnotationDisabled(method); + } + IList attributes = parameterInfo.GetCustomAttributesData(); - NullableAttributeStateParser parser = parameterInfo.Member is MethodBase method && IsPrivateOrInternalMethodAndAnnotationDisabled(method) - ? NullableAttributeStateParser.Unknown - : CreateParser(attributes); + NullableAttributeStateParser parser = annotationsDisabled ? NullableAttributeStateParser.Unknown : CreateParser(attributes); NullabilityInfo nullability = GetNullabilityInfo(parameterInfo.Member, parameterInfo.ParameterType, parser); if (nullability.ReadState != NullabilityState.Unknown) diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Reflection/NullabilityInfoContextTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Reflection/NullabilityInfoContextTests.cs index 25e80df1fa867e..d20d7b50831906 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Reflection/NullabilityInfoContextTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Reflection/NullabilityInfoContextTests.cs @@ -1471,6 +1471,24 @@ public void TestMethodsWithGenericParameters(Delegate @delegate, NullabilityStat Assert.Equal(expectedRead, info.ReadState); Assert.Equal(expectedWrite, info.WriteState); } + + public static IEnumerable TestClassesWithIndexers() => new object[][] + { + [typeof(ClassWithOnlyIndexedGetProperty), "Item", NullabilityState.NotNull, NullabilityState.NotNull], + [typeof(ClassWithIndexedGetPropertyAndTupleProperty), "Item", NullabilityState.NotNull, NullabilityState.NotNull], + [typeof(ClassWithOnlyIndexedSetProperty), "Item", NullabilityState.NotNull, NullabilityState.NotNull], + [typeof(ClassWithIndexedSetPropertyAndTupleProperty), "Item", NullabilityState.NotNull, NullabilityState.NotNull], + }; + + [Theory] + [MemberData(nameof(TestClassesWithIndexers))] + public void TestPropertyIndexer(Type type, string propertyName, NullabilityState expectedRead, NullabilityState expectedWrite) + { + PropertyInfo property = type.GetProperty(propertyName)!; + NullabilityInfo info = nullabilityContext.Create(property.GetIndexParameters()[0]); + Assert.Equal(expectedRead, info.ReadState); + Assert.Equal(expectedWrite, info.WriteState); + } } #pragma warning disable CS0649, CS0067, CS0414 @@ -1806,4 +1824,22 @@ public class ClassWithGenericMethods_Allow public static void GenericMethod([AllowNull] T value) => throw new Exception(); public static void GenericNotNullMethod([AllowNull] T value) where T : notnull => throw new Exception(); } + public class ClassWithOnlyIndexedGetProperty + { + public string this[string name] { get => throw new Exception(); } + } + public class ClassWithIndexedGetPropertyAndTupleProperty + { + public string this[string name] { get => throw new Exception(); } + public (int A, int B) ValueTupleProp { get; } + } + public class ClassWithOnlyIndexedSetProperty + { + public string this[string name] { set => throw new Exception(); } + } + public class ClassWithIndexedSetPropertyAndTupleProperty + { + public string this[string name] { set => throw new Exception(); } + public (int A, int B) ValueTupleProp { get; } + } }