Skip to content

Commit 2f79bcf

Browse files
Add new ParseError level to ScriptFileMarkerLevel and only have it send parse errors (#888)
* Add new PSSA 1.18 ParseError Severity * ignore parseerrors from PSSA * address feedback * back to empty list since we supply parse errors in PSES again * address feedback
1 parent 8730ea4 commit 2f79bcf

File tree

5 files changed

+52
-62
lines changed

5 files changed

+52
-62
lines changed

src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs

+10-8
Original file line numberDiff line numberDiff line change
@@ -1192,7 +1192,7 @@ protected async Task HandleCommentHelpRequestAsync(
11921192
funcText = string.Join("\n", lines);
11931193
}
11941194

1195-
ScriptFileMarker[] analysisResults = await this.editorSession.AnalysisService.GetSemanticMarkersAsync(
1195+
List<ScriptFileMarker> analysisResults = await this.editorSession.AnalysisService.GetSemanticMarkersAsync(
11961196
funcText,
11971197
AnalysisService.GetCommentHelpRuleSettings(
11981198
enable: true,
@@ -1725,7 +1725,7 @@ private static async Task DelayThenInvokeDiagnosticsAsync(
17251725
{
17261726
await PublishScriptDiagnosticsAsync(
17271727
script,
1728-
script.SyntaxMarkers,
1728+
script.DiagnosticMarkers,
17291729
correctionIndex,
17301730
eventSender);
17311731
}
@@ -1743,7 +1743,7 @@ await PublishScriptDiagnosticsAsync(
17431743
// Get the requested files
17441744
foreach (ScriptFile scriptFile in filesToAnalyze)
17451745
{
1746-
ScriptFileMarker[] semanticMarkers = null;
1746+
List<ScriptFileMarker> semanticMarkers = null;
17471747
if (isScriptAnalysisEnabled && editorSession.AnalysisService != null)
17481748
{
17491749
using (Logger.LogExecutionTime($"Script analysis of {scriptFile.FilePath} completed."))
@@ -1755,13 +1755,15 @@ await PublishScriptDiagnosticsAsync(
17551755
{
17561756
// Semantic markers aren't available if the AnalysisService
17571757
// isn't available
1758-
semanticMarkers = new ScriptFileMarker[0];
1758+
semanticMarkers = new List<ScriptFileMarker>();
17591759
}
17601760

1761+
scriptFile.DiagnosticMarkers.AddRange(semanticMarkers);
1762+
17611763
await PublishScriptDiagnosticsAsync(
17621764
scriptFile,
17631765
// Concat script analysis errors to any existing parse errors
1764-
scriptFile.SyntaxMarkers.Concat(semanticMarkers).ToArray(),
1766+
scriptFile.DiagnosticMarkers,
17651767
correctionIndex,
17661768
eventSender);
17671769
}
@@ -1772,14 +1774,14 @@ private async Task ClearMarkersAsync(ScriptFile scriptFile, EventContext eventCo
17721774
// send empty diagnostic markers to clear any markers associated with the given file
17731775
await PublishScriptDiagnosticsAsync(
17741776
scriptFile,
1775-
new ScriptFileMarker[0],
1777+
new List<ScriptFileMarker>(),
17761778
this.codeActionsPerFile,
17771779
eventContext);
17781780
}
17791781

17801782
private static async Task PublishScriptDiagnosticsAsync(
17811783
ScriptFile scriptFile,
1782-
ScriptFileMarker[] markers,
1784+
List<ScriptFileMarker> markers,
17831785
Dictionary<string, Dictionary<string, MarkerCorrection>> correctionIndex,
17841786
EventContext eventContext)
17851787
{
@@ -1792,7 +1794,7 @@ await PublishScriptDiagnosticsAsync(
17921794

17931795
private static async Task PublishScriptDiagnosticsAsync(
17941796
ScriptFile scriptFile,
1795-
ScriptFileMarker[] markers,
1797+
List<ScriptFileMarker> markers,
17961798
Dictionary<string, Dictionary<string, MarkerCorrection>> correctionIndex,
17971799
Func<NotificationType<PublishDiagnosticsNotification, object>, PublishDiagnosticsNotification, Task> eventSender)
17981800
{

src/PowerShellEditorServices/Analysis/AnalysisService.cs

+11-14
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,6 @@ public class AnalysisService : IDisposable
5252
/// </summary>
5353
private static readonly PSObject[] s_emptyDiagnosticResult = new PSObject[0];
5454

55-
/// <summary>
56-
/// An empty script marker result to return when no script markers can be returned.
57-
/// </summary>
58-
private static readonly ScriptFileMarker[] s_emptyScriptMarkerResult = new ScriptFileMarker[0];
59-
6055
private static readonly string[] s_emptyGetRuleResult = new string[0];
6156

6257
/// <summary>
@@ -266,7 +261,7 @@ public static Hashtable GetPSSASettingsHashtable(IDictionary<string, Hashtable>
266261
/// </summary>
267262
/// <param name="file">The ScriptFile which will be analyzed for semantic markers.</param>
268263
/// <returns>An array of ScriptFileMarkers containing semantic analysis results.</returns>
269-
public async Task<ScriptFileMarker[]> GetSemanticMarkersAsync(ScriptFile file)
264+
public async Task<List<ScriptFileMarker>> GetSemanticMarkersAsync(ScriptFile file)
270265
{
271266
return await GetSemanticMarkersAsync<string>(file, ActiveRules, SettingsPath);
272267
}
@@ -277,7 +272,7 @@ public async Task<ScriptFileMarker[]> GetSemanticMarkersAsync(ScriptFile file)
277272
/// <param name="file">The ScriptFile to be analyzed.</param>
278273
/// <param name="settings">ScriptAnalyzer settings</param>
279274
/// <returns></returns>
280-
public async Task<ScriptFileMarker[]> GetSemanticMarkersAsync(ScriptFile file, Hashtable settings)
275+
public async Task<List<ScriptFileMarker>> GetSemanticMarkersAsync(ScriptFile file, Hashtable settings)
281276
{
282277
return await GetSemanticMarkersAsync<Hashtable>(file, null, settings);
283278
}
@@ -288,7 +283,7 @@ public async Task<ScriptFileMarker[]> GetSemanticMarkersAsync(ScriptFile file, H
288283
/// <param name="scriptContent">The script content to be analyzed.</param>
289284
/// <param name="settings">ScriptAnalyzer settings</param>
290285
/// <returns></returns>
291-
public async Task<ScriptFileMarker[]> GetSemanticMarkersAsync(
286+
public async Task<List<ScriptFileMarker>> GetSemanticMarkersAsync(
292287
string scriptContent,
293288
Hashtable settings)
294289
{
@@ -379,7 +374,7 @@ public async Task<string> FormatAsync(
379374

380375
#region Private Methods
381376

382-
private async Task<ScriptFileMarker[]> GetSemanticMarkersAsync<TSettings>(
377+
private async Task<List<ScriptFileMarker>> GetSemanticMarkersAsync<TSettings>(
383378
ScriptFile file,
384379
string[] rules,
385380
TSettings settings) where TSettings : class
@@ -394,11 +389,11 @@ private async Task<ScriptFileMarker[]> GetSemanticMarkersAsync<TSettings>(
394389
else
395390
{
396391
// Return an empty marker list
397-
return s_emptyScriptMarkerResult;
392+
return new List<ScriptFileMarker>();
398393
}
399394
}
400395

401-
private async Task<ScriptFileMarker[]> GetSemanticMarkersAsync<TSettings>(
396+
private async Task<List<ScriptFileMarker>> GetSemanticMarkersAsync<TSettings>(
402397
string scriptContent,
403398
string[] rules,
404399
TSettings settings) where TSettings : class
@@ -407,12 +402,12 @@ private async Task<ScriptFileMarker[]> GetSemanticMarkersAsync<TSettings>(
407402
&& (rules != null || settings != null))
408403
{
409404
var scriptFileMarkers = await GetDiagnosticRecordsAsync(scriptContent, rules, settings);
410-
return scriptFileMarkers.Select(ScriptFileMarker.FromDiagnosticRecord).ToArray();
405+
return scriptFileMarkers.Select(ScriptFileMarker.FromDiagnosticRecord).ToList();
411406
}
412407
else
413408
{
414409
// Return an empty marker list
415-
return s_emptyScriptMarkerResult;
410+
return new List<ScriptFileMarker>();
416411
}
417412
}
418413

@@ -514,7 +509,9 @@ private async Task<PSObject[]> GetDiagnosticRecordsAsync<TSettings>(
514509
new Dictionary<string, object>
515510
{
516511
{ "ScriptDefinition", scriptContent },
517-
{ settingParameter, settingArgument }
512+
{ settingParameter, settingArgument },
513+
// We ignore ParseErrors from PSSA because we already send them when we parse the file.
514+
{ "Severity", new [] { ScriptFileMarkerLevel.Error, ScriptFileMarkerLevel.Information, ScriptFileMarkerLevel.Warning }}
518515
});
519516

520517
diagnosticRecords = result?.Output;

src/PowerShellEditorServices/Workspace/ScriptFile.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ public string Contents
100100
/// Gets the list of syntax markers found by parsing this
101101
/// file's contents.
102102
/// </summary>
103-
public ScriptFileMarker[] SyntaxMarkers
103+
public List<ScriptFileMarker> DiagnosticMarkers
104104
{
105105
get;
106106
private set;
@@ -654,10 +654,10 @@ private void ParseFileContents()
654654
}
655655

656656
// Translate parse errors into syntax markers
657-
this.SyntaxMarkers =
657+
this.DiagnosticMarkers =
658658
parseErrors
659659
.Select(ScriptFileMarker.FromParseError)
660-
.ToArray();
660+
.ToList();
661661

662662
// Untitled files have no directory
663663
// Discussed in https://github.com/PowerShell/PowerShellEditorServices/pull/815.

src/PowerShellEditorServices/Workspace/ScriptFileMarker.cs

+26-35
Original file line numberDiff line numberDiff line change
@@ -33,20 +33,22 @@ public class MarkerCorrection
3333
/// </summary>
3434
public enum ScriptFileMarkerLevel
3535
{
36-
/// <summary>
37-
/// The marker represents an informational message.
38-
/// </summary>
39-
Information = 0,
40-
41-
/// <summary>
42-
/// The marker represents a warning message.
43-
/// </summary>
44-
Warning,
45-
46-
/// <summary>
47-
/// The marker represents an error message.
48-
/// </summary>
49-
Error
36+
/// <summary>
37+
        /// Information: This warning is trivial, but may be useful. They are recommended by PowerShell best practice.
38+
        /// </summary>
39+
        Information = 0,
40+
        /// <summary>
41+
        /// WARNING: This warning may cause a problem or does not follow PowerShell's recommended guidelines.
42+
        /// </summary>
43+
        Warning = 1,
44+
        /// <summary>
45+
        /// ERROR: This warning is likely to cause a problem or does not follow PowerShell's required guidelines.
46+
        /// </summary>
47+
        Error = 2,
48+
        /// <summary>
49+
        /// ERROR: This diagnostic is caused by an actual parsing error, and is generated only by the engine.
50+
        /// </summary>
51+
        ParseError = 3
5052
};
5153

5254
/// <summary>
@@ -62,7 +64,7 @@ public class ScriptFileMarker
6264
/// Gets or sets the marker's message string.
6365
/// </summary>
6466
public string Message { get; set; }
65-
67+
6668
/// <summary>
6769
/// Gets or sets the ruleName associated with this marker.
6870
/// </summary>
@@ -162,36 +164,25 @@ internal static ScriptFileMarker FromDiagnosticRecord(PSObject psObject)
162164
};
163165
}
164166

167+
string severity = diagnosticRecord.Severity.ToString();
168+
if (!Enum.TryParse(severity, out ScriptFileMarkerLevel level))
169+
{
170+
throw new ArgumentException(
171+
$"The provided DiagnosticSeverity value '{severity}' is unknown.",
172+
"diagnosticSeverity");
173+
}
174+
165175
return new ScriptFileMarker
166176
{
167177
Message = $"{diagnosticRecord.Message as string}",
168178
RuleName = $"{diagnosticRecord.RuleName as string}",
169-
Level = GetMarkerLevelFromDiagnosticSeverity((diagnosticRecord.Severity as Enum).ToString()),
179+
Level = level,
170180
ScriptRegion = ScriptRegion.Create(diagnosticRecord.Extent as IScriptExtent),
171181
Correction = correction,
172182
Source = "PSScriptAnalyzer"
173183
};
174184
}
175185

176-
private static ScriptFileMarkerLevel GetMarkerLevelFromDiagnosticSeverity(
177-
string diagnosticSeverity)
178-
{
179-
switch (diagnosticSeverity)
180-
{
181-
case "Information":
182-
return ScriptFileMarkerLevel.Information;
183-
case "Warning":
184-
return ScriptFileMarkerLevel.Warning;
185-
case "Error":
186-
return ScriptFileMarkerLevel.Error;
187-
default:
188-
throw new ArgumentException(
189-
string.Format(
190-
"The provided DiagnosticSeverity value '{0}' is unknown.",
191-
diagnosticSeverity),
192-
"diagnosticSeverity");
193-
}
194-
}
195186
#endregion
196187
}
197188
}

test/PowerShellEditorServices.Test/Session/ScriptFileTests.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -550,7 +550,7 @@ public void PropertiesInitializedCorrectlyForFile()
550550
Assert.True(scriptFile.IsAnalysisEnabled);
551551
Assert.False(scriptFile.IsInMemory);
552552
Assert.Empty(scriptFile.ReferencedFiles);
553-
Assert.Empty(scriptFile.SyntaxMarkers);
553+
Assert.Empty(scriptFile.DiagnosticMarkers);
554554
Assert.Single(scriptFile.ScriptTokens);
555555
Assert.Single(scriptFile.FileLines);
556556
}
@@ -576,7 +576,7 @@ public void PropertiesInitializedCorrectlyForUntitled()
576576
Assert.True(scriptFile.IsAnalysisEnabled);
577577
Assert.True(scriptFile.IsInMemory);
578578
Assert.Empty(scriptFile.ReferencedFiles);
579-
Assert.Empty(scriptFile.SyntaxMarkers);
579+
Assert.Empty(scriptFile.DiagnosticMarkers);
580580
Assert.Equal(10, scriptFile.ScriptTokens.Length);
581581
Assert.Equal(3, scriptFile.FileLines.Count);
582582
}

0 commit comments

Comments
 (0)