Skip to content

Implement nullable analysis for field keyword #75244

Closed
@RikkiGibson

Description

@RikkiGibson

#57012
dotnet/csharplang#8425

Tracks implementation of short-term nullability solution for field keyword in properties.

Calling out a few areas to change to implement set enforcement (not part of the initial PR, but maybe we will do it as a stretch goal):

else
{
do
{
foreach (var memberName in method.NotNullMembers)
{
enforceMemberNotNullOnMember(syntaxOpt, state, method, memberName);
}
method = method.OverriddenMethod;
}
while (method != null);
}

                     else
                     {
+                        if (method is SourcePropertyAccessorSymbol
+                            {
+                                MethodKind: MethodKind.PropertySet,
+                                AssociatedSymbol: SourcePropertySymbolBase { UsesFieldKeyword: true, BackingField: { } backingField }
+                            })
+                        {
+                            if (memberHasBadState(member, state))
+                            {
+                                // Member '{name}' must have a non-null value when exiting.
+                                Diagnostics.Add(ErrorCode.WRN_MemberNotNull, syntaxOpt?.GetLocation() ?? methodMainNode.Syntax.GetLastToken().GetLocation(), member.Name);
+                            }
+                        }

                         do
                         {
                             foreach (var memberName in method.NotNullMembers)
                             {
                                 enforceMemberNotNullOnMember(syntaxOpt, state, method, memberName);
                             }
 
                             method = method.OverriddenMethod;
                         }
                         while (method != null);
                     }

else
{
do
{
makeMembersMaybeNull(method, method.NotNullMembers);
makeMembersMaybeNull(method, method.NotNullWhenTrueMembers);
makeMembersMaybeNull(method, method.NotNullWhenFalseMembers);
method = method.OverriddenMethod;
}
while (method != null);
}

                     else
                     {
+                        if (method is SourcePropertyAccessorSymbol
+                            {
+                                MethodKind: MethodKind.PropertySet,
+                                AssociatedSymbol: SourcePropertySymbolBase { UsesFieldKeyword: true, BackingField: { } backingField }
+                            })
+                        {
+                            // https://github.com/dotnet/csharplang/blob/main/proposals/field-keyword.md#setter-analysis
+                            // setter assumes the backing field may be null and has to put the field into the correct state when exiting.
+                            if (getSlotForFieldOrPropertyOrEvent(backingField) is int memberSlot &&
+                                memberSlot > 0)
+                            {
+                                SetState(ref this.State, memberSlot, NullableFlowState.MaybeNull);
+                            }
+                        }

                         do
                         {
                             makeMembersMaybeNull(method, method.NotNullMembers);
                             makeMembersMaybeNull(method, method.NotNullWhenTrueMembers);
                             makeMembersMaybeNull(method, method.NotNullWhenFalseMembers);
                             method = method.OverriddenMethod;
                         }
                         while (method != null);
                     }

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions