dawn created this revision.
dawn added reviewers: clayborg, jingham, spyffe.
dawn added a subscriber: lldb-commits.
dawn set the repository for this revision to rL LLVM.

This patch adds the option -l/--language to the expression command, for use 
when setting the language options or choosing an alternate FE.  If not 
specified, the target.language setting is used.  It is the expression 
counterpart of http://reviews.llvm.org/D11119 which added the --language option 
to breakpoint set command.

I ran into problems adding the test case as you can see.  Apparently runCmd 
always fails if an error is returned from the command, so I had to reverse the 
tests using try/expect.  I can optionally comment them out until the issue is 
fixed - let me know.

Repository:
  rL LLVM

http://reviews.llvm.org/D11447

Files:
  source/Commands/CommandObjectExpression.cpp
  source/Commands/CommandObjectExpression.h
  test/expression_command/options/Makefile
  test/expression_command/options/TestExprOptions.py
  test/expression_command/options/foo.cpp
  test/expression_command/options/main.cpp

Index: test/expression_command/options/main.cpp
===================================================================
--- test/expression_command/options/main.cpp
+++ test/expression_command/options/main.cpp
@@ -0,0 +1,16 @@
+extern "C" int foo(void);
+static int static_value = 0;
+
+int
+bar()
+{
+    static_value++;
+    return static_value;
+}
+
+int main (int argc, char const *argv[])
+{
+    // breakpoint_in_main
+    bar();
+    return foo();
+}
Index: test/expression_command/options/foo.cpp
===================================================================
--- test/expression_command/options/foo.cpp
+++ test/expression_command/options/foo.cpp
@@ -0,0 +1,11 @@
+namespace ns {
+    int func(void)
+    {
+        return 0;
+    }
+}
+
+extern "C" int foo(void)
+{
+    return ns::func();
+}
Index: test/expression_command/options/TestExprOptions.py
===================================================================
--- test/expression_command/options/TestExprOptions.py
+++ test/expression_command/options/TestExprOptions.py
@@ -0,0 +1,113 @@
+"""
+Test expression command options.
+
+Test cases:
+
+o test_expr_options:
+  Test expression command options.
+"""
+
+import os, time
+import unittest2
+import lldb
+import lldbutil
+from lldbtest import *
+
+class ExprOptionsTestCase(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    def setUp(self):
+        # Call super's setUp().
+        TestBase.setUp(self)
+        # Find the line number to break for main.c.
+        self.line = line_number('main.cpp',
+                                '// breakpoint_in_main')
+
+        # Disable confirmation prompt to avoid infinite wait
+        #self.runCmd("settings set auto-confirm true")
+        #self.addTearDownHook(lambda: self.runCmd("settings clear auto-confirm"))
+
+
+    def build_and_run(self):
+        """These expression command options should work as expected."""
+        self.buildDefault()
+
+        self.runCmd("file a.out", CURRENT_EXECUTABLE_SET)
+
+        lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.line,
+            num_expected_locations=1, loc_exact=False)
+
+        self.runCmd("run", RUN_SUCCEEDED)
+
+    def test_expr_options(self):
+        self.build_and_run()
+
+        # FIXME: runCmd (called by expect) fails if an error is
+        # returned making it impossible to add negative tests.  As a
+        # workaround, we'll expect runCmd to fail using the following
+        # method:
+        try:
+            self.expect("expression blabla",
+                startstr = "unexpected value")
+            self.assertTrue(false, "runCmd didn't fail")
+        except:
+            print "OK"
+
+        # -- test --language on ObjC builtin type --
+        # Make sure we can evaluate the ObjC builtin type 'id':
+        self.expect("expr id my_id = 0; my_id",
+            substrs = ["= nil"])
+        # Make sure it still works if language is set to ObjC:
+        self.expect("expr -l objc -- id my_id = 0; my_id",
+            substrs = ["= nil"])
+        # Make sure it fails if language is set to C:
+        try:
+            self.expect("expr -l c -- id my_id = 0; my_id",
+                substrs = ["= nil"]) #FIXME: reverse test!
+                #startstr = "error") #FIXME: use this when runCmd is fixed
+            self.assertTrue(false, "runCmd didn't fail")
+        except:
+            print "OK"
+        # Make sure it fails if the target's language is set to C:
+        self.runCmd("settings set target.language c")
+        try:
+            self.expect("expr id my_id = 0; my_id",
+                substrs = ["= nil"]) #FIXME: reverse test!
+                #startstr = "error") #FIXME: use this when runCmd is fixed
+            self.assertTrue(false, "runCmd didn't fail")
+        except:
+            print "OK"
+        self.runCmd("settings clear target.language")
+
+        # -- test --language on C++ expression --
+        # Make sure we can evaluate 'ns::func'.
+        self.expect("expr ns::func",
+            patterns = ["\(int .* = 0x.*"])
+        # Make sure it still works if language is set to C++:
+        self.expect("expr -l c++ -- ns::func",
+            patterns = ["\(int .* = 0x.*"])
+        # Make sure it fails if language is set to C:
+        try:
+            self.expect("expr -l c -- ns::func",
+                patterns = ["\(int .* = 0x.*"]) #FIXME: reverse test!
+                #startstr = "error") #FIXME: use this when runCmd is fixed
+            self.assertTrue(false, "runCmd didn't fail")
+        except:
+            print "OK"
+        # Make sure it fails if the target's language is set to C:
+        self.runCmd("settings set target.language c")
+        try:
+            self.expect("expr ns::func",
+                patterns = ["\(int .* = 0x.*"]) #FIXME: reverse test!
+                #startstr = "error") #FIXME: use this when runCmd is fixed
+            self.assertTrue(false, "runCmd didn't fail")
+        except:
+            print "OK"
+        self.runCmd("settings clear target.language")
+
+if __name__ == '__main__':
+    import atexit
+    lldb.SBDebugger.Initialize()
+    atexit.register(lambda: lldb.SBDebugger.Terminate())
+    unittest2.main()
Index: test/expression_command/options/Makefile
===================================================================
--- test/expression_command/options/Makefile
+++ test/expression_command/options/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../make
+
+CXX_SOURCES := main.cpp foo.cpp
+
+include $(LEVEL)/Makefile.rules
Index: source/Commands/CommandObjectExpression.h
===================================================================
--- source/Commands/CommandObjectExpression.h
+++ source/Commands/CommandObjectExpression.h
@@ -61,6 +61,7 @@
         bool        debug;
         uint32_t    timeout;
         bool        try_all_threads;
