ReSharper - Possible Null Assignment when using Microsoft.Contracts

Viewed 10257

Is there any way to indicate to ReSharper that a null reference won't occur because of Design-by-Contract Requires checking? For example, the following code will raise the warning (Possible 'null' assignment to entity marked with 'NotNull' attribute) in ReSharper on lines 7 and 8:

private Dictionary<string, string> _Lookup = new Dictionary<string, string>();

public void Foo(string s)
{
    Contract.Requires(!String.IsNullOrEmpty(s));

    if (_Lookup.ContainsKey(s))
        _Lookup.Remove(s);
}

What is really odd is that if you remove the Contract.Requires(...) line, the ReSharper message goes away.

Update

I found the solution through ExternalAnnotations which was also mentioned by Mike below. Here's an example of how to do it for a function in Microsoft.Contracts:

  • Create a directory called Microsoft.Contracts under the ExternalAnnotations ReSharper directory.
  • Next, Create a file called Microsoft.Contracts.xml and populate like so:

<assembly name="Microsoft.Contracts">
    <member name="M:System.Diagnostics.Contracts.Contract.Requires(System.Boolean)">
        <attribute ctor="M:JetBrains.Annotations.AssertionMethodAttribute.#ctor"/>
        <parameter name="condition">
            <attribute ctor="M:JetBrains.Annotations.AssertionConditionAttribute.#ctor(JetBrains.Annotations.AssertionConditionType)">
                <argument>0</argument>
            </attribute>
        </parameter>
    </member>
</assembly>

  • Restart Visual Studio, and the message goes away!
7 Answers

I think you can but it isn't trivial. Take a look at Resharper online help for code annotation

They annotated the BCL classes and the NUnit framework (and more) to enhance Resharpers code inspection capabilities.

For example with the NUnit asserts they annotated with an AssertionMethodAttribute. This tells Resharpers code inspection that if you got past an Assert.IsNotNull(foo); then foo must not be null and it won't produce the "Possible 'null' assignment..." warning anymore.

You could produce an xml file annotating the Contracts.Requires method to indicate that it is just like an Assert.

The reason the message goes away when you remove the assertion is that R# works in an "optimistic" mode by default. It assumes everything is non-null until you do something that indicates it can actually be null. That's what happens when you add the call to String.IsNullOrEmpty. You're stating that s could actually be null. It just isn't aware that the Contract.Requires method will stop execution if that's the case, but that you solved with the annotation.

In R# 5.0 you can change to a pessimistic mode that assumes the worst at every corner.

Related