Skip to content

Commit d728a50

Browse files
author
Quoc Truong
committed
Merge pull request #60 from PowerShell/FixVariableAnalysisScope
Fix VariableAnalysis error with outer scope
2 parents e10ff30 + 92abd36 commit d728a50

6 files changed

+57
-9
lines changed

Engine/Helper.cs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -700,7 +700,8 @@ public object VisitScriptBlock(ScriptBlockAst scriptBlockAst)
700700

701701
VariableAnalysis previousOuter = OuterAnalysis;
702702

703-
// We already run variable analysis in these cases so check
703+
// We already run variable analysis if the parent is a function so skip these.
704+
// Otherwise, we have to do variable analysis using the outer scope variables.
704705
if (!(scriptBlockAst.Parent is FunctionDefinitionAst) && !(scriptBlockAst.Parent is FunctionMemberAst))
705706
{
706707
OuterAnalysis = Helper.Instance.InitializeVariableAnalysisHelper(scriptBlockAst, OuterAnalysis);
@@ -726,8 +727,15 @@ public object VisitScriptBlock(ScriptBlockAst scriptBlockAst)
726727
scriptBlockAst.EndBlock.Visit(this);
727728
}
728729

730+
VariableAnalysis innerAnalysis = OuterAnalysis;
729731
OuterAnalysis = previousOuter;
730732

733+
if (!(scriptBlockAst.Parent is FunctionDefinitionAst) && !(scriptBlockAst.Parent is FunctionMemberAst))
734+
{
735+
// Update the variable analysis of the outer script block
736+
VariableAnalysis.UpdateOuterAnalysis(OuterAnalysis, innerAnalysis);
737+
}
738+
731739
return null;
732740
}
733741

@@ -889,6 +897,13 @@ public object VisitCatchClause(CatchClauseAst catchClauseAst)
889897
/// <returns></returns>
890898
public object VisitCommand(CommandAst commandAst)
891899
{
900+
if (commandAst == null) return null;
901+
902+
foreach (CommandElementAst ceAst in commandAst.CommandElements)
903+
{
904+
ceAst.Visit(this);
905+
}
906+
892907
return null;
893908
}
894909

@@ -1219,12 +1234,19 @@ public object VisitParenExpression(ParenExpressionAst parenExpressionAst)
12191234
}
12201235

12211236
/// <summary>
1222-
/// Do nothing
1237+
/// Visit pipeline
12231238
/// </summary>
12241239
/// <param name="pipelineAst"></param>
12251240
/// <returns></returns>
12261241
public object VisitPipeline(PipelineAst pipelineAst)
12271242
{
1243+
if (pipelineAst == null) return null;
1244+
1245+
foreach (var command in pipelineAst.PipelineElements)
1246+
{
1247+
command.Visit(this);
1248+
}
1249+
12281250
return null;
12291251
}
12301252

Engine/VariableAnalysis.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,31 @@ public void AnalyzeImpl(Ast ast, VariableAnalysis outerAnalysis)
255255
}
256256
}
257257

258+
/// <summary>
259+
/// Updates the variablesdictionary of the outeranalysis based on that of the inneranalysis
260+
/// </summary>
261+
/// <param name="OuterAnalysis"></param>
262+
/// <param name="InnerAnalysis"></param>
263+
internal static void UpdateOuterAnalysis(VariableAnalysis OuterAnalysis, VariableAnalysis InnerAnalysis)
264+
{
265+
if (OuterAnalysis == null || InnerAnalysis == null)
266+
{
267+
return;
268+
}
269+
270+
foreach (var key in InnerAnalysis.VariablesDictionary.Keys)
271+
{
272+
if (OuterAnalysis.VariablesDictionary.ContainsKey(key))
273+
{
274+
OuterAnalysis.VariablesDictionary[key] = InnerAnalysis.VariablesDictionary[key];
275+
}
276+
else
277+
{
278+
OuterAnalysis.VariablesDictionary.Add(key, InnerAnalysis.VariablesDictionary[key]);
279+
}
280+
}
281+
}
282+
258283
/// <summary>
259284
/// Return variableanalysisdetails for VarTarget.
260285
/// This function should only be called after Block.SparseSimpleConstants are called.

Engine/VariableAnalysisBase.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2957,10 +2957,6 @@ public object VisitScriptBlockExpression(ScriptBlockExpressionAst scriptBlockExp
29572957
{
29582958
// Don't recurse into the script block, it's variables are distinct from the script block
29592959
// we're currently analyzing.
2960-
if (scriptBlockExpressionAst != null)
2961-
{
2962-
scriptBlockExpressionAst.ScriptBlock.Visit(this.Decorator);
2963-
}
29642960
return null;
29652961
}
29662962

Tests/Rules/AvoidGlobalOrUnitializedVars.ps1

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,7 @@ while ($false) {
1919
$a;
2020

2121
# $d may not be initialized too
22-
$d;
22+
$d;
23+
24+
# error must be raised here
25+
Invoke-Command -ScriptBlock {$a; }

Tests/Rules/AvoidGlobalOrUnitializedVars.tests.ps1

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ Describe "AvoidGlobalVars" {
3131

3232
Describe "AvoidUnitializedVars" {
3333
Context "When there are violations" {
34-
It "has 4 avoid using unitialized variable violations" {
35-
$nonInitializedViolations.Count | Should Be 4
34+
It "has 5 avoid using unitialized variable violations" {
35+
$nonInitializedViolations.Count | Should Be 5
3636
}
3737

3838
It "has the correct description message" {

Tests/Rules/AvoidGlobalOrUnitializedVarsNoViolations.ps1

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ stop-process 12,23 -ErrorVariable ev -ErrorAction SilentlyContinue
2222
if($null -ne $ev)
2323
{
2424
Write-host $ev[0]
25+
# no error should be raised here
26+
Invoke-Command {$b}
2527
}
2628

2729
get-process notepad | tee-object -variable proc

0 commit comments

Comments
 (0)