Support for contract annotations

Resharper has this nice little attribute you can place on methods called Contract Annotations.

In a nutshell, they provide a way to declare “if this method gets null as input, the output is going to be false” and similar. This information can help the analyzer more accurately detect things like illegal null accesses.

Concrete example, we have two extension methods on IList<T> called HasItems() and IsEmpty(). They check for null and then check the count of the list so that instead of writing

if (myList != null && myList.Count > 0)
{ 
    // use myList
}
if (myList.HasItems())
{ 
    // use myList
}

Unfortunately, since sonar doesn’t understand that if HasItems() returns true, it means myList is not null. It will incorrectly warn about the following

// Use of  ?. hints to sonar that we think it could be null
int sum = myList?.Sum() ?? 0;
// Somewhere further down...
if (myList.HasItems())
{
     // Incorrectly flags this as S2259 saying "myList is null on at least one execution path"
     int count = myList.Count;
}

The way contract annotations work is that you decorate the method with a simple expression to let the analyzer know what output to expect:

[ContractAnnotation("null => false")]
public static bool HasItems<T>(this IList<T> list)
{
	Contract.Ensures(Contract.Result<bool>() == true && list != null);
	if (list == null)
		return false;
	return list.Count > 0;
}

[ContractAnnotation("null => true")]
public static bool IsEmpty<T>(this IList<T> list)
{
	Contract.Ensures(Contract.Result<bool>() == false && list != null);
	return list == null || list.Count == 0;
}

Ideally, sonar should use the same attributes as resharper so that we don’t have to decorate them twice

Hi @Isaks

Thanks for the suggestion, I will look into this and consider it in our roadmap. We are currently working on support for Rider in Sonarlint so recognizing the Resharper annotations may become a popular request.

Tom