4

We have a custom extension method .IsNullOrEmpty() that does exactly what it sounds like it does.

public static bool IsNullOrEmpty<T>(this IEnumerable<T> target)
{
  bool flag = true;
  if (target != null)
  {
    using (IEnumerator<T> enumerator = target.GetEnumerator())
    {
      if (enumerator.MoveNext())
      {
        T current = enumerator.Current;
        flag = false;
      }
    }
  }
  return flag;
}

However, parasoft does not recognize this as a valid null check and it gives a

BD.EXCEPT.NR-1: Avoid NullReferenceException

soon after the extension method is used.

Example:

IEnumerable<Foo> foos = _repo.GetFoos();
IEnumerable<Bar> bars;

if (!foos.IsNullOrEmpty())
{
    bars = foos.Select(foo => foo.Bar);  // This is where the Parasoft violation would occur.
}

Is there a way to get Parasoft to recognize our extension method?

JED
  • 1,538
  • 2
  • 19
  • 47
  • 2
    Your `IsNullOrEmpty` does not check that all items in sequence are not null. So if at least one item in `foos` is null you will get NRE when executing `foo.Bar` – Aleks Andreev Apr 08 '19 at 19:42
  • Can you add the class information on Foo and Bar? Your extension method isn't the best in checking a custom classed IEnumerable for null data, but we need more information in order to best help. – Michael Apr 08 '19 at 19:43
  • Do you still see the message with `if (!foos.IsNullOrEmpty() && !(foos is null))`? BTW any reason why not just `return !(target?.Any() == true);`? – vc 74 Apr 08 '19 at 19:44
  • It's all legacy code. I was asked to go through and resolve some of the parasoft violations. This extension method is used 100+ times throughout the code base. I couldn't give you a good reason why they chose to use it. – JED Apr 08 '19 at 19:46
  • @JED I'm not questioning the existence of this method but more its pre Linq coding style – vc 74 Apr 08 '19 at 19:47
  • @vc74 the violation goes away (as does ReSharper's suggestion) if I add `!(foo is null)` to the if statement – JED Apr 08 '19 at 19:57
  • but I don't understand why it wouldn't work if `IEnumerable Foos` is strongly typed and then the extension method specifically checks it for null. – JED Apr 08 '19 at 20:00
  • 1
    @JED `var x = new Foo[1]{null}` is an example of non-null, non-empty enumerable that will throw NRE for `x.First().Bar` (because *an element* of the sequence is null). There are two potential NREs - so even solving first one (which seem to be the core of this question) will not remove the second one. You may want to [edit] post with `foos.Select(foo => foo?.Bar);` to clarify that you only care of `foos` confirmed to be non-null/non-empty. – Alexei Levenkov Apr 08 '19 at 21:03

1 Answers1

1

If the target is null, you cannot call a method on it, it'll bomb.

You need the null check still.

if (foos != null && !foos.IsNullOrEmpty())
{
    bars = foos.Select(foo => foo.Bar);  // This is where the Parasoft violation would occur.
}

The other approproach would be to create a function to check it is has data instead (the opposite of your function), then you could call the ? operator on the null object and the boolean would return FALSE in that case which would be desirable.

if (foos?.Any())
{
    bars = foos.Select(foo => foo.Bar);  // This is where the Parasoft violation would occur.
}
Ctznkane525
  • 7,297
  • 3
  • 16
  • 40
  • 4
    I think the OP knows about null reference exceptions but expects the static analysis tool to detect the body of his `if` block is safe – vc 74 Apr 08 '19 at 19:46
  • 7
    You can call extension methods on `null`. – Lee Apr 08 '19 at 19:57
  • 2
    "If the target is null, you cannot call a method on it, it'll bomb." - how this is related to the question about extensions? – Alexei Levenkov Apr 08 '19 at 20:02
  • If I do `if (foos?.Any()){}` I get an error that nullable bool cannot be implicitly converted into bool. It would need to be `if (foos?.Any() == true)){}` – JED Apr 08 '19 at 20:19
  • And even if I change my extension method to be equal to `if (foos?.Any() == true)`, the parasoft violation still occurs. – JED Apr 08 '19 at 20:24
  • I use `((string)maybeNull).IsNullOrEmpty` all the time D: – user2864740 Apr 10 '19 at 17:20