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 theExternalAnnotations
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!
Note: as of the current R# 8.0 EAP, this functionality is included.
Here's the solution for the current (i.e. .NET 4.0) version of Code Contracts:
Inside
...\ExternalAnnotations\mscorlib\Contracts.xml
, add the following:Resharper has changed their contract annotation model as of version 7.
You need a different file. The new location (I guess only for Metro apps) is: "C:\Program Files (x86)\JetBrains\ReSharper\v7.1\Bin\ExternalAnnotations\.NETCore\System.Diagnostics.Contracts\Contracts.xml"
I am using Visual Studio 2012 and .Net 4.5 and Resharper 7.1.
Content:
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 thats
could actually be null. It just isn't aware that theContract.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.
TL;DR - Add the conditional compilation symbol
CONTRACTS_FULL
to your project.The
Contract.Requires(...)
method is empty and disabled, unless you enable and use the Code Contacts rewriter. By running the rewriter manually, or (usually) enabling it through the Visual Studio project properties, you will keep theContract.Requires(...)
code in your compiled and rewritten binaries. You know the code will work, and ignoring the Resharper warning, you can run it and test.What is the problem then? Resharper doesn't know that the code contracts are running, since they are really only injected at (post-)compile time. In the eyes of Resharper, it's disabled in the same way as the
DEBUG
preprocessor symbol works and how Visual Studio greys out areas of your code that won't be part of your compiled binaries.According to the Code Contracts user manual (chapter 2, first paragraph) and the source code in
ContractExtensions.cs
(included in the Code Contracts install folder),CONTRACTS_FULL
needs to be set before compiling with it. The Contract methods are actually implemented with[ConditionalAttribute("CONTRACTS_FULL")]
and ignored (not included at compile time) unless the flag is set. Resharper respects this flag, and assumes that the function will not run unless it's set.Solution: Add the conditional compilation symbol
CONTRACTS_FULL
to your project. See Using Code Contracts Visual Studio and with Resharper by Henning Krause.http://www.infinitec.de/image.axd?picture=Windows-Live-Writer/Using-CodeContracts-with-Resharper/05970F39/ConditionalSymbol.png
The Resharper team has been notified; Code analysis doesn't consider settings on the 'Code Contracts' project properties tab, Support of Microsoft Code Contracts.
I'd like to add that for people writing their own assertion methods and such, you can include these attributes without an external XML file. In Visual Studio, go to
ReSharper > Options > Code Annotations
and click theCopy default implementation to clipboard
button. Then create a new file (anywhere you want in your solution) and paste in the code from the clipboard. Now, you can create methods like this:Now any call to
Require.That(a != null)
will indicate to ReSharper that you can't get past this line ifa
is null. Unlike the ExternalAnnotations technique, this will work for anyone using your methods, without any additional work on their part.Update
Resharper has changed their contract annotation model as of version 7. Here's what the above method would look like now:
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.