Skip to content

Commit 029a543

Browse files
committed
Add more bits
1 parent e860f57 commit 029a543

File tree

1 file changed

+54
-7
lines changed

1 file changed

+54
-7
lines changed

Rules/UseDeclaredVarsMoreThanAssignments.cs

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -149,15 +149,17 @@ private class Visitor : AstVisitor, IAstPostVisitHandler
149149
private readonly IRule _rule;
150150
private readonly string _scriptPath;
151151
private readonly List<DiagnosticRecord> _diagnostics;
152-
private readonly Stack<KeyValuePair<ScriptBlockAst, Dictionary<string, ExpressionAst>>> _scriptBlockContext;
152+
private readonly Stack<KeyValuePair<ScriptBlockAst, Dictionary<string, Ast>>> _scriptBlockContext;
153+
private readonly Dictionary<string, Ast> _scriptScopeVariables;
153154
private readonly HashSet<ScriptBlockAst> _dotSourcedScriptBlocks;
154155

155156
public Visitor(IRule rule, string scriptPath)
156157
{
157158
_rule = rule;
158159
_scriptPath = scriptPath;
159160
_diagnostics = new List<DiagnosticRecord>();
160-
_scriptBlockContext = new Stack<KeyValuePair<ScriptBlockAst, Dictionary<string, ExpressionAst>>>();
161+
_scriptScopeVariables = new Dictionary<string, Ast>(StringComparer.OrdinalIgnoreCase);
162+
_scriptBlockContext = new Stack<KeyValuePair<ScriptBlockAst, Dictionary<string, Ast>>>();
161163
_dotSourcedScriptBlocks = new HashSet<ScriptBlockAst>();
162164
}
163165

@@ -182,7 +184,7 @@ public void PostVisit(Ast ast)
182184
// looking up the stack only happens at runtime, so it's something we can't analyze
183185
if (_scriptBlockContext.Peek().Key == ast)
184186
{
185-
Dictionary<string, ExpressionAst> unusedVariables = _scriptBlockContext.Pop().Value;
187+
Dictionary<string, Ast> unusedVariables = _scriptBlockContext.Pop().Value;
186188
foreach (ExpressionAst variableDefinition in unusedVariables.Values)
187189
{
188190
if (!TryGetVariableNameFromExpression(variableDefinition, out string variableName))
@@ -209,17 +211,17 @@ public override AstVisitAction VisitScriptBlock(ScriptBlockAst scriptBlockAst)
209211
if (!_dotSourcedScriptBlocks.Remove(scriptBlockAst))
210212
{
211213
_scriptBlockContext.Push(
212-
new KeyValuePair<ScriptBlockAst, Dictionary<string, ExpressionAst>>(
214+
new KeyValuePair<ScriptBlockAst, Dictionary<string, Ast>>(
213215
scriptBlockAst,
214-
new Dictionary<string, ExpressionAst>(StringComparer.OrdinalIgnoreCase)));
216+
new Dictionary<string, Ast>(StringComparer.OrdinalIgnoreCase)));
215217
}
216218

217219
return AstVisitAction.Continue;
218220
}
219221

220222
public override AstVisitAction VisitAssignmentStatement(AssignmentStatementAst assignmentStatementAst)
221223
{
222-
Dictionary<string, ExpressionAst> scopeVariables = _scriptBlockContext.Peek().Value;
224+
Dictionary<string, Ast> scopeVariables = _scriptBlockContext.Peek().Value;
223225

224226
// Want to visit the RHS to check for used variables
225227
// We visit it first since it's evaluated first, so we catch '$x = $x' when $x has never been set
@@ -228,6 +230,7 @@ public override AstVisitAction VisitAssignmentStatement(AssignmentStatementAst a
228230
switch (assignmentStatementAst.Left)
229231
{
230232
case MemberExpressionAst memberExpressionAst:
233+
memberExpressionAst.Visit(this);
231234
break;
232235

233236
case ArrayLiteralAst arrayLhs:
@@ -288,7 +291,7 @@ public override AstVisitAction VisitCommand(CommandAst commandAst)
288291
return AstVisitAction.Continue;
289292
}
290293

291-
Dictionary<string, ExpressionAst> scopeVariables = _scriptBlockContext.Peek().Value;
294+
Dictionary<string, Ast> scopeVariables = _scriptBlockContext.Peek().Value;
292295

293296
// We may encounter a Set-Variable (etc), which we treat as assignment
294297
// The parameters here happen to be common to the variable definition cmdlets
@@ -342,6 +345,38 @@ public IEnumerable<ScriptBlockAst> GetScriptBlockAstsFromCommandElements(
342345
}
343346
}
344347

348+
private void RegisterVariableDeclaration(string variableName, Ast definingAst, VariableScope scope)
349+
{
350+
switch (scope)
351+
{
352+
case VariableScope.Private:
353+
case VariableScope.Local:
354+
case VariableScope.Normal:
355+
_scriptBlockContext.Peek().Value[variableName] = definingAst;
356+
return;
357+
358+
case VariableScope.Script:
359+
_scriptScopeVariables[variableName] = definingAst;
360+
return;
361+
}
362+
}
363+
364+
private void RegisterVariableUse(string variableName, VariableScope scope)
365+
{
366+
switch (scope)
367+
{
368+
case VariableScope.Private:
369+
case VariableScope.Local:
370+
case VariableScope.Normal:
371+
_scriptBlockContext.Peek().Value.Remove(variableName);
372+
return;
373+
374+
case VariableScope.Script:
375+
_scriptScopeVariables.Remove(variableName);
376+
return;
377+
}
378+
}
379+
345380
private static bool TryGetVariableNameFromParameters(
346381
ReadOnlyCollection<CommandElementAst> commandElements,
347382
IReadOnlyDictionary<string, string> switchParameters,
@@ -483,5 +518,17 @@ private static bool IsInParameterDict(IReadOnlyDictionary<string, string> parame
483518
return false;
484519
}
485520
}
521+
522+
private enum VariableScope
523+
{
524+
Unknown = 0,
525+
Normal,
526+
Private,
527+
Local,
528+
Script,
529+
Global,
530+
Env,
531+
Using,
532+
}
486533
}
487534
}

0 commit comments

Comments
 (0)