diff --git a/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/ExceptionCandidate.cs b/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/ExceptionCandidate.cs index 4f480d64d90..a9c5c760d5e 100644 --- a/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/ExceptionCandidate.cs +++ b/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/ExceptionCandidate.cs @@ -66,7 +66,7 @@ private ExceptionState FromOperation(IArrayElementReferenceOperationWrapper refe : new ExceptionState(typeCatalog.SystemIndexOutOfRangeException); private ExceptionState FromOperation(ProgramState state, IMemberReferenceOperationWrapper reference) => - reference.IsStaticOrThis() + reference.IsStaticOrThis(state) || state[reference.Instance]?.HasConstraint(ObjectConstraint.NotNull) is true || reference.IsOnReaderWriterLockOrSlim() // Needed by S2222 ? null diff --git a/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/Extensions/IOperationExtensions.cs b/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/Extensions/IOperationExtensions.cs index d47ec63101a..79aa2a04c4d 100644 --- a/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/Extensions/IOperationExtensions.cs +++ b/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/Extensions/IOperationExtensions.cs @@ -27,13 +27,13 @@ internal static ISymbol TrackedSymbol(this IOperation operation, ProgramState st { OperationKindEx.FlowCaptureReference when state.ResolveCapture(operation) is var resolved && resolved != operation => resolved.TrackedSymbol(state), OperationKindEx.Conversion when operation.ToConversion() is var conversion && (!conversion.IsTryCast || conversion.IsUpcast()) => TrackedSymbol(operation.ToConversion().Operand, state), - OperationKindEx.FieldReference when operation.ToFieldReference() is var fieldReference && IsStaticOrThis(fieldReference) && !fieldReference.Type.IsEnum() => fieldReference.Field, + OperationKindEx.FieldReference when operation.ToFieldReference() is var fieldReference && IsStaticOrThis(fieldReference, state) && !fieldReference.Type.IsEnum() => fieldReference.Field, OperationKindEx.LocalReference => operation.ToLocalReference().Local, OperationKindEx.ParameterReference => operation.ToParameterReference().Parameter, OperationKindEx.Argument => operation.ToArgument().Value.TrackedSymbol(state), OperationKindEx.DeclarationExpression => IDeclarationExpressionOperationWrapper.FromOperation(operation).Expression.TrackedSymbol(state), OperationKindEx.PropertyReference when operation.ToPropertyReference() is { Property: { IsVirtual: false } property } propertyReference - && IsStaticOrThis(propertyReference) + && IsStaticOrThis(propertyReference, state) && property.IsAutoProperty() => property, _ => null @@ -120,9 +120,9 @@ internal static IEventReferenceOperationWrapper ToEventReference(this IOperation internal static IUnaryOperationWrapper ToUnary(this IOperation operation) => IUnaryOperationWrapper.FromOperation(operation); - public static bool IsStaticOrThis(this IMemberReferenceOperationWrapper reference) => + public static bool IsStaticOrThis(this IMemberReferenceOperationWrapper reference, ProgramState state) => reference.Instance == null // static fields - || reference.Instance.Kind == OperationKindEx.InstanceReference; + || state.ResolveCaptureAndUnwrapConversion(reference.Instance).Kind == OperationKindEx.InstanceReference; public static IOperation UnwrapConversion(this IOperation operation) { diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/NullPointerDereference.CSharp6.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/NullPointerDereference.CSharp6.cs index 28a56a1adde..9b968e41e31 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/NullPointerDereference.CSharp6.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/NullPointerDereference.CSharp6.cs @@ -13,7 +13,7 @@ void ConditionalThisFieldAccess() { object o = null; this._foo1 = o; - this?._foo1.ToString(); // Not supported, TrackedSymbol() does not resolve flow capture references + this?._foo1.ToString(); // Noncompliant } string TryCatch3()