Skip to content

Commit 633e36b

Browse files
author
Kayla Davis
committed
Add alias support on find references
1 parent f670863 commit 633e36b

17 files changed

+329
-48
lines changed

src/PowerShellEditorServices.Transport.Stdio/Request/DeclarationRequest.cs

+4-14
Original file line numberDiff line numberDiff line change
@@ -35,24 +35,14 @@ public override void ProcessMessage(
3535

3636
}
3737

38-
if (definition != null)
38+
DefinitionResponse defResponse = DefinitionResponse.Create();
39+
if (definition != null && definition.FoundDefinition != null)
3940
{
40-
DefinitionResponse defResponse;
41-
if (definition.FoundDefinition != null)
42-
{
43-
defResponse = DefinitionResponse.Create(definition.FoundDefinition);
44-
}
45-
else
46-
{
47-
defResponse = DefinitionResponse.Create();
48-
}
49-
50-
messageWriter.WriteMessage(
51-
this.PrepareResponse(defResponse));
41+
defResponse = DefinitionResponse.Create(definition.FoundDefinition);
5242
}
5343

5444
messageWriter.WriteMessage(
55-
this.PrepareResponse(DefinitionResponse.Create()));
45+
this.PrepareResponse(defResponse));
5646
}
5747
}
5848
}

src/PowerShellEditorServices/Language/AstOperations.cs

+41-6
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.Collections.Generic;
78
using System.Linq;
89
using System.Management.Automation;
@@ -108,30 +109,64 @@ static public SymbolReference FindCommandAtPosition(Ast scriptAst, int lineNumbe
108109
}
109110

110111
/// <summary>
111-
/// Finds all references in a script of the given symbol
112+
/// Finds all references (including aliases) in a script for the given symbol
112113
/// </summary>
113114
/// <param name="scriptAst">The abstract syntax tree of the given script</param>
114115
/// <param name="symbolReference">The symbol that we are looking for referneces of</param>
115-
/// <returns>A collection of SymbolReference objects that are refrences to the symbolRefrence</returns>
116-
static public IEnumerable<SymbolReference> FindReferencesOfSymbol(Ast scriptAst, SymbolReference symbolReference)
116+
/// <param name="CmdletToAliasDictionary">Dictionary maping cmdlets to aliases for finding alias references</param>
117+
/// <param name="AliasToCmdletDictionary">Dictionary maping aliases to cmdlets for finding alias references</param>
118+
/// <returns></returns>
119+
static public IEnumerable<SymbolReference> FindReferencesOfSymbol(
120+
Ast scriptAst,
121+
SymbolReference symbolReference,
122+
Dictionary<String, List<String>> CmdletToAliasDictionary,
123+
Dictionary<String, String> AliasToCmdletDictionary)
117124
{
118125
// find the symbol evaluators for the node types we are handling
119-
FindReferencesVisitor referencesVisitor = new FindReferencesVisitor(symbolReference);
126+
FindReferencesVisitor referencesVisitor =
127+
new FindReferencesVisitor(
128+
symbolReference,
129+
CmdletToAliasDictionary,
130+
AliasToCmdletDictionary);
120131
scriptAst.Visit(referencesVisitor);
121132

122133
return referencesVisitor.FoundReferences;
123134

124135
}
136+
/// <summary>
137+
/// Finds all references (not including aliases) in a script for the given symbol
138+
/// </summary>
139+
/// <param name="scriptAst">The abstract syntax tree of the given script</param>
140+
/// <param name="foundSymbol">The symbol that we are looking for referneces of</param>
141+
/// <param name="needsAliases">If this reference search needs aliases.
142+
/// This should always be false and used for occurence requests</param>
143+
/// <returns>A collection of SymbolReference objects that are refrences to the symbolRefrence
144+
/// not including aliases</returns>
145+
static public IEnumerable<SymbolReference> FindReferencesOfSymbol(
146+
ScriptBlockAst scriptAst,
147+
SymbolReference foundSymbol,
148+
bool needsAliases)
149+
{
150+
FindReferencesVisitor referencesVisitor =
151+
new FindReferencesVisitor(foundSymbol);
152+
scriptAst.Visit(referencesVisitor);
153+
154+
return referencesVisitor.FoundReferences;
155+
}
125156

