[Lldb-commits] [lldb] [lldb-dap] Do not show warnings on Completions request. (PR #172917)
Ebuka Ezike via lldb-commits
lldb-commits at lists.llvm.org
Thu Dec 18 14:37:59 PST 2025
https://github.com/da-viper created https://github.com/llvm/llvm-project/pull/172917
Why typing a command that happens to start with a variable, there are warnings complaining about the ambiguous expression.
>From 6698c9117096349bdfce54983d2c1514f6d6161b Mon Sep 17 00:00:00 2001
From: Ebuka Ezike <yerimyah1 at gmail.com>
Date: Thu, 18 Dec 2025 22:32:40 +0000
Subject: [PATCH] [lldb-dap] Do not show warnings on Completions request.
---
.../completions/TestDAP_completions.py | 11 +++
lldb/tools/lldb-dap/DAP.cpp | 95 +++++++++----------
lldb/tools/lldb-dap/DAP.h | 2 +-
3 files changed, 57 insertions(+), 51 deletions(-)
diff --git a/lldb/test/API/tools/lldb-dap/completions/TestDAP_completions.py b/lldb/test/API/tools/lldb-dap/completions/TestDAP_completions.py
index 954a3a4b7d14e..0ebecf6872a7d 100644
--- a/lldb/test/API/tools/lldb-dap/completions/TestDAP_completions.py
+++ b/lldb/test/API/tools/lldb-dap/completions/TestDAP_completions.py
@@ -244,6 +244,10 @@ def test_auto_completions(self):
self.assertTrue(res["success"])
self.continue_to_next_stop()
+
+ # Stopped at breakpoint 1
+ # 'var' variable is in scope, completions should not show any warning.
+ self.dap_server.get_completions("var ")
self.continue_to_next_stop()
# We are stopped inside `main`. Variables `var1` and `var2` are in scope.
@@ -268,3 +272,10 @@ def test_auto_completions(self):
variable_var2_completion,
],
)
+
+ self.continue_to_exit()
+ console_str = self.get_console()
+ # we check in console to avoid waiting for output event.
+ self.assertNotIn(
+ "Expression 'var' is both an LLDB command and variable", console_str
+ )
diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp
index 58c9922214583..19743eb26572d 100644
--- a/lldb/tools/lldb-dap/DAP.cpp
+++ b/lldb/tools/lldb-dap/DAP.cpp
@@ -594,63 +594,58 @@ lldb::SBFrame DAP::GetLLDBFrame(const llvm::json::Object &arguments) {
return GetLLDBFrame(frame_id);
}
-ReplMode DAP::DetectReplMode(lldb::SBFrame frame, std::string &expression,
+ReplMode DAP::DetectReplMode(lldb::SBFrame &frame, std::string &expression,
bool partial_expression) {
// Check for the escape hatch prefix.
- if (!expression.empty() &&
- llvm::StringRef(expression)
- .starts_with(configuration.commandEscapePrefix)) {
- expression = expression.substr(configuration.commandEscapePrefix.size());
+ if (llvm::StringRef expr_ref = expression;
+ expr_ref.consume_front(configuration.commandEscapePrefix)) {
+ expression = expr_ref;
return ReplMode::Command;
}
- switch (repl_mode) {
- case ReplMode::Variable:
- return ReplMode::Variable;
- case ReplMode::Command:
- return ReplMode::Command;
- case ReplMode::Auto:
- // To determine if the expression is a command or not, check if the first
- // term is a variable or command. If it's a variable in scope we will prefer
- // that behavior and give a warning to the user if they meant to invoke the
- // operation as a command.
- //
- // Example use case:
- // int p and expression "p + 1" > variable
- // int i and expression "i" > variable
- // int var and expression "va" > command
- std::pair<llvm::StringRef, llvm::StringRef> token =
- llvm::getToken(expression);
-
- // If the first token is not fully finished yet, we can't
- // determine whether this will be a variable or a lldb command.
- if (partial_expression && token.second.empty())
- return ReplMode::Auto;
-
- std::string term = token.first.str();
- lldb::SBCommandInterpreter interpreter = debugger.GetCommandInterpreter();
- bool term_is_command = interpreter.CommandExists(term.c_str()) ||
- interpreter.UserCommandExists(term.c_str()) ||
- interpreter.AliasExists(term.c_str());
- bool term_is_variable = frame.FindVariable(term.c_str()).IsValid();
-
- // If we have both a variable and command, warn the user about the conflict.
- if (term_is_command && term_is_variable) {
- llvm::errs()
- << "Warning: Expression '" << term
- << "' is both an LLDB command and variable. It will be evaluated as "
- "a variable. To evaluate the expression as an LLDB command, use '"
- << configuration.commandEscapePrefix << "' as a prefix.\n";
- }
-
- // Variables take preference to commands in auto, since commands can always
- // be called using the command_escape_prefix
- return term_is_variable ? ReplMode::Variable
- : term_is_command ? ReplMode::Command
- : ReplMode::Variable;
+ if (repl_mode != ReplMode::Auto)
+ return repl_mode;
+ // To determine if the expression is a command or not, check if the first
+ // term is a variable or command. If it's a variable in scope we will prefer
+ // that behavior and give a warning to the user if they meant to invoke the
+ // operation as a command.
+ //
+ // Example use case:
+ // int p and expression "p + 1" > variable
+ // int i and expression "i" > variable
+ // int var and expression "va" > command
+ const auto [first_tok, remaining] = llvm::getToken(expression);
+
+ // If the first token is not fully finished yet, we can't
+ // determine whether this will be a variable or a lldb command.
+ if (partial_expression && remaining.empty())
+ return ReplMode::Auto;
+
+ std::string first = first_tok.str();
+ const char *first_cstr = first.c_str();
+ lldb::SBCommandInterpreter interpreter = debugger.GetCommandInterpreter();
+ const bool is_command = interpreter.CommandExists(first_cstr) ||
+ interpreter.UserCommandExists(first_cstr) ||
+ interpreter.AliasExists(first_cstr);
+ const bool is_variable = frame.FindVariable(first_cstr).IsValid();
+
+ // If we have both a variable and command, warn the user about the conflict.
+ if (!partial_expression && is_command && is_variable) {
+ const std::string warning_msg =
+ llvm::formatv("warning: Expression '{}' is both an LLDB command and "
+ "variable. It will be evaluated as "
+ "a variable. To evaluate the expression as an LLDB "
+ "command, use '{}' as a prefix.\n",
+ first, configuration.commandEscapePrefix);
+ this->SendOutput(OutputType::Console, warning_msg);
}
- llvm_unreachable("enum cases exhausted.");
+ // Variables take preference to commands in auto, since commands can always
+ // be called using the command_escape_prefix
+ if (is_variable)
+ return ReplMode::Variable;
+
+ return is_command ? ReplMode::Command : ReplMode::Variable;
}
std::optional<protocol::Source> DAP::ResolveSource(const lldb::SBFrame &frame) {
diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h
index 01139221ea37f..9500c82a853c8 100644
--- a/lldb/tools/lldb-dap/DAP.h
+++ b/lldb/tools/lldb-dap/DAP.h
@@ -270,7 +270,7 @@ struct DAP final : public DAPTransport::MessageHandler {
/// either an expression or a statement, depending on the rest of
/// the expression.
/// \return the expression mode
- ReplMode DetectReplMode(lldb::SBFrame frame, std::string &expression,
+ ReplMode DetectReplMode(lldb::SBFrame &frame, std::string &expression,
bool partial_expression);
/// Create a `protocol::Source` object as described in the debug adapter
More information about the lldb-commits
mailing list