Description
System.CommandLine version: 2.0.0-beta4.22272.1
There is a mismatch between how =
is handled between splitting up the tokens and processing words for completion, which results in a crash.
using System.CommandLine;
using System.CommandLine.Builder;
using System.CommandLine.Parsing;
RootCommand root = new();
root.AddOption(new Option<string>("--test").AddCompletions("asdf"));
CommandLineBuilder builder = new(root);
builder.UseDefaults();
return await builder.Build().InvokeAsync(args);
Attempting tab completion on CompletionCrashRepro --test=asd
results in a crash:
> System.Linq.dll!System.Linq.ThrowHelper.ThrowNoMatchException() Line 27 C#
System.Linq.dll!System.Linq.Enumerable.Last<System.CommandLine.Parsing.Token>(System.Collections.Generic.IEnumerable<System.CommandLine.Parsing.Token> source, System.Func<System.CommandLine.Parsing.Token, bool> predicate) Line 30 C#
System.CommandLine.dll!System.CommandLine.Parsing.ParseResult.SymbolToComplete.__WillAcceptAnArgument|42_1(System.CommandLine.Parsing.ParseResult parseResult, int? position, System.CommandLine.Parsing.OptionResult optionResult) Line 305 C#
System.CommandLine.dll!System.CommandLine.Parsing.ParseResult.SymbolToComplete.__AllSymbolResultsForCompletion|0() Line 271 C#
System.Linq.dll!System.Collections.Generic.LargeArrayBuilder<System.CommandLine.Parsing.SymbolResult>.AddRange(System.Collections.Generic.IEnumerable<System.CommandLine.Parsing.SymbolResult> items) Line 116 C#
System.Linq.dll!System.Collections.Generic.EnumerableHelpers.ToArray<System.CommandLine.Parsing.SymbolResult>(System.Collections.Generic.IEnumerable<System.CommandLine.Parsing.SymbolResult> source) Line 85 C#
System.Linq.dll!System.Linq.Enumerable.ToArray<System.CommandLine.Parsing.SymbolResult>(System.Collections.Generic.IEnumerable<System.CommandLine.Parsing.SymbolResult> source) Line 17 C#
System.CommandLine.dll!System.CommandLine.Parsing.ParseResult.SymbolToComplete(int? position) Line 255 C#
System.CommandLine.dll!System.CommandLine.Parsing.ParseResult.GetCompletions(int? position) Line 219 C#
System.CommandLine.dll!System.CommandLine.Invocation.SuggestDirectiveResult.Apply(System.CommandLine.Invocation.InvocationContext context) Line 25 C#
System.CommandLine.dll!System.CommandLine.Invocation.InvocationPipeline.GetExitCode(System.CommandLine.Invocation.InvocationContext context) Line 98 C#
System.CommandLine.dll!System.CommandLine.Invocation.InvocationPipeline.InvokeAsync.__FullInvocationChainAsync|2_0(System.CommandLine.Invocation.InvocationContext context) Line 38 C#
System.CommandLine.dll!System.CommandLine.Invocation.InvocationPipeline.InvokeAsync(System.CommandLine.IConsole console) Line 30 C#
System.CommandLine.dll!System.CommandLine.Parsing.ParseResultExtensions.InvokeAsync(System.CommandLine.Parsing.ParseResult parseResult, System.CommandLine.IConsole console) Line 27 C#
System.CommandLine.dll!System.CommandLine.Parsing.ParserExtensions.InvokeAsync(System.CommandLine.Parsing.Parser parser, string[] args, System.CommandLine.IConsole console) Line 54 C#
CompletionCrashRepro.dll!Program.<Main>$(string[] args) Line 15 C#
CompletionCrashRepro.dll!Program.<Main>(string[] args) Unknown
This same crash does not occur if a space is used instead of =
: CompletionCrashRepro --test asd
, and the completion works as expected.
(Note: I found the easiest way to actually reproduce this was by running this with the arguments of: [suggest:30] "CompletionCrashRepro --test=asd"
rather than actually doing tab completion.)
The reason for this is that ParseResult.WillAcceptAnArgument
has this line:
var tokenToComplete = parseResult.Tokens.Last(t => t.Value == textCompletionContext.WordToComplete);
However, the =
is stripped out in parseResult.Tokens
(["--test", "asd"]
), but not in textCompletionContext.WordToComplete
("--test=asd"
). This results in .Last(...)
finding no matches, which crashes.