diff --git a/analyzers/src/SonarAnalyzer.CSharp/SymbolicExecution/Roslyn/PublicMethodArgumentsShouldBeCheckedForNull.cs b/analyzers/src/SonarAnalyzer.CSharp/SymbolicExecution/Roslyn/PublicMethodArgumentsShouldBeCheckedForNull.cs index 64029a03bf9..352594a053f 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/SymbolicExecution/Roslyn/PublicMethodArgumentsShouldBeCheckedForNull.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/SymbolicExecution/Roslyn/PublicMethodArgumentsShouldBeCheckedForNull.cs @@ -71,18 +71,18 @@ static bool MethodDereferencesArguments(BaseMethodDeclarationSyntax method) protected override ProgramState PreProcessSimple(SymbolicContext context) { - var operation = context.Operation.Instance; - if (operation.Kind == OperationKindEx.ParameterReference - && operation.ToParameterReference().Parameter is var parameter + if (NullDereferenceCandidate(context.Operation.Instance) is { } candidate + && candidate.Kind == OperationKindEx.ParameterReference + && candidate.ToParameterReference() is var dereferencedParameter + && dereferencedParameter.Parameter is var parameter && !parameter.Type.IsValueType - && IsParameterDereferenced(context.Operation) && NullableStateIsNotKnownForParameter(parameter) && !parameter.HasAttribute(KnownType.Microsoft_AspNetCore_Mvc_FromServicesAttribute)) { var message = SemanticModel.GetDeclaredSymbol(Node).IsConstructor() ? "Refactor this constructor to avoid using members of parameter '{0}' because it could be null." : "Refactor this method to add validation of parameter '{0}' before using it."; - ReportIssue(operation, string.Format(message, operation.Syntax), context); + ReportIssue(dereferencedParameter.WrappedOperation, string.Format(message, dereferencedParameter.WrappedOperation.Syntax), context); } return context.State; @@ -91,15 +91,17 @@ bool NullableStateIsNotKnownForParameter(IParameterSymbol symbol) => context.State[symbol] is null || !context.State[symbol].HasConstraint(); } - private static bool IsParameterDereferenced(IOperationWrapperSonar operation) => - operation.Parent != null - && operation.Parent.IsAnyKind( - OperationKindEx.Invocation, - OperationKindEx.FieldReference, - OperationKindEx.PropertyReference, - OperationKindEx.EventReference, - OperationKindEx.Await, - OperationKindEx.ArrayElementReference); + private static IOperation NullDereferenceCandidate(IOperation operation) => + operation.Kind switch + { + OperationKindEx.Invocation => operation.ToInvocation().Instance, + OperationKindEx.FieldReference => operation.ToFieldReference().Instance, + OperationKindEx.PropertyReference => operation.ToPropertyReference().Instance, + OperationKindEx.EventReference => operation.ToEventReference().Instance, + OperationKindEx.Await => operation.ToAwait().Operation, + OperationKindEx.ArrayElementReference => operation.ToArrayElementReference().ArrayReference, + _ => null, + }; private sealed class ArgumentDereferenceWalker : SafeCSharpSyntaxWalker {