/// <summary> /// Decides if the current function defintion is the right defition /// for the symbol being searched for. The defintion of the symbol will be a of type /// SymbolType.Function and have the same name as the symbol /// </summary> /// <param name="functionDefinitionAst">A FunctionDefinitionAst in the script's AST</param> /// <returns>A descion to stop searching if the right FunctionDefinitionAst was found, /// or a decision to continue if it wasn't found</returns> public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst functionDefinitionAst) { // Get the start column number of the function name, // instead of the the start column of 'function' and create new extent for the functionName int startColumnNumber = functionDefinitionAst.Extent.Text.IndexOf( functionDefinitionAst.Name) + 1; IScriptExtent nameExtent = new ScriptExtent() { Text = functionDefinitionAst.Name, StartLineNumber = functionDefinitionAst.Extent.StartLineNumber, StartColumnNumber = startColumnNumber, EndLineNumber = functionDefinitionAst.Extent.StartLineNumber, EndColumnNumber = startColumnNumber + functionDefinitionAst.Name.Length }; if (symbolRef.SymbolType.Equals(SymbolType.Function) && nameExtent.Text.Equals(symbolRef.ScriptRegion.Text, StringComparison.InvariantCultureIgnoreCase)) { this.FoundDeclartion = new SymbolReference( SymbolType.Function, nameExtent); return AstVisitAction.StopVisit; } return base.VisitFunctionDefinition(functionDefinitionAst); }
internal SymbolDetails( SymbolReference symbolReference, Runspace runspace) { this.SymbolReference = symbolReference; // If the symbol is a command, get its documentation if (symbolReference.SymbolType == SymbolType.Function) { CommandInfo commandInfo = CommandHelpers.GetCommandInfo( symbolReference.SymbolName, runspace); this.Documentation = CommandHelpers.GetCommandSynopsis( commandInfo, runspace); this.DisplayString = "function " + symbolReference.SymbolName; } else if (symbolReference.SymbolType == SymbolType.Parameter) { // TODO: Get parameter help this.DisplayString = "(parameter) " + symbolReference.SymbolName; } else if (symbolReference.SymbolType == SymbolType.Variable) { this.DisplayString = symbolReference.SymbolName; } }
/// <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 descion 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 = 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> /// Constructs an instance of a ParameterSetSignatures object /// </summary> /// <param name="commandInfoSet">Collection of parameter set info</param> /// <param name="foundSymbol"> The SymbolReference of the command</param> public ParameterSetSignatures(IEnumerable<CommandParameterSetInfo> commandInfoSet, SymbolReference foundSymbol) { List<ParameterSetSignature> paramSetSignatures = new List<ParameterSetSignature>(); foreach (CommandParameterSetInfo setInfo in commandInfoSet) { paramSetSignatures.Add(new ParameterSetSignature(setInfo)); } Signatures = paramSetSignatures.ToArray(); CommandName = foundSymbol.ScriptRegion.Text; ScriptRegion = foundSymbol.ScriptRegion; }
/// <summary> /// Finds the definition of the symbol /// </summary> /// <param name="scriptAst">The abstract syntax tree of the given script</param> /// <param name="symbolReference">The symbol that we are looking for the definition of</param> /// <returns>A SymbolReference of the definition of the symbolReference</returns> public static SymbolReference FindDefinitionOfSymbol( Ast scriptAst, SymbolReference symbolReference) { FindDeclartionVisitor declarationVisitor = new FindDeclartionVisitor( symbolReference); scriptAst.Visit(declarationVisitor); return declarationVisitor.FoundDeclartion; }
/// <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 descion 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> /// Decides if the current variable expression is the right defition for /// the symbol being searched for. The defintion of the symbol will be a of type /// SymbolType.Variable and have the same name as the symbol /// </summary> /// <param name="variableExpressionAst">A FunctionDefinitionAst in the script's AST</param> /// <returns>A descion to stop searching if the right VariableExpressionAst was found, /// or a decision to continue if it wasn't found</returns> public override AstVisitAction VisitVariableExpression(VariableExpressionAst variableExpressionAst) { if(symbolRef.SymbolType.Equals(SymbolType.Variable) && variableExpressionAst.Extent.Text.Equals(symbolRef.SymbolName, StringComparison.InvariantCultureIgnoreCase)) { this.FoundDeclartion = new SymbolReference( SymbolType.Variable, variableExpressionAst.Extent); return AstVisitAction.StopVisit; } return AstVisitAction.Continue; }
internal SymbolDetails( SymbolReference symbolReference, Runspace runspace) { this.SymbolReference = symbolReference; // If the symbol is a command, get its documentation if (symbolReference.SymbolType == SymbolType.Function) { CommandInfo commandInfo = CommandHelpers.GetCommandInfo( symbolReference.SymbolName, runspace); if (commandInfo != null) { this.Documentation = CommandHelpers.GetCommandSynopsis( commandInfo, runspace); if (commandInfo.CommandType == CommandTypes.Application) { this.DisplayString = "(application) " + symbolReference.SymbolName; } else { this.DisplayString = "function " + symbolReference.SymbolName; } } else { // Command information can't be loaded. This is likely due to // the symbol being a function that is defined in a file that // hasn't been loaded in the runspace yet. this.DisplayString = "function " + symbolReference.SymbolName; } } else if (symbolReference.SymbolType == SymbolType.Parameter) { // TODO: Get parameter help this.DisplayString = "(parameter) " + symbolReference.SymbolName; } else if (symbolReference.SymbolType == SymbolType.Variable) { this.DisplayString = symbolReference.SymbolName; } }
/// <summary> /// Finds all references (including aliases) in a script for the given symbol /// </summary> /// <param name="scriptAst">The abstract syntax tree of the given script</param> /// <param name="symbolReference">The symbol that we are looking for referneces of</param> /// <param name="CmdletToAliasDictionary">Dictionary maping cmdlets to aliases for finding alias references</param> /// <param name="AliasToCmdletDictionary">Dictionary maping aliases to cmdlets for finding alias references</param> /// <returns></returns> public static IEnumerable<SymbolReference> FindReferencesOfSymbol( Ast scriptAst, SymbolReference symbolReference, Dictionary<String, List<String>> CmdletToAliasDictionary, Dictionary<String, String> AliasToCmdletDictionary) { // find the symbol evaluators for the node types we are handling FindReferencesVisitor referencesVisitor = new FindReferencesVisitor( symbolReference, CmdletToAliasDictionary, AliasToCmdletDictionary); scriptAst.Visit(referencesVisitor); return referencesVisitor.FoundReferences; }
/// <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 descion 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> /// Finds all references (including aliases) in a script for the given symbol /// </summary> /// <param name="scriptAst">The abstract syntax tree of the given script</param> /// <param name="symbolReference">The symbol that we are looking for referneces of</param> /// <param name="CmdletToAliasDictionary">Dictionary maping cmdlets to aliases for finding alias references</param> /// <param name="AliasToCmdletDictionary">Dictionary maping aliases to cmdlets for finding alias references</param> /// <returns></returns> static public IEnumerable <SymbolReference> FindReferencesOfSymbol( Ast scriptAst, SymbolReference symbolReference, Dictionary <String, List <String> > CmdletToAliasDictionary, Dictionary <String, String> AliasToCmdletDictionary) { // find the symbol evaluators for the node types we are handling FindReferencesVisitor referencesVisitor = new FindReferencesVisitor( symbolReference, CmdletToAliasDictionary, AliasToCmdletDictionary); scriptAst.Visit(referencesVisitor); return(referencesVisitor.FoundReferences); }
/// <summary> /// Finds the symbol in the script given a file location /// </summary> /// <param name="scriptFile">The details and contents of a open script file</param> /// <param name="lineNumber">The line number of the cursor for the given script</param> /// <param name="columnNumber">The coulumn number of the cursor for the given script</param> /// <returns>A SymbolReference of the symbol found at the given location /// or null if there is no symbol at that location /// </returns> public SymbolReference FindSymbolAtLocation( ScriptFile scriptFile, int lineNumber, int columnNumber) { SymbolReference symbolReference = AstOperations.FindSymbolAtPosition( scriptFile.ScriptAst, lineNumber, columnNumber); if (symbolReference != null) { symbolReference.FilePath = scriptFile.FilePath; } return(symbolReference); }
/// <summary> /// Constructor used when searching for aliases is needed /// </summary> /// <param name="symbolReference">The found symbolReference that other symbols are being compared to</param> /// <param name="CmdletToAliasDictionary">Dictionary maping cmdlets to aliases for finding alias references</param> /// <param name="AliasToCmdletDictionary">Dictionary maping aliases to cmdlets for finding alias references</param> public FindReferencesVisitor( SymbolReference symbolReference, Dictionary<String, List<String>> CmdletToAliasDictionary, Dictionary<String, String> AliasToCmdletDictionary) { this.symbolRef = symbolReference; this.FoundReferences = new List<SymbolReference>(); this.needsAliases = true; this.CmdletToAliasDictionary = CmdletToAliasDictionary; this.AliasToCmdletDictionary = AliasToCmdletDictionary; // Try to get the symbolReference's command name of an alias, // if a command name does not exists (if the symbol isn't an alias to a command) // set symbolRefCommandName to and empty string value AliasToCmdletDictionary.TryGetValue(symbolReference.ScriptRegion.Text, out symbolRefCommandName); if (symbolRefCommandName == null) { symbolRefCommandName = string.Empty; } }
public override AstVisitAction VisitPipeline(PipelineAst pipelineAst) { if (this.lineNumber == pipelineAst.Extent.StartLineNumber) { // Which command is the cursor in? foreach (var commandAst in pipelineAst.PipelineElements.OfType<CommandAst>()) { int trueEndColumnNumber = commandAst.Extent.EndColumnNumber; string currentLine = commandAst.Extent.StartScriptPosition.Line; if (currentLine.Length >= trueEndColumnNumber) { // Get the text left in the line after the command's extent string remainingLine = currentLine.Substring( commandAst.Extent.EndColumnNumber); // Calculate the "true" end column number by finding out how many // whitespace characters are between this command and the next (or // the end of the line). // NOTE: +1 is added to trueEndColumnNumber to account for the position // just after the last character in the command string or script line. int preTrimLength = remainingLine.Length; int postTrimLength = remainingLine.TrimStart().Length; trueEndColumnNumber = commandAst.Extent.EndColumnNumber + (preTrimLength - postTrimLength) + 1; } if (commandAst.Extent.StartColumnNumber <= columnNumber && trueEndColumnNumber >= columnNumber) { this.FoundCommandReference = new SymbolReference( SymbolType.Function, commandAst.CommandElements[0].Extent); return AstVisitAction.StopVisit; } } } return base.VisitPipeline(pipelineAst); }
public override AstVisitAction VisitPipeline(PipelineAst pipelineAst) { if (this.lineNumber == pipelineAst.Extent.StartLineNumber) { // Which command is the cursor in? foreach (var commandAst in pipelineAst.PipelineElements.OfType <CommandAst>()) { int trueEndColumnNumber = commandAst.Extent.EndColumnNumber; string currentLine = commandAst.Extent.StartScriptPosition.Line; if (currentLine.Length >= trueEndColumnNumber) { // Get the text left in the line after the command's extent string remainingLine = currentLine.Substring( commandAst.Extent.EndColumnNumber); // Calculate the "true" end column number by finding out how many // whitespace characters are between this command and the next (or // the end of the line). // NOTE: +1 is added to trueEndColumnNumber to account for the position // just after the last character in the command string or script line. int preTrimLength = remainingLine.Length; int postTrimLength = remainingLine.TrimStart().Length; trueEndColumnNumber = commandAst.Extent.EndColumnNumber + (preTrimLength - postTrimLength) + 1; } if (commandAst.Extent.StartColumnNumber <= columnNumber && trueEndColumnNumber >= columnNumber) { this.FoundCommandReference = new SymbolReference( SymbolType.Function, commandAst.CommandElements[0].Extent); return(AstVisitAction.StopVisit); } } } return(base.VisitPipeline(pipelineAst)); }
/// <summary> /// Finds the parameter set hints of a specific command (determined by a given file location) /// </summary> /// <param name="file">The details and contents of a open script file</param> /// <param name="lineNumber">The line number of the cursor for the given script</param> /// <param name="columnNumber">The coulumn number of the cursor for the given script</param> /// <returns>ParameterSetSignatures</returns> public async Task <ParameterSetSignatures> FindParameterSetsInFile( ScriptFile file, int lineNumber, int columnNumber) { SymbolReference foundSymbol = AstOperations.FindCommandAtPosition( file.ScriptAst, lineNumber, columnNumber); if (foundSymbol != null) { CommandInfo commandInfo = await CommandHelpers.GetCommandInfo( foundSymbol.SymbolName, this.powerShellContext); if (commandInfo != null) { try { IEnumerable <CommandParameterSetInfo> commandParamSets = commandInfo.ParameterSets; return(new ParameterSetSignatures(commandParamSets, foundSymbol)); } catch (InvalidOperationException) { // For some commands there are no paramsets (like applications). Until // the valid command types are better understood, catch this exception // which gets raised when there are no ParameterSets for the command type. return(null); } } else { return(null); } } else { return(null); } }
/// <summary> /// Check if the left hand side of an assignmentStatementAst is a VariableExpressionAst /// with the same name as that of symbolRef. /// </summary> /// <param name="assignmentStatementAst">An AssignmentStatementAst</param> /// <returns>A decision to stop searching if the right VariableExpressionAst was found, /// or a decision to continue if it wasn't found</returns> public override AstVisitAction VisitAssignmentStatement(AssignmentStatementAst assignmentStatementAst) { if (variableName == null) { return(AstVisitAction.Continue); } // We want to check VariableExpressionAsts from within this AssignmentStatementAst so we visit it. FindDeclarationVariableExpressionVisitor visitor = new FindDeclarationVariableExpressionVisitor(symbolRef); assignmentStatementAst.Left.Visit(visitor); if (visitor.FoundDeclaration != null) { FoundDeclaration = visitor.FoundDeclaration; return(AstVisitAction.StopVisit); } return(AstVisitAction.Continue); }
/// <summary> /// Constructor used when searching for aliases is needed /// </summary> /// <param name="symbolReference">The found symbolReference that other symbols are being compared to</param> /// <param name="CmdletToAliasDictionary">Dictionary maping cmdlets to aliases for finding alias references</param> /// <param name="AliasToCmdletDictionary">Dictionary maping aliases to cmdlets for finding alias references</param> public FindReferencesVisitor( SymbolReference symbolReference, Dictionary <String, List <String> > CmdletToAliasDictionary, Dictionary <String, String> AliasToCmdletDictionary) { this.symbolRef = symbolReference; this.FoundReferences = new List <SymbolReference>(); this.needsAliases = true; this.CmdletToAliasDictionary = CmdletToAliasDictionary; this.AliasToCmdletDictionary = AliasToCmdletDictionary; // Try to get the symbolReference's command name of an alias, // if a command name does not exists (if the symbol isn't an alias to a command) // set symbolRefCommandName to and empty string value AliasToCmdletDictionary.TryGetValue(symbolReference.ScriptRegion.Text, out symbolRefCommandName); if (symbolRefCommandName == null) { symbolRefCommandName = string.Empty; } }
private async Task <SymbolReference> FindDeclarationForBuiltinCommand( CommandInfo cmdInfo, SymbolReference foundSymbol, Workspace workspace) { SymbolReference foundDefinition = null; if (cmdInfo != null) { int index = 0; ScriptFile[] nestedModuleFiles; CommandInfo commandInfo = await CommandHelpers.GetCommandInfo( foundSymbol.SymbolName, this.powerShellContext); nestedModuleFiles = GetBuiltinCommandScriptFiles( commandInfo.Module, workspace); while (foundDefinition == null && index < nestedModuleFiles.Length) { foundDefinition = AstOperations.FindDefinitionOfSymbol( nestedModuleFiles[index].ScriptAst, foundSymbol); if (foundDefinition != null) { foundDefinition.FilePath = nestedModuleFiles[index].FilePath; } index++; } } return(foundDefinition); }
/// <summary> /// Finds the definition of a symbol in the script file or any of the /// files that it references. /// </summary> /// <param name="sourceFile">The initial script file to be searched for the symbol's definition.</param> /// <param name="foundSymbol">The symbol for which a definition will be found.</param> /// <param name="workspace">The Workspace to which the ScriptFile belongs.</param> /// <returns>The resulting GetDefinitionResult for the symbol's definition.</returns> public async Task <GetDefinitionResult> GetDefinitionOfSymbol( ScriptFile sourceFile, SymbolReference foundSymbol, Workspace workspace) { Validate.IsNotNull("sourceFile", sourceFile); Validate.IsNotNull("foundSymbol", foundSymbol); Validate.IsNotNull("workspace", workspace); ScriptFile[] referencedFiles = workspace.ExpandScriptReferences( sourceFile); var filesSearched = new HashSet <string>(StringComparer.OrdinalIgnoreCase); // look through the referenced files until definition is found // or there are no more file to look through SymbolReference foundDefinition = null; for (int i = 0; i < referencedFiles.Length; i++) { foundDefinition = AstOperations.FindDefinitionOfSymbol( referencedFiles[i].ScriptAst, foundSymbol); filesSearched.Add(referencedFiles[i].FilePath); if (foundDefinition != null) { foundDefinition.FilePath = referencedFiles[i].FilePath; break; } } // if the definition the not found in referenced files // look for it in all the files in the workspace if (foundDefinition == null) { // Get a list of all powershell files in the workspace path var allFiles = workspace.EnumeratePSFiles(); foreach (var file in allFiles) { if (filesSearched.Contains(file)) { continue; } Token[] tokens = null; ParseError[] parseErrors = null; foundDefinition = AstOperations.FindDefinitionOfSymbol( Parser.ParseFile(file, out tokens, out parseErrors), foundSymbol); filesSearched.Add(file); if (foundDefinition != null) { foundDefinition.FilePath = file; break; } } } // if definition is not found in file in the workspace // look for it in the builtin commands if (foundDefinition == null) { CommandInfo cmdInfo = await CommandHelpers.GetCommandInfo( foundSymbol.SymbolName, this.powerShellContext); foundDefinition = FindDeclarationForBuiltinCommand( cmdInfo, foundSymbol, workspace); } return(foundDefinition != null ? new GetDefinitionResult(foundDefinition) : null); }
/// <summary> /// Finds all the references of a symbol /// </summary> /// <param name="foundSymbol">The symbol to find all references for</param> /// <param name="referencedFiles">An array of scriptFiles too search for references in</param> /// <returns>FindReferencesResult</returns> public async Task<FindReferencesResult> FindReferencesOfSymbol( SymbolReference foundSymbol, ScriptFile[] referencedFiles) { if (foundSymbol != null) { int symbolOffset = referencedFiles[0].GetOffsetAtPosition( foundSymbol.ScriptRegion.StartLineNumber, foundSymbol.ScriptRegion.StartColumnNumber); // Make sure aliases have been loaded await GetAliases(); List<SymbolReference> symbolReferences = new List<SymbolReference>(); foreach (ScriptFile file in referencedFiles) { IEnumerable<SymbolReference> symbolReferencesinFile = AstOperations .FindReferencesOfSymbol( file.ScriptAst, foundSymbol, CmdletToAliasDictionary, AliasToCmdletDictionary) .Select( reference => { reference.SourceLine = file.GetLine(reference.ScriptRegion.StartLineNumber); reference.FilePath = file.FilePath; return reference; }); symbolReferences.AddRange(symbolReferencesinFile); } return new FindReferencesResult { SymbolFileOffset = symbolOffset, SymbolName = foundSymbol.SymbolName, FoundReferences = symbolReferences }; } else { return null; } }
public FindDeclartionVisitor(SymbolReference symbolRef) { this.symbolRef = symbolRef; }
/// <summary> /// Finds all the references of a symbol /// </summary> /// <param name="foundSymbol">The symbol to find all references for</param> /// <param name="referencedFiles">An array of scriptFiles too search for references in</param> /// <param name="workspace">The workspace that will be searched for symbols</param> /// <returns>FindReferencesResult</returns> public async Task <FindReferencesResult> FindReferencesOfSymbol( SymbolReference foundSymbol, ScriptFile[] referencedFiles, Workspace workspace) { if (foundSymbol != null) { int symbolOffset = referencedFiles[0].GetOffsetAtPosition( foundSymbol.ScriptRegion.StartLineNumber, foundSymbol.ScriptRegion.StartColumnNumber); // Make sure aliases have been loaded await GetAliases(); // We want to look for references first in referenced files, hence we use ordered dictionary var fileMap = new OrderedDictionary(StringComparer.OrdinalIgnoreCase); foreach (ScriptFile file in referencedFiles) { fileMap.Add(file.FilePath, file); } var allFiles = workspace.EnumeratePSFiles(); foreach (var file in allFiles) { if (!fileMap.Contains(file)) { fileMap.Add(file, new ScriptFile(file, null, this.powerShellContext.LocalPowerShellVersion.Version)); } } List <SymbolReference> symbolReferences = new List <SymbolReference>(); foreach (var fileName in fileMap.Keys) { var file = (ScriptFile)fileMap[fileName]; IEnumerable <SymbolReference> symbolReferencesinFile = AstOperations .FindReferencesOfSymbol( file.ScriptAst, foundSymbol, CmdletToAliasDictionary, AliasToCmdletDictionary) .Select( reference => { try { reference.SourceLine = file.GetLine(reference.ScriptRegion.StartLineNumber); } catch (ArgumentOutOfRangeException e) { reference.SourceLine = string.Empty; this.logger.WriteException("Found reference is out of range in script file", e); } reference.FilePath = file.FilePath; return(reference); }); symbolReferences.AddRange(symbolReferencesinFile); } return (new FindReferencesResult { SymbolFileOffset = symbolOffset, SymbolName = foundSymbol.SymbolName, FoundReferences = symbolReferences }); } else { return(null); } }
/// <summary> /// Constructor used when searching for aliases is not needed /// </summary> /// <param name="foundSymbol">The found symbolReference that other symbols are being compared to</param> public FindReferencesVisitor(SymbolReference foundSymbol) { this.symbolRef = foundSymbol; this.FoundReferences = new List<SymbolReference>(); this.needsAliases = false; }
/// <summary> /// Constructs an instance of a ParameterSetSignatures object /// </summary> /// <param name="commandInfoSet">Collection of parameter set info</param> /// <param name="foundSymbol"> The SymbolReference of the command</param> public ParameterSetSignatures(IEnumerable <CommandParameterSetInfo> commandInfoSet, SymbolReference foundSymbol) { List <ParameterSetSignature> paramSetSignatures = new List <ParameterSetSignature>(); foreach (CommandParameterSetInfo setInfo in commandInfoSet) { paramSetSignatures.Add(new ParameterSetSignature(setInfo)); } Signatures = paramSetSignatures.ToArray(); CommandName = foundSymbol.ScriptRegion.Text; ScriptRegion = foundSymbol.ScriptRegion; }
/// <summary> /// Finds the definition of a symbol in the script file or any of the /// files that it references. /// </summary> /// <param name="sourceFile">The initial script file to be searched for the symbol's definition.</param> /// <param name="foundSymbol">The symbol for which a definition will be found.</param> /// <param name="workspace">The Workspace to which the ScriptFile belongs.</param> /// <returns>The resulting GetDefinitionResult for the symbol's definition.</returns> public async Task <GetDefinitionResult> GetDefinitionOfSymbolAsync( ScriptFile sourceFile, SymbolReference foundSymbol, Workspace workspace) { Validate.IsNotNull(nameof(sourceFile), sourceFile); Validate.IsNotNull(nameof(foundSymbol), foundSymbol); Validate.IsNotNull(nameof(workspace), workspace); ScriptFile[] referencedFiles = workspace.ExpandScriptReferences( sourceFile); var filesSearched = new HashSet <string>(StringComparer.OrdinalIgnoreCase); // look through the referenced files until definition is found // or there are no more file to look through SymbolReference foundDefinition = null; foreach (ScriptFile scriptFile in referencedFiles) { foundDefinition = AstOperations.FindDefinitionOfSymbol( scriptFile.ScriptAst, foundSymbol); filesSearched.Add(scriptFile.FilePath); if (foundDefinition != null) { foundDefinition.FilePath = scriptFile.FilePath; break; } if (foundSymbol.SymbolType == SymbolType.Function) { // Dot-sourcing is parsed as a "Function" Symbol. string dotSourcedPath = GetDotSourcedPath(foundSymbol, workspace, scriptFile); if (scriptFile.FilePath == dotSourcedPath) { foundDefinition = new SymbolReference(SymbolType.Function, foundSymbol.SymbolName, scriptFile.ScriptAst.Extent, scriptFile.FilePath); break; } } } // if the definition the not found in referenced files // look for it in all the files in the workspace if (foundDefinition == null) { // Get a list of all powershell files in the workspace path IEnumerable <string> allFiles = workspace.EnumeratePSFiles(); foreach (string file in allFiles) { if (filesSearched.Contains(file)) { continue; } Token[] tokens = null; ParseError[] parseErrors = null; foundDefinition = AstOperations.FindDefinitionOfSymbol( Parser.ParseFile(file, out tokens, out parseErrors), foundSymbol); filesSearched.Add(file); if (foundDefinition != null) { foundDefinition.FilePath = file; break; } } } // if definition is not found in file in the workspace // look for it in the builtin commands if (foundDefinition == null) { CommandInfo cmdInfo = await CommandHelpers.GetCommandInfoAsync( foundSymbol.SymbolName, _powerShellContext); foundDefinition = FindDeclarationForBuiltinCommand( cmdInfo, foundSymbol, workspace); } return(foundDefinition != null ? new GetDefinitionResult(foundDefinition) : null); }
/// <summary> /// Finds all references (not including aliases) in a script for the given symbol /// </summary> /// <param name="scriptAst">The abstract syntax tree of the given script</param> /// <param name="foundSymbol">The symbol that we are looking for referneces of</param> /// <param name="needsAliases">If this reference search needs aliases. /// This should always be false and used for occurence requests</param> /// <returns>A collection of SymbolReference objects that are refrences to the symbolRefrence /// not including aliases</returns> public static IEnumerable<SymbolReference> FindReferencesOfSymbol( ScriptBlockAst scriptAst, SymbolReference foundSymbol, bool needsAliases) { FindReferencesVisitor referencesVisitor = new FindReferencesVisitor(foundSymbol); scriptAst.Visit(referencesVisitor); return referencesVisitor.FoundReferences; }
/// <summary> /// Finds all the references of a symbol /// </summary> /// <param name="foundSymbol">The symbol to find all references for</param> /// <param name="referencedFiles">An array of scriptFiles too search for references in</param> /// <param name="workspace">The workspace that will be searched for symbols</param> /// <returns>FindReferencesResult</returns> public async Task <FindReferencesResult> FindReferencesOfSymbolAsync( SymbolReference foundSymbol, ScriptFile[] referencedFiles, Workspace workspace) { if (foundSymbol == null) { return(null); } int symbolOffset = referencedFiles[0].GetOffsetAtPosition( foundSymbol.ScriptRegion.StartLineNumber, foundSymbol.ScriptRegion.StartColumnNumber); // Make sure aliases have been loaded await GetAliasesAsync(); // We want to look for references first in referenced files, hence we use ordered dictionary // TODO: File system case-sensitivity is based on filesystem not OS, but OS is a much cheaper heuristic var fileMap = RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? new OrderedDictionary() : new OrderedDictionary(StringComparer.OrdinalIgnoreCase); foreach (ScriptFile scriptFile in referencedFiles) { fileMap[scriptFile.FilePath] = scriptFile; } foreach (string filePath in workspace.EnumeratePSFiles()) { if (!fileMap.Contains(filePath)) { if (!workspace.TryGetFile(filePath, out ScriptFile scriptFile)) { // If we can't access the file for some reason, just ignore it continue; } fileMap[filePath] = scriptFile; } } var symbolReferences = new List <SymbolReference>(); foreach (object fileName in fileMap.Keys) { var file = (ScriptFile)fileMap[fileName]; await _aliasHandle.WaitAsync(); try { IEnumerable <SymbolReference> references = AstOperations.FindReferencesOfSymbol( file.ScriptAst, foundSymbol, _cmdletToAliasDictionary, _aliasToCmdletDictionary); foreach (SymbolReference reference in references) { try { reference.SourceLine = file.GetLine(reference.ScriptRegion.StartLineNumber); } catch (ArgumentOutOfRangeException e) { reference.SourceLine = string.Empty; _logger.WriteException("Found reference is out of range in script file", e); } reference.FilePath = file.FilePath; symbolReferences.Add(reference); } } finally { _aliasHandle.Release(); } } return(new FindReferencesResult { SymbolFileOffset = symbolOffset, SymbolName = foundSymbol.SymbolName, FoundReferences = symbolReferences }); }
/// <summary> /// Constructor used when searching for aliases is not needed /// </summary> /// <param name="foundSymbol">The found symbolReference that other symbols are being compared to</param> public FindReferencesVisitor(SymbolReference foundSymbol) { this.symbolRef = foundSymbol; this.FoundReferences = new List <SymbolReference>(); this.needsAliases = false; }
/// <summary> /// Finds all the references of a symbol /// </summary> /// <param name="foundSymbol">The symbol to find all references for</param> /// <param name="referencedFiles">An array of scriptFiles too search for references in</param> /// <param name="workspace">The workspace that will be searched for symbols</param> /// <returns>FindReferencesResult</returns> public async Task <FindReferencesResult> FindReferencesOfSymbol( SymbolReference foundSymbol, ScriptFile[] referencedFiles, Workspace workspace) { if (foundSymbol == null) { return(null); } int symbolOffset = referencedFiles[0].GetOffsetAtPosition( foundSymbol.ScriptRegion.StartLineNumber, foundSymbol.ScriptRegion.StartColumnNumber); // Make sure aliases have been loaded await GetAliases(); // We want to look for references first in referenced files, hence we use ordered dictionary // TODO: File system case-sensitivity is based on filesystem not OS, but OS is a much cheaper heuristic #if CoreCLR // The RuntimeInformation.IsOSPlatform is not supported in .NET Framework var fileMap = RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? new OrderedDictionary() : new OrderedDictionary(StringComparer.OrdinalIgnoreCase); #else var fileMap = new OrderedDictionary(StringComparer.OrdinalIgnoreCase); #endif foreach (ScriptFile file in referencedFiles) { fileMap.Add(file.FilePath, file); } foreach (string file in workspace.EnumeratePSFiles()) { if (!fileMap.Contains(file)) { ScriptFile scriptFile; try { scriptFile = workspace.GetFile(file); } catch (Exception e) when(e is IOException || e is SecurityException || e is FileNotFoundException || e is DirectoryNotFoundException || e is PathTooLongException || e is UnauthorizedAccessException) { // If we can't access the file for some reason, just ignore it continue; } fileMap.Add(file, scriptFile); } } var symbolReferences = new List <SymbolReference>(); foreach (object fileName in fileMap.Keys) { var file = (ScriptFile)fileMap[fileName]; IEnumerable <SymbolReference> references = AstOperations.FindReferencesOfSymbol( file.ScriptAst, foundSymbol, _cmdletToAliasDictionary, _aliasToCmdletDictionary); foreach (SymbolReference reference in references) { try { reference.SourceLine = file.GetLine(reference.ScriptRegion.StartLineNumber); } catch (ArgumentOutOfRangeException e) { reference.SourceLine = string.Empty; _logger.WriteException("Found reference is out of range in script file", e); } reference.FilePath = file.FilePath; symbolReferences.Add(reference); } } return(new FindReferencesResult { SymbolFileOffset = symbolOffset, SymbolName = foundSymbol.SymbolName, FoundReferences = symbolReferences }); }
/// <summary> /// Finds the definition of a symbol in the script file or any of the /// files that it references. /// </summary> /// <param name="sourceFile">The initial script file to be searched for the symbol's definition.</param> /// <param name="foundSymbol">The symbol for which a definition will be found.</param> /// <param name="workspace">The Workspace to which the ScriptFile belongs.</param> /// <returns>The resulting GetDefinitionResult for the symbol's definition.</returns> public async Task<GetDefinitionResult> GetDefinitionOfSymbol( ScriptFile sourceFile, SymbolReference foundSymbol, Workspace workspace) { Validate.IsNotNull("sourceFile", sourceFile); Validate.IsNotNull("foundSymbol", foundSymbol); Validate.IsNotNull("workspace", workspace); ScriptFile[] referencedFiles = workspace.ExpandScriptReferences( sourceFile); // look through the referenced files until definition is found // or there are no more file to look through SymbolReference foundDefinition = null; for (int i = 0; i < referencedFiles.Length; i++) { foundDefinition = AstOperations.FindDefinitionOfSymbol( referencedFiles[i].ScriptAst, foundSymbol); if (foundDefinition != null) { foundDefinition.FilePath = referencedFiles[i].FilePath; break; } } // if definition is not found in referenced files // look for it in the builtin commands if (foundDefinition == null) { CommandInfo cmdInfo = await GetCommandInfo(foundSymbol.SymbolName); foundDefinition = await FindDeclarationForBuiltinCommand( cmdInfo, foundSymbol, workspace); } return foundDefinition != null ? new GetDefinitionResult(foundDefinition) : null; }
/// <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 descion 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; }
private async Task<SymbolReference> FindDeclarationForBuiltinCommand( CommandInfo cmdInfo, SymbolReference foundSymbol, Workspace workspace) { SymbolReference foundDefinition = null; if (cmdInfo != null) { int index = 0; ScriptFile[] nestedModuleFiles; CommandInfo commandInfo = await GetCommandInfo(foundSymbol.SymbolName); nestedModuleFiles = GetBuiltinCommandScriptFiles( commandInfo.Module, workspace); while (foundDefinition == null && index < nestedModuleFiles.Length) { foundDefinition = AstOperations.FindDefinitionOfSymbol( nestedModuleFiles[index].ScriptAst, foundSymbol); if (foundDefinition != null) { foundDefinition.FilePath = nestedModuleFiles[index].FilePath; } index++; } } return foundDefinition; }