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 || 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: 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/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/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(); +}