Skip to content

Commit 26f623a

Browse files
bergmeisterJamesWTruher
authored andcommitted
Fix NullReferenceException in AlignAssignmentStatement rule when CheckHashtable is enabled (#838)
* Fix a nullreference that occured for '$MyObj | % { @{$_.Name = $_.Value} }' when the PSAlignAssignmentStatement setting CheckHashtable was turned on. The reason for it was because the previous implementation expected the key in a hashtable to not contain more than 1 token expression. * fix regression in previous commit to traverse the tokenlist at least until the keyStartOffset and then search for the equal token. Works mainly fine except that I get an off by one error, which leads to a false positive warning when analysing the settings file provided by issue 828. * Add test for fix of issue 828
1 parent a2ab2de commit 26f623a

File tree

4 files changed

+109
-7
lines changed

4 files changed

+109
-7
lines changed

Rules/AlignAssignmentStatement.cs

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -300,18 +300,28 @@ private static List<Tuple<IScriptExtent, IScriptExtent>> GetExtents(
300300
foreach (var kvp in hashtableAst.KeyValuePairs)
301301
{
302302
var keyStartOffset = kvp.Item1.Extent.StartOffset;
303+
bool keyStartOffSetReached = false;
303304
var keyTokenNode = tokenOps.GetTokenNodes(
304-
token => token.Extent.StartOffset == keyStartOffset).FirstOrDefault();
305-
if (keyTokenNode == null
306-
|| keyTokenNode.Next == null
307-
|| keyTokenNode.Next.Value.Kind != TokenKind.Equals)
305+
token =>
306+
{
307+
if (keyStartOffSetReached)
308+
{
309+
return token.Kind == TokenKind.Equals;
310+
}
311+
if (token.Extent.StartOffset == keyStartOffset)
312+
{
313+
keyStartOffSetReached = true;
314+
}
315+
return false;
316+
}).FirstOrDefault();
317+
if (keyTokenNode == null || keyTokenNode.Value == null)
308318
{
309-
return null;
319+
continue;
310320
}
321+
var assignmentToken = keyTokenNode.Value.Extent;
311322

312323
nodeTuples.Add(new Tuple<IScriptExtent, IScriptExtent>(
313-
kvp.Item1.Extent,
314-
keyTokenNode.Next.Value.Extent));
324+
kvp.Item1.Extent, assignmentToken));
315325
}
316326

317327
return nodeTuples;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
Describe "Issue 828: No NullReferenceExceptionin AlignAssignmentStatement rule when CheckHashtable is enabled" {
2+
It "Should not throw" {
3+
# For details, see here: https://github.com/PowerShell/PSScriptAnalyzer/issues/828
4+
# The issue states basically that calling 'Invoke-ScriptAnalyzer .' with a certain settings file being in the same location that has CheckHashtable enabled
5+
# combined with a script contatining the command '$MyObj | % { @{$_.Name = $_.Value} }' could make it throw a NullReferencException.
6+
$cmdletThrewError = $false
7+
$initialErrorActionPreference = $ErrorActionPreference
8+
$initialLocation = Get-Location
9+
try
10+
{
11+
Set-Location $PSScriptRoot
12+
$ErrorActionPreference = 'Stop'
13+
Invoke-ScriptAnalyzer .
14+
}
15+
catch
16+
{
17+
$cmdletThrewError = $true
18+
}
19+
finally
20+
{
21+
$ErrorActionPreference = $initialErrorActionPreference
22+
Set-Location $initialLocation
23+
}
24+
25+
$cmdletThrewError | Should Be $false
26+
}
27+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
@{
2+
Severity = @(
3+
'Error',
4+
'Warning',
5+
'Information'
6+
)
7+
ExcludeRules = @(
8+
'PSUseOutputTypeCorrectly',
9+
'PSUseShouldProcessForStateChangingFunctions'
10+
)
11+
Rules = @{
12+
PSAlignAssignmentStatement = @{
13+
Enable = $true
14+
CheckHashtable = $true
15+
}
16+
PSAvoidUsingCmdletAliases = @{
17+
# only whitelist verbs from *-Object cmdlets
18+
Whitelist = @(
19+
'%',
20+
'?',
21+
'compare',
22+
'foreach',
23+
'group',
24+
'measure',
25+
'select',
26+
'sort',
27+
'tee',
28+
'where'
29+
)
30+
}
31+
PSPlaceCloseBrace = @{
32+
Enable = $true
33+
NoEmptyLineBefore = $false
34+
IgnoreOneLineBlock = $true
35+
NewLineAfter = $false
36+
}
37+
PSPlaceOpenBrace = @{
38+
Enable = $true
39+
OnSameLine = $true
40+
NewLineAfter = $true
41+
IgnoreOneLineBlock = $true
42+
}
43+
PSProvideCommentHelp = @{
44+
Enable = $true
45+
ExportedOnly = $true
46+
BlockComment = $true
47+
VSCodeSnippetCorrection = $true
48+
Placement = "before"
49+
}
50+
PSUseConsistentIndentation = @{
51+
Enable = $true
52+
IndentationSize = 4
53+
Kind = "space"
54+
}
55+
PSUseConsistentWhitespace = @{
56+
Enable = $true
57+
CheckOpenBrace = $true
58+
CheckOpenParen = $true
59+
CheckOperator = $false
60+
CheckSeparator = $true
61+
}
62+
}
63+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# This script has to be like that in order to reproduce the issue
2+
$MyObj | % { @{$_.Name = $_.Value} }

0 commit comments

Comments
 (0)