+        lldb::LanguageType language;
         LanguageRuntimeDescriptionDisplayVerbosity m_verbosity;
     };
 
Index: source/Commands/CommandObjectExpression.cpp
===================================================================
--- source/Commands/CommandObjectExpression.cpp
+++ source/Commands/CommandObjectExpression.cpp
@@ -63,6 +63,7 @@
     { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "timeout",            't', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeUnsignedInteger,  "Timeout value (in microseconds) for running the expression."},
     { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "unwind-on-error",    'u', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean,    "Clean up program state if the expression causes a crash, or raises a signal.  Note, unlike gdb hitting a breakpoint is controlled by another option (-i)."},
     { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "debug",              'g', OptionParser::eNoArgument      , NULL, NULL, 0, eArgTypeNone,       "When specified, debug the JIT code by setting a breakpoint on the first instruction and forcing breakpoints to not be ignored (-i0) and no unwinding to happen on error (-u0)."},
+    { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "language",           'l', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeLanguage,   "Specifies the Language to use when parsing the expression.  If not set the target.language setting is used." },
     { LLDB_OPT_SET_1, false, "description-verbosity", 'v', OptionParser::eOptionalArgument, NULL, g_description_verbosity_type, 0, eArgTypeDescriptionVerbosity,        "How verbose should the output of this expression be, if the object description is asked for."},
 };
 
@@ -84,12 +85,11 @@
 
     switch (short_option)
     {
-      //case 'l':
-      //if (language.SetLanguageFromCString (option_arg) == false)
-      //{
-      //    error.SetErrorStringWithFormat("invalid language option argument '%s'", option_arg);
-      //}
-      //break;
+    case 'l':
+        language = LanguageRuntime::GetLanguageTypeFromString (option_arg);
+        if (language == eLanguageTypeUnknown)
+            error.SetErrorStringWithFormat ("unknown language type: '%s' for expression", option_arg);
+        break;
 
     case 'a':
         {
@@ -180,6 +180,7 @@
     try_all_threads = true;
     timeout = 0;
     debug = false;
+    language = eLanguageTypeUnknown;
     m_verbosity = eLanguageRuntimeDescriptionDisplayVerbosityCompact;
 }
 
@@ -192,7 +193,7 @@
 CommandObjectExpression::CommandObjectExpression (CommandInterpreter &interpreter) :
     CommandObjectRaw (interpreter,
                       "expression",
-                      "Evaluate a C/ObjC/C++ expression in the current program context, using user defined variables and variables currently in scope.",
+                      "Evaluate an expression in the current program context, using user defined variables and variables currently in scope.",
                       NULL,
                       eCommandProcessMustBePaused | eCommandTryTargetAPILock),
     IOHandlerDelegate (IOHandlerDelegate::Completion::Expression),
@@ -300,6 +301,12 @@
         options.SetTryAllThreads(m_command_options.try_all_threads);
         options.SetDebug(m_command_options.debug);
         
+        // If the language was not specified, set it from target's properties
+        if (m_command_options.language != eLanguageTypeUnknown)
+            options.SetLanguage(m_command_options.language);
+        else
+            options.SetLanguage(target->GetLanguage());
+
         // If there is any chance we are going to stop and want to see
         // what went wrong with our expression, we should generate debug info
         if (!m_command_options.ignore_breakpoints ||
_______________________________________________
lldb-commits mailing list
lldb-commits@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits

Reply via email to