From 4c593da24bf23839cad7ab65d49c707d773ad85b Mon Sep 17 00:00:00 2001 From: MartinGC94 Date: Thu, 13 Apr 2023 19:37:42 +0200 Subject: [PATCH 1/2] Fix CompleteInput error for empty scripts --- .../engine/CommandCompletion/CompletionAnalysis.cs | 5 +++++ .../engine/InitialSessionState.cs | 3 ++- .../powershell/Host/TabCompletion/TabCompletion.Tests.ps1 | 8 ++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/System.Management.Automation/engine/CommandCompletion/CompletionAnalysis.cs b/src/System.Management.Automation/engine/CommandCompletion/CompletionAnalysis.cs index 9315880138a..4f02f251623 100644 --- a/src/System.Management.Automation/engine/CommandCompletion/CompletionAnalysis.cs +++ b/src/System.Management.Automation/engine/CommandCompletion/CompletionAnalysis.cs @@ -155,6 +155,11 @@ internal static AstAnalysisContext ExtractAstContext(Ast inputAst, Token[] input ast => IsCursorWithinOrJustAfterExtent(positionForAstSearch, ast.Extent), searchNestedScriptBlocks: true).ToList(); + if (relatedAsts.Count == 0) + { + relatedAsts.Add(inputAst); + } + // If the last ast is an unnamed block that starts with "param" the cursor is inside a param block. // To avoid adding special handling to all the completers that look at the last ast, we remove it here because it's not useful for completion. if (relatedAsts[^1].Extent.Text.StartsWith("param", StringComparison.OrdinalIgnoreCase) diff --git a/src/System.Management.Automation/engine/InitialSessionState.cs b/src/System.Management.Automation/engine/InitialSessionState.cs index 4cf2bc44e35..d5cdfe1ebaa 100644 --- a/src/System.Management.Automation/engine/InitialSessionState.cs +++ b/src/System.Management.Automation/engine/InitialSessionState.cs @@ -4044,6 +4044,7 @@ internal void ImportCmdletsFromAssembly(Assembly assembly, PSModuleInfo module) [OutputType([System.Management.Automation.CommandCompletion])] Param( [Parameter(ParameterSetName = 'ScriptInputSet', Mandatory = $true, Position = 0)] + [AllowEmptyString()] [string] $inputScript, [Parameter(ParameterSetName = 'ScriptInputSet', Position = 1)] @@ -4081,7 +4082,7 @@ internal void ImportCmdletsFromAssembly(Assembly assembly, PSModuleInfo module) <#options#> $options) } } - "; +"; /// /// This is the default function to use for clear-host. diff --git a/test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1 b/test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1 index d7c98b1589d..f0c8c34fa40 100644 --- a/test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1 +++ b/test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1 @@ -1997,6 +1997,14 @@ dir -Recurse ` param($inputStr, $expected) $inputStr | Should -Throw -ErrorId $expected } + + It "Should not throw errors in tab completion with empty input string" { + {[System.Management.Automation.CommandCompletion]::CompleteInput("", 0, $null)} | Should -Not -Throw + } + + It "Should not throw errors in tab completion with empty input ast" { + {[System.Management.Automation.CommandCompletion]::CompleteInput({}.Ast, @(), {}.Ast.Extent.StartScriptPosition, $null)} | Should -Not -Throw + } } Context "DSC tab completion tests" { From a9c675df07f4fc1d9117cc817af4e115878929b7 Mon Sep 17 00:00:00 2001 From: MartinGC94 Date: Tue, 9 May 2023 15:57:21 +0200 Subject: [PATCH 2/2] Add Dongbo suggestions. --- .../engine/CommandCompletion/CommandCompletion.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/System.Management.Automation/engine/CommandCompletion/CommandCompletion.cs b/src/System.Management.Automation/engine/CommandCompletion/CommandCompletion.cs index 21b4832a363..0da165775a8 100644 --- a/src/System.Management.Automation/engine/CommandCompletion/CommandCompletion.cs +++ b/src/System.Management.Automation/engine/CommandCompletion/CommandCompletion.cs @@ -93,7 +93,7 @@ public static Tuple MapStringInputToParsedInput(s /// public static CommandCompletion CompleteInput(string input, int cursorIndex, Hashtable options) { - if (input == null) + if (input == null || input.Length == 0) { return s_emptyCommandCompletion; } @@ -126,6 +126,11 @@ public static CommandCompletion CompleteInput(Ast ast, Token[] tokens, IScriptPo throw PSTraceSource.NewArgumentNullException(nameof(positionOfCursor)); } + if (ast.Extent.Text.Length == 0) + { + return s_emptyCommandCompletion; + } + return CompleteInputImpl(ast, tokens, positionOfCursor, options); } @@ -141,7 +146,7 @@ public static CommandCompletion CompleteInput(Ast ast, Token[] tokens, IScriptPo [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "powershell")] public static CommandCompletion CompleteInput(string input, int cursorIndex, Hashtable options, PowerShell powershell) { - if (input == null) + if (input == null || input.Length == 0) { return s_emptyCommandCompletion; } @@ -231,6 +236,11 @@ public static CommandCompletion CompleteInput(Ast ast, Token[] tokens, IScriptPo throw PSTraceSource.NewArgumentNullException(nameof(powershell)); } + if (ast.Extent.Text.Length == 0) + { + return s_emptyCommandCompletion; + } + // If we are in a debugger stop, let the debugger do the command completion. var debugger = powershell.Runspace?.Debugger; if ((debugger != null) && debugger.InBreakpoint)