diff --git a/ChangeLog.md b/ChangeLog.md index 258b2a71a4..94c5157720 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Convert more syntax to implicit object creation (RCS1250) ([#910](https://github.com/josefpihrt/roslynator/pull/910)). +- Add code fix for CS0037 ([#929](https://github.com/josefpihrt/roslynator/pull/929)). ### Changed diff --git a/docs/cs/CS0037.md b/docs/cs/CS0037.md index 5af8231da2..879c7654aa 100644 --- a/docs/cs/CS0037.md +++ b/docs/cs/CS0037.md @@ -9,6 +9,8 @@ ## Code Fixes +* Remove property or field initializer * Replace 'null' with default value + *\(Generated with [DotMarkdown](http://github.com/JosefPihrt/DotMarkdown)\)* \ No newline at end of file diff --git a/src/CodeFixes/CSharp/CodeFixes/RemovePropertyOrFieldInitializerCodeFixProvider.cs b/src/CodeFixes/CSharp/CodeFixes/RemovePropertyOrFieldInitializerCodeFixProvider.cs index 25382354b2..325d1ed68e 100644 --- a/src/CodeFixes/CSharp/CodeFixes/RemovePropertyOrFieldInitializerCodeFixProvider.cs +++ b/src/CodeFixes/CSharp/CodeFixes/RemovePropertyOrFieldInitializerCodeFixProvider.cs @@ -2,7 +2,6 @@ using System.Collections.Immutable; using System.Composition; -using System.Diagnostics; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeActions; @@ -24,6 +23,7 @@ public override ImmutableArray FixableDiagnosticIds get { return ImmutableArray.Create( + CompilerDiagnosticIdentifiers.CS0037_CannotConvertNullToTypeBecauseItIsNonNullableValueType, CompilerDiagnosticIdentifiers.CS0573_CannotHaveInstancePropertyOrFieldInitializersInStruct, CompilerDiagnosticIdentifiers.CS8050_OnlyAutoImplementedPropertiesCanHaveInitializers); } @@ -41,12 +41,9 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) if (!TryFindToken(root, context.Span.Start, out SyntaxToken token)) return; - SyntaxDebug.Assert(token.IsKind(SyntaxKind.IdentifierToken), token); + SyntaxDebug.Assert(token.IsKind(SyntaxKind.IdentifierToken, SyntaxKind.NullKeyword), token); - if (!token.IsKind(SyntaxKind.IdentifierToken)) - return; - - switch (token.Parent) + switch (GetNode(token)) { case PropertyDeclarationSyntax propertyDeclaration: { @@ -83,12 +80,36 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) return context.Document.ReplaceNodeAsync(variableDeclarator, newNode, ct); }, - GetEquivalenceKey(CompilerDiagnosticIdentifiers.CS0573_CannotHaveInstancePropertyOrFieldInitializersInStruct, CodeFixIdentifiers.RemovePropertyOrFieldInitializer)); + GetEquivalenceKey(diagnostic, CodeFixIdentifiers.RemovePropertyOrFieldInitializer)); context.RegisterCodeFix(codeAction, diagnostic); break; } } + + static SyntaxNode GetNode(SyntaxToken token) + { + if (token.IsKind(SyntaxKind.IdentifierToken)) + return token.Parent; + + if (token.IsKind(SyntaxKind.NullKeyword)) + { + SyntaxNode node = token.Parent; + + if (node.IsKind(SyntaxKind.NullLiteralExpression)) + { + node = node.Parent; + + if (node.IsKind(SyntaxKind.SuppressNullableWarningExpression)) + node = node.Parent; + + if (node.IsKind(SyntaxKind.EqualsValueClause)) + return node.Parent; + } + } + + return null; + } } } } diff --git a/src/CodeFixes/CodeFixes.xml b/src/CodeFixes/CodeFixes.xml index 9634bc343d..e05517a416 100644 --- a/src/CodeFixes/CodeFixes.xml +++ b/src/CodeFixes/CodeFixes.xml @@ -120,6 +120,7 @@ + CS0037 CS0573 CS8050 diff --git a/src/Tests/CodeFixes.Tests/CS0037CannotConvertNullToTypeBecauseItIsNonNullableValueTypeTests.cs b/src/Tests/CodeFixes.Tests/CS0037CannotConvertNullToTypeBecauseItIsNonNullableValueTypeTests.cs new file mode 100644 index 0000000000..d1f1991051 --- /dev/null +++ b/src/Tests/CodeFixes.Tests/CS0037CannotConvertNullToTypeBecauseItIsNonNullableValueTypeTests.cs @@ -0,0 +1,73 @@ +// Copyright (c) Josef Pihrt and Contributors. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Threading.Tasks; +using Roslynator.Testing.CSharp; +using Xunit; + +namespace Roslynator.CSharp.CodeFixes.Tests +{ + public class CS0037CannotConvertNullToTypeBecauseItIsNonNullableValueTypeTests : AbstractCSharpCompilerDiagnosticFixVerifier + { + public override string DiagnosticId { get; } = CompilerDiagnosticIdentifiers.CS0037_CannotConvertNullToTypeBecauseItIsNonNullableValueType; + + [Fact, Trait(Traits.CodeFix, CompilerDiagnosticIdentifiers.CS0037_CannotConvertNullToTypeBecauseItIsNonNullableValueType)] + public async Task Test_RemovePropertyInitializer() + { + await VerifyFixAsync(@" +using System; + +class C +{ + public StringSplitOptions Options { get; set } = null; +} +", @" +using System; + +class C +{ + public StringSplitOptions Options { get; set } +} +", equivalenceKey: EquivalenceKey.Create(DiagnosticId, CodeFixIdentifiers.RemovePropertyOrFieldInitializer)); + } + + [Fact, Trait(Traits.CodeFix, CompilerDiagnosticIdentifiers.CS0037_CannotConvertNullToTypeBecauseItIsNonNullableValueType)] + public async Task Test_RemovePropertyInitializer_NullForgivingOperator() + { + await VerifyFixAsync(@" +using System; + +class C +{ + public StringSplitOptions Options { get; set } = null!; +} +", @" +using System; + +class C +{ + public StringSplitOptions Options { get; set } +} +", equivalenceKey: EquivalenceKey.Create(DiagnosticId, CodeFixIdentifiers.RemovePropertyOrFieldInitializer)); + } + + [Fact, Trait(Traits.CodeFix, CompilerDiagnosticIdentifiers.CS0037_CannotConvertNullToTypeBecauseItIsNonNullableValueType)] + public async Task Test_RemoveFieldInitializer() + { + await VerifyFixAsync(@" +using System; + +class C +{ + public StringSplitOptions Options = null!; +} +", @" +using System; + +class C +{ + public StringSplitOptions Options; +} +", equivalenceKey: EquivalenceKey.Create(DiagnosticId, CodeFixIdentifiers.RemovePropertyOrFieldInitializer)); + } + } +}