From dccea933c78299f4b55cc0a011d27daa9589ee3e Mon Sep 17 00:00:00 2001 From: Robert Holt Date: Tue, 7 Aug 2018 17:41:34 -0700 Subject: [PATCH 1/8] Stop creating new JsonSerializers --- .../CodeLens/CodeLensFeature.cs | 68 +++++++++---------- .../Utility/HashCodeCombiner.cs | 7 ++ 2 files changed, 40 insertions(+), 35 deletions(-) create mode 100644 src/PowerShellEditorServices/Utility/HashCodeCombiner.cs diff --git a/src/PowerShellEditorServices.Host/CodeLens/CodeLensFeature.cs b/src/PowerShellEditorServices.Host/CodeLens/CodeLensFeature.cs index 4392523ac..b219b53a9 100644 --- a/src/PowerShellEditorServices.Host/CodeLens/CodeLensFeature.cs +++ b/src/PowerShellEditorServices.Host/CodeLens/CodeLensFeature.cs @@ -9,6 +9,7 @@ using Microsoft.PowerShell.EditorServices.Utility; using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -21,27 +22,19 @@ internal class CodeLensFeature : FeatureComponentBase, ICodeLenses { - private EditorSession editorSession; + private readonly EditorSession _editorSession; - private JsonSerializer jsonSerializer = - JsonSerializer.Create( - Constants.JsonSerializerSettings); + private readonly JsonSerializer _jsonSerializer; - public CodeLensFeature( + private CodeLensFeature( EditorSession editorSession, - IMessageHandlers messageHandlers, + JsonSerializer jsonSerializer, ILogger logger) : base(logger) { - this.editorSession = editorSession; + _editorSession = editorSession; - messageHandlers.SetRequestHandler( - CodeLensRequest.Type, - this.HandleCodeLensRequest); - - messageHandlers.SetRequestHandler( - CodeLensResolveRequest.Type, - this.HandleCodeLensResolveRequest); + _jsonSerializer = jsonSerializer; } public static CodeLensFeature Create( @@ -51,9 +44,19 @@ public static CodeLensFeature Create( var codeLenses = new CodeLensFeature( editorSession, - components.Get(), + JsonSerializer.Create(Constants.JsonSerializerSettings), components.Get()); + var messageHandlers = components.Get(); + + messageHandlers.SetRequestHandler( + CodeLensRequest.Type, + codeLenses.HandleCodeLensRequest); + + messageHandlers.SetRequestHandler( + CodeLensResolveRequest.Type, + codeLenses.HandleCodeLensResolveRequest); + codeLenses.Providers.Add( new ReferencesCodeLensProvider( editorSession)); @@ -79,28 +82,23 @@ private async Task HandleCodeLensRequest( CodeLensRequest codeLensParams, RequestContext requestContext) { - JsonSerializer jsonSerializer = - JsonSerializer.Create( - Constants.JsonSerializerSettings); - var scriptFile = - this.editorSession.Workspace.GetFile( + this._editorSession.Workspace.GetFile( codeLensParams.TextDocument.Uri); - var codeLenses = - this.ProvideCodeLenses(scriptFile) - .Select( - codeLens => - codeLens.ToProtocolCodeLens( - new CodeLensData - { - Uri = codeLens.File.ClientFilePath, - ProviderId = codeLens.Provider.ProviderId - }, - this.jsonSerializer)) - .ToArray(); + CodeLens[] codeLensResults = ProvideCodeLenses(scriptFile); + + var clMsg = new LanguageServer.CodeLens[codeLensResults.Length]; + for (int i = 0; i < codeLensResults.Length; i++) + { + clMsg[i] = codeLensResults[i].ToProtocolCodeLens(new CodeLensData + { + Uri = codeLensResults[i].File.ClientFilePath, + ProviderId = codeLensResults[i].Provider.ProviderId + }, _jsonSerializer); + } - await requestContext.SendResult(codeLenses); + await requestContext.SendResult(clMsg); } private async Task HandleCodeLensResolveRequest( @@ -119,7 +117,7 @@ private async Task HandleCodeLensResolveRequest( if (originalProvider != null) { ScriptFile scriptFile = - this.editorSession.Workspace.GetFile( + this._editorSession.Workspace.GetFile( codeLensData.Uri); ScriptRegion region = new ScriptRegion @@ -143,7 +141,7 @@ await originalProvider.ResolveCodeLensAsync( await requestContext.SendResult( resolvedCodeLens.ToProtocolCodeLens( - this.jsonSerializer)); + this._jsonSerializer)); } else { diff --git a/src/PowerShellEditorServices/Utility/HashCodeCombiner.cs b/src/PowerShellEditorServices/Utility/HashCodeCombiner.cs new file mode 100644 index 000000000..dc9e6360d --- /dev/null +++ b/src/PowerShellEditorServices/Utility/HashCodeCombiner.cs @@ -0,0 +1,7 @@ +namespace PowerShellEditorServices.Utility +{ + public class HashCodeCombiner + { + + } +} \ No newline at end of file From d9d1d35875faaa41d58e21d27647ecfb04e7bc6f Mon Sep 17 00:00:00 2001 From: Robert Holt Date: Wed, 8 Aug 2018 12:41:17 -0700 Subject: [PATCH 2/8] Reduce allocating operations in CodeLens providers --- .../CodeLens/CodeLensFeature.cs | 91 ++++++--- .../CodeLens/PesterCodeLensProvider.cs | 107 ++++++----- .../CodeLens/ReferencesCodeLensProvider.cs | 178 ++++++++++++------ 3 files changed, 250 insertions(+), 126 deletions(-) diff --git a/src/PowerShellEditorServices.Host/CodeLens/CodeLensFeature.cs b/src/PowerShellEditorServices.Host/CodeLens/CodeLensFeature.cs index b219b53a9..e37938814 100644 --- a/src/PowerShellEditorServices.Host/CodeLens/CodeLensFeature.cs +++ b/src/PowerShellEditorServices.Host/CodeLens/CodeLensFeature.cs @@ -18,25 +18,23 @@ namespace Microsoft.PowerShell.EditorServices.CodeLenses { + /// + /// Implements the CodeLens feature for EditorServices. + /// internal class CodeLensFeature : FeatureComponentBase, ICodeLenses { - private readonly EditorSession _editorSession; - - private readonly JsonSerializer _jsonSerializer; - - private CodeLensFeature( - EditorSession editorSession, - JsonSerializer jsonSerializer, - ILogger logger) - : base(logger) - { - _editorSession = editorSession; - - _jsonSerializer = jsonSerializer; - } + /// + /// Create a new CodeLens instance around a given editor session + /// from the component registry. + /// + /// + /// The component registry to provider other components and to register the CodeLens provider in. + /// + /// The editor session context of the CodeLens provider. + /// A new CodeLens provider for the given editor session. public static CodeLensFeature Create( IComponentRegistry components, EditorSession editorSession) @@ -70,14 +68,53 @@ public static CodeLensFeature Create( return codeLenses; } + /// + /// The editor session context to get workspace and language server data from. + /// + private readonly EditorSession _editorSession; + + /// + /// The json serializer instance for CodeLens object translation. + /// + private readonly JsonSerializer _jsonSerializer; + + /// + /// + /// + /// + /// + /// + private CodeLensFeature( + EditorSession editorSession, + JsonSerializer jsonSerializer, + ILogger logger) + : base(logger) + { + _editorSession = editorSession; + _jsonSerializer = jsonSerializer; + } + + /// + /// Get all the CodeLenses for a given script file. + /// + /// The PowerShell script file to get CodeLenses for. + /// All generated CodeLenses for the given script file. public CodeLens[] ProvideCodeLenses(ScriptFile scriptFile) { - return - this.InvokeProviders(p => p.ProvideCodeLenses(scriptFile)) - .SelectMany(r => r) - .ToArray(); + var acc = new List(); + foreach (CodeLens[] providerResult in InvokeProviders(provider => provider.ProvideCodeLenses(scriptFile))) + { + acc.AddRange(providerResult); + } + + return acc.ToArray(); } + /// + /// Handles a request for CodeLenses from VSCode. + /// + /// Parameters on the CodeLens request that was received. + /// private async Task HandleCodeLensRequest( CodeLensRequest codeLensParams, RequestContext requestContext) @@ -88,19 +125,26 @@ private async Task HandleCodeLensRequest( CodeLens[] codeLensResults = ProvideCodeLenses(scriptFile); - var clMsg = new LanguageServer.CodeLens[codeLensResults.Length]; + var codeLensResponse = new LanguageServer.CodeLens[codeLensResults.Length]; for (int i = 0; i < codeLensResults.Length; i++) { - clMsg[i] = codeLensResults[i].ToProtocolCodeLens(new CodeLensData + codeLensResponse[i] = codeLensResults[i].ToProtocolCodeLens( + new CodeLensData { Uri = codeLensResults[i].File.ClientFilePath, ProviderId = codeLensResults[i].Provider.ProviderId - }, _jsonSerializer); + }, + _jsonSerializer); } - await requestContext.SendResult(clMsg); + await requestContext.SendResult(codeLensResponse); } + /// + /// Handle a CodeLens resolve request from VSCode. + /// + /// The CodeLens to be resolved/updated. + /// private async Task HandleCodeLensResolveRequest( LanguageServer.CodeLens codeLens, RequestContext requestContext) @@ -151,6 +195,9 @@ await requestContext.SendError( } } + /// + /// Represents data expected back in an LSP CodeLens response. + /// private class CodeLensData { public string Uri { get; set; } diff --git a/src/PowerShellEditorServices.Host/CodeLens/PesterCodeLensProvider.cs b/src/PowerShellEditorServices.Host/CodeLens/PesterCodeLensProvider.cs index 61d700bb9..67f00b25a 100644 --- a/src/PowerShellEditorServices.Host/CodeLens/PesterCodeLensProvider.cs +++ b/src/PowerShellEditorServices.Host/CodeLens/PesterCodeLensProvider.cs @@ -15,71 +15,90 @@ namespace Microsoft.PowerShell.EditorServices.CodeLenses { internal class PesterCodeLensProvider : FeatureProviderBase, ICodeLensProvider { - private static char[] QuoteChars = new char[] { '\'', '"'}; + /// + /// The editor session context to provide CodeLenses for. + /// + private EditorSession _editorSession; - private EditorSession editorSession; - private IDocumentSymbolProvider symbolProvider; + /// + /// The symbol provider to get symbols from to build code lenses with. + /// + private IDocumentSymbolProvider _symbolProvider; + /// + /// Create a new Pester CodeLens provider for a given editor session. + /// + /// The editor session context for which to provide Pester CodeLenses. public PesterCodeLensProvider(EditorSession editorSession) { - this.editorSession = editorSession; - this.symbolProvider = new PesterDocumentSymbolProvider(); + _editorSession = editorSession; + _symbolProvider = new PesterDocumentSymbolProvider(); } - private IEnumerable GetPesterLens( + /// + /// Get the Pester CodeLenses for a given Pester symbol. + /// + /// The Pester symbol to get CodeLenses for. + /// The script file the Pester symbol comes from. + /// All CodeLenses for the given Pester symbol. + private CodeLens[] GetPesterLens( PesterSymbolReference pesterSymbol, ScriptFile scriptFile) { - var clientCommands = new ClientCommand[] + var codeLensResults = new CodeLens[] { - new ClientCommand( - "PowerShell.RunPesterTests", - "Run tests", - new object[] - { - scriptFile.ClientFilePath, - false, // Don't debug - pesterSymbol.TestName, - }), + new CodeLens( + this, + scriptFile, + pesterSymbol.ScriptRegion, + new ClientCommand( + "PowerShell.RunPesterTests", + "Run tests", + new object[] { scriptFile.ClientFilePath, false /* No debug */, pesterSymbol.TestName })), - new ClientCommand( - "PowerShell.RunPesterTests", - "Debug tests", - new object[] - { - scriptFile.ClientFilePath, - true, // Run in debugger - pesterSymbol.TestName, - }), + new CodeLens( + this, + scriptFile, + pesterSymbol.ScriptRegion, + new ClientCommand( + "PowerShell.RunPesterTests", + "Debug tests", + new object[] { scriptFile.ClientFilePath, true /* Run in debugger */, pesterSymbol.TestName })), }; - return - clientCommands.Select( - command => - new CodeLens( - this, - scriptFile, - pesterSymbol.ScriptRegion, - command)); + return codeLensResults; } + /// + /// Get all Pester CodeLenses for a given script file. + /// + /// The script file to get Pester CodeLenses for. + /// All Pester CodeLenses for the given script file. public CodeLens[] ProvideCodeLenses(ScriptFile scriptFile) { - var symbols = - this.symbolProvider - .ProvideDocumentSymbols(scriptFile); + var lenses = new List(); + foreach (var symbol in _symbolProvider.ProvideDocumentSymbols(scriptFile)) + { + if (symbol is PesterSymbolReference pesterSymbol) + { + if (pesterSymbol.Command != PesterCommandType.Describe) + { + continue; + } - var lenses = - symbols - .OfType() - .Where(s => s.Command == PesterCommandType.Describe) - .SelectMany(s => this.GetPesterLens(s, scriptFile)) - .Where(codeLens => codeLens != null) - .ToArray(); + lenses.AddRange(GetPesterLens(pesterSymbol, scriptFile)); + } + } - return lenses; + return lenses.ToArray(); } + /// + /// Resolve the CodeLens provision asynchronously -- just wraps the CodeLens argument in a task. + /// + /// The code lens to resolve. + /// + /// The given CodeLens, wrapped in a task. public Task ResolveCodeLensAsync( CodeLens codeLens, CancellationToken cancellationToken) diff --git a/src/PowerShellEditorServices.Host/CodeLens/ReferencesCodeLensProvider.cs b/src/PowerShellEditorServices.Host/CodeLens/ReferencesCodeLensProvider.cs index abe29a997..84b5f9df1 100644 --- a/src/PowerShellEditorServices.Host/CodeLens/ReferencesCodeLensProvider.cs +++ b/src/PowerShellEditorServices.Host/CodeLens/ReferencesCodeLensProvider.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.PowerShell.EditorServices.Commands; @@ -14,87 +15,120 @@ namespace Microsoft.PowerShell.EditorServices.CodeLenses { + /// + /// Provides the "reference" code lens by extracting document symbols. + /// internal class ReferencesCodeLensProvider : FeatureProviderBase, ICodeLensProvider { - private EditorSession editorSession; - private IDocumentSymbolProvider symbolProvider; + /// + /// The editor session code lenses are being provided from. + /// + private EditorSession _editorSession; + /// + /// The document symbol provider to supply symbols to generate the code lenses. + /// + private IDocumentSymbolProvider _symbolProvider; + + /// + /// Construct a new ReferencesCodeLensProvider for a given EditorSession. + /// + /// public ReferencesCodeLensProvider(EditorSession editorSession) { - this.editorSession = editorSession; + _editorSession = editorSession; // TODO: Pull this from components - this.symbolProvider = - new ScriptDocumentSymbolProvider( - editorSession.PowerShellContext.LocalPowerShellVersion.Version); + _symbolProvider = new ScriptDocumentSymbolProvider( + editorSession.PowerShellContext.LocalPowerShellVersion.Version); } + /// + /// Get all reference code lenses for a given script file. + /// + /// The PowerShell script file to get code lenses for. + /// An array of CodeLenses describing all functions in the given script file. public CodeLens[] ProvideCodeLenses(ScriptFile scriptFile) { - return - this.symbolProvider - .ProvideDocumentSymbols(scriptFile) - .Where(symbol => symbol.SymbolType == SymbolType.Function) - .Select( - symbol => - new CodeLens( - this, - scriptFile, - symbol.ScriptRegion)) - .ToArray(); + var acc = new List(); + foreach (SymbolReference sym in _symbolProvider.ProvideDocumentSymbols(scriptFile)) + { + if (sym.SymbolType == SymbolType.Function) + { + acc.Add(new CodeLens(this, scriptFile, sym.ScriptRegion)); + } + } + + return acc.ToArray(); } + /// + /// Take a codelens and create a new codelens object with updated references. + /// + /// The old code lens to get updated references for. + /// The cancellation token for this request. + /// A new code lens object describing the same data as the old one but with updated references. public async Task ResolveCodeLensAsync( CodeLens codeLens, CancellationToken cancellationToken) { - ScriptFile[] references = - editorSession.Workspace.ExpandScriptReferences( - codeLens.File); - - var foundSymbol = - this.editorSession.LanguageService.FindFunctionDefinitionAtLocation( - codeLens.File, - codeLens.ScriptExtent.StartLineNumber, - codeLens.ScriptExtent.StartColumnNumber); - - FindReferencesResult referencesResult = - await editorSession.LanguageService.FindReferencesOfSymbol( - foundSymbol, - references, - editorSession.Workspace); - - Location[] referenceLocations = - referencesResult == null - ? new Location[0] - : referencesResult - .FoundReferences - .Where(r => NotReferenceDefinition(foundSymbol, r)) - .Select( - r => new Location - { - Uri = GetFileUri(r.FilePath), - Range = r.ScriptRegion.ToRange() - }) - .ToArray(); + ScriptFile[] references = _editorSession.Workspace.ExpandScriptReferences( + codeLens.File); - return - new CodeLens( - codeLens, - new ClientCommand( - "editor.action.showReferences", - referenceLocations.Length == 1 - ? "1 reference" - : $"{referenceLocations.Length} references", - new object[] - { - codeLens.File.ClientFilePath, - codeLens.ScriptExtent.ToRange().Start, - referenceLocations, - } + var foundSymbol = _editorSession.LanguageService.FindFunctionDefinitionAtLocation( + codeLens.File, + codeLens.ScriptExtent.StartLineNumber, + codeLens.ScriptExtent.StartColumnNumber); + + FindReferencesResult referencesResult = await _editorSession.LanguageService.FindReferencesOfSymbol( + foundSymbol, + references, + _editorSession.Workspace); + + Location[] referenceLocations; + if (referencesResult == null) + { + referenceLocations = Array.Empty(); + } + else + { + var acc = new List(); + foreach (SymbolReference foundReference in referencesResult.FoundReferences) + { + if (!NotReferenceDefinition(foundSymbol, foundReference)) + { + continue; + } + + acc.Add(new Location + { + Uri = GetFileUri(foundReference.FilePath), + Range = foundReference.ScriptRegion.ToRange() + }); + } + referenceLocations = acc.ToArray(); + } + + return new CodeLens( + codeLens, + new ClientCommand( + "editor.action.showReferences", + GetReferenceCountHeader(referenceLocations.Length), + new object[] + { + codeLens.File.ClientFilePath, + codeLens.ScriptExtent.ToRange().Start, + referenceLocations, + } )); } + /// + /// Check whether a SymbolReference is not a reference to another defined symbol. + /// + /// The symbol definition that may be referenced. + /// The reference symbol to check. + /// True if the reference is not a reference to the definition, false otherwise. private static bool NotReferenceDefinition( SymbolReference definition, SymbolReference reference) @@ -105,6 +139,11 @@ private static bool NotReferenceDefinition( || !string.Equals(definition.SymbolName, reference.SymbolName, StringComparison.OrdinalIgnoreCase); } + /// + /// Get a URI for a given file path. + /// + /// A file path that may be prefixed with URI scheme already. + /// A URI to the file. private static string GetFileUri(string filePath) { // If the file isn't untitled, return a URI-style path @@ -113,5 +152,24 @@ private static string GetFileUri(string filePath) ? new Uri("file://" + filePath).AbsoluteUri : filePath; } + + /// + /// Get the code lens header for the number of references on a definition, + /// given the number of references. + /// + /// The number of references found for a given definition. + /// The header string for the reference code lens. + private static string GetReferenceCountHeader(int referenceCount) + { + if (referenceCount == 1) + { + return "1 reference"; + } + + var sb = new StringBuilder(14); // "100 references".Length = 14 + sb.Append(referenceCount); + sb.Append(" references"); + return sb.ToString(); + } } } From 4d200bd777598b88aaed914e5728f448501e7cbb Mon Sep 17 00:00:00 2001 From: Robert Holt Date: Wed, 8 Aug 2018 12:44:49 -0700 Subject: [PATCH 3/8] Fix style mistake --- .../CodeLens/CodeLensFeature.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/PowerShellEditorServices.Host/CodeLens/CodeLensFeature.cs b/src/PowerShellEditorServices.Host/CodeLens/CodeLensFeature.cs index e37938814..e201c7f1a 100644 --- a/src/PowerShellEditorServices.Host/CodeLens/CodeLensFeature.cs +++ b/src/PowerShellEditorServices.Host/CodeLens/CodeLensFeature.cs @@ -120,7 +120,7 @@ private async Task HandleCodeLensRequest( RequestContext requestContext) { var scriptFile = - this._editorSession.Workspace.GetFile( + _editorSession.Workspace.GetFile( codeLensParams.TextDocument.Uri); CodeLens[] codeLensResults = ProvideCodeLenses(scriptFile); @@ -161,7 +161,7 @@ private async Task HandleCodeLensResolveRequest( if (originalProvider != null) { ScriptFile scriptFile = - this._editorSession.Workspace.GetFile( + _editorSession.Workspace.GetFile( codeLensData.Uri); ScriptRegion region = new ScriptRegion @@ -185,7 +185,7 @@ await originalProvider.ResolveCodeLensAsync( await requestContext.SendResult( resolvedCodeLens.ToProtocolCodeLens( - this._jsonSerializer)); + _jsonSerializer)); } else { From dc09c18c2d8cc4d1085248632e1c38cd9cd8345f Mon Sep 17 00:00:00 2001 From: Robert Holt Date: Wed, 8 Aug 2018 12:45:48 -0700 Subject: [PATCH 4/8] Fix style mistake --- src/PowerShellEditorServices.Host/CodeLens/CodeLensFeature.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PowerShellEditorServices.Host/CodeLens/CodeLensFeature.cs b/src/PowerShellEditorServices.Host/CodeLens/CodeLensFeature.cs index e201c7f1a..402b7e90b 100644 --- a/src/PowerShellEditorServices.Host/CodeLens/CodeLensFeature.cs +++ b/src/PowerShellEditorServices.Host/CodeLens/CodeLensFeature.cs @@ -155,7 +155,7 @@ private async Task HandleCodeLensResolveRequest( CodeLensData codeLensData = codeLens.Data.ToObject(); ICodeLensProvider originalProvider = - this.Providers.FirstOrDefault( + Providers.FirstOrDefault( provider => provider.ProviderId.Equals(codeLensData.ProviderId)); if (originalProvider != null) From 76d7aadb3bb3b8319bf011cf9b360f6996176b91 Mon Sep 17 00:00:00 2001 From: Robert Holt Date: Wed, 8 Aug 2018 12:49:39 -0700 Subject: [PATCH 5/8] Remove unused class --- src/PowerShellEditorServices/Utility/HashCodeCombiner.cs | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 src/PowerShellEditorServices/Utility/HashCodeCombiner.cs diff --git a/src/PowerShellEditorServices/Utility/HashCodeCombiner.cs b/src/PowerShellEditorServices/Utility/HashCodeCombiner.cs deleted file mode 100644 index dc9e6360d..000000000 --- a/src/PowerShellEditorServices/Utility/HashCodeCombiner.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace PowerShellEditorServices.Utility -{ - public class HashCodeCombiner - { - - } -} \ No newline at end of file From 4136b5628c297a9ef74f2d4d2c6a10f440c15434 Mon Sep 17 00:00:00 2001 From: Robert Holt Date: Wed, 8 Aug 2018 12:54:01 -0700 Subject: [PATCH 6/8] Use types instead of var --- .../CodeLens/CodeLensFeature.cs | 5 ++--- .../CodeLens/PesterCodeLensProvider.cs | 2 +- .../CodeLens/ReferencesCodeLensProvider.cs | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/PowerShellEditorServices.Host/CodeLens/CodeLensFeature.cs b/src/PowerShellEditorServices.Host/CodeLens/CodeLensFeature.cs index 402b7e90b..7281418dd 100644 --- a/src/PowerShellEditorServices.Host/CodeLens/CodeLensFeature.cs +++ b/src/PowerShellEditorServices.Host/CodeLens/CodeLensFeature.cs @@ -119,9 +119,8 @@ private async Task HandleCodeLensRequest( CodeLensRequest codeLensParams, RequestContext requestContext) { - var scriptFile = - _editorSession.Workspace.GetFile( - codeLensParams.TextDocument.Uri); + ScriptFile scriptFile = _editorSession.Workspace.GetFile( + codeLensParams.TextDocument.Uri); CodeLens[] codeLensResults = ProvideCodeLenses(scriptFile); diff --git a/src/PowerShellEditorServices.Host/CodeLens/PesterCodeLensProvider.cs b/src/PowerShellEditorServices.Host/CodeLens/PesterCodeLensProvider.cs index 67f00b25a..619ca0a49 100644 --- a/src/PowerShellEditorServices.Host/CodeLens/PesterCodeLensProvider.cs +++ b/src/PowerShellEditorServices.Host/CodeLens/PesterCodeLensProvider.cs @@ -77,7 +77,7 @@ private CodeLens[] GetPesterLens( public CodeLens[] ProvideCodeLenses(ScriptFile scriptFile) { var lenses = new List(); - foreach (var symbol in _symbolProvider.ProvideDocumentSymbols(scriptFile)) + foreach (SymbolReference symbol in _symbolProvider.ProvideDocumentSymbols(scriptFile)) { if (symbol is PesterSymbolReference pesterSymbol) { diff --git a/src/PowerShellEditorServices.Host/CodeLens/ReferencesCodeLensProvider.cs b/src/PowerShellEditorServices.Host/CodeLens/ReferencesCodeLensProvider.cs index 84b5f9df1..0bf8695d1 100644 --- a/src/PowerShellEditorServices.Host/CodeLens/ReferencesCodeLensProvider.cs +++ b/src/PowerShellEditorServices.Host/CodeLens/ReferencesCodeLensProvider.cs @@ -75,7 +75,7 @@ public async Task ResolveCodeLensAsync( ScriptFile[] references = _editorSession.Workspace.ExpandScriptReferences( codeLens.File); - var foundSymbol = _editorSession.LanguageService.FindFunctionDefinitionAtLocation( + SymbolReference foundSymbol = _editorSession.LanguageService.FindFunctionDefinitionAtLocation( codeLens.File, codeLens.ScriptExtent.StartLineNumber, codeLens.ScriptExtent.StartColumnNumber); From 4f7230fc5882394c72182255e89fcdc24bff3d38 Mon Sep 17 00:00:00 2001 From: Robert Holt Date: Fri, 10 Aug 2018 10:34:36 -0700 Subject: [PATCH 7/8] Use SelectMany in simple non-linq case --- .../CodeLens/CodeLensFeature.cs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/PowerShellEditorServices.Host/CodeLens/CodeLensFeature.cs b/src/PowerShellEditorServices.Host/CodeLens/CodeLensFeature.cs index 7281418dd..ac5f388a3 100644 --- a/src/PowerShellEditorServices.Host/CodeLens/CodeLensFeature.cs +++ b/src/PowerShellEditorServices.Host/CodeLens/CodeLensFeature.cs @@ -101,13 +101,9 @@ private CodeLensFeature( /// All generated CodeLenses for the given script file. public CodeLens[] ProvideCodeLenses(ScriptFile scriptFile) { - var acc = new List(); - foreach (CodeLens[] providerResult in InvokeProviders(provider => provider.ProvideCodeLenses(scriptFile))) - { - acc.AddRange(providerResult); - } - - return acc.ToArray(); + return InvokeProviders(provider => provider.ProvideCodeLenses(scriptFile)) + .SelectMany(codeLens => codeLens) + .ToArray(); } /// From 66d976c72d8fa1f7bb994672f54191f448590be1 Mon Sep 17 00:00:00 2001 From: Robert Holt Date: Thu, 16 Aug 2018 15:30:56 -0700 Subject: [PATCH 8/8] Fix empty array handling --- .../CodeLens/ReferencesCodeLensProvider.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/PowerShellEditorServices.Host/CodeLens/ReferencesCodeLensProvider.cs b/src/PowerShellEditorServices.Host/CodeLens/ReferencesCodeLensProvider.cs index 0bf8695d1..c833aec27 100644 --- a/src/PowerShellEditorServices.Host/CodeLens/ReferencesCodeLensProvider.cs +++ b/src/PowerShellEditorServices.Host/CodeLens/ReferencesCodeLensProvider.cs @@ -20,6 +20,8 @@ namespace Microsoft.PowerShell.EditorServices.CodeLenses /// internal class ReferencesCodeLensProvider : FeatureProviderBase, ICodeLensProvider { + private static readonly Location[] s_emptyLocationArray = new Location[0]; + /// /// The editor session code lenses are being provided from. /// @@ -88,7 +90,7 @@ public async Task ResolveCodeLensAsync( Location[] referenceLocations; if (referencesResult == null) { - referenceLocations = Array.Empty(); + referenceLocations = s_emptyLocationArray; } else {