Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update 'Add DebuggerDisplay' refactoring to support constant interpolated strings #51536

Merged
merged 4 commits into from
Mar 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,23 @@
// 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.CodeRefactorings;
using Microsoft.CodeAnalysis.CSharp.AddDebuggerDisplay;
using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.Testing;
using Xunit;
using VerifyCS = Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions.CSharpCodeRefactoringVerifier<
Microsoft.CodeAnalysis.CSharp.AddDebuggerDisplay.CSharpAddDebuggerDisplayCodeRefactoringProvider>;

namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.AddDebuggerDisplay
{
[Trait(Traits.Feature, Traits.Features.CodeActionsAddDebuggerDisplay)]
public sealed class AddDebuggerDisplayTests : AbstractCSharpCodeActionTest
public sealed class AddDebuggerDisplayTests
{
protected override CodeRefactoringProvider CreateCodeRefactoringProvider(Workspace workspace, TestParameters parameters)
=> new CSharpAddDebuggerDisplayCodeRefactoringProvider();

[Fact]
public async Task OfferedOnEmptyClass()
{
await TestInRegularAndScriptAsync(@"
await VerifyCS.VerifyRefactoringAsync(@"
[||]class C
{
}", @"
Expand All @@ -38,11 +34,39 @@ private string GetDebuggerDisplay()
}");
}

[Fact]
public async Task SupportsConstantInterpolatedStrings()
{
var code = @"
[||]class C
{
}";
var fixedCode = @"
using System.Diagnostics;
[DebuggerDisplay($""{{{nameof(GetDebuggerDisplay)}(),nq}}"")]
class C
{
private string GetDebuggerDisplay()
{
return ToString();
}
}";

await new VerifyCS.Test()
{
LanguageVersion = LanguageVersion.Preview,
TestCode = code,
FixedCode = fixedCode,
}.RunAsync();
}

[Fact]
public async Task OfferedOnEmptyRecord()
{
await TestInRegularAndScriptAsync(@"
[||]record C;", @"
var code = @"
[||]record C;";
var fixedCode = @"
using System.Diagnostics;
[DebuggerDisplay(""{"" + nameof(GetDebuggerDisplay) + ""(),nq}"")]
Expand All @@ -52,13 +76,21 @@ private string GetDebuggerDisplay()
{
return ToString();
}
}");
}";

await new VerifyCS.Test()
{
LanguageVersion = LanguageVersion.CSharp9,
ReferenceAssemblies = ReferenceAssemblies.Net.Net50,
TestCode = code,
FixedCode = fixedCode,
}.RunAsync();
}

[Fact]
public async Task OfferedOnEmptyStruct()
{
await TestInRegularAndScriptAsync(@"
await VerifyCS.VerifyRefactoringAsync(@"
[||]struct Foo
{
}", @"
Expand All @@ -77,52 +109,62 @@ private string GetDebuggerDisplay()
[Fact]
public async Task NotOfferedOnStaticClass()
{
await TestMissingInRegularAndScriptAsync(@"
var code = @"
[||]static class Foo
{
}");
}";

await VerifyCS.VerifyRefactoringAsync(code, code);
}

[Fact]
public async Task NotOfferedOnInterfaceWithToString()
{
await TestMissingInRegularAndScriptAsync(@"
var code = @"
[||]interface IFoo
{
string ToString();
}");
}";

await VerifyCS.VerifyRefactoringAsync(code, code);
}

[Fact]
public async Task NotOfferedOnEnum()
{
await TestMissingInRegularAndScriptAsync(@"
var code = @"
[||]enum Foo
{
}");
}";

await VerifyCS.VerifyRefactoringAsync(code, code);
}

[Fact]
public async Task NotOfferedOnDelegate()
{
await TestMissingInRegularAndScriptAsync(@"
[||]delegate void Foo();");
var code = @"
[||]delegate void Foo();";

await VerifyCS.VerifyRefactoringAsync(code, code);
}

[Fact]
public async Task NotOfferedOnUnrelatedClassMembers()
{
await TestMissingInRegularAndScriptAsync(@"
var code = @"
class C
{
[||]public int Foo { get; }
}");
}";

await VerifyCS.VerifyRefactoringAsync(code, code);
}

[Fact]
public async Task OfferedOnToString()
{
await TestInRegularAndScriptAsync(@"
await VerifyCS.VerifyRefactoringAsync(@"
class C
{
public override string [||]ToString() => ""Foo"";
Expand All @@ -144,7 +186,7 @@ private string GetDebuggerDisplay()
[Fact]
public async Task OfferedOnShadowingToString()
{
await TestInRegularAndScriptAsync(@"
await VerifyCS.VerifyRefactoringAsync(@"
class A
{
public new string [||]ToString() => ""Foo"";
Expand All @@ -166,7 +208,7 @@ private string GetDebuggerDisplay()
[Fact]
public async Task NotOfferedOnWrongOverloadOfToString()
{
await TestMissingInRegularAndScriptAsync(@"
var code = @"
class A
{
public virtual string ToString(int bar = 0) => ""Foo"";
Expand All @@ -175,13 +217,15 @@ class A
class B : A
{
public override string [||]ToString(int bar = 0) => ""Bar"";
}");
}";

await VerifyCS.VerifyRefactoringAsync(code, code);
}

[Fact]
public async Task OfferedOnExistingDebuggerDisplayMethod()
{
await TestInRegularAndScriptAsync(@"
await VerifyCS.VerifyRefactoringAsync(@"
class C
{
private string [||]GetDebuggerDisplay() => ""Foo"";
Expand All @@ -198,17 +242,19 @@ class C
[Fact]
public async Task NotOfferedOnWrongOverloadOfDebuggerDisplayMethod()
{
await TestMissingInRegularAndScriptAsync(@"
var code = @"
class A
{
private string [||]GetDebuggerDisplay(int bar = 0) => ""Foo"";
}");
}";

await VerifyCS.VerifyRefactoringAsync(code, code);
}

[Fact]
public async Task NamespaceImportIsNotDuplicated()
{
await TestInRegularAndScriptAsync(@"
await VerifyCS.VerifyRefactoringAsync(@"
using System.Diagnostics;
[||]class C
Expand All @@ -229,7 +275,7 @@ private string GetDebuggerDisplay()
[Fact]
public async Task NamespaceImportIsSorted()
{
await TestInRegularAndScriptAsync(@"
await VerifyCS.VerifyRefactoringAsync(@"
using System.Xml;
[||]class C
Expand All @@ -251,34 +297,38 @@ private string GetDebuggerDisplay()
[Fact]
public async Task NotOfferedWhenAlreadySpecified()
{
await TestMissingInRegularAndScriptAsync(@"
var code = @"
[System.Diagnostics.DebuggerDisplay(""Foo"")]
[||]class C
{
}");
}";

await VerifyCS.VerifyRefactoringAsync(code, code);
}

[Fact]
public async Task NotOfferedWhenAlreadySpecifiedWithSuffix()
{
await TestMissingInRegularAndScriptAsync(@"
var code = @"
[System.Diagnostics.DebuggerDisplayAttribute(""Foo"")]
[||]class C
{
}");
}";

await VerifyCS.VerifyRefactoringAsync(code, code);
}

[Fact]
public async Task OfferedWhenAttributeWithTheSameNameIsSpecified()
{
await TestInRegularAndScriptAsync(@"
[BrokenCode.DebuggerDisplay(""Foo"")]
await VerifyCS.VerifyRefactoringAsync(@"
[{|CS0246:BrokenCode|}.DebuggerDisplay(""Foo"")]
[||]class C
{
}", @"
using System.Diagnostics;
[BrokenCode.DebuggerDisplay(""Foo"")]
[{|CS0246:BrokenCode|}.DebuggerDisplay(""Foo"")]
[DebuggerDisplay(""{"" + nameof(GetDebuggerDisplay) + ""(),nq}"")]
[||]class C
{
Expand All @@ -292,14 +342,14 @@ private string GetDebuggerDisplay()
[Fact]
public async Task OfferedWhenAttributeWithTheSameNameIsSpecifiedWithSuffix()
{
await TestInRegularAndScriptAsync(@"
[BrokenCode.DebuggerDisplayAttribute(""Foo"")]
await VerifyCS.VerifyRefactoringAsync(@"
[{|CS0246:BrokenCode|}.DebuggerDisplayAttribute(""Foo"")]
[||]class C
{
}", @"
using System.Diagnostics;
[BrokenCode.DebuggerDisplayAttribute(""Foo"")]
[{|CS0246:BrokenCode|}.DebuggerDisplayAttribute(""Foo"")]
[DebuggerDisplay(""{"" + nameof(GetDebuggerDisplay) + ""(),nq}"")]
[||]class C
{
Expand All @@ -313,19 +363,21 @@ private string GetDebuggerDisplay()
[Fact]
public async Task AliasedTypeIsRecognized()
{
await TestMissingInRegularAndScriptAsync(@"
var code = @"
using DD = System.Diagnostics.DebuggerDisplayAttribute;
[DD(""Foo"")]
[||]class C
{
}");
}";

await VerifyCS.VerifyRefactoringAsync(code, code);
}

[Fact]
public async Task OfferedWhenBaseClassHasDebuggerDisplay()
{
await TestInRegularAndScriptAsync(@"
await VerifyCS.VerifyRefactoringAsync(@"
using System.Diagnostics;
[DebuggerDisplay(""Foo"")]
Expand Down Expand Up @@ -356,7 +408,7 @@ private string GetDebuggerDisplay()
[Fact]
public async Task ExistingDebuggerDisplayMethodIsUsedEvenWhenPublicStaticNonString()
{
await TestInRegularAndScriptAsync(@"
await VerifyCS.VerifyRefactoringAsync(@"
[||]class C
{
public static object GetDebuggerDisplay() => ""Foo"";
Expand All @@ -373,7 +425,7 @@ class C
[Fact]
public async Task ExistingDebuggerDisplayMethodWithParameterIsNotUsed()
{
await TestInRegularAndScriptAsync(@"
await VerifyCS.VerifyRefactoringAsync(@"
[||]class C
{
private string GetDebuggerDisplay(int foo = 0) => foo.ToString();
Expand Down
Loading