From 995b771c08d07cfd35206e572f58534bc607c528 Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Fri, 26 Feb 2021 20:33:13 -0800 Subject: [PATCH 1/4] Convert AddDebuggerDisplayTests to the new test framework --- .../AddDebuggerDisplayTests.cs | 119 +++++++++++------- .../AddDebuggerDisplayTests.vb | 103 ++++++++------- 2 files changed, 131 insertions(+), 91 deletions(-) diff --git a/src/EditorFeatures/CSharpTest/AddDebuggerDisplay/AddDebuggerDisplayTests.cs b/src/EditorFeatures/CSharpTest/AddDebuggerDisplay/AddDebuggerDisplayTests.cs index 9020fede972f6..0b0df22f72435 100644 --- a/src/EditorFeatures/CSharpTest/AddDebuggerDisplay/AddDebuggerDisplayTests.cs +++ b/src/EditorFeatures/CSharpTest/AddDebuggerDisplay/AddDebuggerDisplayTests.cs @@ -5,24 +5,22 @@ #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 { }", @" @@ -41,8 +39,9 @@ private string GetDebuggerDisplay() [Fact] public async Task OfferedOnEmptyRecord() { - await TestInRegularAndScriptAsync(@" -[||]record C;", @" + var code = @" +[||]record C;"; + var fixedCode = @" using System.Diagnostics; [DebuggerDisplay(""{"" + nameof(GetDebuggerDisplay) + ""(),nq}"")] @@ -52,13 +51,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 { }", @" @@ -77,52 +84,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""; @@ -144,7 +161,7 @@ private string GetDebuggerDisplay() [Fact] public async Task OfferedOnShadowingToString() { - await TestInRegularAndScriptAsync(@" + await VerifyCS.VerifyRefactoringAsync(@" class A { public new string [||]ToString() => ""Foo""; @@ -166,7 +183,7 @@ private string GetDebuggerDisplay() [Fact] public async Task NotOfferedOnWrongOverloadOfToString() { - await TestMissingInRegularAndScriptAsync(@" + var code = @" class A { public virtual string ToString(int bar = 0) => ""Foo""; @@ -175,13 +192,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""; @@ -198,17 +217,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 @@ -229,7 +250,7 @@ private string GetDebuggerDisplay() [Fact] public async Task NamespaceImportIsSorted() { - await TestInRegularAndScriptAsync(@" + await VerifyCS.VerifyRefactoringAsync(@" using System.Xml; [||]class C @@ -251,34 +272,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 { @@ -292,14 +317,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 { @@ -313,19 +338,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"")] @@ -356,7 +383,7 @@ private string GetDebuggerDisplay() [Fact] public async Task ExistingDebuggerDisplayMethodIsUsedEvenWhenPublicStaticNonString() { - await TestInRegularAndScriptAsync(@" + await VerifyCS.VerifyRefactoringAsync(@" [||]class C { public static object GetDebuggerDisplay() => ""Foo""; @@ -373,7 +400,7 @@ class C [Fact] public async Task ExistingDebuggerDisplayMethodWithParameterIsNotUsed() { - await TestInRegularAndScriptAsync(@" + await VerifyCS.VerifyRefactoringAsync(@" [||]class C { private string GetDebuggerDisplay(int foo = 0) => foo.ToString(); diff --git a/src/EditorFeatures/VisualBasicTest/AddDebuggerDisplay/AddDebuggerDisplayTests.vb b/src/EditorFeatures/VisualBasicTest/AddDebuggerDisplay/AddDebuggerDisplayTests.vb index 4c392f5ad8bd3..b845607ebc828 100644 --- a/src/EditorFeatures/VisualBasicTest/AddDebuggerDisplay/AddDebuggerDisplayTests.vb +++ b/src/EditorFeatures/VisualBasicTest/AddDebuggerDisplay/AddDebuggerDisplayTests.vb @@ -2,23 +2,16 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports Microsoft.CodeAnalysis.CodeRefactorings -Imports Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CodeRefactorings -Imports Microsoft.CodeAnalysis.VisualBasic.AddDebuggerDisplay +Imports VerifyVB = Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions.VisualBasicCodeRefactoringVerifier(Of + Microsoft.CodeAnalysis.VisualBasic.AddDebuggerDisplay.VisualBasicAddDebuggerDisplayCodeRefactoringProvider) Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.AddDebuggerDisplay Public NotInheritable Class AddDebuggerDisplayTests - Inherits AbstractVisualBasicCodeActionTest - - Protected Overrides Function CreateCodeRefactoringProvider(workspace As Workspace, parameters As TestParameters) As CodeRefactoringProvider - Return New VisualBasicAddDebuggerDisplayCodeRefactoringProvider() - End Function - Public Async Function OfferedOnEmptyClass() As Task - Await TestInRegularAndScriptAsync(" + Await VerifyVB.VerifyRefactoringAsync(" [||]Class C End Class", " Imports System.Diagnostics @@ -33,7 +26,7 @@ End Class") Public Async Function OfferedOnEmptyStruct() As Task - Await TestInRegularAndScriptAsync(" + Await VerifyVB.VerifyRefactoringAsync(" [||]Structure Foo End Structure", " Imports System.Diagnostics @@ -48,43 +41,53 @@ End Structure") Public Async Function NotOfferedOnModule() As Task - Await TestMissingInRegularAndScriptAsync(" + Dim code = " [||]Module Foo -End Module") +End Module" + + Await VerifyVB.VerifyRefactoringAsync(code, code) End Function Public Async Function NotOfferedOnInterfaceWithToString() As Task - Await TestMissingInRegularAndScriptAsync(" + Dim code = " [||]Interface IFoo Function ToString() As String -End Interface") +End Interface" + + Await VerifyVB.VerifyRefactoringAsync(code, code) End Function Public Async Function NotOfferedOnEnum() As Task - Await TestMissingInRegularAndScriptAsync(" + Dim code = " [||]Enum Foo -End Enum") +End Enum" + + Await VerifyVB.VerifyRefactoringAsync(code, code) End Function Public Async Function NotOfferedOnDelegate() As Task - Await TestMissingInRegularAndScriptAsync(" -[||]Delegate Sub Foo()") + Dim code = " +[||]Delegate Sub Foo()" + + Await VerifyVB.VerifyRefactoringAsync(code, code) End Function Public Async Function NotOfferedOnUnrelatedClassMembers() As Task - Await TestMissingInRegularAndScriptAsync(" + Dim code = " Class C [||]Public ReadOnly Property Foo As Integer -End Class") +End Class" + + Await VerifyVB.VerifyRefactoringAsync(code, code) End Function Public Async Function OfferedOnToString() As Task - Await TestInRegularAndScriptAsync(" + Await VerifyVB.VerifyRefactoringAsync(" Class C Public Overrides Function [||]ToString() As String Return ""Foo"" @@ -106,7 +109,7 @@ End Class") Public Async Function OfferedOnShadowedToString() As Task - Await TestInRegularAndScriptAsync(" + Await VerifyVB.VerifyRefactoringAsync(" Class C Public Shadows Function [||]ToString() As String Return ""Foo"" @@ -128,7 +131,7 @@ End Class") Public Async Function NotOfferedOnWrongOverloadOfToString() As Task - Await TestMissingInRegularAndScriptAsync(" + Dim code = " Class A Public Overrides Function ToString(Optional bar As Integer = 0) As String Return ""Foo"" @@ -141,12 +144,14 @@ Class B Public Overrides Function [||]ToString(Optional bar As Integer = 0) As String Return ""Bar"" End Function -End Class") +End Class" + + Await VerifyVB.VerifyRefactoringAsync(code, code) End Function Public Async Function OfferedOnExistingDebuggerDisplayMethod() As Task - Await TestInRegularAndScriptAsync(" + Await VerifyVB.VerifyRefactoringAsync(" Class C Private Function [||]GetDebuggerDisplay() As String Return ""Foo"" @@ -164,17 +169,19 @@ End Class") Public Async Function NotOfferedOnWrongOverloadOfDebuggerDisplayMethod() As Task - Await TestMissingInRegularAndScriptAsync(" + Dim code = " Class C Private Function [||]GetDebuggerDisplay(Optional bar As Integer = 0) As String Return ""Foo"" End Function -End Class") +End Class" + + Await VerifyVB.VerifyRefactoringAsync(code, code) End Function Public Async Function NamespaceImportIsNotDuplicated() As Task - Await TestInRegularAndScriptAsync(" + Await VerifyVB.VerifyRefactoringAsync(" Imports System.Diagnostics [||]Class C @@ -191,7 +198,7 @@ End Class") Public Async Function NamespaceImportIsSorted() As Task - Await TestInRegularAndScriptAsync(" + Await VerifyVB.VerifyRefactoringAsync(" Imports System.Xml [||]Class C @@ -209,29 +216,33 @@ End Class") Public Async Function NotOfferedWhenAlreadySpecified() As Task - Await TestMissingInRegularAndScriptAsync(" + Dim code = " [||]Class C -End Class") +End Class" + + Await VerifyVB.VerifyRefactoringAsync(code, code) End Function Public Async Function NotOfferedWhenAlreadySpecifiedWithSuffix() As Task - Await TestMissingInRegularAndScriptAsync(" + Dim code = " [||]Class C -End Class") +End Class" + + Await VerifyVB.VerifyRefactoringAsync(code, code) End Function Public Async Function OfferedWhenAttributeWithTheSameNameIsSpecified() As Task - Await TestInRegularAndScriptAsync(" - + Await VerifyVB.VerifyRefactoringAsync(" +<{|BC30002:BrokenCode.DebuggerDisplay|}(""Foo"")> [||]Class C End Class", " Imports System.Diagnostics - +<{|BC30002:BrokenCode.DebuggerDisplay|}(""Foo"")> Class C Private Function GetDebuggerDisplay() As String @@ -242,13 +253,13 @@ End Class") Public Async Function OfferedWhenAttributeWithTheSameNameIsSpecifiedWithSuffix() As Task - Await TestInRegularAndScriptAsync(" - + Await VerifyVB.VerifyRefactoringAsync(" +<{|BC30002:BrokenCode.DebuggerDisplayAttribute|}(""Foo"")> [||]Class C End Class", " Imports System.Diagnostics - +<{|BC30002:BrokenCode.DebuggerDisplayAttribute|}(""Foo"")> Class C Private Function GetDebuggerDisplay() As String @@ -259,17 +270,19 @@ End Class") Public Async Function AliasedTypeIsRecognized() As Task - Await TestMissingInRegularAndScriptAsync(" + Dim code = " Imports DD = System.Diagnostics.DebuggerDisplayAttribute [||]Class C -End Class") +End Class" + + Await VerifyVB.VerifyRefactoringAsync(code, code) End Function Public Async Function OfferedWhenBaseClassHasDebuggerDisplay() As Task - Await TestInRegularAndScriptAsync(" + Await VerifyVB.VerifyRefactoringAsync(" Imports System.Diagnostics [DebuggerDisplay(""Foo"")] @@ -297,7 +310,7 @@ End Class") Public Async Function ExistingDebuggerDisplayMethodIsUsedEvenWhenPublicSharedNonString() As Task - Await TestInRegularAndScriptAsync(" + Await VerifyVB.VerifyRefactoringAsync(" [||]Class C Public Shared Function GetDebuggerDisplay() As Object Return ""Foo"" @@ -315,7 +328,7 @@ End Class") Public Async Function ExistingDebuggerDisplayMethodWithParameterIsNotUsed() As Task - Await TestInRegularAndScriptAsync(" + Await VerifyVB.VerifyRefactoringAsync(" [||]Class C Private Function GetDebuggerDisplay(Optional foo As Integer = 0) As String Return ""Foo"" From 924c50e2ac6b0e72d8ba32e4cabb41444b4fe9cb Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Fri, 26 Feb 2021 20:41:25 -0800 Subject: [PATCH 2/4] Fix errors in test inputs --- .../AddDebuggerDisplay/AddDebuggerDisplayTests.vb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/EditorFeatures/VisualBasicTest/AddDebuggerDisplay/AddDebuggerDisplayTests.vb b/src/EditorFeatures/VisualBasicTest/AddDebuggerDisplay/AddDebuggerDisplayTests.vb index b845607ebc828..7c104952fd9aa 100644 --- a/src/EditorFeatures/VisualBasicTest/AddDebuggerDisplay/AddDebuggerDisplayTests.vb +++ b/src/EditorFeatures/VisualBasicTest/AddDebuggerDisplay/AddDebuggerDisplayTests.vb @@ -62,6 +62,7 @@ End Interface" Public Async Function NotOfferedOnEnum() As Task Dim code = " [||]Enum Foo + None End Enum" Await VerifyVB.VerifyRefactoringAsync(code, code) @@ -133,7 +134,7 @@ End Class") Public Async Function NotOfferedOnWrongOverloadOfToString() As Task Dim code = " Class A - Public Overrides Function ToString(Optional bar As Integer = 0) As String + Public Overridable Function ToString(Optional bar As Integer = 0) As String Return ""Foo"" End Function End Class @@ -285,7 +286,7 @@ End Class" Await VerifyVB.VerifyRefactoringAsync(" Imports System.Diagnostics -[DebuggerDisplay(""Foo"")] + Class A End Class @@ -294,7 +295,7 @@ End Class End Class", " Imports System.Diagnostics -[DebuggerDisplay(""Foo"")] + Class A End Class From 733eeccea2eeff098c27bf5924c04cf53348dd46 Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Fri, 26 Feb 2021 20:51:13 -0800 Subject: [PATCH 3/4] Support constant string interpolation for DebuggerDisplay --- .../AddDebuggerDisplayTests.cs | 27 ++++++++++++++ ...dDebuggerDisplayCodeRefactoringProvider.cs | 4 ++ ...dDebuggerDisplayCodeRefactoringProvider.cs | 37 +++++++++++++++---- ...dDebuggerDisplayCodeRefactoringProvider.vb | 4 ++ 4 files changed, 65 insertions(+), 7 deletions(-) diff --git a/src/EditorFeatures/CSharpTest/AddDebuggerDisplay/AddDebuggerDisplayTests.cs b/src/EditorFeatures/CSharpTest/AddDebuggerDisplay/AddDebuggerDisplayTests.cs index 0b0df22f72435..ec376778f1b80 100644 --- a/src/EditorFeatures/CSharpTest/AddDebuggerDisplay/AddDebuggerDisplayTests.cs +++ b/src/EditorFeatures/CSharpTest/AddDebuggerDisplay/AddDebuggerDisplayTests.cs @@ -36,6 +36,33 @@ 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() { diff --git a/src/Features/CSharp/Portable/AddDebuggerDisplay/CSharpAddDebuggerDisplayCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/AddDebuggerDisplay/CSharpAddDebuggerDisplayCodeRefactoringProvider.cs index c1884d2c01588..0f73e5426101c 100644 --- a/src/Features/CSharp/Portable/AddDebuggerDisplay/CSharpAddDebuggerDisplayCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/AddDebuggerDisplay/CSharpAddDebuggerDisplayCodeRefactoringProvider.cs @@ -8,6 +8,7 @@ using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis.AddDebuggerDisplay; using Microsoft.CodeAnalysis.CodeRefactorings; +using Microsoft.CodeAnalysis.CSharp.Shared.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; namespace Microsoft.CodeAnalysis.CSharp.AddDebuggerDisplay @@ -25,5 +26,8 @@ public CSharpAddDebuggerDisplayCodeRefactoringProvider() } protected override bool CanNameofAccessNonPublicMembersFromAttributeArgument => true; + + protected override bool SupportsConstantInterpolatedStrings(Document document) + => ((CSharpParseOptions)document.Project.ParseOptions!).LanguageVersion.HasConstantInterpolatedStrings(); } } diff --git a/src/Features/Core/Portable/AddDebuggerDisplay/AbstractAddDebuggerDisplayCodeRefactoringProvider.cs b/src/Features/Core/Portable/AddDebuggerDisplay/AbstractAddDebuggerDisplayCodeRefactoringProvider.cs index 06e4474ceee06..71612d63fd162 100644 --- a/src/Features/Core/Portable/AddDebuggerDisplay/AbstractAddDebuggerDisplayCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/AddDebuggerDisplay/AbstractAddDebuggerDisplayCodeRefactoringProvider.cs @@ -26,6 +26,8 @@ internal abstract class AbstractAddDebuggerDisplayCodeRefactoringProvider< protected abstract bool CanNameofAccessNonPublicMembersFromAttributeArgument { get; } + protected abstract bool SupportsConstantInterpolatedStrings(Document document); + public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var (document, _, cancellationToken) = context; @@ -115,14 +117,35 @@ private async Task ApplyAsync(Document document, TTypeDeclarationSynta var editor = new SyntaxEditor(syntaxRoot, document.Project.Solution.Workspace); var generator = editor.Generator; - var attributeArgument = CanNameofAccessNonPublicMembersFromAttributeArgument - ? generator.AddExpression( - generator.AddExpression( - generator.LiteralExpression(DebuggerDisplayPrefix), - generator.NameOfExpression(generator.IdentifierName(DebuggerDisplayMethodName))), - generator.LiteralExpression(DebuggerDisplaySuffix)) - : generator.LiteralExpression( + SyntaxNode attributeArgument; + if (CanNameofAccessNonPublicMembersFromAttributeArgument) + { + if (SupportsConstantInterpolatedStrings(document)) + { + attributeArgument = generator.InterpolatedStringExpression( + generator.CreateInterpolatedStringStartToken(isVerbatim: false), + new SyntaxNode[] + { + generator.InterpolatedStringText(generator.InterpolatedStringTextToken("{{", "{{")), + generator.Interpolation(generator.NameOfExpression(generator.IdentifierName(DebuggerDisplayMethodName))), + generator.InterpolatedStringText(generator.InterpolatedStringTextToken("(),nq}}", "(),nq}}")), + }, + generator.CreateInterpolatedStringEndToken()); + } + else + { + attributeArgument = generator.AddExpression( + generator.AddExpression( + generator.LiteralExpression(DebuggerDisplayPrefix), + generator.NameOfExpression(generator.IdentifierName(DebuggerDisplayMethodName))), + generator.LiteralExpression(DebuggerDisplaySuffix)); + } + } + else + { + attributeArgument = generator.LiteralExpression( DebuggerDisplayPrefix + DebuggerDisplayMethodName + DebuggerDisplaySuffix); + } var newAttribute = generator .Attribute(generator.TypeExpression(debuggerAttributeTypeSymbol), new[] { attributeArgument }) diff --git a/src/Features/VisualBasic/Portable/AddDebuggerDisplay/VisualBasicAddDebuggerDisplayCodeRefactoringProvider.vb b/src/Features/VisualBasic/Portable/AddDebuggerDisplay/VisualBasicAddDebuggerDisplayCodeRefactoringProvider.vb index 63dec3962a2d9..fa1091a90d222 100644 --- a/src/Features/VisualBasic/Portable/AddDebuggerDisplay/VisualBasicAddDebuggerDisplayCodeRefactoringProvider.vb +++ b/src/Features/VisualBasic/Portable/AddDebuggerDisplay/VisualBasicAddDebuggerDisplayCodeRefactoringProvider.vb @@ -20,5 +20,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.AddDebuggerDisplay End Sub Protected Overrides ReadOnly Property CanNameofAccessNonPublicMembersFromAttributeArgument As Boolean + + Protected Overrides Function SupportsConstantInterpolatedStrings(document As Document) As Boolean + Return False + End Function End Class End Namespace From ac2c7e461f8356282ee3adf9a5353563919873cd Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Fri, 26 Feb 2021 21:08:27 -0800 Subject: [PATCH 4/4] Cleanup MEF attributes --- .../AddDebuggerDisplay/AddDebuggerDisplayTests.cs | 2 -- .../CSharpAddDebuggerDisplayCodeRefactoringProvider.cs | 7 +++---- ...VisualBasicAddDebuggerDisplayCodeRefactoringProvider.vb | 4 ++-- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/EditorFeatures/CSharpTest/AddDebuggerDisplay/AddDebuggerDisplayTests.cs b/src/EditorFeatures/CSharpTest/AddDebuggerDisplay/AddDebuggerDisplayTests.cs index ec376778f1b80..f5724c74dbb02 100644 --- a/src/EditorFeatures/CSharpTest/AddDebuggerDisplay/AddDebuggerDisplayTests.cs +++ b/src/EditorFeatures/CSharpTest/AddDebuggerDisplay/AddDebuggerDisplayTests.cs @@ -2,8 +2,6 @@ // 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.CSharp; using Microsoft.CodeAnalysis.Test.Utilities; diff --git a/src/Features/CSharp/Portable/AddDebuggerDisplay/CSharpAddDebuggerDisplayCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/AddDebuggerDisplay/CSharpAddDebuggerDisplayCodeRefactoringProvider.cs index 0f73e5426101c..687f6ef72fccc 100644 --- a/src/Features/CSharp/Portable/AddDebuggerDisplay/CSharpAddDebuggerDisplayCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/AddDebuggerDisplay/CSharpAddDebuggerDisplayCodeRefactoringProvider.cs @@ -2,14 +2,13 @@ // 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.Composition; -using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis.AddDebuggerDisplay; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.CSharp.Shared.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Host.Mef; namespace Microsoft.CodeAnalysis.CSharp.AddDebuggerDisplay { @@ -20,7 +19,7 @@ internal sealed class CSharpAddDebuggerDisplayCodeRefactoringProvider MethodDeclarationSyntax> { [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 CSharpAddDebuggerDisplayCodeRefactoringProvider() { } diff --git a/src/Features/VisualBasic/Portable/AddDebuggerDisplay/VisualBasicAddDebuggerDisplayCodeRefactoringProvider.vb b/src/Features/VisualBasic/Portable/AddDebuggerDisplay/VisualBasicAddDebuggerDisplayCodeRefactoringProvider.vb index fa1091a90d222..111481ddeaf7c 100644 --- a/src/Features/VisualBasic/Portable/AddDebuggerDisplay/VisualBasicAddDebuggerDisplayCodeRefactoringProvider.vb +++ b/src/Features/VisualBasic/Portable/AddDebuggerDisplay/VisualBasicAddDebuggerDisplayCodeRefactoringProvider.vb @@ -3,9 +3,9 @@ ' See the LICENSE file in the project root for more information. Imports System.Composition -Imports System.Diagnostics.CodeAnalysis Imports Microsoft.CodeAnalysis.AddDebuggerDisplay Imports Microsoft.CodeAnalysis.CodeRefactorings +Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.AddDebuggerDisplay @@ -15,7 +15,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.AddDebuggerDisplay TypeBlockSyntax, MethodStatementSyntax) - + Public Sub New() End Sub