diff --git a/appveyor.yml b/appveyor.yml index 654f78f97..bef29824a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,5 +1,5 @@ version: '$(core_version).{build}' -os: Unstable +os: WMF 5 configuration: Release clone_depth: 10 diff --git a/src/PowerShellEditorServices/PowerShellEditorServices.csproj b/src/PowerShellEditorServices/PowerShellEditorServices.csproj index 6fa634a43..e813124e4 100644 --- a/src/PowerShellEditorServices/PowerShellEditorServices.csproj +++ b/src/PowerShellEditorServices/PowerShellEditorServices.csproj @@ -13,9 +13,16 @@ 512 ..\..\ true - PowerShellv3 - PowerShellv4 - PowerShellv5 + $(DefineConstants);PowerShellv3 + $(DefineConstants);PowerShellv4 + + + + + + + $(DefineConstants);PowerShellv5r1;PowerShellv5 + $(DefineConstants);PowerShellv5r2;PowerShellv5 true diff --git a/src/PowerShellEditorServices/Session/EditorSession.cs b/src/PowerShellEditorServices/Session/EditorSession.cs index 463bac882..7ab2f3b59 100644 --- a/src/PowerShellEditorServices/Session/EditorSession.cs +++ b/src/PowerShellEditorServices/Session/EditorSession.cs @@ -60,9 +60,6 @@ public class EditorSession /// public void StartSession() { - // Create a workspace to contain open files - this.Workspace = new Workspace(); - // Initialize all services this.PowerShellContext = new PowerShellContext(); this.LanguageService = new LanguageService(this.PowerShellContext); @@ -81,6 +78,9 @@ public void StartSession() LogLevel.Warning, "Script Analyzer binaries not found, AnalysisService will be disabled."); } + + // Create a workspace to contain open files + this.Workspace = new Workspace(this.PowerShellContext.PowerShellVersion); } #endregion diff --git a/src/PowerShellEditorServices/Workspace/ScriptFile.cs b/src/PowerShellEditorServices/Workspace/ScriptFile.cs index 52d48c1fd..730a7b3f4 100644 --- a/src/PowerShellEditorServices/Workspace/ScriptFile.cs +++ b/src/PowerShellEditorServices/Workspace/ScriptFile.cs @@ -21,6 +21,7 @@ public class ScriptFile #region Private Fields private Token[] scriptTokens; + private Version powerShellVersion; #endregion @@ -126,12 +127,18 @@ public string[] ReferencedFiles /// The path at which the script file resides. /// The path which the client uses to identify the file. /// The TextReader to use for reading the file's contents. - public ScriptFile(string filePath, string clientFilePath, TextReader textReader) + /// The version of PowerShell for which the script is being parsed. + public ScriptFile( + string filePath, + string clientFilePath, + TextReader textReader, + Version powerShellVersion) { this.FilePath = filePath; this.ClientFilePath = clientFilePath; this.IsAnalysisEnabled = true; this.IsInMemory = Workspace.IsPathInMemory(filePath); + this.powerShellVersion = powerShellVersion; this.SetFileContents(textReader.ReadToEnd()); } @@ -142,11 +149,17 @@ public ScriptFile(string filePath, string clientFilePath, TextReader textReader) /// The path at which the script file resides. /// The path which the client uses to identify the file. /// The initial contents of the script file. - public ScriptFile(string filePath, string clientFilePath, string initialBuffer) + /// The version of PowerShell for which the script is being parsed. + public ScriptFile( + string filePath, + string clientFilePath, + string initialBuffer, + Version powerShellVersion) { this.FilePath = filePath; this.ClientFilePath = clientFilePath; this.IsAnalysisEnabled = true; + this.powerShellVersion = powerShellVersion; this.SetFileContents(initialBuffer); } @@ -358,15 +371,39 @@ private void ParseFileContents() try { +#if PowerShellv5r2 + // This overload appeared with Windows 10 Update 1 + if (this.powerShellVersion.Major >= 5 && + this.powerShellVersion.Build >= 10586) + { + // Include the file path so that module relative + // paths are evaluated correctly + this.ScriptAst = + Parser.ParseInput( + this.Contents, + this.FilePath, + out this.scriptTokens, + out parseErrors); + } + else + { + this.ScriptAst = + Parser.ParseInput( + this.Contents, + out this.scriptTokens, + out parseErrors); + } +#else this.ScriptAst = Parser.ParseInput( - this.Contents, - out this.scriptTokens, + this.Contents, + out this.scriptTokens, out parseErrors); +#endif } catch (RuntimeException ex) { - var parseError = + var parseError = new ParseError( null, ex.ErrorRecord.FullyQualifiedErrorId, @@ -388,6 +425,6 @@ private void ParseFileContents() AstOperations.FindDotSourcedIncludes(this.ScriptAst); } - #endregion +#endregion } } diff --git a/src/PowerShellEditorServices/Workspace/Workspace.cs b/src/PowerShellEditorServices/Workspace/Workspace.cs index e59406bb1..7bece0f93 100644 --- a/src/PowerShellEditorServices/Workspace/Workspace.cs +++ b/src/PowerShellEditorServices/Workspace/Workspace.cs @@ -20,6 +20,7 @@ public class Workspace { #region Private Fields + private Version powerShellVersion; private Dictionary workspaceFiles = new Dictionary(); #endregion @@ -33,6 +34,19 @@ public class Workspace #endregion + #region Constructors + + /// + /// Creates a new instance of the Workspace class. + /// + /// The version of PowerShell for which scripts will be parsed. + public Workspace(Version powerShellVersion) + { + this.powerShellVersion = powerShellVersion; + } + + #endregion + #region Public Methods /// @@ -63,7 +77,13 @@ public ScriptFile GetFile(string filePath) using (StreamReader streamReader = new StreamReader(resolvedFilePath, Encoding.UTF8)) { - scriptFile = new ScriptFile(resolvedFilePath, filePath, streamReader); + scriptFile = + new ScriptFile( + resolvedFilePath, + filePath, + streamReader, + this.powerShellVersion); + this.workspaceFiles.Add(keyName, scriptFile); } @@ -92,7 +112,13 @@ public ScriptFile GetFileBuffer(string filePath, string initialBuffer) ScriptFile scriptFile = null; if (!this.workspaceFiles.TryGetValue(keyName, out scriptFile)) { - scriptFile = new ScriptFile(resolvedFilePath, filePath, initialBuffer); + scriptFile = + new ScriptFile( + resolvedFilePath, + filePath, + initialBuffer, + this.powerShellVersion); + this.workspaceFiles.Add(keyName, scriptFile); Logger.Write(LogLevel.Verbose, "Opened file as in-memory buffer: " + resolvedFilePath); diff --git a/test/PowerShellEditorServices.Test.Host/LanguageServerTests.cs b/test/PowerShellEditorServices.Test.Host/LanguageServerTests.cs index 325f03677..a73e32ab5 100644 --- a/test/PowerShellEditorServices.Test.Host/LanguageServerTests.cs +++ b/test/PowerShellEditorServices.Test.Host/LanguageServerTests.cs @@ -81,6 +81,21 @@ await this.WaitForEvent( Assert.Contains("unapproved", diagnostics.Diagnostics[0].Message); } + [Fact] + public async Task ServiceReturnsNoErrorsForUsingRelativeModulePaths() + { + // Send the 'didOpen' event + await this.SendOpenFileEvent("TestFiles\\Module.psm1", false); + + // Wait for the diagnostic event + PublishDiagnosticsNotification diagnostics = + await this.WaitForEvent( + PublishDiagnosticsNotification.Type); + + // Was there a syntax error? + Assert.Equal(0, diagnostics.Diagnostics.Length); + } + [Fact] public async Task ServiceCompletesFunctionName() { diff --git a/test/PowerShellEditorServices.Test.Host/PowerShellEditorServices.Test.Host.csproj b/test/PowerShellEditorServices.Test.Host/PowerShellEditorServices.Test.Host.csproj index 6829c0aa3..a11df7a8a 100644 --- a/test/PowerShellEditorServices.Test.Host/PowerShellEditorServices.Test.Host.csproj +++ b/test/PowerShellEditorServices.Test.Host/PowerShellEditorServices.Test.Host.csproj @@ -74,12 +74,18 @@ + + PreserveNewest + PreserveNewest PreserveNewest + + PreserveNewest + PreserveNewest diff --git a/test/PowerShellEditorServices.Test.Host/TestFiles/ChildModule/ChildModule.psm1 b/test/PowerShellEditorServices.Test.Host/TestFiles/ChildModule/ChildModule.psm1 new file mode 100644 index 000000000..b13e23032 --- /dev/null +++ b/test/PowerShellEditorServices.Test.Host/TestFiles/ChildModule/ChildModule.psm1 @@ -0,0 +1,2 @@ +function Get-Stuff { +} \ No newline at end of file diff --git a/test/PowerShellEditorServices.Test.Host/TestFiles/Module.psm1 b/test/PowerShellEditorServices.Test.Host/TestFiles/Module.psm1 new file mode 100644 index 000000000..5fb8eeb7c --- /dev/null +++ b/test/PowerShellEditorServices.Test.Host/TestFiles/Module.psm1 @@ -0,0 +1 @@ +using module ".\ChildModule" \ No newline at end of file diff --git a/test/PowerShellEditorServices.Test/Debugging/DebugServiceTests.cs b/test/PowerShellEditorServices.Test/Debugging/DebugServiceTests.cs index 1c9f66f5d..e9a220a06 100644 --- a/test/PowerShellEditorServices.Test/Debugging/DebugServiceTests.cs +++ b/test/PowerShellEditorServices.Test/Debugging/DebugServiceTests.cs @@ -30,7 +30,10 @@ public class DebugServiceTests : IDisposable public DebugServiceTests() { - this.workspace = new Workspace(); + this.powerShellContext = new PowerShellContext(); + this.powerShellContext.SessionStateChanged += powerShellContext_SessionStateChanged; + + this.workspace = new Workspace(this.powerShellContext.PowerShellVersion); // Load the test debug file this.debugScriptFile = @@ -41,13 +44,15 @@ public DebugServiceTests() this.workspace.GetFile( @"..\..\..\PowerShellEditorServices.Test.Shared\Debugging\VariableTest.ps1"); - this.powerShellContext = new PowerShellContext(); - this.powerShellContext.SessionStateChanged += powerShellContext_SessionStateChanged; - this.debugService = new DebugService(this.powerShellContext); this.debugService.DebuggerStopped += debugService_DebuggerStopped; this.debugService.BreakpointUpdated += debugService_BreakpointUpdated; this.runnerContext = SynchronizationContext.Current; + + // Load the test debug file + this.debugScriptFile = + this.workspace.GetFile( + @"..\..\..\PowerShellEditorServices.Test.Shared\Debugging\DebugTest.ps1"); } async void powerShellContext_SessionStateChanged(object sender, SessionStateChangedEventArgs e) diff --git a/test/PowerShellEditorServices.Test/Language/LanguageServiceTests.cs b/test/PowerShellEditorServices.Test/Language/LanguageServiceTests.cs index 24fbd7aa8..1d8374581 100644 --- a/test/PowerShellEditorServices.Test/Language/LanguageServiceTests.cs +++ b/test/PowerShellEditorServices.Test/Language/LanguageServiceTests.cs @@ -32,9 +32,8 @@ public class LanguageServiceTests : IDisposable public LanguageServiceTests() { - this.workspace = new Workspace(); - this.powerShellContext = new PowerShellContext(); + this.workspace = new Workspace(this.powerShellContext.PowerShellVersion); this.languageService = new LanguageService(this.powerShellContext); } diff --git a/test/PowerShellEditorServices.Test/Language/PowerShellVersionTests.cs b/test/PowerShellEditorServices.Test/Language/PowerShellVersionTests.cs index ec334f24b..e4d1dd995 100644 --- a/test/PowerShellEditorServices.Test/Language/PowerShellVersionTests.cs +++ b/test/PowerShellEditorServices.Test/Language/PowerShellVersionTests.cs @@ -16,10 +16,10 @@ namespace Microsoft.PowerShell.EditorServices.Test.Language public class PowerShellVersionTests { [Theory] - [InlineData("3")] - [InlineData("4")] - [InlineData("5")] - public void CompilesWithPowerShellVersion(string version) + [InlineData("3", "4")] + [InlineData("4", "4")] + [InlineData("5", "5r1")] + public void CompilesWithPowerShellVersion(string version, string versionSuffix) { var assemblyPath = Path.GetFullPath( @@ -40,7 +40,7 @@ public void CompilesWithPowerShellVersion(string version) try { - Compile(projectVersion, version); + Compile(projectVersion, version, versionSuffix); } finally { @@ -48,7 +48,7 @@ public void CompilesWithPowerShellVersion(string version) } } - private void Compile(string project, string version) + private void Compile(string project, string version, string versionSuffix) { string msbuild; using (var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\MSBuild\ToolsVersions\14.0")) diff --git a/test/PowerShellEditorServices.Test/Session/ScriptFileTests.cs b/test/PowerShellEditorServices.Test/Session/ScriptFileTests.cs index f28280273..2f488cfe1 100644 --- a/test/PowerShellEditorServices.Test/Session/ScriptFileTests.cs +++ b/test/PowerShellEditorServices.Test/Session/ScriptFileTests.cs @@ -4,6 +4,7 @@ // using Microsoft.PowerShell.EditorServices; +using System; using System.IO; using Xunit; @@ -11,6 +12,8 @@ namespace PSLanguageService.Test { public class FileChangeTests { + private static readonly Version PowerShellVersion = new Version("5.0"); + [Fact] public void CanApplySingleLineInsert() { @@ -135,7 +138,13 @@ public void FindsDotSourcedFiles() using (StringReader stringReader = new StringReader(exampleScriptContents)) { - ScriptFile scriptFile = new ScriptFile("DotSourceTestFile.ps1", "DotSourceTestFile.ps1", stringReader); + ScriptFile scriptFile = + new ScriptFile( + "DotSourceTestFile.ps1", + "DotSourceTestFile.ps1", + stringReader, + PowerShellVersion); + Assert.Equal(3, scriptFile.ReferencedFiles.Length); System.Console.Write("a" + scriptFile.ReferencedFiles[0]); Assert.Equal(@".\athing.ps1", scriptFile.ReferencedFiles[0]); @@ -150,7 +159,12 @@ private void AssertFileChange( using (StringReader stringReader = new StringReader(initialString)) { // Create an in-memory file from the StringReader - ScriptFile fileToChange = new ScriptFile("TestFile.ps1", "TestFile.ps1", stringReader); + ScriptFile fileToChange = + new ScriptFile( + "TestFile.ps1", + "TestFile.ps1", + stringReader, + PowerShellVersion); // Apply the FileChange and assert the resulting contents fileToChange.ApplyChange(fileChange);