Skip to content

Commit 6cdd65b

Browse files
author
Kapil Borle
authored
Merge pull request #458 from kapilmb/fix-variable-definition
Fix finding variable definitions in workspace
2 parents c01145c + 8ef58a1 commit 6cdd65b

File tree

6 files changed

+116
-42
lines changed

6 files changed

+116
-42
lines changed

src/PowerShellEditorServices/Language/AstOperations.cs

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ namespace Microsoft.PowerShell.EditorServices
2424
internal static class AstOperations
2525
{
2626
/// <summary>
27-
/// Gets completions for the symbol found in the Ast at
27+
/// Gets completions for the symbol found in the Ast at
2828
/// the given file offset.
2929
/// </summary>
3030
/// <param name="scriptAst">
@@ -47,14 +47,14 @@ internal static class AstOperations
4747
/// symbol at the given offset.
4848
/// </returns>
4949
static public async Task<CommandCompletion> GetCompletions(
50-
Ast scriptAst,
51-
Token[] currentTokens,
50+
Ast scriptAst,
51+
Token[] currentTokens,
5252
int fileOffset,
5353
PowerShellContext powerShellContext,
5454
CancellationToken cancellationToken)
5555
{
5656
var type = scriptAst.Extent.StartScriptPosition.GetType();
57-
var method =
57+
var method =
5858
#if CoreCLR
5959
type.GetMethod(
6060
"CloneWithNewOffset",
@@ -67,9 +67,9 @@ static public async Task<CommandCompletion> GetCompletions(
6767
new[] { typeof(int) }, null);
6868
#endif
6969

70-
IScriptPosition cursorPosition =
70+
IScriptPosition cursorPosition =
7171
(IScriptPosition)method.Invoke(
72-
scriptAst.Extent.StartScriptPosition,
72+
scriptAst.Extent.StartScriptPosition,
7373
new object[] { fileOffset });
7474

7575
Logger.Write(
@@ -138,7 +138,7 @@ static public async Task<CommandCompletion> GetCompletions(
138138
}
139139

140140
/// <summary>
141-
/// Finds the symbol at a given file location
141+
/// Finds the symbol at a given file location
142142
/// </summary>
143143
/// <param name="scriptAst">The abstract syntax tree of the given script</param>
144144
/// <param name="lineNumber">The line number of the cursor for the given script</param>
@@ -176,15 +176,15 @@ static public SymbolReference FindCommandAtPosition(Ast scriptAst, int lineNumbe
176176
/// <param name="AliasToCmdletDictionary">Dictionary maping aliases to cmdlets for finding alias references</param>
177177
/// <returns></returns>
178178
static public IEnumerable<SymbolReference> FindReferencesOfSymbol(
179-
Ast scriptAst,
180-
SymbolReference symbolReference,
179+
Ast scriptAst,
180+
SymbolReference symbolReference,
181181
Dictionary<String, List<String>> CmdletToAliasDictionary,
182182
Dictionary<String, String> AliasToCmdletDictionary)
183183
{
184184
// find the symbol evaluators for the node types we are handling
185-
FindReferencesVisitor referencesVisitor =
185+
FindReferencesVisitor referencesVisitor =
186186
new FindReferencesVisitor(
187-
symbolReference,
187+
symbolReference,
188188
CmdletToAliasDictionary,
189189
AliasToCmdletDictionary);
190190
scriptAst.Visit(referencesVisitor);
@@ -202,8 +202,8 @@ static public IEnumerable<SymbolReference> FindReferencesOfSymbol(
202202
/// <returns>A collection of SymbolReference objects that are refrences to the symbolRefrence
203203
/// not including aliases</returns>
204204
static public IEnumerable<SymbolReference> FindReferencesOfSymbol(
205-
ScriptBlockAst scriptAst,
206-
SymbolReference foundSymbol,
205+
ScriptBlockAst scriptAst,
206+
SymbolReference foundSymbol,
207207
bool needsAliases)
208208
{
209209
FindReferencesVisitor referencesVisitor =
@@ -214,7 +214,7 @@ static public IEnumerable<SymbolReference> FindReferencesOfSymbol(
214214
}
215215

216216
/// <summary>
217-
/// Finds the definition of the symbol
217+
/// Finds the definition of the symbol
218218
/// </summary>
219219
/// <param name="scriptAst">The abstract syntax tree of the given script</param>
220220
/// <param name="symbolReference">The symbol that we are looking for the definition of</param>
@@ -223,12 +223,12 @@ static public SymbolReference FindDefinitionOfSymbol(
223223
Ast scriptAst,
224224
SymbolReference symbolReference)
225225
{
226-
FindDeclartionVisitor declarationVisitor =
227-
new FindDeclartionVisitor(
226+
FindDeclarationVisitor declarationVisitor =
227+
new FindDeclarationVisitor(
228228
symbolReference);
229229
scriptAst.Visit(declarationVisitor);
230230

231-
return declarationVisitor.FoundDeclartion;
231+
return declarationVisitor.FoundDeclaration;
232232
}
233233

234234
/// <summary>

src/PowerShellEditorServices/Language/FindDeclartionVisitor.cs renamed to src/PowerShellEditorServices/Language/FindDeclarationVisitor.cs

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -9,30 +9,36 @@
99
namespace Microsoft.PowerShell.EditorServices
1010
{
1111
/// <summary>
12-
/// The vistor used to find the defintion of a symbol
12+
/// The visitor used to find the definition of a symbol
1313
/// </summary>
14-
internal class FindDeclartionVisitor : AstVisitor
14+
internal class FindDeclarationVisitor : AstVisitor
1515
{
1616
private SymbolReference symbolRef;
17+
private string variableName;
1718

18-
public SymbolReference FoundDeclartion{ get; private set; }
19+
public SymbolReference FoundDeclaration{ get; private set; }
1920

20-
public FindDeclartionVisitor(SymbolReference symbolRef)
21+
public FindDeclarationVisitor(SymbolReference symbolRef)
2122
{
2223
this.symbolRef = symbolRef;
24+
if (this.symbolRef.SymbolType == SymbolType.Variable)
25+
{
26+
// converts `$varName` to `varName` or of the form ${varName} to varName
27+
variableName = symbolRef.SymbolName.TrimStart('$').Trim('{', '}');
28+
}
2329
}
2430

2531
/// <summary>
26-
/// Decides if the current function defintion is the right defition
27-
/// for the symbol being searched for. The defintion of the symbol will be a of type
32+
/// Decides if the current function definition is the right definition
33+
/// for the symbol being searched for. The definition of the symbol will be a of type
2834
/// SymbolType.Function and have the same name as the symbol
2935
/// </summary>
3036
/// <param name="functionDefinitionAst">A FunctionDefinitionAst in the script's AST</param>
31-
/// <returns>A descion to stop searching if the right FunctionDefinitionAst was found,
37+
/// <returns>A descion to stop searching if the right FunctionDefinitionAst was found,
3238
/// or a decision to continue if it wasn't found</returns>
3339
public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst functionDefinitionAst)
3440
{
35-
// Get the start column number of the function name,
41+
// Get the start column number of the function name,
3642
// instead of the the start column of 'function' and create new extent for the functionName
3743
int startColumnNumber =
3844
functionDefinitionAst.Extent.Text.IndexOf(
@@ -50,7 +56,7 @@ public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst fun
5056
if (symbolRef.SymbolType.Equals(SymbolType.Function) &&
5157
nameExtent.Text.Equals(symbolRef.ScriptRegion.Text, StringComparison.CurrentCultureIgnoreCase))
5258
{
53-
this.FoundDeclartion =
59+
this.FoundDeclaration =
5460
new SymbolReference(
5561
SymbolType.Function,
5662
nameExtent);
@@ -62,27 +68,27 @@ public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst fun
6268
}
6369

6470
/// <summary>
65-
/// Decides if the current variable expression is the right defition for
66-
/// the symbol being searched for. The defintion of the symbol will be a of type
67-
/// SymbolType.Variable and have the same name as the symbol
71+
/// Check if the left hand side of an assignmentStatementAst is a VariableExpressionAst
72+
/// with the same name as that of symbolRef.
6873
/// </summary>
69-
/// <param name="variableExpressionAst">A FunctionDefinitionAst in the script's AST</param>
70-
/// <returns>A descion to stop searching if the right VariableExpressionAst was found,
74+
/// <param name="assignmentStatementAst">An AssignmentStatementAst/param>
75+
/// <returns>A decision to stop searching if the right VariableExpressionAst was found,
7176
/// or a decision to continue if it wasn't found</returns>
72-
public override AstVisitAction VisitVariableExpression(VariableExpressionAst variableExpressionAst)
77+
public override AstVisitAction VisitAssignmentStatement(AssignmentStatementAst assignmentStatementAst)
7378
{
74-
if(symbolRef.SymbolType.Equals(SymbolType.Variable) &&
75-
variableExpressionAst.Extent.Text.Equals(symbolRef.SymbolName, StringComparison.CurrentCultureIgnoreCase))
79+
var variableExprAst = assignmentStatementAst.Left as VariableExpressionAst;
80+
if (variableExprAst == null ||
81+
variableName == null ||
82+
!variableExprAst.VariablePath.UserPath.Equals(
83+
variableName,
84+
StringComparison.OrdinalIgnoreCase))
7685
{
77-
this.FoundDeclartion =
78-
new SymbolReference(
79-
SymbolType.Variable,
80-
variableExpressionAst.Extent);
81-
82-
return AstVisitAction.StopVisit;
86+
return AstVisitAction.Continue;
8387
}
8488

85-
return AstVisitAction.Continue;
89+
// TODO also find instances of set-variable
90+
FoundDeclaration = new SymbolReference(SymbolType.Variable, variableExprAst.Extent);
91+
return AstVisitAction.StopVisit;
8692
}
8793
}
8894
}

src/PowerShellEditorServices/Language/SymbolReference.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
44
//
55

6+
using System;
67
using System.Diagnostics;
78
using System.Management.Automation.Language;
89

test/PowerShellEditorServices.Test.Host/LanguageServerTests.cs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,66 @@ await this.SendRequest(
455455
Assert.Equal(7, locations[0].Range.End.Character);
456456
}
457457

458+
[Fact]
459+
public async Task FindsDefinitionOfVariableInOtherFile()
460+
{
461+
await this.SendOpenFileEvent("TestFiles\\FindReferences.ps1");
462+
463+
Location[] locations =
464+
await this.SendRequest(
465+
DefinitionRequest.Type,
466+
new TextDocumentPositionParams
467+
{
468+
TextDocument = new TextDocumentIdentifier
469+
{
470+
Uri = "TestFiles\\FindReferences.ps1"
471+
},
472+
Position = new Position
473+
{
474+
Line = 15,
475+
Character = 20,
476+
}
477+
});
478+
479+
Assert.NotNull(locations);
480+
Assert.Equal(1, locations.Length);
481+
Assert.EndsWith("VariableDefinition.ps1", locations[0].Uri);
482+
Assert.Equal(0, locations[0].Range.Start.Line);
483+
Assert.Equal(0, locations[0].Range.Start.Character);
484+
Assert.Equal(0, locations[0].Range.End.Line);
485+
Assert.Equal(20, locations[0].Range.End.Character);
486+
}
487+
488+
[Fact]
489+
public async Task FindDefinitionOfVariableWithSpecialChars()
490+
{
491+
await this.SendOpenFileEvent("TestFiles\\FindReferences.ps1");
492+
493+
Location[] locations =
494+
await this.SendRequest(
495+
DefinitionRequest.Type,
496+
new TextDocumentPositionParams
497+
{
498+
TextDocument = new TextDocumentIdentifier
499+
{
500+
Uri = "TestFiles\\FindReferences.ps1"
501+
},
502+
Position = new Position
503+
{
504+
Line = 18,
505+
Character = 24,
506+
}
507+
});
508+
509+
Assert.NotNull(locations);
510+
Assert.Equal(1, locations.Length);
511+
Assert.EndsWith("FindReferences.ps1", locations[0].Uri);
512+
Assert.Equal(17, locations[0].Range.Start.Line);
513+
Assert.Equal(0, locations[0].Range.Start.Character);
514+
Assert.Equal(17, locations[0].Range.End.Line);
515+
Assert.Equal(27, locations[0].Range.End.Character);
516+
}
517+
458518
[Fact]
459519
public async Task FindsOccurencesOnFunctionDefinition()
460520
{

test/PowerShellEditorServices.Test.Host/TestFiles/FindReferences.ps1

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,10 @@ My-Function $things
1010

1111
Write-Output "Hi";
1212

13-
Write-Output ""
13+
Write-Output ""
14+
15+
. .\VariableDefinition.ps1
16+
Write-Output $variableInOtherFile
17+
18+
${variable-with-weird-name} = "this variable has special characters"
19+
Write-Output ${variable-with-weird-name}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
$variableInOtherFile = "some value"

0 commit comments

Comments
 (0)