diff --git a/lldb/include/lldb/Interpreter/Args.h b/lldb/include/lldb/Interpreter/Args.h index e11636b63f17..e79318ba5626 100644 --- a/lldb/include/lldb/Interpreter/Args.h +++ b/lldb/include/lldb/Interpreter/Args.h @@ -424,6 +424,9 @@ public: static void ExpandEscapedCharacters (const char *src, std::string &dst); + static std::string + EscapeLLDBCommandArgument (const std::string& arg, char quote_char); + // This one isn't really relevant to Arguments per se, but we're using the Args as a // general strings container, so... void diff --git a/lldb/source/Interpreter/Args.cpp b/lldb/source/Interpreter/Args.cpp index 2895f0ebdeae..d9371fe9fa96 100644 --- a/lldb/source/Interpreter/Args.cpp +++ b/lldb/source/Interpreter/Args.cpp @@ -1668,3 +1668,33 @@ Args::ExpandEscapedCharacters (const char *src, std::string &dst) } } +std::string +Args::EscapeLLDBCommandArgument (const std::string& arg, char quote_char) +{ + const char* chars_to_escape = nullptr; + switch (quote_char) + { + case '\0': + chars_to_escape = " \t\\'\"`"; + break; + case '\'': + chars_to_escape = ""; + break; + case '"': + chars_to_escape = "$\"`\\"; + break; + default: + assert(false && "Unhandled quote character"); + } + + std::string res; + res.reserve(arg.size()); + for (char c : arg) + { + if (::strchr(chars_to_escape, c)) + res.push_back('\\'); + res.push_back(c); + } + return res; +} + diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp index 1147d1330dea..fa1c8af9091e 100644 --- a/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/lldb/source/Interpreter/CommandInterpreter.cpp @@ -2002,7 +2002,7 @@ CommandInterpreter::HandleCompletion (const char *current_line, matches); if (num_command_matches <= 0) - return num_command_matches; + return num_command_matches; if (num_args == 0) { @@ -2021,18 +2021,18 @@ CommandInterpreter::HandleCompletion (const char *current_line, std::string common_prefix; matches.LongestCommonPrefix (common_prefix); const size_t partial_name_len = command_partial_str.size(); + common_prefix.erase (0, partial_name_len); // If we matched a unique single command, add a space... // Only do this if the completer told us this was a complete word, however... if (num_command_matches == 1 && word_complete) { char quote_char = parsed_line.GetArgumentQuoteCharAtIndex(cursor_index); + common_prefix = Args::EscapeLLDBCommandArgument(common_prefix, quote_char); if (quote_char != '\0') common_prefix.push_back(quote_char); - common_prefix.push_back(' '); } - common_prefix.erase (0, partial_name_len); matches.InsertStringAtIndex(0, common_prefix.c_str()); } return num_command_matches; diff --git a/lldb/test/functionalities/completion/Makefile b/lldb/test/functionalities/completion/Makefile new file mode 100644 index 000000000000..8a7102e347af --- /dev/null +++ b/lldb/test/functionalities/completion/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../make + +CXX_SOURCES := main.cpp + +include $(LEVEL)/Makefile.rules diff --git a/lldb/test/functionalities/completion/TestCompletion.py b/lldb/test/functionalities/completion/TestCompletion.py index 5eed47a45b0a..c02e40bcfc12 100644 --- a/lldb/test/functionalities/completion/TestCompletion.py +++ b/lldb/test/functionalities/completion/TestCompletion.py @@ -219,6 +219,23 @@ class CommandLineCompletionTestCase(TestBase): """Test that 'target va' completes to 'target variable '.""" self.complete_from_to('target va', 'target variable ') + @skipUnlessDarwin + @dsym_test + def test_symbol_name_dsym(self): + self.buildDsym() + self.complete_from_to('''file a.out + breakpoint set -n Fo''', + 'breakpoint set -n Foo::Bar(int,\\ int)', + turn_off_re_match=True) + + @dwarf_test + def test_symbol_name_dwarf(self): + self.buildDwarf() + self.complete_from_to('''file a.out + breakpoint set -n Fo''', + 'breakpoint set -n Foo::Bar(int,\\ int)', + turn_off_re_match=True) + def complete_from_to(self, str_input, patterns, turn_off_re_match=False): """Test that the completion mechanism completes str_input to patterns, where patterns could be a pattern-string or a list of pattern-strings""" diff --git a/lldb/test/functionalities/completion/main.cpp b/lldb/test/functionalities/completion/main.cpp new file mode 100644 index 000000000000..b408720d2cdc --- /dev/null +++ b/lldb/test/functionalities/completion/main.cpp @@ -0,0 +1,14 @@ +class Foo +{ +public: + int Bar(int x, int y) + { + return x + y; + } +}; + +int main() +{ + Foo f; + f.Bar(1, 2); +}