Skip to content
This repository was archived by the owner on Oct 2, 2022. It is now read-only.

Commit 735d04a

Browse files
Bart Koelmanbkoelman
authored andcommitted
Added analyzer/fixer to convert from Resharper annotations to C# builtin syntax
1 parent f4952df commit 735d04a

22 files changed

Lines changed: 2103 additions & 19 deletions

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
This Visual Studio analyzer supports you in consequently annotating your codebase with Resharpers nullability attributes. Doing so improves the [nullability analysis engine in Resharper](https://www.jetbrains.com/resharper/help/Code_Analysis__Code_Annotations.html), so `NullReferenceException`s at runtime will become something from the past.
77

8+
**Update:** When used on a project that has C# nullable reference types enabled, this analyzer suppresses its original behavior and turns into a utility to convert existing Resharper nullability attributes to C# 8 syntax. See [documentation](doc/reference/CNUL_ResharperNullabilityAnnotationsCanBeConvertedToCSharpSyntax.md) for details.
9+
810
## Get started
911

1012
* You need [Visual Studio](https://www.visualstudio.com/) 2015/2017/2019 and [Resharper](https://www.jetbrains.com/resharper/) v9 (or higher) to use this analyzer. See [here](https://github.com/bkoelman/ResharperCodeContractNullabilityFxCop/) if you use Visual Studio 2013 or lower.
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# CNUL: Resharper nullability annotation(s) can be converted to C# syntax
2+
3+
## Cause
4+
A member or parameter contains Resharper nullability annotations, while the project is configured to enable C# nullable reference types.
5+
6+
## Rule description
7+
Nullable reference types are a new language feature in C# v8. It supersedes the nullability annotations that were introduced by Resharper. This rule offers to convert existing code that uses the Resharper attribute to the new C# syntax.
8+
9+
## How to fix violations
10+
Run the associated code fixer by selecting "Convert to C# syntax". It is recommended to run on entire document, project or solution (if memory allows).
11+
Remember to uninstall the ResharperCodeContractNullability package after all your code has been converted.
12+
13+
## When to suppress warnings
14+
There is no technical reason to suppress this warning.
15+
16+
## Example of a violation
17+
18+
### Description
19+
The type `C` defines members and parameters that are decorated with Resharper annotations.
20+
21+
### Code
22+
```csharp
23+
using System;
24+
using System.Collections.Generic;
25+
using System.Threading.Tasks;
26+
using JetBrains.Annotations;
27+
28+
namespace N
29+
{
30+
public class C
31+
{
32+
[CanBeNull]
33+
[ItemNotNull]
34+
private readonly List<string> _f = new List<string>();
35+
36+
[CanBeNull]
37+
[ItemNotNull]
38+
public ICollection<string> P => _f?.AsReadOnly();
39+
40+
[NotNull]
41+
[ItemNotNull]
42+
public Lazy<string> M([NotNull] [ItemNotNull] Task<string> p)
43+
{
44+
_f?.Add(p.Result);
45+
return new Lazy<string>(() => p.Result);
46+
}
47+
}
48+
}
49+
```
50+
51+
## Example of how to fix
52+
53+
### Description
54+
All annotated members and parameters of the type `C` are now converted.
55+
56+
### Code
57+
58+
```csharp
59+
using System;
60+
using System.Collections.Generic;
61+
using System.Threading.Tasks;
62+
63+
namespace N
64+
{
65+
public class C
66+
{
67+
private readonly List<string>? _f = new List<string>();
68+
69+
public ICollection<string>? P => _f?.AsReadOnly();
70+
71+
public Lazy<string> M(Task<string> p)
72+
{
73+
_f?.Add(p.Result);
74+
return new Lazy<string>(() => p.Result);
75+
}
76+
}
77+
}
78+
```
79+
80+
## Related rules
81+
82+
RNUL: [Member is missing nullability annotation](RNUL_MemberIsMissingNullabilityAnnotation.md)
83+
84+
RINUL: [Member is missing item nullability annotation](RINUL_MemberIsMissingItemNullabilityAnnotation.md)

src/CodeContractNullability/CodeContractNullability.Test/CodeContractNullability.Test.csproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
3-
<TargetFrameworks>net46;net452</TargetFrameworks>
3+
<TargetFrameworks>net472;net452</TargetFrameworks>
44
</PropertyGroup>
55
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
66
<DefineConstants>TRACE;DEBUG;JETBRAINS_ANNOTATIONS</DefineConstants>
@@ -33,8 +33,8 @@
3333
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
3434
</PackageReference>
3535
</ItemGroup>
36-
<ItemGroup Condition="'$(TargetFramework)' == 'net46'">
37-
<PackageReference Include="Microsoft.CodeAnalysis" Version="2.10.0" />
36+
<ItemGroup Condition="'$(TargetFramework)' == 'net472'">
37+
<PackageReference Include="Microsoft.CodeAnalysis" Version="3.0.0-beta4-final" />
3838
</ItemGroup>
3939
<ItemGroup Condition="'$(TargetFramework)' == 'net452'">
4040
<PackageReference Include="Microsoft.CodeAnalysis" Version="1.0.1" />
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
using CodeContractNullability.NullabilityAttributes;
2+
using CodeContractNullability.Test.TestDataBuilders;
3+
using CodeContractNullability.Utilities;
4+
using JetBrains.Annotations;
5+
using Microsoft.CodeAnalysis.CodeFixes;
6+
using Microsoft.CodeAnalysis.Diagnostics;
7+
using RoslynTestFramework;
8+
9+
namespace CodeContractNullability.Test
10+
{
11+
public abstract class ConversionNullabilityTest : AnalysisTestFixture
12+
{
13+
protected override string DiagnosticId => NullableReferenceTypeConversionAnalyzer.DiagnosticId;
14+
15+
protected override DiagnosticAnalyzer CreateAnalyzer()
16+
{
17+
var analyzer = new NullableReferenceTypeConversionAnalyzer();
18+
analyzer.NullabilityAttributeProvider.Override(new SimpleNullabilityAttributeProvider());
19+
return analyzer;
20+
}
21+
22+
protected override CodeFixProvider CreateFixProvider()
23+
{
24+
return new NullableReferenceTypeConversionCodeFixProvider();
25+
}
26+
27+
private protected void VerifyDiagnostics([NotNull] ParsedSourceCode source,
28+
[NotNull] [ItemNotNull] params string[] messages)
29+
{
30+
Guard.NotNull(source, nameof(source));
31+
32+
AssertDiagnostics(source.TestContext, messages);
33+
}
34+
35+
private protected void VerifyFix([NotNull] ParsedSourceCode source,
36+
[NotNull] [ItemNotNull] params string[] messages)
37+
{
38+
Guard.NotNull(source, nameof(source));
39+
40+
string[] expectedCode =
41+
{
42+
source.ExpectedText
43+
};
44+
var fixContext = new FixProviderTestContext(source.TestContext, expectedCode,
45+
source.CodeComparisonMode);
46+
47+
AssertDiagnosticsWithCodeFixes(fixContext, messages);
48+
}
49+
50+
[NotNull]
51+
protected static string CreateMessageForField([NotNull] string name)
52+
{
53+
return new ConversionDiagnosticMessageBuilder()
54+
.OfType(SymbolType.Field)
55+
.Named(name)
56+
.Build();
57+
}
58+
59+
[NotNull]
60+
protected static string CreateMessageForProperty([NotNull] string name)
61+
{
62+
return new ConversionDiagnosticMessageBuilder()
63+
.OfType(SymbolType.Property)
64+
.Named(name)
65+
.Build();
66+
}
67+
68+
[NotNull]
69+
protected static string CreateMessageForMethod([NotNull] string name)
70+
{
71+
return new ConversionDiagnosticMessageBuilder()
72+
.OfType(SymbolType.Method)
73+
.Named(name)
74+
.Build();
75+
}
76+
77+
[NotNull]
78+
protected static string CreateMessageForDelegate([NotNull] string name)
79+
{
80+
return new ConversionDiagnosticMessageBuilder()
81+
.OfType(SymbolType.Delegate)
82+
.Named(name)
83+
.Build();
84+
}
85+
86+
[NotNull]
87+
protected static string CreateMessageForParameter([NotNull] string name)
88+
{
89+
return new ConversionDiagnosticMessageBuilder()
90+
.OfType(SymbolType.Parameter)
91+
.Named(name)
92+
.Build();
93+
}
94+
}
95+
}

0 commit comments

Comments
 (0)