Using Annotations to Assist ReSharper in Analyzing Your Code

Full article

(The code - posted here as images to demonstrate ReSharper’s code analysis - is also available on Github.)

Anyone who uses ReSharper is familiar with the little squiggly line indicating a “warning” of one kind or another. And anyone who develops with .NET is familiar with the ubiquitous NullReferenceException and ReSharper’s “possible ‘System.NullReferenceException'” warning.

This post was inspired by a question on SO: ReSharper: Null check is always false warning

ReSharper and optimistic analysis

Here’s a really simple example (VS 2013 / R# 8.2) demonstrating the feature. In both cases, a string is initialized to null and then we conditionally set it to a value, before displaying the length of the string.

In this first snippet, ReSharper’s analysis detects that “name” will *always *be null, and underlines it to warn that accessing the “Length” property will possibly throw an exception. In this caresharper string possible null warning](https://grantwinney.com/content/images/2014/12/resharper-string-possible-null-warning.png)

In the next snippet, ReSharper’s analysis detects that name will *never *be null, so no underline. (It also grays out the first initialization, resharper string no warning](https://grantwinney.com/content/images/2014/12/resharper-string-no-warning.png)

Now I’ll remove part of the code to a separate method. Obviously, a NullReferenceException will still be thrown, but ReSharperresharper string separate method no warning](https://grantwinney.com/content/images/2014/12/resharper-string-separate-method-no-warning.png)

The reason for the above behavior is that ReSharper can’t afford to traverse all paths and evaluate all outcomes, on-the-fly. It’d be too expensive. Yes, in this case it’s only a single method. But what about methods nested 10 deep, which then call to another assembly that needs to be decompiled, and ultimately makes a service call to some API out on the Interwebz?

Instead, ReSharper uses “optimistic analysis”, which means that when it can’t determine the outcome, it doesn’t show the warning. If it were a pessimistic analyzer, it’d display the warning when it wasn’t sure. Either way, it amounts to guessing, and sometimes we may want to help it be more accurate.

Get a clue!

What if we had a way to help ReSharper? We do, actually. ReSharper can’t determine whether the method could possibly return null, but we can give it a nudge nudge wink wink, using some special attributes from JetBrains (also referred to as “annotatioresharper string canbenull hint](https://grantwinney.com/content/images/2014/12/resharper-string-canbenull-hint.png)

Notice the addition of the “CanBeNull” attribute in the above code. We’ve told ReSharper that the method might return null, so now it can warn other developers that happen to call it.

Note that it only works one level deep. Marking a nested method which will ultimately cause a NullReferenceException does not affectresharper string canbenull no hint](https://grantwinney.com/content/images/2014/12/resharper-string-canbenull-no-hint.png)

Using Annotations

Annotations (aka “contracts”, aka attributes) like the one above are supplied by JetBrains. They created them, so we could give ReSharper a heads-up.

Referencing the assembly directly

If you don’t mind referencing another assembly, you can reference JetBrains.Annotations directly. On my machine, the file is located at:

C:\Program Files (x86)\JetBrains\ReSharper\v8.2\Bin\JetBrains.Annotations.dll

You’ll need to reference the assembly in your files too. In C#, for example, don’t forget to add:

using JetBrains.Annotations;

Copying the annotations to your project locally

If you do not want, or are not allowed, to reference the assembly directly (or you want to modify the annotations for your own use), JetBrains has provided another method for using them.

Open the ReSharper menu in VS, click on Options, and find the “Code Annotations” tab on the left. Use the button on the right to copy the annotationresharper copy annotions to clipboard](https://grantwinney.com/content/images/2014/12/resharper-copy-annotions-to-clipboard.png)

Paste them into a new class file. The name of the file doesn’t matter, but the namespace does… sort of. ReSharper will offer to modify the namespace to fit in with the rest of your solution, but if you do that and make no other changes, ReSharper won’t respect the attribute while analyzing your code. You could add one more line above the namespace:

// ReSharper disable once CheckNamespace
namespace JetBrains.Annotations

Alternatively, you could modify the namespace and then open the Annotations settings again. ReSharper will recognize the location of the annotations (here I buried them in a couple of nested directories) and give you the option of selecting that location. Do so and save the settings, and it will respect the annotations resharper specify namespace with annoations](https://grantwinney.com/content/images/2014/12/resharper-specify-namespace-with-annoations.png)

This gives you access to dozens of other attributes with whichresharper list of all annotations (wide)](https://grantwinney.com/content/images/2014/12/resharper-list-of-all-annotations-wide.png)

The two that seem most useful in a variety of situations are the CanBeNull and NotNull attributes.

CanBeNull, when ReSharper assumes (optimistically) that an object will not be null

One example of CanBeNresharper string canbenull hint](https://grantwinney.com/content/images/2014/12/resharper-string-canbenull-hint.png)

While some annotations have limited usage (like AspRequiredAttribute, which only applies to classes), others can be applied in a variety of ways. Either look up the documentation online, or use a tool like JetBrains’ dotPeek to read the source:

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property |
                AttributeTargets.Field | AttributeTargets.Parameter |
                AttributeTargets.Delegate,
                AllowMultiple = false, Inherited = true)]
public sealed class CanBeNullAttribute : Attribute

Here’s another example, where the annotation has been applied to a parameter. Again, ReSharper doesn’t know whether or not “myString” could possibly be null, so it optimistically assumes it won’t be. But we can annotate the parameter to hint to ReSharper that “myString” may very well be null. Nresharper string parameter warning](https://grantwinney.com/content/images/2014/12/resharper-string-parameter-warning.png)

CanBeNull, when ReSharper assumes (unwisely) that an object CAN’T be null

I’ve been a long-time user of ReSharper, but only stumbled on annotations while searching for a solution to this question. The OP copied NHibernate’s NullableDictionary class into his project, and noticed ReSharper warning about the followresharper dictionary key possibly null warning](https://grantwinney.com/content/images/2014/12/resharper-dictionary-key-possibly-null-warning.png)

Normally, you can’t have a null key in a Dictionary. From MSDN:

As long as an object is used as a key in the Dictionary<TKey, TValue>, it must not change in any way that affects its hash value. Every key in a Dictionary<TKey, TValue> must be unique according to the dictionary’s equality comparer. **A key cannot be **null. (my emphasis)

ReSharper is assuming that, since the class implements IDictionary, the key passed to TryGetValue cannot be null. (You can verify this by deleting the IDictionary interface from the class signature… the warning disappears.) I suppose it’s a cost-effective assumption, since most dictionaries would not implement a null key, but it’s certainly not a safe one.

Implementation details are left up to the class implementing an interface, so assumptions like this should not be made based solely on the interface being implemented. This is reflected in the docs for IDictionary, also on MSDN:

Implementations can vary in whether they allow key to be null.

Here, we’ve got a class where the key can be null, and we want to let ReSharper know it. There are a few ways we could do this. One way is a special comment, which you can add by clicking the light bulb in the left margin, after placing the cursor on the offending piece of code. Personally, not my favorite. I don’t need more comments, and it leaves resharper disable warning with comments](https://grantwinney.com/content/images/2014/12/resharper-disable-warning-with-comments.png)

Instead, we can use annotations again, this time marking the parameter as “CanBeNull”, so ReSharper knows that all of this codresharper dictionary key possibly null disable with annotation](https://grantwinney.com/content/images/2014/12/resharper-dictionary-key-possibly-null-disable-with-annotation.png)

NotNull, when ReSharper determines that accessing a null value will throw an exception

For the sake of completeness, here’s the NotNull attribute in action. Accessing the value of a nullable int, without first checking whether or not it has a value, will throw an exception, and ReSharper is warning us. By marking the called method with the NotNull attribute, we are telling ReSharper that the method will never return a null, so the warning is unnecessary. *(Silly example, as you’d change the return value in the signature instead, but it demonresharper sample notnull usage](https://grantwinney.com/content/images/2014/12/resharper-sample-notnull-usage.png)

References

You can read more about the ReSharper NullReferenceException analysis, and related annotations/contracts, at JetBrains’s website.

You can also read more about the various annotations, their descriptions and a few sample usages.

(The code - posted here as images to demonstrate ReSharper’s code analysis - is also available on Github.)

Author

Grant Winney

I write when I've got something to share - a personal project, a solution to a difficult problem, or just an idea. We learn by doing and sharing. We've all got something to contribute.


Comments / Reactions