126157
/// <summary>
127158
/// Finds the definition of the symbol
128159
/// </summary>
129160
/// <param name="scriptAst">The abstract syntax tree of the given script</param>
130161
/// <param name="symbolReference">The symbol that we are looking for the definition of</param>
131162
/// <returns>A SymbolReference of the definition of the symbolReference</returns>
132-
static public SymbolReference FindDefinitionOfSymbol(Ast scriptAst, SymbolReference symbolReference)
163+
static public SymbolReference FindDefinitionOfSymbol(
164+
Ast scriptAst,
165+
SymbolReference symbolReference)
133166
{
134-
FindDeclartionVisitor declarationVisitor = new FindDeclartionVisitor(symbolReference);
167+
FindDeclartionVisitor declarationVisitor =
168+
new FindDeclartionVisitor(
169+
symbolReference);
135170
scriptAst.Visit(declarationVisitor);
136171

137172
return declarationVisitor.FoundDeclartion;

src/PowerShellEditorServices/Language/FindCommandVisitor.cs

+2
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ public FindCommandVisitor(int lineNumber, int columnNumber)
3333
public override AstVisitAction VisitCommand(CommandAst commandAst)
3434
{
3535
Ast commandNameAst = commandAst.CommandElements[0];
36+
37+
// Only want commands that are using a trigger character, which requires at least 2 cmd elements
3638
if (!(commandAst.CommandElements.Count > 1))
3739
{
3840
return base.VisitCommand(commandAst);

src/PowerShellEditorServices/Language/FindDeclartionVisitor.cs

+2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ public FindDeclartionVisitor(SymbolReference symbolRef)
3232
/// or a decision to continue if it wasn't found</returns>
3333
public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst functionDefinitionAst)
3434
{
35+
// Get the start column number of the function name,
36+
// instead of the the start column of 'function' and create new extent for the functionName
3537
int startColumnNumber =
3638
functionDefinitionAst.Extent.Text.IndexOf(
3739
functionDefinitionAst.Name) + 1;

src/PowerShellEditorServices/Language/FindDotSourcedVisitor.cs

-2
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@
33
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
44
//
55

6-
using Microsoft.PowerShell.EditorServices.Session;
76
using System.Collections.Generic;
8-
using System.IO;
97
using System.Management.Automation.Language;
108

119
namespace Microsoft.PowerShell.EditorServices.Language

src/PowerShellEditorServices/Language/FindReferencesVisitor.cs

+82-7
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,47 @@ namespace Microsoft.PowerShell.EditorServices.Language
1515
internal class FindReferencesVisitor : AstVisitor
1616
{
1717
private SymbolReference symbolRef;
18+
private Dictionary<String, List<String>> CmdletToAliasDictionary;
19+
private Dictionary<String, String> AliasToCmdletDictionary;
20+
private string symbolRefCommandName;
21+
private bool needsAliases;
1822

1923
public List<SymbolReference> FoundReferences { get; set; }
2024

21-
public FindReferencesVisitor(SymbolReference symbolRef)
25+
/// <summary>
26+
/// Constructor used when searching for aliases is needed
27+
/// </summary>
28+
/// <param name="symbolReference">The found symbolReference that other symbols are being compared to</param>
29+
/// <param name="CmdletToAliasDictionary">Dictionary maping cmdlets to aliases for finding alias references</param>
30+
/// <param name="AliasToCmdletDictionary">Dictionary maping aliases to cmdlets for finding alias references</param>
31+
public FindReferencesVisitor(
32+
SymbolReference symbolReference,
33+
Dictionary<String, List<String>> CmdletToAliasDictionary,
34+
Dictionary<String, String> AliasToCmdletDictionary)
2235
{
23-
this.symbolRef = symbolRef;
36+
this.symbolRef = symbolReference;
2437
this.FoundReferences = new List<SymbolReference>();
38+
this.needsAliases = true;
39+
this.CmdletToAliasDictionary = CmdletToAliasDictionary;
40+
this.AliasToCmdletDictionary = AliasToCmdletDictionary;
41+
42+
// Try to get the symbolReference's command name of an alias,
43+
// if a command name does not exists (if the symbol isn't an alias to a command)
44+
// set symbolRefCommandName to and empty string value
45+
AliasToCmdletDictionary.TryGetValue(symbolReference.ScriptRegion.Text, out symbolRefCommandName);
46+
if (symbolRefCommandName == null) { symbolRefCommandName = string.Empty; }
47+
48+
}
49+
50+
/// <summary>
51+
/// Constructor used when searching for aliases is not needed
52+
/// </summary>
53+
/// <param name="foundSymbol">The found symbolReference that other symbols are being compared to</param>
54+
public FindReferencesVisitor(SymbolReference foundSymbol)
55+
{
56+
this.symbolRef = foundSymbol;
57+
this.FoundReferences = new List<SymbolReference>();
58+
this.needsAliases = false;
2559
}
2660

2761
/// <summary>
@@ -34,12 +68,51 @@ public FindReferencesVisitor(SymbolReference symbolRef)
3468
public override AstVisitAction VisitCommand(CommandAst commandAst)
3569
{
3670
Ast commandNameAst = commandAst.CommandElements[0];
37-
if(symbolRef.SymbolType.Equals(SymbolType.Function) &&
38-
commandNameAst.Extent.Text.Equals(symbolRef.ScriptRegion.Text, StringComparison.InvariantCultureIgnoreCase))
71+
string commandName = commandNameAst.Extent.Text;
72+
73+
if(symbolRef.SymbolType.Equals(SymbolType.Function))
3974
{
40-
this.FoundReferences.Add(new SymbolReference(
41-
SymbolType.Function,
42-
commandNameAst.Extent));
75+
if (needsAliases)
76+
{
77+
// Try to get the commandAst's name and aliases,
78+
// if a command does not exists (if the symbol isn't an alias to a command)
79+
// set command to and empty string value string command
80+
// if the aliases do not exist (if the symvol isn't a command that has aliases)
81+
// set aliases to an empty List<string>
82+
string command;
83+
List<string> alaises;
84+
CmdletToAliasDictionary.TryGetValue(commandName, out alaises);
85+
AliasToCmdletDictionary.TryGetValue(commandName, out command);
86+
if (alaises == null) { alaises = new List<string>(); }
87+
if (command == null) { command = string.Empty; }
88+
89+
if (symbolRef.SymbolType.Equals(SymbolType.Function))
90+
{
91+
// Check if the found symbol's name is the same as the commandAst's name OR
92+
// if the symbol's name is an alias for this commandAst's name (commandAst is a cmdlet) OR
93+
// if the symbol's name is the same as the commandAst's cmdlet name (commandAst is a alias)
94+
if (commandName.Equals(symbolRef.SymbolName, StringComparison.InvariantCultureIgnoreCase) ||
95+
alaises.Contains(symbolRef.ScriptRegion.Text.ToLower()) ||
96+
command.Equals(symbolRef.ScriptRegion.Text, StringComparison.InvariantCultureIgnoreCase) ||
97+
(!command.Equals(string.Empty) && command.Equals(symbolRefCommandName, StringComparison.InvariantCultureIgnoreCase)))
98+
{
99+
this.FoundReferences.Add(new SymbolReference(
100+
SymbolType.Function,
101+
commandNameAst.Extent));
102+
}
103+
}
104+
105+
}
106+
else // search does not include aliases
107+
{
108+
if (commandName.Equals(symbolRef.SymbolName, StringComparison.InvariantCultureIgnoreCase))
109+
{
110+
this.FoundReferences.Add(new SymbolReference(
111+
SymbolType.Function,
112+
commandNameAst.Extent));
113+
}
114+
}
115+
43116
}
44117
return base.VisitCommand(commandAst);
45118
}
@@ -52,6 +125,8 @@ public override AstVisitAction VisitCommand(CommandAst commandAst)
52125
/// <returns>A visit action that continues the search for references</returns>
53126
public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst functionDefinitionAst)
54127
{
128+
// Get the start column number of the function name,
129+
// instead of the the start column of 'function' and create new extent for the functionName
55130
int startColumnNumber =
56131
functionDefinitionAst.Extent.Text.IndexOf(
57132
functionDefinitionAst.Name) + 1;

src/PowerShellEditorServices/Language/LanguageService.cs

+41-3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
namespace Microsoft.PowerShell.EditorServices.Language
1111
{
1212
using Microsoft.PowerShell.EditorServices.Utility;
13+
using System;
1314
using System.Management.Automation;
1415
using System.Management.Automation.Runspaces;
1516

@@ -26,7 +27,8 @@ public class LanguageService
2627
private int mostRecentRequestLine;
2728
private int mostRecentRequestOffest;
2829
private string mostRecentRequestFile;
29-
30+
private Dictionary<String, List<String>> CmdletToAliasDictionary;
31+
private Dictionary<String, String> AliasToCmdletDictionary;
3032
#endregion
3133

3234
#region Constructors
@@ -43,6 +45,9 @@ public LanguageService(Runspace languageServiceRunspace)
4345
Validate.IsNotNull("languageServiceRunspace", languageServiceRunspace);
4446

4547
this.runspace = languageServiceRunspace;
48+
this.CmdletToAliasDictionary = new Dictionary<String, List<String>>(StringComparer.OrdinalIgnoreCase);
49+
this.AliasToCmdletDictionary = new Dictionary<String, String>(StringComparer.OrdinalIgnoreCase);
50+
GetAliases();
4651
}
4752

4853
#endregion
@@ -109,6 +114,7 @@ public CompletionDetails GetCompletionDetailsInFile(
109114
int columnNumber,
110115
string entryName)
111116
{
117+
// Makes sure the most recent completions request was the same line and column as this request
112118
if (file.FilePath.Equals(mostRecentRequestFile) &&
113119
lineNumber == mostRecentRequestLine &&
114120
columnNumber == mostRecentRequestOffest)
@@ -174,7 +180,9 @@ public FindReferencesResult FindReferencesOfSymbol(
174180
AstOperations
175181
.FindReferencesOfSymbol(
176182
file.ScriptAst,
177-
foundSymbol)
183+
foundSymbol,
184+
CmdletToAliasDictionary,
185+
AliasToCmdletDictionary)
178186
.Select(
179187
reference =>
180188
{
@@ -269,11 +277,13 @@ public FindOccurrencesResult FindOccurrencesInFile(
269277

270278
if (foundSymbol != null)
271279
{
280+
// find all references, and indicate that looking for aliases is not needed
272281
IEnumerable<SymbolReference> symbolOccurrences =
273282
AstOperations
274283
.FindReferencesOfSymbol(
275284
file.ScriptAst,
276-
foundSymbol);
285+
foundSymbol,
286+
false);
277287

278288
return
279289
new FindOccurrencesResult
@@ -329,6 +339,30 @@ public ParameterSetSignatures FindParameterSetsInFile(
329339

330340
#endregion
331341

342+
#region Private Fields
343+
344+
/// <summary>
345+
/// Gets all aliases found in the runspace
346+
/// </summary>
347+
private void GetAliases()
348+
{
349+
CommandInvocationIntrinsics invokeCommand = runspace.SessionStateProxy.InvokeCommand;
350+
IEnumerable<CommandInfo> aliases = invokeCommand.GetCommands("*", CommandTypes.Alias, true);
351+
foreach (AliasInfo aliasInfo in aliases)
352+
{
353+
if (!CmdletToAliasDictionary.ContainsKey(aliasInfo.Definition))
354+
{
355+
CmdletToAliasDictionary.Add(aliasInfo.Definition, new List<String>() { aliasInfo.Name });
356+
}
357+
else
358+
{
359+
CmdletToAliasDictionary[aliasInfo.Definition].Add(aliasInfo.Name);
360+
}
361+
362+
AliasToCmdletDictionary.Add(aliasInfo.Name, aliasInfo.Definition);
363+
}
364+
}
365+
332366
private CommandInfo GetCommandInfo(string commandName)
333367
{
334368
CommandInfo commandInfo = null;
@@ -348,12 +382,15 @@ private ScriptFile[] GetBuiltinCommandScriptFiles(
348382
PSModuleInfo moduleInfo,
349383
Workspace workspace)
350384
{
385+
// if there is module info for this command
351386
if (moduleInfo != null)
352387
{
353388
string modPath = moduleInfo.Path;
354389
List<ScriptFile> scriptFiles = new List<ScriptFile>();
355390
ScriptFile newFile;
356391

392+
// find any files where the moduleInfo's path ends with ps1 or psm1
393+
// and add it to allowed script files
357394
if (modPath.EndsWith(@".ps1") || modPath.EndsWith(@".psm1"))
358395
{
359396
newFile = workspace.GetFile(modPath);
@@ -412,5 +449,6 @@ private SymbolReference FindDeclarationForBuiltinCommand(
412449

413450
return foundDefinition;
414451
}
452+
#endregion
415453
}
416454
}

src/PowerShellEditorServices/Session/EditorSession.cs

-5
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,8 @@
66
using Microsoft.PowerShell.EditorServices.Analysis;
77
using Microsoft.PowerShell.EditorServices.Console;
88
using Microsoft.PowerShell.EditorServices.Language;
9-
using Microsoft.PowerShell.EditorServices.Utility;
10-
using System;
11-
using System.Collections.Generic;
12-
using System.IO;
139
using System.Management.Automation;
1410
using System.Management.Automation.Runspaces;
15-
using System.Text;
1611
using System.Threading;
1712

1813
namespace Microsoft.PowerShell.EditorServices.Session

0 commit comments

Comments
 (0)