diff --git a/src/fsharp/service/FSharpParseFileResults.fs b/src/fsharp/service/FSharpParseFileResults.fs index 4896d95396f..b559f3a2ca5 100644 --- a/src/fsharp/service/FSharpParseFileResults.fs +++ b/src/fsharp/service/FSharpParseFileResults.fs @@ -306,6 +306,14 @@ type FSharpParseFileResults(diagnostics: FSharpDiagnostic[], input: ParsedInput, Some(app.Range, lambdaArgs.Range, lambdaBody.Range) | _ -> defaultTraverse binding }) + member _.TryRangeOfStringInterpolationContainingPos pos = + SyntaxTraversal.Traverse(pos, input, { new SyntaxVisitorBase<_>() with + member _.VisitExpr(_, _, defaultTraverse, expr) = + match expr with + | SynExpr.InterpolatedString(range = range) when rangeContainsPos range pos -> + Some range + | _ -> defaultTraverse expr }) + member _.TryRangeOfExprInYieldOrReturn pos = SyntaxTraversal.Traverse(pos, input, { new SyntaxVisitorBase<_>() with member _.VisitExpr(_path, _, defaultTraverse, expr) = diff --git a/src/fsharp/service/FSharpParseFileResults.fsi b/src/fsharp/service/FSharpParseFileResults.fsi index e5048aa4700..24be61e2dfa 100644 --- a/src/fsharp/service/FSharpParseFileResults.fsi +++ b/src/fsharp/service/FSharpParseFileResults.fsi @@ -20,6 +20,9 @@ type public FSharpParseFileResults = /// Attempts to find the range of an attempted lambda expression or pattern, the argument range, and the expr range when writing a C#-style "lambda" (which is actually an operator application) member TryRangeOfParenEnclosingOpEqualsGreaterUsage: opGreaterEqualPos: pos -> (range * range * range) option + /// Attempts to find the range of the string interpolation that contains a given position. + member TryRangeOfStringInterpolationContainingPos: pos: pos -> range option + /// Attempts to find the range of an expression `expr` contained in a `yield expr` or `return expr` expression (and bang-variants). member TryRangeOfExprInYieldOrReturn: pos: pos -> range option diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected b/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected index 9fa7d5da8a5..483cc3ca488 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected @@ -2069,6 +2069,7 @@ FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Microsoft.FSharp.Core.FShar FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range] TryRangeOfNameOfNearestOuterBindingContainingPos(FSharp.Compiler.Text.Position) FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range] TryRangeOfRecordExpressionContainingPos(FSharp.Compiler.Text.Position) FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range] TryRangeOfRefCellDereferenceContainingPos(FSharp.Compiler.Text.Position) +FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range] TryRangeOfStringInterpolationContainingPos(FSharp.Compiler.Text.Position) FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range] ValidateBreakpointLocation(FSharp.Compiler.Text.Position) FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Text.Range]] GetAllArgumentsForFunctionApplicationAtPostion(FSharp.Compiler.Text.Position) FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`2[FSharp.Compiler.Syntax.Ident,System.Int32]] TryIdentOfPipelineContainingPosAndNumArgsApplied(FSharp.Compiler.Text.Position) diff --git a/vsintegration/src/FSharp.Editor/CodeFix/UseTripleQuotedInterpolation.fs b/vsintegration/src/FSharp.Editor/CodeFix/UseTripleQuotedInterpolation.fs new file mode 100644 index 00000000000..4e7bb2c1130 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/CodeFix/UseTripleQuotedInterpolation.fs @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace Microsoft.VisualStudio.FSharp.Editor + +open System.Composition + +open Microsoft.CodeAnalysis.Text +open Microsoft.CodeAnalysis.CodeFixes + +[] +type internal FSharpUseTripleQuotedInterpolationCodeFixProvider + [] + ( + ) = + inherit CodeFixProvider() + + let fixableDiagnosticIds = ["FS3373"] + + override _.FixableDiagnosticIds = Seq.toImmutableArray fixableDiagnosticIds + + override _.RegisterCodeFixesAsync context = + asyncMaybe { + let! parseResults = context.Document.GetFSharpParseResultsAsync(nameof(FSharpUseTripleQuotedInterpolationCodeFixProvider)) |> liftAsync + + let! sourceText = context.Document.GetTextAsync(context.CancellationToken) + let errorRange = RoslynHelpers.TextSpanToFSharpRange(context.Document.FilePath, context.Span, sourceText) + + let! interpolationRange = parseResults.TryRangeOfStringInterpolationContainingPos errorRange.Start + let! interpolationSpan = RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, interpolationRange) + + let replacement = + let interpolation = sourceText.GetSubText(interpolationSpan).ToString() + TextChange(interpolationSpan, "$\"\"" + interpolation.[ 1 .. ] + "\"\"") + + let diagnostics = + context.Diagnostics + |> Seq.filter (fun x -> fixableDiagnosticIds |> List.contains x.Id) + |> Seq.toImmutableArray + + let title = SR.UseTripleQuotedInterpolation() + + let codeFix = + CodeFixHelpers.createTextChangeCodeFix( + title, + context, + (fun () -> asyncMaybe.Return [| replacement |])) + + context.RegisterCodeFix(codeFix, diagnostics) + } + |> Async.Ignore + |> RoslynHelpers.StartAsyncUnitAsTask(context.CancellationToken) diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 52adc3455de..21d2a8474eb 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -121,6 +121,7 @@ + diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.resx b/vsintegration/src/FSharp.Editor/FSharp.Editor.resx index bb52e1a6d80..3e21fdd3825 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.resx +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.resx @@ -288,4 +288,7 @@ Use 'nameof' - + + Use triple quoted string interpolation. + + \ No newline at end of file diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf index 46110921718..3924536b1b7 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf @@ -262,6 +262,11 @@ Použít nameof + + Use triple quoted string interpolation. + Use triple quoted string interpolation. + + Use 'upcast' Použijte upcast diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf index f1f58499629..7d63c9ad51f 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf @@ -262,6 +262,11 @@ "nameof" verwenden + + Use triple quoted string interpolation. + Use triple quoted string interpolation. + + Use 'upcast' "upcast" verwenden diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf index 94b05697af1..e3e2edb57b0 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf @@ -262,6 +262,11 @@ Usar 'nameof' + + Use triple quoted string interpolation. + Use triple quoted string interpolation. + + Use 'upcast' Usar "upcast" diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf index 411291f3107..c642a2abc0b 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf @@ -262,6 +262,11 @@ Utiliser « nameof » + + Use triple quoted string interpolation. + Use triple quoted string interpolation. + + Use 'upcast' Utiliser 'upcast' diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf index 0135663e689..57551afdd4a 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf @@ -262,6 +262,11 @@ Usa 'nameof' + + Use triple quoted string interpolation. + Use triple quoted string interpolation. + + Use 'upcast' Usare 'upcast' diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf index 4d2eee45eda..001c76425ff 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf @@ -262,6 +262,11 @@ 'nameof' を使用する + + Use triple quoted string interpolation. + Use triple quoted string interpolation. + + Use 'upcast' 'upcast' を使用する diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf index bf8970636e7..b506295efc5 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf @@ -262,6 +262,11 @@ 'nameof' 사용 + + Use triple quoted string interpolation. + Use triple quoted string interpolation. + + Use 'upcast' 'upcast' 사용 diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf index 17f87908463..c0b790d2ff7 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf @@ -262,6 +262,11 @@ Użyj wyrażenia "nameof" + + Use triple quoted string interpolation. + Use triple quoted string interpolation. + + Use 'upcast' Użyj operatora „upcast” diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf index ecdeb82bfc2..7103870cac4 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf @@ -262,6 +262,11 @@ Usar 'nameof' + + Use triple quoted string interpolation. + Use triple quoted string interpolation. + + Use 'upcast' Usar 'upcast' diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf index fd61cbdc2eb..cef630548b9 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf @@ -262,6 +262,11 @@ Использовать "nameof" + + Use triple quoted string interpolation. + Use triple quoted string interpolation. + + Use 'upcast' Используйте "upcast" diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf index 99c7fe89225..15e65caeb38 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf @@ -262,6 +262,11 @@ “Nameof” kullanın + + Use triple quoted string interpolation. + Use triple quoted string interpolation. + + Use 'upcast' 'upcast' kullan diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf index 08ede03e605..af618ea6949 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf @@ -262,6 +262,11 @@ 使用 "nameof" + + Use triple quoted string interpolation. + Use triple quoted string interpolation. + + Use 'upcast' 使用“向上转换” diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf index 43c5ce4f127..13006a09b88 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf @@ -262,6 +262,11 @@ 使用 'nameof' + + Use triple quoted string interpolation. + Use triple quoted string interpolation. + + Use 'upcast' 使用「向上轉型」