diff --git a/.gitignore b/.gitignore index 32318eee28..db0688c2ef 100644 --- a/.gitignore +++ b/.gitignore @@ -342,7 +342,6 @@ ASALocalRun/ src/ProjectTemplates/Quantum.App1/Quantum.App1.csproj src/ProjectTemplates/Quantum.Library1/Quantum.Library1.csproj src/ProjectTemplates/Quantum.Test1/Quantum.Test1.csproj -src/QsCompiler/LanguageServer/TemporaryProject.cs src/QuantumSdk/DefaultItems/DefaultItems.props src/ProjectTemplates/Quantum.App1/.template.config/template.json src/ProjectTemplates/Quantum.Library1/.template.config/template.json diff --git a/src/QsCompiler/LanguageServer/EditorState.cs b/src/QsCompiler/LanguageServer/EditorState.cs index 450a5a880d..9de522db4d 100644 --- a/src/QsCompiler/LanguageServer/EditorState.cs +++ b/src/QsCompiler/LanguageServer/EditorState.cs @@ -28,7 +28,6 @@ internal class EditorState : IDisposable private readonly Action publish; private readonly Action, Dictionary> sendTelemetry; - private readonly Action? onTemporaryProjectLoaded; /// /// needed to determine if the reality of a source file that has changed on disk is indeed given by the content on disk, @@ -60,8 +59,7 @@ internal EditorState( Action? publishDiagnostics, Action, Dictionary>? sendTelemetry, Action? log, - Action? onException, - Action? onTemporaryProjectLoaded) + Action? onException) { this.ignoreEditorUpdatesForFiles = new ConcurrentDictionary(); this.sendTelemetry = sendTelemetry ?? ((eventName, properties, measurements) => { }); @@ -86,7 +84,6 @@ internal EditorState( this.projectLoader = projectLoader; this.projects = new ProjectManager(onException, log, this.publish); - this.onTemporaryProjectLoaded = onTemporaryProjectLoaded; } /// @@ -156,30 +153,6 @@ internal bool QsProjectLoader(Uri projectFile, [NotNullWhen(true)] out ProjectIn return true; } - internal Uri QsTemporaryProjectLoader(Uri sourceFileUri, string? sdkVersion) - { - var sourceFolderPath = Path.GetDirectoryName(sourceFileUri.LocalPath) ?? ""; - var projectFileName = string.Join( - "_x2f_", // arbitrary string to help avoid collisions - sourceFolderPath - .Replace("_", "_x5f_") // arbitrary string to help avoid collisions - .Split(Path.GetInvalidFileNameChars())); - var projectFolderPath = Directory.CreateDirectory(Path.Combine( - Path.GetTempPath(), - "qsharp", - projectFileName)).FullName; - var projectFilePath = Path.Combine(projectFolderPath, $"generated.csproj"); - using (var outputFile = new StreamWriter(projectFilePath)) - { - outputFile.WriteLine( - TemporaryProject.GetFileContents( - compilationScope: Path.Combine(sourceFolderPath, "*.qs"), - sdkVersion: sdkVersion)); - } - - return new Uri(projectFilePath); - } - /// /// For each given uri, loads the corresponding project if the uri contains the project file for a Q# project, /// and publishes suitable diagnostics for it. diff --git a/src/QsCompiler/LanguageServer/LanguageServer.cs b/src/QsCompiler/LanguageServer/LanguageServer.cs index fd4d61edd7..419280fa5c 100644 --- a/src/QsCompiler/LanguageServer/LanguageServer.cs +++ b/src/QsCompiler/LanguageServer/LanguageServer.cs @@ -100,8 +100,7 @@ void ProcessFileEvents(IEnumerable e) => diagnostics => this.PublishDiagnosticsAsync(diagnostics), (name, props, meas) => this.SendTelemetryAsync(name, props, meas), this.LogToWindow, - this.OnInternalError, - this.OnTemporaryProjectLoaded); + this.OnInternalError); this.waitForInit.Set(); } @@ -214,9 +213,6 @@ internal void OnInternalError(Exception ex) } } - private void OnTemporaryProjectLoaded(Uri projectUri) => - this.fileWatcher.ListenAsync(Path.GetDirectoryName(projectUri.LocalPath), false, null, "*.csproj").Wait(); - /* jsonrpc methods for initialization and shut down */ private Task InitializeWorkspaceAsync(ImmutableDictionary> folders) diff --git a/src/QsCompiler/LanguageServer/TemporaryProject.cs.v.template b/src/QsCompiler/LanguageServer/TemporaryProject.cs.v.template deleted file mode 100644 index 13d6aad7ec..0000000000 --- a/src/QsCompiler/LanguageServer/TemporaryProject.cs.v.template +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -namespace Microsoft.Quantum.QsLanguageServer -{ - internal static class TemporaryProject - { - internal static string GetFileContents(string compilationScope, string? sdkVersion = null) => $@" - - - netstandard2.1 - - - - - "; - } -} diff --git a/src/QsCompiler/TestProjects/test14/Operation14.qs b/src/QsCompiler/TestProjects/test14/Operation14.qs deleted file mode 100644 index 4b01284140..0000000000 --- a/src/QsCompiler/TestProjects/test14/Operation14.qs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -namespace test14 { - open Microsoft.Quantum.Canon; - open Microsoft.Quantum.Intrinsic; - - operation Operation () : Unit { - } -} diff --git a/src/QsCompiler/Tests.LanguageServer/ProjectLoaderTests.cs b/src/QsCompiler/Tests.LanguageServer/ProjectLoaderTests.cs index 35385e95a6..1dad2b904c 100644 --- a/src/QsCompiler/Tests.LanguageServer/ProjectLoaderTests.cs +++ b/src/QsCompiler/Tests.LanguageServer/ProjectLoaderTests.cs @@ -39,11 +39,13 @@ private static string ProjectFileName(string project) => private static string SourceFileName(string project, string fileName) => Path.Combine("TestProjects", project, fileName); - private (string, ProjectInformation?) Context(string project) + internal static Uri ProjectUri(string project) => + new Uri(Path.GetFullPath(ProjectFileName(project))); + + internal static (Uri, ProjectInformation?) Context(string project) { - var relativePath = ProjectFileName(project); - var uri = new Uri(Path.GetFullPath(relativePath)); - return (uri.LocalPath, CompilationContext.Load(uri)); + var uri = ProjectUri(project); + return (uri, CompilationContext.Load(uri)); } [TestMethod] @@ -74,7 +76,7 @@ public void SupportedTargetFrameworks() [TestMethod] public void FindProjectTargetFramework() { - void CompareFramework(string project, string? expected) + static void CompareFramework(string project, string? expected) { var projectFileName = ProjectFileName(project); var props = new ProjectLoader().DesignTimeBuildProperties(projectFileName, out var _, (x, y) => (y.Contains('.') ? 1 : 0) - (x.Contains('.') ? 1 : 0)); @@ -122,7 +124,7 @@ public void LoadNonQSharpProjects() foreach (var project in invalidProjects) { - var (_, context) = this.Context(project); + var (_, context) = Context(project); Assert.IsNull(context); } } @@ -130,8 +132,8 @@ public void LoadNonQSharpProjects() [TestMethod] public void LoadOutdatedQSharpProject() { - var (projectFile, context) = this.Context("test9"); - var projDir = Path.GetDirectoryName(projectFile) ?? ""; + var (projectFile, context) = Context("test9"); + var projDir = Path.GetDirectoryName(projectFile.LocalPath) ?? ""; Assert.IsNotNull(context); Assert.AreEqual("test9.dll", Path.GetFileName(context!.Properties.OutputPath)); Assert.IsTrue((Path.GetDirectoryName(context.Properties.OutputPath) ?? "").StartsWith(projDir)); @@ -150,8 +152,8 @@ public void LoadOutdatedQSharpProject() [TestMethod] public void LoadQSharpCoreLibraries() { - var (projectFile, context) = this.Context("test3"); - var projDir = Path.GetDirectoryName(projectFile) ?? ""; + var (projectFile, context) = Context("test3"); + var projDir = Path.GetDirectoryName(projectFile.LocalPath) ?? ""; Assert.IsNotNull(context); Assert.AreEqual("test3.dll", Path.GetFileName(context!.Properties.OutputPath)); Assert.IsTrue((Path.GetDirectoryName(context.Properties.OutputPath) ?? "").StartsWith(projDir)); @@ -169,8 +171,8 @@ public void LoadQSharpCoreLibraries() Assert.IsFalse(context.UsesXunitHelper()); CollectionAssert.AreEquivalent(qsFiles, context.SourceFiles.ToArray()); - (projectFile, context) = this.Context("test12"); - projDir = Path.GetDirectoryName(projectFile) ?? ""; + (projectFile, context) = Context("test12"); + projDir = Path.GetDirectoryName(projectFile.LocalPath) ?? ""; Assert.IsNotNull(context); Assert.AreEqual("test12.dll", Path.GetFileName(context!.Properties.OutputPath)); Assert.IsTrue((Path.GetDirectoryName(context.Properties.OutputPath) ?? "").StartsWith(projDir)); @@ -192,8 +194,8 @@ public void LoadQSharpCoreLibraries() [TestMethod] public void LoadQSharpFrameworkLibrary() { - var (projectFile, context) = this.Context("test7"); - var projDir = Path.GetDirectoryName(projectFile) ?? ""; + var (projectFile, context) = Context("test7"); + var projDir = Path.GetDirectoryName(projectFile.LocalPath) ?? ""; Assert.IsNotNull(context); Assert.AreEqual("test7.dll", Path.GetFileName(context!.Properties.OutputPath)); Assert.IsTrue((Path.GetDirectoryName(context.Properties.OutputPath) ?? "").StartsWith(projDir)); @@ -212,8 +214,8 @@ public void LoadQSharpFrameworkLibrary() [TestMethod] public void LoadQSharpConsoleApps() { - var (projectFile, context) = this.Context("test4"); - var projDir = Path.GetDirectoryName(projectFile) ?? ""; + var (projectFile, context) = Context("test4"); + var projDir = Path.GetDirectoryName(projectFile.LocalPath) ?? ""; Assert.IsNotNull(context); Assert.AreEqual("test4.dll", Path.GetFileName(context!.Properties.OutputPath)); Assert.IsTrue((Path.GetDirectoryName(context.Properties.OutputPath) ?? "").StartsWith(projDir)); @@ -229,8 +231,8 @@ public void LoadQSharpConsoleApps() Assert.IsTrue(context.UsesProject("test3.csproj")); CollectionAssert.AreEquivalent(qsFiles, context.SourceFiles.ToArray()); - (projectFile, context) = this.Context("test10"); - projDir = Path.GetDirectoryName(projectFile) ?? ""; + (projectFile, context) = Context("test10"); + projDir = Path.GetDirectoryName(projectFile.LocalPath) ?? ""; Assert.IsNotNull(context); Assert.AreEqual("test10.dll", Path.GetFileName(context!.Properties.OutputPath)); Assert.IsTrue((Path.GetDirectoryName(context.Properties.OutputPath) ?? "").StartsWith(projDir)); @@ -244,8 +246,8 @@ public void LoadQSharpConsoleApps() Assert.IsTrue(context.UsesCanon()); CollectionAssert.AreEquivalent(qsFiles, context.SourceFiles.ToArray()); - (projectFile, context) = this.Context("test11"); - projDir = Path.GetDirectoryName(projectFile) ?? ""; + (projectFile, context) = Context("test11"); + projDir = Path.GetDirectoryName(projectFile.LocalPath) ?? ""; Assert.IsNotNull(context); Assert.AreEqual("test11.dll", Path.GetFileName(context!.Properties.OutputPath)); Assert.IsTrue((Path.GetDirectoryName(context.Properties.OutputPath) ?? "").StartsWith(projDir)); @@ -263,8 +265,8 @@ public void LoadQSharpConsoleApps() [TestMethod] public void LoadQSharpUnitTest() { - var (projectFile, context) = this.Context("test5"); - var projDir = Path.GetDirectoryName(projectFile) ?? ""; + var (projectFile, context) = Context("test5"); + var projDir = Path.GetDirectoryName(projectFile.LocalPath) ?? ""; Assert.IsNotNull(context); Assert.AreEqual("test5.dll", Path.GetFileName(context!.Properties.OutputPath)); Assert.IsTrue((Path.GetDirectoryName(context.Properties.OutputPath) ?? "").StartsWith(projDir)); @@ -287,8 +289,8 @@ public void LoadQSharpUnitTest() [TestMethod] public void LoadQSharpMultiFrameworkLibrary() { - var (projectFile, context) = this.Context("test6"); - var projDir = Path.GetDirectoryName(projectFile) ?? ""; + var (projectFile, context) = Context("test6"); + var projDir = Path.GetDirectoryName(projectFile.LocalPath) ?? ""; Assert.IsNotNull(context); Assert.AreEqual("test6.dll", Path.GetFileName(context!.Properties.OutputPath)); Assert.IsTrue((Path.GetDirectoryName(context.Properties.OutputPath) ?? "").StartsWith(projDir)); @@ -306,20 +308,6 @@ public void LoadQSharpMultiFrameworkLibrary() Assert.IsTrue(context.UsesProject("test3.csproj")); CollectionAssert.AreEquivalent(qsFiles, context.SourceFiles.ToArray()); } - - [TestMethod] - public void LoadQSharpTemporaryProject() - { - var sourceFile = Path.GetFullPath(SourceFileName("test14", "Operation14.qs")); - var projectUri = CompilationContext.CreateTemporaryProject(new Uri(sourceFile), "0.12.20072031"); - Assert.IsNotNull(projectUri); - - var qsFiles = new string[] { sourceFile }; - var projectInformation = CompilationContext.Load(projectUri); - Assert.IsNotNull(projectInformation); - Assert.IsTrue(projectInformation!.UsesCanon()); - CollectionAssert.AreEquivalent(qsFiles, projectInformation!.SourceFiles.ToArray()); - } } internal static class CompilationContext @@ -327,13 +315,11 @@ internal static class CompilationContext private static void LogOutput(string msg, MessageType level) => Console.WriteLine($"[{level}]: {msg}"); - internal static ProjectInformation? Load(Uri projectFile) => - new EditorState(new ProjectLoader(LogOutput), null, null, null, null, null) - .QsProjectLoader(projectFile, out var loaded) ? loaded : null; + internal static EditorState Editor => + new EditorState(new ProjectLoader(LogOutput), null, null, null, null); - internal static Uri CreateTemporaryProject(Uri sourceFile, string sdkVersion) => - new EditorState(new ProjectLoader(LogOutput), null, null, null, null, null) - .QsTemporaryProjectLoader(sourceFile, sdkVersion); + internal static ProjectInformation? Load(Uri projectFile) => + Editor.QsProjectLoader(projectFile, out var loaded) ? loaded : null; internal static bool UsesDll(this ProjectInformation info, string dll) => info.References.Any(r => r.EndsWith(dll)); @@ -342,6 +328,8 @@ internal static Uri CreateTemporaryProject(Uri sourceFile, string sdkVersion) => // NB: We check whether the project uses either the 0.3–0.5 name (Primitives) or the 0.6– name (Intrinsic). internal static bool UsesIntrinsics(this ProjectInformation info) => info.UsesDll("Microsoft.Quantum.Intrinsic.dll") || info.UsesDll("Microsoft.Quantum.Primitives.dll"); + internal static bool UsesQSharpCore(this ProjectInformation info) => info.UsesDll("Microsoft.Quantum.QSharp.Core.dll"); + internal static bool UsesCanon(this ProjectInformation info) => info.UsesDll("Microsoft.Quantum.Canon.dll") || info.UsesDll("Microsoft.Quantum.Standard.dll"); diff --git a/src/QsCompiler/Tests.LanguageServer/Tests.cs b/src/QsCompiler/Tests.LanguageServer/Tests.cs index 5618317220..4083802783 100644 --- a/src/QsCompiler/Tests.LanguageServer/Tests.cs +++ b/src/QsCompiler/Tests.LanguageServer/Tests.cs @@ -274,9 +274,10 @@ async Task RunTest(bool emptyLastLine, bool useQsExtension) } } + await RunTest(emptyLastLine: true, useQsExtension: true); await RunTest(emptyLastLine: true, useQsExtension: false); + await RunTest(emptyLastLine: false, useQsExtension: true); await RunTest(emptyLastLine: false, useQsExtension: false); - await RunTest(emptyLastLine: true, useQsExtension: true); } [TestMethod]