diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj
index cf1ff4e9c25ca6894a49fea0c4431daff8636931..cdfc599466f623e722d7223a2ed8eff06a9399be 100644
--- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj
+++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj
@@ -126,6 +126,9 @@
+
+
+
diff --git a/vsintegration/src/FSharp.Editor/Hints/HintService.fs b/vsintegration/src/FSharp.Editor/Hints/HintService.fs
new file mode 100644
index 0000000000000000000000000000000000000000..13edb5448d8918444e09b213ab48df84d343d71b
--- /dev/null
+++ b/vsintegration/src/FSharp.Editor/Hints/HintService.fs
@@ -0,0 +1,79 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+
+namespace Microsoft.VisualStudio.FSharp.Editor.Hints
+
+open Microsoft.CodeAnalysis
+open Microsoft.VisualStudio.FSharp.Editor
+open FSharp.Compiler.CodeAnalysis
+open FSharp.Compiler.Symbols
+open FSharp.Compiler.Text
+
+module HintService =
+
+ // Relatively convenient for testing
+ type NativeHint = {
+ Range: range
+ Parts: TaggedText list
+ }
+
+ let private isValidForHint
+ (parseFileResults: FSharpParseFileResults)
+ (symbol: FSharpMemberOrFunctionOrValue)
+ (symbolUse: FSharpSymbolUse) =
+
+ let isNotAnnotatedManually =
+ not (parseFileResults.IsTypeAnnotationGivenAtPosition symbolUse.Range.Start)
+
+ let isNotAfterDot =
+ symbolUse.IsFromDefinition
+ && not symbol.IsMemberThisValue
+
+ let isNotTypeAlias =
+ not symbol.IsConstructorThisValue
+
+ symbol.IsValue // we'll be adding other stuff gradually here
+ && isNotAnnotatedManually
+ && isNotAfterDot
+ && isNotTypeAlias
+
+ let private getHintParts
+ (symbol: FSharpMemberOrFunctionOrValue)
+ (symbolUse: FSharpSymbolUse) =
+
+ match symbol.GetReturnTypeLayout symbolUse.DisplayContext with
+ | Some typeInfo ->
+ let colon = TaggedText(TextTag.Text, ": ")
+ colon :: (typeInfo |> Array.toList)
+
+ // not sure when this can happen but better safe than sorry
+ | None ->
+ []
+
+ let private getHintsForSymbol parseResults (symbolUse: FSharpSymbolUse) =
+ match symbolUse.Symbol with
+ | :? FSharpMemberOrFunctionOrValue as mfvSymbol
+ when isValidForHint parseResults mfvSymbol symbolUse ->
+
+ [ {
+ Range = symbolUse.Range
+ Parts = getHintParts mfvSymbol symbolUse
+ } ]
+
+ // we'll be adding other stuff gradually here
+ | _ ->
+ []
+
+ let getHintsForDocument (document: Document) userOpName cancellationToken =
+ async {
+ if isSignatureFile document.FilePath
+ then
+ return []
+ else
+ let! parseResults, checkResults =
+ document.GetFSharpParseAndCheckResultsAsync userOpName
+
+ return
+ checkResults.GetAllUsesOfAllSymbolsInFile cancellationToken
+ |> Seq.toList
+ |> List.collect (getHintsForSymbol parseResults)
+ }
diff --git a/vsintegration/src/FSharp.Editor/Hints/NativeToRoslynHintConverter.fs b/vsintegration/src/FSharp.Editor/Hints/NativeToRoslynHintConverter.fs
new file mode 100644
index 0000000000000000000000000000000000000000..9396d7d9256e088ac4da9327d5afaa4fc666c7ad
--- /dev/null
+++ b/vsintegration/src/FSharp.Editor/Hints/NativeToRoslynHintConverter.fs
@@ -0,0 +1,27 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+
+namespace Microsoft.VisualStudio.FSharp.Editor.Hints
+
+open System.Collections.Immutable
+open Microsoft.CodeAnalysis.Text
+open Microsoft.CodeAnalysis.ExternalAccess.FSharp.InlineHints
+open Microsoft.VisualStudio.FSharp.Editor
+open FSharp.Compiler.Text
+open HintService
+
+module NativeToRoslynHintConverter =
+
+ let rangeToSpan range sourceText =
+ let symbolSpan = RoslynHelpers.FSharpRangeToTextSpan(sourceText, range)
+ let overshadowLength = 0 // anything >0 means overlaying the code
+ TextSpan(symbolSpan.End, overshadowLength)
+
+ let nativeToRoslynText (taggedText: TaggedText) =
+ let tag = RoslynHelpers.roslynTag taggedText.Tag
+ let text = taggedText.Text
+ RoslynTaggedText(tag, text)
+
+ let convert sourceText hint =
+ let span = rangeToSpan hint.Range sourceText
+ let displayParts = hint.Parts |> Seq.map nativeToRoslynText
+ FSharpInlineHint(span, displayParts.ToImmutableArray())
\ No newline at end of file
diff --git a/vsintegration/src/FSharp.Editor/Hints/RoslynAdapter.fs b/vsintegration/src/FSharp.Editor/Hints/RoslynAdapter.fs
new file mode 100644
index 0000000000000000000000000000000000000000..01fde061024a6185f0e059d24973c28cb9e0ef44
--- /dev/null
+++ b/vsintegration/src/FSharp.Editor/Hints/RoslynAdapter.fs
@@ -0,0 +1,38 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+
+namespace Microsoft.VisualStudio.FSharp.Editor.Hints
+
+open System.Collections.Immutable
+open System.ComponentModel.Composition
+open Microsoft.CodeAnalysis.ExternalAccess.FSharp.InlineHints
+open Microsoft.VisualStudio.FSharp.Editor
+
+// So the Roslyn interface is called IFSharpInlineHintsService
+// but our implementation is called just HintsService.
+// That's because we'll likely use this API for things other than inline hints,
+// e.g. signature hints above the line, pipeline hints on the side and so on.
+
+[)>]
+type internal RoslynAdapter
+ []
+ (settings: EditorOptions) =
+
+ static let userOpName = "Hints"
+
+ interface IFSharpInlineHintsService with
+ member _.GetInlineHintsAsync(document, _, cancellationToken) =
+ async {
+ if not settings.Advanced.IsInlineHintsEnabled
+ then return ImmutableArray.Empty
+
+ else
+ let! sourceText = document.GetTextAsync cancellationToken |> Async.AwaitTask
+ let! nativeHints =
+ HintService.getHintsForDocument document userOpName cancellationToken
+
+ let roslynHints =
+ nativeHints
+ |> Seq.map (NativeToRoslynHintConverter.convert sourceText)
+
+ return roslynHints.ToImmutableArray()
+ } |> RoslynHelpers.StartAsyncAsTask cancellationToken
diff --git a/vsintegration/src/FSharp.Editor/Options/EditorOptions.fs b/vsintegration/src/FSharp.Editor/Options/EditorOptions.fs
index e6c4b202d8eaf29462cfbf293cacb0f79556a58c..e9a05b99c7acc0d9d8e5f8a76481880b52d5d70b 100644
--- a/vsintegration/src/FSharp.Editor/Options/EditorOptions.fs
+++ b/vsintegration/src/FSharp.Editor/Options/EditorOptions.fs
@@ -85,10 +85,12 @@ type LensOptions =
[]
type AdvancedOptions =
{ IsBlockStructureEnabled: bool
- IsOutliningEnabled: bool }
+ IsOutliningEnabled: bool
+ IsInlineHintsEnabled: bool }
static member Default =
{ IsBlockStructureEnabled = true
- IsOutliningEnabled = true }
+ IsOutliningEnabled = true
+ IsInlineHintsEnabled = false }
[]
type FormattingOptions =
diff --git a/vsintegration/src/FSharp.UIResources/AdvancedOptionsControl.xaml b/vsintegration/src/FSharp.UIResources/AdvancedOptionsControl.xaml
index 7126d6efb8bbad8743f20f0aee4d4347f5b60f30..4e80e56c6f484d2a70a9c281f0871f5f734445ce 100644
--- a/vsintegration/src/FSharp.UIResources/AdvancedOptionsControl.xaml
+++ b/vsintegration/src/FSharp.UIResources/AdvancedOptionsControl.xaml
@@ -24,6 +24,10 @@
+
+
+
diff --git a/vsintegration/src/FSharp.UIResources/Strings.Designer.cs b/vsintegration/src/FSharp.UIResources/Strings.Designer.cs
index d7e8ec6a86c1cd2943861f458f79511772b63a53..23f3b7232049ef1fc486c89bfd23a2f40c92d6f2 100644
--- a/vsintegration/src/FSharp.UIResources/Strings.Designer.cs
+++ b/vsintegration/src/FSharp.UIResources/Strings.Designer.cs
@@ -204,6 +204,15 @@ public class Strings {
}
}
+ ///
+ /// Looks up a localized string similar to Inline Hints.
+ ///
+ public static string Inline_Hints {
+ get {
+ return ResourceManager.GetString("Inline_Hints", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to IntelliSense Performance Options.
///
@@ -330,6 +339,15 @@ public class Strings {
}
}
+ ///
+ /// Looks up a localized string similar to Display inline type hints (experimental).
+ ///
+ public static string Show_Inline_Hints {
+ get {
+ return ResourceManager.GetString("Show_Inline_Hints", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to S_how navigation links as.
///
diff --git a/vsintegration/src/FSharp.UIResources/Strings.resx b/vsintegration/src/FSharp.UIResources/Strings.resx
index a55acfe02906a503a5f04c726415266c7144abd4..e6f9fccd9dac505ac1f23ae5de8d9f0896191a3e 100644
--- a/vsintegration/src/FSharp.UIResources/Strings.resx
+++ b/vsintegration/src/FSharp.UIResources/Strings.resx
@@ -189,6 +189,12 @@
Show outlining and collapsible nodes for F# code
+
+ Inline Hints
+
+
+ Display inline type hints (experimental)
+
Time until stale results are used (in milliseconds)
diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.cs.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.cs.xlf
index 465126331dd46c4f591ea01d9de9a7795daa1ad0..2c2fe934b7c532a76ec40bfd9a73d3faa36826f9 100644
--- a/vsintegration/src/FSharp.UIResources/xlf/Strings.cs.xlf
+++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.cs.xlf
@@ -7,6 +7,11 @@
Vždy umístit otevřené příkazy na nejvyšší úroveň
+
+
+ Inline Hints
+
+
Lens
@@ -77,6 +82,11 @@
Parallelization (requires restart)
+
+
+ Display inline type hints (experimental)
+
+
Zobrazit s_ymboly v neotevřených oborech názvů
diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.de.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.de.xlf
index 19dbdecc59179a825fd0425a4fe9d48c53aa29cd..b946628c022a2cbd1ef5911a2cb34269f7fc38dd 100644
--- a/vsintegration/src/FSharp.UIResources/xlf/Strings.de.xlf
+++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.de.xlf
@@ -7,6 +7,11 @@
open-Anweisungen immer an oberster Ebene platzieren
+
+
+ Inline Hints
+
+
Lens
@@ -77,6 +82,11 @@
Parallelization (requires restart)
+
+
+ Display inline type hints (experimental)
+
+
S_ymbole in nicht geöffneten Namespaces anzeigen
diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.es.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.es.xlf
index 593de70499a8a40ae0d33e6dd7f0a978e3194729..9212a40cb0b9357dded724f1112359035240f66f 100644
--- a/vsintegration/src/FSharp.UIResources/xlf/Strings.es.xlf
+++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.es.xlf
@@ -7,6 +7,11 @@
Colocar siempre las instrucciones open en el nivel superior
+
+
+ Inline Hints
+
+
Lens
@@ -77,6 +82,11 @@
Parallelization (requires restart)
+
+
+ Display inline type hints (experimental)
+
+
Mostrar sím_bolos en espacios de nombres sin abrir
diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.fr.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.fr.xlf
index ac9837fd02a81cfe8a8fb917eeb91659516f4d7b..5fa8f1caea20b50cc229d94426a443848ec8c7a2 100644
--- a/vsintegration/src/FSharp.UIResources/xlf/Strings.fr.xlf
+++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.fr.xlf
@@ -7,6 +7,11 @@
Placer toujours les instructions open au niveau supérieur
+
+
+ Inline Hints
+
+
Lens
@@ -77,6 +82,11 @@
Parallelization (requires restart)
+
+
+ Display inline type hints (experimental)
+
+
Afficher les sym_boles dans les espaces de noms non ouverts
diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.it.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.it.xlf
index b1cbcdc1cda6e5b14018958191d15505a1c4a09d..a5732c33ea345eae84d90cc7564bc5340a681bb0 100644
--- a/vsintegration/src/FSharp.UIResources/xlf/Strings.it.xlf
+++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.it.xlf
@@ -7,6 +7,11 @@
Inserisci sempre le istruzioni OPEN al primo livello
+
+
+ Inline Hints
+
+
Lens
@@ -77,6 +82,11 @@
Parallelization (requires restart)
+
+
+ Display inline type hints (experimental)
+
+
Mostra si_mboli in spazi dei nomi non aperti
diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.ja.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.ja.xlf
index 1d40d97e0e7e93f4196663f325f5cc3f4ec7cf07..30a7d45df9f034bc250bb00a54d4be2a4b1fd03e 100644
--- a/vsintegration/src/FSharp.UIResources/xlf/Strings.ja.xlf
+++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.ja.xlf
@@ -7,6 +7,11 @@
Open ステートメントを常に最上位に配置する
+
+
+ Inline Hints
+
+
Lens
@@ -77,6 +82,11 @@
Parallelization (requires restart)
+
+
+ Display inline type hints (experimental)
+
+
開かれていない名前空間の記号を表示する(_Y)
diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.ko.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.ko.xlf
index 42d4f8d5b2f2b17a22699576024acc3b3176346d..ef59262a118ebcff9308db50ebc2b32dbc8dbaad 100644
--- a/vsintegration/src/FSharp.UIResources/xlf/Strings.ko.xlf
+++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.ko.xlf
@@ -7,6 +7,11 @@
항상 최상위에 open 문 배치
+
+
+ Inline Hints
+
+
Lens
@@ -77,6 +82,11 @@
Parallelization (requires restart)
+
+
+ Display inline type hints (experimental)
+
+
열려 있지 않은 네임스페이스에 기호 표시(_Y)
diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.pl.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.pl.xlf
index 80c575eb707871a726f9b3df46a353e6a989ea62..b388b74d48e63cba0d45eb9060341b521d74cfd2 100644
--- a/vsintegration/src/FSharp.UIResources/xlf/Strings.pl.xlf
+++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.pl.xlf
@@ -7,6 +7,11 @@
Zawsze umieszczaj otwarte instrukcje na najwyższym poziomie
+
+
+ Inline Hints
+
+
Lens
@@ -77,6 +82,11 @@
Parallelization (requires restart)
+
+
+ Display inline type hints (experimental)
+
+
Pokaż s_ymbole w nieotwartych przestrzeniach nazw
diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.pt-BR.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.pt-BR.xlf
index ed7bd886e925151f1ac72a30d39799b645ae4009..43082d7a4680c28758550d179e1f466cd597df3d 100644
--- a/vsintegration/src/FSharp.UIResources/xlf/Strings.pt-BR.xlf
+++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.pt-BR.xlf
@@ -7,6 +7,11 @@
Sempre coloque as instruções abertas no nível superior
+
+
+ Inline Hints
+
+
Lens
@@ -77,6 +82,11 @@
Parallelization (requires restart)
+
+
+ Display inline type hints (experimental)
+
+
Mostrar s_ímbolos em namespaces não abertos
diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.ru.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.ru.xlf
index 2b61ff39466d301806d83706e6ec208074c433e8..dfe465c0259f41fcb00f1af688f44228a8ab86a2 100644
--- a/vsintegration/src/FSharp.UIResources/xlf/Strings.ru.xlf
+++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.ru.xlf
@@ -7,6 +7,11 @@
Всегда располагайте открытые операторы на верхнем уровне
+
+
+ Inline Hints
+
+
Lens
@@ -77,6 +82,11 @@
Parallelization (requires restart)
+
+
+ Display inline type hints (experimental)
+
+
По_казать символы в неоткрытых пространствах имен
diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.tr.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.tr.xlf
index 031215b1fdcc0e34732cff5976a3bb5ab469e27e..7717e353c223c280992bd7f3718dc8957f9599a9 100644
--- a/vsintegration/src/FSharp.UIResources/xlf/Strings.tr.xlf
+++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.tr.xlf
@@ -7,6 +7,11 @@
Açık deyimleri her zaman en üst düzeye yerleştir
+
+
+ Inline Hints
+
+
Lens
@@ -77,6 +82,11 @@
Parallelization (requires restart)
+
+
+ Display inline type hints (experimental)
+
+
Açılmamış ad alanlarında s_embolleri göster
diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hans.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hans.xlf
index f78d543557e048685a83a2360ad2209b738107ac..7e5b5761e6e0207b6463e59b2009e389a074974a 100644
--- a/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hans.xlf
+++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hans.xlf
@@ -7,6 +7,11 @@
始终在顶层放置 open 语句
+
+
+ Inline Hints
+
+
Lens
@@ -77,6 +82,11 @@
Parallelization (requires restart)
+
+
+ Display inline type hints (experimental)
+
+
显示未打开的命名空间中的符号(_Y)
diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hant.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hant.xlf
index 71eac224dc4fa149735d4fe32dc3189954bcf814..c24a02fb051d7a0d94e240d01119a4162f228098 100644
--- a/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hant.xlf
+++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hant.xlf
@@ -7,6 +7,11 @@
一律將 open 陳述式放在最上層
+
+
+ Inline Hints
+
+
Lens
@@ -77,6 +82,11 @@
Parallelization (requires restart)
+
+
+ Display inline type hints (experimental)
+
+
顯示未開啟之命名空間中的符號(_Y)
diff --git a/vsintegration/tests/UnitTests/HintServiceTests.fs b/vsintegration/tests/UnitTests/HintServiceTests.fs
new file mode 100644
index 0000000000000000000000000000000000000000..f94954df4c9a0f3e55cf006a5a4bf5347d37dcd5
--- /dev/null
+++ b/vsintegration/tests/UnitTests/HintServiceTests.fs
@@ -0,0 +1,115 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+
+namespace VisualFSharp.UnitTests.Editor.Hints
+
+open NUnit.Framework
+open HintTestFramework
+
+module HintServiceTests =
+
+[]
+let ``Type hints are not shown in signature files`` () =
+ let fsiCode = """
+module Test
+
+val numbers: int[]
+"""
+ let fsCode = """
+module Test
+
+let numbers = [|42|]
+"""
+ let fsiDocument, _ = getFsiAndFsDocuments fsiCode fsCode
+
+ let result = getHints fsiDocument
+
+ Assert.IsEmpty(result)
+
+[]
+let ``Type hints are not shown for let-bound functions yet`` () =
+ let code = """
+let setConsoleOut = System.Console.SetOut
+"""
+ let document = getFsDocument code
+
+ let result = getHints document
+
+ Assert.IsEmpty(result)
+
+[]
+let ``Type hint is shown for a let binding`` () =
+ let code = """
+type Song = { Artist: string; Title: string }
+
+let s = { Artist = "Moby"; Title = "Porcelain" }
+"""
+ let document = getFsDocument code
+ let expected = [{ Content = ": Song"; Location = (3, 6) }]
+
+ let actual = getHints document
+
+ Assert.AreEqual(expected, actual)
+
+[]
+let ``Type hint is not shown for a let binding when the type is manually specified`` () =
+ let code = """
+type Song = { Artist: string; Title: string }
+
+let s: Song = { Artist = "Moby"; Title = "Porcelain" }
+"""
+ let document = getFsDocument code
+
+ let result = getHints document
+
+ Assert.IsEmpty(result)
+
+[]
+let ``Type hint is shown for a parameter`` () =
+ let code = """
+type Song = { Artist: string; Title: string }
+
+let whoSings s = s.Artist
+"""
+ let document = getFsDocument code
+ let expected = [{ Content = ": Song"; Location = (3, 15) }]
+
+ let actual = getHints document
+
+ Assert.AreEqual(expected, actual)
+
+[]
+let ``Type hint is not shown for a parameter when the type is manually specified`` () =
+ let code = """
+type Song = { Artist: string; Title: string }
+
+let whoSings (s: Song) = s.Artist
+"""
+ let document = getFsDocument code
+
+ let result = getHints document
+
+ Assert.IsEmpty(result)
+
+[] // here we don't want a hint after "this"
+let ``Type hint is not shown for type self-identifiers`` () =
+ let code = """
+type Song() =
+ member this.GetName() = "Porcelain"
+"""
+ let document = getFsDocument code
+
+ let result = getHints document
+
+ Assert.IsEmpty(result)
+
+[] // here we don't want a hint after "x"
+let ``Type hint is not shown for type aliases`` () =
+ let code = """
+type Song() as x =
+ member this.Name = "Porcelain"
+"""
+ let document = getFsDocument code
+
+ let result = getHints document
+
+ Assert.IsEmpty(result)
diff --git a/vsintegration/tests/UnitTests/HintTestFramework.fs b/vsintegration/tests/UnitTests/HintTestFramework.fs
new file mode 100644
index 0000000000000000000000000000000000000000..87d4438abc36d43b9be1bac5cd83e6a3917df005
--- /dev/null
+++ b/vsintegration/tests/UnitTests/HintTestFramework.fs
@@ -0,0 +1,52 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+
+namespace VisualFSharp.UnitTests.Editor.Hints
+
+open System.Threading
+open Microsoft.VisualStudio.FSharp.Editor
+open Microsoft.VisualStudio.FSharp.Editor.Hints
+open Microsoft.VisualStudio.FSharp.Editor.Hints.HintService
+open VisualFSharp.UnitTests.Editor
+open Microsoft.CodeAnalysis.Text
+
+module HintTestFramework =
+
+// another representation for extra convenience
+type TestHint = {
+ Content: string
+ Location: int * int
+}
+
+let private convert hint =
+ let content =
+ hint.Parts
+ |> Seq.map (fun hintPart -> hintPart.Text)
+ |> String.concat ""
+
+ // that's about different coordinate systems
+ // in tests, the most convenient is the one used in editor,
+ // hence this conversion
+ let location = (hint.Range.StartLine - 1, hint.Range.EndColumn + 1)
+
+ { Content = content
+ Location = location }
+
+let getFsDocument code =
+ use project = SingleFileProject code
+ let fileName = fst project.Files.Head
+ let document, _ = RoslynTestHelpers.CreateSingleDocumentSolution(fileName, code)
+ document
+
+let getFsiAndFsDocuments (fsiCode: string) (fsCode: string) =
+ RoslynTestHelpers.CreateTwoDocumentSolution(
+ "test.fsi",
+ SourceText.From fsiCode,
+ "test.fs",
+ SourceText.From fsCode)
+
+let getHints document =
+ async {
+ let! hints = HintService.getHintsForDocument document "test" CancellationToken.None
+ return hints |> Seq.map convert
+ }
+ |> Async.RunSynchronously
diff --git a/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs b/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs
index f7de265b87b1fa5d3ccb80818a591d9c102ef8bb..da0451837a64d10c26b930dc3cc322e4e0f4b8ba 100644
--- a/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs
+++ b/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs
@@ -273,7 +273,59 @@ type RoslynTestHelpers private () =
document
+ static member CreateTwoDocumentSolution (filePath1, text1: SourceText, filePath2, text2: SourceText) =
+ let workspace = new AdhocWorkspace(TestHostServices())
+
+ let projId = ProjectId.CreateNewId()
+ let docId1 = DocumentId.CreateNewId(projId)
+ let docId2 = DocumentId.CreateNewId(projId)
+
+ let docInfo1 =
+ DocumentInfo.Create(
+ docId1,
+ filePath1,
+ loader=TextLoader.From(text1.Container, VersionStamp.Create(DateTime.UtcNow)),
+ filePath=filePath1,
+ sourceCodeKind= SourceCodeKind.Regular)
+
+ let docInfo2 =
+ DocumentInfo.Create(
+ docId2,
+ filePath2,
+ loader=TextLoader.From(text2.Container, VersionStamp.Create(DateTime.UtcNow)),
+ filePath=filePath2,
+ sourceCodeKind= SourceCodeKind.Regular)
+
+ let projFilePath = "C:\\test.fsproj"
+ let projInfo =
+ ProjectInfo.Create(
+ projId,
+ VersionStamp.Create(DateTime.UtcNow),
+ projFilePath,
+ "test.dll",
+ LanguageNames.FSharp,
+ documents = [docInfo1;docInfo2],
+ filePath = projFilePath
+ )
+
+ let solutionInfo = SolutionInfo.Create(SolutionId.CreateNewId(), VersionStamp.Create(DateTime.UtcNow), "test.sln", [projInfo])
+ let solution = workspace.AddSolution(solutionInfo)
+
+ workspace
+ .Services
+ .GetService()
+ .FSharpProjectOptionsManager
+ .SetCommandLineOptions(projId, [|filePath1;filePath2|], ImmutableArray.Empty)
+
+ let document1 = solution.GetProject(projId).GetDocument(docId1)
+ let document2 = solution.GetProject(projId).GetDocument(docId2)
+ document1, document2
+
static member CreateSingleDocumentSolution (filePath, code: string, ?options) =
let text = SourceText.From(code)
RoslynTestHelpers.CreateSingleDocumentSolution(filePath, text, ?options = options), text
+ static member CreateTwoDocumentSolution (filePath1, code1: string, filePath2, code2: string) =
+ let text1 = SourceText.From code1
+ let text2 = SourceText.From code2
+ RoslynTestHelpers.CreateTwoDocumentSolution(filePath1, text1, filePath2, text2)
diff --git a/vsintegration/tests/UnitTests/VisualFSharp.UnitTests.fsproj b/vsintegration/tests/UnitTests/VisualFSharp.UnitTests.fsproj
index 542ec626ebd18f06e5c38b24da8beffa06d27395..15b068503d80dbdc1ac88101308d10acf715f562 100644
--- a/vsintegration/tests/UnitTests/VisualFSharp.UnitTests.fsproj
+++ b/vsintegration/tests/UnitTests/VisualFSharp.UnitTests.fsproj
@@ -102,6 +102,12 @@
Editor\QuickInfoTests.fs
+
+ Editor\Hints\HintTestFramework.fs
+
+
+ Editor\Hints\HintServiceTests.fs
+
Editor\GoToDefinitionServiceTests.fs