How can I configure ReSharper to accept [Required] (from PostSharp) as equivalent to [NotNull] (or vice versa)?

327 views Asked by At

I'm using PostSharp and ReSharper together in a variety of projects, specifically, making use of both PostSharp's code contract enforcement, and of ReSharper's annotations in the interest of better code.

Trouble is, when it comes to nullability, I end up with lots of parameter, etc., declarations that look like this:

public void Foo ([Required] [JetBrains.Annotations.NotNull] object bar)

...in order to both enforce with the former and annotate with the latter that bar cannot be null.

Is there a way in which I can configure ReSharper to treat the presence of the [Required] attribute as equivalent to [NotNull] for annotation purposes, or some other method (I'm not particular as to how) to avoid having to repeat myself like this for every not-null parameter, etc.?

2

There are 2 answers

0
AlexD On BEST ANSWER

As described on this documentation page, ReSharper can actually recognize custom annotations even when they are defined in the namespace other than "JetBrains.Annotations". So you can define your own custom annotations and turn some of them into aspect providers that apply a code contract to the target element.

First, open "ReSharper Options" | "Code Annotations" and click "Copy C# implementation to clipboard". Also, uncheck "internal" to reuse annotations across projects.

Then create a new code file and paste annotations. You can rename the namespace (e.g. MyAnnotations). If you choose to use custom namespace, you need to open "ReSharper Options" again and select the check-box next to your custom namespace in "Custom namespaces should be marked in the list below".

Now you can find NotNullAttribute and change its source code in the following way:

public sealed class NotNullAttribute : LocationLevelAspect, IAspectProvider
{
    public IEnumerable<AspectInstance> ProvideAspects(object targetElement)
    {
        var requiredConstruction = new ObjectConstruction( typeof( PostSharp.Patterns.Contracts.RequiredAttribute ) );
        yield return new AspectInstance( targetElement, requiredConstruction, null );
    }
}

You can apply this custom attribute in your code and it will work as both PostSharp aspect and ReSharper annotation.

public void Foo ([MyAnnotations.NotNull] object bar)
0
Plasmadog On

AlexD technically has answered the question, but only because there is a bad assumption in the original question. The PostSharp.Required attribute is not equivalent to JetBrains.NotNull. NotNull means exactly that, while Required means neither null nor empty.

AlexD's approach is to modify the JetBrains NotNull attribute in such a way as to behave like the Required attribute and use that instead. But JetBrains does not have an equivalent to Required, so if you want to retain two distinct attributes for "not null" and "neither null nor empty", and also have both attributes respected by Resharper, then this approach cannot work.