Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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<CustomAttributeData> 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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1471,6 +1471,24 @@ public void TestMethodsWithGenericParameters(Delegate @delegate, NullabilityStat
Assert.Equal(expectedRead, info.ReadState);
Assert.Equal(expectedWrite, info.WriteState);
}

public static IEnumerable<object[]> 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
Expand Down Expand Up @@ -1806,4 +1824,22 @@ public class ClassWithGenericMethods_Allow
public static void GenericMethod<T>([AllowNull] T value) => throw new Exception();
public static void GenericNotNullMethod<T>([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; }
}
}
Loading