Skip to content

Commit 3a7fed2

Browse files
Copilotbergmeister
andauthored
Filter Invoke-ScriptAnalyzer by diagnostic severity
Co-authored-by: bergmeister <9250262+bergmeister@users.noreply.github.com>
1 parent 2fbea9e commit 3a7fed2

3 files changed

Lines changed: 40 additions & 35 deletions

File tree

‎Engine/Commands/InvokeScriptAnalyzerCommand.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ public string[] IncludeRule
146146
private string[] includeRule;
147147

148148
/// <summary>
149-
/// IncludeRule: Array of the severity types to be enabled.
149+
/// Severity levels of the diagnostic records to include.
150150
/// </summary>
151151
[ValidateSet("Warning", "Error", "Information", "ParseError", IgnoreCase = true)]
152152
[Parameter(Mandatory = false)]

‎Engine/ScriptAnalyzer.cs‎

Lines changed: 15 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1485,7 +1485,7 @@ public List<DiagnosticRecord> AnalyzeScriptDefinition(string scriptDefinition, o
14851485
var relevantParseErrors = RemoveTypeNotFoundParseErrors(errors, out List<DiagnosticRecord> diagnosticRecords);
14861486

14871487
// Add parse errors first if requested!
1488-
if ( relevantParseErrors != null && (severity == null || severity.Contains("ParseError", StringComparer.OrdinalIgnoreCase)))
1488+
if ( relevantParseErrors != null )
14891489
{
14901490
var results = new List<DiagnosticRecord>();
14911491
foreach ( ParseError parseError in relevantParseErrors )
@@ -1505,7 +1505,7 @@ public List<DiagnosticRecord> AnalyzeScriptDefinition(string scriptDefinition, o
15051505

15061506
// now, analyze the script definition
15071507
diagnosticRecords.AddRange(this.AnalyzeSyntaxTree(scriptAst, scriptTokens, null, skipVariableAnalysis, emitSuppressionErrors));
1508-
return diagnosticRecords;
1508+
return FilterDiagnosticsBySeverity(diagnosticRecords).ToList();
15091509
}
15101510

15111511
/// <summary>
@@ -1876,7 +1876,7 @@ private IEnumerable<DiagnosticRecord> AnalyzeFile(string filePath)
18761876
// no parsing can really be done, but there are other rules to run (specifically encoding).
18771877
if ( s_aboutHelpRegex.IsMatch(Path.GetFileName(filePath)) )
18781878
{
1879-
return diagnosticRecords.Concat(this.AnalyzeSyntaxTree(scriptAst, scriptTokens, filePath));
1879+
return FilterDiagnosticsBySeverity(diagnosticRecords.Concat(this.AnalyzeSyntaxTree(scriptAst, scriptTokens, filePath)));
18801880
}
18811881

18821882
// Process script
@@ -1899,7 +1899,7 @@ private IEnumerable<DiagnosticRecord> AnalyzeFile(string filePath)
18991899
IEnumerable<ParseError> relevantParseErrors = RemoveTypeNotFoundParseErrors(errors, out diagnosticRecords);
19001900

19011901
// First, add all parse errors if they've been requested
1902-
if ( relevantParseErrors != null && (severity == null || severity.Contains("ParseError", StringComparer.OrdinalIgnoreCase)))
1902+
if ( relevantParseErrors != null )
19031903
{
19041904
List<DiagnosticRecord> results = new List<DiagnosticRecord>();
19051905
foreach ( ParseError parseError in relevantParseErrors )
@@ -1916,7 +1916,7 @@ private IEnumerable<DiagnosticRecord> AnalyzeFile(string filePath)
19161916
diagnosticRecords.AddRange(results);
19171917
}
19181918

1919-
return diagnosticRecords.Concat(this.AnalyzeSyntaxTree(scriptAst, scriptTokens, filePath));
1919+
return FilterDiagnosticsBySeverity(diagnosticRecords.Concat(this.AnalyzeSyntaxTree(scriptAst, scriptTokens, filePath)));
19201920
}
19211921

19221922
private bool IsModuleNotFoundError(ParseError error)
@@ -1925,42 +1925,26 @@ private bool IsModuleNotFoundError(ParseError error)
19251925
&& error.ErrorId.Equals("ModuleNotFoundDuringParse", StringComparison.OrdinalIgnoreCase);
19261926
}
19271927

1928-
private bool IsSeverityAllowed(IEnumerable<uint> allowedSeverities, IRule rule)
1928+
private bool IsDiagnosticSeverityAllowed(DiagnosticRecord diagnostic)
19291929
{
19301930
return severity == null
1931-
|| (allowedSeverities != null
1932-
&& rule != null
1933-
&& HasGetSeverity(rule)
1934-
&& allowedSeverities.Contains((uint)rule.GetSeverity()));
1931+
|| (diagnostic != null
1932+
&& severity.Contains(diagnostic.Severity.ToString(), StringComparer.OrdinalIgnoreCase));
19351933
}
19361934

