Skip to content

Commit

Permalink
Honor null forgiving operator
Browse files Browse the repository at this point in the history
  • Loading branch information
antonioaversa committed Apr 6, 2023
1 parent fada459 commit 54c3b8c
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,24 @@ protected override ProgramState PreProcessSimple(SymbolicContext context)
&& reference.Property.Name == nameof(Nullable<int>.Value)
&& reference.Instance is { } instance
&& instance.Type.IsNullableValueType()
&& context.HasConstraint(instance, ObjectConstraint.Null))
&& context.HasConstraint(instance, ObjectConstraint.Null)
&& NoNullForgiving(reference.Instance))
{
ReportIssue(instance, instance.Syntax.ToString());
}
else if (operationInstance.Kind == OperationKindEx.Conversion
&& operationInstance.ToConversion() is var conversion
&& conversion.Operand.Type.IsNullableValueType()
&& conversion.Type.IsNonNullableValueType()
&& context.HasConstraint(conversion.Operand, ObjectConstraint.Null))
&& context.HasConstraint(conversion.Operand, ObjectConstraint.Null)
&& NoNullForgiving(conversion.Operand))
{
ReportIssue(conversion.Operand, conversion.Operand.Syntax.ToString());
}

return context.State;

bool NoNullForgiving(IOperation reference) =>
SemanticModel.GetTypeInfo(reference.Syntax).Nullability().FlowState != NullableFlowState.NotNull;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,42 +7,42 @@ class NullForgivingOperator
{
void Basics(int? i)
{
_ = i!.Value; // Compliant, unknown
_ = i!.Value; // Compliant, user-asserted non-empty via bang
i = SomeMethod();
_ = i!.Value; // Compliant, unknown
_ = i!.Value; // Compliant

i = null;
_ = i!.Value; // Noncompliant, empty
_ = i!.Value; // Compliant
i = new int?();
_ = i!.Value; // Noncompliant, empty
_ = i!.Value; // Compliant
i = new Nullable<int>();
_ = i!.Value; // Noncompliant, empty
_ = i!.Value; // Compliant

i = 42;
_ = i!.Value; // Compliant, non-empty
_ = i!.Value; // Compliant
}

void CastToValueType(int? i)
{
_ = (int)i!; // Compliant, unknown
_ = (int)i!; // Compliant, user-asserted non-empty via bang
i = SomeMethod();
_ = (int)i!; // Compliant, unknown
_ = (int)i!; // Compliant

i = null;
_ = (int)i!; // Noncompliant, empty
_ = (int)i!; // Compliant
i = new int?();
_ = (int)i!; // Noncompliant, empty
_ = (int)i!; // Compliant
i = new Nullable<int>();
_ = (int)i!; // Noncompliant, empty
_ = (int)i!; // Compliant
}

void CastToNullableType(int? i)
{
_ = ((int?)i)!.Value; // Compliant, unknown
_ = (i as int?)!.Value; // Compliant, unknown
_ = ((int?)i)!.Value; // Compliant, user-asserted non-empty via bang
_ = (i as int?)!.Value; // Compliant

_ = ((int?)null)!.Value; // Noncompliant
_ = (null as int?)!.Value; // Noncompliant
_ = ((int?)null)!.Value; // Compliant
_ = (null as int?)!.Value; // Compliant
}

static int? SomeMethod() => null;
Expand Down

0 comments on commit 54c3b8c

Please sign in to comment.