[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