How-To's

Better null checks, string formatting and path completion with JetBrains Annotations

In the previous blog post of our series around using JetBrains Annotations to improve Rider (and ReSharper’s) code analysis, code completion and navigation, we looked at some background: what are these annotations? And how do we add them to our source code? Now that we have them added to our code, we can look at some examples!

In this series:

We started our series with some ASP.NET MVC annotations (of which there are many more). Rider and ReSharper support a large number of annotations – let’s look at a few interesting examples.

Better null safety with CanBeNull/NotNull/ItemCanBeNull/ItemNotNull

Rider and ReSharper perform value analysis to help us in detecting possible null references, redundant comparisons and null checks. Consider the following code:

static string GetGuidString() => Guid.NewGuid().ToString();

public static void Main(string[] args)
{
    var guidString = GetGuidString();
    if (guidString != null)
    {
        // ...
    }
}

Our GetGuidString() method always returns a value, so the guidString != null is redundant. By decorating it with the [NotNull] attribute, Rider and ReSharper will inform us the null check is always true (and hence, redundant):

NotNull annotation

Similarly we can annotate method parameters with these attributes – either manually or when using the Check parameter for null quick fix (via Alt+Enter). Rider and ReSharper will then warn us if we pass an invalid value:

Annotating NotNull parameter

Writing the full name of the attribute can be cumbersome. Rider and ReSharper will add [CanBeNull] when we use the ? type assist, and [NotNull] when using the ! type assist:

Type assist for NotNull and CanBeNull annotations

We can use the ItemCanBeNull/ItemNotNull annotations with implementations of IEnumerable, Task and Lazy classes to indicate that the value of a collection item, of the Task.Result property or of the Lazy.Value property can or can never be null.

Better string formatting with with StringFormatMethod

Using the StringFormatMethod annotation, we can indicate that a method works similar to the string.Format method. When we use the annotation, Rider and ReSharper will know our method takes a composite format string, followed by arguments that will replace the placeholders in the format string. All of a sudden, we get syntax highlighting, code analysis and code completion for the placeholders, including formatting!

StringFormatMethod annotation provides syntax highlighting, code analysis and code completion

File-system completion with PathReference

When annotating a class member (such as a property) or a method parameter with PathReference, we will get code completion for files and folders within our project. Paths can be relative or absolute, starting from the web root (~). The PathReference annotation also provides navigation to the specified path!

PathReference annotation provides code completion and navigation

What other annotations are there?

There are many more annotations we can use to make Rider and ReSharper better at helping us.

  • NotifyPropertyChangedInvocator is great when writing a class that implements the INotifyPropertyChanged interface and opens access to a number of additional context actions on properties (such as automatically creating a backing field and adding change notification.
  • The RegexPattern annotation makes a field, property or parameter a regular expression, providing syntax highlighting, code completion and validation of our regular expression.
  • ContractAnnotation describes the relation between method input and output, for example by telling Rider and ReSharper that when a null value is passed, a null value will be returned.
  • Pure indicates that a method does not make any observable state changes, ensuring callers that there will be no side effects from calling that method. The [Pure] annotation not only allows to find places where return values are ignored, it also makes some analyses more precise.
  • PublicAPI indicates a method is exposed as a public API, and therefore marked as “used” by code analysis. This will prevent Rider and ReSharper from graying it out because it looks unused.
  • And many, many more! Do check our web help for a full overview of all available annotations and examples of how to use them.

Download the latest Rider or give ReSharper a try! We’d love to hear your feedback!

image description