Skip to content

[LLDB]Provide clearer error message for invalid commands. #111891

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lldb/include/lldb/Interpreter/CommandObjectMultiword.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ class CommandObjectMultiword : public CommandObject {
return m_subcommand_dict;
}

std::string GetSubcommandsHintText();

CommandObject::CommandMap m_subcommand_dict;
bool m_can_be_removed;
};
Expand Down
46 changes: 36 additions & 10 deletions lldb/source/Commands/CommandObjectMultiword.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,28 +194,54 @@ void CommandObjectMultiword::Execute(const char *args_string,

std::string error_msg;
const size_t num_subcmd_matches = matches.GetSize();
if (num_subcmd_matches > 0)
if (num_subcmd_matches > 0) {
error_msg.assign("ambiguous command ");
else
error_msg.assign("invalid command ");

error_msg.append("'");
error_msg.append(std::string(GetCommandName()));
error_msg.append(" ");
error_msg.append(std::string(sub_command));
error_msg.append("'.");
error_msg.append("'");
error_msg.append(std::string(GetCommandName()));
error_msg.append(" ");
error_msg.append(std::string(sub_command));
error_msg.append("'.");

if (num_subcmd_matches > 0) {
error_msg.append(" Possible completions:");
for (const std::string &match : matches) {
error_msg.append("\n\t");
error_msg.append(match);
}
} else {
// Try to offer some alternatives to help correct the command.
error_msg.assign(
llvm::Twine("'" + sub_command + "' is not a valid subcommand of \"" +
GetCommandName() + "\"." + GetSubcommandsHintText() +
" Use \"help " + GetCommandName() + "\" to find out more.")
.str());
}
error_msg.append("\n");
result.AppendRawError(error_msg.c_str());
}

std::string CommandObjectMultiword::GetSubcommandsHintText() {
if (m_subcommand_dict.empty())
return "";
const size_t maxCount = 5;
size_t i = 0;
std::string buffer = " Valid subcommand";
buffer.append(m_subcommand_dict.size() > 1 ? "s are:" : "is");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're missing a space before "is". The output will also be garbled for the case of zero subcommands (I think such a thing can happen if the user registers a custom multiword command (SBCommandInterpreter::AddMultiwordCommand), but does not add any subcommands to it).

Copy link
Member Author

@oontvoo oontvoo Oct 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're missing a space before "is"

Done.

The output will also be garbled for the case of zero subcommands

Which output? the error msg as a whole or just this function's output?

unless i'm missing something, if there are zero subcommands, the function would have returned "" on line 223, which means the error message would have been something like "foo" is not a valid subcommand of "breakpoint". Use "help breakpoint" to find out more. (ie., there will be no suggestions on subcommands).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right. I missed the empty() check at the beginning of the function.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right. I missed the empty() check at the beginning of the function.

CommandMap::iterator pos;
for (pos = m_subcommand_dict.begin();
pos != m_subcommand_dict.end() && i < maxCount; ++pos, ++i) {
buffer.append(" ");
buffer.append(pos->first);
buffer.append(",");
}
if (i < m_subcommand_dict.size())
buffer.append(" and others");
else
buffer.pop_back();

buffer.append(".");
return buffer;
}

void CommandObjectMultiword::GenerateHelpText(Stream &output_stream) {
// First time through here, generate the help text for the object and push it
// to the return result object as well
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# UNSUPPORTED: system-windows
#
# RUN: %clang_host -g -O0 %S/Inputs/main.c -o %t.out
# RUN: not %lldb -b -o 'breakpoint foo' %t.out -o exit 2>&1 | FileCheck %s --check-prefix BP-MSG
# RUN: not %lldb -b -o 'watchpoint set foo' %t.out -o exit 2>&1 | FileCheck %s --check-prefix WP-MSG
# CHECK: at main.c:2:21
# BP-MSG: 'foo' is not a valid subcommand of "breakpoint". Valid subcommands are: clear, command, delete, disable, enable, and others. Use "help breakpoint" to find out more.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'foo' is not a valid subcommand of "breakpoint"
It would be nice if we could be consistent about the kind of quotes we use at least within a single sentence.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

# WP-MSG: 'foo' is not a valid subcommand of "watchpoint set". Valid subcommands are: expression, variable. Use "help watchpoint set" to find out more.
Loading