From 8909f6781caddf7b1b666be5ee85f38889d284f5 Mon Sep 17 00:00:00 2001 From: Christoph Bergmeister Date: Thu, 21 Feb 2019 21:21:30 +0000 Subject: [PATCH 1/6] Fix rule name lookup mismatch for custom rules to allow for suppresion and unify code --- Engine/Generic/ExternalRule.cs | 8 +++++++- Engine/ScriptAnalyzer.cs | 10 +++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Engine/Generic/ExternalRule.cs b/Engine/Generic/ExternalRule.cs index 57fe11ac4..028e2ca5b 100644 --- a/Engine/Generic/ExternalRule.cs +++ b/Engine/Generic/ExternalRule.cs @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using System.Globalization; + namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic { internal class ExternalRule : IExternalRule @@ -15,9 +17,13 @@ internal class ExternalRule : IExternalRule string modPath = string.Empty; string paramType = string.Empty; + /// + /// Adds module name (source name) to handle ducplicate function names in different modules. + /// + /// public string GetName() { - return this.name; + return string.Format(CultureInfo.CurrentCulture, "{0}\\{1}", this.GetSourceName(), this.name); } public string GetCommonName() diff --git a/Engine/ScriptAnalyzer.cs b/Engine/ScriptAnalyzer.cs index 5b5ccd890..5490f4fca 100644 --- a/Engine/ScriptAnalyzer.cs +++ b/Engine/ScriptAnalyzer.cs @@ -1206,9 +1206,7 @@ internal IEnumerable GetExternalRecord(Ast ast, Token[] token, // Adds command to run external analyzer rule, like // Measure-CurlyBracket -ScriptBlockAst $ScriptBlockAst - // Adds module name (source name) to handle ducplicate function names in different modules. - string ruleName = string.Format("{0}\\{1}", rule.GetSourceName(), rule.GetName()); - posh.Commands.AddCommand(ruleName); + posh.Commands.AddCommand(rule.GetName()); posh.Commands.AddParameter(rule.GetParameter(), token); // Merges results because external analyzer rules may throw exceptions. @@ -1236,9 +1234,7 @@ internal IEnumerable GetExternalRecord(Ast ast, Token[] token, // Adds command to run external analyzer rule, like // Measure-CurlyBracket -ScriptBlockAst $ScriptBlockAst - // Adds module name (source name) to handle ducplicate function names in different modules. - string ruleName = string.Format("{0}\\{1}", rule.GetSourceName(), rule.GetName()); - posh.Commands.AddCommand(ruleName); + posh.Commands.AddCommand(rule.GetName()); posh.Commands.AddParameter(rule.GetParameter(), childAst); // Merges results because external analyzer rules may throw exceptions. @@ -2278,7 +2274,7 @@ public IEnumerable AnalyzeSyntaxTree( { if (IsRuleAllowed(exRule)) { - string ruleName = string.Format(CultureInfo.CurrentCulture, "{0}\\{1}", exRule.GetSourceName(), exRule.GetName()); + string ruleName = exRule.GetName(); this.outputWriter.WriteVerbose(string.Format(CultureInfo.CurrentCulture, Strings.VerboseRunningMessage, ruleName)); // Ensure that any unhandled errors from Rules are converted to non-terminating errors From 6ee671fe2443e943d2d44c069eaa6d3f357e551b Mon Sep 17 00:00:00 2001 From: Christoph Bergmeister Date: Thu, 21 Feb 2019 21:28:59 +0000 Subject: [PATCH 2/6] Remove note that custom rules suppression are not supported --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index dc9f5e617..af5750de1 100644 --- a/README.md +++ b/README.md @@ -307,8 +307,6 @@ Suppress violation in `start-bar`, `start-baz` and `start-bam` but not in `start Param() ``` -**Note**: Rule suppression is currently supported only for built-in rules. - **Note**: Parser Errors cannot be suppressed via the `SuppressMessageAttribute` [Back to ToC](#table-of-contents) From cf469526fa2436bb489b0d311696d6f9c9429c55 Mon Sep 17 00:00:00 2001 From: Christoph Bergmeister Date: Thu, 21 Feb 2019 21:49:17 +0000 Subject: [PATCH 3/6] fix CustomizedRule.tests.ps1 --- Tests/Engine/CustomizedRule.tests.ps1 | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/Tests/Engine/CustomizedRule.tests.ps1 b/Tests/Engine/CustomizedRule.tests.ps1 index 543abc768..0c12b2c7e 100644 --- a/Tests/Engine/CustomizedRule.tests.ps1 +++ b/Tests/Engine/CustomizedRule.tests.ps1 @@ -20,12 +20,13 @@ if (-not (Test-PSEditionCoreCLR)) $message = "this is help" -$measure = "Measure-RequiresRunAsAdministrator" +$ruleFunctionName = "Measure-RequiresRunAsAdministrator" Describe "Test importing customized rules with null return results" { + $ruleName = "SampleRulesWithErrors\$ruleFunctionName" Context "Test Get-ScriptAnalyzer with customized rules" { It "will not terminate the engine" { - $customizedRulePath = Get-ScriptAnalyzerRule -CustomizedRulePath $directory\samplerule\SampleRulesWithErrors.psm1 | Where-Object {$_.RuleName -eq $measure} + $customizedRulePath = Get-ScriptAnalyzerRule -CustomizedRulePath $directory\samplerule\SampleRulesWithErrors.psm1 | Where-Object {$_.RuleName -eq $ruleName} $customizedRulePath.Count | Should -Be 1 } @@ -33,7 +34,7 @@ Describe "Test importing customized rules with null return results" { Context "Test Invoke-ScriptAnalyzer with customized rules" { It "will not terminate the engine" { - $customizedRulePath = Invoke-ScriptAnalyzer $directory\TestScript.ps1 -CustomizedRulePath $directory\samplerule\SampleRulesWithErrors.psm1 | Where-Object {$_.RuleName -eq $measure} + $customizedRulePath = Invoke-ScriptAnalyzer $directory\TestScript.ps1 -CustomizedRulePath $directory\samplerule\SampleRulesWithErrors.psm1 | Where-Object {$_.RuleName -eq $ruleName} $customizedRulePath.Count | Should -Be 0 } } @@ -78,19 +79,20 @@ Describe "Test importing correct customized rules" { } Context "Test Get-ScriptAnalyzer with customized rules" { + $ruleName = "samplerule\$ruleFunctionName" It "will show the custom rule" { - $customizedRulePath = Get-ScriptAnalyzerRule -CustomizedRulePath $directory\samplerule\samplerule.psm1 | Where-Object {$_.RuleName -eq $measure} + $customizedRulePath = Get-ScriptAnalyzerRule -CustomizedRulePath $directory\samplerule\samplerule.psm1 | Where-Object {$_.RuleName -eq $ruleName} $customizedRulePath.Count | Should -Be 1 } It "will show the custom rule when given a rule folder path" { - $customizedRulePath = Get-ScriptAnalyzerRule -CustomizedRulePath $directory\samplerule | Where-Object {$_.RuleName -eq $measure} + $customizedRulePath = Get-ScriptAnalyzerRule -CustomizedRulePath $directory\samplerule | Where-Object {$_.RuleName -eq $ruleName} $customizedRulePath.Count | Should -Be 1 } It "will show the custom rule when given a rule folder path with trailing backslash" -skip:$($IsLinux -or $IsMacOS) { # needs fixing for linux - $customizedRulePath = Get-ScriptAnalyzerRule -CustomizedRulePath $directory/samplerule/ | Where-Object {$_.RuleName -eq $measure} + $customizedRulePath = Get-ScriptAnalyzerRule -CustomizedRulePath $directory/samplerule/ | Where-Object {$_.RuleName -eq $ruleName} $customizedRulePath.Count | Should -Be 1 } @@ -101,12 +103,14 @@ Describe "Test importing correct customized rules" { { $expectedNumRules = 3 } - $customizedRulePath = Get-ScriptAnalyzerRule -CustomizedRulePath $directory\samplerule\samplerule* | Where-Object {$_.RuleName -match $measure} + $customizedRulePath = Get-ScriptAnalyzerRule -CustomizedRulePath $directory\samplerule\samplerule* | + Where-Object {$_.RuleName -match $ruleFunctionName} $customizedRulePath.Count | Should -Be $expectedNumRules } It "will show the custom rules when given recurse switch" { - $customizedRulePath = Get-ScriptAnalyzerRule -RecurseCustomRulePath -CustomizedRulePath "$directory\samplerule", "$directory\samplerule\samplerule2" | Where-Object {$_.RuleName -eq $measure} + $customizedRulePath = Get-ScriptAnalyzerRule -RecurseCustomRulePath -CustomizedRulePath "$directory\samplerule", "$directory\samplerule\samplerule2" | + Where-Object { $_.RuleName.EndsWith($ruleFunctionName) } $customizedRulePath.Count | Should -Be 5 } @@ -117,12 +121,14 @@ Describe "Test importing correct customized rules" { { $expectedNumRules = 4 } - $customizedRulePath = Get-ScriptAnalyzerRule -RecurseCustomRulePath -CustomizedRulePath $directory\samplerule\samplerule* | Where-Object {$_.RuleName -eq $measure} + $customizedRulePath = Get-ScriptAnalyzerRule -RecurseCustomRulePath -CustomizedRulePath $directory\samplerule\samplerule* | + Where-Object { $_.RuleName.EndsWith($ruleFunctionName) } $customizedRulePath.Count | Should -Be $expectedNumRules } It "will show the custom rules when given glob with recurse switch" { - $customizedRulePath = Get-ScriptAnalyzerRule -RecurseCustomRulePath -CustomizedRulePath $directory\samplerule* | Where-Object {$_.RuleName -eq $measure} + $customizedRulePath = Get-ScriptAnalyzerRule -RecurseCustomRulePath -CustomizedRulePath $directory\samplerule* | + Where-Object { $_.RuleName.EndsWith($ruleFunctionName) } $customizedRulePath.Count | Should -Be 3 } } From 9694617e9d67c6e2268366bd9b1547ef881a4b95 Mon Sep 17 00:00:00 2001 From: "Christoph Bergmeister (MVP)" Date: Fri, 22 Feb 2019 23:30:01 +0000 Subject: [PATCH 4/6] do not change GetName method and add GetFullName method instead to avoid breaking existing functionality, therefore also revert the last change in test file --- Engine/Generic/ExternalRule.cs | 9 +++++---- Engine/Generic/IExternalRule.cs | 6 ++++++ Engine/Generic/RuleSuppression.cs | 2 +- Engine/ScriptAnalyzer.cs | 6 +++--- Tests/Engine/CustomizedRule.tests.ps1 | 26 ++++++++++---------------- 5 files changed, 25 insertions(+), 24 deletions(-) diff --git a/Engine/Generic/ExternalRule.cs b/Engine/Generic/ExternalRule.cs index 028e2ca5b..55379c3ba 100644 --- a/Engine/Generic/ExternalRule.cs +++ b/Engine/Generic/ExternalRule.cs @@ -17,11 +17,12 @@ internal class ExternalRule : IExternalRule string modPath = string.Empty; string paramType = string.Empty; - /// - /// Adds module name (source name) to handle ducplicate function names in different modules. - /// - /// public string GetName() + { + return this.name; + } + + public string GetFullName() { return string.Format(CultureInfo.CurrentCulture, "{0}\\{1}", this.GetSourceName(), this.name); } diff --git a/Engine/Generic/IExternalRule.cs b/Engine/Generic/IExternalRule.cs index 08ac40910..ed18ba548 100644 --- a/Engine/Generic/IExternalRule.cs +++ b/Engine/Generic/IExternalRule.cs @@ -8,6 +8,12 @@ namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic /// internal interface IExternalRule : IRule { + /// + /// Adds module name (source name) to handle ducplicate function names in different modules. + /// + /// + string GetFullName(); + /// /// GetParameter: Retrieves AstType parameter /// diff --git a/Engine/Generic/RuleSuppression.cs b/Engine/Generic/RuleSuppression.cs index ac59d43b4..f3bb848ff 100644 --- a/Engine/Generic/RuleSuppression.cs +++ b/Engine/Generic/RuleSuppression.cs @@ -64,7 +64,7 @@ public string RuleName && (ScriptAnalyzer.Instance.TokenRules != null && ScriptAnalyzer.Instance.TokenRules.Count(item => String.Equals(item.GetName(), _ruleName, StringComparison.OrdinalIgnoreCase)) == 0) && (ScriptAnalyzer.Instance.ExternalRules != null - && ScriptAnalyzer.Instance.ExternalRules.Count(item => String.Equals(item.GetName(), _ruleName, StringComparison.OrdinalIgnoreCase)) == 0) + && ScriptAnalyzer.Instance.ExternalRules.Count(item => String.Equals(item.GetFullName(), _ruleName, StringComparison.OrdinalIgnoreCase)) == 0) && (ScriptAnalyzer.Instance.DSCResourceRules != null && ScriptAnalyzer.Instance.DSCResourceRules.Count(item => String.Equals(item.GetName(), _ruleName, StringComparison.OrdinalIgnoreCase)) == 0)) { diff --git a/Engine/ScriptAnalyzer.cs b/Engine/ScriptAnalyzer.cs index 5490f4fca..cc8a411a6 100644 --- a/Engine/ScriptAnalyzer.cs +++ b/Engine/ScriptAnalyzer.cs @@ -1206,7 +1206,7 @@ internal IEnumerable GetExternalRecord(Ast ast, Token[] token, // Adds command to run external analyzer rule, like // Measure-CurlyBracket -ScriptBlockAst $ScriptBlockAst - posh.Commands.AddCommand(rule.GetName()); + posh.Commands.AddCommand(rule.GetFullName()); posh.Commands.AddParameter(rule.GetParameter(), token); // Merges results because external analyzer rules may throw exceptions. @@ -1234,7 +1234,7 @@ internal IEnumerable GetExternalRecord(Ast ast, Token[] token, // Adds command to run external analyzer rule, like // Measure-CurlyBracket -ScriptBlockAst $ScriptBlockAst - posh.Commands.AddCommand(rule.GetName()); + posh.Commands.AddCommand(rule.GetFullName()); posh.Commands.AddParameter(rule.GetParameter(), childAst); // Merges results because external analyzer rules may throw exceptions. @@ -2274,7 +2274,7 @@ public IEnumerable AnalyzeSyntaxTree( { if (IsRuleAllowed(exRule)) { - string ruleName = exRule.GetName(); + string ruleName = exRule.GetFullName(); this.outputWriter.WriteVerbose(string.Format(CultureInfo.CurrentCulture, Strings.VerboseRunningMessage, ruleName)); // Ensure that any unhandled errors from Rules are converted to non-terminating errors diff --git a/Tests/Engine/CustomizedRule.tests.ps1 b/Tests/Engine/CustomizedRule.tests.ps1 index 0c12b2c7e..543abc768 100644 --- a/Tests/Engine/CustomizedRule.tests.ps1 +++ b/Tests/Engine/CustomizedRule.tests.ps1 @@ -20,13 +20,12 @@ if (-not (Test-PSEditionCoreCLR)) $message = "this is help" -$ruleFunctionName = "Measure-RequiresRunAsAdministrator" +$measure = "Measure-RequiresRunAsAdministrator" Describe "Test importing customized rules with null return results" { - $ruleName = "SampleRulesWithErrors\$ruleFunctionName" Context "Test Get-ScriptAnalyzer with customized rules" { It "will not terminate the engine" { - $customizedRulePath = Get-ScriptAnalyzerRule -CustomizedRulePath $directory\samplerule\SampleRulesWithErrors.psm1 | Where-Object {$_.RuleName -eq $ruleName} + $customizedRulePath = Get-ScriptAnalyzerRule -CustomizedRulePath $directory\samplerule\SampleRulesWithErrors.psm1 | Where-Object {$_.RuleName -eq $measure} $customizedRulePath.Count | Should -Be 1 } @@ -34,7 +33,7 @@ Describe "Test importing customized rules with null return results" { Context "Test Invoke-ScriptAnalyzer with customized rules" { It "will not terminate the engine" { - $customizedRulePath = Invoke-ScriptAnalyzer $directory\TestScript.ps1 -CustomizedRulePath $directory\samplerule\SampleRulesWithErrors.psm1 | Where-Object {$_.RuleName -eq $ruleName} + $customizedRulePath = Invoke-ScriptAnalyzer $directory\TestScript.ps1 -CustomizedRulePath $directory\samplerule\SampleRulesWithErrors.psm1 | Where-Object {$_.RuleName -eq $measure} $customizedRulePath.Count | Should -Be 0 } } @@ -79,20 +78,19 @@ Describe "Test importing correct customized rules" { } Context "Test Get-ScriptAnalyzer with customized rules" { - $ruleName = "samplerule\$ruleFunctionName" It "will show the custom rule" { - $customizedRulePath = Get-ScriptAnalyzerRule -CustomizedRulePath $directory\samplerule\samplerule.psm1 | Where-Object {$_.RuleName -eq $ruleName} + $customizedRulePath = Get-ScriptAnalyzerRule -CustomizedRulePath $directory\samplerule\samplerule.psm1 | Where-Object {$_.RuleName -eq $measure} $customizedRulePath.Count | Should -Be 1 } It "will show the custom rule when given a rule folder path" { - $customizedRulePath = Get-ScriptAnalyzerRule -CustomizedRulePath $directory\samplerule | Where-Object {$_.RuleName -eq $ruleName} + $customizedRulePath = Get-ScriptAnalyzerRule -CustomizedRulePath $directory\samplerule | Where-Object {$_.RuleName -eq $measure} $customizedRulePath.Count | Should -Be 1 } It "will show the custom rule when given a rule folder path with trailing backslash" -skip:$($IsLinux -or $IsMacOS) { # needs fixing for linux - $customizedRulePath = Get-ScriptAnalyzerRule -CustomizedRulePath $directory/samplerule/ | Where-Object {$_.RuleName -eq $ruleName} + $customizedRulePath = Get-ScriptAnalyzerRule -CustomizedRulePath $directory/samplerule/ | Where-Object {$_.RuleName -eq $measure} $customizedRulePath.Count | Should -Be 1 } @@ -103,14 +101,12 @@ Describe "Test importing correct customized rules" { { $expectedNumRules = 3 } - $customizedRulePath = Get-ScriptAnalyzerRule -CustomizedRulePath $directory\samplerule\samplerule* | - Where-Object {$_.RuleName -match $ruleFunctionName} + $customizedRulePath = Get-ScriptAnalyzerRule -CustomizedRulePath $directory\samplerule\samplerule* | Where-Object {$_.RuleName -match $measure} $customizedRulePath.Count | Should -Be $expectedNumRules } It "will show the custom rules when given recurse switch" { - $customizedRulePath = Get-ScriptAnalyzerRule -RecurseCustomRulePath -CustomizedRulePath "$directory\samplerule", "$directory\samplerule\samplerule2" | - Where-Object { $_.RuleName.EndsWith($ruleFunctionName) } + $customizedRulePath = Get-ScriptAnalyzerRule -RecurseCustomRulePath -CustomizedRulePath "$directory\samplerule", "$directory\samplerule\samplerule2" | Where-Object {$_.RuleName -eq $measure} $customizedRulePath.Count | Should -Be 5 } @@ -121,14 +117,12 @@ Describe "Test importing correct customized rules" { { $expectedNumRules = 4 } - $customizedRulePath = Get-ScriptAnalyzerRule -RecurseCustomRulePath -CustomizedRulePath $directory\samplerule\samplerule* | - Where-Object { $_.RuleName.EndsWith($ruleFunctionName) } + $customizedRulePath = Get-ScriptAnalyzerRule -RecurseCustomRulePath -CustomizedRulePath $directory\samplerule\samplerule* | Where-Object {$_.RuleName -eq $measure} $customizedRulePath.Count | Should -Be $expectedNumRules } It "will show the custom rules when given glob with recurse switch" { - $customizedRulePath = Get-ScriptAnalyzerRule -RecurseCustomRulePath -CustomizedRulePath $directory\samplerule* | - Where-Object { $_.RuleName.EndsWith($ruleFunctionName) } + $customizedRulePath = Get-ScriptAnalyzerRule -RecurseCustomRulePath -CustomizedRulePath $directory\samplerule* | Where-Object {$_.RuleName -eq $measure} $customizedRulePath.Count | Should -Be 3 } } From caa624d4984f4942faeb89f5014d38b1a61a5a22 Mon Sep 17 00:00:00 2001 From: "Christoph Bergmeister (MVP)" Date: Sun, 24 Feb 2019 13:51:26 +0000 Subject: [PATCH 5/6] Add test and fix dummy test rule to return script extent. TODO: Fix suppressing custom rules when there is no Extent supplied --- Tests/Engine/CustomizedRule.tests.ps1 | 11 +++++++++++ Tests/Engine/samplerule/samplerule.psm1 | 4 ++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Tests/Engine/CustomizedRule.tests.ps1 b/Tests/Engine/CustomizedRule.tests.ps1 index 543abc768..7936de266 100644 --- a/Tests/Engine/CustomizedRule.tests.ps1 +++ b/Tests/Engine/CustomizedRule.tests.ps1 @@ -160,6 +160,17 @@ Describe "Test importing correct customized rules" { $violations[0].SuggestedCorrections.Text | Should -Be 'text' $violations[0].SuggestedCorrections.File | Should -Be 'filePath' $violations[0].SuggestedCorrections.Description | Should -Be 'description' + } + + It "can suppress custom rule" { + $script = "[Diagnostics.CodeAnalysis.SuppressMessageAttribute('samplerule\$measure','')]Param()" + $testScriptPath = "TestDrive:\SuppressedCustomRule.ps1" + Set-Content -Path $testScriptPath -Value $script + + $customizedRulePath = Invoke-ScriptAnalyzer -Path $testScriptPath -CustomizedRulePath $directory\samplerule\samplerule.psm1 | + Where-Object { $_.Message -eq $message } + + $customizedRulePath.Count | Should -Be 0 } if (!$testingLibraryUsage) diff --git a/Tests/Engine/samplerule/samplerule.psm1 b/Tests/Engine/samplerule/samplerule.psm1 index 6cf0ea1fd..a86f5cc90 100644 --- a/Tests/Engine/samplerule/samplerule.psm1 +++ b/Tests/Engine/samplerule/samplerule.psm1 @@ -27,13 +27,13 @@ function Measure-RequiresRunAsAdministrator [ValidateNotNullOrEmpty()] [System.Management.Automation.Language.ScriptBlockAst] $testAst - ) + ) $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,$null,$l + -ArgumentList "This is help",$testAst.Extent,$PSCmdlet.MyInvocation.InvocationName,Warning,$null,$null,$l return $dr } Export-ModuleMember -Function Measure* \ No newline at end of file From c20354116e627f7a33a5fb001983c8150861135d Mon Sep 17 00:00:00 2001 From: "Christoph Bergmeister (MVP)" Date: Sun, 24 Feb 2019 15:26:13 +0000 Subject: [PATCH 6/6] Make test custom rule return null extent again by fixing the Engine to be able to cope with it --- Engine/Helper.cs | 8 ++++++-- Tests/Engine/samplerule/samplerule.psm1 | 5 ++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Engine/Helper.cs b/Engine/Helper.cs index b093d9c0f..35a0a11a1 100644 --- a/Engine/Helper.cs +++ b/Engine/Helper.cs @@ -1419,7 +1419,7 @@ public Tuple, List> SuppressRule( while (startRecord < diagnostics.Count // && diagnostics[startRecord].Extent.StartOffset < ruleSuppression.StartOffset) // && diagnostics[startRecord].Extent.StartLineNumber < ruleSuppression.st) - && offsetArr[startRecord].Item1 < ruleSuppression.StartOffset) + && offsetArr[startRecord] != null && offsetArr[startRecord].Item1 < ruleSuppression.StartOffset) { startRecord += 1; } @@ -1433,7 +1433,7 @@ public Tuple, List> SuppressRule( var curOffset = offsetArr[recordIndex]; //if (record.Extent.EndOffset > ruleSuppression.EndOffset) - if (curOffset.Item2 > ruleSuppression.EndOffset) + if (curOffset != null && curOffset.Item2 > ruleSuppression.EndOffset) { break; } @@ -1489,6 +1489,10 @@ private Tuple[] GetOffsetArray(List diagnostics) for (int k = 0; k < diagnostics.Count; k++) { var ext = diagnostics[k].Extent; + if (ext == null) + { + continue; + } if (ext.StartOffset == 0 && ext.EndOffset == 0) { // check if line and column number correspond to 0 offsets diff --git a/Tests/Engine/samplerule/samplerule.psm1 b/Tests/Engine/samplerule/samplerule.psm1 index a86f5cc90..f740c0ea1 100644 --- a/Tests/Engine/samplerule/samplerule.psm1 +++ b/Tests/Engine/samplerule/samplerule.psm1 @@ -28,12 +28,15 @@ function Measure-RequiresRunAsAdministrator [System.Management.Automation.Language.ScriptBlockAst] $testAst ) + + # The implementation is mocked out for testing purposes only and many properties are deliberately set to null to test if PSSA can cope with it $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) + $extent = $null $dr = New-Object ` -Typename "Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord" ` - -ArgumentList "This is help",$testAst.Extent,$PSCmdlet.MyInvocation.InvocationName,Warning,$null,$null,$l + -ArgumentList "This is help",$extent,$PSCmdlet.MyInvocation.InvocationName,Warning,$null,$null,$l return $dr } Export-ModuleMember -Function Measure* \ No newline at end of file