Skip to content

Commit

Permalink
Migrate S4158: Do not report on method references (#7453)
Browse files Browse the repository at this point in the history
  • Loading branch information
pavel-mikula-sonarsource authored Jun 16, 2023
1 parent 6dceab4 commit b6ce681
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,9 @@ protected override ProgramState PreProcessSimple(SymbolicContext context)
{
return ProcessInvocation(context, invocation);
}
else if (operation.AsMethodReference() is { } methodReference)
else if (operation.AsMethodReference() is { Instance: not null } methodReference)
{
return ProcessMethod(context, methodReference.Method, methodReference.Instance);
return ProcessAddMethod(context.State, methodReference.Method, methodReference.Instance);
}
else if (operation.AsPropertyReference() is { Property.IsIndexer: true } indexer)
{
Expand Down Expand Up @@ -163,33 +163,37 @@ public override void ExecutionCompleted()

private ProgramState ProcessInvocation(SymbolicContext context, IInvocationOperationWrapper invocation)
{
return invocation.TargetMethod.Is(KnownType.System_Linq_Enumerable, nameof(Enumerable.Count))
&& SizeConstraint(context.State, invocation.Instance ?? invocation.Arguments[0].ToArgument().Value, HasFilteringPredicate()) is { } constraint
? context.SetOperationConstraint(constraint)
: ProcessMethod(context, invocation.TargetMethod, invocation.Instance);

bool HasFilteringPredicate() =>
invocation.Arguments.Any(x => x.ToArgument().Parameter.Type.Is(KnownType.System_Func_T_TResult));
}

private ProgramState ProcessMethod(SymbolicContext context, IMethodSymbol method, IOperation instance)
{
var state = context.State;
if (instance is null)
if (invocation.TargetMethod.Is(KnownType.System_Linq_Enumerable, nameof(Enumerable.Count))
&& SizeConstraint(context.State, invocation.Instance ?? invocation.Arguments[0].ToArgument().Value, HasFilteringPredicate()) is { } constraint)
{
return state;
return context.SetOperationConstraint(constraint);
}
if (RaisingMethods.Contains(method.Name))
else if (invocation.Instance is { } instance)
{
if (state[instance]?.HasConstraint(CollectionConstraint.Empty) is true)
{
emptyAccess.Add(context.Operation.Instance);
}
else
if (RaisingMethods.Contains(invocation.TargetMethod.Name))
{
nonEmptyAccess.Add(context.Operation.Instance);
if (context.State[instance]?.HasConstraint(CollectionConstraint.Empty) is true)
{
emptyAccess.Add(context.Operation.Instance);
}
else
{
nonEmptyAccess.Add(context.Operation.Instance);
}
}
return ProcessAddMethod(context.State, invocation.TargetMethod, instance);
}
else
{
return context.State;
}

bool HasFilteringPredicate() =>
invocation.Arguments.Any(x => x.ToArgument().Parameter.Type.Is(KnownType.System_Func_T_TResult));
}

private static ProgramState ProcessAddMethod(ProgramState state, IMethodSymbol method, IOperation instance)
{
if (AddMethods.Contains(method.Name))
{
state = state.SetOperationConstraint(instance, CollectionConstraint.NotEmpty);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -702,7 +702,7 @@ public void AddPassedAsParameter()
list.Clear(); // Compliant

list = new List<int>();
DoSomething(list.Clear); // Noncompliant
DoSomething(list.Clear); // We don't raise here to avoid FPs

DoSomething(StaticMethodWithoutInstance);

Expand All @@ -717,7 +717,7 @@ public void AddPassedAsParameter()
list.Clear(); // Compliant, but will break when we learn Empty from Clear()

list = new List<int>();
Action clear = list.Clear; // Noncompliant FP
Action clear = list.Clear; // We don't raise here to avoid FPs
clear(); // FN
clear(); // FN

Expand All @@ -728,6 +728,17 @@ public void AddPassedAsParameter()
clear(); // FN
}

public void AddPassedAsParameter_Dictionary() // Reproducer from Peach
{
var d = new Dictionary<int, int>();
AddSomething(
d.ContainsKey, // Compliant
(k, v) => d[k] = v);

void AddSomething(Func<int, bool> containsKey, Action<int, int> add)
{ }
}

private static void StaticMethodWithoutInstance() { }

public void Count()
Expand Down

0 comments on commit b6ce681

Please sign in to comment.