diff --git a/Engine/Generic/DiagnosticRecord.cs b/Engine/Generic/DiagnosticRecord.cs index ca3c3c882..28d0e87bd 100644 --- a/Engine/Generic/DiagnosticRecord.cs +++ b/Engine/Generic/DiagnosticRecord.cs @@ -18,7 +18,7 @@ public class DiagnosticRecord private DiagnosticSeverity severity; private string scriptPath; private string ruleSuppressionId; - private List suggestedCorrections; + private IEnumerable suggestedCorrections; /// /// Represents a string from the rule about why this diagnostic was created. @@ -89,6 +89,7 @@ public string RuleSuppressionID public IEnumerable SuggestedCorrections { get { return suggestedCorrections; } + set { suggestedCorrections = value; } } /// @@ -108,7 +109,7 @@ public DiagnosticRecord() /// The severity of this diagnostic /// The full path of the script file being analyzed /// The correction suggested by the rule to replace the extent text - public DiagnosticRecord(string message, IScriptExtent extent, string ruleName, DiagnosticSeverity severity, string scriptPath, string ruleId = null, List suggestedCorrections = null) + public DiagnosticRecord(string message, IScriptExtent extent, string ruleName, DiagnosticSeverity severity, string scriptPath, string ruleId = null, IEnumerable suggestedCorrections = null) { Message = message; RuleName = ruleName; diff --git a/Engine/ScriptAnalyzer.cs b/Engine/ScriptAnalyzer.cs index 1c6a64fff..ae6e22255 100644 --- a/Engine/ScriptAnalyzer.cs +++ b/Engine/ScriptAnalyzer.cs @@ -1267,6 +1267,7 @@ internal IEnumerable GetExternalRecord(Ast ast, Token[] token, IScriptExtent extent; string message = string.Empty; string ruleName = string.Empty; + IEnumerable suggestedCorrections; if (psobject != null && psobject.ImmediateBaseObject != null) { @@ -1286,6 +1287,7 @@ internal IEnumerable GetExternalRecord(Ast ast, Token[] token, message = psobject.Properties["Message"].Value.ToString(); extent = (IScriptExtent)psobject.Properties["Extent"].Value; ruleName = psobject.Properties["RuleName"].Value.ToString(); + suggestedCorrections = (IEnumerable)psobject.Properties["SuggestedCorrections"].Value; } catch (Exception ex) { @@ -1295,7 +1297,7 @@ internal IEnumerable GetExternalRecord(Ast ast, Token[] token, if (!string.IsNullOrEmpty(message)) { - diagnostics.Add(new DiagnosticRecord(message, extent, ruleName, severity, filePath)); + diagnostics.Add(new DiagnosticRecord(message, extent, ruleName, severity, filePath) { SuggestedCorrections = suggestedCorrections }); } } } diff --git a/ScriptRuleDocumentation.md b/ScriptRuleDocumentation.md index dca9151e8..45e558ef7 100644 --- a/ScriptRuleDocumentation.md +++ b/ScriptRuleDocumentation.md @@ -51,7 +51,7 @@ Param ) ``` -- DiagnosticRecord should have four properties: Message, Extent, RuleName and Severity +- DiagnosticRecord should have at least four properties: Message, Extent, RuleName and Severity ``` PowerShell $result = [Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord[]]@{ @@ -61,6 +61,27 @@ $result = [Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord[ "Severity" = "Warning" } ``` +Optionally, since version 1.17.0, a `SuggestedCorrections` property of type `IEnumerable` can also be added in script rules but care must be taken that the type is correct, an example is: +```powershell +[int]$startLineNumber = $ast.Extent.StartLineNumber +[int]$endLineNumber = $ast.Extent.EndLineNumber +[int]$startColumnNumber = $ast.Extent.StartColumnNumber +[int]$endColumnNumber = $ast.Extent.EndColumnNumber +[string]$correction = 'Correct text that replaces Extent text' +[string]$file = $MyInvocation.MyCommand.Definition +[string]$optionalDescription = 'Useful but optional description text' +$correctionExtent = New-Object 'Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.CorrectionExtent' $startLineNumber,$endLineNumber,$startColumnNumber,$endColumnNumber,$correction,$description +$suggestedCorrections = New-Object System.Collections.ObjectModel.Collection['Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.CorrectionExtent'] +$suggestedCorrections.add($correctionExtent) | out-null + +[Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord]@{ + "Message" = "This is a rule with a suggested correction" + "Extent" = $ast.Extent + "RuleName" = $PSCmdlet.MyInvocation.InvocationName + "Severity" = "Warning" + "SuggestedCorrections" = $suggestedCorrections +} +``` - Make sure you export the function(s) at the end of the script using Export-ModuleMember diff --git a/Tests/Engine/CustomizedRule.tests.ps1 b/Tests/Engine/CustomizedRule.tests.ps1 index 3ad6225ad..2062f995a 100644 --- a/Tests/Engine/CustomizedRule.tests.ps1 +++ b/Tests/Engine/CustomizedRule.tests.ps1 @@ -149,6 +149,19 @@ Describe "Test importing correct customized rules" { $violations[0].ScriptPath | Should -Be $expectedScriptPath } + It "will set SuggestedCorrections" { + $violations = Invoke-ScriptAnalyzer $directory\TestScript.ps1 -CustomizedRulePath $directory\samplerule + $expectedScriptPath = Join-Path $directory 'TestScript.ps1' + $violations[0].SuggestedCorrections | Should -Not -BeNullOrEmpty + $violations[0].SuggestedCorrections.StartLineNumber | Should -Be 1 + $violations[0].SuggestedCorrections.EndLineNumber | Should -Be 2 + $violations[0].SuggestedCorrections.StartColumnNumber | Should -Be 3 + $violations[0].SuggestedCorrections.EndColumnNumber | Should -Be 4 + $violations[0].SuggestedCorrections.Text | Should -Be 'text' + $violations[0].SuggestedCorrections.File | Should -Be 'filePath' + $violations[0].SuggestedCorrections.Description | Should -Be 'description' + } + if (!$testingLibraryUsage) { It "will show the custom rule in the results when given a rule folder path with trailing backslash" { diff --git a/Tests/Engine/samplerule/samplerule.psm1 b/Tests/Engine/samplerule/samplerule.psm1 index d3cc6516d..6cf0ea1fd 100644 --- a/Tests/Engine/samplerule/samplerule.psm1 +++ b/Tests/Engine/samplerule/samplerule.psm1 @@ -28,9 +28,12 @@ function Measure-RequiresRunAsAdministrator [System.Management.Automation.Language.ScriptBlockAst] $testAst ) - $dr = New-Object ` + $l=(new-object System.Collections.ObjectModel.Collection["Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.CorrectionExtent"]) + $c = (new-object Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.CorrectionExtent 1,2,3,4,'text','filePath','description') + $l.Add($c) + $dr = New-Object ` -Typename "Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord" ` - -ArgumentList "This is help",$ast.Extent,$PSCmdlet.MyInvocation.InvocationName,Warning,$null - return @($dr) + -ArgumentList "This is help",$ast.Extent,$PSCmdlet.MyInvocation.InvocationName,Warning,$null,$null,$l + return $dr } Export-ModuleMember -Function Measure* \ No newline at end of file