forked from PowerShell/PowerShellEditorServices
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request PowerShell#16 from TylerLeonhardt/working-workspac…
…esymbolshandler A working WorkspaceSymbolsHandler
- Loading branch information
Showing
21 changed files
with
1,316 additions
and
124 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
145 changes: 145 additions & 0 deletions
145
src/PowerShellEditorServices.Engine/Services/Symbols/FindSymbolVisitor.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
// | ||
// Copyright (c) Microsoft. All rights reserved. | ||
// Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
// | ||
|
||
using System.Management.Automation.Language; | ||
|
||
namespace Microsoft.PowerShell.EditorServices.Symbols | ||
{ | ||
/// <summary> | ||
/// The visitor used to find the the symbol at a specfic location in the AST | ||
/// </summary> | ||
internal class FindSymbolVisitor : AstVisitor | ||
{ | ||
private int lineNumber; | ||
private int columnNumber; | ||
private bool includeFunctionDefinitions; | ||
|
||
public SymbolReference FoundSymbolReference { get; private set; } | ||
|
||
public FindSymbolVisitor( | ||
int lineNumber, | ||
int columnNumber, | ||
bool includeFunctionDefinitions) | ||
{ | ||
this.lineNumber = lineNumber; | ||
this.columnNumber = columnNumber; | ||
this.includeFunctionDefinitions = includeFunctionDefinitions; | ||
} | ||
|
||
/// <summary> | ||
/// Checks to see if this command ast is the symbol we are looking for. | ||
/// </summary> | ||
/// <param name="commandAst">A CommandAst object in the script's AST</param> | ||
/// <returns>A decision to stop searching if the right symbol was found, | ||
/// or a decision to continue if it wasn't found</returns> | ||
public override AstVisitAction VisitCommand(CommandAst commandAst) | ||
{ | ||
Ast commandNameAst = commandAst.CommandElements[0]; | ||
|
||
if (this.IsPositionInExtent(commandNameAst.Extent)) | ||
{ | ||
this.FoundSymbolReference = | ||
new SymbolReference( | ||
SymbolType.Function, | ||
commandNameAst.Extent); | ||
|
||
return AstVisitAction.StopVisit; | ||
} | ||
|
||
return base.VisitCommand(commandAst); | ||
} | ||
|
||
/// <summary> | ||
/// Checks to see if this function definition is the symbol we are looking for. | ||
/// </summary> | ||
/// <param name="functionDefinitionAst">A functionDefinitionAst object in the script's AST</param> | ||
/// <returns>A decision to stop searching if the right symbol was found, | ||
/// or a decision to continue if it wasn't found</returns> | ||
public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst functionDefinitionAst) | ||
{ | ||
int startColumnNumber = 1; | ||
|
||
if (!this.includeFunctionDefinitions) | ||
{ | ||
startColumnNumber = | ||
functionDefinitionAst.Extent.Text.IndexOf( | ||
functionDefinitionAst.Name) + 1; | ||
} | ||
|
||
IScriptExtent nameExtent = new ScriptExtent() | ||
{ | ||
Text = functionDefinitionAst.Name, | ||
StartLineNumber = functionDefinitionAst.Extent.StartLineNumber, | ||
EndLineNumber = functionDefinitionAst.Extent.EndLineNumber, | ||
StartColumnNumber = startColumnNumber, | ||
EndColumnNumber = startColumnNumber + functionDefinitionAst.Name.Length | ||
}; | ||
|
||
if (this.IsPositionInExtent(nameExtent)) | ||
{ | ||
this.FoundSymbolReference = | ||
new SymbolReference( | ||
SymbolType.Function, | ||
nameExtent); | ||
|
||
return AstVisitAction.StopVisit; | ||
} | ||
|
||
return base.VisitFunctionDefinition(functionDefinitionAst); | ||
} | ||
|
||
/// <summary> | ||
/// Checks to see if this command parameter is the symbol we are looking for. | ||
/// </summary> | ||
/// <param name="commandParameterAst">A CommandParameterAst object in the script's AST</param> | ||
/// <returns>A decision to stop searching if the right symbol was found, | ||
/// or a decision to continue if it wasn't found</returns> | ||
public override AstVisitAction VisitCommandParameter(CommandParameterAst commandParameterAst) | ||
{ | ||
if (this.IsPositionInExtent(commandParameterAst.Extent)) | ||
{ | ||
this.FoundSymbolReference = | ||
new SymbolReference( | ||
SymbolType.Parameter, | ||
commandParameterAst.Extent); | ||
return AstVisitAction.StopVisit; | ||
} | ||
return AstVisitAction.Continue; | ||
} | ||
|
||
/// <summary> | ||
/// Checks to see if this variable expression is the symbol we are looking for. | ||
/// </summary> | ||
/// <param name="variableExpressionAst">A VariableExpressionAst object in the script's AST</param> | ||
/// <returns>A decision to stop searching if the right symbol was found, | ||
/// or a decision to continue if it wasn't found</returns> | ||
public override AstVisitAction VisitVariableExpression(VariableExpressionAst variableExpressionAst) | ||
{ | ||
if (this.IsPositionInExtent(variableExpressionAst.Extent)) | ||
{ | ||
this.FoundSymbolReference = | ||
new SymbolReference( | ||
SymbolType.Variable, | ||
variableExpressionAst.Extent); | ||
|
||
return AstVisitAction.StopVisit; | ||
} | ||
|
||
return AstVisitAction.Continue; | ||
} | ||
|
||
/// <summary> | ||
/// Is the position of the given location is in the ast's extent | ||
/// </summary> | ||
/// <param name="extent">The script extent of the element</param> | ||
/// <returns>True if the given position is in the range of the element's extent </returns> | ||
private bool IsPositionInExtent(IScriptExtent extent) | ||
{ | ||
return (extent.StartLineNumber == lineNumber && | ||
extent.StartColumnNumber <= columnNumber && | ||
extent.EndColumnNumber >= columnNumber); | ||
} | ||
} | ||
} |
148 changes: 148 additions & 0 deletions
148
src/PowerShellEditorServices.Engine/Services/Symbols/FindSymbolsVisitor.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
// | ||
// Copyright (c) Microsoft. All rights reserved. | ||
// Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
// | ||
|
||
using System.Collections.Generic; | ||
using System.Management.Automation.Language; | ||
|
||
namespace Microsoft.PowerShell.EditorServices.Symbols | ||
{ | ||
/// <summary> | ||
/// The visitor used to find all the symbols (function and class defs) in the AST. | ||
/// </summary> | ||
/// <remarks> | ||
/// Requires PowerShell v3 or higher | ||
/// </remarks> | ||
internal class FindSymbolsVisitor : AstVisitor | ||
{ | ||
public List<SymbolReference> SymbolReferences { get; private set; } | ||
|
||
public FindSymbolsVisitor() | ||
{ | ||
this.SymbolReferences = new List<SymbolReference>(); | ||
} | ||
|
||
/// <summary> | ||
/// Adds each function definition as a | ||
/// </summary> | ||
/// <param name="functionDefinitionAst">A functionDefinitionAst object in the script's AST</param> | ||
/// <returns>A decision to stop searching if the right symbol was found, | ||
/// or a decision to continue if it wasn't found</returns> | ||
public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst functionDefinitionAst) | ||
{ | ||
IScriptExtent nameExtent = new ScriptExtent() { | ||
Text = functionDefinitionAst.Name, | ||
StartLineNumber = functionDefinitionAst.Extent.StartLineNumber, | ||
EndLineNumber = functionDefinitionAst.Extent.EndLineNumber, | ||
StartColumnNumber = functionDefinitionAst.Extent.StartColumnNumber, | ||
EndColumnNumber = functionDefinitionAst.Extent.EndColumnNumber | ||
}; | ||
|
||
SymbolType symbolType = | ||
functionDefinitionAst.IsWorkflow ? | ||
SymbolType.Workflow : SymbolType.Function; | ||
|
||
this.SymbolReferences.Add( | ||
new SymbolReference( | ||
symbolType, | ||
nameExtent)); | ||
|
||
return AstVisitAction.Continue; | ||
} | ||
|
||
/// <summary> | ||
/// Checks to see if this variable expression is the symbol we are looking for. | ||
/// </summary> | ||
/// <param name="variableExpressionAst">A VariableExpressionAst object in the script's AST</param> | ||
/// <returns>A decision to stop searching if the right symbol was found, | ||
/// or a decision to continue if it wasn't found</returns> | ||
public override AstVisitAction VisitVariableExpression(VariableExpressionAst variableExpressionAst) | ||
{ | ||
if (!IsAssignedAtScriptScope(variableExpressionAst)) | ||
{ | ||
return AstVisitAction.Continue; | ||
} | ||
|
||
this.SymbolReferences.Add( | ||
new SymbolReference( | ||
SymbolType.Variable, | ||
variableExpressionAst.Extent)); | ||
|
||
return AstVisitAction.Continue; | ||
} | ||
|
||
private bool IsAssignedAtScriptScope(VariableExpressionAst variableExpressionAst) | ||
{ | ||
Ast parent = variableExpressionAst.Parent; | ||
if (!(parent is AssignmentStatementAst)) | ||
{ | ||
return false; | ||
} | ||
|
||
parent = parent.Parent; | ||
if (parent == null || parent.Parent == null || parent.Parent.Parent == null) | ||
{ | ||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Visitor to find all the keys in Hashtable AST | ||
/// </summary> | ||
internal class FindHashtableSymbolsVisitor : AstVisitor | ||
{ | ||
/// <summary> | ||
/// List of symbols (keys) found in the hashtable | ||
/// </summary> | ||
public List<SymbolReference> SymbolReferences { get; private set; } | ||
|
||
/// <summary> | ||
/// Initializes a new instance of FindHashtableSymbolsVisitor class | ||
/// </summary> | ||
public FindHashtableSymbolsVisitor() | ||
{ | ||
SymbolReferences = new List<SymbolReference>(); | ||
} | ||
|
||
/// <summary> | ||
/// Adds keys in the input hashtable to the symbol reference | ||
/// </summary> | ||
public override AstVisitAction VisitHashtable(HashtableAst hashtableAst) | ||
{ | ||
if (hashtableAst.KeyValuePairs == null) | ||
{ | ||
return AstVisitAction.Continue; | ||
} | ||
|
||
foreach (var kvp in hashtableAst.KeyValuePairs) | ||
{ | ||
var keyStrConstExprAst = kvp.Item1 as StringConstantExpressionAst; | ||
if (keyStrConstExprAst != null) | ||
{ | ||
IScriptExtent nameExtent = new ScriptExtent() | ||
{ | ||
Text = keyStrConstExprAst.Value, | ||
StartLineNumber = kvp.Item1.Extent.StartLineNumber, | ||
EndLineNumber = kvp.Item2.Extent.EndLineNumber, | ||
StartColumnNumber = kvp.Item1.Extent.StartColumnNumber, | ||
EndColumnNumber = kvp.Item2.Extent.EndColumnNumber | ||
}; | ||
|
||
SymbolType symbolType = SymbolType.HashtableKey; | ||
|
||
this.SymbolReferences.Add( | ||
new SymbolReference( | ||
symbolType, | ||
nameExtent)); | ||
|
||
} | ||
} | ||
|
||
return AstVisitAction.Continue; | ||
} | ||
} | ||
} |
Oops, something went wrong.