[Lldb-commits] [lldb] r235633 - Factor resolution of abbreviations and aliases so that they can be tested directly. http://reviews.llvm.org/D9033
Adrian McCarthy
amccarth at google.com
Thu Apr 23 13:00:26 PDT 2015
Author: amccarth
Date: Thu Apr 23 15:00:25 2015
New Revision: 235633
URL: http://llvm.org/viewvc/llvm-project?rev=235633&view=rev
Log:
Factor resolution of abbreviations and aliases so that they can be tested directly. http://reviews.llvm.org/D9033
Modified:
lldb/trunk/include/lldb/API/SBCommandInterpreter.h
lldb/trunk/include/lldb/Interpreter/CommandInterpreter.h
lldb/trunk/scripts/Python/interface/SBCommandInterpreter.i
lldb/trunk/source/API/SBCommandInterpreter.cpp
lldb/trunk/source/Commands/CommandObjectMultiword.cpp
lldb/trunk/source/Interpreter/CommandInterpreter.cpp
lldb/trunk/test/functionalities/abbreviation/TestAbbreviations.py
Modified: lldb/trunk/include/lldb/API/SBCommandInterpreter.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/API/SBCommandInterpreter.h?rev=235633&r1=235632&r2=235633&view=diff
==============================================================================
--- lldb/trunk/include/lldb/API/SBCommandInterpreter.h (original)
+++ lldb/trunk/include/lldb/API/SBCommandInterpreter.h Thu Apr 23 15:00:25 2015
@@ -225,6 +225,13 @@ public:
void
SetPromptOnQuit(bool b);
+ //----------------------------------------------------------------------
+ /// Resolve the command just as HandleCommand would, expanding abbreviations
+ /// and aliases. If successful, result->GetOutput has the full expansion.
+ //----------------------------------------------------------------------
+ void
+ ResolveCommand(const char *command_line, SBCommandReturnObject &result);
+
protected:
lldb_private::CommandInterpreter &
Modified: lldb/trunk/include/lldb/Interpreter/CommandInterpreter.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Interpreter/CommandInterpreter.h?rev=235633&r1=235632&r2=235633&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Interpreter/CommandInterpreter.h (original)
+++ lldb/trunk/include/lldb/Interpreter/CommandInterpreter.h Thu Apr 23 15:00:25 2015
@@ -628,6 +628,9 @@ public:
void
SetPromptOnQuit (bool b);
+ void
+ ResolveCommand(const char *command_line, CommandReturnObject &result);
+
bool
GetStopCmdSourceOnError () const;
@@ -688,6 +691,13 @@ private:
Error
PreprocessCommand (std::string &command);
+ // Completely resolves aliases and abbreviations, returning a pointer to the
+ // final command object and updating command_line to the fully substituted
+ // and translated command.
+ CommandObject *
+ ResolveCommandImpl(std::string &command_line, CommandReturnObject &result);
+
+
Debugger &m_debugger; // The debugger session that this interpreter is associated with
ExecutionContextRef m_exe_ctx_ref; // The current execution context to use when handling commands
bool m_synchronous_execution;
Modified: lldb/trunk/scripts/Python/interface/SBCommandInterpreter.i
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/scripts/Python/interface/SBCommandInterpreter.i?rev=235633&r1=235632&r2=235633&view=diff
==============================================================================
--- lldb/trunk/scripts/Python/interface/SBCommandInterpreter.i (original)
+++ lldb/trunk/scripts/Python/interface/SBCommandInterpreter.i Thu Apr 23 15:00:25 2015
@@ -155,6 +155,9 @@ public:
void
SetPromptOnQuit(bool b);
+ void
+ ResolveCommand(const char *command_line, SBCommandReturnObject &result);
+
bool
CommandExists (const char *cmd);
Modified: lldb/trunk/source/API/SBCommandInterpreter.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/API/SBCommandInterpreter.cpp?rev=235633&r1=235632&r2=235633&view=diff
==============================================================================
--- lldb/trunk/source/API/SBCommandInterpreter.cpp (original)
+++ lldb/trunk/source/API/SBCommandInterpreter.cpp Thu Apr 23 15:00:25 2015
@@ -462,6 +462,22 @@ SBCommandInterpreter::SetPromptOnQuit (b
m_opaque_ptr->SetPromptOnQuit(b);
}
+void
+SBCommandInterpreter::ResolveCommand(const char *command_line, SBCommandReturnObject &result)
+{
+ result.Clear();
+ if (command_line && m_opaque_ptr)
+ {
+ m_opaque_ptr->ResolveCommand(command_line, result.ref());
+ }
+ else
+ {
+ result->AppendError("SBCommandInterpreter or the command line is not valid");
+ result->SetStatus(eReturnStatusFailed);
+ }
+}
+
+
CommandInterpreter *
SBCommandInterpreter::get ()
{
Modified: lldb/trunk/source/Commands/CommandObjectMultiword.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectMultiword.cpp?rev=235633&r1=235632&r2=235633&view=diff
==============================================================================
--- lldb/trunk/source/Commands/CommandObjectMultiword.cpp (original)
+++ lldb/trunk/source/Commands/CommandObjectMultiword.cpp Thu Apr 23 15:00:25 2015
@@ -153,7 +153,7 @@ CommandObjectMultiword::Execute(const ch
error_msg.append (GetCommandName());
error_msg.append (" ");
error_msg.append (sub_command);
- error_msg.append ("'");
+ error_msg.append ("'.");
if (num_subcmd_matches > 0)
{
Modified: lldb/trunk/source/Interpreter/CommandInterpreter.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/CommandInterpreter.cpp?rev=235633&r1=235632&r2=235633&view=diff
==============================================================================
--- lldb/trunk/source/Interpreter/CommandInterpreter.cpp (original)
+++ lldb/trunk/source/Interpreter/CommandInterpreter.cpp Thu Apr 23 15:00:25 2015
@@ -79,6 +79,7 @@
using namespace lldb;
using namespace lldb_private;
+static const char *k_white_space = " \t\v";
static PropertyDefinition
g_properties[] =
@@ -156,6 +157,17 @@ CommandInterpreter::SetPromptOnQuit (boo
m_collection_sp->SetPropertyAtIndexAsBoolean (nullptr, idx, b);
}
+void
+CommandInterpreter::ResolveCommand(const char *command_line, CommandReturnObject &result)
+{
+ std::string command = command_line;
+ if (ResolveCommandImpl(command, result) != nullptr) {
+ result.AppendMessageWithFormat("%s", command.c_str());
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ }
+}
+
+
bool
CommandInterpreter::GetStopCmdSourceOnError () const
{
@@ -1258,8 +1270,7 @@ CommandInterpreter::GetCommandObjectForC
// eventually be invoked by the given command line.
CommandObject *cmd_obj = nullptr;
- std::string white_space (" \t\v");
- size_t start = command_string.find_first_not_of (white_space);
+ size_t start = command_string.find_first_not_of (k_white_space);
size_t end = 0;
bool done = false;
while (!done)
@@ -1267,7 +1278,7 @@ CommandInterpreter::GetCommandObjectForC
if (start != std::string::npos)
{
// Get the next word from command_string.
- end = command_string.find_first_of (white_space, start);
+ end = command_string.find_first_of (k_white_space, start);
if (end == std::string::npos)
end = command_string.size();
std::string cmd_word = command_string.substr (start, end - start);
@@ -1296,7 +1307,7 @@ CommandInterpreter::GetCommandObjectForC
if (!cmd_obj || !cmd_obj->IsMultiwordObject() || end >= command_string.size())
done = true;
else
- start = command_string.find_first_not_of (white_space, end);
+ start = command_string.find_first_not_of (k_white_space, end);
}
else
// Unable to find any more words.
@@ -1311,7 +1322,6 @@ CommandInterpreter::GetCommandObjectForC
return cmd_obj;
}
-static const char *k_white_space = " \t\v";
static const char *k_valid_command_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
static void
StripLeadingSpaces (std::string &s)
@@ -1471,7 +1481,7 @@ CommandInterpreter::BuildAliasResult (co
("Not enough arguments provided; you need at least %d arguments to use this alias.\n",
index);
result.SetStatus (eReturnStatusFailed);
- return alias_cmd_obj;
+ return nullptr;
}
else
{
@@ -1496,7 +1506,7 @@ CommandInterpreter::PreprocessCommand (s
{
// The command preprocessor needs to do things to the command
// line before any parsing of arguments or anything else is done.
- // The only current stuff that gets proprocessed is anyting enclosed
+ // The only current stuff that gets preprocessed is anything enclosed
// in backtick ('`') characters is evaluated as an expression and
// the result of the expression must be a scalar that can be substituted
// into the command. An example would be:
@@ -1637,9 +1647,6 @@ CommandInterpreter::HandleCommand (const
{
- bool done = false;
- CommandObject *cmd_obj = nullptr;
- bool wants_raw_input = false;
std::string command_string (command_line);
std::string original_command_string (command_line);
@@ -1739,192 +1746,34 @@ CommandInterpreter::HandleCommand (const
result.SetStatus(eReturnStatusFailed);
return false;
}
- // Phase 1.
-
- // Before we do ANY kind of argument processing, etc. we need to figure out what the real/final command object
- // is for the specified command, and whether or not it wants raw input. This gets complicated by the fact that
- // the user could have specified an alias, and in translating the alias there may also be command options and/or
- // even data (including raw text strings) that need to be found and inserted into the command line as part of
- // the translation. So this first step is plain look-up & replacement, resulting in three things: 1). the command
- // object whose Execute method will actually be called; 2). a revised command string, with all substitutions &
- // replacements taken care of; 3). whether or not the Execute function wants raw input or not.
-
- StreamString revised_command_line;
- size_t actual_cmd_name_len = 0;
- std::string next_word;
- StringList matches;
- while (!done)
- {
- char quote_char = '\0';
- std::string suffix;
- ExtractCommand (command_string, next_word, suffix, quote_char);
- if (cmd_obj == nullptr)
- {
- std::string full_name;
- if (GetAliasFullName(next_word.c_str(), full_name))
- {
- std::string alias_result;
- cmd_obj = BuildAliasResult (full_name.c_str(), command_string, alias_result, result);
- revised_command_line.Printf ("%s", alias_result.c_str());
- if (cmd_obj)
- {
- wants_raw_input = cmd_obj->WantsRawCommandString ();
- actual_cmd_name_len = strlen (cmd_obj->GetCommandName());
- }
- }
- else
- {
- cmd_obj = GetCommandObject (next_word.c_str(), &matches);
- if (cmd_obj)
- {
- actual_cmd_name_len += next_word.length();
- revised_command_line.Printf ("%s", next_word.c_str());
- wants_raw_input = cmd_obj->WantsRawCommandString ();
- }
- else
- {
- revised_command_line.Printf ("%s", next_word.c_str());
- }
- }
- }
- else
- {
- if (cmd_obj->IsMultiwordObject ())
- {
- CommandObject *sub_cmd_obj = cmd_obj->GetSubcommandObject (next_word.c_str());
- if (sub_cmd_obj)
- {
- actual_cmd_name_len += next_word.length() + 1;
- revised_command_line.Printf (" %s", next_word.c_str());
- cmd_obj = sub_cmd_obj;
- wants_raw_input = cmd_obj->WantsRawCommandString ();
- }
- else
- {
- if (quote_char)
- revised_command_line.Printf (" %c%s%s%c", quote_char, next_word.c_str(), suffix.c_str(), quote_char);
- else
- revised_command_line.Printf (" %s%s", next_word.c_str(), suffix.c_str());
- done = true;
- }
- }
- else
- {
- if (quote_char)
- revised_command_line.Printf (" %c%s%s%c", quote_char, next_word.c_str(), suffix.c_str(), quote_char);
- else
- revised_command_line.Printf (" %s%s", next_word.c_str(), suffix.c_str());
- done = true;
- }
- }
- if (cmd_obj == nullptr)
- {
- const size_t num_matches = matches.GetSize();
- if (matches.GetSize() > 1) {
- StreamString error_msg;
- error_msg.Printf ("Ambiguous command '%s'. Possible matches:\n", next_word.c_str());
-
- for (uint32_t i = 0; i < num_matches; ++i) {
- error_msg.Printf ("\t%s\n", matches.GetStringAtIndex(i));
- }
- result.AppendRawError (error_msg.GetString().c_str());
- } else {
- // We didn't have only one match, otherwise we wouldn't get here.
- assert(num_matches == 0);
- result.AppendErrorWithFormat ("'%s' is not a valid command.\n", next_word.c_str());
- }
- result.SetStatus (eReturnStatusFailed);
- return false;
- }
-
- if (cmd_obj->IsMultiwordObject ())
- {
- if (!suffix.empty())
- {
-
- result.AppendErrorWithFormat ("command '%s' did not recognize '%s%s%s' as valid (subcommand might be invalid).\n",
- cmd_obj->GetCommandName(),
- next_word.empty() ? "" : next_word.c_str(),
- next_word.empty() ? " -- " : " ",
- suffix.c_str());
- result.SetStatus (eReturnStatusFailed);
- return false;
- }
- }
- else
- {
- // If we found a normal command, we are done
- done = true;
- if (!suffix.empty())
- {
- switch (suffix[0])
- {
- case '/':
- // GDB format suffixes
- {
- Options *command_options = cmd_obj->GetOptions();
- if (command_options && command_options->SupportsLongOption("gdb-format"))
- {
- std::string gdb_format_option ("--gdb-format=");
- gdb_format_option += (suffix.c_str() + 1);
+ // Phase 1.
- bool inserted = false;
- std::string &cmd = revised_command_line.GetString();
- size_t arg_terminator_idx = FindArgumentTerminator (cmd);
- if (arg_terminator_idx != std::string::npos)
- {
- // Insert the gdb format option before the "--" that terminates options
- gdb_format_option.append(1,' ');
- cmd.insert(arg_terminator_idx, gdb_format_option);
- inserted = true;
- }
-
- if (!inserted)
- revised_command_line.Printf (" %s", gdb_format_option.c_str());
-
- if (wants_raw_input && FindArgumentTerminator(cmd) == std::string::npos)
- revised_command_line.PutCString (" --");
- }
- else
- {
- result.AppendErrorWithFormat ("the '%s' command doesn't support the --gdb-format option\n",
- cmd_obj->GetCommandName());
- result.SetStatus (eReturnStatusFailed);
- return false;
- }
- }
- break;
-
- default:
- result.AppendErrorWithFormat ("unknown command shorthand suffix: '%s'\n",
- suffix.c_str());
- result.SetStatus (eReturnStatusFailed);
- return false;
-
- }
- }
- }
- if (command_string.length() == 0)
- done = true;
-
- }
+ // Before we do ANY kind of argument processing, we need to figure out what
+ // the real/final command object is for the specified command. This gets
+ // complicated by the fact that the user could have specified an alias, and,
+ // in translating the alias, there may also be command options and/or even
+ // data (including raw text strings) that need to be found and inserted into
+ // the command line as part of the translation. So this first step is plain
+ // look-up and replacement, resulting in:
+ // 1. the command object whose Execute method will actually be called
+ // 2. a revised command string, with all substitutions and replacements
+ // taken care of
+ // From 1 above, we can determine whether the Execute function wants raw
+ // input or not.
+
+ CommandObject *cmd_obj = ResolveCommandImpl(command_string, result);
+
+ // Although the user may have abbreviated the command, the command_string now
+ // has the command expanded to the full name. For example, if the input
+ // was "br s -n main", command_string is now "breakpoint set -n main".
- if (!command_string.empty())
- revised_command_line.Printf (" %s", command_string.c_str());
-
- // End of Phase 1.
- // At this point cmd_obj should contain the CommandObject whose Execute method will be called, if the command
- // specified was valid; revised_command_line contains the complete command line (including command name(s)),
- // fully translated with all substitutions & translations taken care of (still in raw text format); and
- // wants_raw_input specifies whether the Execute method expects raw input or not.
-
-
if (log)
{
- log->Printf ("HandleCommand, cmd_obj : '%s'", cmd_obj ? cmd_obj->GetCommandName() : "<not found>");
- log->Printf ("HandleCommand, revised_command_line: '%s'", revised_command_line.GetData());
- log->Printf ("HandleCommand, wants_raw_input:'%s'", wants_raw_input ? "True" : "False");
+ log->Printf("HandleCommand, cmd_obj : '%s'", cmd_obj ? cmd_obj->GetCommandName() : "<not found>");
+ log->Printf("HandleCommand, (revised) command_string: '%s'", command_string.c_str());
+ const bool wants_raw_input = (cmd_obj != NULL) ? cmd_obj->WantsRawCommandString() : false;
+ log->Printf("HandleCommand, wants_raw_input:'%s'", wants_raw_input ? "True" : "False");
}
// Phase 2.
@@ -1935,7 +1784,7 @@ CommandInterpreter::HandleCommand (const
{
if (add_to_history)
{
- Args command_args (revised_command_line.GetData());
+ Args command_args (command_string);
const char *repeat_command = cmd_obj->GetRepeatCommand(command_args, 0);
if (repeat_command != nullptr)
m_repeat_command.assign(repeat_command);
@@ -1945,18 +1794,13 @@ CommandInterpreter::HandleCommand (const
m_command_history.AppendString (original_command_string);
}
- command_string = revised_command_line.GetData();
- std::string command_name (cmd_obj->GetCommandName());
std::string remainder;
+ const std::size_t actual_cmd_name_len = strlen (cmd_obj->GetCommandName());
if (actual_cmd_name_len < command_string.length())
- remainder = command_string.substr (actual_cmd_name_len); // Note: 'actual_cmd_name_len' may be considerably shorter
- // than cmd_obj->GetCommandName(), because name completion
- // allows users to enter short versions of the names,
- // e.g. 'br s' for 'breakpoint set'.
+ remainder = command_string.substr (actual_cmd_name_len);
// Remove any initial spaces
- std::string white_space (" \t\v");
- size_t pos = remainder.find_first_not_of (white_space);
+ size_t pos = remainder.find_first_not_of (k_white_space);
if (pos != 0 && pos != std::string::npos)
remainder.erase(0, pos);
@@ -1968,7 +1812,7 @@ CommandInterpreter::HandleCommand (const
else
{
// We didn't find the first command object, so complete the first argument.
- Args command_args (revised_command_line.GetData());
+ Args command_args (command_string);
StringList matches;
int num_matches;
int cursor_index = 0;
@@ -3393,3 +3237,179 @@ CommandInterpreter::RunCommandInterprete
}
+CommandObject *
+CommandInterpreter::ResolveCommandImpl(std::string &command_line, CommandReturnObject &result)
+{
+ std::string scratch_command(command_line); // working copy so we don't modify command_line unless we succeed
+ CommandObject *cmd_obj = nullptr;
+ StreamString revised_command_line;
+ bool wants_raw_input = false;
+ size_t actual_cmd_name_len = 0;
+ std::string next_word;
+ StringList matches;
+ bool done = false;
+ while (!done)
+ {
+ char quote_char = '\0';
+ std::string suffix;
+ ExtractCommand(scratch_command, next_word, suffix, quote_char);
+ if (cmd_obj == nullptr)
+ {
+ std::string full_name;
+ if (GetAliasFullName(next_word.c_str(), full_name))
+ {
+ std::string alias_result;
+ cmd_obj = BuildAliasResult(full_name.c_str(), scratch_command, alias_result, result);
+ revised_command_line.Printf("%s", alias_result.c_str());
+ if (cmd_obj)
+ {
+ wants_raw_input = cmd_obj->WantsRawCommandString();
+ actual_cmd_name_len = strlen(cmd_obj->GetCommandName());
+ }
+ }
+ else
+ {
+ cmd_obj = GetCommandObject(next_word.c_str(), &matches);
+ if (cmd_obj)
+ {
+ actual_cmd_name_len += strlen(cmd_obj->GetCommandName());
+ revised_command_line.Printf("%s", cmd_obj->GetCommandName());
+ wants_raw_input = cmd_obj->WantsRawCommandString();
+ }
+ else
+ {
+ revised_command_line.Printf ("%s", next_word.c_str());
+ }
+ }
+ }
+ else
+ {
+ if (cmd_obj->IsMultiwordObject ())
+ {
+ CommandObject *sub_cmd_obj = cmd_obj->GetSubcommandObject(next_word.c_str());
+ if (sub_cmd_obj)
+ {
+ // The subcommand's name includes the parent command's name,
+ // so restart rather than append to the revised_command_line.
+ actual_cmd_name_len = strlen(sub_cmd_obj->GetCommandName()) + 1;
+ revised_command_line.Clear();
+ revised_command_line.Printf("%s", sub_cmd_obj->GetCommandName());
+ cmd_obj = sub_cmd_obj;
+ wants_raw_input = cmd_obj->WantsRawCommandString();
+ }
+ else
+ {
+ if (quote_char)
+ revised_command_line.Printf(" %c%s%s%c", quote_char, next_word.c_str(), suffix.c_str(), quote_char);
+ else
+ revised_command_line.Printf(" %s%s", next_word.c_str(), suffix.c_str());
+ done = true;
+ }
+ }
+ else
+ {
+ if (quote_char)
+ revised_command_line.Printf(" %c%s%s%c", quote_char, next_word.c_str(), suffix.c_str(), quote_char);
+ else
+ revised_command_line.Printf(" %s%s", next_word.c_str(), suffix.c_str());
+ done = true;
+ }
+ }
+
+ if (cmd_obj == nullptr)
+ {
+ const size_t num_matches = matches.GetSize();
+ if (matches.GetSize() > 1) {
+ StreamString error_msg;
+ error_msg.Printf("Ambiguous command '%s'. Possible matches:\n", next_word.c_str());
+
+ for (uint32_t i = 0; i < num_matches; ++i) {
+ error_msg.Printf("\t%s\n", matches.GetStringAtIndex(i));
+ }
+ result.AppendRawError(error_msg.GetString().c_str());
+ } else {
+ // We didn't have only one match, otherwise we wouldn't get here.
+ assert(num_matches == 0);
+ result.AppendErrorWithFormat("'%s' is not a valid command.\n", next_word.c_str());
+ }
+ result.SetStatus(eReturnStatusFailed);
+ return nullptr;
+ }
+
+ if (cmd_obj->IsMultiwordObject())
+ {
+ if (!suffix.empty())
+ {
+ result.AppendErrorWithFormat("command '%s' did not recognize '%s%s%s' as valid (subcommand might be invalid).\n",
+ cmd_obj->GetCommandName(),
+ next_word.empty() ? "" : next_word.c_str(),
+ next_word.empty() ? " -- " : " ",
+ suffix.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return nullptr;
+ }
+ }
+ else
+ {
+ // If we found a normal command, we are done
+ done = true;
+ if (!suffix.empty())
+ {
+ switch (suffix[0])
+ {
+ case '/':
+ // GDB format suffixes
+ {
+ Options *command_options = cmd_obj->GetOptions();
+ if (command_options && command_options->SupportsLongOption("gdb-format"))
+ {
+ std::string gdb_format_option("--gdb-format=");
+ gdb_format_option += (suffix.c_str() + 1);
+
+ bool inserted = false;
+ std::string &cmd = revised_command_line.GetString();
+ size_t arg_terminator_idx = FindArgumentTerminator(cmd);
+ if (arg_terminator_idx != std::string::npos)
+ {
+ // Insert the gdb format option before the "--" that terminates options
+ gdb_format_option.append(1,' ');
+ cmd.insert(arg_terminator_idx, gdb_format_option);
+ inserted = true;
+ }
+
+ if (!inserted)
+ revised_command_line.Printf(" %s", gdb_format_option.c_str());
+
+ if (wants_raw_input && FindArgumentTerminator(cmd) == std::string::npos)
+ revised_command_line.PutCString(" --");
+ }
+ else
+ {
+ result.AppendErrorWithFormat("the '%s' command doesn't support the --gdb-format option\n",
+ cmd_obj->GetCommandName());
+ result.SetStatus(eReturnStatusFailed);
+ return nullptr;
+ }
+ }
+ break;
+
+ default:
+ result.AppendErrorWithFormat("unknown command shorthand suffix: '%s'\n",
+ suffix.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return nullptr;
+ }
+ }
+ }
+ if (scratch_command.empty())
+ done = true;
+ }
+
+ if (!scratch_command.empty())
+ revised_command_line.Printf(" %s", scratch_command.c_str());
+
+ if (cmd_obj != NULL)
+ command_line = revised_command_line.GetData();
+
+ return cmd_obj;
+}
Modified: lldb/trunk/test/functionalities/abbreviation/TestAbbreviations.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/abbreviation/TestAbbreviations.py?rev=235633&r1=235632&r2=235633&view=diff
==============================================================================
--- lldb/trunk/test/functionalities/abbreviation/TestAbbreviations.py (original)
+++ lldb/trunk/test/functionalities/abbreviation/TestAbbreviations.py Thu Apr 23 15:00:25 2015
@@ -1,5 +1,5 @@
"""
-Test some lldb command abbreviations.
+Test some lldb command abbreviations and aliases for proper resolution.
"""
import os, time
@@ -13,172 +13,88 @@ class AbbreviationsTestCase(TestBase):
mydir = TestBase.compute_mydir(__file__)
@expectedFailureFreeBSD("llvm.org/pr22611 thread race condition breaks prompt setting")
- @skipIfWindows # one-shot script commands deadlock on Windows.
- def test_nonrunning_command_abbreviations (self):
- self.expect("ap script",
- startstr = "The following built-in commands may relate to 'script':",
- substrs = ['breakpoint command add',
- 'breakpoint command list',
- 'breakpoint list',
- 'command alias',
- 'expression',
- 'script'])
+ def test_command_abbreviations_and_aliases (self):
+ command_interpreter = self.dbg.GetCommandInterpreter()
+ self.assertTrue(command_interpreter, VALID_COMMAND_INTERPRETER)
+ result = lldb.SBCommandReturnObject()
+
+ # Check that abbreviations are expanded to the full command.
+ command_interpreter.ResolveCommand("ap script", result)
+ self.assertTrue(result.Succeeded())
+ self.assertEqual("apropos script", result.GetOutput())
+
+ command_interpreter.ResolveCommand("h", result)
+ self.assertTrue(result.Succeeded())
+ self.assertEqual("help", result.GetOutput())
+
+ # Check resolution of abbreviations for multi-word commands.
+ command_interpreter.ResolveCommand("lo li", result)
+ self.assertTrue(result.Succeeded())
+ self.assertEqual("log list", result.GetOutput())
+
+ command_interpreter.ResolveCommand("br s", result)
+ self.assertTrue(result.Succeeded())
+ self.assertEqual("breakpoint set", result.GetOutput())
+
+ # Try an ambiguous abbreviation.
+ # "pl" could be "platform" or "plugin".
+ command_interpreter.ResolveCommand("pl", result)
+ self.assertFalse(result.Succeeded())
+ self.assertTrue(result.GetError().startswith("Ambiguous command"))
+
+ # Make sure an unabbreviated command is not mangled.
+ command_interpreter.ResolveCommand("breakpoint set --name main --line 123", result)
+ self.assertTrue(result.Succeeded())
+ self.assertEqual("breakpoint set --name main --line 123", result.GetOutput())
+ # Create some aliases.
self.runCmd("com a alias com al")
self.runCmd("alias gurp help")
- self.expect("gurp target create",
- substrs = ['Syntax: target create <cmd-options> <filename>'])
+
+ # Check that an alias is replaced with the actual command
+ command_interpreter.ResolveCommand("gurp target create", result)
+ self.assertTrue(result.Succeeded())
+ self.assertEqual("help target create", result.GetOutput())
+
+ # Delete the alias and make sure it no longer has an effect.
self.runCmd("com u gurp")
- self.expect("gurp",
- COMMAND_FAILED_AS_EXPECTED, error = True,
- substrs = ["error: 'gurp' is not a valid command."])
-
- # Only one matching command: execute it.
- self.expect("h",
- startstr = "Debugger commands:")
-
- # Execute cleanup function during test tear down
- def cleanup():
- self.runCmd("command alias t thread select")
- self.addTearDownHook(cleanup)
-
- # Several matching commands: list them and error out.
- self.runCmd("command unalias t")
- self.expect("t",
- COMMAND_FAILED_AS_EXPECTED, error = True,
- substrs = ["Ambiguous command 't'. Possible matches:",
- "target", "thread", "type"])
-
- self.runCmd("com sou ./change_prompt.lldb")
-
- self.expect("settings show prompt",
- startstr = 'prompt (string) = "[with-three-trailing-spaces] "')
-
-
- self.runCmd("settings clear prompt")
- self.expect("settings show prompt",
- startstr = 'prompt (string) = "(lldb) "')
-
-
- self.expect("lo li",
- startstr = "Logging categories for ")
-
- self.runCmd("se se prompt 'Sycamore> '")
- self.expect("se sh prompt",
- startstr = 'prompt (string) = "Sycamore> "')
-
- self.runCmd("se cl prompt")
- self.expect("set sh prompt",
- startstr = 'prompt (string) = "(lldb) "')
-
- # We don't want to display the stdout if not in TraceOn() mode.
- if not self.TraceOn():
- self.HideStdout()
-
- self.runCmd (r'''sc print "\n\n\tHello!\n"''')
-
-
- @skipUnlessDarwin
- @dsym_test
- def test_with_dsym (self):
- self.buildDsym ()
- self.running_abbreviations ()
-
- @dwarf_test
- @expectedFailureLinux # not related to abbreviations, "dis -f" output has int3 in it
- def test_with_dwarf (self):
- self.buildDwarf ()
- self.running_abbreviations ()
-
- def running_abbreviations (self):
- exe = os.path.join (os.getcwd(), "a.out")
- # Use "file", i.e., no abbreviation. We're exactly matching the command
- # verbatim when dealing with remote testsuite execution.
- # For more details, see TestBase.runCmd().
- self.expect("file " + exe,
- patterns = [ "Current executable set to .*a.out.*" ])
-
- # By default, the setting interpreter.expand-regex-aliases is false.
- self.expect("_regexp-br product", matching=False,
- substrs = [ "breakpoint set --name" ])
-
- match_object = lldbutil.run_break_set_command (self, "br s -n sum")
- lldbutil.check_breakpoint_result (self, match_object, symbol_name='sum', symbol_match_exact=False, num_locations=1)
-
- match_object = lldbutil.run_break_set_command (self, "br s -f main.cpp -l 32")
- lldbutil.check_breakpoint_result (self, match_object, file_name='main.cpp', line_number=32, num_locations=1)
-
- self.runCmd("br co a -s python 1 -o 'print frame'")
- self.expect("br co l 1",
- substrs = [ "Breakpoint 1:",
- "Breakpoint commands:",
- "print frame" ])
-
- self.runCmd("br co del 1")
- self.expect("breakpoint command list 1",
- startstr = "Breakpoint 1 does not have an associated command.")
-
- self.expect("br di",
- startstr = 'All breakpoints disabled. (3 breakpoints)')
-
- self.expect("bre e",
- startstr = "All breakpoints enabled. (3 breakpoints)")
-
- self.expect("break list",
- substrs = ["1: name = 'product', locations = 1",
- "2: name = 'sum', locations = 1",
- "3: file = 'main.cpp', line = 32, locations = 1"])
- self.expect("br cl -l 32 -f main.cpp",
- startstr = "1 breakpoints cleared:",
- substrs = ["3: file = 'main.cpp', line = 32, locations = 1"])
-
- # Add a future to terminate the current process being debugged.
- #
- # The test framework relies on detecting either "run" or "process launch"
- # command to automatically kill the inferior upon tear down.
- # But we'll be using "pro la" command to launch the inferior.
- self.expect("pro la",
- patterns = [ "Process .* launched: "])
-
- self.expect("pro st",
- patterns = [ "Process .* stopped",
- "thread #1:",
- "a.out",
- "sum\(a=1238, b=78392\)",
- "at main.cpp\:25",
- "stop reason = breakpoint 2.1" ])
-
- # ARCH, if not specified, defaults to x86_64.
- self.runCmd("dis -f")
- disassembly = self.res.GetOutput()
- if self.getArchitecture() in ["", 'x86_64', 'i386']:
- # hey! we shouldn't have a software breakpoint in here
- self.assertFalse("int3" in disassembly)
- self.expect(disassembly, exe=False,
- startstr = "a.out`sum(int, int)",
- substrs = [' mov',
- ' addl ',
- 'ret'])
- else:
- self.fail('unimplemented for arch = "{arch}"'.format(arch=self.getArchitecture()))
-
- self.expect("i d l main.cpp",
- patterns = ["Line table for .*main.cpp in `a.out"])
-
- self.expect("i d se",
- patterns = ["Dumping sections for [0-9]+ modules."])
-
- self.expect("i d symf",
- patterns = ["Dumping debug symbols for [0-9]+ modules."])
-
- self.expect("i d symt",
- patterns = ["Dumping symbol table for [0-9]+ modules."])
-
- if self.platformIsDarwin():
- self.expect("i li",
- substrs = [ 'a.out',
- '/usr/lib/dyld',
- '/usr/lib/libSystem.B.dylib'])
+ command_interpreter.ResolveCommand("gurp", result)
+ self.assertFalse(result.Succeeded())
+
+ # Check aliases with text replacement.
+ self.runCmd("alias pltty process launch -s -o %1 -e %1")
+ command_interpreter.ResolveCommand("pltty /dev/tty0", result)
+ self.assertTrue(result.Succeeded())
+ self.assertEqual("process launch -s -o /dev/tty0 -e /dev/tty0", result.GetOutput())
+
+ self.runCmd("alias xyzzy breakpoint set -n %1 -l %2")
+ command_interpreter.ResolveCommand("xyzzy main 123", result)
+ self.assertTrue(result.Succeeded())
+ self.assertEqual("breakpoint set -n main -l 123", result.GetOutput().strip())
+
+ # And again, without enough parameters.
+ command_interpreter.ResolveCommand("xyzzy main", result)
+ self.assertFalse(result.Succeeded())
+
+ # Check a command that wants the raw input.
+ command_interpreter.ResolveCommand(r'''sc print "\n\n\tHello!\n"''', result)
+ self.assertTrue(result.Succeeded())
+ self.assertEqual(r'''script print "\n\n\tHello!\n"''', result.GetOutput())
+
+ # Prompt changing stuff should be tested, but this doesn't seem like the
+ # right test to do it in. It has nothing to do with aliases or abbreviations.
+ #self.runCmd("com sou ./change_prompt.lldb")
+ #self.expect("settings show prompt",
+ # startstr = 'prompt (string) = "[with-three-trailing-spaces] "')
+ #self.runCmd("settings clear prompt")
+ #self.expect("settings show prompt",
+ # startstr = 'prompt (string) = "(lldb) "')
+ #self.runCmd("se se prompt 'Sycamore> '")
+ #self.expect("se sh prompt",
+ # startstr = 'prompt (string) = "Sycamore> "')
+ #self.runCmd("se cl prompt")
+ #self.expect("set sh prompt",
+ # startstr = 'prompt (string) = "(lldb) "')
if __name__ == '__main__':
More information about the lldb-commits
mailing list