I See Dead Code

This is a really short post describing a change to Resharper's (R#) code analysis for dead code. TL;DR: when C# 8 came along with Nullable Reference Types, R# turned off some of its analyses in #nullable enabled contexts and lost its ability to see dead code.

The slightly longer version follow:

R# warns you about dead code. Given the following code:

public class Foo
{
public void DoSomething(bool value) {
if (value == true) {
Console.WriteLine("All good");
}

ThrowException();

Console.WriteLine("Bad!");
}

[ContractAnnotation("=>halt")]
static void ThrowException() {
throw new InvalidOperationException();
}
}

We should see this in Visual Studio:

This is because the [ContractAnnotation] attribute says the code flow halts at this point.

The attribute used to be [TerminatesProgram], but it's now obsolete in favour of [ContractAnnotation]:

Seeing as dead code isn't very useful and can cause confusion, I always set this analysis to Error:

But over the past couple of years, I've noticed that I haven't been seeing it as much. I've been using a lot previews of both Visual Studio and R#, so I put it down to that.

But the other day, I stopped and examined why it wasn't showing. I felt sure it should show, but it simply wasn't.

So I filed a bug report.

The upshot is: JetBrains has a 'dataflow analyzer' that checks a lot of things. It checks if variables are initialised before use, the nullability of variables, and flow driven by boolean values. But ever since C# 8 introduced Nullable Reference Types, JetBrains had to turn off some of the functionality in its analyser in #nullable enabled contexts as it wasn't compatible with compiler's analyser. Plus, they say, the compiler's analyser did a better job in some aspects.

This pretty much ties into when I thought I stopped seeing this work (C# 8 was released in November 2019).

JetBrains also said that in #nullable enabled contexts, the [DoesNotReturn] attribute has similar semantics. This is described in the nullable-analysis docs, although it isn't nearly as useful; the documentation of that attribute says that:

null-state analysis doesn't check any code in a method that follows a call to a method annotated with [DoesNotReturn]

For example:

This shows that nullable-analysis picks up the null dereference in (1), but doesn't bother in (2). And sadly, the dead code in (2 and 3) is no longer shown to be dead.

Overall, nullable-analysis is a great feature, but it's unfortunate that another great feature, spotting dead code, has had to go.

🙏🙏🙏

Since you've made it this far, sharing this article on your favorite social media network would be highly appreciated 💖! For feedback, please 🦋 ping me on Bluesky! 🦋

Leave a comment

Comments are moderated, so there may be a short delays before you see it.

Published