Skip to content

Commit

Permalink
Fix constructor exit warnings for generic NotNull (#49841)
Browse files Browse the repository at this point in the history
  • Loading branch information
RikkiGibson authored Dec 10, 2020
1 parent eed178a commit 18c645c
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 2 deletions.
6 changes: 4 additions & 2 deletions src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -644,8 +644,10 @@ void checkMemberStateOnConstructorExit(MethodSymbol constructor, Symbol member,
}

var memberState = state[slot];
var badState = fieldType.Type.IsPossiblyNullableReferenceTypeTypeParameter() ? NullableFlowState.MaybeDefault : NullableFlowState.MaybeNull;
if (memberState == badState)
var badState = fieldType.Type.IsPossiblyNullableReferenceTypeTypeParameter() && (annotations & FlowAnalysisAnnotations.NotNull) == 0
? NullableFlowState.MaybeDefault
: NullableFlowState.MaybeNull;
if (memberState >= badState) // is 'memberState' as bad as or worse than 'badState'?
{
Diagnostics.Add(ErrorCode.WRN_UninitializedNonNullableField, exitLocation ?? symbol.Locations.FirstOrNone(), symbol.Kind.Localize(), symbol.Name);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28846,6 +28846,88 @@ public C([NotNull] out string? pOut)
Diagnostic(ErrorCode.WRN_ParameterDisallowsNull, "}").WithArguments("pOut").WithLocation(8, 5));
}

[Theory, WorkItem(48996, "https://github.com/dotnet/roslyn/issues/48996")]
[InlineData("")]
[InlineData("where T : class?")]
public void NotNullProperty_Constructor(string constraints)
{
var source = @"
#nullable enable
using System.Diagnostics.CodeAnalysis;

class C<T> " + constraints + @"
{
[NotNull] public T Prop { get; set; }

public C() { } // 1
public C(T t) { Prop = t; } // 2
public C(T t, int x) { Prop = t; Prop.ToString(); } // 3
public C([DisallowNull] T t, int x, int y) { Prop = t; }

[MemberNotNull(nameof(Prop))]
public void Init(T t)
{
Prop = t;
} // 4
}
";
var comp = CreateNullableCompilation(new[] { source, NotNullAttributeDefinition, MemberNotNullAttributeDefinition, DisallowNullAttributeDefinition });
comp.VerifyDiagnostics(
// (9,12): warning CS8618: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
// public C() { } // 1
Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "C").WithArguments("property", "Prop").WithLocation(9, 12),
// (10,12): warning CS8618: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
// public C(T t) { Prop = t; } // 2
Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "C").WithArguments("property", "Prop").WithLocation(10, 12),
// (11,38): warning CS8602: Dereference of a possibly null reference.
// public C(T t, int x) { Prop = t; Prop.ToString(); } // 3
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "Prop").WithLocation(11, 38),
// (18,5): warning CS8774: Member 'Prop' must have a non-null value when exiting.
// } // 4
Diagnostic(ErrorCode.WRN_MemberNotNull, "}").WithArguments("Prop").WithLocation(18, 5));
}

[Theory, WorkItem(48996, "https://github.com/dotnet/roslyn/issues/48996")]
[InlineData("")]
[InlineData("where T : class?")]
public void NotNullField_Constructor(string constraints)
{
var source = @"
#nullable enable
using System.Diagnostics.CodeAnalysis;

class C<T> " + constraints + @"
{
[NotNull] public T field;

public C() { } // 1
public C(T t) { field = t; } // 2
public C(T t, int x) { field = t; field.ToString(); } // 3
public C([DisallowNull] T t, int x, int y) { field = t; }

[MemberNotNull(nameof(field))]
public void Init(T t)
{
field = t;
} // 4
}
";
var comp = CreateNullableCompilation(new[] { source, NotNullAttributeDefinition, MemberNotNullAttributeDefinition, DisallowNullAttributeDefinition });
comp.VerifyDiagnostics(
// (9,12): warning CS8618: Non-nullable field 'field' must contain a non-null value when exiting constructor. Consider declaring the field as nullable.
// public C() { } // 1
Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "C").WithArguments("field", "field").WithLocation(9, 12),
// (10,12): warning CS8618: Non-nullable field 'field' must contain a non-null value when exiting constructor. Consider declaring the field as nullable.
// public C(T t) { field = t; } // 2
Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "C").WithArguments("field", "field").WithLocation(10, 12),
// (11,39): warning CS8602: Dereference of a possibly null reference.
// public C(T t, int x) { field = t; field.ToString(); } // 3
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "field").WithLocation(11, 39),
// (18,5): warning CS8774: Member 'field' must have a non-null value when exiting.
// } // 4
Diagnostic(ErrorCode.WRN_MemberNotNull, "}").WithArguments("field").WithLocation(18, 5));
}

[Fact]
public void NotNullIfNotNull_Return_NullableInt()
{
Expand Down

0 comments on commit 18c645c

Please sign in to comment.