Skip to content

Commit

Permalink
SE - Nullable: Infer constraints for HasValue property (#6850)
Browse files Browse the repository at this point in the history
  • Loading branch information
pavel-mikula-sonarsource committed Mar 31, 2023
1 parent 1b0e653 commit f2f03e9
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -73,16 +73,28 @@ protected override IPropertyReferenceOperationWrapper Convert(IOperation operati

protected override ProgramState Process(SymbolicContext context, IPropertyReferenceOperationWrapper propertyReference)
{
var state = context.State;
if (propertyReference.Instance.TrackedSymbol() is { } symbol)
{
var state = context.State.SetSymbolConstraint(symbol, ObjectConstraint.NotNull);
return propertyReference.Property.Name == "Value" && propertyReference.Instance.Type.IsNullableValueType() && context.State[symbol] is { } value
? state.SetOperationValue(context.Operation, value)
: state;
if (propertyReference.Instance.Type.IsNullableValueType())
{
if (propertyReference.Property.Name == "Value" && state[symbol] is { } value)
{
state = state.SetOperationValue(context.Operation, value);
}
else if (propertyReference.Property.Name == "HasValue")
{
// Return directly, do not set NotNull on the symbol itself
return state[symbol]?.Constraint<ObjectConstraint>() is { } objectConstraint
? state.SetOperationConstraint(context.Operation, BoolConstraint.From(objectConstraint == ObjectConstraint.NotNull))
: state;
}
}
return state.SetSymbolConstraint(symbol, ObjectConstraint.NotNull);
}
else
{
return context.State;
return state;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,30 @@ public void Nullable_Value_ReadsConstraintsFromInstance()
validator.ValidateTag("FalseFirst", x => x.HasConstraint(BoolConstraint.False).Should().BeTrue());
validator.ValidateTag("FalseFirst", x => x.HasConstraint(TestConstraint.First).Should().BeTrue());
}

[TestMethod]
public void Nullable_HasValue_ReadsBoolConstraintFromObjectConstraint()
{
const string code = """
var hasValue = arg.HasValue;
Tag("HasValueUnknown", hasValue);
Tag("SymbolUnknown", arg);
arg = true;
hasValue = arg.HasValue;
Tag("HasValueAfterTrue", hasValue);
Tag("SymbolAfterTrue", arg);
arg = null;
hasValue = arg.HasValue;
Tag("HasValueAfterNull", hasValue);
Tag("SymbolAfterNull", arg);
""";
var validator = SETestContext.CreateCS(code, ", bool? arg").Validator;
validator.ValidateTag("HasValueUnknown", x => x.Should().BeNull());
validator.ValidateTag("SymbolUnknown", x => x.Should().BeNull());
validator.ValidateTag("HasValueAfterTrue", x => x.Should().BeNull()); // ToDo: Should be x.HasConstraint(BoolConstraint.True).Should().BeTrue()); after we build NotNull for bool literal.
validator.ValidateTag("SymbolAfterTrue", x => x.HasConstraint(BoolConstraint.True).Should().BeTrue());
validator.ValidateTag("SymbolAfterTrue", x => x.HasConstraint(ObjectConstraint.NotNull).Should().BeFalse()); // ToDo: Should be BeTrue() after we build NotNull for bool literal
validator.ValidateTag("HasValueAfterNull", x => x.HasConstraint(BoolConstraint.False).Should().BeTrue());
validator.ValidateTag("SymbolAfterNull", x => x.HasConstraint(ObjectConstraint.Null).Should().BeTrue());
}
}

0 comments on commit f2f03e9

Please sign in to comment.