Add a way to break out of this method's recursion

  • Language: C#

  • Issue: Add a way to break out of this method’s recursion.

  • False Positive

  • Rationale: This is coming back as a Recursion Blocker but after reviewing the code it looks like the method is calling a method of the same name with different params, ultimately not being a recursive method.

    • SonarQube Server / Developer
      /// <summary>
      /// Evaluates secondary solutions from a collection of solutions.
      /// </summary>
      /// <param name="solutions">The collection of solutions.</param>
      /// <returns>A list of secondary solutions.</returns>
      public static List<Solution> EvaluateSecondarySolutions(this IEnumerable solutions, bool checkOnhold = true)
      {
          return solutions.AsQueryable().EvaluateSecondarySolutions();
      }
    
      /// <summary>
      /// Evaluates secondary solutions from a queryable collection of solutions.
      /// </summary>
      /// <param name="solutions">The queryable collection of solutions.</param>
      /// <returns>A list of secondary solutions.</returns>
      public static List<Solution> EvaluateSecondarySolutions(this IQueryable<Solution> solutions, bool checkOnhold = true)
      {
          var secondarySolutions = new List<Solution>();
    
          foreach (var solution in solutions)
          {
              // Business Logic
    
              secondarySolutions.Add(solution);
          }
    
          return secondarySolutions;
      }
    

Hey there.

Take a look at this post.

Specifically, make sure you include which version of SonarQube you’re using and what the affected Rule ID is.

I can confirm the FP

public static class S2190
{
	public static List<int> Query(this IEnumerable items, bool checkOnhold = true) // FP: calls other method.
	{
		return items.AsQueryable().Query();
	}

	public static List<int> Query(this IQueryable<int> items, bool checkOnhold = true)
	{
		return new List<int>();
	}
}

Tested with SonarAnalyzer.CSharp v10.11.0.117924.

  • Developer Edition
  • v2025.3 (108892) Not sure how to find the Rule ID

Did you mean to write this instead?

  public static List<Solution> EvaluateSecondarySolutions(this IEnumerable<Solution> solutions, bool checkOnhold = true)
  {
      return solutions.AsQueryable().EvaluateSecondarySolutions();
  }

In the given code, a non-generic IEnumerable is passed to AsQueryable, resulting in a non-generic IQueryable. This non-generic IQueryable implements at compile time IEnumerable but not IQueryable<Solution>, so the call to EvaluateSecondarySolutions is recursive.

Hi @dbeckerton, & @Corniel

I believe @jilles-sg is correct and that this is a TP.
Within Visual studio we can see that for the given functions we can see that the call is recursive from the IEnumerable to the IEnumerable:


When we add the <int> constraint, we can see that the call hierarchy resolves as expected From the IEnumerable to the IQueryable:

Would you agree?

Weird. I thought I had this working, but now I check the code again and I agree.

Note that

public static class S2190
{
	public static List<int> Query(this IEnumerable<int> items, bool checkOnhold = true)
	{
		return items.AsQueryable().Query();
	}

	public static List<int> Query(this IQueryable<int> items, bool checkOnhold = true)
	{
		return new List<int>();
	}
}

breaks out of the recursion, but this case is not reported by S2190.

Sorry for the confusion.

1 Like