From e203de73ed8050bf6402fa9ec2b48b71cd1e40cb Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt Date: Mon, 25 Mar 2019 11:57:30 -0700 Subject: [PATCH] cherry pick #888 Add new ParseError level to ScriptFileMarkerLevel and only have it send parse errors --- .../Server/LanguageServer.cs | 25 +++++--- .../Analysis/AnalysisService.cs | 25 ++++---- .../Workspace/ScriptFile.cs | 6 +- .../Workspace/ScriptFileMarker.cs | 61 ++++++++----------- .../Session/ScriptFileTests.cs | 4 +- 5 files changed, 60 insertions(+), 61 deletions(-) diff --git a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs index 78b19cfe5..7c278eb2c 100644 --- a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs +++ b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs @@ -1215,7 +1215,7 @@ protected async Task HandleCommentHelpRequest( funcText = string.Join("\n", lines); } - ScriptFileMarker[] analysisResults = await this.editorSession.AnalysisService.GetSemanticMarkersAsync( + List analysisResults = await this.editorSession.AnalysisService.GetSemanticMarkersAsync( funcText, AnalysisService.GetCommentHelpRuleSettings( enable: true, @@ -1728,6 +1728,15 @@ private static async Task DelayThenInvokeDiagnostics( catch (TaskCanceledException) { // If the task is cancelled, exit directly + foreach (var script in filesToAnalyze) + { + await PublishScriptDiagnostics( + script, + script.DiagnosticMarkers, + correctionIndex, + eventSender); + } + return; } @@ -1741,7 +1750,7 @@ private static async Task DelayThenInvokeDiagnostics( // Get the requested files foreach (ScriptFile scriptFile in filesToAnalyze) { - ScriptFileMarker[] semanticMarkers = null; + List semanticMarkers = null; if (isScriptAnalysisEnabled && editorSession.AnalysisService != null) { using (Logger.LogExecutionTime($"Script analysis of {scriptFile.FilePath} completed.")) @@ -1753,13 +1762,15 @@ private static async Task DelayThenInvokeDiagnostics( { // Semantic markers aren't available if the AnalysisService // isn't available - semanticMarkers = new ScriptFileMarker[0]; + semanticMarkers = new List(); } + scriptFile.DiagnosticMarkers.AddRange(semanticMarkers); + await PublishScriptDiagnostics( scriptFile, // Concat script analysis errors to any existing parse errors - scriptFile.SyntaxMarkers.Concat(semanticMarkers).ToArray(), + scriptFile.DiagnosticMarkers, correctionIndex, eventSender); } @@ -1770,14 +1781,14 @@ private async Task ClearMarkers(ScriptFile scriptFile, EventContext eventContext // send empty diagnostic markers to clear any markers associated with the given file await PublishScriptDiagnostics( scriptFile, - new ScriptFileMarker[0], + new List(), this.codeActionsPerFile, eventContext); } private static async Task PublishScriptDiagnostics( ScriptFile scriptFile, - ScriptFileMarker[] markers, + List markers, Dictionary> correctionIndex, EventContext eventContext) { @@ -1790,7 +1801,7 @@ await PublishScriptDiagnostics( private static async Task PublishScriptDiagnostics( ScriptFile scriptFile, - ScriptFileMarker[] markers, + List markers, Dictionary> correctionIndex, Func, PublishDiagnosticsNotification, Task> eventSender) { diff --git a/src/PowerShellEditorServices/Analysis/AnalysisService.cs b/src/PowerShellEditorServices/Analysis/AnalysisService.cs index 40b6327e5..e7badac84 100644 --- a/src/PowerShellEditorServices/Analysis/AnalysisService.cs +++ b/src/PowerShellEditorServices/Analysis/AnalysisService.cs @@ -52,11 +52,6 @@ public class AnalysisService : IDisposable /// private static readonly PSObject[] s_emptyDiagnosticResult = new PSObject[0]; - /// - /// An empty script marker result to return when no script markers can be returned. - /// - private static readonly ScriptFileMarker[] s_emptyScriptMarkerResult = new ScriptFileMarker[0]; - private static readonly string[] s_emptyGetRuleResult = new string[0]; /// @@ -266,7 +261,7 @@ public static Hashtable GetPSSASettingsHashtable(IDictionary /// /// The ScriptFile which will be analyzed for semantic markers. /// An array of ScriptFileMarkers containing semantic analysis results. - public async Task GetSemanticMarkersAsync(ScriptFile file) + public async Task> GetSemanticMarkersAsync(ScriptFile file) { return await GetSemanticMarkersAsync(file, ActiveRules, SettingsPath); } @@ -277,7 +272,7 @@ public async Task GetSemanticMarkersAsync(ScriptFile file) /// The ScriptFile to be analyzed. /// ScriptAnalyzer settings /// - public async Task GetSemanticMarkersAsync(ScriptFile file, Hashtable settings) + public async Task> GetSemanticMarkersAsync(ScriptFile file, Hashtable settings) { return await GetSemanticMarkersAsync(file, null, settings); } @@ -288,7 +283,7 @@ public async Task GetSemanticMarkersAsync(ScriptFile file, H /// The script content to be analyzed. /// ScriptAnalyzer settings /// - public async Task GetSemanticMarkersAsync( + public async Task> GetSemanticMarkersAsync( string scriptContent, Hashtable settings) { @@ -379,7 +374,7 @@ public async Task Format( #region Private Methods - private async Task GetSemanticMarkersAsync( + private async Task> GetSemanticMarkersAsync( ScriptFile file, string[] rules, TSettings settings) where TSettings : class @@ -394,11 +389,11 @@ private async Task GetSemanticMarkersAsync( else { // Return an empty marker list - return s_emptyScriptMarkerResult; + return new List(); } } - private async Task GetSemanticMarkersAsync( + private async Task> GetSemanticMarkersAsync( string scriptContent, string[] rules, TSettings settings) where TSettings : class @@ -407,12 +402,12 @@ private async Task GetSemanticMarkersAsync( && (rules != null || settings != null)) { var scriptFileMarkers = await GetDiagnosticRecordsAsync(scriptContent, rules, settings); - return scriptFileMarkers.Select(ScriptFileMarker.FromDiagnosticRecord).ToArray(); + return scriptFileMarkers.Select(ScriptFileMarker.FromDiagnosticRecord).ToList(); } else { // Return an empty marker list - return s_emptyScriptMarkerResult; + return new List(); } } @@ -514,7 +509,9 @@ private async Task GetDiagnosticRecordsAsync( new Dictionary { { "ScriptDefinition", scriptContent }, - { settingParameter, settingArgument } + { settingParameter, settingArgument }, + // We ignore ParseErrors from PSSA because we already send them when we parse the file. + { "Severity", new [] { ScriptFileMarkerLevel.Error, ScriptFileMarkerLevel.Information, ScriptFileMarkerLevel.Warning }} }); diagnosticRecords = result?.Output; diff --git a/src/PowerShellEditorServices/Workspace/ScriptFile.cs b/src/PowerShellEditorServices/Workspace/ScriptFile.cs index 08e9c6a00..2499bef08 100644 --- a/src/PowerShellEditorServices/Workspace/ScriptFile.cs +++ b/src/PowerShellEditorServices/Workspace/ScriptFile.cs @@ -100,7 +100,7 @@ public string Contents /// Gets the list of syntax markers found by parsing this /// file's contents. /// - public ScriptFileMarker[] SyntaxMarkers + public List DiagnosticMarkers { get; private set; @@ -662,10 +662,10 @@ private void ParseFileContents() } // Translate parse errors into syntax markers - this.SyntaxMarkers = + this.DiagnosticMarkers = parseErrors .Select(ScriptFileMarker.FromParseError) - .ToArray(); + .ToList(); // Untitled files have no directory // Discussed in https://github.com/PowerShell/PowerShellEditorServices/pull/815. diff --git a/src/PowerShellEditorServices/Workspace/ScriptFileMarker.cs b/src/PowerShellEditorServices/Workspace/ScriptFileMarker.cs index 3737b7169..9eb73cb6c 100644 --- a/src/PowerShellEditorServices/Workspace/ScriptFileMarker.cs +++ b/src/PowerShellEditorServices/Workspace/ScriptFileMarker.cs @@ -33,20 +33,22 @@ public class MarkerCorrection /// public enum ScriptFileMarkerLevel { - /// - /// The marker represents an informational message. - /// - Information = 0, - - /// - /// The marker represents a warning message. - /// - Warning, - - /// - /// The marker represents an error message. - /// - Error + ///  +        /// Information: This warning is trivial, but may be useful. They are recommended by PowerShell best practice. +        ///  +        Information = 0, +        ///  +        /// WARNING: This warning may cause a problem or does not follow PowerShell's recommended guidelines. +        ///  +        Warning = 1, +        ///  +        /// ERROR: This warning is likely to cause a problem or does not follow PowerShell's required guidelines. +        ///  +        Error = 2, +        ///  +        /// ERROR: This diagnostic is caused by an actual parsing error, and is generated only by the engine. +        ///  +        ParseError = 3 }; /// @@ -62,7 +64,7 @@ public class ScriptFileMarker /// Gets or sets the marker's message string. /// public string Message { get; set; } - + /// /// Gets or sets the ruleName associated with this marker. /// @@ -162,36 +164,25 @@ internal static ScriptFileMarker FromDiagnosticRecord(PSObject psObject) }; } + string severity = diagnosticRecord.Severity.ToString(); + if (!Enum.TryParse(severity, out ScriptFileMarkerLevel level)) + { + throw new ArgumentException( + $"The provided DiagnosticSeverity value '{severity}' is unknown.", + "diagnosticSeverity"); + } + return new ScriptFileMarker { Message = $"{diagnosticRecord.Message as string}", RuleName = $"{diagnosticRecord.RuleName as string}", - Level = GetMarkerLevelFromDiagnosticSeverity((diagnosticRecord.Severity as Enum).ToString()), + Level = level, ScriptRegion = ScriptRegion.Create(diagnosticRecord.Extent as IScriptExtent), Correction = correction, Source = "PSScriptAnalyzer" }; } - private static ScriptFileMarkerLevel GetMarkerLevelFromDiagnosticSeverity( - string diagnosticSeverity) - { - switch (diagnosticSeverity) - { - case "Information": - return ScriptFileMarkerLevel.Information; - case "Warning": - return ScriptFileMarkerLevel.Warning; - case "Error": - return ScriptFileMarkerLevel.Error; - default: - throw new ArgumentException( - string.Format( - "The provided DiagnosticSeverity value '{0}' is unknown.", - diagnosticSeverity), - "diagnosticSeverity"); - } - } #endregion } } diff --git a/test/PowerShellEditorServices.Test/Session/ScriptFileTests.cs b/test/PowerShellEditorServices.Test/Session/ScriptFileTests.cs index f9555c40a..31543b1d5 100644 --- a/test/PowerShellEditorServices.Test/Session/ScriptFileTests.cs +++ b/test/PowerShellEditorServices.Test/Session/ScriptFileTests.cs @@ -548,7 +548,7 @@ public void PropertiesInitializedCorrectlyForFile() Assert.True(scriptFile.IsAnalysisEnabled); Assert.False(scriptFile.IsInMemory); Assert.Empty(scriptFile.ReferencedFiles); - Assert.Empty(scriptFile.SyntaxMarkers); + Assert.Empty(scriptFile.DiagnosticMarkers); Assert.Single(scriptFile.ScriptTokens); Assert.Single(scriptFile.FileLines); } @@ -574,7 +574,7 @@ public void PropertiesInitializedCorrectlyForUntitled() Assert.True(scriptFile.IsAnalysisEnabled); Assert.True(scriptFile.IsInMemory); Assert.Empty(scriptFile.ReferencedFiles); - Assert.Empty(scriptFile.SyntaxMarkers); + Assert.Empty(scriptFile.DiagnosticMarkers); Assert.Equal(10, scriptFile.ScriptTokens.Length); Assert.Equal(3, scriptFile.FileLines.Count); }