Skip to content
This repository was archived by the owner on Jan 12, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
29 changes: 1 addition & 28 deletions src/QsCompiler/LanguageServer/EditorState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ internal class EditorState : IDisposable

private readonly Action<PublishDiagnosticParams> publish;
private readonly Action<string, Dictionary<string, string?>, Dictionary<string, int>> sendTelemetry;
private readonly Action<Uri>? onTemporaryProjectLoaded;

/// <summary>
/// needed to determine if the reality of a source file that has changed on disk is indeed given by the content on disk,
Expand Down Expand Up @@ -60,8 +59,7 @@ internal EditorState(
Action<PublishDiagnosticParams>? publishDiagnostics,
Action<string, Dictionary<string, string?>, Dictionary<string, int>>? sendTelemetry,
Action<string, MessageType>? log,
Action<Exception>? onException,
Action<Uri>? onTemporaryProjectLoaded)
Action<Exception>? onException)
{
this.ignoreEditorUpdatesForFiles = new ConcurrentDictionary<Uri, byte>();
this.sendTelemetry = sendTelemetry ?? ((eventName, properties, measurements) => { });
Expand All @@ -86,7 +84,6 @@ internal EditorState(

this.projectLoader = projectLoader;
this.projects = new ProjectManager(onException, log, this.publish);
this.onTemporaryProjectLoaded = onTemporaryProjectLoaded;
}

/// <summary>
Expand Down Expand Up @@ -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);
}

/// <summary>
/// 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.
Expand Down
6 changes: 1 addition & 5 deletions src/QsCompiler/LanguageServer/LanguageServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,7 @@ void ProcessFileEvents(IEnumerable<FileEvent> e) =>
diagnostics => this.PublishDiagnosticsAsync(diagnostics),
(name, props, meas) => this.SendTelemetryAsync(name, props, meas),
this.LogToWindow,
this.OnInternalError,
this.OnTemporaryProjectLoaded);
this.OnInternalError);
this.waitForInit.Set();
}

Expand Down Expand Up @@ -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<Uri, ImmutableHashSet<string>> folders)
Expand Down
18 changes: 0 additions & 18 deletions src/QsCompiler/LanguageServer/TemporaryProject.cs.v.template

This file was deleted.

10 changes: 0 additions & 10 deletions src/QsCompiler/TestProjects/test14/Operation14.qs

This file was deleted.

76 changes: 32 additions & 44 deletions src/QsCompiler/Tests.LanguageServer/ProjectLoaderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -122,16 +124,16 @@ public void LoadNonQSharpProjects()

foreach (var project in invalidProjects)
{
var (_, context) = this.Context(project);
var (_, context) = Context(project);
Assert.IsNull(context);
}
}

[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));
Expand All @@ -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));
Expand All @@ -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));
Expand All @@ -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));
Expand All @@ -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));
Expand All @@ -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));
Expand All @@ -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));
Expand All @@ -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));
Expand All @@ -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));
Expand All @@ -306,34 +308,18 @@ 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
{
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));

Expand All @@ -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");
Expand Down
3 changes: 2 additions & 1 deletion src/QsCompiler/Tests.LanguageServer/Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down