Skip to content

Commit 4160320

Browse files
authored
[lldb-dap] Do not show warnings on Completions request. (llvm#172917)
Why typing a command that happens to start with a variable, there are warnings complaining about the ambiguous expression.
1 parent b9984f5 commit 4160320

File tree

3 files changed

+57
-51
lines changed

3 files changed

+57
-51
lines changed

lldb/test/API/tools/lldb-dap/completions/TestDAP_completions.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,10 @@ def test_auto_completions(self):
244244
self.assertTrue(res["success"])
245245

246246
self.continue_to_next_stop()
247+
248+
# Stopped at breakpoint 1
249+
# 'var' variable is in scope, completions should not show any warning.
250+
self.dap_server.get_completions("var ")
247251
self.continue_to_next_stop()
248252

249253
# We are stopped inside `main`. Variables `var1` and `var2` are in scope.
@@ -268,3 +272,10 @@ def test_auto_completions(self):
268272
variable_var2_completion,
269273
],
270274
)
275+
276+
self.continue_to_exit()
277+
console_str = self.get_console()
278+
# we check in console to avoid waiting for output event.
279+
self.assertNotIn(
280+
"Expression 'var' is both an LLDB command and variable", console_str
281+
)

lldb/tools/lldb-dap/DAP.cpp

Lines changed: 45 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -594,63 +594,58 @@ lldb::SBFrame DAP::GetLLDBFrame(const llvm::json::Object &arguments) {
594594
return GetLLDBFrame(frame_id);
595595
}
596596

597-
ReplMode DAP::DetectReplMode(lldb::SBFrame frame, std::string &expression,
597+
ReplMode DAP::DetectReplMode(lldb::SBFrame &frame, std::string &expression,
598598
bool partial_expression) {
599599
// Check for the escape hatch prefix.
600-
if (!expression.empty() &&
601-
llvm::StringRef(expression)
602-
.starts_with(configuration.commandEscapePrefix)) {
603-
expression = expression.substr(configuration.commandEscapePrefix.size());
600+
if (llvm::StringRef expr_ref = expression;
601+
expr_ref.consume_front(configuration.commandEscapePrefix)) {
602+
expression = expr_ref;
604603
return ReplMode::Command;
605604
}
606605

607-
switch (repl_mode) {
608-
case ReplMode::Variable:
609-
return ReplMode::Variable;
610-
case ReplMode::Command:
611-
return ReplMode::Command;
612-
case ReplMode::Auto:
613-
// To determine if the expression is a command or not, check if the first
614-
// term is a variable or command. If it's a variable in scope we will prefer
615-
// that behavior and give a warning to the user if they meant to invoke the
616-
// operation as a command.
617-
//
618-
// Example use case:
619-
// int p and expression "p + 1" > variable
620-
// int i and expression "i" > variable
621-
// int var and expression "va" > command
622-
std::pair<llvm::StringRef, llvm::StringRef> token =
623-
llvm::getToken(expression);
624-
625-
// If the first token is not fully finished yet, we can't
626-
// determine whether this will be a variable or a lldb command.
627-
if (partial_expression && token.second.empty())
628-
return ReplMode::Auto;
629-
630-
std::string term = token.first.str();
631-
lldb::SBCommandInterpreter interpreter = debugger.GetCommandInterpreter();
632-
bool term_is_command = interpreter.CommandExists(term.c_str()) ||
633-
interpreter.UserCommandExists(term.c_str()) ||
634-
interpreter.AliasExists(term.c_str());
635-
bool term_is_variable = frame.FindVariable(term.c_str()).IsValid();
636-
637-
// If we have both a variable and command, warn the user about the conflict.
638-
if (term_is_command && term_is_variable) {
639-
llvm::errs()
640-
<< "Warning: Expression '" << term
641-
<< "' is both an LLDB command and variable. It will be evaluated as "
642-
"a variable. To evaluate the expression as an LLDB command, use '"
643-
<< configuration.commandEscapePrefix << "' as a prefix.\n";
644-
}
645-
646-
// Variables take preference to commands in auto, since commands can always
647-
// be called using the command_escape_prefix
648-
return term_is_variable ? ReplMode::Variable
649-
: term_is_command ? ReplMode::Command
650-
: ReplMode::Variable;
606+
if (repl_mode != ReplMode::Auto)
607+
return repl_mode;
608+
// To determine if the expression is a command or not, check if the first
609+
// term is a variable or command. If it's a variable in scope we will prefer
610+
// that behavior and give a warning to the user if they meant to invoke the
611+
// operation as a command.
612+
//
613+
// Example use case:
614+
// int p and expression "p + 1" > variable
615+
// int i and expression "i" > variable
616+
// int var and expression "va" > command
617+
const auto [first_tok, remaining] = llvm::getToken(expression);
618+
619+
// If the first token is not fully finished yet, we can't
620+
// determine whether this will be a variable or a lldb command.
621+
if (partial_expression && remaining.empty())
622+
return ReplMode::Auto;
623+
624+
std::string first = first_tok.str();
625+
const char *first_cstr = first.c_str();
626+
lldb::SBCommandInterpreter interpreter = debugger.GetCommandInterpreter();
627+
const bool is_command = interpreter.CommandExists(first_cstr) ||
628+
interpreter.UserCommandExists(first_cstr) ||
629+
interpreter.AliasExists(first_cstr);
630+
const bool is_variable = frame.FindVariable(first_cstr).IsValid();
631+
632+
// If we have both a variable and command, warn the user about the conflict.
633+
if (!partial_expression && is_command && is_variable) {
634+
const std::string warning_msg =
635+
llvm::formatv("warning: Expression '{}' is both an LLDB command and "
636+
"variable. It will be evaluated as "
637+
"a variable. To evaluate the expression as an LLDB "
638+
"command, use '{}' as a prefix.\n",
639+
first, configuration.commandEscapePrefix);
640+
SendOutput(OutputType::Console, warning_msg);
651641
}
652642

653-
llvm_unreachable("enum cases exhausted.");
643+
// Variables take preference to commands in auto, since commands can always
644+
// be called using the command_escape_prefix
645+
if (is_variable)
646+
return ReplMode::Variable;
647+
648+
return is_command ? ReplMode::Command : ReplMode::Variable;
654649
}
655650

656651
std::optional<protocol::Source> DAP::ResolveSource(const lldb::SBFrame &frame) {

lldb/tools/lldb-dap/DAP.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ struct DAP final : public DAPTransport::MessageHandler {
270270
/// either an expression or a statement, depending on the rest of
271271
/// the expression.
272272
/// \return the expression mode
273-
ReplMode DetectReplMode(lldb::SBFrame frame, std::string &expression,
273+
ReplMode DetectReplMode(lldb::SBFrame &frame, std::string &expression,
274274
bool partial_expression);
275275

276276
/// Create a `protocol::Source` object as described in the debug adapter

0 commit comments

Comments
 (0)