Skip to content

Commit 956dbea

Browse files
Razmo99JustinGrote
authored andcommitted
added new test cases for functions with variables defined outside of scope and a helper method IsVariableExpressionAssignedInTargetScope
1 parent 28761bf commit 956dbea

File tree

5 files changed

+103
-8
lines changed

5 files changed

+103
-8
lines changed

src/PowerShellEditorServices/Services/PowerShell/Refactoring/IterativeVariableVisitor.cs

+45-8
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ internal class IterativeVariableRename
2525
internal FunctionDefinitionAst TargetFunction;
2626
internal RenameSymbolOptions options;
2727

28-
public IterativeVariableRename(string NewName, int StartLineNumber, int StartColumnNumber, Ast ScriptAst,RenameSymbolOptions options = null)
28+
public IterativeVariableRename(string NewName, int StartLineNumber, int StartColumnNumber, Ast ScriptAst, RenameSymbolOptions options = null)
2929
{
3030
this.NewName = NewName;
3131
this.StartLineNumber = StartLineNumber;
@@ -185,38 +185,75 @@ internal static Ast GetAstParentScope(Ast node)
185185
{
186186
Ast parent = node;
187187
// Walk backwards up the tree looking for a ScriptBLock of a FunctionDefinition
188-
parent = Utilities.GetAstParentOfType(parent, typeof(ScriptBlockAst), typeof(FunctionDefinitionAst), typeof(ForEachStatementAst),typeof(ForStatementAst));
188+
parent = Utilities.GetAstParentOfType(parent, typeof(ScriptBlockAst), typeof(FunctionDefinitionAst), typeof(ForEachStatementAst), typeof(ForStatementAst));
189189
if (parent is ScriptBlockAst && parent.Parent != null && parent.Parent is FunctionDefinitionAst)
190190
{
191191
parent = parent.Parent;
192192
}
193193
// Check if the parent of the VariableExpressionAst is a ForEachStatementAst then check if the variable names match
194194
// if so this is probably a variable defined within a foreach loop
195-
else if(parent is ForEachStatementAst ForEachStmnt && node is VariableExpressionAst VarExp &&
196-
ForEachStmnt.Variable.VariablePath.UserPath == VarExp.VariablePath.UserPath) {
195+
else if (parent is ForEachStatementAst ForEachStmnt && node is VariableExpressionAst VarExp &&
196+
ForEachStmnt.Variable.VariablePath.UserPath == VarExp.VariablePath.UserPath)
197+
{
197198
parent = ForEachStmnt;
198199
}
199200
// Check if the parent of the VariableExpressionAst is a ForStatementAst then check if the variable names match
200201
// if so this is probably a variable defined within a foreach loop
201-
else if(parent is ForStatementAst ForStmnt && node is VariableExpressionAst ForVarExp &&
202+
else if (parent is ForStatementAst ForStmnt && node is VariableExpressionAst ForVarExp &&
202203
ForStmnt.Initializer is AssignmentStatementAst AssignStmnt && AssignStmnt.Left is VariableExpressionAst VarExpStmnt &&
203-
VarExpStmnt.VariablePath.UserPath == ForVarExp.VariablePath.UserPath){
204+
VarExpStmnt.VariablePath.UserPath == ForVarExp.VariablePath.UserPath)
205+
{
204206
parent = ForStmnt;
205207
}
206208

207209
return parent;
208210
}
209211

212+
internal static bool IsVariableExpressionAssignedInTargetScope(VariableExpressionAst node, Ast scope)
213+
{
214+
bool r = false;
215+
216+
List<VariableExpressionAst> VariableAssignments = node.FindAll(ast =>
217+
{
218+
return ast is VariableExpressionAst VarDef &&
219+
VarDef.Parent is AssignmentStatementAst or ParameterAst &&
220+
VarDef.VariablePath.UserPath.ToLower() == node.VariablePath.UserPath.ToLower() &&
221+
// Look Backwards from the node above
222+
(VarDef.Extent.EndLineNumber < node.Extent.StartLineNumber ||
223+
(VarDef.Extent.EndColumnNumber <= node.Extent.StartColumnNumber &&
224+
VarDef.Extent.EndLineNumber <= node.Extent.StartLineNumber)) &&
225+
// Must be within the the designated scope
226+
VarDef.Extent.StartLineNumber >= scope.Extent.StartLineNumber;
227+
}, true).Cast<VariableExpressionAst>().ToList();
228+
229+
if (VariableAssignments.Count > 0)
230+
{
231+
r = true;
232+
}
233+
// Node is probably the first Assignment Statement within scope
234+
if (node.Parent is AssignmentStatementAst && node.Extent.StartLineNumber >= scope.Extent.StartLineNumber)
235+
{
236+
r = true;
237+
}
238+
239+
return r;
240+
}
241+
210242
internal static bool WithinTargetsScope(Ast Target, Ast Child)
211243
{
212244
bool r = false;
213245
Ast childParent = Child.Parent;
214246
Ast TargetScope = GetAstParentScope(Target);
215247
while (childParent != null)
216248
{
217-
if (childParent is FunctionDefinitionAst)
249+
if (childParent is FunctionDefinitionAst FuncDefAst)
218250
{
219-
break;
251+
if (Child is VariableExpressionAst VarExpAst && !IsVariableExpressionAssignedInTargetScope(VarExpAst, FuncDefAst))
252+
{
253+
254+
}else{
255+
break;
256+
}
220257
}
221258
if (childParent == TargetScope)
222259
{

test/PowerShellEditorServices.Test.Shared/Refactoring/Variables/RefactorVariablesData.cs

+14
Original file line numberDiff line numberDiff line change
@@ -177,5 +177,19 @@ internal static class RenameVariableData
177177
Line = 6,
178178
RenameTo = "Renamed"
179179
};
180+
public static readonly RenameSymbolParams VariableDotNotationFromInnerFunction = new()
181+
{
182+
FileName = "VariableDotNotationFromInnerFunction.ps1",
183+
Column = 26,
184+
Line = 11,
185+
RenameTo = "Renamed"
186+
};
187+
public static readonly RenameSymbolParams VariableDotNotationFromOuterVar = new()
188+
{
189+
FileName = "VariableDotNotationFromInnerFunction.ps1",
190+
Column = 1,
191+
Line = 1,
192+
RenameTo = "Renamed"
193+
};
180194
}
181195
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
$NeededTools = @{
2+
OpenSsl = 'openssl for macOS'
3+
PowerShellGet = 'PowerShellGet latest'
4+
InvokeBuild = 'InvokeBuild latest'
5+
}
6+
7+
function getMissingTools () {
8+
$missingTools = @()
9+
10+
if (needsOpenSsl) {
11+
$missingTools += $NeededTools.OpenSsl
12+
}
13+
if (needsPowerShellGet) {
14+
$missingTools += $NeededTools.PowerShellGet
15+
}
16+
if (needsInvokeBuild) {
17+
$missingTools += $NeededTools.InvokeBuild
18+
}
19+
20+
return $missingTools
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
$Renamed = @{
2+
OpenSsl = 'openssl for macOS'
3+
PowerShellGet = 'PowerShellGet latest'
4+
InvokeBuild = 'InvokeBuild latest'
5+
}
6+
7+
function getMissingTools () {
8+
$missingTools = @()
9+
10+
if (needsOpenSsl) {
11+
$missingTools += $Renamed.OpenSsl
12+
}
13+
if (needsPowerShellGet) {
14+
$missingTools += $Renamed.PowerShellGet
15+
}
16+
if (needsInvokeBuild) {
17+
$missingTools += $Renamed.InvokeBuild
18+
}
19+
20+
return $missingTools
21+
}

test/PowerShellEditorServices.Test/Refactoring/RefactorVariableTests.cs

+2
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ public VariableRenameTestData()
7272
Add(new RenameSymbolParamsSerialized(RenameVariableData.VariableInForeachDuplicateAssignment));
7373
Add(new RenameSymbolParamsSerialized(RenameVariableData.VariableInForloopDuplicateAssignment));
7474
Add(new RenameSymbolParamsSerialized(RenameVariableData.VariableNestedScopeFunctionRefactorInner));
75+
Add(new RenameSymbolParamsSerialized(RenameVariableData.VariableDotNotationFromOuterVar));
76+
Add(new RenameSymbolParamsSerialized(RenameVariableData.VariableDotNotationFromInnerFunction));
7577
}
7678
}
7779

0 commit comments

Comments
 (0)