diff --git a/src/PowerShellEditorServices/Services/CodeLens/PesterCodeLensProvider.cs b/src/PowerShellEditorServices/Services/CodeLens/PesterCodeLensProvider.cs index 881bbc0372..293d2ff48c 100644 --- a/src/PowerShellEditorServices/Services/CodeLens/PesterCodeLensProvider.cs +++ b/src/PowerShellEditorServices/Services/CodeLens/PesterCodeLensProvider.cs @@ -7,7 +7,6 @@ using Microsoft.PowerShell.EditorServices.Services; using Microsoft.PowerShell.EditorServices.Services.Symbols; using Microsoft.PowerShell.EditorServices.Services.TextDocument; -using Microsoft.PowerShell.EditorServices.Utility; using Newtonsoft.Json.Linq; using OmniSharp.Extensions.LanguageServer.Protocol.Models; using OmniSharp.Extensions.LanguageServer.Protocol.Serialization; diff --git a/src/PowerShellEditorServices/Services/CodeLens/ReferencesCodeLensProvider.cs b/src/PowerShellEditorServices/Services/CodeLens/ReferencesCodeLensProvider.cs index 653d157807..eeea04375a 100644 --- a/src/PowerShellEditorServices/Services/CodeLens/ReferencesCodeLensProvider.cs +++ b/src/PowerShellEditorServices/Services/CodeLens/ReferencesCodeLensProvider.cs @@ -9,7 +9,6 @@ using Microsoft.PowerShell.EditorServices.Services; using Microsoft.PowerShell.EditorServices.Services.Symbols; using Microsoft.PowerShell.EditorServices.Services.TextDocument; -using Microsoft.PowerShell.EditorServices.Utility; using Newtonsoft.Json.Linq; using OmniSharp.Extensions.LanguageServer.Protocol; using OmniSharp.Extensions.LanguageServer.Protocol.Models; diff --git a/src/PowerShellEditorServices/Services/Symbols/PesterDocumentSymbolProvider.cs b/src/PowerShellEditorServices/Services/Symbols/PesterDocumentSymbolProvider.cs index cbdedb96da..8730ed0812 100644 --- a/src/PowerShellEditorServices/Services/Symbols/PesterDocumentSymbolProvider.cs +++ b/src/PowerShellEditorServices/Services/Symbols/PesterDocumentSymbolProvider.cs @@ -196,7 +196,7 @@ internal enum PesterCommandType /// Provides a specialization of SymbolReference containing /// extra information about Pester test symbols. /// - internal class PesterSymbolReference : SymbolReference + internal record PesterSymbolReference : SymbolReference { /// /// Lookup for Pester keywords we support. Ideally we could extract these from Pester itself diff --git a/src/PowerShellEditorServices/Services/Symbols/ReferenceTable.cs b/src/PowerShellEditorServices/Services/Symbols/ReferenceTable.cs index deafed8f26..d80e0dbd02 100644 --- a/src/PowerShellEditorServices/Services/Symbols/ReferenceTable.cs +++ b/src/PowerShellEditorServices/Services/Symbols/ReferenceTable.cs @@ -109,10 +109,6 @@ public override AstVisitAction VisitCommand(CommandAst commandAst) return AstVisitAction.Continue; } - // TODO: We should examine if we really want to constrain the extents to the name only. This - // means that highlighting only highlights the symbol name, but providing the whole extend - // means the whole function (or class etc.) gets highlighted, which seems to be a personal - // preference. public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst functionDefinitionAst) { // Extent for constructors and method trigger both this and VisitFunctionMember(). Covered in the latter. @@ -122,7 +118,7 @@ public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst fun return AstVisitAction.Continue; } - // We only want the function name + // We only want the function name as the extent for highlighting (and so forth). IScriptExtent nameExtent = VisitorUtils.GetNameExtent(functionDefinitionAst); _references.AddReference( SymbolType.Function, @@ -159,7 +155,6 @@ public override AstVisitAction VisitTypeDefinition(TypeDefinitionAst typeDefinit { SymbolType symbolType = typeDefinitionAst.IsEnum ? SymbolType.Enum : SymbolType.Class; - // We only want the type name. Get start-location for name IScriptExtent nameExtent = VisitorUtils.GetNameExtent(typeDefinitionAst); _references.AddReference(symbolType, typeDefinitionAst.Name, nameExtent); @@ -189,7 +184,6 @@ public override AstVisitAction VisitFunctionMember(FunctionMemberAst functionMem ? SymbolType.Constructor : SymbolType.Method; - // We only want the method/ctor name. Get start-location for name IScriptExtent nameExtent = VisitorUtils.GetNameExtent(functionMemberAst, true, false); _references.AddReference( symbolType, @@ -201,7 +195,6 @@ public override AstVisitAction VisitFunctionMember(FunctionMemberAst functionMem public override AstVisitAction VisitPropertyMember(PropertyMemberAst propertyMemberAst) { - // We only want the property name. Get start-location for name IScriptExtent nameExtent = VisitorUtils.GetNameExtent(propertyMemberAst, false); _references.AddReference( SymbolType.Property, @@ -210,7 +203,5 @@ public override AstVisitAction VisitPropertyMember(PropertyMemberAst propertyMem return AstVisitAction.Continue; } - - // TODO: What else can we implement? } } diff --git a/src/PowerShellEditorServices/Services/Symbols/SymbolReference.cs b/src/PowerShellEditorServices/Services/Symbols/SymbolReference.cs index ccedc0468f..c3a3c5d321 100644 --- a/src/PowerShellEditorServices/Services/Symbols/SymbolReference.cs +++ b/src/PowerShellEditorServices/Services/Symbols/SymbolReference.cs @@ -1,75 +1,30 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +#nullable enable + using System.Diagnostics; using System.Management.Automation.Language; using Microsoft.PowerShell.EditorServices.Services.TextDocument; namespace Microsoft.PowerShell.EditorServices.Services.Symbols { - internal interface ISymbolReference - { - /// - /// Gets the symbol's type - /// - SymbolType SymbolType { get; } - - /// - /// Gets the name of the symbol - /// - string SymbolName { get; } - - /// - /// Gets the script extent of the symbol - /// - ScriptRegion ScriptRegion { get; } - - /// - /// Gets the contents of the line the given symbol is on - /// - string SourceLine { get; } - - /// - /// Gets the path of the file in which the symbol was found. - /// - string FilePath { get; } - } - /// /// A class that holds the type, name, script extent, and source line of a symbol /// [DebuggerDisplay("SymbolType = {SymbolType}, SymbolName = {SymbolName}")] - internal class SymbolReference : ISymbolReference + internal record SymbolReference { - #region Properties - - /// - /// Gets the symbol's type - /// public SymbolType SymbolType { get; } - /// - /// Gets the name of the symbol - /// public string SymbolName { get; } - /// - /// Gets the script extent of the symbol - /// public ScriptRegion ScriptRegion { get; } - /// - /// Gets the contents of the line the given symbol is on - /// public string SourceLine { get; internal set; } - /// - /// Gets the path of the file in which the symbol was found. - /// public string FilePath { get; internal set; } - #endregion - /// /// Constructs and instance of a SymbolReference /// @@ -88,16 +43,9 @@ public SymbolReference( // TODO: Verify params SymbolType = symbolType; SymbolName = symbolName; - ScriptRegion = ScriptRegion.Create(scriptExtent); + ScriptRegion = new(scriptExtent); FilePath = filePath; SourceLine = sourceLine; - - // TODO: Make sure end column number usage is correct - - // Build the display string - //this.DisplayString = - // string.Format( - // "{0} {1}") } public SymbolReference( @@ -108,7 +56,7 @@ public SymbolReference( { SymbolType = symbolType; SymbolName = symbolName; - ScriptRegion = ScriptRegion.Create(scriptExtent); + ScriptRegion = new(scriptExtent); FilePath = file.FilePath; try { diff --git a/src/PowerShellEditorServices/Services/Symbols/Vistors/AstOperations.cs b/src/PowerShellEditorServices/Services/Symbols/Vistors/AstOperations.cs index 8799a9ce9c..b46e7e83d7 100644 --- a/src/PowerShellEditorServices/Services/Symbols/Vistors/AstOperations.cs +++ b/src/PowerShellEditorServices/Services/Symbols/Vistors/AstOperations.cs @@ -196,72 +196,6 @@ public static SymbolReference FindDefinitionOfSymbol( return declarationVisitor.FoundDeclaration; } - /// - /// Finds all symbols in a script - /// - /// The abstract syntax tree of the given script - /// A collection of SymbolReference objects - public static IEnumerable FindSymbolsInDocument(Ast scriptAst) - { - FindSymbolsVisitor findSymbolsVisitor = new(); - scriptAst.Visit(findSymbolsVisitor); - return findSymbolsVisitor.SymbolReferences; - } - - /// - /// Checks if a given ast represents the root node of a *.psd1 file. - /// - /// The abstract syntax tree of the given script - /// true if the AST represents a *.psd1 file, otherwise false - public static bool IsPowerShellDataFileAst(Ast ast) - { - // sometimes we don't have reliable access to the filename - // so we employ heuristics to check if the contents are - // part of a psd1 file. - return IsPowerShellDataFileAstNode( - new { Item = ast, Children = new List() }, - new Type[] { - typeof(ScriptBlockAst), - typeof(NamedBlockAst), - typeof(PipelineAst), - typeof(CommandExpressionAst), - typeof(HashtableAst) }, - 0); - } - - private static bool IsPowerShellDataFileAstNode(dynamic node, Type[] levelAstMap, int level) - { - dynamic levelAstTypeMatch = node.Item.GetType().Equals(levelAstMap[level]); - if (!levelAstTypeMatch) - { - return false; - } - - if (level == levelAstMap.Length - 1) - { - return levelAstTypeMatch; - } - - IEnumerable astsFound = (node.Item as Ast)?.FindAll(a => a is not null, false); - if (astsFound != null) - { - foreach (Ast astFound in astsFound) - { - if (!astFound.Equals(node.Item) - && node.Item.Equals(astFound.Parent) - && IsPowerShellDataFileAstNode( - new { Item = astFound, Children = new List() }, - levelAstMap, - level + 1)) - { - return true; - } - } - } - - return false; - } - /// /// Finds all files dot sourced in a script /// diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeActionHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeActionHandler.cs index 2681baa195..895c804ec7 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeActionHandler.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeActionHandler.cs @@ -95,7 +95,7 @@ public override async Task Handle(CodeActionParams { Uri = request.TextDocument.Uri }, - Edits = new TextEditContainer(ScriptRegion.ToTextEdit(markerCorrection.Edit)) + Edits = new TextEditContainer(markerCorrection.Edit.ToTextEdit()) })) } }); diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/DefinitionHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/DefinitionHandler.cs index 95dba3c5ac..1b00b98053 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/DefinitionHandler.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/DefinitionHandler.cs @@ -57,7 +57,7 @@ public override async Task Handle(DefinitionParams requ new Location { Uri = DocumentUri.From(foundDefinition.FilePath), - Range = ScriptRegion.GetRangeFromScriptRegion(foundDefinition.ScriptRegion) + Range = foundDefinition.ScriptRegion.ToRange() })); } } diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/DocumentSymbolHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/DocumentSymbolHandler.cs index d54f7232b7..8119f5e77b 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/DocumentSymbolHandler.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/DocumentSymbolHandler.cs @@ -59,6 +59,7 @@ public override Task Handle(Document ? foundSymbols .Select(r => { + // TODO: This should be a DocumentSymbol now as SymbolInformation is deprecated. return new SymbolInformationOrDocumentSymbol(new SymbolInformation { ContainerName = containerName, @@ -66,7 +67,7 @@ public override Task Handle(Document Location = new Location { Uri = DocumentUri.From(r.FilePath), - Range = ScriptRegion.GetRangeFromScriptRegion(r.ScriptRegion) + Range = r.ScriptRegion.ToRange() }, Name = SymbolTypeUtils.GetDecoratedSymbolName(r) }); diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/HoverHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/HoverHandler.cs index 02264d4695..7dbe075286 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/HoverHandler.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/HoverHandler.cs @@ -67,12 +67,10 @@ await _symbolsService.FindSymbolDetailsAtLocationAsync( symbolInfo.Add(new MarkedString("markdown", symbolDetails.Documentation)); } - Range symbolRange = ScriptRegion.GetRangeFromScriptRegion(symbolDetails.SymbolReference.ScriptRegion); - return new Hover { Contents = new MarkedStringsOrMarkupContent(symbolInfo), - Range = symbolRange + Range = symbolDetails.SymbolReference.ScriptRegion.ToRange() }; } } diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/ReferencesHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/ReferencesHandler.cs index a6dde43e58..6e545ba71f 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/ReferencesHandler.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/ReferencesHandler.cs @@ -56,7 +56,7 @@ await _symbolsService.ScanForReferencesOfSymbol( locations.Add(new Location { Uri = DocumentUri.From(foundReference.FilePath), - Range = ScriptRegion.GetRangeFromScriptRegion(foundReference.ScriptRegion) + Range = foundReference.ScriptRegion.ToRange() }); } } diff --git a/src/PowerShellEditorServices/Services/TextDocument/ScriptFileMarker.cs b/src/PowerShellEditorServices/Services/TextDocument/ScriptFileMarker.cs index 43c4657015..e3273e3e6c 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/ScriptFileMarker.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/ScriptFileMarker.cs @@ -34,19 +34,19 @@ public enum ScriptFileMarkerLevel ///          /// Information: This warning is trivial, but may be useful. They are recommended by PowerShell best practice.         ///  -        Information = 0, + Information = 0,         ///          /// WARNING: This warning may cause a problem or does not follow PowerShell's recommended guidelines.         ///  -        Warning = 1, + Warning = 1,         ///          /// ERROR: This warning is likely to cause a problem or does not follow PowerShell's required guidelines.         ///  -        Error = 2, + Error = 2,         ///          /// ERROR: This diagnostic is caused by an actual parsing error, and is generated only by the engine.         ///  -        ParseError = 3 + ParseError = 3 }; /// @@ -102,7 +102,7 @@ internal static ScriptFileMarker FromParseError( { Message = parseError.Message, Level = ScriptFileMarkerLevel.Error, - ScriptRegion = ScriptRegion.Create(parseError.Extent), + ScriptRegion = new(parseError.Extent), Source = "PowerShell" }; } @@ -157,7 +157,7 @@ internal static ScriptFileMarker FromDiagnosticRecord(PSObject psObject) Message = diagnosticRecord.Message as string ?? string.Empty, RuleName = diagnosticRecord.RuleName as string ?? string.Empty, Level = level, - ScriptRegion = ScriptRegion.Create(diagnosticRecord.Extent as IScriptExtent), + ScriptRegion = new(diagnosticRecord.Extent as IScriptExtent), Corrections = markerCorrections, Source = "PSScriptAnalyzer" }; diff --git a/src/PowerShellEditorServices/Services/TextDocument/ScriptRegion.cs b/src/PowerShellEditorServices/Services/TextDocument/ScriptRegion.cs index 5973f59b15..789d6f11d9 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/ScriptRegion.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/ScriptRegion.cs @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +#nullable enable + using System; using System.Management.Automation.Language; using OmniSharp.Extensions.LanguageServer.Protocol.Models; @@ -12,82 +14,25 @@ namespace Microsoft.PowerShell.EditorServices.Services.TextDocument /// public sealed class ScriptRegion : IScriptExtent { - #region Static Methods - - /// - /// Creates a new instance of the ScriptRegion class from an - /// instance of an IScriptExtent implementation. - /// - /// - /// The IScriptExtent to copy into the ScriptRegion. - /// - /// - /// A new ScriptRegion instance with the same details as the IScriptExtent. - /// - public static ScriptRegion Create(IScriptExtent scriptExtent) - { - // IScriptExtent throws an ArgumentOutOfRange exception if Text is null - string scriptExtentText; - try - { - scriptExtentText = scriptExtent.Text; - } - catch (ArgumentOutOfRangeException) - { - scriptExtentText = string.Empty; - } - - return new ScriptRegion( - scriptExtent.File, - scriptExtentText, - scriptExtent.StartLineNumber, - scriptExtent.StartColumnNumber, - scriptExtent.StartOffset, - scriptExtent.EndLineNumber, - scriptExtent.EndColumnNumber, - scriptExtent.EndOffset); - } + public TextEdit ToTextEdit() => new() { NewText = Text, Range = ToRange() }; - internal static TextEdit ToTextEdit(ScriptRegion scriptRegion) - { - return new TextEdit - { - NewText = scriptRegion.Text, - Range = new Range - { - Start = new Position - { - Line = scriptRegion.StartLineNumber - 1, - Character = scriptRegion.StartColumnNumber - 1, - }, - End = new Position - { - Line = scriptRegion.EndLineNumber - 1, - Character = scriptRegion.EndColumnNumber - 1, - } - } - }; - } - - internal static Range GetRangeFromScriptRegion(ScriptRegion scriptRegion) + public Range ToRange() { return new Range { Start = new Position { - Line = scriptRegion.StartLineNumber - 1, - Character = scriptRegion.StartColumnNumber - 1 + Line = StartLineNumber - 1, + Character = StartColumnNumber - 1 }, End = new Position { - Line = scriptRegion.EndLineNumber - 1, - Character = scriptRegion.EndColumnNumber - 1 + Line = EndLineNumber - 1, + Character = EndColumnNumber - 1 } }; } - #endregion - #region Constructors public ScriptRegion( @@ -110,6 +55,28 @@ public ScriptRegion( EndOffset = endOffset; } + public ScriptRegion (IScriptExtent scriptExtent) + { + File = scriptExtent.File; + + // IScriptExtent throws an ArgumentOutOfRange exception if Text is null + try + { + Text = scriptExtent.Text; + } + catch (ArgumentOutOfRangeException) + { + Text = string.Empty; + } + + StartLineNumber = scriptExtent.StartLineNumber; + StartColumnNumber = scriptExtent.StartColumnNumber; + StartOffset = scriptExtent.StartOffset; + EndLineNumber = scriptExtent.EndLineNumber; + EndColumnNumber = scriptExtent.EndColumnNumber; + EndOffset = scriptExtent.EndOffset; + } + #endregion #region Properties diff --git a/src/PowerShellEditorServices/Services/Workspace/Handlers/WorkspaceSymbolsHandler.cs b/src/PowerShellEditorServices/Services/Workspace/Handlers/WorkspaceSymbolsHandler.cs index 8ee6afbe88..2fd1a7daf1 100644 --- a/src/PowerShellEditorServices/Services/Workspace/Handlers/WorkspaceSymbolsHandler.cs +++ b/src/PowerShellEditorServices/Services/Workspace/Handlers/WorkspaceSymbolsHandler.cs @@ -64,9 +64,10 @@ public override async Task> Handle(WorkspaceSymbolP Location location = new() { Uri = DocumentUri.From(foundOccurrence.FilePath), - Range = ScriptRegion.GetRangeFromScriptRegion(foundOccurrence.ScriptRegion) + Range = foundOccurrence.ScriptRegion.ToRange() }; + // TODO: This should be a WorkplaceSymbol now as SymbolInformation is deprecated. symbols.Add(new SymbolInformation { ContainerName = containerName,