Skip to content

Commit 531ae40

Browse files
committed
Fixed all function Prepare tests
1 parent 67d8798 commit 531ae40

File tree

3 files changed

+65
-43
lines changed

3 files changed

+65
-43
lines changed

src/PowerShellEditorServices/Services/TextDocument/Services/RenameService.cs

Lines changed: 44 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -71,14 +71,13 @@ ILanguageServerConfiguration config
7171

7272
ScriptPositionAdapter position = request.Position;
7373
Ast? target = FindRenamableSymbol(scriptFile, position);
74-
if (target is null) { return null; }
7574

76-
// Will implicitly convert to RangeOrPlaceholder and adjust to 0-based
77-
return target switch
78-
{
79-
FunctionDefinitionAst funcAst => GetFunctionNameExtent(funcAst),
80-
_ => new ScriptExtentAdapter(target.Extent)
81-
};
75+
// Since 3.16 we can simply basically return a DefaultBehavior true or null to signal to the client that the position is valid for rename and it should use its default selection criteria (which is probably the language semantic highlighting or grammar). For the current scope of the rename provider, this should be fine, but we have the option to supply the specific range in the future for special cases.
76+
RangeOrPlaceholderRange? renamable = target is null ? null : new RangeOrPlaceholderRange
77+
(
78+
new RenameDefaultBehavior() { DefaultBehavior = true }
79+
);
80+
return renamable;
8281
}
8382

8483
public async Task<WorkspaceEdit?> RenameSymbol(RenameParams request, CancellationToken cancellationToken)
@@ -176,25 +175,36 @@ internal static TextEdit[] RenameVariable(Ast symbol, Ast scriptAst, RenameParam
176175
{
177176
if (stringAst.Parent is not CommandAst parent) { return null; }
178177
if (parent.GetCommandName() != stringAst.Value) { return null; }
178+
if (parent.CommandElements[0] != stringAst) { return null; }
179+
// TODO: Potentially find if function was defined earlier in the file to avoid native executable renames and whatnot?
180+
}
181+
182+
// Only the function name is valid for rename, not other components
183+
if (ast is FunctionDefinitionAst funcDefAst)
184+
{
185+
if (!GetFunctionNameExtent(funcDefAst).Contains(position))
186+
{
187+
return null;
188+
}
179189
}
180190

181191
return ast;
182192
}
183193

184194

195+
/// <summary>
196+
/// Return an extent that only contains the position of the name of the function, for Client highlighting purposes.
197+
/// </summary>
185198
private static ScriptExtentAdapter GetFunctionNameExtent(FunctionDefinitionAst ast)
186199
{
187200
string name = ast.Name;
188201
// FIXME: Gather dynamically from the AST and include backticks and whatnot that might be present
189202
int funcLength = "function ".Length;
190203
ScriptExtentAdapter funcExtent = new(ast.Extent);
204+
funcExtent.Start = funcExtent.Start.Delta(0, funcLength);
205+
funcExtent.End = funcExtent.Start.Delta(0, name.Length);
191206

192-
// Get a range that represents only the function name
193-
return funcExtent with
194-
{
195-
Start = funcExtent.Start.Delta(0, funcLength),
196-
End = funcExtent.Start.Delta(0, funcLength + name.Length)
197-
};
207+
return funcExtent;
198208
}
199209
}
200210

@@ -219,41 +229,47 @@ public static class AstExtensions
219229

220230
// This will be updated with each loop, and re-Find to dig deeper
221231
Ast? mostSpecificAst = null;
232+
Ast? currentAst = ast;
222233

223234
do
224235
{
225-
ast = ast.Find(currentAst =>
236+
currentAst = currentAst.Find(thisAst =>
226237
{
227-
if (currentAst == mostSpecificAst) { return false; }
238+
if (thisAst == mostSpecificAst) { return false; }
228239

229240
int line = position.LineNumber;
230241
int column = position.ColumnNumber;
231242

232243
// Performance optimization, skip statements that don't contain the position
233244
if (
234-
currentAst.Extent.EndLineNumber < line
235-
|| currentAst.Extent.StartLineNumber > line
236-
|| (currentAst.Extent.EndLineNumber == line && currentAst.Extent.EndColumnNumber < column)
237-
|| (currentAst.Extent.StartLineNumber == line && currentAst.Extent.StartColumnNumber > column)
245+
thisAst.Extent.EndLineNumber < line
246+
|| thisAst.Extent.StartLineNumber > line
247+
|| (thisAst.Extent.EndLineNumber == line && thisAst.Extent.EndColumnNumber < column)
248+
|| (thisAst.Extent.StartLineNumber == line && thisAst.Extent.StartColumnNumber > column)
238249
)
239250
{
240251
return false;
241252
}
242253

243-
if (allowedTypes is not null && !allowedTypes.Contains(currentAst.GetType()))
254+
if (allowedTypes is not null && !allowedTypes.Contains(thisAst.GetType()))
244255
{
245256
return false;
246257
}
247258

248-
if (new ScriptExtentAdapter(currentAst.Extent).Contains(position))
259+
if (new ScriptExtentAdapter(thisAst.Extent).Contains(position))
249260
{
250-
mostSpecificAst = currentAst;
251-
return true; //Stops the find
261+
mostSpecificAst = thisAst;
262+
return true; //Stops this particular find and looks more specifically
252263
}
253264

254265
return false;
255266
}, true);
256-
} while (ast is not null);
267+
268+
if (currentAst is not null)
269+
{
270+
mostSpecificAst = currentAst;
271+
}
272+
} while (currentAst is not null);
257273

