diff --git a/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/RuleChecks/EmptyNullableValueAccessBase.cs b/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/RuleChecks/EmptyNullableValueAccessBase.cs index 59a46a95d31..6c0d457079c 100644 --- a/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/RuleChecks/EmptyNullableValueAccessBase.cs +++ b/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/RuleChecks/EmptyNullableValueAccessBase.cs @@ -32,7 +32,8 @@ protected override ProgramState PreProcessSimple(SymbolicContext context) if (operationInstance.Kind == OperationKindEx.PropertyReference && operationInstance.ToPropertyReference() is var reference && reference.Property.Name == nameof(Nullable.Value) - && reference.Instance.Type.IsNullableValueType() + && reference.Instance is { } instance + && instance.Type.IsNullableValueType() && context.HasConstraint(reference.Instance, ObjectConstraint.Null)) { ReportIssue(reference.Instance, reference.Instance.Syntax.ToString()); diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/EmptyNullableValueAccess.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/EmptyNullableValueAccess.cs index 8552a98a82e..5fb32b96695 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/EmptyNullableValueAccess.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/EmptyNullableValueAccess.cs @@ -928,7 +928,7 @@ void Basics(MaybeInt i) } } -namespace TypeWithValueProperty +namespace TypeWithValueInstanceProperty { class Test { @@ -971,3 +971,56 @@ struct StructWithValuePropertyAndCastOperators } } +namespace TypeWithValueStaticProperty +{ + class Test + { + void Basics() + { + _ = AClassWithStaticValueProperty.Value; // Compliant, not on nullable value type + _ = AClassWithStaticValueProperty.Value.Value; // Compliant + _ = AClassWithStaticValueProperty.Value.Value.InstanceProperty; // Compliant + _ = AClassWithStaticValueProperty.Value.Value.InstanceProperty.Value; // Compliant + _ = new AClassWithInstanceValueProperty().Value; // Compliant + } + } + + class AClassWithStaticValueProperty + { + public AClassWithInstanceValueProperty InstanceProperty => new AClassWithInstanceValueProperty(); + + public static AClassWithInstanceValueProperty Value => new AClassWithInstanceValueProperty(); + } + + class AClassWithInstanceValueProperty + { + public AClassWithStaticValueProperty Value => new AClassWithStaticValueProperty(); + } +} + +namespace TypeWithValueStaticField +{ + class Test + { + void Basics() + { + _ = AClassWithStaticValueField.Value; // Compliant, not on nullable value type + _ = AClassWithStaticValueField.Value.Value; // Compliant + _ = AClassWithStaticValueField.Value.Value.InstanceField; // Compliant + _ = AClassWithStaticValueField.Value.Value.InstanceField.Value; // Compliant + _ = new AClassWithInstanceValueField().Value; // Compliant + } + } + + class AClassWithStaticValueField + { + public AClassWithInstanceValueField InstanceField = new AClassWithInstanceValueField(); + + public static AClassWithInstanceValueField Value = new AClassWithInstanceValueField(); + } + + class AClassWithInstanceValueField + { + public AClassWithStaticValueField Value = new AClassWithStaticValueField(); + } +}