1937-
private static bool IsRuleEnabled(IRule rule)
1938-
{
1939-
var configurableRule = rule as ConfigurableRule;
1940-
return configurableRule == null || configurableRule.Enable;
1941-
}
1942-
1943-
IEnumerable<uint> GetAllowedSeveritiesInInt()
1944-
{
1945-
return severity != null
1946-
? severity.Select(item => (uint)Enum.Parse(typeof(DiagnosticSeverity), item, true))
1947-
: null;
1948-
}
1949-
1950-
bool HasMethod<T>(T obj, string methodName)
1935+
private IEnumerable<DiagnosticRecord> FilterDiagnosticsBySeverity(IEnumerable<DiagnosticRecord> diagnostics)
19511936
{
1952-
var type = obj.GetType();
1953-
return type.GetMethod(methodName) != null;
1937+
return severity == null ? diagnostics : diagnostics.Where(IsDiagnosticSeverityAllowed);
19541938
}
19551939

1956-
bool HasGetSeverity<T>(T obj)
1940+
private static bool IsRuleEnabled(IRule rule)
19571941
{
1958-
return HasMethod<T>(obj, "GetSeverity");
1942+
var configurableRule = rule as ConfigurableRule;
1943+
return configurableRule == null || configurableRule.Enable;
19591944
}
19601945

19611946
bool IsRuleAllowed(IRule rule)
19621947
{
1963-
IEnumerable<uint> allowedSeverities = GetAllowedSeveritiesInInt();
19641948
bool includeRegexMatch = false;
19651949
bool excludeRegexMatch = false;
19661950
foreach (Regex include in includeRegexList)
@@ -1981,12 +1965,8 @@ bool IsRuleAllowed(IRule rule)
19811965
}
19821966
}
19831967

1984-
bool helpRule = String.Equals(rule.GetName(), "PSUseUTF8EncodingForHelpFile", StringComparison.OrdinalIgnoreCase);
1985-
bool includeSeverity = IsSeverityAllowed(allowedSeverities, rule);
1986-
19871968
return (includeRule == null || includeRegexMatch)
19881969
&& (excludeRule == null || !excludeRegexMatch)
1989-
&& IsSeverityAllowed(allowedSeverities, rule)
19901970
&& IsRuleEnabled(rule);
19911971
}
19921972

@@ -2358,13 +2338,14 @@ public IEnumerable<DiagnosticRecord> AnalyzeSyntaxTree(
23582338
// Need to reverse the concurrentbag to ensure that results are sorted in the increasing order of line numbers
23592339
IEnumerable<DiagnosticRecord> diagnosticsList = diagnostics.Reverse();
23602340

2361-
return _suppressionPreference switch
2341+
IEnumerable<DiagnosticRecord> selectedDiagnostics = _suppressionPreference switch
23622342
{
23632343
SuppressionPreference.SuppressedOnly => suppressed.OfType<DiagnosticRecord>(),
23642344
SuppressionPreference.Omit => diagnosticsList,
23652345
SuppressionPreference.Include => diagnosticsList.Concat(suppressed.OfType<DiagnosticRecord>()),
23662346
_ => throw new ArgumentException($"SuppressionPreference has invalid value '{_suppressionPreference}'"),
23672347
};
2348+
return FilterDiagnosticsBySeverity(selectedDiagnostics);
23682349
}
23692350
}
23702351
}

‎Tests/Engine/CustomizedRule.tests.ps1‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,30 @@ Describe "Test importing correct customized rules" {
157157
$customizedRulePath.Count | Should -Be 0
158158
}
159159

160+
It "filters custom rule diagnostics by diagnostic severity" {
161+
$customRuleContent = @'
162+
function ReportError {
163+
param (
164+
[System.Management.Automation.Language.CommandAst]$ast
165+
)
166+
167+
if ($ast.GetCommandName() -eq 'Invoke-Something') {
168+
New-Object -Typename 'Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord' `
169+
-ArgumentList 'This is an error', $ast.Extent, 'ReportError', Error, $ast.Extent.File, $null, $null
170+
}
171+
}
172+
'@
173+
$customRuleScriptPath = Join-Path $TestDrive 'SeverityRule.psm1'
174+
Set-Content -Path $customRuleScriptPath -Value $customRuleContent
175+
176+
$errors = Invoke-ScriptAnalyzer -ScriptDefinition 'Invoke-Something' -CustomRulePath $customRuleScriptPath -Severity Error
177+
$errors.Count | Should -Be 1
178+
$errors[0].Severity | Should -Be 'Error'
179+
180+
$warnings = Invoke-ScriptAnalyzer -ScriptDefinition 'Invoke-Something' -CustomRulePath $customRuleScriptPath -Severity Warning
181+
$warnings.Count | Should -Be 0
182+
}
183+
160184
It "can suppress custom rule with rule name expression '<RuleNameExpression>'" -TestCases @(
161185
@{RuleNameExpression = '$MyInvocation.MyCommand.Name'; RuleName = 'WarningAboutDoSomething' }
162186
@{RuleNameExpression = '$MyInvocation.InvocationName'; RuleName = 'MyCustomRule\WarningAboutDoSomething' }

0 commit comments

Comments
 (0)