Skip to content

Commit c265f03

Browse files
bergmeisterChristoph Bergmeister
and
Christoph Bergmeister
authored
UseUsingScopeModifierInNewRunspaces: Fix ArgumentException when the same variable name is used in 2 different sessions. (#1493)
* UseUsingScopeModifierInNewRunspaces: Fix ArgumentException when the same variable name is used in 2 different sessions. * use .add method to fix full .net build Co-authored-by: Christoph Bergmeister <[email protected]>
1 parent aa66551 commit c265f03

File tree

2 files changed

+39
-15
lines changed

2 files changed

+39
-15
lines changed

Rules/UseUsingScopeModifierInNewRunspaces.cs

+18-15
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ private class SyntaxCompatibilityVisitor : AstVisitor
116116
private static readonly IEnumerable<string> s_invokeCommandCmdletNamesAndAliases =
117117
Helper.Instance.CmdletNameAndAliases("Invoke-Command");
118118

119-
private readonly Dictionary<string, Dictionary<string, VariableExpressionAst>> _varsDeclaredPerSession;
119+
private readonly Dictionary<string, HashSet<string>> _varsDeclaredPerSession;
120120

121121
private readonly List<DiagnosticRecord> _diagnosticAccumulator;
122122

@@ -127,7 +127,7 @@ private class SyntaxCompatibilityVisitor : AstVisitor
127127
public SyntaxCompatibilityVisitor(UseUsingScopeModifierInNewRunspaces rule, string analyzedScriptPath)
128128
{
129129
_diagnosticAccumulator = new List<DiagnosticRecord>();
130-
_varsDeclaredPerSession = new Dictionary<string, Dictionary<string, VariableExpressionAst>>();
130+
_varsDeclaredPerSession = new Dictionary<string, HashSet<string>>();
131131
_rule = rule;
132132
_analyzedFilePath = analyzedScriptPath;
133133
}
@@ -183,15 +183,15 @@ public override AstVisitAction VisitScriptBlockExpression(ScriptBlockExpressionA
183183
return AstVisitAction.Continue;
184184
}
185185

186-
IReadOnlyDictionary<string, VariableExpressionAst> varsInLocalAssignments = FindVarsInAssignmentAsts(scriptBlockExpressionAst);
186+
HashSet<string> varsInLocalAssignments = FindVarsInAssignmentAsts(scriptBlockExpressionAst);
187187
if (varsInLocalAssignments != null)
188188
{
189189
AddAssignedVarsToSession(sessionName, varsInLocalAssignments);
190190
}
191191

192192
GenerateDiagnosticRecords(
193193
FindNonAssignedNonUsingVarAsts(
194-
scriptBlockExpressionAst,
194+
scriptBlockExpressionAst,
195195
GetAssignedVarsInSession(sessionName)));
196196

197197
return AstVisitAction.SkipChildren;
@@ -205,10 +205,10 @@ public override AstVisitAction VisitScriptBlockExpression(ScriptBlockExpressionA
205205
/// Example: `$foo = "foo"` ==> the VariableExpressionAst for $foo is returned
206206
/// </summary>
207207
/// <param name="ast"></param>
208-
private static IReadOnlyDictionary<string, VariableExpressionAst> FindVarsInAssignmentAsts(Ast ast)
208+
private static HashSet<string> FindVarsInAssignmentAsts(Ast ast)
209209
{
210-
Dictionary<string, VariableExpressionAst> variableDictionary =
211-
new Dictionary<string, VariableExpressionAst>();
210+
HashSet<string> variableDictionary =
211+
new HashSet<string>();
212212

213213
// Find all variables that are assigned within this ast
214214
foreach (AssignmentStatementAst statementAst in ast.FindAll(IsAssignmentStatementAst, true))
@@ -217,11 +217,11 @@ private static IReadOnlyDictionary<string, VariableExpressionAst> FindVarsInAssi
217217
{
218218
string variableName = string.Format(variable.VariablePath.UserPath,
219219
StringComparer.OrdinalIgnoreCase);
220-
variableDictionary.Add(variableName, variable);
220+
variableDictionary.Add(variableName);
221221
}
222222
};
223223

224-
return new ReadOnlyDictionary<string, VariableExpressionAst>(variableDictionary);
224+
return variableDictionary;
225225
}
226226

227227
/// <summary>
@@ -264,14 +264,14 @@ private static bool IsAssignmentStatementAst(Ast ast)
264264
/// <param name="ast"></param>
265265
/// <param name="varsInAssignments"></param>
266266
private static IEnumerable<VariableExpressionAst> FindNonAssignedNonUsingVarAsts(
267-
Ast ast, IReadOnlyDictionary<string, VariableExpressionAst> varsInAssignments)
267+
Ast ast, HashSet<string> varsInAssignments)
268268
{
269269
// Find all variables that are not locally assigned, and don't have $using: scope modifier
270270
foreach (VariableExpressionAst variable in ast.FindAll(IsNonUsingNonSpecialVariableExpressionAst, true))
271271
{
272272
var varName = string.Format(variable.VariablePath.UserPath, StringComparer.OrdinalIgnoreCase);
273273

274-
if (varsInAssignments.ContainsKey(varName))
274+
if (varsInAssignments.Contains(varName))
275275
{
276276
yield break;
277277
}
@@ -368,7 +368,7 @@ private static bool TryGetSessionNameFromInvokeCommand(CommandAst invokeCommandA
368368
/// GetAssignedVarsInSession: Retrieves all previously declared vars for a given session (as in Invoke-Command -Session $session).
369369
/// </summary>
370370
/// <param name="sessionName"></param>
371-
private IReadOnlyDictionary<string,VariableExpressionAst> GetAssignedVarsInSession(string sessionName)
371+
private HashSet<string> GetAssignedVarsInSession(string sessionName)
372372
{
373373
return _varsDeclaredPerSession[sessionName];
374374
}
@@ -378,16 +378,19 @@ private IReadOnlyDictionary<string,VariableExpressionAst> GetAssignedVarsInSessi
378378
/// </summary>
379379
/// <param name="sessionName"></param>
380380
/// <param name="variablesToAdd"></param>
381-
private void AddAssignedVarsToSession(string sessionName, IReadOnlyDictionary<string, VariableExpressionAst> variablesToAdd)
381+
private void AddAssignedVarsToSession(string sessionName, HashSet<string> variablesToAdd)
382382
{
383383
if (!_varsDeclaredPerSession.ContainsKey(sessionName))
384384
{
385-
_varsDeclaredPerSession.Add(sessionName, new Dictionary<string, VariableExpressionAst>());
385+
_varsDeclaredPerSession.Add(sessionName, new HashSet<string>());
386386
}
387387

388388
foreach (var item in variablesToAdd)
389389
{
390-
_varsDeclaredPerSession[sessionName].Add(item.Key, item.Value);
390+
if (!_varsDeclaredPerSession[sessionName].Contains(item))
391+
{
392+
_varsDeclaredPerSession[sessionName].Add(item);
393+
}
391394
}
392395
}
393396

Tests/Rules/UseUsingScopeModifierInNewRunspaces.tests.ps1

+21
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,27 @@ Describe "UseUsingScopeModifierInNewRunspaces" {
274274
}
275275
}'
276276
}
277+
# Issue 1492: https://github.com/PowerShell/PSScriptAnalyzer/issues/1492
278+
@{
279+
Description = 'Does not throw when the same variable name is used in two different sessions'
280+
ScriptBlock = @'
281+
function Get-One{
282+
283+
Invoke-Command -Session $sourceRemoteSession {
284+
$a = $sccmModule
285+
foo $a
286+
}
287+
}
288+
289+
function Get-Two{
290+
291+
Invoke-Command -Session $sourceRemoteSession {
292+
$a = $sccmModule
293+
foo $a
294+
}
295+
}
296+
'@
297+
}
277298
)
278299
}
279300

0 commit comments

Comments
 (0)