From 82ec11f1909c6402a73305141362415a7ce36f61 Mon Sep 17 00:00:00 2001 From: Andy Jordan Date: Thu, 12 Jan 2023 16:17:26 -0800 Subject: [PATCH] Fix outline view (filter out `EmptyScriptExtent`) And also prepare `SymbolReference` for eventual support of `DocumentSymbol`. --- .../Services/Symbols/ReferenceTable.cs | 47 +++- .../Services/Symbols/ScriptExtent.cs | 2 + .../Services/Symbols/SymbolReference.cs | 5 + .../Services/Symbols/SymbolsService.cs | 1 + .../Handlers/DocumentHighlightHandler.cs | 2 +- .../Handlers/DocumentSymbolHandler.cs | 17 +- .../Services/TextDocument/ScriptRegion.cs | 2 + .../Handlers/WorkspaceSymbolsHandler.cs | 6 + .../References/SimpleFile.ps1 | 2 +- .../Language/SymbolsServiceTests.cs | 204 ++++++++++-------- .../Services/Symbols/AstOperationsTests.cs | 8 +- 11 files changed, 193 insertions(+), 103 deletions(-) diff --git a/src/PowerShellEditorServices/Services/Symbols/ReferenceTable.cs b/src/PowerShellEditorServices/Services/Symbols/ReferenceTable.cs index 9bbffb455..e4fce76d9 100644 --- a/src/PowerShellEditorServices/Services/Symbols/ReferenceTable.cs +++ b/src/PowerShellEditorServices/Services/Symbols/ReferenceTable.cs @@ -71,9 +71,20 @@ internal void EnsureInitialized() _parent.ScriptAst.Visit(new ReferenceVisitor(this)); } - private void AddReference(SymbolType type, string name, IScriptExtent extent, bool isDeclaration = false) + private static bool ExtentIsEmpty(IScriptExtent e) => string.IsNullOrEmpty(e.File) && + e.StartLineNumber == 0 && e.StartColumnNumber == 0 && + e.EndLineNumber == 0 && e.EndColumnNumber == 0 && + string.IsNullOrEmpty(e.Text); + + private void AddReference(SymbolType type, string name, IScriptExtent nameExtent, IScriptExtent extent, bool isDeclaration = false) { - SymbolReference symbol = new(type, name, extent, _parent, isDeclaration); + // We have to exclude implicit things like `$this` that don't actually exist. + if (ExtentIsEmpty(extent)) + { + return; + } + + SymbolReference symbol = new(type, name, nameExtent, extent, _parent, isDeclaration); _symbolReferences.AddOrUpdate( name, _ => new ConcurrentBag { symbol }, @@ -103,7 +114,8 @@ public override AstVisitAction VisitCommand(CommandAst commandAst) _references.AddReference( SymbolType.Function, CommandHelpers.StripModuleQualification(commandName, out _), - commandAst.CommandElements[0].Extent + commandAst.CommandElements[0].Extent, + commandAst.Extent ); return AstVisitAction.Continue; @@ -131,6 +143,7 @@ public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst fun symbolType, functionDefinitionAst.Name, nameExtent, + functionDefinitionAst.Extent, isDeclaration: true); return AstVisitAction.Continue; @@ -141,6 +154,7 @@ public override AstVisitAction VisitCommandParameter(CommandParameterAst command _references.AddReference( SymbolType.Parameter, commandParameterAst.Extent.Text, + commandParameterAst.Extent, commandParameterAst.Extent); return AstVisitAction.Continue; @@ -153,6 +167,7 @@ public override AstVisitAction VisitVariableExpression(VariableExpressionAst var _references.AddReference( SymbolType.Variable, $"${variableExpressionAst.VariablePath.UserPath}", + variableExpressionAst.Extent, variableExpressionAst.Extent ); @@ -166,7 +181,11 @@ public override AstVisitAction VisitTypeDefinition(TypeDefinitionAst typeDefinit : SymbolType.Class; IScriptExtent nameExtent = VisitorUtils.GetNameExtent(typeDefinitionAst); - _references.AddReference(symbolType, typeDefinitionAst.Name, nameExtent); + _references.AddReference( + symbolType, + typeDefinitionAst.Name, + nameExtent, + typeDefinitionAst.Extent); return AstVisitAction.Continue; } @@ -176,6 +195,7 @@ public override AstVisitAction VisitTypeExpression(TypeExpressionAst typeExpress _references.AddReference( SymbolType.Type, typeExpressionAst.TypeName.Name, + typeExpressionAst.Extent, typeExpressionAst.Extent); return AstVisitAction.Continue; @@ -183,7 +203,11 @@ public override AstVisitAction VisitTypeExpression(TypeExpressionAst typeExpress public override AstVisitAction VisitTypeConstraint(TypeConstraintAst typeConstraintAst) { - _references.AddReference(SymbolType.Type, typeConstraintAst.TypeName.Name, typeConstraintAst.Extent); + _references.AddReference( + SymbolType.Type, + typeConstraintAst.TypeName.Name, + typeConstraintAst.Extent, + typeConstraintAst.Extent); return AstVisitAction.Continue; } @@ -197,8 +221,9 @@ public override AstVisitAction VisitFunctionMember(FunctionMemberAst functionMem IScriptExtent nameExtent = VisitorUtils.GetNameExtent(functionMemberAst, true, false); _references.AddReference( symbolType, - VisitorUtils.GetMemberOverloadName(functionMemberAst, true, false), - nameExtent); + nameExtent.Text, + nameExtent, + functionMemberAst.Extent); return AstVisitAction.Continue; } @@ -212,8 +237,9 @@ propertyMemberAst.Parent is TypeDefinitionAst typeAst && typeAst.IsEnum IScriptExtent nameExtent = VisitorUtils.GetNameExtent(propertyMemberAst, false); _references.AddReference( symbolType, - VisitorUtils.GetMemberOverloadName(propertyMemberAst, false), - nameExtent); + nameExtent.Text, + nameExtent, + propertyMemberAst.Extent); return AstVisitAction.Continue; } @@ -224,7 +250,8 @@ public override AstVisitAction VisitConfigurationDefinition(ConfigurationDefinit _references.AddReference( SymbolType.Configuration, nameExtent.Text, - nameExtent); + nameExtent, + configurationDefinitionAst.Extent); return AstVisitAction.Continue; } diff --git a/src/PowerShellEditorServices/Services/Symbols/ScriptExtent.cs b/src/PowerShellEditorServices/Services/Symbols/ScriptExtent.cs index 2224be725..1cd87f44f 100644 --- a/src/PowerShellEditorServices/Services/Symbols/ScriptExtent.cs +++ b/src/PowerShellEditorServices/Services/Symbols/ScriptExtent.cs @@ -91,6 +91,8 @@ public int EndOffset set; } + public override string ToString() => Text; + /// /// Gets the ending script position of the extent. /// diff --git a/src/PowerShellEditorServices/Services/Symbols/SymbolReference.cs b/src/PowerShellEditorServices/Services/Symbols/SymbolReference.cs index 25144c89f..752d5121b 100644 --- a/src/PowerShellEditorServices/Services/Symbols/SymbolReference.cs +++ b/src/PowerShellEditorServices/Services/Symbols/SymbolReference.cs @@ -19,6 +19,8 @@ internal record SymbolReference public string SymbolName { get; } + public ScriptRegion NameRegion { get; } + public ScriptRegion ScriptRegion { get; } public string SourceLine { get; internal set; } @@ -48,6 +50,7 @@ public SymbolReference( SymbolType = symbolType; SymbolName = symbolName; ScriptRegion = new(scriptExtent); + NameRegion = ScriptRegion; FilePath = filePath; SourceLine = sourceLine; IsDeclaration = isDeclaration; @@ -56,12 +59,14 @@ public SymbolReference( public SymbolReference( SymbolType symbolType, string symbolName, + IScriptExtent nameExtent, IScriptExtent scriptExtent, ScriptFile file, bool isDeclaration) { SymbolType = symbolType; SymbolName = symbolName; + NameRegion = new(nameExtent); ScriptRegion = new(scriptExtent); FilePath = file.FilePath; try diff --git a/src/PowerShellEditorServices/Services/Symbols/SymbolsService.cs b/src/PowerShellEditorServices/Services/Symbols/SymbolsService.cs index c05722da5..69b823fb3 100644 --- a/src/PowerShellEditorServices/Services/Symbols/SymbolsService.cs +++ b/src/PowerShellEditorServices/Services/Symbols/SymbolsService.cs @@ -429,6 +429,7 @@ public async Task GetDefinitionOfSymbolAsync( SymbolReference foundDefinition = null; foreach (ScriptFile scriptFile in referencedFiles) { + // TODO: This needs to just search the file's references (filtered to declarations); foundDefinition = AstOperations.FindDefinitionOfSymbol(scriptFile.ScriptAst, foundSymbol); filesSearched.Add(scriptFile.FilePath); diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/DocumentHighlightHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/DocumentHighlightHandler.cs index 8791a6466..5758e59a1 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/DocumentHighlightHandler.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/DocumentHighlightHandler.cs @@ -56,7 +56,7 @@ public override Task Handle( highlights.Add(new DocumentHighlight { Kind = DocumentHighlightKind.Write, // TODO: Which symbol types are writable? - Range = occurrence.ScriptRegion.ToRange() + Range = occurrence.NameRegion.ToRange() // Just the symbol name }); } diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/DocumentSymbolHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/DocumentSymbolHandler.cs index 8aeb7559d..c1ab8d434 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/DocumentSymbolHandler.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/DocumentSymbolHandler.cs @@ -55,6 +55,7 @@ public override async Task Handle(Do } string containerName = Path.GetFileNameWithoutExtension(scriptFile.FilePath); + List symbols = new(); foreach (SymbolReference r in foundSymbols) { @@ -63,7 +64,21 @@ public override async Task Handle(Do await Task.Yield(); cancellationToken.ThrowIfCancellationRequested(); + if (r.SymbolType is SymbolType.Type) + { + continue; + } + // TODO: This should be a DocumentSymbol now as SymbolInformation is deprecated. + // But this requires figuring out how to populate `children`. + // + // symbols.Add(new SymbolInformationOrDocumentSymbol(new DocumentSymbol + // { + // Name = SymbolTypeUtils.GetDecoratedSymbolName(r), + // Kind = SymbolTypeUtils.GetSymbolKind(r.SymbolType), + // Range = r.ScriptRegion.ToRange(), + // SelectionRange = r.NameRegion.ToRange() + // })); symbols.Add(new SymbolInformationOrDocumentSymbol(new SymbolInformation { ContainerName = containerName, @@ -71,7 +86,7 @@ public override async Task Handle(Do Location = new Location { Uri = DocumentUri.From(r.FilePath), - Range = r.ScriptRegion.ToRange() + Range = r.ScriptRegion.ToRange() // The whole thing, not just the name. }, Name = SymbolTypeUtils.GetDecoratedSymbolName(r) })); diff --git a/src/PowerShellEditorServices/Services/TextDocument/ScriptRegion.cs b/src/PowerShellEditorServices/Services/TextDocument/ScriptRegion.cs index 789d6f11d..5d12077f9 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/ScriptRegion.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/ScriptRegion.cs @@ -33,6 +33,8 @@ public Range ToRange() }; } + public override string ToString() => $"Start {StartLineNumber}:{StartColumnNumber}, End {EndLineNumber}:{EndColumnNumber}"; + #region Constructors public ScriptRegion( diff --git a/src/PowerShellEditorServices/Services/Workspace/Handlers/WorkspaceSymbolsHandler.cs b/src/PowerShellEditorServices/Services/Workspace/Handlers/WorkspaceSymbolsHandler.cs index 602ec1230..939a80f9d 100644 --- a/src/PowerShellEditorServices/Services/Workspace/Handlers/WorkspaceSymbolsHandler.cs +++ b/src/PowerShellEditorServices/Services/Workspace/Handlers/WorkspaceSymbolsHandler.cs @@ -49,6 +49,12 @@ public override async Task> Handle(WorkspaceSymbolP // so it's helpful to add some yields. await Task.Yield(); cancellationToken.ThrowIfCancellationRequested(); + + if (foundOccurrence.SymbolType is SymbolType.Type) + { + continue; + } + if (!IsQueryMatch(request.Query, foundOccurrence.SymbolName)) { continue; diff --git a/test/PowerShellEditorServices.Test.Shared/References/SimpleFile.ps1 b/test/PowerShellEditorServices.Test.Shared/References/SimpleFile.ps1 index e7a271447..b60389c63 100644 --- a/test/PowerShellEditorServices.Test.Shared/References/SimpleFile.ps1 +++ b/test/PowerShellEditorServices.Test.Shared/References/SimpleFile.ps1 @@ -1,6 +1,6 @@ function My-Function ($myInput) { - My-Function $myInput + My-Function $myInput } $things = 4 diff --git a/test/PowerShellEditorServices.Test/Language/SymbolsServiceTests.cs b/test/PowerShellEditorServices.Test/Language/SymbolsServiceTests.cs index 8bcd07c81..d58d806dc 100644 --- a/test/PowerShellEditorServices.Test/Language/SymbolsServiceTests.cs +++ b/test/PowerShellEditorServices.Test/Language/SymbolsServiceTests.cs @@ -57,6 +57,19 @@ public void Dispose() GC.SuppressFinalize(this); } + private static void AssertIsRegion( + ScriptRegion region, + int startLineNumber, + int startColumnNumber, + int endLineNumber, + int endColumnNumber) + { + Assert.Equal(startLineNumber, region.StartLineNumber); + Assert.Equal(startColumnNumber, region.StartColumnNumber); + Assert.Equal(endLineNumber, region.EndLineNumber); + Assert.Equal(endColumnNumber, region.EndColumnNumber); + } + private ScriptFile GetScriptFile(ScriptRegion scriptRegion) => workspace.GetFile(TestUtilities.GetSharedPath(scriptRegion.File)); private Task GetParamSetSignatures(ScriptRegion scriptRegion) @@ -116,28 +129,31 @@ private IReadOnlyList GetOccurrences(ScriptRegion scriptRegion) [Fact] public async Task FindsParameterHintsOnCommand() { - ParameterSetSignatures paramSignatures = await GetParamSetSignatures(FindsParameterSetsOnCommandData.SourceDetails).ConfigureAwait(true); - Assert.NotNull(paramSignatures); - Assert.Equal("Get-Process", paramSignatures.CommandName); - Assert.Equal(6, paramSignatures.Signatures.Length); + ParameterSetSignatures signatures = await GetParamSetSignatures(FindsParameterSetsOnCommandData.SourceDetails).ConfigureAwait(true); + Assert.NotNull(signatures); + Assert.Equal("Get-Process", signatures.CommandName); + Assert.Equal(6, signatures.Signatures.Length); } [Fact] public async Task FindsCommandForParamHintsWithSpaces() { - ParameterSetSignatures paramSignatures = await GetParamSetSignatures(FindsParameterSetsOnCommandWithSpacesData.SourceDetails).ConfigureAwait(true); - Assert.NotNull(paramSignatures); - Assert.Equal("Write-Host", paramSignatures.CommandName); - Assert.Single(paramSignatures.Signatures); + ParameterSetSignatures signatures = await GetParamSetSignatures(FindsParameterSetsOnCommandWithSpacesData.SourceDetails).ConfigureAwait(true); + Assert.NotNull(signatures); + Assert.Equal("Write-Host", signatures.CommandName); + Assert.Single(signatures.Signatures); } [Fact] public async Task FindsFunctionDefinition() { - SymbolReference definitionResult = await GetDefinition(FindsFunctionDefinitionData.SourceDetails).ConfigureAwait(true); - Assert.Equal(1, definitionResult.ScriptRegion.StartLineNumber); - Assert.Equal(10, definitionResult.ScriptRegion.StartColumnNumber); - Assert.Equal("My-Function", definitionResult.SymbolName); + SymbolReference symbol = await GetDefinition(FindsFunctionDefinitionData.SourceDetails).ConfigureAwait(true); + Assert.Equal("My-Function", symbol.SymbolName); + AssertIsRegion(symbol.NameRegion, 1, 10, 1, 21); + // TODO: This should pull the declaration from references. + // AssertIsRegion(symbol.ScriptRegion, 1, 1, 4, 2); + Assert.Equal(SymbolType.Function, symbol.SymbolType); + // Assert.True(symbol.IsDeclaration); } [Fact] @@ -149,19 +165,22 @@ await psesHost.ExecutePSCommandAsync( new PSCommand().AddScript("Set-Alias -Name My-Alias -Value My-Function"), CancellationToken.None).ConfigureAwait(true); - SymbolReference definitionResult = await GetDefinition(FindsFunctionDefinitionOfAliasData.SourceDetails).ConfigureAwait(true); - Assert.Equal(1, definitionResult.ScriptRegion.StartLineNumber); - Assert.Equal(10, definitionResult.ScriptRegion.StartColumnNumber); - Assert.Equal("My-Function", definitionResult.SymbolName); + SymbolReference symbol = await GetDefinition(FindsFunctionDefinitionOfAliasData.SourceDetails).ConfigureAwait(true); + AssertIsRegion(symbol.NameRegion, 1, 10, 1, 21); + Assert.Equal("My-Function", symbol.SymbolName); + Assert.Equal(SymbolType.Function, symbol.SymbolType); + // TODO: This should pull the declaration from references. + // Assert.True(symbol.IsDeclaration); } [Fact] public async Task FindsReferencesOnFunction() { - 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); + List symbols = await GetReferences(FindsReferencesOnFunctionData.SourceDetails).ConfigureAwait(true); + Assert.Collection(symbols, + (i) => AssertIsRegion(i.NameRegion, 1, 10, 1, 21), + (i) => AssertIsRegion(i.NameRegion, 3, 5, 3, 16), + (i) => AssertIsRegion(i.NameRegion, 10, 1, 10, 12)); } [Fact] @@ -172,10 +191,14 @@ await psesHost.ExecutePSCommandAsync( new PSCommand().AddScript("Set-Alias -Name My-Alias -Value My-Function"), CancellationToken.None).ConfigureAwait(true); - List referencesResult = await GetReferences(FindsReferencesOnFunctionData.SourceDetails).ConfigureAwait(true); - Assert.Equal(4, referencesResult.Count); - Assert.Equal(1, referencesResult[0].ScriptRegion.StartLineNumber); - Assert.Equal(10, referencesResult[0].ScriptRegion.StartColumnNumber); + List symbols = await GetReferences(FindsReferencesOnFunctionData.SourceDetails).ConfigureAwait(true); + Assert.Collection(symbols, + (i) => AssertIsRegion(i.NameRegion, 1, 10, 1, 21), + (i) => AssertIsRegion(i.NameRegion, 3, 5, 3, 16), + (i) => AssertIsRegion(i.NameRegion, 10, 1, 10, 12), + // The alias. + (i) => AssertIsRegion(i.NameRegion, 20, 1, 20, 9)); + Assert.Equal("My-Alias", symbols[3].SymbolName); } [Fact] @@ -271,6 +294,7 @@ public async Task FindsReferencesOnCommandWithAlias() [Fact] public async Task FindsClassDefinition() { + // TODO: We should find the definition by searching known symbols filtered to declarations. SymbolReference definitionResult = await GetDefinition(FindsTypeSymbolsDefinitionData.ClassSourceDetails).ConfigureAwait(true); Assert.Equal(8, definitionResult.ScriptRegion.StartLineNumber); Assert.Equal(7, definitionResult.ScriptRegion.StartColumnNumber); @@ -280,10 +304,14 @@ public async Task FindsClassDefinition() [Fact] public async Task FindsReferencesOnClass() { - List referencesResult = await GetReferences(FindsReferencesOnTypeSymbolsData.ClassSourceDetails).ConfigureAwait(true); - Assert.Equal(2, referencesResult.Count); - Assert.Equal(8, referencesResult[0].ScriptRegion.StartLineNumber); - Assert.Equal(7, referencesResult[0].ScriptRegion.StartColumnNumber); + List symbols = await GetReferences(FindsReferencesOnTypeSymbolsData.ClassSourceDetails).ConfigureAwait(true); + Assert.Collection(symbols, + (i) => AssertIsRegion(i.ScriptRegion, 8, 1, 31, 2), + (i) => AssertIsRegion(i.ScriptRegion, 34, 6, 34, 18)); + Assert.Collection(symbols, + (i) => AssertIsRegion(i.NameRegion, 8, 7, 8, 17), + // TODO: This should exclude the [] and be 34:7 and 34:18 + (i) => AssertIsRegion(i.NameRegion, 34, 6, 34, 18)); } [Fact] @@ -337,8 +365,13 @@ public async Task FindsReferencesOnTypeExpression() { List referencesResult = await GetReferences(FindsReferencesOnTypeSymbolsData.TypeExpressionSourceDetails).ConfigureAwait(true); Assert.Equal(2, referencesResult.Count); - Assert.Equal(8, referencesResult[0].ScriptRegion.StartLineNumber); - Assert.Equal(7, referencesResult[0].ScriptRegion.StartColumnNumber); + SymbolReference superClass = referencesResult[0]; + Assert.Equal(8, superClass.ScriptRegion.StartLineNumber); + Assert.Equal(1, superClass.ScriptRegion.StartColumnNumber); + Assert.Equal(31, superClass.ScriptRegion.EndLineNumber); + Assert.Equal(2, superClass.ScriptRegion.EndColumnNumber); + Assert.Equal(8, superClass.NameRegion.StartLineNumber); + Assert.Equal(7, superClass.NameRegion.StartColumnNumber); } [Fact] @@ -417,10 +450,12 @@ public async Task FindsMethodDefinition() [Fact] public async Task FindsReferencesOnMethod() { - List referencesResult = await GetReferences(FindsReferencesOnTypeSymbolsData.MethodSourceDetails).ConfigureAwait(true); - Assert.Single(referencesResult); - Assert.Equal(19, referencesResult[0].ScriptRegion.StartLineNumber); - Assert.Equal(13, referencesResult[0].ScriptRegion.StartColumnNumber); + List symbols = await GetReferences(FindsReferencesOnTypeSymbolsData.MethodSourceDetails).ConfigureAwait(true); + SymbolReference symbol = Assert.Single(symbols); + Assert.Equal("SuperClass.MyClassMethod([string]$param1, $param2, [int]$param3)", symbol.SymbolName); + Assert.Equal(SymbolType.Method, symbol.SymbolType); + AssertIsRegion(symbol.NameRegion, 19, 13, 19, 26); + AssertIsRegion(symbol.ScriptRegion, 19, 5, 22, 6); } [Fact] @@ -444,19 +479,25 @@ public async Task FindsPropertyDefinition() [Fact] public async Task FindsReferencesOnProperty() { - List referencesResult = await GetReferences(FindsReferencesOnTypeSymbolsData.PropertySourceDetails).ConfigureAwait(true); - Assert.Single(referencesResult); - Assert.Equal(17, referencesResult[0].ScriptRegion.StartLineNumber); - Assert.Equal(10, referencesResult[0].ScriptRegion.StartColumnNumber); + List symbols = await GetReferences(FindsReferencesOnTypeSymbolsData.PropertySourceDetails).ConfigureAwait(true); + SymbolReference symbol = Assert.Single(symbols); + Assert.Equal("SuperClass.SomeProp", symbol.SymbolName); + Assert.Equal(SymbolType.Property, symbol.SymbolType); + AssertIsRegion(symbol.NameRegion, 17, 10, 17, 19); + AssertIsRegion(symbol.ScriptRegion, 17, 5, 17, 19); + // TODO: This should also find $o.SomeProp } [Fact] public void FindsOccurrencesOnProperty() { - IReadOnlyList occurrencesResult = GetOccurrences(FindsOccurrencesOnTypeSymbolsData.PropertySourceDetails); - Assert.Equal(1, occurrencesResult.Count); - Assert.Equal("SuperClass.SomePropWithDefault", occurrencesResult[occurrencesResult.Count - 1].SymbolName); - Assert.Equal(15, occurrencesResult[occurrencesResult.Count - 1].ScriptRegion.StartLineNumber); + IReadOnlyList symbols = GetOccurrences(FindsOccurrencesOnTypeSymbolsData.PropertySourceDetails); + SymbolReference symbol = Assert.Single(symbols); + Assert.Equal("SuperClass.SomePropWithDefault", symbol.SymbolName); + Assert.Equal(SymbolType.Property, symbol.SymbolType); + AssertIsRegion(symbol.NameRegion, 15, 13, 15, 33); + AssertIsRegion(symbol.ScriptRegion, 15, 5, 15, 61); + // TODO: This should also find the $this.SomePropWithDefault reference. } [Fact] @@ -559,62 +600,53 @@ public async Task FindsDetailsWithSignatureForMethod() [Fact] public void FindsSymbolsInFile() { - IEnumerable symbolsResult = FindSymbolsInFile(FindSymbolsInMultiSymbolFile.SourceDetails); + IEnumerable symbols = FindSymbolsInFile(FindSymbolsInMultiSymbolFile.SourceDetails); - Assert.Equal(7, symbolsResult.Count(symbolReference => symbolReference.SymbolType == SymbolType.Function)); - Assert.Equal(13, symbolsResult.Count(symbolReference => symbolReference.SymbolType == SymbolType.Variable)); + Assert.Equal(7, symbols.Count(symbolReference => symbolReference.SymbolType == SymbolType.Function)); + Assert.Equal(12, symbols.Count(symbolReference => symbolReference.SymbolType == SymbolType.Variable)); - SymbolReference firstFunctionSymbol = symbolsResult.First(r => r.SymbolType == SymbolType.Function); + SymbolReference firstFunctionSymbol = symbols.First(r => r.SymbolType == SymbolType.Function); Assert.Equal("AFunction", firstFunctionSymbol.SymbolName); - Assert.Equal(7, firstFunctionSymbol.ScriptRegion.StartLineNumber); - Assert.Equal(10, firstFunctionSymbol.ScriptRegion.StartColumnNumber); + AssertIsRegion(firstFunctionSymbol.NameRegion, 7, 10, 7, 19); - SymbolReference lastVariableSymbol = symbolsResult.Last(r => r.SymbolType == SymbolType.Variable); + SymbolReference lastVariableSymbol = symbols.Last(r => r.SymbolType == SymbolType.Variable); Assert.Equal("$param3", lastVariableSymbol.SymbolName); - Assert.Equal(32, lastVariableSymbol.ScriptRegion.StartLineNumber); - Assert.Equal(50, lastVariableSymbol.ScriptRegion.StartColumnNumber); + AssertIsRegion(lastVariableSymbol.NameRegion, 32, 50, 32, 57); SymbolReference firstWorkflowSymbol = - Assert.Single(symbolsResult.Where(symbolReference => symbolReference.SymbolType == SymbolType.Workflow)); + Assert.Single(symbols.Where(symbolReference => symbolReference.SymbolType == SymbolType.Workflow)); Assert.Equal("AWorkflow", firstWorkflowSymbol.SymbolName); - Assert.Equal(23, firstWorkflowSymbol.ScriptRegion.StartLineNumber); - Assert.Equal(10, firstWorkflowSymbol.ScriptRegion.StartColumnNumber); + AssertIsRegion(firstWorkflowSymbol.NameRegion, 23, 10, 23, 19); SymbolReference firstClassSymbol = - Assert.Single(symbolsResult.Where(symbolReference => symbolReference.SymbolType == SymbolType.Class)); + Assert.Single(symbols.Where(symbolReference => symbolReference.SymbolType == SymbolType.Class)); Assert.Equal("AClass", firstClassSymbol.SymbolName); - Assert.Equal(25, firstClassSymbol.ScriptRegion.StartLineNumber); - Assert.Equal(7, firstClassSymbol.ScriptRegion.StartColumnNumber); + AssertIsRegion(firstClassSymbol.NameRegion, 25, 7, 25, 13); SymbolReference firstPropertySymbol = - Assert.Single(symbolsResult.Where(symbolReference => symbolReference.SymbolType == SymbolType.Property)); + Assert.Single(symbols.Where(symbolReference => symbolReference.SymbolType == SymbolType.Property)); Assert.Equal("AClass.AProperty", firstPropertySymbol.SymbolName); - Assert.Equal(26, firstPropertySymbol.ScriptRegion.StartLineNumber); - Assert.Equal(13, firstPropertySymbol.ScriptRegion.StartColumnNumber); + AssertIsRegion(firstPropertySymbol.NameRegion, 26, 13, 26, 23); SymbolReference firstConstructorSymbol = - Assert.Single(symbolsResult.Where(symbolReference => symbolReference.SymbolType == SymbolType.Constructor)); + Assert.Single(symbols.Where(symbolReference => symbolReference.SymbolType == SymbolType.Constructor)); Assert.Equal("AClass.AClass([string]$AParameter)", firstConstructorSymbol.SymbolName); - Assert.Equal(28, firstConstructorSymbol.ScriptRegion.StartLineNumber); - Assert.Equal(5, firstConstructorSymbol.ScriptRegion.StartColumnNumber); + AssertIsRegion(firstConstructorSymbol.NameRegion, 28, 5, 28, 11); SymbolReference firstMethodSymbol = - Assert.Single(symbolsResult.Where(symbolReference => symbolReference.SymbolType == SymbolType.Method)); + Assert.Single(symbols.Where(symbolReference => symbolReference.SymbolType == SymbolType.Method)); Assert.Equal("AClass.AMethod([string]$param1, [int]$param2, $param3)", firstMethodSymbol.SymbolName); - Assert.Equal(32, firstMethodSymbol.ScriptRegion.StartLineNumber); - Assert.Equal(11, firstMethodSymbol.ScriptRegion.StartColumnNumber); + AssertIsRegion(firstMethodSymbol.NameRegion, 32, 11, 32, 18); SymbolReference firstEnumSymbol = - Assert.Single(symbolsResult.Where(symbolReference => symbolReference.SymbolType == SymbolType.Enum)); + Assert.Single(symbols.Where(symbolReference => symbolReference.SymbolType == SymbolType.Enum)); Assert.Equal("AEnum", firstEnumSymbol.SymbolName); - Assert.Equal(37, firstEnumSymbol.ScriptRegion.StartLineNumber); - Assert.Equal(6, firstEnumSymbol.ScriptRegion.StartColumnNumber); + AssertIsRegion(firstEnumSymbol.NameRegion, 37, 6, 37, 11); SymbolReference firstEnumMemberSymbol = - Assert.Single(symbolsResult.Where(symbolReference => symbolReference.SymbolType == SymbolType.EnumMember)); + Assert.Single(symbols.Where(symbolReference => symbolReference.SymbolType == SymbolType.EnumMember)); Assert.Equal("AEnum.AValue", firstEnumMemberSymbol.SymbolName); - Assert.Equal(38, firstEnumMemberSymbol.ScriptRegion.StartLineNumber); - Assert.Equal(5, firstEnumMemberSymbol.ScriptRegion.StartColumnNumber); + AssertIsRegion(firstEnumMemberSymbol.NameRegion, 38, 5, 38, 11); } [Fact] @@ -625,44 +657,44 @@ public void FindsSymbolsWithNewLineInFile() SymbolReference firstFunctionSymbol = Assert.Single(symbols.Where(symbolReference => symbolReference.SymbolType == SymbolType.Function)); Assert.Equal("returnTrue", firstFunctionSymbol.SymbolName); - Assert.Equal(2, firstFunctionSymbol.ScriptRegion.StartLineNumber); - Assert.Equal(1, firstFunctionSymbol.ScriptRegion.StartColumnNumber); + AssertIsRegion(firstFunctionSymbol.NameRegion, 2, 1, 2, 11); + AssertIsRegion(firstFunctionSymbol.ScriptRegion, 1, 1, 4, 2); SymbolReference firstClassSymbol = Assert.Single(symbols.Where(symbolReference => symbolReference.SymbolType == SymbolType.Class)); Assert.Equal("NewLineClass", firstClassSymbol.SymbolName); - Assert.Equal(7, firstClassSymbol.ScriptRegion.StartLineNumber); - Assert.Equal(1, firstClassSymbol.ScriptRegion.StartColumnNumber); + AssertIsRegion(firstClassSymbol.NameRegion, 7, 1, 7, 13); + AssertIsRegion(firstClassSymbol.ScriptRegion, 6, 1, 23, 2); SymbolReference firstConstructorSymbol = Assert.Single(symbols.Where(symbolReference => symbolReference.SymbolType == SymbolType.Constructor)); Assert.Equal("NewLineClass.NewLineClass()", firstConstructorSymbol.SymbolName); - Assert.Equal(8, firstConstructorSymbol.ScriptRegion.StartLineNumber); - Assert.Equal(5, firstConstructorSymbol.ScriptRegion.StartColumnNumber); + AssertIsRegion(firstConstructorSymbol.NameRegion, 8, 5, 8, 17); + AssertIsRegion(firstConstructorSymbol.ScriptRegion, 8, 5, 10, 6); SymbolReference firstPropertySymbol = Assert.Single(symbols.Where(symbolReference => symbolReference.SymbolType == SymbolType.Property)); Assert.Equal("NewLineClass.SomePropWithDefault", firstPropertySymbol.SymbolName); - Assert.Equal(15, firstPropertySymbol.ScriptRegion.StartLineNumber); - Assert.Equal(5, firstPropertySymbol.ScriptRegion.StartColumnNumber); + AssertIsRegion(firstPropertySymbol.NameRegion, 15, 5, 15, 25); + AssertIsRegion(firstPropertySymbol.ScriptRegion, 12, 5, 15, 40); SymbolReference firstMethodSymbol = Assert.Single(symbols.Where(symbolReference => symbolReference.SymbolType == SymbolType.Method)); Assert.Equal("NewLineClass.MyClassMethod([MyNewLineEnum]$param1)", firstMethodSymbol.SymbolName); - Assert.Equal(20, firstMethodSymbol.ScriptRegion.StartLineNumber); - Assert.Equal(5, firstMethodSymbol.ScriptRegion.StartColumnNumber); + AssertIsRegion(firstMethodSymbol.NameRegion, 20, 5, 20, 18); + AssertIsRegion(firstMethodSymbol.ScriptRegion, 17, 5, 22, 6); SymbolReference firstEnumSymbol = Assert.Single(symbols.Where(symbolReference => symbolReference.SymbolType == SymbolType.Enum)); Assert.Equal("MyNewLineEnum", firstEnumSymbol.SymbolName); - Assert.Equal(26, firstEnumSymbol.ScriptRegion.StartLineNumber); - Assert.Equal(1, firstEnumSymbol.ScriptRegion.StartColumnNumber); + AssertIsRegion(firstEnumSymbol.NameRegion, 26, 1, 26, 14); + AssertIsRegion(firstEnumSymbol.ScriptRegion, 25, 1, 28, 2); SymbolReference firstEnumMemberSymbol = Assert.Single(symbols.Where(symbolReference => symbolReference.SymbolType == SymbolType.EnumMember)); Assert.Equal("MyNewLineEnum.First", firstEnumMemberSymbol.SymbolName); - Assert.Equal(27, firstEnumMemberSymbol.ScriptRegion.StartLineNumber); - Assert.Equal(5, firstEnumMemberSymbol.ScriptRegion.StartColumnNumber); + AssertIsRegion(firstEnumMemberSymbol.NameRegion, 27, 5, 27, 10); + AssertIsRegion(firstEnumMemberSymbol.ScriptRegion, 27, 5, 27, 10); } [SkippableFact] diff --git a/test/PowerShellEditorServices.Test/Services/Symbols/AstOperationsTests.cs b/test/PowerShellEditorServices.Test/Services/Symbols/AstOperationsTests.cs index 67213a71f..157caacd9 100644 --- a/test/PowerShellEditorServices.Test/Services/Symbols/AstOperationsTests.cs +++ b/test/PowerShellEditorServices.Test/Services/Symbols/AstOperationsTests.cs @@ -59,10 +59,10 @@ public void CanFindReferencesOfSymbolAtPosition(int lineNumber, int columnNumber int positionsIndex = 0; foreach (SymbolReference reference in references.OrderBy((i) => i.ScriptRegion.ToRange().Start)) { - Assert.Equal(symbolRange[positionsIndex].Start.Line, reference.ScriptRegion.StartLineNumber); - Assert.Equal(symbolRange[positionsIndex].Start.Character, reference.ScriptRegion.StartColumnNumber); - Assert.Equal(symbolRange[positionsIndex].End.Line, reference.ScriptRegion.EndLineNumber); - Assert.Equal(symbolRange[positionsIndex].End.Character, reference.ScriptRegion.EndColumnNumber); + Assert.Equal(symbolRange[positionsIndex].Start.Line, reference.NameRegion.StartLineNumber); + Assert.Equal(symbolRange[positionsIndex].Start.Character, reference.NameRegion.StartColumnNumber); + Assert.Equal(symbolRange[positionsIndex].End.Line, reference.NameRegion.EndLineNumber); + Assert.Equal(symbolRange[positionsIndex].End.Character, reference.NameRegion.EndColumnNumber); positionsIndex++; }