diff --git a/fcs/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.Tests.fsproj b/fcs/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.Tests.fsproj
index d6c71b55456..6ee0cfab376 100644
--- a/fcs/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.Tests.fsproj
+++ b/fcs/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.Tests.fsproj
@@ -101,5 +101,6 @@
+
\ No newline at end of file
diff --git a/src/fsharp/CompileOps.fs b/src/fsharp/CompileOps.fs
index 69f83055562..22e5923374e 100644
--- a/src/fsharp/CompileOps.fs
+++ b/src/fsharp/CompileOps.fs
@@ -2321,6 +2321,7 @@ type TcConfigBuilder =
isInvalidationSupported = isInvalidationSupported
copyFSharpCore = defaultCopyFSharpCore
tryGetMetadataSnapshot = tryGetMetadataSnapshot
+ useFsiAuxLib = isInteractive
}
member tcConfigB.ResolveSourceFile(m, nm, pathLoadedFrom) =
diff --git a/src/fsharp/service/FSharpCheckerResults.fs b/src/fsharp/service/FSharpCheckerResults.fs
index ab8ee3d216f..cd9b187d3ad 100644
--- a/src/fsharp/service/FSharpCheckerResults.fs
+++ b/src/fsharp/service/FSharpCheckerResults.fs
@@ -58,7 +58,7 @@ module internal FSharpCheckerResultsSettings =
| s -> int64 s
// Look for DLLs in the location of the service DLL first.
- let defaultFSharpBinariesDir = FSharpEnvironment.BinFolderOfDefaultFSharpCompiler(Some(typeof.Assembly.Location)).Value
+ let defaultFSharpBinariesDir = FSharpEnvironment.BinFolderOfDefaultFSharpCompiler(Some(Path.GetDirectoryName(typeof.Assembly.Location))).Value
[]
type FSharpFindDeclFailureReason =
diff --git a/src/fsharp/service/IncrementalBuild.fs b/src/fsharp/service/IncrementalBuild.fs
index 4cb4c23ea4a..365570b5d62 100755
--- a/src/fsharp/service/IncrementalBuild.fs
+++ b/src/fsharp/service/IncrementalBuild.fs
@@ -1732,7 +1732,7 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInput
defaultFSharpBinariesDir,
implicitIncludeDir=projectDirectory,
reduceMemoryUsage=ReduceMemoryFlag.Yes,
- isInteractive=false,
+ isInteractive=useScriptResolutionRules,
isInvalidationSupported=true,
defaultCopyFSharpCore=CopyFSharpCoreFlag.No,
tryGetMetadataSnapshot=tryGetMetadataSnapshot)
diff --git a/vsintegration/tests/UnitTests/FsxCompletionProviderTests.fs b/vsintegration/tests/UnitTests/FsxCompletionProviderTests.fs
new file mode 100644
index 00000000000..468c916dc95
--- /dev/null
+++ b/vsintegration/tests/UnitTests/FsxCompletionProviderTests.fs
@@ -0,0 +1,161 @@
+// To run the tests in this file:
+//
+// Technique 1: Compile VisualFSharp.UnitTests.dll and run it as a set of unit tests
+//
+// Technique 2:
+//
+// Enable some tests in the #if EXE section at the end of the file,
+// then compile this file as an EXE that has InternalsVisibleTo access into the
+// appropriate DLLs. This can be the quickest way to get turnaround on updating the tests
+// and capturing large amounts of structured output.
+(*
+ cd Debug\net40\bin
+ .\fsc.exe --define:EXE -r:.\Microsoft.Build.Utilities.Core.dll -o VisualFSharp.UnitTests.exe -g --optimize- -r .\FSharp.Compiler.Private.dll -r .\FSharp.Editor.dll -r nunit.framework.dll ..\..\..\tests\service\FsUnit.fs ..\..\..\tests\service\Common.fs /delaysign /keyfile:..\..\..\src\fsharp\msft.pubkey ..\..\..\vsintegration\tests\UnitTests\FsxCompletionProviderTests.fs
+ .\VisualFSharp.UnitTests.exe
+*)
+// Technique 3:
+//
+// Use F# Interactive. This only works for FSharp.Compiler.Service.dll which has a public API
+
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+namespace Microsoft.VisualStudio.FSharp.Editor.Tests.Roslyn
+
+open System
+open System.Collections.Generic
+open System.IO
+open System.Linq
+open System.Reflection
+
+open NUnit.Framework
+
+open Microsoft.CodeAnalysis
+open Microsoft.CodeAnalysis.Completion
+open Microsoft.CodeAnalysis.Text
+open Microsoft.VisualStudio.FSharp.Editor
+
+open FSharp.Compiler.SourceCodeServices
+open UnitTests.TestLib.LanguageService
+
+// AppDomain helper
+type Worker () =
+ inherit MarshalByRefObject()
+
+ let filePath = "C:\\test.fsx"
+ let projectOptions = {
+ ProjectFileName = "C:\\test.fsproj"
+ ProjectId = None
+ SourceFiles = [| filePath |]
+ ReferencedProjects = [| |]
+ OtherOptions = [| |]
+ IsIncompleteTypeCheckEnvironment = true
+ UseScriptResolutionRules = true
+ LoadTime = DateTime.MaxValue
+ OriginalLoadReferences = []
+ UnresolvedReferences = None
+ ExtraProjectInfo = None
+ Stamp = None
+ }
+
+ let formatCompletions(completions : string seq) =
+ "\n\t" + String.Join("\n\t", completions)
+
+ let VerifyCompletionList(fileContents: string, marker: string, expected: string list, unexpected: string list) =
+ let caretPosition = fileContents.IndexOf(marker) + marker.Length
+ let results =
+ FSharpCompletionProvider.ProvideCompletionsAsyncAux(checker, SourceText.From(fileContents), caretPosition, projectOptions, filePath, 0, (fun _ -> []), LanguageServicePerformanceOptions.Default, IntelliSenseOptions.Default)
+ |> Async.RunSynchronously
+ |> Option.defaultValue (ResizeArray())
+ |> Seq.map(fun result -> result.DisplayText)
+
+ let expectedFound =
+ expected
+ |> Seq.filter results.Contains
+
+ let expectedNotFound =
+ expected
+ |> Seq.filter (expectedFound.Contains >> not)
+
+ let unexpectedNotFound =
+ unexpected
+ |> Seq.filter (results.Contains >> not)
+
+ let unexpectedFound =
+ unexpected
+ |> Seq.filter (unexpectedNotFound.Contains >> not)
+
+ // If either of these are true, then the test fails.
+ let hasExpectedNotFound = not (Seq.isEmpty expectedNotFound)
+ let hasUnexpectedFound = not (Seq.isEmpty unexpectedFound)
+
+ if hasExpectedNotFound || hasUnexpectedFound then
+ let expectedNotFoundMsg =
+ if hasExpectedNotFound then
+ sprintf "\nExpected completions not found:%s\n" (formatCompletions expectedNotFound)
+ else
+ String.Empty
+
+ let unexpectedFoundMsg =
+ if hasUnexpectedFound then
+ sprintf "\nUnexpected completions found:%s\n" (formatCompletions unexpectedFound)
+ else
+ String.Empty
+
+ let completionsMsg = sprintf "\nin Completions:%s" (formatCompletions results)
+
+ let msg = sprintf "%s%s%s" expectedNotFoundMsg unexpectedFoundMsg completionsMsg
+
+ Assert.Fail(msg)
+
+ member __.VerifyCompletionListExactly(fileContents: string, marker: string, expected: List) =
+
+ let caretPosition = fileContents.IndexOf(marker) + marker.Length
+ let expected = expected |> Seq.toList
+ let actual =
+ let x = FSharpCompletionProvider.ProvideCompletionsAsyncAux(checker, SourceText.From(fileContents), caretPosition, projectOptions, filePath, 0, (fun _ -> []), LanguageServicePerformanceOptions.Default, IntelliSenseOptions.Default)
+ |> Async.RunSynchronously
+ x |> Option.defaultValue (ResizeArray())
+ |> Seq.toList
+ // sort items as Roslyn do - by `SortText`
+ |> List.sortBy (fun x -> x.SortText)
+
+ let actualNames = actual |> List.map (fun x -> x.DisplayText)
+
+ if actualNames <> expected then
+ Assert.Fail(sprintf "Expected:\n%s,\nbut was:\n%s\nactual with sort text:\n%s"
+ (String.Join("; ", expected |> List.map (sprintf "\"%s\"")))
+ (String.Join("; ", actualNames |> List.map (sprintf "\"%s\"")))
+ (String.Join("\n", actual |> List.map (fun x -> sprintf "%s => %s" x.DisplayText x.SortText))))
+
+module FsxCompletionProviderTests =
+
+ let pathToThisDll = Assembly.GetExecutingAssembly().CodeBase
+
+ let getWorker () =
+
+ let adSetup =
+ let setup = new System.AppDomainSetup ()
+ setup.PrivateBinPath <- pathToThisDll
+ setup.ApplicationBase <- Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "SomeNonExistentDirectory")
+ setup
+
+ let ad = AppDomain.CreateDomain((Guid()).ToString(), null, adSetup)
+ (ad.CreateInstanceFromAndUnwrap(pathToThisDll, typeof.FullName)) :?> Worker
+
+ []
+ let fsiShouldTriggerCompletionInFsxFile() =
+
+ let fileContents = """
+ fsi.
+ """
+ let expected = List([
+ "CommandLineArgs"; "EventLoop"; "FloatingPointFormat"; "FormatProvider"; "PrintDepth";
+ "PrintLength"; "PrintSize"; "PrintWidth"; "ShowDeclarationValues"; "ShowIEnumerable";
+ "ShowProperties"; "AddPrinter"; "AddPrintTransformer"; "Equals"; "GetHashCode";
+ "GetType"; "ToString"; ])
+
+ // We execute in a seperate appdomain so that we can set BaseDirectory to a non-existent location
+ getWorker().VerifyCompletionListExactly(fileContents, "fsi.", expected)
+
+#if EXE
+ShouldTriggerCompletionInFsxFile()
+#endif
diff --git a/vsintegration/tests/UnitTests/VisualFSharp.UnitTests.fsproj b/vsintegration/tests/UnitTests/VisualFSharp.UnitTests.fsproj
index 6a3cae016a6..9598b23b5c2 100644
--- a/vsintegration/tests/UnitTests/VisualFSharp.UnitTests.fsproj
+++ b/vsintegration/tests/UnitTests/VisualFSharp.UnitTests.fsproj
@@ -148,6 +148,9 @@
Roslyn\CompletionProviderTests.fs
+
+ Roslyn\FsxCompletionProviderTests.fs
+
Roslyn\SignatureHelpProviderTests.fs