diff --git a/src/PowerShellEditorServices/Services/CodeLens/ICodeLensProvider.cs b/src/PowerShellEditorServices/Services/CodeLens/ICodeLensProvider.cs index 0221e5f1e..ff4ba33e1 100644 --- a/src/PowerShellEditorServices/Services/CodeLens/ICodeLensProvider.cs +++ b/src/PowerShellEditorServices/Services/CodeLens/ICodeLensProvider.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +using System.Threading.Tasks; using Microsoft.PowerShell.EditorServices.Services.TextDocument; using OmniSharp.Extensions.LanguageServer.Protocol.Models; @@ -34,13 +35,12 @@ internal interface ICodeLensProvider /// The CodeLens to resolve. /// /// - /// A CancellationToken which can be used to cancel the - /// request. + /// The ScriptFile to resolve it in (sometimes unused). /// /// /// A Task which returns the resolved CodeLens when completed. /// - CodeLens ResolveCodeLens( + Task ResolveCodeLens( CodeLens codeLens, ScriptFile scriptFile); } diff --git a/src/PowerShellEditorServices/Services/CodeLens/PesterCodeLensProvider.cs b/src/PowerShellEditorServices/Services/CodeLens/PesterCodeLensProvider.cs index da67d3aaf..dc6fc91e5 100644 --- a/src/PowerShellEditorServices/Services/CodeLens/PesterCodeLensProvider.cs +++ b/src/PowerShellEditorServices/Services/CodeLens/PesterCodeLensProvider.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System; using System.Collections.Generic; +using System.Threading.Tasks; using Microsoft.PowerShell.EditorServices.Services; using Microsoft.PowerShell.EditorServices.Services.Symbols; using Microsoft.PowerShell.EditorServices.Services.TextDocument; @@ -133,11 +134,11 @@ public CodeLens[] ProvideCodeLenses(ScriptFile scriptFile) /// The code lens to resolve. /// The script file. /// The given CodeLens, wrapped in a task. - public CodeLens ResolveCodeLens(CodeLens codeLens, ScriptFile scriptFile) + public Task ResolveCodeLens(CodeLens codeLens, ScriptFile scriptFile) { // This provider has no specific behavior for // resolving CodeLenses. - return codeLens; + return Task.FromResult(codeLens); } } } diff --git a/src/PowerShellEditorServices/Services/CodeLens/ReferencesCodeLensProvider.cs b/src/PowerShellEditorServices/Services/CodeLens/ReferencesCodeLensProvider.cs index 84119ee81..e56dc1153 100644 --- a/src/PowerShellEditorServices/Services/CodeLens/ReferencesCodeLensProvider.cs +++ b/src/PowerShellEditorServices/Services/CodeLens/ReferencesCodeLensProvider.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Text; +using System.Threading.Tasks; using Microsoft.PowerShell.EditorServices.Services; using Microsoft.PowerShell.EditorServices.Services.Symbols; using Microsoft.PowerShell.EditorServices.Services.TextDocument; @@ -79,10 +80,10 @@ public CodeLens[] ProvideCodeLenses(ScriptFile scriptFile) /// Take a codelens and create a new codelens object with updated references. /// /// The old code lens to get updated references for. + /// /// A new code lens object describing the same data as the old one but with updated references. - public CodeLens ResolveCodeLens(CodeLens codeLens, ScriptFile scriptFile) + public async Task ResolveCodeLens(CodeLens codeLens, ScriptFile scriptFile) { - ScriptFile[] references = _workspaceService.ExpandScriptReferences( scriptFile); @@ -91,10 +92,10 @@ public CodeLens ResolveCodeLens(CodeLens codeLens, ScriptFile scriptFile) codeLens.Range.Start.Line + 1, codeLens.Range.Start.Character + 1); - List referencesResult = _symbolsService.FindReferencesOfSymbol( + List referencesResult = await _symbolsService.FindReferencesOfSymbol( foundSymbol, references, - _workspaceService); + _workspaceService).ConfigureAwait(false); Location[] referenceLocations; if (referencesResult == null) diff --git a/src/PowerShellEditorServices/Services/PowerShell/Utility/CommandHelpers.cs b/src/PowerShellEditorServices/Services/PowerShell/Utility/CommandHelpers.cs index 15f6845ae..9c83169b7 100644 --- a/src/PowerShellEditorServices/Services/PowerShell/Utility/CommandHelpers.cs +++ b/src/PowerShellEditorServices/Services/PowerShell/Utility/CommandHelpers.cs @@ -17,8 +17,8 @@ namespace Microsoft.PowerShell.EditorServices.Services.PowerShell.Utility /// internal static class CommandHelpers { - private static readonly HashSet s_nounExclusionList = new HashSet - { + private static readonly HashSet s_nounExclusionList = new() + { // PowerShellGet v2 nouns "CredsFromCredentialProvider", "DscResource", @@ -36,8 +36,8 @@ internal static class CommandHelpers }; // This is used when a noun exists in multiple modules (for example, "Command" is used in Microsoft.PowerShell.Core and also PowerShellGet) - private static readonly HashSet s_cmdletExclusionList = new HashSet - { + private static readonly HashSet s_cmdletExclusionList = new() + { // Commands in PowerShellGet with conflicting nouns "Find-Command", "Find-Module", @@ -49,17 +49,17 @@ internal static class CommandHelpers "Update-ModuleManifest", }; - private static readonly ConcurrentDictionary s_commandInfoCache = - new ConcurrentDictionary(); - - private static readonly ConcurrentDictionary s_synopsisCache = - new ConcurrentDictionary(); + private static readonly ConcurrentDictionary s_commandInfoCache = new(); + private static readonly ConcurrentDictionary s_synopsisCache = new(); + private static readonly ConcurrentDictionary> s_cmdletToAliasCache = new(System.StringComparer.OrdinalIgnoreCase); + private static readonly ConcurrentDictionary s_aliasToCmdletCache = new(System.StringComparer.OrdinalIgnoreCase); /// /// Gets the CommandInfo instance for a command with a particular name. /// /// The name of the command. - /// The PowerShellContext to use for running Get-Command. + /// The current runspace. + /// The execution service. /// A CommandInfo object with details about the specified command. public static async Task GetCommandInfoAsync( string commandName, @@ -97,7 +97,11 @@ public static async Task GetCommandInfoAsync( .AddArgument(commandName) .AddParameter("ErrorAction", "Ignore"); - CommandInfo commandInfo = (await executionService.ExecutePSCommandAsync(command, CancellationToken.None).ConfigureAwait(false)).FirstOrDefault(); + IReadOnlyList results = await executionService + .ExecutePSCommandAsync(command, CancellationToken.None) + .ConfigureAwait(false); + + CommandInfo commandInfo = results.Count > 0 ? results[0] : null; // Only cache CmdletInfos since they're exposed in binaries they are likely to not change throughout the session. if (commandInfo?.CommandType == CommandTypes.Cmdlet) @@ -112,8 +116,8 @@ public static async Task GetCommandInfoAsync( /// Gets the command's "Synopsis" documentation section. /// /// The CommandInfo instance for the command. - /// The PowerShellContext to use for getting command documentation. - /// + /// The exeuction service to use for getting command documentation. + /// The synopsis. public static async Task GetCommandSynopsisAsync( CommandInfo commandInfo, IInternalPowerShellExecutionService executionService) @@ -146,13 +150,13 @@ public static async Task GetCommandSynopsisAsync( .AddParameter("Online", false) .AddParameter("ErrorAction", "Ignore"); - IReadOnlyList results = await executionService.ExecutePSCommandAsync(command, CancellationToken.None).ConfigureAwait(false); - PSObject helpObject = results.FirstOrDefault(); + IReadOnlyList results = await executionService + .ExecutePSCommandAsync(command, CancellationToken.None) + .ConfigureAwait(false); // Extract the synopsis string from the object - string synopsisString = - (string)helpObject?.Properties["synopsis"].Value ?? - string.Empty; + PSObject helpObject = results.Count > 0 ? results[0] : null; + string synopsisString = (string)helpObject?.Properties["synopsis"].Value ?? string.Empty; // Only cache cmdlet infos because since they're exposed in binaries, the can never change throughout the session. if (commandInfo.CommandType == CommandTypes.Cmdlet) @@ -168,5 +172,39 @@ public static async Task GetCommandSynopsisAsync( return synopsisString; } + + /// + /// Gets all aliases found in the runspace + /// + /// + public static async Task<(Dictionary>, Dictionary)> GetAliasesAsync(IInternalPowerShellExecutionService executionService) + { + Validate.IsNotNull(nameof(executionService), executionService); + + IEnumerable aliases = await executionService.ExecuteDelegateAsync>( + nameof(GetAliasesAsync), + Execution.ExecutionOptions.Default, + (pwsh, _) => + { + CommandInvocationIntrinsics invokeCommand = pwsh.Runspace.SessionStateProxy.InvokeCommand; + return invokeCommand.GetCommands("*", CommandTypes.Alias, nameIsPattern: true); + }, + CancellationToken.None).ConfigureAwait(false); + + foreach (AliasInfo aliasInfo in aliases) + { + // TODO: When we move to netstandard2.1, we can use another overload which generates + // static delegates and thus reduces allocations. + s_cmdletToAliasCache.AddOrUpdate( + aliasInfo.Definition, + (_) => new List { aliasInfo.Name }, + (_, v) => { v.Add(aliasInfo.Name); return v; }); + + s_aliasToCmdletCache.TryAdd(aliasInfo.Name, aliasInfo.Definition); + } + + return (new Dictionary>(s_cmdletToAliasCache), + new Dictionary(s_aliasToCmdletCache)); + } } } diff --git a/src/PowerShellEditorServices/Services/Symbols/SymbolsService.cs b/src/PowerShellEditorServices/Services/Symbols/SymbolsService.cs index e110b5ef2..bf8e3e8c1 100644 --- a/src/PowerShellEditorServices/Services/Symbols/SymbolsService.cs +++ b/src/PowerShellEditorServices/Services/Symbols/SymbolsService.cs @@ -39,7 +39,6 @@ internal class SymbolsService private readonly ConcurrentDictionary _codeLensProviders; private readonly ConcurrentDictionary _documentSymbolProviders; - #endregion #region Constructors @@ -49,6 +48,10 @@ internal class SymbolsService /// the given Runspace to execute language service operations. /// /// An ILoggerFactory implementation used for writing log messages. + /// + /// + /// + /// public SymbolsService( ILoggerFactory factory, IRunspaceContext runspaceContext, @@ -176,7 +179,7 @@ public static SymbolReference FindSymbolAtLocation( /// An array of scriptFiles too search for references in /// The workspace that will be searched for symbols /// FindReferencesResult - public List FindReferencesOfSymbol( + public async Task> FindReferencesOfSymbol( SymbolReference foundSymbol, ScriptFile[] referencedFiles, WorkspaceService workspace) @@ -186,7 +189,7 @@ public List FindReferencesOfSymbol( return null; } - // NOTE: we use to make sure aliases were loaded but took it out because we needed the pipeline thread. + (Dictionary> cmdletToAliases, Dictionary aliasToCmdlets) = await CommandHelpers.GetAliasesAsync(_executionService).ConfigureAwait(false); // 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 @@ -221,7 +224,8 @@ public List FindReferencesOfSymbol( IEnumerable references = AstOperations.FindReferencesOfSymbol( file.ScriptAst, foundSymbol, - needsAliases: false); + cmdletToAliases, + aliasToCmdlets); foreach (SymbolReference reference in references) { @@ -264,10 +268,7 @@ public static IReadOnlyList FindOccurrencesInFile( return null; } - return AstOperations.FindReferencesOfSymbol( - file.ScriptAst, - foundSymbol, - needsAliases: false).ToArray(); + return AstOperations.FindReferencesOfSymbol(file.ScriptAst, foundSymbol).ToArray(); } /// @@ -306,7 +307,7 @@ public static SymbolReference FindFunctionDefinitionAtLocation( /// The line number at which the symbol can be located. /// The column number at which the symbol can be located. /// - public async Task FindSymbolDetailsAtLocationAsync( + public Task FindSymbolDetailsAtLocationAsync( ScriptFile scriptFile, int lineNumber, int columnNumber) @@ -319,16 +320,14 @@ public async Task FindSymbolDetailsAtLocationAsync( if (symbolReference == null) { - return null; + return Task.FromResult(null); } symbolReference.FilePath = scriptFile.FilePath; - SymbolDetails symbolDetails = await SymbolDetails.CreateAsync( + return SymbolDetails.CreateAsync( symbolReference, _runspaceContext.CurrentRunspace, - _executionService).ConfigureAwait(false); - - return symbolDetails; + _executionService); } /// @@ -446,8 +445,7 @@ public async Task GetDefinitionOfSymbolAsync( if (foundDefinition == null) { // Get a list of all powershell files in the workspace path - IEnumerable allFiles = _workspaceService.EnumeratePSFiles(); - foreach (string file in allFiles) + foreach (string file in _workspaceService.EnumeratePSFiles()) { if (filesSearched.Contains(file)) { @@ -543,7 +541,7 @@ private ScriptFile[] GetBuiltinCommandScriptFiles( } string modPath = moduleInfo.Path; - List scriptFiles = new List(); + List scriptFiles = new(); ScriptFile newFile; // find any files where the moduleInfo's path ends with ps1 or psm1 @@ -598,7 +596,7 @@ public static FunctionDefinitionAst GetFunctionDefinitionForHelpComment( IEnumerable foundAsts = scriptFile.ScriptAst.FindAll( ast => { - if (!(ast is FunctionDefinitionAst fdAst)) + if (ast is not FunctionDefinitionAst fdAst) { return false; } @@ -608,7 +606,7 @@ public static FunctionDefinitionAst GetFunctionDefinitionForHelpComment( }, true); - if (foundAsts == null || !foundAsts.Any()) + if (foundAsts?.Any() != true) { helpLocation = null; return null; diff --git a/src/PowerShellEditorServices/Services/Symbols/Vistors/AstOperations.cs b/src/PowerShellEditorServices/Services/Symbols/Vistors/AstOperations.cs index f312352f1..a0cc38ac4 100644 --- a/src/PowerShellEditorServices/Services/Symbols/Vistors/AstOperations.cs +++ b/src/PowerShellEditorServices/Services/Symbols/Vistors/AstOperations.cs @@ -153,42 +153,21 @@ public static SymbolReference FindCommandAtPosition(Ast scriptAst, int lineNumbe /// /// The abstract syntax tree of the given script /// The symbol that we are looking for referneces of - /// Dictionary maping cmdlets to aliases for finding alias references - /// Dictionary maping aliases to cmdlets for finding alias references + /// Dictionary maping cmdlets to aliases for finding alias references + /// Dictionary maping aliases to cmdlets for finding alias references /// public static IEnumerable FindReferencesOfSymbol( Ast scriptAst, SymbolReference symbolReference, - Dictionary> CmdletToAliasDictionary, - Dictionary AliasToCmdletDictionary) + IDictionary> cmdletToAliasDictionary = default, + IDictionary aliasToCmdletDictionary = default) { // find the symbol evaluators for the node types we are handling - FindReferencesVisitor referencesVisitor = - new FindReferencesVisitor( - symbolReference, - CmdletToAliasDictionary, - AliasToCmdletDictionary); - scriptAst.Visit(referencesVisitor); + FindReferencesVisitor referencesVisitor = new( + symbolReference, + cmdletToAliasDictionary, + aliasToCmdletDictionary); - return referencesVisitor.FoundReferences; - } - - /// - /// Finds all references (not including aliases) in a script for the given symbol - /// - /// The abstract syntax tree of the given script - /// The symbol that we are looking for referneces of - /// If this reference search needs aliases. - /// This should always be false and used for occurence requests - /// A collection of SymbolReference objects that are refrences to the symbolRefrence - /// not including aliases - public static IEnumerable FindReferencesOfSymbol( - ScriptBlockAst scriptAst, - SymbolReference foundSymbol, - bool needsAliases) - { - FindReferencesVisitor referencesVisitor = - new FindReferencesVisitor(foundSymbol); scriptAst.Visit(referencesVisitor); return referencesVisitor.FoundReferences; diff --git a/src/PowerShellEditorServices/Services/Symbols/Vistors/FindReferencesVisitor.cs b/src/PowerShellEditorServices/Services/Symbols/Vistors/FindReferencesVisitor.cs index a0dcb319b..7dae792a7 100644 --- a/src/PowerShellEditorServices/Services/Symbols/Vistors/FindReferencesVisitor.cs +++ b/src/PowerShellEditorServices/Services/Symbols/Vistors/FindReferencesVisitor.cs @@ -12,11 +12,11 @@ namespace Microsoft.PowerShell.EditorServices.Services.Symbols /// internal class FindReferencesVisitor : AstVisitor { - private SymbolReference symbolRef; - private Dictionary> CmdletToAliasDictionary; - private Dictionary AliasToCmdletDictionary; - private string symbolRefCommandName; - private bool needsAliases; + private readonly SymbolReference _symbolRef; + private readonly IDictionary> _cmdletToAliasDictionary; + private readonly IDictionary _aliasToCmdletDictionary; + private readonly string _symbolRefCommandName; + private readonly bool _needsAliases; public List FoundReferences { get; set; } @@ -24,36 +24,35 @@ internal class FindReferencesVisitor : AstVisitor /// Constructor used when searching for aliases is needed /// /// The found symbolReference that other symbols are being compared to - /// Dictionary maping cmdlets to aliases for finding alias references - /// Dictionary maping aliases to cmdlets for finding alias references + /// Dictionary maping cmdlets to aliases for finding alias references + /// Dictionary maping aliases to cmdlets for finding alias references public FindReferencesVisitor( SymbolReference symbolReference, - Dictionary> CmdletToAliasDictionary, - Dictionary AliasToCmdletDictionary) + IDictionary> cmdletToAliasDictionary = default, + IDictionary aliasToCmdletDictionary = default) { - this.symbolRef = symbolReference; - this.FoundReferences = new List(); - 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; } + _symbolRef = symbolReference; + FoundReferences = new List(); - } + if (cmdletToAliasDictionary is null || aliasToCmdletDictionary is null) + { + _needsAliases = false; + return; + } - /// - /// Constructor used when searching for aliases is not needed - /// - /// The found symbolReference that other symbols are being compared to - public FindReferencesVisitor(SymbolReference foundSymbol) - { - this.symbolRef = foundSymbol; - this.FoundReferences = new List(); - this.needsAliases = false; + _needsAliases = true; + _cmdletToAliasDictionary = cmdletToAliasDictionary; + _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 an + // empty string. + aliasToCmdletDictionary.TryGetValue(symbolReference.ScriptRegion.Text, out _symbolRefCommandName); + + if (_symbolRefCommandName == null) + { + _symbolRefCommandName = string.Empty; + } } /// @@ -68,50 +67,44 @@ public override AstVisitAction VisitCommand(CommandAst commandAst) Ast commandNameAst = commandAst.CommandElements[0]; string commandName = commandNameAst.Extent.Text; - if(symbolRef.SymbolType.Equals(SymbolType.Function)) + if (_symbolRef.SymbolType.Equals(SymbolType.Function)) { - if (needsAliases) + if (_needsAliases) { - // Try to get the commandAst's name and aliases, - // if a command does not exists (if the symbol isn't an alias to a command) - // set command to and empty string value string command - // if the aliases do not exist (if the symvol isn't a command that has aliases) + // Try to get the commandAst's name and aliases. + // + // If a command does not exist (if the symbol isn't an alias to a command) set + // command to an empty string value string command. + // + // If the aliases do not exist (if the symbol isn't a command that has aliases) // set aliases to an empty List - string command; - List alaises; - CmdletToAliasDictionary.TryGetValue(commandName, out alaises); - AliasToCmdletDictionary.TryGetValue(commandName, out command); - if (alaises == null) { alaises = new List(); } + _cmdletToAliasDictionary.TryGetValue(commandName, out List aliases); + _aliasToCmdletDictionary.TryGetValue(commandName, out string command); + if (aliases == null) { aliases = new List(); } if (command == null) { command = string.Empty; } - if (symbolRef.SymbolType.Equals(SymbolType.Function)) + // Check if the found symbol's name is the same as the commandAst's name OR + // if the symbol's name is an alias for this commandAst's name (commandAst is a cmdlet) OR + // if the symbol's name is the same as the commandAst's cmdlet name (commandAst is a alias) + if (commandName.Equals(_symbolRef.SymbolName, StringComparison.OrdinalIgnoreCase) + // Note that PowerShell command names and aliases are case insensitive. + || aliases.Exists((match) => string.Equals(match, _symbolRef.ScriptRegion.Text, StringComparison.OrdinalIgnoreCase)) + || command.Equals(_symbolRef.ScriptRegion.Text, StringComparison.OrdinalIgnoreCase) + || (!string.IsNullOrEmpty(command) + && command.Equals(_symbolRefCommandName, StringComparison.OrdinalIgnoreCase))) { - // Check if the found symbol's name is the same as the commandAst's name OR - // if the symbol's name is an alias for this commandAst's name (commandAst is a cmdlet) OR - // if the symbol's name is the same as the commandAst's cmdlet name (commandAst is a alias) - if (commandName.Equals(symbolRef.SymbolName, StringComparison.CurrentCultureIgnoreCase) || - alaises.Contains(symbolRef.ScriptRegion.Text.ToLower()) || - command.Equals(symbolRef.ScriptRegion.Text, StringComparison.CurrentCultureIgnoreCase) || - (!string.IsNullOrEmpty(command) && command.Equals(symbolRefCommandName, StringComparison.CurrentCultureIgnoreCase))) - { - this.FoundReferences.Add(new SymbolReference( - SymbolType.Function, - commandNameAst.Extent)); - } + FoundReferences.Add(new SymbolReference(SymbolType.Function, commandNameAst.Extent)); } - } else // search does not include aliases { - if (commandName.Equals(symbolRef.SymbolName, StringComparison.CurrentCultureIgnoreCase)) + if (commandName.Equals(_symbolRef.SymbolName, StringComparison.OrdinalIgnoreCase)) { - this.FoundReferences.Add(new SymbolReference( - SymbolType.Function, - commandNameAst.Extent)); + FoundReferences.Add(new SymbolReference(SymbolType.Function, commandNameAst.Extent)); } } - } + return base.VisitCommand(commandAst); } @@ -135,12 +128,10 @@ public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst fun File = functionDefinitionAst.Extent.File }; - if (symbolRef.SymbolType.Equals(SymbolType.Function) && - nameExtent.Text.Equals(symbolRef.SymbolName, StringComparison.CurrentCultureIgnoreCase)) + if (_symbolRef.SymbolType.Equals(SymbolType.Function) && + nameExtent.Text.Equals(_symbolRef.SymbolName, StringComparison.CurrentCultureIgnoreCase)) { - this.FoundReferences.Add(new SymbolReference( - SymbolType.Function, - nameExtent)); + FoundReferences.Add(new SymbolReference(SymbolType.Function, nameExtent)); } return base.VisitFunctionDefinition(functionDefinitionAst); } @@ -153,12 +144,10 @@ public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst fun /// A visit action that continues the search for references public override AstVisitAction VisitCommandParameter(CommandParameterAst commandParameterAst) { - if (symbolRef.SymbolType.Equals(SymbolType.Parameter) && - commandParameterAst.Extent.Text.Equals(symbolRef.SymbolName, StringComparison.CurrentCultureIgnoreCase)) + if (_symbolRef.SymbolType.Equals(SymbolType.Parameter) && + commandParameterAst.Extent.Text.Equals(_symbolRef.SymbolName, StringComparison.CurrentCultureIgnoreCase)) { - this.FoundReferences.Add(new SymbolReference( - SymbolType.Parameter, - commandParameterAst.Extent)); + FoundReferences.Add(new SymbolReference(SymbolType.Parameter, commandParameterAst.Extent)); } return AstVisitAction.Continue; } @@ -171,12 +160,10 @@ public override AstVisitAction VisitCommandParameter(CommandParameterAst command /// A visit action that continues the search for references public override AstVisitAction VisitVariableExpression(VariableExpressionAst variableExpressionAst) { - if(symbolRef.SymbolType.Equals(SymbolType.Variable) && - variableExpressionAst.Extent.Text.Equals(symbolRef.SymbolName, StringComparison.CurrentCultureIgnoreCase)) + if (_symbolRef.SymbolType.Equals(SymbolType.Variable) + && variableExpressionAst.Extent.Text.Equals(_symbolRef.SymbolName, StringComparison.CurrentCultureIgnoreCase)) { - this.FoundReferences.Add(new SymbolReference( - SymbolType.Variable, - variableExpressionAst.Extent)); + FoundReferences.Add(new SymbolReference(SymbolType.Variable, variableExpressionAst.Extent)); } return AstVisitAction.Continue; } @@ -186,7 +173,7 @@ private static (int, int) GetStartColumnAndLineNumbersFromAst(FunctionDefinition { int startColumnNumber = ast.Extent.StartColumnNumber; int startLineNumber = ast.Extent.StartLineNumber; - int astOffset = 0; + int astOffset; if (ast.IsFilter) { diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeLensHandlers.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeLensHandlers.cs index 80850d8a5..a6a7c6dd7 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeLensHandlers.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeLensHandlers.cs @@ -75,8 +75,7 @@ public Task Handle(CodeLens request, CancellationToken cancellationTok _workspaceService.GetFile( codeLensData.Uri); - var resolvedCodeLens = originalProvider.ResolveCodeLens(request, scriptFile); - return Task.FromResult(resolvedCodeLens); + return originalProvider.ResolveCodeLens(request, scriptFile); } public void SetCapability(CodeLensCapability capability) diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/ReferencesHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/ReferencesHandler.cs index 0b8560644..ebce705d2 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/ReferencesHandler.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/ReferencesHandler.cs @@ -34,7 +34,7 @@ public PsesReferencesHandler(ILoggerFactory factory, SymbolsService symbolsServi DocumentSelector = LspUtils.PowerShellDocumentSelector }; - public override Task Handle(ReferenceParams request, CancellationToken cancellationToken) + public async override Task Handle(ReferenceParams request, CancellationToken cancellationToken) { ScriptFile scriptFile = _workspaceService.GetFile(request.TextDocument.Uri); @@ -45,10 +45,10 @@ public override Task Handle(ReferenceParams request, Cancella request.Position.Character + 1); List referencesResult = - _symbolsService.FindReferencesOfSymbol( + await _symbolsService.FindReferencesOfSymbol( foundSymbol, _workspaceService.ExpandScriptReferences(scriptFile), - _workspaceService); + _workspaceService).ConfigureAwait(false); var locations = new List(); @@ -64,7 +64,7 @@ public override Task Handle(ReferenceParams request, Cancella } } - return Task.FromResult(new LocationContainer(locations)); + return new LocationContainer(locations); } private static Range GetRangeFromScriptRegion(ScriptRegion scriptRegion) diff --git a/test/PowerShellEditorServices.Test.Shared/References/FindsReferencesOnBuiltInCommandWithAlias.cs b/test/PowerShellEditorServices.Test.Shared/References/FindsReferencesOnBuiltInCommandWithAlias.cs index 1bc7ec8e6..2f39f29c6 100644 --- a/test/PowerShellEditorServices.Test.Shared/References/FindsReferencesOnBuiltInCommandWithAlias.cs +++ b/test/PowerShellEditorServices.Test.Shared/References/FindsReferencesOnBuiltInCommandWithAlias.cs @@ -17,16 +17,4 @@ public static class FindsReferencesOnBuiltInCommandWithAliasData endColumnNumber: 0, endOffset: 0); } - public static class FindsReferencesOnBuiltInAliasData - { - public static readonly ScriptRegion SourceDetails = new( - file: TestUtilities.NormalizePath("References/SimpleFile.ps1"), - text: string.Empty, - startLineNumber: 15, - startColumnNumber: 2, - startOffset: 0, - endLineNumber: 0, - endColumnNumber: 0, - endOffset: 0); - } } diff --git a/test/PowerShellEditorServices.Test/Language/SymbolsServiceTests.cs b/test/PowerShellEditorServices.Test/Language/SymbolsServiceTests.cs index d0d58aa17..24d0a6fbe 100644 --- a/test/PowerShellEditorServices.Test/Language/SymbolsServiceTests.cs +++ b/test/PowerShellEditorServices.Test/Language/SymbolsServiceTests.cs @@ -71,7 +71,7 @@ private Task GetDefinition(ScriptRegion scriptRegion) return symbolsService.GetDefinitionOfSymbolAsync(scriptFile, symbolReference); } - private List GetReferences(ScriptRegion scriptRegion) + private Task> GetReferences(ScriptRegion scriptRegion) { ScriptFile scriptFile = GetScriptFile(scriptRegion); @@ -126,9 +126,9 @@ public async Task FindsFunctionDefinition() } [Fact] - public void FindsReferencesOnFunction() + public async Task FindsReferencesOnFunction() { - List referencesResult = GetReferences(FindsReferencesOnFunctionData.SourceDetails); + List referencesResult = await GetReferences(FindsReferencesOnFunctionData.SourceDetails).ConfigureAwait(true); Assert.Equal(3, referencesResult.Count); Assert.Equal(1, referencesResult[0].ScriptRegion.StartLineNumber); Assert.Equal(10, referencesResult[0].ScriptRegion.StartColumnNumber); @@ -177,9 +177,9 @@ public async Task FindsVariableDefinition() } [Fact] - public void FindsReferencesOnVariable() + public async Task FindsReferencesOnVariable() { - List referencesResult = GetReferences(FindsReferencesOnVariableData.SourceDetails); + List referencesResult = await GetReferences(FindsReferencesOnVariableData.SourceDetails).ConfigureAwait(true); Assert.Equal(3, referencesResult.Count); Assert.Equal(10, referencesResult[referencesResult.Count - 1].ScriptRegion.StartLineNumber); Assert.Equal(13, referencesResult[referencesResult.Count - 1].ScriptRegion.StartColumnNumber); @@ -203,35 +203,27 @@ public void FindsOccurrencesOnParameter() Assert.Equal(3, occurrencesResult[occurrencesResult.Count - 1].ScriptRegion.StartLineNumber); } - [Fact(Skip = "TODO Fix this test. A possible bug in PSES product code.")] - public void FindsReferencesOnCommandWithAlias() + [Fact] + public async Task FindsReferencesOnCommandWithAlias() { - List referencesResult = GetReferences(FindsReferencesOnBuiltInCommandWithAliasData.SourceDetails); + List referencesResult = await GetReferences(FindsReferencesOnBuiltInCommandWithAliasData.SourceDetails).ConfigureAwait(true); Assert.Equal(4, referencesResult.Count); Assert.Equal("gci", referencesResult[1].SymbolName); - Assert.Equal("Get-ChildItem", referencesResult[referencesResult.Count - 1].SymbolName); - } - - [Fact(Skip = "TODO Fix this test. A possible bug in PSES product code.")] - public void FindsReferencesOnAlias() - { - List referencesResult = GetReferences(FindsReferencesOnBuiltInCommandWithAliasData.SourceDetails); - Assert.Equal(4, referencesResult.Count); Assert.Equal("dir", referencesResult[2].SymbolName); Assert.Equal("Get-ChildItem", referencesResult[referencesResult.Count - 1].SymbolName); } [Fact] - public void FindsReferencesOnFileWithReferencesFileB() + public async Task FindsReferencesOnFileWithReferencesFileB() { - List referencesResult = GetReferences(FindsReferencesOnFunctionMultiFileDotSourceFileB.SourceDetails); + List referencesResult = await GetReferences(FindsReferencesOnFunctionMultiFileDotSourceFileB.SourceDetails).ConfigureAwait(true); Assert.Equal(4, referencesResult.Count); } [Fact] - public void FindsReferencesOnFileWithReferencesFileC() + public async Task FindsReferencesOnFileWithReferencesFileC() { - List referencesResult = GetReferences(FindsReferencesOnFunctionMultiFileDotSourceFileC.SourceDetails); + List referencesResult = await GetReferences(FindsReferencesOnFunctionMultiFileDotSourceFileC.SourceDetails).ConfigureAwait(true); Assert.Equal(4, referencesResult.Count); } diff --git a/test/PowerShellEditorServices.Test/Services/Symbols/AstOperationsTests.cs b/test/PowerShellEditorServices.Test/Services/Symbols/AstOperationsTests.cs index 6d9d36e1c..c35bba787 100644 --- a/test/PowerShellEditorServices.Test/Services/Symbols/AstOperationsTests.cs +++ b/test/PowerShellEditorServices.Test/Services/Symbols/AstOperationsTests.cs @@ -7,13 +7,13 @@ using Microsoft.PowerShell.EditorServices.Services.Symbols; using OmniSharp.Extensions.LanguageServer.Protocol.Models; using Xunit; -using Xunit.Abstractions; namespace Microsoft.PowerShell.EditorServices.Test.Services.Symbols { + [Trait("Category", "AstOperations")] public class AstOperationsTests { - private static string s_scriptString = @"function BasicFunction {} + private const string s_scriptString = @"function BasicFunction {} BasicFunction function FunctionWithExtraSpace @@ -36,9 +36,8 @@ function FunctionWithExtraSpace FunctionNameOnDifferentLine "; - private static ScriptBlockAst s_ast = (ScriptBlockAst) ScriptBlock.Create(s_scriptString).Ast; + private static readonly ScriptBlockAst s_ast = (ScriptBlockAst) ScriptBlock.Create(s_scriptString).Ast; - [Trait("Category", "AstOperations")] [Theory] [InlineData(2, 3, "BasicFunction")] [InlineData(7, 18, "FunctionWithExtraSpace")] @@ -50,14 +49,13 @@ public void CanFindSymbolAtPostion(int lineNumber, int columnNumber, string expe Assert.Equal(expectedName, reference.SymbolName); } - [Trait("Category", "AstOperations")] [Theory] - [MemberData(nameof(FindReferencesOfSymbolAtPostionData), parameters: 3)] + [MemberData(nameof(FindReferencesOfSymbolAtPostionData))] public void CanFindReferencesOfSymbolAtPostion(int lineNumber, int columnNumber, Position[] positions) { SymbolReference symbol = AstOperations.FindSymbolAtPosition(s_ast, lineNumber, columnNumber); - IEnumerable references = AstOperations.FindReferencesOfSymbol(s_ast, symbol, needsAliases: false); + IEnumerable references = AstOperations.FindReferencesOfSymbol(s_ast, symbol); int positionsIndex = 0; foreach (SymbolReference reference in references) @@ -69,9 +67,7 @@ public void CanFindReferencesOfSymbolAtPostion(int lineNumber, int columnNumber, } } - public static object[][] FindReferencesOfSymbolAtPostionData => s_findReferencesOfSymbolAtPostionData; - - private static readonly object[][] s_findReferencesOfSymbolAtPostionData = new object[][] + public static object[][] FindReferencesOfSymbolAtPostionData { get; } = new object[][] { new object[] { 2, 3, new[] { new Position(1, 10), new Position(2, 1) } }, new object[] { 7, 18, new[] { new Position(4, 19), new Position(7, 3) } },