Skip to content

Completion crashes when using = syntax for options #2279

Open
@zivarah

Description

@zivarah

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions