diff --git a/src/EditorFeatures/CSharp/CSharpEditorResources.Designer.cs b/src/EditorFeatures/CSharp/CSharpEditorResources.Designer.cs
index 28d709117a03e4a91e9b62731af492fa18f2d7ef..12ec92cb5d7943aab82d54232d664d082f7437f2 100644
--- a/src/EditorFeatures/CSharp/CSharpEditorResources.Designer.cs
+++ b/src/EditorFeatures/CSharp/CSharpEditorResources.Designer.cs
@@ -60,6 +60,15 @@ internal class CSharpEditorResources {
}
}
+ ///
+ /// Looks up a localized string similar to Fix interpolated verbatim string.
+ ///
+ internal static string Fix_interpolated_verbatim_string {
+ get {
+ return ResourceManager.GetString("Fix_interpolated_verbatim_string", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to (Press TAB to insert).
///
diff --git a/src/EditorFeatures/CSharp/CSharpEditorResources.resx b/src/EditorFeatures/CSharp/CSharpEditorResources.resx
index d27291f3f75f3713e2799484bb52d9367fc888d4..e8650f88e00c1f7ba011edc03863931d5367645c 100644
--- a/src/EditorFeatures/CSharp/CSharpEditorResources.resx
+++ b/src/EditorFeatures/CSharp/CSharpEditorResources.resx
@@ -117,6 +117,9 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+ Fix interpolated verbatim string
+
(Press TAB to insert)
diff --git a/src/EditorFeatures/CSharp/FixInterpolatedVerbatimString/FixInterpolatedVerbatimStringCommandHandler.cs b/src/EditorFeatures/CSharp/FixInterpolatedVerbatimString/FixInterpolatedVerbatimStringCommandHandler.cs
new file mode 100644
index 0000000000000000000000000000000000000000..653220727825e774f0d64fd5ceea6f11ae12ecd2
--- /dev/null
+++ b/src/EditorFeatures/CSharp/FixInterpolatedVerbatimString/FixInterpolatedVerbatimStringCommandHandler.cs
@@ -0,0 +1,63 @@
+// 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.ComponentModel.Composition;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
+using Microsoft.CodeAnalysis.Text;
+using Microsoft.VisualStudio.Commanding;
+using Microsoft.VisualStudio.Text;
+using Microsoft.VisualStudio.Text.Editor.Commanding.Commands;
+using Microsoft.VisualStudio.Utilities;
+using VSCommanding = Microsoft.VisualStudio.Commanding;
+
+namespace Microsoft.CodeAnalysis.Editor.CSharp.FixInterpolatedVerbatimString
+{
+ ///
+ /// Replaces @$" with $@", which is the preferred and until C# 8.0 the only supported form
+ /// of an interpolated verbatim string start token. In C# 8.0 we still auto-correct to this form for consistency.
+ ///
+ [Export(typeof(VSCommanding.ICommandHandler))]
+ [ContentType(ContentTypeNames.CSharpContentType)]
+ [Name(nameof(FixInterpolatedVerbatimStringCommandHandler))]
+ internal sealed class FixInterpolatedVerbatimStringCommandHandler : IChainedCommandHandler
+ {
+ public string DisplayName => CSharpEditorResources.Fix_interpolated_verbatim_string;
+
+ public void ExecuteCommand(TypeCharCommandArgs args, Action nextCommandHandler, CommandExecutionContext executionContext)
+ {
+ // We need to check for the token *after* the opening quote is typed, so defer to the editor first
+ nextCommandHandler();
+
+ if (args.TypedChar == '"')
+ {
+ var caret = args.TextView.GetCaretPoint(args.SubjectBuffer);
+ if (caret != null)
+ {
+ var position = caret.Value.Position;
+ var snapshot = caret.Value.Snapshot;
+
+ if (position >= 3 &&
+ snapshot[position - 1] == '"' &&
+ snapshot[position - 2] == '$' &&
+ snapshot[position - 3] == '@')
+ {
+ var document = snapshot.GetOpenDocumentInCurrentContextWithChanges();
+ if (document != null)
+ {
+ var root = document.GetSyntaxRootSynchronously(executionContext.OperationContext.UserCancellationToken);
+ var token = root.FindToken(position - 3);
+ if (token.IsKind(SyntaxKind.InterpolatedVerbatimStringStartToken))
+ {
+ args.SubjectBuffer.Replace(new Span(position - 3, 2), "$@");
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public VSCommanding.CommandState GetCommandState(TypeCharCommandArgs args, Func nextCommandHandler)
+ => nextCommandHandler();
+ }
+}
diff --git a/src/EditorFeatures/CSharp/SplitStringLiteral/SplitStringLiteralCommandHandler.cs b/src/EditorFeatures/CSharp/SplitStringLiteral/SplitStringLiteralCommandHandler.cs
index c31092dba7431ec0490400da9d5f30c11f9fcbe0..3af3564a9dab66366fec3eebe9ffeb2b588fa542 100644
--- a/src/EditorFeatures/CSharp/SplitStringLiteral/SplitStringLiteralCommandHandler.cs
+++ b/src/EditorFeatures/CSharp/SplitStringLiteral/SplitStringLiteralCommandHandler.cs
@@ -1,4 +1,6 @@
-using System.ComponentModel.Composition;
+// 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.ComponentModel.Composition;
using System.Threading;
using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.cs.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.cs.xlf
index a17aebf9f66c4fb7bdee6a4e2ad8048ec0803567..3391d2c1f867c972787cec3e8849b1927502ff41 100644
--- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.cs.xlf
+++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.cs.xlf
@@ -2,6 +2,11 @@
+
+
+ Fix interpolated verbatim string
+
+
(Pro vložení stiskněte TAB.)
diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.de.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.de.xlf
index 50d22d4cbf64fdc52f851364f371d28dfaa1a2f0..a66e264a4e40b28faf4dbcc87f02b43956bad397 100644
--- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.de.xlf
+++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.de.xlf
@@ -2,6 +2,11 @@
+
+
+ Fix interpolated verbatim string
+
+
(Zum Einfügen TAB-TASTE drücken)
diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.es.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.es.xlf
index c3a1bcdb8c24542f338aabf24a316dc2f17ad8d4..5bfe2078450de5d7139a38b0528338febd327bf2 100644
--- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.es.xlf
+++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.es.xlf
@@ -2,6 +2,11 @@
+
+
+ Fix interpolated verbatim string
+
+
(Presione TAB para insertar)
diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.fr.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.fr.xlf
index 371e6847a165012aa529c4bad1b361661f30ca2a..760cd1f717c28dbbda5828eff591a349fae8630a 100644
--- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.fr.xlf
+++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.fr.xlf
@@ -2,6 +2,11 @@
+
+
+ Fix interpolated verbatim string
+
+
(Appuyez sur TAB pour insérer)
diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.it.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.it.xlf
index 3f705fc00cd62b32051f2bb6f685e6ac7024ae47..70a6be74b8402cd857959af413fb2ede12235819 100644
--- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.it.xlf
+++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.it.xlf
@@ -2,6 +2,11 @@
+
+
+ Fix interpolated verbatim string
+
+
(Premere TAB per inserire)
diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ja.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ja.xlf
index 79836dd659f25b80d240893aaf58bbea87186f21..4e941b8e6e616766f785c845cb3355448495523a 100644
--- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ja.xlf
+++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ja.xlf
@@ -2,6 +2,11 @@
+
+
+ Fix interpolated verbatim string
+
+
(Tab キーを押して挿入)
diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ko.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ko.xlf
index 4f37904a65657456eb26d6a86927e95469d4722e..34d816961e3a5912f86286b79c5540086660b20b 100644
--- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ko.xlf
+++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ko.xlf
@@ -2,6 +2,11 @@
+
+
+ Fix interpolated verbatim string
+
+
(삽입하려면 <Tab> 키 누름)
diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pl.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pl.xlf
index 8357da8a9bcb6ef4759c43218a321942963eb412..00308e0a7fa2b8a6aa68746599983110dae6bae0 100644
--- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pl.xlf
+++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pl.xlf
@@ -2,6 +2,11 @@
+
+
+ Fix interpolated verbatim string
+
+
(Naciśnij klawisz TAB, aby wstawić)
diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pt-BR.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pt-BR.xlf
index 62ccf9cbe2aa7d9715b4bde5148a0fd570c6cb90..110f9897ee18d76d36a0c19ff73a6ed5be0b1e2f 100644
--- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pt-BR.xlf
+++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pt-BR.xlf
@@ -2,6 +2,11 @@
+
+
+ Fix interpolated verbatim string
+
+
(Pressione TAB para inserir)
diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ru.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ru.xlf
index c863054ae86173e48f889375d6366f8861ae07d8..cb77ad446dd9bd6b0f76feb689d48934f012d034 100644
--- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ru.xlf
+++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ru.xlf
@@ -2,6 +2,11 @@
+
+
+ Fix interpolated verbatim string
+
+
(Нажмите клавишу TAB для вставки)
diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.tr.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.tr.xlf
index 68e2ef9108775b52a9289caca8b7254afeb09f7c..348464115430bf685941cce35fb2a0e2d19573c7 100644
--- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.tr.xlf
+++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.tr.xlf
@@ -2,6 +2,11 @@
+
+
+ Fix interpolated verbatim string
+
+
(Eklemek için TAB tuşuna basın)
diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hans.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hans.xlf
index eebbc0d6aa1419520d46e612fad37ff8f69984c4..6c8ff00750991e7f9ef8c5b16aa26ce28db91372 100644
--- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hans.xlf
+++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hans.xlf
@@ -2,6 +2,11 @@
+
+
+ Fix interpolated verbatim string
+
+
(按 Tab 插入)
diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hant.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hant.xlf
index dca16e32a211a90a55a1deccaa0ffe269841613e..4bf9b233bf8602f3d6a8ef46bd41588ef0c58dae 100644
--- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hant.xlf
+++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hant.xlf
@@ -2,6 +2,11 @@
+
+
+ Fix interpolated verbatim string
+
+
(按 TAB 鍵插入)
diff --git a/src/EditorFeatures/CSharpTest/FixInterpolatedVerbatimString/FixInterpolatedVerbatimStringCommandHandlerTests.cs b/src/EditorFeatures/CSharpTest/FixInterpolatedVerbatimString/FixInterpolatedVerbatimStringCommandHandlerTests.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5ce65c0be709a8812cefaae3cdaabc1988ab0a03
--- /dev/null
+++ b/src/EditorFeatures/CSharpTest/FixInterpolatedVerbatimString/FixInterpolatedVerbatimStringCommandHandlerTests.cs
@@ -0,0 +1,315 @@
+// 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.Linq;
+using Microsoft.CodeAnalysis.Editor.CSharp.FixInterpolatedVerbatimString;
+using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
+using Microsoft.CodeAnalysis.Editor.UnitTests.Utilities;
+using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces;
+using Microsoft.CodeAnalysis.Test.Utilities;
+using Microsoft.CodeAnalysis.Text;
+using Microsoft.CodeAnalysis.Text.Shared.Extensions;
+using Microsoft.VisualStudio.Text.Editor.Commanding.Commands;
+using Microsoft.VisualStudio.Text.Operations;
+using Roslyn.Test.Utilities;
+using Xunit;
+
+namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.FixInterpolatedVerbatimString
+{
+ [UseExportProvider]
+ public class FixInterpolatedVerbatimStringCommandHandlerTests
+ {
+ private static TestWorkspace CreateTestWorkspace(string inputMarkup)
+ {
+ var workspace = TestWorkspace.CreateCSharp(inputMarkup);
+ var document = workspace.Documents.Single();
+ var view = document.GetTextView();
+ view.SetSelection(document.SelectedSpans.Single().ToSnapshotSpan(view.TextBuffer.CurrentSnapshot));
+ return workspace;
+ }
+
+ private static (string quoteCharSnapshotText, int quoteCharCaretPosition) TypeQuoteChar(TestWorkspace workspace)
+ {
+ var view = workspace.Documents.Single().GetTextView();
+ var commandHandler = new FixInterpolatedVerbatimStringCommandHandler();
+
+ string quoteCharSnapshotText = default;
+ int quoteCharCaretPosition = default;
+
+ commandHandler.ExecuteCommand(new TypeCharCommandArgs(view, view.TextBuffer, '"'),
+ () =>
+ {
+ var editorOperations = workspace.GetService().GetEditorOperations(view);
+ editorOperations.InsertText("\"");
+
+ quoteCharSnapshotText = view.TextBuffer.CurrentSnapshot.GetText();
+ quoteCharCaretPosition = view.Caret.Position.BufferPosition.Position;
+
+ }, TestCommandExecutionContext.Create());
+
+ return (quoteCharSnapshotText, quoteCharCaretPosition);
+ }
+
+ private static void TestHandled(string inputMarkup, string expectedOutputMarkup)
+ {
+ using (var workspace = CreateTestWorkspace(inputMarkup))
+ {
+ var (quoteCharSnapshotText, quoteCharCaretPosition) = TypeQuoteChar(workspace);
+ var view = workspace.Documents.Single().GetTextView();
+
+ MarkupTestFile.GetSpans(expectedOutputMarkup,
+ out var expectedOutput, out ImmutableArray expectedSpans);
+
+ Assert.Equal(expectedOutput, view.TextBuffer.CurrentSnapshot.GetText());
+ Assert.Equal(expectedSpans.Single().Start, view.Caret.Position.BufferPosition.Position);
+
+ var history = workspace.GetService().GetHistory(view.TextBuffer);
+ history.Undo(count: 1);
+
+ // Ensure that after undo, the ordering fix is undone but the quote remains inserted
+ Assert.Equal(quoteCharSnapshotText, view.TextBuffer.CurrentSnapshot.GetText());
+ Assert.Equal(quoteCharCaretPosition, view.Caret.Position.BufferPosition.Position);
+ }
+ }
+
+ private static void TestNotHandled(string inputMarkup)
+ {
+ using (var workspace = CreateTestWorkspace(inputMarkup))
+ {
+ var originalView = workspace.Documents.Single().GetTextView();
+ var originalSnapshotText = originalView.TextBuffer.CurrentSnapshot.GetText();
+ var originalCaretPosition = originalView.Caret.Position.BufferPosition.Position;
+
+ var (quoteCharSnapshotText, quoteCharCaretPosition) = TypeQuoteChar(workspace);
+ var view = workspace.Documents.Single().GetTextView();
+
+ Assert.Equal(quoteCharSnapshotText, view.TextBuffer.CurrentSnapshot.GetText());
+ Assert.Equal(quoteCharCaretPosition, view.Caret.Position.BufferPosition.Position);
+
+ var history = workspace.GetService().GetHistory(view.TextBuffer);
+ history.Undo(count: 1);
+
+ // Ensure that after undo, the quote is removed because the command made no changes
+ Assert.Equal(originalSnapshotText, view.TextBuffer.CurrentSnapshot.GetText());
+ Assert.Equal(originalCaretPosition, view.Caret.Position.BufferPosition.Position);
+ }
+ }
+
+ [WpfFact, Trait(Traits.Feature, Traits.Features.FixInterpolatedVerbatimString)]
+ public void TestAfterAtSignDollarSign()
+ {
+ TestHandled(
+@"class C
+{
+ void M()
+ {
+ var v = @$[||]
+ }
+}",
+@"class C
+{
+ void M()
+ {
+ var v = $@""[||]
+ }
+}");
+ }
+
+ [WpfFact, Trait(Traits.Feature, Traits.Features.FixInterpolatedVerbatimString)]
+ public void TestMissingAfterDollarSignAtSign()
+ {
+ TestNotHandled(
+@"class C
+{
+ void M()
+ {
+ var v = $@[||]
+ }
+}");
+ }
+
+ [WpfFact, Trait(Traits.Feature, Traits.Features.FixInterpolatedVerbatimString)]
+ public void TestMissingAfterAtSign()
+ {
+ TestNotHandled(
+@"class C
+{
+ void M()
+ {
+ var v = @[||]
+ }
+}");
+ }
+
+ [WpfFact, Trait(Traits.Feature, Traits.Features.FixInterpolatedVerbatimString)]
+ public void TestMissingAfterDollarSign()
+ {
+ TestNotHandled(
+@"class C
+{
+ void M()
+ {
+ var v = $[||]
+ }
+}");
+ }
+
+ [WpfFact, Trait(Traits.Feature, Traits.Features.FixInterpolatedVerbatimString)]
+ public void TestMissingInEmptyFileAfterAtSignDollarSign()
+ {
+ TestNotHandled(@"@$[||]");
+ }
+
+ [WpfFact, Trait(Traits.Feature, Traits.Features.FixInterpolatedVerbatimString)]
+ public void TestMissingInEmptyFileAfterDollarSign()
+ {
+ TestNotHandled(@"$[||]");
+ }
+
+ [WpfFact, Trait(Traits.Feature, Traits.Features.FixInterpolatedVerbatimString)]
+ public void TestMissingInEmptyFile()
+ {
+ TestNotHandled(@"[||]");
+ }
+
+ [WpfFact, Trait(Traits.Feature, Traits.Features.FixInterpolatedVerbatimString)]
+ public void TestAfterAtSignDollarSignEndOfFile()
+ {
+ TestHandled(
+@"class C
+{
+ void M()
+ {
+ var v = @$[||]",
+@"class C
+{
+ void M()
+ {
+ var v = $@""[||]");
+ }
+
+ [WpfFact, Trait(Traits.Feature, Traits.Features.FixInterpolatedVerbatimString)]
+ public void TestMissingInClassDeclaration()
+ {
+ TestNotHandled(
+@"class C
+{
+ @$[||]
+}");
+ }
+
+ [WpfFact, Trait(Traits.Feature, Traits.Features.FixInterpolatedVerbatimString)]
+ public void TestMissingInComment1()
+ {
+ TestNotHandled(
+@"class C
+{
+ void M()
+ {
+ var v = // @$[||]
+ }
+}");
+ }
+
+ [WpfFact, Trait(Traits.Feature, Traits.Features.FixInterpolatedVerbatimString)]
+ public void TestMissingInComment2()
+ {
+ TestNotHandled(
+@"class C
+{
+ void M()
+ {
+ var v = /* @$[||]
+ }
+}");
+ }
+
+ [WpfFact, Trait(Traits.Feature, Traits.Features.FixInterpolatedVerbatimString)]
+ public void TestMissingInString()
+ {
+ TestNotHandled(
+@"class C
+{
+ void M()
+ {
+ var v = ""@$[||]
+ }
+}");
+ }
+
+ [WpfFact, Trait(Traits.Feature, Traits.Features.FixInterpolatedVerbatimString)]
+ public void TestMissingInVerbatimString()
+ {
+ TestNotHandled(
+@"class C
+{
+ void M()
+ {
+ var v = @""@$[||]
+ }
+}");
+ }
+
+ [WpfFact, Trait(Traits.Feature, Traits.Features.FixInterpolatedVerbatimString)]
+ public void TestMissingInInterpolatedString()
+ {
+ TestNotHandled(
+@"class C
+{
+ void M()
+ {
+ var v = $""@$[||]
+ }
+}");
+ }
+
+ [WpfFact, Trait(Traits.Feature, Traits.Features.FixInterpolatedVerbatimString)]
+ public void TestMissingInInterpolatedVerbatimString1()
+ {
+ TestNotHandled(
+@"class C
+{
+ void M()
+ {
+ var v = $@""@$[||]
+ }
+}");
+ }
+
+ [WpfFact, Trait(Traits.Feature, Traits.Features.FixInterpolatedVerbatimString)]
+ public void TestMissingInInterpolatedVerbatimString2()
+ {
+ TestNotHandled(
+@"class C
+{
+ void M()
+ {
+ var v = @$""@$[||]
+ }
+}");
+ }
+
+ [WpfFact, Trait(Traits.Feature, Traits.Features.FixInterpolatedVerbatimString)]
+ public void TestTrivia()
+ {
+ TestHandled(
+@"class C
+{
+ void M()
+ {
+ var v = // a
+ /* b */ @$[||] // c
+ }
+}",
+@"class C
+{
+ void M()
+ {
+ var v = // a
+ /* b */ $@""[||] // c
+ }
+}");
+ }
+ }
+}
diff --git a/src/EditorFeatures/CSharpTest/SplitStringLiteral/SplitStringLiteralCommandHandlerTests.cs b/src/EditorFeatures/CSharpTest/SplitStringLiteral/SplitStringLiteralCommandHandlerTests.cs
index 395c30f3e1a7c896c2679bec90e1015aa1057689..595aba796f67a7cb44a705c7615bbea7d4817d6b 100644
--- a/src/EditorFeatures/CSharpTest/SplitStringLiteral/SplitStringLiteralCommandHandlerTests.cs
+++ b/src/EditorFeatures/CSharpTest/SplitStringLiteral/SplitStringLiteralCommandHandlerTests.cs
@@ -1,4 +1,6 @@
-using System;
+// 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.Linq;
using Microsoft.CodeAnalysis.Editor.CSharp.SplitStringLiteral;
diff --git a/src/Test/Utilities/Portable/Traits/Traits.cs b/src/Test/Utilities/Portable/Traits/Traits.cs
index e2b458ae637711875616c98e066bfdc7bc6e1c56..605f809c4a042540943256b800773c648528b974 100644
--- a/src/Test/Utilities/Portable/Traits/Traits.cs
+++ b/src/Test/Utilities/Portable/Traits/Traits.cs
@@ -179,6 +179,7 @@ public static class Features
public const string F1Help = nameof(F1Help);
public const string FindReferences = nameof(FindReferences);
public const string FixIncorrectTokens = nameof(FixIncorrectTokens);
+ public const string FixInterpolatedVerbatimString = nameof(FixInterpolatedVerbatimString);
public const string Formatting = nameof(Formatting);
public const string GoToDefinition = nameof(GoToDefinition);
public const string GoToImplementation = nameof(GoToImplementation);
diff --git a/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpAutomaticBraceCompletion.cs b/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpAutomaticBraceCompletion.cs
index f34f93d5e655469e470f4562c11e65e1b0b4ee86..634c1699ff7d8d8f2b4af3d43b5bfac7fc40c563 100644
--- a/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpAutomaticBraceCompletion.cs
+++ b/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpAutomaticBraceCompletion.cs
@@ -200,6 +200,38 @@ class C {
VisualStudio.Editor.Verify.CurrentLineText("string str = \"Hi Roslyn!\"$$", assertCaretPosition: true);
}
+ [WpfFact, Trait(Traits.Feature, Traits.Features.AutomaticCompletion)]
+ public void DoubleQuote_FixedInterpolatedVerbatimString()
+ {
+ SetUpEditor(@"
+class C
+{
+ void M()
+ {
+ $$
+ }
+}");
+
+ VisualStudio.Editor.SendKeys("var v = @$\"");
+ VisualStudio.Editor.Verify.CurrentLineText("var v = $@\"$$\"", assertCaretPosition: true);
+
+ // Backspace removes quotes
+ VisualStudio.Editor.SendKeys(VirtualKey.Backspace);
+ VisualStudio.Editor.Verify.CurrentLineText("var v = $@$$", assertCaretPosition: true);
+
+ // Undo puts them back
+ VisualStudio.Editor.Undo();
+ VisualStudio.Editor.Verify.CurrentLineText("var v = $@\"$$\"", assertCaretPosition: true);
+
+ // First, the FixInterpolatedVerbatimString action is undone (@$ reordering)
+ VisualStudio.Editor.Undo();
+ VisualStudio.Editor.Verify.CurrentLineText("var v = @$\"$$\"", assertCaretPosition: true);
+
+ // Then the automatic quote completion is undone
+ VisualStudio.Editor.Undo();
+ VisualStudio.Editor.Verify.CurrentLineText("var v = @$\"$$", assertCaretPosition: true);
+ }
+
[WpfFact, Trait(Traits.Feature, Traits.Features.AutomaticCompletion)]
public void AngleBracket_PossibleGenerics_InsertionAndCompletion()
{