diff --git a/Rules/AlignAssignmentStatement.cs b/Rules/AlignAssignmentStatement.cs index 37566862e..a17b4afd6 100644 --- a/Rules/AlignAssignmentStatement.cs +++ b/Rules/AlignAssignmentStatement.cs @@ -300,18 +300,28 @@ private static List> GetExtents( foreach (var kvp in hashtableAst.KeyValuePairs) { var keyStartOffset = kvp.Item1.Extent.StartOffset; + bool keyStartOffSetReached = false; var keyTokenNode = tokenOps.GetTokenNodes( - token => token.Extent.StartOffset == keyStartOffset).FirstOrDefault(); - if (keyTokenNode == null - || keyTokenNode.Next == null - || keyTokenNode.Next.Value.Kind != TokenKind.Equals) + token => + { + if (keyStartOffSetReached) + { + return token.Kind == TokenKind.Equals; + } + if (token.Extent.StartOffset == keyStartOffset) + { + keyStartOffSetReached = true; + } + return false; + }).FirstOrDefault(); + if (keyTokenNode == null || keyTokenNode.Value == null) { - return null; + continue; } + var assignmentToken = keyTokenNode.Value.Extent; nodeTuples.Add(new Tuple( - kvp.Item1.Extent, - keyTokenNode.Next.Value.Extent)); + kvp.Item1.Extent, assignmentToken)); } return nodeTuples; diff --git a/Tests/Engine/SettingsTest/Issue828/Issue828.tests.ps1 b/Tests/Engine/SettingsTest/Issue828/Issue828.tests.ps1 new file mode 100644 index 000000000..851256485 --- /dev/null +++ b/Tests/Engine/SettingsTest/Issue828/Issue828.tests.ps1 @@ -0,0 +1,27 @@ +Describe "Issue 828: No NullReferenceExceptionin AlignAssignmentStatement rule when CheckHashtable is enabled" { + It "Should not throw" { + # For details, see here: https://github.com/PowerShell/PSScriptAnalyzer/issues/828 + # The issue states basically that calling 'Invoke-ScriptAnalyzer .' with a certain settings file being in the same location that has CheckHashtable enabled + # combined with a script contatining the command '$MyObj | % { @{$_.Name = $_.Value} }' could make it throw a NullReferencException. + $cmdletThrewError = $false + $initialErrorActionPreference = $ErrorActionPreference + $initialLocation = Get-Location + try + { + Set-Location $PSScriptRoot + $ErrorActionPreference = 'Stop' + Invoke-ScriptAnalyzer . + } + catch + { + $cmdletThrewError = $true + } + finally + { + $ErrorActionPreference = $initialErrorActionPreference + Set-Location $initialLocation + } + + $cmdletThrewError | Should Be $false + } +} \ No newline at end of file diff --git a/Tests/Engine/SettingsTest/Issue828/PSScriptAnalyzerSettings.psd1 b/Tests/Engine/SettingsTest/Issue828/PSScriptAnalyzerSettings.psd1 new file mode 100644 index 000000000..9ac432ef9 --- /dev/null +++ b/Tests/Engine/SettingsTest/Issue828/PSScriptAnalyzerSettings.psd1 @@ -0,0 +1,63 @@ +@{ + Severity = @( + 'Error', + 'Warning', + 'Information' + ) + ExcludeRules = @( + 'PSUseOutputTypeCorrectly', + 'PSUseShouldProcessForStateChangingFunctions' + ) + Rules = @{ + PSAlignAssignmentStatement = @{ + Enable = $true + CheckHashtable = $true + } + PSAvoidUsingCmdletAliases = @{ + # only whitelist verbs from *-Object cmdlets + Whitelist = @( + '%', + '?', + 'compare', + 'foreach', + 'group', + 'measure', + 'select', + 'sort', + 'tee', + 'where' + ) + } + PSPlaceCloseBrace = @{ + Enable = $true + NoEmptyLineBefore = $false + IgnoreOneLineBlock = $true + NewLineAfter = $false + } + PSPlaceOpenBrace = @{ + Enable = $true + OnSameLine = $true + NewLineAfter = $true + IgnoreOneLineBlock = $true + } + PSProvideCommentHelp = @{ + Enable = $true + ExportedOnly = $true + BlockComment = $true + VSCodeSnippetCorrection = $true + Placement = "before" + } + PSUseConsistentIndentation = @{ + Enable = $true + IndentationSize = 4 + Kind = "space" + } + PSUseConsistentWhitespace = @{ + Enable = $true + CheckOpenBrace = $true + CheckOpenParen = $true + CheckOperator = $false + CheckSeparator = $true + } + } +} \ No newline at end of file diff --git a/Tests/Engine/SettingsTest/Issue828/script.ps1 b/Tests/Engine/SettingsTest/Issue828/script.ps1 new file mode 100644 index 000000000..95d3f7edd --- /dev/null +++ b/Tests/Engine/SettingsTest/Issue828/script.ps1 @@ -0,0 +1,2 @@ +# This script has to be like that in order to reproduce the issue +$MyObj | % { @{$_.Name = $_.Value} } \ No newline at end of file