diff --git a/Rules/AvoidAssignmentToAutomaticVariable.cs b/Rules/AvoidAssignmentToAutomaticVariable.cs index 1f2a784dd..c188da341 100644 --- a/Rules/AvoidAssignmentToAutomaticVariable.cs +++ b/Rules/AvoidAssignmentToAutomaticVariable.cs @@ -62,20 +62,20 @@ public IEnumerable AnalyzeScript(Ast ast, string fileName) if (_readOnlyAutomaticVariables.Contains(variableName, StringComparer.OrdinalIgnoreCase)) { yield return new DiagnosticRecord(DiagnosticRecordHelper.FormatError(Strings.AvoidAssignmentToReadOnlyAutomaticVariableError, variableName), - variableExpressionAst.Extent, GetName(), DiagnosticSeverity.Error, fileName); + variableExpressionAst.Extent, GetName(), DiagnosticSeverity.Error, fileName, variableName); } if (_readOnlyAutomaticVariablesIntroducedInVersion6_0.Contains(variableName, StringComparer.OrdinalIgnoreCase)) { var severity = IsPowerShellVersion6OrGreater() ? DiagnosticSeverity.Error : DiagnosticSeverity.Warning; yield return new DiagnosticRecord(DiagnosticRecordHelper.FormatError(Strings.AvoidAssignmentToReadOnlyAutomaticVariableIntroducedInPowerShell6_0Error, variableName), - variableExpressionAst.Extent, GetName(), severity, fileName); + variableExpressionAst.Extent, GetName(), severity, fileName, variableName); } if (_writableAutomaticVariables.Contains(variableName, StringComparer.OrdinalIgnoreCase)) { yield return new DiagnosticRecord(DiagnosticRecordHelper.FormatError(Strings.AvoidAssignmentToWritableAutomaticVariableError, variableName), - variableExpressionAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName); + variableExpressionAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName, variableName); } } @@ -93,20 +93,20 @@ public IEnumerable AnalyzeScript(Ast ast, string fileName) if (_readOnlyAutomaticVariables.Contains(variableName, StringComparer.OrdinalIgnoreCase)) { yield return new DiagnosticRecord(DiagnosticRecordHelper.FormatError(Strings.AvoidAssignmentToReadOnlyAutomaticVariableError, variableName), - variableExpressionAst.Extent, GetName(), DiagnosticSeverity.Error, fileName); + variableExpressionAst.Extent, GetName(), DiagnosticSeverity.Error, fileName, variableName); } if (_readOnlyAutomaticVariablesIntroducedInVersion6_0.Contains(variableName, StringComparer.OrdinalIgnoreCase)) { var severity = IsPowerShellVersion6OrGreater() ? DiagnosticSeverity.Error : DiagnosticSeverity.Warning; yield return new DiagnosticRecord(DiagnosticRecordHelper.FormatError(Strings.AvoidAssignmentToReadOnlyAutomaticVariableIntroducedInPowerShell6_0Error, variableName), - variableExpressionAst.Extent, GetName(), severity, fileName); + variableExpressionAst.Extent, GetName(), severity, fileName, variableName); } if (_writableAutomaticVariables.Contains(variableName, StringComparer.OrdinalIgnoreCase)) { yield return new DiagnosticRecord(DiagnosticRecordHelper.FormatError(Strings.AvoidAssignmentToWritableAutomaticVariableError, variableName), - variableExpressionAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName); + variableExpressionAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName, variableName); } } } diff --git a/Tests/Rules/AvoidAssignmentToAutomaticVariable.tests.ps1 b/Tests/Rules/AvoidAssignmentToAutomaticVariable.tests.ps1 index 50aea15cd..8130990c2 100644 --- a/Tests/Rules/AvoidAssignmentToAutomaticVariable.tests.ps1 +++ b/Tests/Rules/AvoidAssignmentToAutomaticVariable.tests.ps1 @@ -7,60 +7,61 @@ BeforeAll { Describe "AvoidAssignmentToAutomaticVariables" { Context "ReadOnly Variables" { + BeforeDiscovery { + $excpectedSeverityForAutomaticVariablesInPowerShell6 = 'Warning' + if ($PSVersionTable.PSVersion.Major -ge 6) + { + $excpectedSeverityForAutomaticVariablesInPowerShell6 = 'Error' + } - $excpectedSeverityForAutomaticVariablesInPowerShell6 = 'Warning' - if ($PSVersionTable.PSVersion.Major -ge 6) - { - $excpectedSeverityForAutomaticVariablesInPowerShell6 = 'Error' + $testCases_AutomaticVariables = @( + @{ VariableName = '?'; ExpectedSeverity = 'Error'; IsReadOnly = $true } + @{ VariableName = 'Error' ; ExpectedSeverity = 'Error'; IsReadOnly = $true } + @{ VariableName = 'ExecutionContext'; ExpectedSeverity = 'Error'; IsReadOnly = $true } + @{ VariableName = 'false'; ExpectedSeverity = 'Error'; IsReadOnly = $true } + @{ VariableName = 'Home'; ExpectedSeverity = 'Error'; IsReadOnly = $true } + @{ VariableName = 'Host'; ExpectedSeverity = 'Error'; IsReadOnly = $true } + @{ VariableName = 'PID'; ExpectedSeverity = 'Error'; IsReadOnly = $true } + @{ VariableName = 'PSCulture'; ExpectedSeverity = 'Error'; IsReadOnly = $true } + @{ VariableName = 'PSEdition'; ExpectedSeverity = 'Error'; IsReadOnly = $true } + @{ VariableName = 'PSHome'; ExpectedSeverity = 'Error'; IsReadOnly = $true } + @{ VariableName = 'PSUICulture'; ExpectedSeverity = 'Error'; IsReadOnly = $true } + @{ VariableName = 'PSVersionTable'; ExpectedSeverity = 'Error'; IsReadOnly = $true } + @{ VariableName = 'ShellId'; ExpectedSeverity = 'Error'; IsReadOnly = $true } + @{ VariableName = 'true'; ExpectedSeverity = 'Error'; IsReadOnly = $true } + # Variables introduced only in PowerShell 6+ have a Severity of Warning only + @{ VariableName = 'IsCoreCLR'; ExpectedSeverity = $excpectedSeverityForAutomaticVariablesInPowerShell6; OnlyPresentInCoreClr = $true } + @{ VariableName = 'IsLinux'; ExpectedSeverity = $excpectedSeverityForAutomaticVariablesInPowerShell6; OnlyPresentInCoreClr = $true } + @{ VariableName = 'IsMacOS'; ExpectedSeverity = $excpectedSeverityForAutomaticVariablesInPowerShell6; OnlyPresentInCoreClr = $true } + @{ VariableName = 'IsWindows'; ExpectedSeverity = $excpectedSeverityForAutomaticVariablesInPowerShell6; OnlyPresentInCoreClr = $true } + @{ VariableName = '_'; ExpectedSeverity = 'Warning' } + @{ VariableName = 'AllNodes'; ExpectedSeverity = 'Warning' } + @{ VariableName = 'Args'; ExpectedSeverity = 'Warning' } + @{ VariableName = 'ConsoleFilename'; ExpectedSeverity = 'Warning' } + @{ VariableName = 'Event'; ExpectedSeverity = 'Warning' } + @{ VariableName = 'EventArgs'; ExpectedSeverity = 'Warning' } + @{ VariableName = 'EventSubscriber'; ExpectedSeverity = 'Warning' } + @{ VariableName = 'ForEach'; ExpectedSeverity = 'Warning' } + @{ VariableName = 'Input'; ExpectedSeverity = 'Warning' } + @{ VariableName = 'Matches'; ExpectedSeverity = 'Warning' } + @{ VariableName = 'MyInvocation'; ExpectedSeverity = 'Warning' } + @{ VariableName = 'NestedPromptLevel'; ExpectedSeverity = 'Warning' } + @{ VariableName = 'Profile'; ExpectedSeverity = 'Warning' } + @{ VariableName = 'PSBoundParameters'; ExpectedSeverity = 'Warning' } + @{ VariableName = 'PsCmdlet'; ExpectedSeverity = 'Warning' } + @{ VariableName = 'PSCommandPath'; ExpectedSeverity = 'Warning' } + @{ VariableName = 'ReportErrorShowExceptionClass'; ExpectedSeverity = 'Warning' } + @{ VariableName = 'ReportErrorShowInnerException'; ExpectedSeverity = 'Warning' } + @{ VariableName = 'ReportErrorShowSource'; ExpectedSeverity = 'Warning' } + @{ VariableName = 'ReportErrorShowStackTrace'; ExpectedSeverity = 'Warning' } + @{ VariableName = 'Sender'; ExpectedSeverity = 'Warning' } + @{ VariableName = 'StackTrace'; ExpectedSeverity = 'Warning' } + @{ VariableName = 'This'; ExpectedSeverity = 'Warning' } + ) + + $testCases_ReadOnlyAutomaticVariables = $testCases_AutomaticVariables | Where-Object { $_.IsReadonly } } - $testCases_AutomaticVariables = @( - @{ VariableName = '?'; ExpectedSeverity = 'Error'; IsReadOnly = $true } - @{ VariableName = 'Error' ; ExpectedSeverity = 'Error'; IsReadOnly = $true } - @{ VariableName = 'ExecutionContext'; ExpectedSeverity = 'Error'; IsReadOnly = $true } - @{ VariableName = 'false'; ExpectedSeverity = 'Error'; IsReadOnly = $true } - @{ VariableName = 'Home'; ExpectedSeverity = 'Error'; IsReadOnly = $true } - @{ VariableName = 'Host'; ExpectedSeverity = 'Error'; IsReadOnly = $true } - @{ VariableName = 'PID'; ExpectedSeverity = 'Error'; IsReadOnly = $true } - @{ VariableName = 'PSCulture'; ExpectedSeverity = 'Error'; IsReadOnly = $true } - @{ VariableName = 'PSEdition'; ExpectedSeverity = 'Error'; IsReadOnly = $true } - @{ VariableName = 'PSHome'; ExpectedSeverity = 'Error'; IsReadOnly = $true } - @{ VariableName = 'PSUICulture'; ExpectedSeverity = 'Error'; IsReadOnly = $true } - @{ VariableName = 'PSVersionTable'; ExpectedSeverity = 'Error'; IsReadOnly = $true } - @{ VariableName = 'ShellId'; ExpectedSeverity = 'Error'; IsReadOnly = $true } - @{ VariableName = 'true'; ExpectedSeverity = 'Error'; IsReadOnly = $true } - # Variables introduced only in PowerShell 6+ have a Severity of Warning only - @{ VariableName = 'IsCoreCLR'; ExpectedSeverity = $excpectedSeverityForAutomaticVariablesInPowerShell6; OnlyPresentInCoreClr = $true } - @{ VariableName = 'IsLinux'; ExpectedSeverity = $excpectedSeverityForAutomaticVariablesInPowerShell6; OnlyPresentInCoreClr = $true } - @{ VariableName = 'IsMacOS'; ExpectedSeverity = $excpectedSeverityForAutomaticVariablesInPowerShell6; OnlyPresentInCoreClr = $true } - @{ VariableName = 'IsWindows'; ExpectedSeverity = $excpectedSeverityForAutomaticVariablesInPowerShell6; OnlyPresentInCoreClr = $true } - @{ VariableName = '_'; ExpectedSeverity = 'Warning' } - @{ VariableName = 'AllNodes'; ExpectedSeverity = 'Warning' } - @{ VariableName = 'Args'; ExpectedSeverity = 'Warning' } - @{ VariableName = 'ConsoleFilename'; ExpectedSeverity = 'Warning' } - @{ VariableName = 'Event'; ExpectedSeverity = 'Warning' } - @{ VariableName = 'EventArgs'; ExpectedSeverity = 'Warning' } - @{ VariableName = 'EventSubscriber'; ExpectedSeverity = 'Warning' } - @{ VariableName = 'ForEach'; ExpectedSeverity = 'Warning' } - @{ VariableName = 'Input'; ExpectedSeverity = 'Warning' } - @{ VariableName = 'Matches'; ExpectedSeverity = 'Warning' } - @{ VariableName = 'MyInvocation'; ExpectedSeverity = 'Warning' } - @{ VariableName = 'NestedPromptLevel'; ExpectedSeverity = 'Warning' } - @{ VariableName = 'Profile'; ExpectedSeverity = 'Warning' } - @{ VariableName = 'PSBoundParameters'; ExpectedSeverity = 'Warning' } - @{ VariableName = 'PsCmdlet'; ExpectedSeverity = 'Warning' } - @{ VariableName = 'PSCommandPath'; ExpectedSeverity = 'Warning' } - @{ VariableName = 'ReportErrorShowExceptionClass'; ExpectedSeverity = 'Warning' } - @{ VariableName = 'ReportErrorShowInnerException'; ExpectedSeverity = 'Warning' } - @{ VariableName = 'ReportErrorShowSource'; ExpectedSeverity = 'Warning' } - @{ VariableName = 'ReportErrorShowStackTrace'; ExpectedSeverity = 'Warning' } - @{ VariableName = 'Sender'; ExpectedSeverity = 'Warning' } - @{ VariableName = 'StackTrace'; ExpectedSeverity = 'Warning' } - @{ VariableName = 'This'; ExpectedSeverity = 'Warning' } - ) - - $testCases_ReadOnlyAutomaticVariables = $testCases_AutomaticVariables | Where-Object { $_.IsReadonly } - It "Variable produces warning of Severity " -TestCases $testCases_AutomaticVariables { param ($VariableName, $ExpectedSeverity) @@ -133,6 +134,29 @@ Describe "AvoidAssignmentToAutomaticVariables" { } } } + } + + Context 'Suppression' { + BeforeDiscovery { + $testCases_RuleSuppression = @( + @{ VariableName = 'true'; Type = 'ReadOnlyAutomaticVariableError' } + @{ VariableName = 'IsWindows'; Type = 'ReadOnlyAutomaticVariableIntroducedInPowerShell6_0Error' } + @{ VariableName = 'ForEach'; Type = 'WritableAutomaticVariableError' } + ) + } + + It 'Variable of type can be suppressed by RuleSuppressionId' -TestCases $testCases_RuleSuppression { + $scriptDef = @" +function suppressionTest { + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('$ruleName', '$VariableName')] + param( + `$$VariableName + ) +} +"@ + $warnings = @(Invoke-ScriptAnalyzer -ScriptDefinition $scriptDef -ExcludeRule PSReviewUnusedParameter) + $warnings.Count | Should -Be 0 + } } }