From 2863a9ec8d1e53f005b7b60ddef0e2dc47771ccc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Kon=C3=AD=C4=8Dek?= Date: Wed, 10 Oct 2018 15:25:28 +0200 Subject: [PATCH] Adding CSharpUseAnotherLiteralCodeFixProvider --- .../UseAnotherLiteralTests.cs | 1008 +++++++++++++++++ .../CSharpFeaturesResources.Designer.cs | 9 + .../Portable/CSharpFeaturesResources.resx | 3 + .../CSharpUseAnotherLiteralCodeFixProvider.cs | 78 ++ .../xlf/CSharpFeaturesResources.cs.xlf | 5 + .../xlf/CSharpFeaturesResources.de.xlf | 5 + .../xlf/CSharpFeaturesResources.es.xlf | 5 + .../xlf/CSharpFeaturesResources.fr.xlf | 5 + .../xlf/CSharpFeaturesResources.it.xlf | 5 + .../xlf/CSharpFeaturesResources.ja.xlf | 5 + .../xlf/CSharpFeaturesResources.ko.xlf | 5 + .../xlf/CSharpFeaturesResources.pl.xlf | 5 + .../xlf/CSharpFeaturesResources.pt-BR.xlf | 5 + .../xlf/CSharpFeaturesResources.ru.xlf | 5 + .../xlf/CSharpFeaturesResources.tr.xlf | 5 + .../xlf/CSharpFeaturesResources.zh-Hans.xlf | 5 + .../xlf/CSharpFeaturesResources.zh-Hant.xlf | 5 + .../PredefinedCodeFixProviderNames.cs | 1 + src/Test/Utilities/Portable/Traits/Traits.cs | 1 + 19 files changed, 1165 insertions(+) create mode 100644 src/EditorFeatures/CSharpTest/UseAnotherLiteral/UseAnotherLiteralTests.cs create mode 100644 src/Features/CSharp/Portable/UseAnotherLiteral/CSharpUseAnotherLiteralCodeFixProvider.cs diff --git a/src/EditorFeatures/CSharpTest/UseAnotherLiteral/UseAnotherLiteralTests.cs b/src/EditorFeatures/CSharpTest/UseAnotherLiteral/UseAnotherLiteralTests.cs new file mode 100644 index 00000000000..5d07ba978fe --- /dev/null +++ b/src/EditorFeatures/CSharpTest/UseAnotherLiteral/UseAnotherLiteralTests.cs @@ -0,0 +1,1008 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.UseAnotherLiteral; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics; +using Microsoft.CodeAnalysis.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.UseAnotherLiteral +{ + [Trait(Traits.Feature, Traits.Features.CodeActionsUseAnotherLiteral)] + public sealed class UseAnotherLiteralTests : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest + { + internal override (DiagnosticAnalyzer, CodeFixProvider) CreateDiagnosticProviderAndFixer(Workspace workspace) + => (null, new CSharpUseAnotherLiteralCodeFixProvider()); + + private static readonly TestParameters s_csharpLatest = + new TestParameters(parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.Latest)); + + private static readonly TestParameters s_csharp7_1 = + new TestParameters(parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp7_1)); + + [Fact] + public async Task TestCSharpLatest_InCaseSwitchLabel_Bool() + { + await TestInRegularAndScript1Async( +@"class C +{ + void M() + { + switch (true) { case [||]default: } + } +}", +@"class C +{ + void M() + { + switch (true) { case false: } + } +}", parameters: s_csharpLatest); + } + + [Fact] + public async Task TestCSharpLatest_InCasePatternSwitchLabel_Bool() + { + await TestInRegularAndScript1Async( +@"class C +{ + void M() + { + switch (true) { case [||]default when true: } + } +}", +@"class C +{ + void M() + { + switch (true) { case false when true: } + } +}", parameters: s_csharpLatest); + } + + [Fact] + public async Task TestCSharpLatest_InIsPattern_Int() + { + await TestInRegularAndScript1Async( +@"class C +{ + void M() + { + if (1 is [||]default) { } + } +}", +@"class C +{ + void M() + { + if (1 is 0) { } + } +}", parameters: s_csharpLatest); + } + + [Fact] + public async Task TestCSharp7_1_InCaseSwitchLabel_Int() + { + await TestInRegularAndScript1Async( +@"class C +{ + void M() + { + switch (1) { case [||]default: } + } +}", +@"class C +{ + void M() + { + switch (1) { case 0: } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InCaseSwitchLabel_Int_InParentheses() + { + await TestInRegularAndScript1Async( +@"class C +{ + void M() + { + switch (1) { case ([||]default): } + } +}", +@"class C +{ + void M() + { + switch (1) { case (0): } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InCaseSwitchLabel_Int_NotInsideCast() + { + await TestMissingInRegularAndScriptAsync( +@"class C +{ + void M() + { + switch (1) { case (int)[||]default: } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InCaseSwitchLabel_Int_NotOnDefaultExpression() + { + await TestMissingInRegularAndScriptAsync( +@"class C +{ + void M() + { + switch (1) { case [||]default(int): } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InCaseSwitchLabel_NotForInvalidType1() + { + await TestMissingInRegularAndScriptAsync( +@"class C +{ + void M() + { + switch (null) { case [||]default: } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InCaseSwitchLabel_NotForInvalidType2() + { + await TestMissingInRegularAndScriptAsync( +@"class C +{ + void M() + { + switch (default) { case [||]default: } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InCaseSwitchLabel_NotForInvalidType3() + { + await TestMissingInRegularAndScriptAsync( +@"class C +{ + void M() + { + switch (() => { }) { case [||]default: } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InCaseSwitchLabel_NotForMissingExpression() + { + await TestMissingInRegularAndScriptAsync( +@"class C +{ + void M() + { + switch () { case [||]default: } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InCaseSwitchLabel_NotForTupleType() + { + await TestMissingInRegularAndScriptAsync( +@"class C +{ + void M() + { + switch ((0, true)) { case [||]default: } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InCasePatternSwitchLabel_Int() + { + await TestInRegularAndScript1Async( +@"class C +{ + void M() + { + switch (1) { case [||]default when true: } + } +}", +@"class C +{ + void M() + { + switch (1) { case 0 when true: } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InCasePatternSwitchLabel_Int_InParentheses() + { + await TestInRegularAndScript1Async( +@"class C +{ + void M() + { + switch (1) { case ([||]default) when true: } + } +}", +@"class C +{ + void M() + { + switch (1) { case (0) when true: } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InCasePatternSwitchLabel_Int_NotInsideCast() + { + await TestMissingInRegularAndScriptAsync( +@"class C +{ + void M() + { + switch (1) { case (int)[||]default when true: } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InCasePatternSwitchLabel_Int_NotOnDefaultExpression() + { + await TestMissingInRegularAndScriptAsync( +@"class C +{ + void M() + { + switch (1) { case [||]default(int) when true: } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InCasePatternSwitchLabel_NotForInvalidType1() + { + await TestMissingInRegularAndScriptAsync( +@"class C +{ + void M() + { + switch (null) { case [||]default when true: } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InCasePatternSwitchLabel_NotForInvalidType2() + { + await TestMissingInRegularAndScriptAsync( +@"class C +{ + void M() + { + switch (default) { case [||]default when true: } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InCasePatternSwitchLabel_NotForInvalidType3() + { + await TestMissingInRegularAndScriptAsync( +@"class C +{ + void M() + { + switch (() => { }) { case [||]default when true: } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InCasePatternSwitchLabel_NotForMissingExpression() + { + await TestMissingInRegularAndScriptAsync( +@"class C +{ + void M() + { + switch () { case [||]default when true: } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InCasePatternSwitchLabel_NotForTupleType() + { + await TestMissingInRegularAndScriptAsync( +@"class C +{ + void M() + { + switch ((0, true)) { case [||]default when true: } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InIsPattern_Bool() + { + await TestInRegularAndScript1Async( +@"class C +{ + void M() + { + if (true is [||]default) { } + } +}", +@"class C +{ + void M() + { + if (true is false) { } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InIsPattern_Bool_InParentheses() + { + await TestInRegularAndScript1Async( +@"class C +{ + void M() + { + if (true is ([||]default)) { } + } +}", +@"class C +{ + void M() + { + if (true is (false)) { } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InIsPattern_Bool_NotInsideCast() + { + await TestMissingInRegularAndScriptAsync( +@"class C +{ + void M() + { + if (true is (bool)[||]default) { } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InIsPattern_Bool_NotOnDefaultExpression() + { + await TestMissingInRegularAndScriptAsync( +@"class C +{ + void M() + { + if (true is [||]default(bool)) { } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InIsPattern_Int() + { + await TestInRegularAndScript1Async( +@"class C +{ + void M() + { + int value = 1; + if (value is [||]default) { } + } +}", +@"class C +{ + void M() + { + int value = 1; + if (value is 0) { } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InIsPattern_UInt() + { + await TestInRegularAndScript1Async( +@"class C +{ + void M() + { + uint value = 1; + if (value is [||]default) { } + } +}", +@"class C +{ + void M() + { + uint value = 1; + if (value is 0U) { } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InIsPattern_Byte() + { + await TestInRegularAndScript1Async( +@"class C +{ + void M() + { + byte value = 1; + if (value is [||]default) { } + } +}", +@"class C +{ + void M() + { + byte value = 1; + if (value is 0) { } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InIsPattern_SByte() + { + await TestInRegularAndScript1Async( +@"class C +{ + void M() + { + sbyte value = 1; + if (value is [||]default) { } + } +}", +@"class C +{ + void M() + { + sbyte value = 1; + if (value is 0) { } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InIsPattern_Short() + { + await TestInRegularAndScript1Async( +@"class C +{ + void M() + { + short value = 1; + if (value is [||]default) { } + } +}", +@"class C +{ + void M() + { + short value = 1; + if (value is 0) { } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InIsPattern_UShort() + { + await TestInRegularAndScript1Async( +@"class C +{ + void M() + { + ushort value = 1; + if (value is [||]default) { } + } +}", +@"class C +{ + void M() + { + ushort value = 1; + if (value is 0) { } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InIsPattern_Long() + { + await TestInRegularAndScript1Async( +@"class C +{ + void M() + { + long value = 1; + if (value is [||]default) { } + } +}", +@"class C +{ + void M() + { + long value = 1; + if (value is 0L) { } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InIsPattern_ULong() + { + await TestInRegularAndScript1Async( +@"class C +{ + void M() + { + ulong value = 1; + if (value is [||]default) { } + } +}", +@"class C +{ + void M() + { + ulong value = 1; + if (value is 0UL) { } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InIsPattern_Float() + { + await TestInRegularAndScript1Async( +@"class C +{ + void M() + { + float value = 1; + if (value is [||]default) { } + } +}", +@"class C +{ + void M() + { + float value = 1; + if (value is 0F) { } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InIsPattern_Double() + { + await TestInRegularAndScript1Async( +@"class C +{ + void M() + { + double value = 1; + if (value is [||]default) { } + } +}", +@"class C +{ + void M() + { + double value = 1; + if (value is 0D) { } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InIsPattern_Decimal() + { + await TestInRegularAndScript1Async( +@"class C +{ + void M() + { + decimal value = 1; + if (value is [||]default) { } + } +}", +@"class C +{ + void M() + { + decimal value = 1; + if (value is 0M) { } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InIsPattern_Char() + { + await TestInRegularAndScript1Async( +@"class C +{ + void M() + { + char value = '1'; + if (value is [||]default) { } + } +}", +@"class C +{ + void M() + { + char value = '1'; + if (value is '\0') { } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InIsPattern_String() + { + await TestInRegularAndScript1Async( +@"class C +{ + void M() + { + string value = ""; + if (value is [||]default) { } + } +}", +@"class C +{ + void M() + { + string value = ""; + if (value is null) { } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InIsPattern_Object() + { + await TestInRegularAndScript1Async( +@"class C +{ + void M() + { + var value = new object(); + if (value is [||]default) { } + } +}", +@"class C +{ + void M() + { + var value = new object(); + if (value is null) { } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InIsPattern_NotForInvalidType1() + { + await TestMissingInRegularAndScriptAsync( +@"class C +{ + void M() + { + var value = null; + if (value is [||]default) { } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InIsPattern_NotForInvalidType2() + { + await TestMissingInRegularAndScriptAsync( +@"class C +{ + void M() + { + if (value is [||]default) { } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InIsPattern_NotForInvalidType3() + { + await TestMissingInRegularAndScriptAsync( +@"class C +{ + void M() + { + if (null is [||]default) { } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InIsPattern_NotForInvalidType4() + { + await TestMissingInRegularAndScriptAsync( +@"class C +{ + void M() + { + if (default is [||]default) { } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InIsPattern_NotForInvalidType5() + { + await TestMissingInRegularAndScriptAsync( +@"class C +{ + void M() + { + if (() => { } is [||]default) { } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InIsPattern_NotForMissingExpression() + { + await TestMissingInRegularAndScriptAsync( +@"class C +{ + void M() + { + if ( is [||]default) { } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InIsPattern_AnonymousType() + { + await TestInRegularAndScript1Async( +@"class C +{ + void M() + { + if (new { a = 0 } is [||]default) { } + } +}", +@"class C +{ + void M() + { + if (new { a = 0 } is null) { } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InIsPattern_CustomClass() + { + await TestInRegularAndScript1Async( +@"class C +{ + class Class { } + void M() + { + if (new Class() is [||]default) { } + } +}", +@"class C +{ + class Class { } + void M() + { + if (new Class() is null) { } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InIsPattern_CustomInterface() + { + await TestInRegularAndScript1Async( +@"class C +{ + interface Interface { } + void M() + { + if (new Interface() is [||]default) { } + } +}", +@"class C +{ + interface Interface { } + void M() + { + if (new Interface() is null) { } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InIsPattern_CustomDelegate() + { + await TestInRegularAndScript1Async( +@"class C +{ + delegate void Delegate(); + void M() + { + if (new Delegate() is [||]default) { } + } +}", +@"class C +{ + delegate void Delegate(); + void M() + { + if (new Delegate() is null) { } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InIsPattern_CustomEnum() + { + await TestInRegularAndScript1Async( +@"class C +{ + enum Enum { } + void M() + { + if (new Enum() is [||]default) { } + } +}", +@"class C +{ + enum Enum { } + void M() + { + if (new Enum() is 0) { } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InIsPattern_NotForCustomStruct() + { + await TestMissingInRegularAndScriptAsync( +@"class C +{ + struct Struct { } + void M() + { + if (new Struct() is [||]default) { } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InIsPattern_NotForTupleType() + { + await TestMissingInRegularAndScriptAsync( +@"class C +{ + void M() + { + if ((0, true) is [||]default) { } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_InIsPattern_Bool_Trivia() + { + await TestInRegularAndScript1Async( +@"class C +{ + void M() + { + if (true is + /*a*/ [||]default /*b*/) { } + } +}", +@"class C +{ + void M() + { + if (true is + /*a*/ false /*b*/) { } + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_NotInsideExpression() + { + await TestMissingInRegularAndScriptAsync( +@"class C +{ + void M() + { + int i = [||]default; + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7_1_NotInsideExpression_InvalidType() + { + await TestMissingInRegularAndScriptAsync( +@"class C +{ + void M() + { + var v = [||]default; + } +}", parameters: s_csharp7_1); + } + + [Fact] + public async Task TestCSharp7Lower_NotInsideExpression() + { + foreach (var languageVersion in new[] { + LanguageVersion.CSharp7, + LanguageVersion.CSharp6, + LanguageVersion.CSharp5, + LanguageVersion.CSharp4, + LanguageVersion.CSharp3, + LanguageVersion.CSharp2, + LanguageVersion.CSharp1, + }) + { + await TestMissingInRegularAndScriptAsync( +@"class C +{ + void M() + { + int i = [||]default; + } +}", parameters: new TestParameters(parseOptions: CSharpParseOptions.Default.WithLanguageVersion(languageVersion))); + } + } + } +} diff --git a/src/Features/CSharp/Portable/CSharpFeaturesResources.Designer.cs b/src/Features/CSharp/Portable/CSharpFeaturesResources.Designer.cs index 5d9e03970ab..e75857fbef1 100644 --- a/src/Features/CSharp/Portable/CSharpFeaturesResources.Designer.cs +++ b/src/Features/CSharp/Portable/CSharpFeaturesResources.Designer.cs @@ -1243,6 +1243,15 @@ internal class CSharpFeaturesResources { } } + /// + /// Looks up a localized string similar to Use '{0}'. + /// + internal static string Use_0 { + get { + return ResourceManager.GetString("Use_0", resourceCulture); + } + } + /// /// Looks up a localized string similar to Use explicit type. /// diff --git a/src/Features/CSharp/Portable/CSharpFeaturesResources.resx b/src/Features/CSharp/Portable/CSharpFeaturesResources.resx index 0f1e415c673..8c0906e9019 100644 --- a/src/Features/CSharp/Portable/CSharpFeaturesResources.resx +++ b/src/Features/CSharp/Portable/CSharpFeaturesResources.resx @@ -572,4 +572,7 @@ Remove unused variables + + Use '{0}' + \ No newline at end of file diff --git a/src/Features/CSharp/Portable/UseAnotherLiteral/CSharpUseAnotherLiteralCodeFixProvider.cs b/src/Features/CSharp/Portable/UseAnotherLiteral/CSharpUseAnotherLiteralCodeFixProvider.cs new file mode 100644 index 00000000000..55ca69ad6d7 --- /dev/null +++ b/src/Features/CSharp/Portable/UseAnotherLiteral/CSharpUseAnotherLiteralCodeFixProvider.cs @@ -0,0 +1,78 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Immutable; +using System.Composition; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.CSharp.UseAnotherLiteral +{ + [ExportCodeFixProvider(LanguageNames.CSharp, Name = PredefinedCodeFixProviderNames.UseAnotherLiteral), Shared] + internal sealed class CSharpUseAnotherLiteralCodeFixProvider : CodeFixProvider + { + private const string CS8313 = nameof(CS8313); // A default literal 'default' is not valid as a case constant. Use another literal (e.g. '0' or 'null') as appropriate. If you intended to write the default label, use 'default:' without 'case'. + private const string CS8363 = nameof(CS8363); // A default literal 'default' is not valid as a pattern. Use another literal (e.g. '0' or 'null') as appropriate. To match everything, use a discard pattern 'var _'. + + public override ImmutableArray FixableDiagnosticIds { get; } = + ImmutableArray.Create(CS8313, CS8363); + + public override FixAllProvider GetFixAllProvider() + { + // This code fix addresses very specific compiler errors. It's unlikely there will be more than 1 of them at a time. + return null; + } + + public override async Task RegisterCodeFixesAsync(CodeFixContext context) + { + var syntaxRoot = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); + var token = syntaxRoot.FindToken(context.Span.Start); + + if (token.Span == context.Span && + token.IsKind(SyntaxKind.DefaultKeyword) && + token.Parent.IsKind(SyntaxKind.DefaultLiteralExpression)) + { + var defaultLiteral = (LiteralExpressionSyntax)token.Parent; + var semanticModel = await context.Document.GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false); + + var constant = semanticModel.GetConstantValue(defaultLiteral, context.CancellationToken); + if (!constant.HasValue) + { + return; + } + + var newLiteral = SyntaxGenerator.GetGenerator(context.Document).LiteralExpression(constant.Value); + + context.RegisterCodeFix( + new MyCodeAction( + c => FixAsync(context.Document, context.Span, newLiteral, c), + newLiteral.ToString()), + context.Diagnostics); + } + } + + private static async Task FixAsync(Document document, TextSpan span, SyntaxNode newLiteral, CancellationToken cancellationToken) + { + var syntaxRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + + var defaultToken = syntaxRoot.FindToken(span.Start); + var defaultLiteral = (LiteralExpressionSyntax)defaultToken.Parent; + + var newRoot = syntaxRoot.ReplaceNode(defaultLiteral, newLiteral.WithTriviaFrom(defaultLiteral)); + return document.WithSyntaxRoot(newRoot); + } + + private sealed class MyCodeAction : CodeAction.DocumentChangeAction + { + public MyCodeAction(Func> createChangedDocument, string literal) + : base(string.Format(CSharpFeaturesResources.Use_0, literal), createChangedDocument, CSharpFeaturesResources.Use_0) + { + } + } + } +} diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.cs.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.cs.xlf index 95a696b91ae..203d98c49b6 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.cs.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.cs.xlf @@ -107,6 +107,11 @@ Sort accessibility modifiers + + Use '{0}' + Use '{0}' + + 'if' statement can be simplified 'if' statement can be simplified diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.de.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.de.xlf index 312762c557d..1cb14d0dea9 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.de.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.de.xlf @@ -107,6 +107,11 @@ Sort accessibility modifiers + + Use '{0}' + Use '{0}' + + 'if' statement can be simplified 'if' statement can be simplified diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.es.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.es.xlf index a8ec4677dbe..cc03acfabdc 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.es.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.es.xlf @@ -107,6 +107,11 @@ Sort accessibility modifiers + + Use '{0}' + Use '{0}' + + 'if' statement can be simplified 'if' statement can be simplified diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.fr.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.fr.xlf index 8a1d72e206e..27bb9e58df9 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.fr.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.fr.xlf @@ -107,6 +107,11 @@ Sort accessibility modifiers + + Use '{0}' + Use '{0}' + + 'if' statement can be simplified 'if' statement can be simplified diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.it.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.it.xlf index f050952f195..293c65889fb 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.it.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.it.xlf @@ -107,6 +107,11 @@ Sort accessibility modifiers + + Use '{0}' + Use '{0}' + + 'if' statement can be simplified 'if' statement can be simplified diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ja.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ja.xlf index 5c132753aaf..e6ea7a3f2cf 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ja.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ja.xlf @@ -107,6 +107,11 @@ Sort accessibility modifiers + + Use '{0}' + Use '{0}' + + 'if' statement can be simplified 'if' statement can be simplified diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ko.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ko.xlf index bde0edec521..b60ad61c4a5 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ko.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ko.xlf @@ -107,6 +107,11 @@ Sort accessibility modifiers + + Use '{0}' + Use '{0}' + + 'if' statement can be simplified 'if' statement can be simplified diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pl.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pl.xlf index bc81c54aa53..06f1797a7ca 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pl.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pl.xlf @@ -107,6 +107,11 @@ Sort accessibility modifiers + + Use '{0}' + Use '{0}' + + 'if' statement can be simplified 'if' statement can be simplified diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pt-BR.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pt-BR.xlf index 564a40a1f20..40e6e91b059 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pt-BR.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pt-BR.xlf @@ -107,6 +107,11 @@ Sort accessibility modifiers + + Use '{0}' + Use '{0}' + + 'if' statement can be simplified 'if' statement can be simplified diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ru.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ru.xlf index e9ad5dfa9a3..fe8592686d5 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ru.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ru.xlf @@ -107,6 +107,11 @@ Sort accessibility modifiers + + Use '{0}' + Use '{0}' + + 'if' statement can be simplified 'if' statement can be simplified diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.tr.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.tr.xlf index 5934f72ac35..021840d1b3d 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.tr.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.tr.xlf @@ -107,6 +107,11 @@ Sort accessibility modifiers + + Use '{0}' + Use '{0}' + + 'if' statement can be simplified 'if' statement can be simplified diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hans.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hans.xlf index b0095f1b017..5d419c063b3 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hans.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hans.xlf @@ -107,6 +107,11 @@ Sort accessibility modifiers + + Use '{0}' + Use '{0}' + + 'if' statement can be simplified 'if' statement can be simplified diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hant.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hant.xlf index 363701cf87b..5dad2fd5546 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hant.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hant.xlf @@ -107,6 +107,11 @@ Sort accessibility modifiers + + Use '{0}' + Use '{0}' + + 'if' statement can be simplified 'if' statement can be simplified diff --git a/src/Features/Core/Portable/CodeFixes/PredefinedCodeFixProviderNames.cs b/src/Features/Core/Portable/CodeFixes/PredefinedCodeFixProviderNames.cs index 98f907a9d74..33c1b29781a 100644 --- a/src/Features/Core/Portable/CodeFixes/PredefinedCodeFixProviderNames.cs +++ b/src/Features/Core/Portable/CodeFixes/PredefinedCodeFixProviderNames.cs @@ -54,6 +54,7 @@ internal static class PredefinedCodeFixProviderNames public const string Suppression = nameof(Suppression); public const string AddOverloads = nameof(AddOverloads); public const string AddNew = nameof(AddNew); + public const string UseAnotherLiteral = nameof(UseAnotherLiteral); public const string UseImplicitType = nameof(UseImplicitType); public const string UseExplicitType = nameof(UseExplicitType); public const string UseCollectionInitializer = nameof(UseCollectionInitializer); diff --git a/src/Test/Utilities/Portable/Traits/Traits.cs b/src/Test/Utilities/Portable/Traits/Traits.cs index e605e3f953f..4ef8605fafa 100644 --- a/src/Test/Utilities/Portable/Traits/Traits.cs +++ b/src/Test/Utilities/Portable/Traits/Traits.cs @@ -122,6 +122,7 @@ public static class Features public const string CodeActionsSimplifyTypeNames = "CodeActions.SimplifyTypeNames"; public const string CodeActionsSpellcheck = "CodeActions.Spellcheck"; public const string CodeActionsSuppression = "CodeActions.Suppression"; + public const string CodeActionsUseAnotherLiteral = "CodeActions.UseAnotherLiteral"; public const string CodeActionsUseInterpolatedVerbatimString = "CodeActions.UseInterpolatedVerbatimString"; public const string CodeActionsUseAutoProperty = "CodeActions.UseAutoProperty"; public const string CodeActionsUseCoalesceExpression = "CodeActions.UseCoalesceExpression"; -- GitLab