258274
return mostSpecificAst;
259275
}
@@ -490,7 +506,10 @@ internal record ScriptExtentAdapter(IScriptExtent extent) : IScriptExtent
490506

491507
public static implicit operator ScriptExtent(ScriptExtentAdapter adapter) => adapter;
492508

493-
public static implicit operator RangeOrPlaceholderRange(ScriptExtentAdapter adapter) => new((Range)adapter);
509+
public static implicit operator RangeOrPlaceholderRange(ScriptExtentAdapter adapter) => new((Range)adapter)
510+
{
511+
DefaultBehavior = new() { DefaultBehavior = false }
512+
};
494513

495514
public IScriptPosition StartScriptPosition => Start;
496515
public IScriptPosition EndScriptPosition => End;

test/PowerShellEditorServices.Test.Shared/Refactoring/Functions/RefactorFunctionTestCases.cs

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,24 @@ namespace PowerShellEditorServices.Test.Shared.Refactoring;
55

66
public class RefactorFunctionTestCases
77
{
8+
/// <summary>
9+
/// Defines where functions should be renamed. These numbers are 1-based.
10+
/// </summary>
811
public static RenameTestTarget[] TestCases =
912
[
10-
new("FunctionsSingle.ps1", Line: 1, Column: 11 ),
11-
new("FunctionMultipleOccurrences.ps1", Line: 1, Column: 5 ),
12-
new("FunctionInnerIsNested.ps1", Line: 5, Column: 5, "bar"),
13-
new("FunctionOuterHasNestedFunction.ps1", Line: 10, Column: 1 ),
14-
new("FunctionWithInnerFunction.ps1", Line: 5, Column: 5, "RenamedInnerFunction"),
15-
new("FunctionWithInternalCalls.ps1", Line: 1, Column: 5 ),
16-
new("FunctionCmdlet.ps1", Line: 10, Column: 1 ),
17-
new("FunctionSameName.ps1", Line: 14, Column: 3, "RenamedSameNameFunction"),
18-
new("FunctionScriptblock.ps1", Line: 5, Column: 5 ),
19-
new("FunctionLoop.ps1", Line: 5, Column: 5 ),
20-
new("FunctionForeach.ps1", Line: 5, Column: 11 ),
21-
new("FunctionForeachObject.ps1", Line: 5, Column: 11 ),
22-
new("FunctionCallWIthinStringExpression.ps1", Line: 1, Column: 10 ),
23-
new("FunctionNestedRedefinition.ps1", Line: 13, Column: 15 )
13+
new("FunctionCallWIthinStringExpression.ps1", Line: 1, Column: 10 ),
14+
new("FunctionCmdlet.ps1", Line: 1, Column: 10 ),
15+
new("FunctionForeach.ps1", Line: 5, Column: 11 ),
16+
new("FunctionForeachObject.ps1", Line: 5, Column: 11 ),
17+
new("FunctionInnerIsNested.ps1", Line: 5, Column: 5 , "bar"),
18+
new("FunctionLoop.ps1", Line: 5, Column: 5 ),
19+
new("FunctionMultipleOccurrences.ps1", Line: 5, Column: 3 ),
20+
new("FunctionNestedRedefinition.ps1", Line: 13, Column: 15 ),
21+
new("FunctionOuterHasNestedFunction.ps1", Line: 2, Column: 15 ),
22+
new("FunctionSameName.ps1", Line: 3, Column: 14 , "RenamedSameNameFunction"),
23+
new("FunctionScriptblock.ps1", Line: 5, Column: 5 ),
24+
new("FunctionsSingle.ps1", Line: 1, Column: 11 ),
25+
new("FunctionWithInnerFunction.ps1", Line: 5, Column: 5 , "RenamedInnerFunction"),
26+
new("FunctionWithInternalCalls.ps1", Line: 3, Column: 6 ),
2427
];
2528
}

test/PowerShellEditorServices.Test/Refactoring/PrepareRenameHandlerTests.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ public async Task FindsFunction(RenameTestTarget s)
6767

6868
RangeOrPlaceholderRange? result = await testHandler.Handle(testParams, CancellationToken.None);
6969

70-
Assert.NotNull(result?.Range);
71-
Assert.True(result.Range.Contains(testParams.Position));
70+
Assert.NotNull(result);
71+
Assert.True(result?.DefaultBehavior?.DefaultBehavior);
7272
}
7373

7474
[Theory]
@@ -79,8 +79,8 @@ public async Task FindsVariable(RenameTestTarget s)
7979

8080
RangeOrPlaceholderRange? result = await testHandler.Handle(testParams, CancellationToken.None);
8181

82-
Assert.NotNull(result?.Range);
83-
Assert.True(result.Range.Contains(testParams.Position));
82+
Assert.NotNull(result);
83+
Assert.True(result?.DefaultBehavior?.DefaultBehavior);
8484
}
8585
}
8686

0 commit comments

Comments
 (0)