Index: include/lldb/Expression/ClangASTSource.h =================================================================== --- include/lldb/Expression/ClangASTSource.h +++ include/lldb/Expression/ClangASTSource.h @@ -46,13 +46,15 @@ /// @param[in] declMap /// A reference to the LLDB object that handles entity lookup. //------------------------------------------------------------------ - ClangASTSource (const lldb::TargetSP &target) : + ClangASTSource (const lldb::TargetSP &target, bool allow_objc = true, bool allow_cxx = true) : m_import_in_progress (false), m_lookups_enabled (false), m_target (target), m_ast_context (NULL), m_active_lexical_decls (), - m_active_lookups () + m_active_lookups (), + m_allow_objc (allow_objc), + m_allow_cxx (allow_cxx) { m_ast_importer = m_target->GetClangASTImporter(); } @@ -407,6 +409,10 @@ ClangASTImporter *m_ast_importer; ///< The target's AST importer. std::set m_active_lexical_decls; std::set m_active_lookups; + + bool m_allow_objc; + bool m_allow_cxx; + }; //---------------------------------------------------------------------- Index: include/lldb/Expression/ClangExpressionDeclMap.h =================================================================== --- include/lldb/Expression/ClangExpressionDeclMap.h +++ include/lldb/Expression/ClangExpressionDeclMap.h @@ -75,7 +75,9 @@ /// The execution context to use when parsing. //------------------------------------------------------------------ ClangExpressionDeclMap (bool keep_result_in_memory, - ExecutionContext &exe_ctx); + ExecutionContext &exe_ctx, + bool allow_objc = true, + bool allow_cxx = true); //------------------------------------------------------------------ /// Destructor @@ -391,6 +393,9 @@ ClangExpressionVariableList m_found_entities; ///< All entities that were looked up for the parser. ClangExpressionVariableList m_struct_members; ///< All entities that need to be placed in the struct. bool m_keep_result_in_memory; ///< True if result persistent variables generated by this expression should stay in memory. + + bool m_allow_cxx; ///< Search for C++ symbols + bool m_allow_objc; ///< Search for ObjC symbols //---------------------------------------------------------------------- /// The following values should not live beyond parsing Index: include/lldb/Target/Target.h =================================================================== --- include/lldb/Target/Target.h +++ include/lldb/Target/Target.h @@ -172,6 +172,8 @@ lldb::LanguageType GetLanguage () const; + void SetLanguage (lldb::LanguageType); + const char * GetExpressionPrefixContentsAsCString (); @@ -948,6 +950,9 @@ void SymbolsDidLoad (ModuleList &module_list); + + lldb::LanguageType + ComputeLanguageType(const ModuleList &module_list); void ClearModules(bool delete_locations); Index: source/Commands/CommandObjectExpression.cpp =================================================================== --- source/Commands/CommandObjectExpression.cpp +++ source/Commands/CommandObjectExpression.cpp @@ -300,13 +300,8 @@ options.SetUseDynamic(m_varobj_options.use_dynamic); options.SetTryAllThreads(m_command_options.try_all_threads); options.SetDebug(m_command_options.debug); + options.SetLanguage(m_command_options.language); - // 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: source/Expression/ClangASTSource.cpp =================================================================== --- source/Expression/ClangASTSource.cpp +++ source/Expression/ClangASTSource.cpp @@ -125,11 +125,10 @@ } break; - // Operator names. Not important for now. + // Operator names. case DeclarationName::CXXOperatorName: case DeclarationName::CXXLiteralOperatorName: - SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name); - return false; + break; // Using directives found in this context. // Tell Sema we didn't find any or we'll end up getting asked a *lot*. @@ -669,7 +668,7 @@ static ConstString id_name("id"); static ConstString Class_name("Class"); - if (name == id_name || name == Class_name) + if (m_allow_objc && (name == id_name || name == Class_name)) return; if (name_unique_cstr == NULL) @@ -1957,11 +1956,14 @@ false); } + // Pass the identifier info for functions the decl_name is needed for operators + clang::DeclarationName decl_name = m_decl_name.getNameKind() == DeclarationName::Identifier ? m_decl_name.getAsIdentifierInfo() : m_decl_name; + clang::FunctionDecl *func_decl = FunctionDecl::Create (*ast, context, SourceLocation(), SourceLocation(), - m_decl_name.getAsIdentifierInfo(), + decl_name, qual_type, NULL, SC_Extern, Index: source/Expression/ClangExpressionDeclMap.cpp =================================================================== --- source/Expression/ClangExpressionDeclMap.cpp +++ source/Expression/ClangExpressionDeclMap.cpp @@ -51,11 +51,13 @@ using namespace lldb_private; using namespace clang; -ClangExpressionDeclMap::ClangExpressionDeclMap (bool keep_result_in_memory, ExecutionContext &exe_ctx) : - ClangASTSource (exe_ctx.GetTargetSP()), +ClangExpressionDeclMap::ClangExpressionDeclMap (bool keep_result_in_memory, ExecutionContext &exe_ctx, bool allow_objc, bool allow_cxx) : + ClangASTSource (exe_ctx.GetTargetSP(), allow_objc, allow_cxx), m_found_entities (), m_struct_members (), m_keep_result_in_memory (keep_result_in_memory), + m_allow_cxx (allow_cxx), + m_allow_objc (allow_objc), m_parser_vars (), m_struct_vars () { @@ -995,7 +997,7 @@ static ConstString id_name("id"); static ConstString Class_name("Class"); - if (name == id_name || name == Class_name) + if (m_allow_objc && (name == id_name || name == Class_name)) return; // Only look for functions by name out in our symbols if the function Index: source/Expression/ClangExpressionParser.cpp =================================================================== --- source/Expression/ClangExpressionParser.cpp +++ source/Expression/ClangExpressionParser.cpp @@ -210,12 +210,18 @@ switch (language) { case lldb::eLanguageTypeC: + case lldb::eLanguageTypeC89: + case lldb::eLanguageTypeC99: + case lldb::eLanguageTypeC11: break; case lldb::eLanguageTypeObjC: m_compiler->getLangOpts().ObjC1 = true; m_compiler->getLangOpts().ObjC2 = true; break; case lldb::eLanguageTypeC_plus_plus: + case lldb::eLanguageTypeC_plus_plus_14: + case lldb::eLanguageTypeC_plus_plus_11: + case lldb::eLanguageTypeC_plus_plus_03: m_compiler->getLangOpts().CPlusPlus = true; m_compiler->getLangOpts().CPlusPlus11 = true; m_compiler->getHeaderSearchOpts().UseLibcxx = true; Index: source/Expression/ClangUserExpression.cpp =================================================================== --- source/Expression/ClangUserExpression.cpp +++ source/Expression/ClangUserExpression.cpp @@ -16,6 +16,7 @@ #include #include +#include "lldb/lldb-enumerations.h" #include "lldb/Core/ConstString.h" #include "lldb/Core/Log.h" #include "lldb/Core/Module.h" @@ -52,6 +53,7 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" +using namespace lldb; using namespace lldb_private; ClangUserExpression::ClangUserExpression (const char *expr, @@ -83,7 +85,15 @@ { switch (m_language) { + case lldb::eLanguageTypeC: + case lldb::eLanguageTypeC89: + case lldb::eLanguageTypeC99: + case lldb::eLanguageTypeC11: + break; case lldb::eLanguageTypeC_plus_plus: + case lldb::eLanguageTypeC_plus_plus_14: + case lldb::eLanguageTypeC_plus_plus_11: + case lldb::eLanguageTypeC_plus_plus_03: m_allow_cxx = true; break; case lldb::eLanguageTypeObjC: @@ -525,7 +535,7 @@ m_materializer_ap.reset(new Materializer()); - m_expr_decl_map.reset(new ClangExpressionDeclMap(keep_result_in_memory, exe_ctx)); + m_expr_decl_map.reset(new ClangExpressionDeclMap(keep_result_in_memory, exe_ctx, m_allow_objc, m_allow_cxx)); class OnExit { @@ -1022,7 +1032,36 @@ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP)); lldb_private::ExecutionPolicy execution_policy = options.GetExecutionPolicy(); - const lldb::LanguageType language = options.GetLanguage(); + + // Predict the language if it was not set in options + lldb::LanguageType language = options.GetLanguage(); + if (language == eLanguageTypeUnknown) { + StackFrameSP frame = exe_ctx.GetFrameSP(); + if (frame && frame->HasDebugInformation()) { + Block *block = frame->GetFrameBlock(); + if (block != NULL) { + lldb::ModuleSP module = block->CalculateSymbolContextModule(); + SymbolContext symbol_context; + block->CalculateSymbolContext(&symbol_context); + + if (module) + language = module->GetSymbolVendor()->ParseCompileUnitLanguage(symbol_context); + } + } + } + if (language == eLanguageTypeUnknown) { + StackFrameSP frame = exe_ctx.GetFrameSP(); + if (frame) { + TargetSP target = frame->CalculateTarget(); + if (target) + language = target->GetLanguage(); + } + } + // Treat C and C++ as C++11 + std::set c_langs = {eLanguageTypeC99, eLanguageTypeC, eLanguageTypeC89, eLanguageTypeC11, eLanguageTypeC_plus_plus, eLanguageTypeC_plus_plus_11, eLanguageTypeC_plus_plus_03}; + if (c_langs.find(language) != c_langs.end()) + language = eLanguageTypeC_plus_plus_11; + const ResultType desired_type = options.DoesCoerceToId() ? ClangUserExpression::eResultTypeId : ClangUserExpression::eResultTypeAny; lldb::ExpressionResults execution_results = lldb::eExpressionSetupError; Index: source/Target/Target.cpp =================================================================== --- source/Target/Target.cpp +++ source/Target/Target.cpp @@ -44,6 +44,7 @@ #include "lldb/Interpreter/Property.h" #include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/SymbolVendor.h" #include "lldb/Target/LanguageRuntime.h" #include "lldb/Target/ObjCLanguageRuntime.h" #include "lldb/Target/Process.h" @@ -1291,12 +1292,43 @@ m_breakpoint_list.UpdateBreakpointsWhenModuleIsReplaced(old_module_sp, new_module_sp); } +lldb::LanguageType +Target::ComputeLanguageType(const ModuleList &module_list) { + std::set languages; + + for (size_t i = 0; i < module_list.GetSize(); i++) { + lldb::ModuleSP module = module_list.GetModuleAtIndex(i); + + if (module) { + for (size_t compile_unit_id = 0; compile_unit_id < module->GetNumCompileUnits(); compile_unit_id++) { + CompUnitSP compile_unit = module->GetCompileUnitAtIndex(compile_unit_id); + SymbolContext module_symbol_context(CalculateTarget(), module, compile_unit.get()); + lldb::LanguageType module_language = module->GetSymbolVendor()->ParseCompileUnitLanguage(module_symbol_context); + languages.insert(module_language); + } + } + } + + + lldb::LanguageType target_language = eLanguageTypeUnknown; + if (languages.size() == 1) { + target_language = *languages.begin(); + } + + return target_language; +} + void Target::ModulesDidLoad (ModuleList &module_list) { if (m_valid && module_list.GetSize()) { m_breakpoint_list.UpdateBreakpoints (module_list, true, false); + + ModuleList ml; + ml.Append(GetExecutableModule()); + SetLanguage(ComputeLanguageType(ml)); + if (m_process_sp) { m_process_sp->ModulesDidLoad (module_list); @@ -3166,6 +3198,7 @@ m_collection_sp.reset (new TargetOptionValueProperties(target, Target::GetGlobalProperties())); // Set callbacks to update launch_info whenever "settins set" updated any of these properties + m_collection_sp->SetValueChangedCallback(ePropertyArg0, TargetProperties::Arg0ValueChangedCallback, this); m_collection_sp->SetValueChangedCallback(ePropertyRunArgs, TargetProperties::RunArgsValueChangedCallback, this); m_collection_sp->SetValueChangedCallback(ePropertyEnvVars, TargetProperties::EnvVarsValueChangedCallback, this); @@ -3468,6 +3501,12 @@ return LanguageType(); } +void +TargetProperties::SetLanguage (lldb::LanguageType language) { + OptionValueLanguage *value = m_collection_sp->GetPropertyAtIndexAsOptionValueLanguage(NULL, ePropertyLanguage); + value->SetLanguageValue(language); +} + const char * TargetProperties::GetExpressionPrefixContentsAsCString () { Index: test/lang/cpp/chained-calls/Makefile =================================================================== --- /dev/null +++ test/lang/cpp/chained-calls/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make + +CXX_SOURCES := main.cpp + +include $(LEVEL)/Makefile.rules Index: test/lang/cpp/chained-calls/TestCppChainedCalls.py =================================================================== --- /dev/null +++ test/lang/cpp/chained-calls/TestCppChainedCalls.py @@ -0,0 +1,94 @@ +import lldb +from lldbtest import * +import lldbutil + +class TestCppChainedCalls(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @skipUnlessDarwin + @dsym_test + def test_with_dsym_and_run_command(self): + self.buildDsym() + self.check() + + @dwarf_test + def test_with_dwarf_and_run_command(self): + self.buildDwarf() + self.check() + + def setUp(self): + TestBase.setUp(self) + + def check(self): + # Get main source file + src_file = "main.cpp" + src_file_spec = lldb.SBFileSpec(src_file) + self.assertTrue(src_file_spec.IsValid(), "Main source file") + + # Get the path of the executable + cwd = os.getcwd() + exe_file = "a.out" + exe_path = os.path.join(cwd, exe_file) + + # Load the executable + target = self.dbg.CreateTarget(exe_path) + self.assertTrue(target.IsValid(), VALID_TARGET) + + # Break on main function + main_breakpoint = target.BreakpointCreateBySourceRegex("Break here", src_file_spec) + self.assertTrue(main_breakpoint.IsValid() and main_breakpoint.GetNumLocations() >= 1, VALID_BREAKPOINT) + + # Launch the process + args = None + env = None + process = target.LaunchSimple(args, env, cwd) + self.assertTrue(process.IsValid(), PROCESS_IS_VALID) + + # Get the thread of the process + self.assertTrue(process.GetState() == lldb.eStateStopped, PROCESS_STOPPED) + thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint) + + # Get frame for current thread + frame = thread.GetSelectedFrame() + + # Test chained calls + test_result = frame.EvaluateExpression("g(f(12345))") + self.assertTrue(test_result.IsValid() and test_result.GetValueAsSigned() == 12345, "g(f(12345)) = 12345") + + test_result = frame.EvaluateExpression("q(p()).a") + self.assertTrue(test_result.IsValid() and test_result.GetValueAsSigned() == 12345678, "q(p()).a = 12345678") + + test_result = frame.EvaluateExpression("(p() + r()).a") + self.assertTrue(test_result.IsValid() and test_result.GetValueAsSigned() == 22345678, "(p() + r()).a = 22345678") + + test_result = frame.EvaluateExpression("q(p() + r()).a") + self.assertTrue(test_result.IsValid() and test_result.GetValueAsSigned() == 22345678, "q(p() + r()).a = 22345678") + + test_result = frame.EvaluateExpression("g(f(6700) + f(89))") + self.assertTrue(test_result.IsValid() and test_result.GetValueAsSigned() == 6789, "g(f(6700) + f(89)) = 6789") + + test_result = frame.EvaluateExpression("g(f(g(f(300) + f(40))) + f(5))") + self.assertTrue(test_result.IsValid() and test_result.GetValueAsSigned() == 345, "g(f(g(f(300) + f(40))) + f(5)) = 345") + + test_result = frame.EvaluateExpression("getb(makeb(), 789)") + self.assertTrue(test_result.IsValid() and test_result.GetValueAsSigned() == 789, "getb(makeb(), 789) = 789") + + test_result = frame.EvaluateExpression("(*c).a") + self.assertTrue(test_result.IsValid() and test_result.GetValueAsSigned() == 5678, "(*c).a = 5678") + + test_result = frame.EvaluateExpression("(*c + *c).a") + self.assertTrue(test_result.IsValid() and test_result.GetValueAsSigned() == 11356, "(*c + *c).a = 11356") + + test_result = frame.EvaluateExpression("q(*c + *c).a") + self.assertTrue(test_result.IsValid() and test_result.GetValueAsSigned() == 11356, "q(*c + *c).a = 11356") + + test_result = frame.EvaluateExpression("make_int().get_type()") + self.assertTrue(test_result.IsValid() and test_result.GetValue() == "INT", "make_int().get_type() = \"INT\"") + + +if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() + atexit.register(lambda: lldb.SBDebugger.Terminate()) + unittest2.main() Index: test/lang/cpp/chained-calls/main.cpp =================================================================== --- /dev/null +++ test/lang/cpp/chained-calls/main.cpp @@ -0,0 +1,186 @@ +class S +{ +public: + S () { } + S (S &obj); + + S operator+ (const S &s); + + int a; +}; + +S::S (S &obj) +{ + a = obj.a; +} + +S +S::operator+ (const S &s) +{ + S res; + + res.a = a + s.a; + + return res; +} + +S +f (int i) +{ + S s; + + s.a = i; + + return s; +} + +int +g (const S &s) +{ + return s.a; +} + +class A +{ +public: + A operator+ (const A &); + int a; +}; + +A +A::operator+ (const A &obj) +{ + A n; + + n.a = a + obj.a; + + return n; +} + +A +p () +{ + A a; + a.a = 12345678; + return a; +} + +A +r () +{ + A a; + a.a = 10000000; + return a; +} + +A +q (const A &a) +{ + return a; +} + +class B +{ +public: + int b[1024]; +}; + +B +makeb () +{ + B b; + int i; + + for (i = 0; i < 1024; i++) + b.b[i] = i; + + return b; +} + +int +getb (const B &b, int i) +{ + return b.b[i]; +} + +class C +{ +public: + C (); + ~C (); + + A operator* (); + + A *a_ptr; +}; + +C::C () +{ + a_ptr = new A; + a_ptr->a = 5678; +} + +C::~C () +{ + delete a_ptr; +} + +A +C::operator* () +{ + return *a_ptr; +} + +#define TYPE_INDEX 1 + +enum type +{ + INT, + CHAR +}; + +union U +{ +public: + U (type t); + type get_type (); + + int a; + char c; + type tp[2]; +}; + +U::U (type t) +{ + tp[TYPE_INDEX] = t; +} + +U +make_int () +{ + return U (INT); +} + +U +make_char () +{ + return U (CHAR); +} + +type +U::get_type () +{ + return tp[TYPE_INDEX]; +} + +int +main () +{ + int i = g(f(0)); + A a = q(p() + r()); + + B b = makeb (); + C c; + + return i + getb(b, 0); /* Break here */ +} Index: test/lang/cpp/global_operators/Makefile =================================================================== --- /dev/null +++ test/lang/cpp/global_operators/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make + +CXX_SOURCES := main.cpp + +include $(LEVEL)/Makefile.rules Index: test/lang/cpp/global_operators/TestCppGlobalOperators.py =================================================================== --- /dev/null +++ test/lang/cpp/global_operators/TestCppGlobalOperators.py @@ -0,0 +1,72 @@ +""" +Test that global operators are found and evaluated. +""" +import lldb +from lldbtest import * +import lldbutil + +class TestCppGlobalOperators(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @skipUnlessDarwin + @dsym_test + def test_with_dsym_and_run_command(self): + self.buildDsym() + self.check() + + @dwarf_test + def test_with_dwarf_and_run_command(self): + self.buildDwarf() + self.check() + + def setUp(self): + TestBase.setUp(self) + + def check(self): + # Get main source file + src_file = "main.cpp" + src_file_spec = lldb.SBFileSpec(src_file) + self.assertTrue(src_file_spec.IsValid(), "Main source file") + + # Get the path of the executable + cwd = os.getcwd() + exe_file = "a.out" + exe_path = os.path.join(cwd, exe_file) + + # Load the executable + target = self.dbg.CreateTarget(exe_path) + self.assertTrue(target.IsValid(), VALID_TARGET) + + # Break on main function + main_breakpoint = target.BreakpointCreateBySourceRegex("// break here", src_file_spec) + self.assertTrue(main_breakpoint.IsValid() and main_breakpoint.GetNumLocations() >= 1, VALID_BREAKPOINT) + + # Launch the process + args = None + env = None + process = target.LaunchSimple(args, env, cwd) + self.assertTrue(process.IsValid(), PROCESS_IS_VALID) + + # Get the thread of the process + self.assertTrue(process.GetState() == lldb.eStateStopped, PROCESS_STOPPED) + thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint) + + # Check if global operators are evaluated + frame = thread.GetSelectedFrame() + + test_result = frame.EvaluateExpression("operator==(s1, s2)") + self.assertTrue(test_result.IsValid() and test_result.GetValue() == "false", "operator==(s1, s2) = false") + + test_result = frame.EvaluateExpression("operator==(s1, s3)") + self.assertTrue(test_result.IsValid() and test_result.GetValue() == "true", "operator==(s1, s3) = true") + + test_result = frame.EvaluateExpression("operator==(s2, s3)") + self.assertTrue(test_result.IsValid() and test_result.GetValue() == "false", "operator==(s2, s3) = false") + + +if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() + atexit.register(lambda: lldb.SBDebugger.Terminate()) + unittest2.main() Index: test/lang/cpp/global_operators/main.cpp =================================================================== --- /dev/null +++ test/lang/cpp/global_operators/main.cpp @@ -0,0 +1,16 @@ +struct Struct { + int value; +}; + +bool operator==(const Struct &a, const Struct &b) { + return a.value == b.value; +} + +int main() { + Struct s1, s2, s3; + s1.value = 3; + s2.value = 5; + s3.value = 3; + return 0; // break here +} + Index: test/lang/cpp/nsimport/Makefile =================================================================== --- /dev/null +++ test/lang/cpp/nsimport/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make + +CXX_SOURCES := main.cpp + +include $(LEVEL)/Makefile.rules Index: test/lang/cpp/nsimport/TestCppNsImport.py =================================================================== --- /dev/null +++ test/lang/cpp/nsimport/TestCppNsImport.py @@ -0,0 +1,76 @@ +""" +Tests imported namespaces in C++. +""" +import lldb +from lldbtest import * +import lldbutil + +class TestCppNsImport(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @skipUnlessDarwin + @dsym_test + def test_with_dsym_and_run_command(self): + """Tests imported namespaces in C++.""" + self.buildDsym() + self.check() + + @dwarf_test + def test_with_dwarf_and_run_command(self): + """Tests imported namespaces in C++.""" + self.buildDwarf() + self.check() + + def setUp(self): + TestBase.setUp(self) + + def check(self): + """Tests imported namespaces in C++.""" + + # Get main source file + src_file = "main.cpp" + src_file_spec = lldb.SBFileSpec(src_file) + self.assertTrue(src_file_spec.IsValid(), "Main source file") + + # Get the path of the executable + cwd = os.getcwd() + exe_file = "a.out" + exe_path = os.path.join(cwd, exe_file) + + # Load the executable + target = self.dbg.CreateTarget(exe_path) + self.assertTrue(target.IsValid(), VALID_TARGET) + + # Break on main function + main_breakpoint = target.BreakpointCreateByName("main") + self.assertTrue(main_breakpoint.IsValid() and main_breakpoint.GetNumLocations() >= 1, VALID_BREAKPOINT) + + # Launch the process + args = None + env = None + process = target.LaunchSimple(args, env, cwd) + self.assertTrue(process.IsValid(), PROCESS_IS_VALID) + + # Get the thread of the process + self.assertTrue(process.GetState() == lldb.eStateStopped, PROCESS_STOPPED) + thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint) + + # Get current fream of the thread at the breakpoint + frame = thread.GetSelectedFrame() + + # Test imported namespaces + test_result = frame.EvaluateExpression("x") + self.assertTrue(test_result.IsValid() and test_result.GetValueAsSigned() == 11, "x = 11") + + test_result = frame.EvaluateExpression("xx") + self.assertTrue(test_result.IsValid() and test_result.GetValueAsSigned() == 22, "xx = 22") + + test_result = frame.EvaluateExpression("xxx") + self.assertTrue(test_result.IsValid() and test_result.GetValueAsSigned() == 33, "xxx = 33") + +if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() + atexit.register(lambda: lldb.SBDebugger.Terminate()) + unittest2.main() Index: test/lang/cpp/nsimport/main.cpp =================================================================== --- /dev/null +++ test/lang/cpp/nsimport/main.cpp @@ -0,0 +1,19 @@ +namespace A { + int x = 11; + namespace { + int xx = 22; + } +} + +using namespace A; + +namespace { + int xxx = 33; +}; + +int main() { + x; + xx; + xxx; + return 0; +} Index: test/lang/cpp/restricted_names/Makefile =================================================================== --- /dev/null +++ test/lang/cpp/restricted_names/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make + +CXX_SOURCES := main.cpp + +include $(LEVEL)/Makefile.rules Index: test/lang/cpp/restricted_names/TestCppRestrictedNames.py =================================================================== --- /dev/null +++ test/lang/cpp/restricted_names/TestCppRestrictedNames.py @@ -0,0 +1,70 @@ +""" +Test restricted names ('id' and 'Class') in C++. +""" +import lldb +from lldbtest import * +import lldbutil + +class TestCppSizeof(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @skipUnlessDarwin + @dsym_test + def test_with_dsym_and_run_command(self): + self.buildDsym() + self.check() + + @dwarf_test + def test_with_dwarf_and_run_command(self): + self.buildDwarf() + self.check() + + def setUp(self): + TestBase.setUp(self) + + def check(self): + # Get main source file + src_file = "main.cpp" + src_file_spec = lldb.SBFileSpec(src_file) + self.assertTrue(src_file_spec.IsValid(), "Main source file") + + # Get the path of the executable + cwd = os.getcwd() + exe_file = "a.out" + exe_path = os.path.join(cwd, exe_file) + + # Load the executable + target = self.dbg.CreateTarget(exe_path) + self.assertTrue(target.IsValid(), VALID_TARGET) + + # Break on main function + main_breakpoint = target.BreakpointCreateBySourceRegex("// break here", src_file_spec) + self.assertTrue(main_breakpoint.IsValid() and main_breakpoint.GetNumLocations() >= 1, VALID_BREAKPOINT) + + # Launch the process + args = None + env = None + process = target.LaunchSimple(args, env, cwd) + self.assertTrue(process.IsValid(), PROCESS_IS_VALID) + + # Get the thread of the process + self.assertTrue(process.GetState() == lldb.eStateStopped, PROCESS_STOPPED) + thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint) + + # Get current fream of the thread at the breakpoint + frame = thread.GetSelectedFrame() + + # Test result for restricted names (check for wrong result) + test_result = frame.EvaluateExpression("Class(2)") + self.assertTrue(test_result.IsValid() and test_result.GetValueAsSigned() == 4, "Class(2) = 4") + + test_result = frame.EvaluateExpression("Class(3)") + self.assertTrue(test_result.IsValid() and test_result.GetValueAsSigned() == 6, "Class(3) = 6") + + +if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() + atexit.register(lambda: lldb.SBDebugger.Terminate()) + unittest2.main() Index: test/lang/cpp/restricted_names/main.cpp =================================================================== --- /dev/null +++ test/lang/cpp/restricted_names/main.cpp @@ -0,0 +1,7 @@ +int Class(int x) { + return x + x; +} + +int main() { // break here + return 0; +} Index: test/lang/objc/objc-builtin-types/TestObjCBuiltinTypes.py =================================================================== --- test/lang/objc/objc-builtin-types/TestObjCBuiltinTypes.py +++ test/lang/objc/objc-builtin-types/TestObjCBuiltinTypes.py @@ -11,15 +11,14 @@ mydir = TestBase.compute_mydir(__file__) @skipUnlessDarwin - @python_api_test - + @unittest2.expectedFailure @dsym_test def test_with_dsym_and_python_api(self): """Test expression parser respect for ObjC built-in types.""" self.buildDsym() self.objc_builtin_types() - @python_api_test + @unittest2.expectedFailure @dwarf_test def test_with_dwarf_and_python_api(self): """Test expression parser respect for ObjC built-in types."""