diff --git a/src/Analyzers/CSharp/CodeFixes/UseDefaultLiteral/CSharpUseDefaultLiteralCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/UseDefaultLiteral/CSharpUseDefaultLiteralCodeFixProvider.cs index 55fad8454a415..cb7cf429285e2 100644 --- a/src/Analyzers/CSharp/CodeFixes/UseDefaultLiteral/CSharpUseDefaultLiteralCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/UseDefaultLiteral/CSharpUseDefaultLiteralCodeFixProvider.cs @@ -2,24 +2,19 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Immutable; using System.Composition; -using System.Diagnostics.CodeAnalysis; -using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; -using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.UseDefaultLiteral { @@ -27,7 +22,7 @@ namespace Microsoft.CodeAnalysis.CSharp.UseDefaultLiteral internal partial class CSharpUseDefaultLiteralCodeFixProvider : SyntaxEditorBasedCodeFixProvider { [ImportingConstructor] - [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public CSharpUseDefaultLiteralCodeFixProvider() { } @@ -53,12 +48,11 @@ protected override async Task FixAllAsync( // Here, we can replace either of the default expressions, but not both. So we have // to replace one at a time, and only actually replace if it's still safe to do so. - var parseOptions = (CSharpParseOptions)document.Project.ParseOptions; - var options = (CSharpAnalyzerOptionsProvider)await document.GetAnalyzerOptionsProviderAsync(cancellationToken).ConfigureAwait(false); var preferSimpleDefaultExpression = options.PreferSimpleDefaultExpression.Value; var originalRoot = editor.OriginalRoot; + var parseOptions = (CSharpParseOptions)originalRoot.SyntaxTree.Options; var originalNodes = diagnostics.SelectAsArray( d => (DefaultExpressionSyntax)originalRoot.FindNode(d.Location.SourceSpan, getInnermostNodeForTie: true)); diff --git a/src/Analyzers/CSharp/Tests/UseDefaultLiteral/UseDefaultLiteralTests.cs b/src/Analyzers/CSharp/Tests/UseDefaultLiteral/UseDefaultLiteralTests.cs index 65a36a369e344..b3439fc0fc238 100644 --- a/src/Analyzers/CSharp/Tests/UseDefaultLiteral/UseDefaultLiteralTests.cs +++ b/src/Analyzers/CSharp/Tests/UseDefaultLiteral/UseDefaultLiteralTests.cs @@ -2,648 +2,813 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.UseDefaultLiteral; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics; +using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; -using Xunit.Abstractions; namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.UseDefaultLiteral { + using VerifyCS = CSharpCodeFixVerifier< + CSharpUseDefaultLiteralDiagnosticAnalyzer, + CSharpUseDefaultLiteralCodeFixProvider>; + [Trait(Traits.Feature, Traits.Features.CodeActionsUseDefaultLiteral)] - public class UseDefaultLiteralTests : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest + public class UseDefaultLiteralTests { - public UseDefaultLiteralTests(ITestOutputHelper logger) - : base(logger) - { - } - - internal override (DiagnosticAnalyzer, CodeFixProvider) CreateDiagnosticProviderAndFixer(Workspace workspace) - => (new CSharpUseDefaultLiteralDiagnosticAnalyzer(), new CSharpUseDefaultLiteralCodeFixProvider()); - - private static readonly CSharpParseOptions s_parseOptions = - CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp7_1); - - private static readonly TestParameters s_testParameters = - new TestParameters(parseOptions: s_parseOptions); - [Fact] public async Task TestNotInCSharp7() { - await TestMissingAsync( -@" -class C -{ - void Goo(string s = [||]default(string)) - { - } -}", parameters: new TestParameters( - parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp7))); + var code = """ + class C + { + void Goo(string s = default(string)) + { + } + } + """; + + await new VerifyCS.Test() + { + TestCode = code, + FixedCode = code, + LanguageVersion = LanguageVersion.CSharp7 + }.RunAsync(); } [Fact] public async Task TestInParameterList() { - await TestAsync( -@" -class C -{ - void Goo(string s = [||]default(string)) - { - } -}", -@" -class C -{ - void Goo(string s = default) - { - } -}", parseOptions: s_parseOptions); + await new VerifyCS.Test + { + TestCode = """ + class C + { + void Goo(string s = [|default(string)|]) + { + } + } + """, + FixedCode = """ + class C + { + void Goo(string s = default) + { + } + } + """, + LanguageVersion = LanguageVersion.CSharp7_1 + }.RunAsync(); } [Fact] public async Task TestInIfCheck() { - await TestAsync( -@" -class C -{ - void Goo(string s) - { - if (s == [||]default(string)) { } - } -}", -@" -class C -{ - void Goo(string s) - { - if (s == default) { } - } -}", parseOptions: s_parseOptions); + await new VerifyCS.Test + { + TestCode = """ + class C + { + void Goo(string s) + { + if (s == [|default(string)|]) { } + } + } + """, + FixedCode = """ + class C + { + void Goo(string s) + { + if (s == default) { } + } + } + """, + LanguageVersion = LanguageVersion.CSharp7_1 + }.RunAsync(); } [Fact] public async Task TestInReturnStatement() { - await TestAsync( -@" -class C -{ - string Goo() - { - return [||]default(string); - } -}", -@" -class C -{ - string Goo() - { - return default; - } -}", parseOptions: s_parseOptions); + await new VerifyCS.Test + { + TestCode = """ + class C + { + string Goo() + { + return [|default(string)|]; + } + } + """, + FixedCode = """ + class C + { + string Goo() + { + return default; + } + } + """, + LanguageVersion = LanguageVersion.CSharp7_1 + }.RunAsync(); } [Fact] public async Task TestInReturnStatement2() { - await TestMissingAsync( -@" -class C -{ - string Goo() - { - return [||]default(int); - } -}", parameters: s_testParameters); + var code = """ + class C + { + string Goo() + { + return {|CS0029:default(int)|}; + } + } + """; + + await new VerifyCS.Test() + { + TestCode = code, + FixedCode = code, + LanguageVersion = LanguageVersion.CSharp7_1 + }.RunAsync(); } [Fact] public async Task TestInLambda1() { - await TestAsync( -@" -using System; - -class C -{ - void Goo() - { - Func f = () => [||]default(string); - } -}", -@" -using System; - -class C -{ - void Goo() - { - Func f = () => [||]default; - } -}", parseOptions: s_parseOptions); + await new VerifyCS.Test + { + TestCode = """ + using System; + + class C + { + void Goo() + { + Func f = () => [|default(string)|]; + } + } + """, + FixedCode = """ + using System; + + class C + { + void Goo() + { + Func f = () => default; + } + } + """, + LanguageVersion = LanguageVersion.CSharp7_1 + }.RunAsync(); } [Fact] public async Task TestInLambda2() { - await TestMissingAsync( -@" -using System; + var code = """ + using System; -class C -{ - void Goo() - { - Func f = () => [||]default(int); - } -}", parameters: s_testParameters); + class C + { + void Goo() + { + Func f = () => {|CS1662:{|CS0029:default(int)|}|}; + } + } + """; + + await new VerifyCS.Test() + { + TestCode = code, + FixedCode = code, + LanguageVersion = LanguageVersion.CSharp7_1 + }.RunAsync(); } [Fact] public async Task TestInLocalInitializer() { - await TestAsync( -@" -class C -{ - void Goo() - { - string s = [||]default(string); - } -}", -@" -class C -{ - void Goo() - { - string s = default; - } -}", parseOptions: s_parseOptions); + await new VerifyCS.Test + { + TestCode = """ + class C + { + void Goo() + { + string s = [|default(string)|]; + } + } + """, + FixedCode = """ + class C + { + void Goo() + { + string s = default; + } + } + """, + LanguageVersion = LanguageVersion.CSharp7_1 + }.RunAsync(); } [Fact] public async Task TestInLocalInitializer2() { - await TestMissingAsync( -@" -class C -{ - void Goo() - { - string s = [||]default(int); - } -}", parameters: s_testParameters); + var code = """ + class C + { + void Goo() + { + string s = {|CS0029:default(int)|}; + } + } + """; + + await new VerifyCS.Test() + { + TestCode = code, + FixedCode = code, + LanguageVersion = LanguageVersion.CSharp7_1 + }.RunAsync(); } [Fact] public async Task TestNotForVar() { - await TestMissingAsync( -@" -class C -{ - void Goo() - { - var s = [||]default(string); - } -}", parameters: s_testParameters); + var code = """ + class C + { + void Goo() + { + var s = default(string); + } + } + """; + + await new VerifyCS.Test() + { + TestCode = code, + FixedCode = code, + LanguageVersion = LanguageVersion.CSharp7_1 + }.RunAsync(); } [Fact] public async Task TestInInvocationExpression() { - await TestAsync( -@" -class C -{ - void Goo() - { - Bar([||]default(string)); - } - - void Bar(string s) { } -}", -@" -class C -{ - void Goo() - { - Bar(default); - } - - void Bar(string s) { } -}", parseOptions: s_parseOptions); + await new VerifyCS.Test + { + TestCode = """ + class C + { + void Goo() + { + Bar([|default(string)|]); + } + + void Bar(string s) { } + } + """, + FixedCode = """ + class C + { + void Goo() + { + Bar(default); + } + + void Bar(string s) { } + } + """, + LanguageVersion = LanguageVersion.CSharp7_1 + }.RunAsync(); } [Fact] public async Task TestNotWithMultipleOverloads() { - await TestMissingAsync( -@" -class C -{ - void Goo() - { - Bar([||]default(string)); - } + var code = """ + class C + { + void Goo() + { + Bar(default(string)); + } - void Bar(string s) { } - void Bar(int i); -}", parameters: s_testParameters); + void Bar(string s) { } + void Bar(int i) { } + } + """; + + await new VerifyCS.Test() + { + TestCode = code, + FixedCode = code, + LanguageVersion = LanguageVersion.CSharp7_1 + }.RunAsync(); } [Fact] public async Task TestLeftSideOfTernary() { - await TestAsync( -@" -class C -{ - void Goo(bool b) - { - var v = b ? [||]default(string) : default(string); - } -}", -@" -class C -{ - void Goo(bool b) - { - var v = b ? default : default(string); - } -}", parseOptions: s_parseOptions); + await new VerifyCS.Test + { + TestCode = """ + class C + { + void Goo(bool b) + { + var v = b ? [|default(string)|] : [|default(string)|]; + } + } + """, + FixedCode = """ + class C + { + void Goo(bool b) + { + var v = b ? default : default(string); + } + } + """, + LanguageVersion = LanguageVersion.CSharp7_1, + DiagnosticSelector = d => d[0], + CodeFixTestBehaviors = Testing.CodeFixTestBehaviors.FixOne | Testing.CodeFixTestBehaviors.SkipFixAllCheck + }.RunAsync(); } [Fact] public async Task TestRightSideOfTernary() { - await TestAsync( -@" -class C -{ - void Goo(bool b) - { - var v = b ? default(string) : [||]default(string); - } -}", -@" -class C -{ - void Goo(bool b) - { - var v = b ? default(string) : default; - } -}", parseOptions: s_parseOptions); + await new VerifyCS.Test + { + TestCode = """ + class C + { + void Goo(bool b) + { + var v = b ? [|default(string)|] : [|default(string)|]; + } + } + """, + FixedCode = """ + class C + { + void Goo(bool b) + { + var v = b ? default(string) : default; + } + } + """, + LanguageVersion = LanguageVersion.CSharp7_1, + DiagnosticSelector = d => d[1], + CodeFixTestBehaviors = Testing.CodeFixTestBehaviors.FixOne | Testing.CodeFixTestBehaviors.SkipFixAllCheck + }.RunAsync(); } [Fact] public async Task TestFixAll1() { - await TestAsync( -@" -class C -{ - void Goo() - { - string s1 = {|FixAllInDocument:default|}(string); - string s2 = default(string); - } -}", -@" -class C -{ - void Goo() - { - string s1 = default; - string s2 = default; - } -}", parseOptions: s_parseOptions); + await new VerifyCS.Test + { + TestCode = """ + class C + { + void Goo() + { + string s1 = [|default(string)|]; + string s2 = [|default(string)|]; + } + } + """, + FixedCode = """ + class C + { + void Goo() + { + string s1 = default; + string s2 = default; + } + } + """, + LanguageVersion = LanguageVersion.CSharp7_1 + }.RunAsync(); } [Fact] public async Task TestFixAll2() { - await TestAsync( -@" -class C -{ - void Goo(bool b) - { - string s1 = b ? {|FixAllInDocument:default|}(string) : default(string); - } -}", -@" -class C -{ - void Goo(bool b) - { - string s1 = b ? default : default(string); - } -}", parseOptions: s_parseOptions); + await new VerifyCS.Test + { + TestCode = """ + class C + { + void Goo(bool b) + { + string s1 = b ? [|default(string)|] : [|default(string)|]; + } + } + """, + FixedCode = """ + class C + { + void Goo(bool b) + { + string s1 = b ? default : default(string); + } + } + """, + LanguageVersion = LanguageVersion.CSharp7_1 + }.RunAsync(); } [Fact] public async Task TestFixAll3() { - await TestAsync( -@" -class C -{ - void Goo() - { - string s1 = {|FixAllInDocument:default|}(string); - string s2 = default(int); - } -}", -@" -class C -{ - void Goo() - { - string s1 = default; - string s2 = default(int); - } -}", parseOptions: s_parseOptions); + await new VerifyCS.Test + { + TestCode = """ + class C + { + void Goo() + { + string s1 = [|default(string)|]; + string s2 = {|CS0029:default(int)|}; + } + } + """, + FixedCode = """ + class C + { + void Goo() + { + string s1 = default; + string s2 = {|CS0029:default(int)|}; + } + } + """, + LanguageVersion = LanguageVersion.CSharp7_1 + }.RunAsync(); } [Fact] public async Task TestDoNotOfferIfTypeWouldChange() { - await TestMissingInRegularAndScriptAsync( -@" -struct S -{ - void M() - { - var s = new S(); - s.Equals([||]default(S)); - } - - public override bool Equals(object obj) - { - return base.Equals(obj); - } -}", new TestParameters(parseOptions: s_parseOptions)); + var code = """ + struct S + { + void M() + { + var s = new S(); + s.Equals(default(S)); + } + + public override bool Equals(object obj) + { + return base.Equals(obj); + } + } + """; + + await new VerifyCS.Test() + { + TestCode = code, + FixedCode = code, + LanguageVersion = LanguageVersion.CSharp7_1 + }.RunAsync(); } [Fact] public async Task TestDoNotOfferIfTypeWouldChange2() { - await TestMissingInRegularAndScriptAsync( -@" -struct S -{ - void M() - { - var s = new S(); - s.Equals([||]default(S)); - } - - public override bool Equals(object obj) - { - return base.Equals(obj); - } -}", new TestParameters(parseOptions: s_parseOptions)); + var code = """ + struct S + { + void M() + { + var s = new S(); + s.Equals(default(S)); + } + + public override bool Equals(object obj) + { + return base.Equals(obj); + } + } + """; + + await new VerifyCS.Test() + { + TestCode = code, + FixedCode = code, + LanguageVersion = LanguageVersion.CSharp7_1 + }.RunAsync(); } [Fact] public async Task TestOnShadowedMethod() { - await TestAsync( -@" -struct S -{ - void M() - { - var s = new S(); - s.Equals([||]default(S)); - } - - public new bool Equals(S s) => true; -}", - -@" -struct S -{ - void M() - { - var s = new S(); - s.Equals(default); - } - - public new bool Equals(S s) => true; -}", parseOptions: s_parseOptions); + await new VerifyCS.Test + { + TestCode = """ + struct S + { + void M() + { + var s = new S(); + s.Equals([|default(S)|]); + } + + public new bool Equals(S s) => true; + } + """, + FixedCode = """ + struct S + { + void M() + { + var s = new S(); + s.Equals(default); + } + + public new bool Equals(S s) => true; + } + """, + LanguageVersion = LanguageVersion.CSharp7_1 + }.RunAsync(); } [Fact, WorkItem(25456, "https://github.com/dotnet/roslyn/issues/25456")] public async Task TestNotInSwitchCase() { - await TestMissingInRegularAndScriptAsync( -@" -class C -{ - void M() - { - switch (true) - { - case [||]default(bool): - } - } -}", s_testParameters); + var code = """ + class C + { + void M() + { + switch (true) + { + case default(bool): + } + } + } + """; + + await new VerifyCS.Test() + { + TestCode = code, + FixedCode = code, + LanguageVersion = LanguageVersion.CSharp7_1 + }.RunAsync(); } [Fact] public async Task TestNotInSwitchCase_InsideParentheses() { - await TestMissingInRegularAndScriptAsync( -@" -class C -{ - void M() - { - switch (true) - { - case ([||]default(bool)): - } - } -}", s_testParameters); + var code = """ + class C + { + void M() + { + switch (true) + { + case (default(bool)): + } + } + } + """; + + await new VerifyCS.Test() + { + TestCode = code, + FixedCode = code, + LanguageVersion = LanguageVersion.CSharp7_1 + }.RunAsync(); } [Fact] public async Task TestInSwitchCase_InsideCast() { - await TestInRegularAndScript1Async( -@" -class C -{ - void M() - { - switch (true) - { - case (bool)[||]default(bool): - } - } -}", -@" -class C -{ - void M() - { - switch (true) - { - case (bool)[||]default: - } - } -}", parameters: s_testParameters); + await new VerifyCS.Test + { + TestCode = """ + class C + { + void M() + { + switch (true) + { + case (bool)[|default(bool)|]: + } + } + } + """, + FixedCode = """ + class C + { + void M() + { + switch (true) + { + case (bool)default: + } + } + } + """, + LanguageVersion = LanguageVersion.CSharp7_1 + }.RunAsync(); } [Fact] public async Task TestNotInPatternSwitchCase() { - await TestMissingInRegularAndScriptAsync( -@" -class C -{ - void M() - { - switch (true) - { - case [||]default(bool) when true: - } - } -}", s_testParameters); + var code = """ + class C + { + void M() + { + switch (true) + { + case default(bool) when true: + } + } + } + """; + + await new VerifyCS.Test() + { + TestCode = code, + FixedCode = code, + LanguageVersion = LanguageVersion.CSharp7_1 + }.RunAsync(); } [Fact] public async Task TestNotInPatternSwitchCase_InsideParentheses() { - await TestMissingInRegularAndScriptAsync( -@" -class C -{ - void M() - { - switch (true) - { - case ([||]default(bool)) when true: - } - } -}", s_testParameters); + var code = """ + class C + { + void M() + { + switch (true) + { + case (default(bool)) when true: + } + } + } + """; + + await new VerifyCS.Test() + { + TestCode = code, + FixedCode = code, + LanguageVersion = LanguageVersion.CSharp7_1 + }.RunAsync(); } [Fact] public async Task TestInPatternSwitchCase_InsideCast() { - await TestInRegularAndScript1Async( -@" -class C -{ - void M() - { - switch (true) - { - case (bool)[||]default(bool) when true: - } - } -}", -@" -class C -{ - void M() - { - switch (true) - { - case (bool)[||]default when true: - } - } -}", parameters: s_testParameters); + await new VerifyCS.Test + { + TestCode = """ + class C + { + void M() + { + switch (true) + { + case (bool)[|default(bool)|] when true: + } + } + } + """, + FixedCode = """ + class C + { + void M() + { + switch (true) + { + case (bool)default when true: + } + } + } + """, + LanguageVersion = LanguageVersion.CSharp7_1 + }.RunAsync(); } [Fact] public async Task TestInPatternSwitchCase_InsideWhenClause() { - await TestInRegularAndScript1Async( -@" -class C -{ - void M() - { - switch (true) - { - case default(bool) when [||]default(bool): - } - } -}", -@" -class C -{ - void M() - { - switch (true) - { - case default(bool) when default: - } - } -}", parameters: s_testParameters); + await new VerifyCS.Test + { + TestCode = """ + class C + { + void M() + { + switch (true) + { + case default(bool) when [|default(bool)|]: + } + } + } + """, + FixedCode = """ + class C + { + void M() + { + switch (true) + { + case default(bool) when default: + } + } + } + """, + LanguageVersion = LanguageVersion.CSharp7_1 + }.RunAsync(); } [Fact] public async Task TestNotInPatternIs() { - await TestMissingInRegularAndScriptAsync( -@" -class C -{ - void M() - { - if (true is [||]default(bool)); - } -}", s_testParameters); + var code = """ + class C + { + void M() + { + if (true is default(bool)); + } + } + """; + + await new VerifyCS.Test() + { + TestCode = code, + FixedCode = code, + LanguageVersion = LanguageVersion.CSharp7_1 + }.RunAsync(); } [Fact] public async Task TestNotInPatternIs_InsideParentheses() { - await TestMissingInRegularAndScriptAsync( -@" -class C -{ - void M() - { - if (true is ([||]default(bool))); - } -}", s_testParameters); + var code = """ + class C + { + void M() + { + if (true is (default(bool))); + } + } + """; + + await new VerifyCS.Test() + { + TestCode = code, + FixedCode = code, + LanguageVersion = LanguageVersion.CSharp7_1 + }.RunAsync(); } [Fact] public async Task TestInPatternIs_InsideCast() { - await TestInRegularAndScript1Async( -@" -class C -{ - void M() - { - if (true is (bool)[||]default(bool)); - } -}", -@" -class C -{ - void M() - { - if (true is (bool)default); - } -}", parameters: s_testParameters); + await new VerifyCS.Test + { + TestCode = """ + class C + { + void M() + { + if (true is (bool)[|default(bool)|]); + } + } + """, + FixedCode = """ + class C + { + void M() + { + if (true is (bool)default); + } + } + """, + LanguageVersion = LanguageVersion.CSharp7_1 + }.RunAsync(); } } }