Index: include/lldb/Symbol/ClangASTContext.h =================================================================== --- include/lldb/Symbol/ClangASTContext.h +++ include/lldb/Symbol/ClangASTContext.h @@ -422,6 +422,11 @@ GetUniqueNamespaceDeclaration (const char *name, clang::DeclContext *decl_ctx); + static clang::NamespaceDecl * + GetUniqueNamespaceDeclaration (clang::ASTContext *ast, + const char *name, + clang::DeclContext *decl_ctx); + //------------------------------------------------------------------ // Function Types //------------------------------------------------------------------ @@ -565,7 +570,9 @@ //---------------------------------------------------------------------- std::vector - DeclContextFindDeclByName (void *opaque_decl_ctx, ConstString name) override; + DeclContextFindDeclByName (void *opaque_decl_ctx, + ConstString name, + const bool ignore_using_decls) override; bool DeclContextIsStructUnionOrClass (void *opaque_decl_ctx) override; Index: include/lldb/Symbol/CompilerDeclContext.h =================================================================== --- include/lldb/Symbol/CompilerDeclContext.h +++ include/lldb/Symbol/CompilerDeclContext.h @@ -66,7 +66,7 @@ IsClang () const; std::vector - FindDeclByName (ConstString name); + FindDeclByName (ConstString name, const bool ignore_using_decls); //---------------------------------------------------------------------- /// Checks if this decl context represents a method of a class. Index: include/lldb/Symbol/TypeSystem.h =================================================================== --- include/lldb/Symbol/TypeSystem.h +++ include/lldb/Symbol/TypeSystem.h @@ -143,7 +143,9 @@ //---------------------------------------------------------------------- virtual std::vector - DeclContextFindDeclByName (void *opaque_decl_ctx, ConstString name); + DeclContextFindDeclByName (void *opaque_decl_ctx, + ConstString name, + const bool ignore_imported_decls); virtual bool DeclContextIsStructUnionOrClass (void *opaque_decl_ctx) = 0; Index: packages/Python/lldbsuite/test/lang/cpp/member-and-local-vars-with-same-name/Makefile =================================================================== --- /dev/null +++ packages/Python/lldbsuite/test/lang/cpp/member-and-local-vars-with-same-name/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make + +CXX_SOURCES = main.cpp + +include $(LEVEL)/Makefile.rules Index: packages/Python/lldbsuite/test/lang/cpp/member-and-local-vars-with-same-name/TestMembersAndLocalsWithSameName.py =================================================================== --- /dev/null +++ packages/Python/lldbsuite/test/lang/cpp/member-and-local-vars-with-same-name/TestMembersAndLocalsWithSameName.py @@ -0,0 +1,197 @@ +import lldb +from lldbsuite.test.lldbtest import * +import lldbsuite.test.lldbutil as lldbutil + +class TestMembersAndLocalsWithSameName(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + def test_when_stopped_in_method(self): + self._load_exe() + + # Set breakpoints + bp1 = self.target.BreakpointCreateBySourceRegex("Break 1", self.src_file_spec) + self.assertTrue(bp1.IsValid() and bp1.GetNumLocations() >= 1, VALID_BREAKPOINT) + bp2 = self.target.BreakpointCreateBySourceRegex("Break 2", self.src_file_spec) + self.assertTrue(bp2.IsValid() and bp2.GetNumLocations() >= 1, VALID_BREAKPOINT) + bp3 = self.target.BreakpointCreateBySourceRegex("Break 3", self.src_file_spec) + self.assertTrue(bp3.IsValid() and bp3.GetNumLocations() >= 1, VALID_BREAKPOINT) + bp4 = self.target.BreakpointCreateBySourceRegex("Break 4", self.src_file_spec) + self.assertTrue(bp4.IsValid() and bp4.GetNumLocations() >= 1, VALID_BREAKPOINT) + + # Launch the process + self.process = self.target.LaunchSimple(None, None, self.get_process_working_directory()) + self.assertTrue(self.process.IsValid(), PROCESS_IS_VALID) + + self.assertTrue(self.process.GetState() == lldb.eStateStopped, PROCESS_STOPPED) + + self._test_globals() + + self.process.Continue() + self.assertTrue(self.process.GetState() == lldb.eStateStopped, PROCESS_STOPPED) + thread = lldbutil.get_stopped_thread(self.process, lldb.eStopReasonBreakpoint) + self.assertTrue(thread.IsValid()) + frame = thread.GetSelectedFrame() + self.assertTrue(frame.IsValid()) + + val = frame.EvaluateExpression("a"); + self.assertTrue(val.IsValid()) + self.assertEqual(val.GetValueAsUnsigned(), 12345) + + val = frame.EvaluateExpression("b"); + self.assertTrue(val.IsValid()) + self.assertEqual(val.GetValueAsUnsigned(), 54321) + + val = frame.EvaluateExpression("c"); + self.assertTrue(val.IsValid()) + self.assertEqual(val.GetValueAsUnsigned(), 34567) + + self.process.Continue() + self.assertTrue(self.process.GetState() == lldb.eStateStopped, PROCESS_STOPPED) + thread = lldbutil.get_stopped_thread(self.process, lldb.eStopReasonBreakpoint) + self.assertTrue(thread.IsValid()) + frame = thread.GetSelectedFrame() + self.assertTrue(frame.IsValid()) + + val = frame.EvaluateExpression("a"); + self.assertTrue(val.IsValid()) + self.assertEqual(val.GetValueAsUnsigned(), 10001) + + val = frame.EvaluateExpression("b"); + self.assertTrue(val.IsValid()) + self.assertEqual(val.GetValueAsUnsigned(), 10002) + + val = frame.EvaluateExpression("c"); + self.assertTrue(val.IsValid()) + self.assertEqual(val.GetValueAsUnsigned(), 10003) + + self.process.Continue() + self.assertTrue(self.process.GetState() == lldb.eStateStopped, PROCESS_STOPPED) + thread = lldbutil.get_stopped_thread(self.process, lldb.eStopReasonBreakpoint) + self.assertTrue(thread.IsValid()) + frame = thread.GetSelectedFrame() + self.assertTrue(frame.IsValid()) + + val = frame.EvaluateExpression("a"); + self.assertTrue(val.IsValid()) + self.assertEqual(val.GetValueAsUnsigned(), 1) + + val = frame.EvaluateExpression("b"); + self.assertTrue(val.IsValid()) + self.assertEqual(val.GetValueAsUnsigned(), 2) + + val = frame.EvaluateExpression("c"); + self.assertTrue(val.IsValid()) + self.assertEqual(val.GetValueAsUnsigned(), 778899) + + def test_when_stopped_in_function(self): + self._load_exe() + + # Set breakpoints + bp1 = self.target.BreakpointCreateBySourceRegex("Break 1", self.src_file_spec) + self.assertTrue(bp1.IsValid() and bp1.GetNumLocations() >= 1, VALID_BREAKPOINT) + bp5 = self.target.BreakpointCreateBySourceRegex("Break 5", self.src_file_spec) + self.assertTrue(bp5.IsValid() and bp5.GetNumLocations() >= 1, VALID_BREAKPOINT) + bp6 = self.target.BreakpointCreateBySourceRegex("Break 6", self.src_file_spec) + self.assertTrue(bp6.IsValid() and bp6.GetNumLocations() >= 1, VALID_BREAKPOINT) + bp7 = self.target.BreakpointCreateBySourceRegex("Break 7", self.src_file_spec) + self.assertTrue(bp7.IsValid() and bp7.GetNumLocations() >= 1, VALID_BREAKPOINT) + + # Launch the process + self.process = self.target.LaunchSimple(None, None, self.get_process_working_directory()) + self.assertTrue(self.process.IsValid(), PROCESS_IS_VALID) + + self.assertTrue(self.process.GetState() == lldb.eStateStopped, PROCESS_STOPPED) + + self._test_globals() + + self.process.Continue() + self.assertTrue(self.process.GetState() == lldb.eStateStopped, PROCESS_STOPPED) + thread = lldbutil.get_stopped_thread(self.process, lldb.eStopReasonBreakpoint) + self.assertTrue(thread.IsValid()) + frame = thread.GetSelectedFrame() + self.assertTrue(frame.IsValid()) + + val = frame.EvaluateExpression("a"); + self.assertTrue(val.IsValid()) + self.assertEqual(val.GetValueAsUnsigned(), 12345) + + val = frame.EvaluateExpression("b"); + self.assertTrue(val.IsValid()) + self.assertEqual(val.GetValueAsUnsigned(), 54321) + + val = frame.EvaluateExpression("c"); + self.assertTrue(val.IsValid()) + self.assertEqual(val.GetValueAsUnsigned(), 34567) + + self.process.Continue() + self.assertTrue(self.process.GetState() == lldb.eStateStopped, PROCESS_STOPPED) + thread = lldbutil.get_stopped_thread(self.process, lldb.eStopReasonBreakpoint) + self.assertTrue(thread.IsValid()) + frame = thread.GetSelectedFrame() + self.assertTrue(frame.IsValid()) + + val = frame.EvaluateExpression("a"); + self.assertTrue(val.IsValid()) + self.assertEqual(val.GetValueAsUnsigned(), 10001) + + val = frame.EvaluateExpression("b"); + self.assertTrue(val.IsValid()) + self.assertEqual(val.GetValueAsUnsigned(), 10002) + + val = frame.EvaluateExpression("c"); + self.assertTrue(val.IsValid()) + self.assertEqual(val.GetValueAsUnsigned(), 10003) + + self.process.Continue() + self.assertTrue(self.process.GetState() == lldb.eStateStopped, PROCESS_STOPPED) + thread = lldbutil.get_stopped_thread(self.process, lldb.eStopReasonBreakpoint) + self.assertTrue(thread.IsValid()) + frame = thread.GetSelectedFrame() + self.assertTrue(frame.IsValid()) + + val = frame.EvaluateExpression("a"); + self.assertTrue(val.IsValid()) + self.assertEqual(val.GetValueAsUnsigned(), 1) + + val = frame.EvaluateExpression("b"); + self.assertTrue(val.IsValid()) + self.assertEqual(val.GetValueAsUnsigned(), 2) + + val = frame.EvaluateExpression("c"); + self.assertTrue(val.IsValid()) + self.assertEqual(val.GetValueAsUnsigned(), 778899) + + def _load_exe(self): + self.build() + + cwd = os.getcwd() + + src_file = os.path.join(cwd, "main.cpp") + self.src_file_spec = lldb.SBFileSpec(src_file) + self.assertTrue(self.src_file_spec.IsValid(), "breakpoint file") + + # Get the path of the executable + exe_path = os.path.join(cwd, 'a.out') + + # Load the executable + self.target = self.dbg.CreateTarget(exe_path) + self.assertTrue(self.target.IsValid(), VALID_TARGET) + + def _test_globals(self): + thread = lldbutil.get_stopped_thread(self.process, lldb.eStopReasonBreakpoint) + self.assertTrue(thread.IsValid()) + frame = thread.GetSelectedFrame() + self.assertTrue(frame.IsValid()) + + val = frame.EvaluateExpression("a"); + self.assertTrue(val.IsValid()) + self.assertEqual(val.GetValueAsUnsigned(), 112233) + + val = frame.EvaluateExpression("b"); + self.assertTrue(val.IsValid()) + self.assertEqual(val.GetValueAsUnsigned(), 445566) + + val = frame.EvaluateExpression("c"); + self.assertTrue(val.IsValid()) + self.assertEqual(val.GetValueAsUnsigned(), 778899) Index: packages/Python/lldbsuite/test/lang/cpp/member-and-local-vars-with-same-name/main.cpp =================================================================== --- /dev/null +++ packages/Python/lldbsuite/test/lang/cpp/member-and-local-vars-with-same-name/main.cpp @@ -0,0 +1,73 @@ +namespace NN +{ + int a = 778899; + int b = 665544; + int c = 445566; +} + +class A +{ +public: + A(); + int Method(int a, int b); + +private: + int a, b; +}; + +A::A() : a(10), b(100) { } + +int a = 112233; +int b = 445566; +int c = 778899; + +int +A::Method(int a, int b) +{ + { + int a = 12345; + int b = 54321; + int c = 34567; + this->a = a + b + this->b; // Break 2 + } + + { + using namespace NN; + int a = 10001; + int b = 10002; + int c = 10003; + this->a = a + b + this->b; // Break 3 + } + + return this->a + this->b + a + b; // Break 4 +} + +int +Function(int a, int b) +{ + int A; + + { + int a = 12345; + int b = 54321; + int c = 34567; + A = a + b + c; // Break 5 + } + + { + using namespace NN; + int a = 10001; + int b = 10002; + int c = 10003; + A = a + b + c; // Break 6 + } + + return A + a + b; // Break 7 +} + +int +main() +{ + A obj; + return obj.Method(1, 2) + Function(1, 2); // Break 1 +} Index: source/Expression/ExpressionSourceCode.cpp =================================================================== --- source/Expression/ExpressionSourceCode.cpp +++ source/Expression/ExpressionSourceCode.cpp @@ -16,7 +16,9 @@ #include "lldb/Symbol/DebugMacros.h" #include "lldb/Symbol/Block.h" #include "lldb/Symbol/TypeSystem.h" +#include "lldb/Symbol/VariableList.h" #include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Language.h" #include "lldb/Target/Platform.h" #include "lldb/Target/StackFrame.h" #include "lldb/Target/Target.h" @@ -175,6 +177,21 @@ } } +static void +AddLocalVariableDecls(const lldb::VariableListSP &var_list_sp, StreamString &stream) +{ + for (size_t i = 0; i < var_list_sp->GetSize(); i++) + { + lldb::VariableSP var_sp = var_list_sp->GetVariableAtIndex(i); + + ConstString var_name = var_sp->GetName(); + if (var_name == ConstString("this") || var_name == ConstString(".block_descriptor")) + continue; + + stream.Printf("using $__lldb_local_vars::%s;\n", var_name.AsCString()); + } +} + bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrapping_language, bool const_object, bool static_method, ExecutionContext &exe_ctx) const { const char *target_specific_defines = "typedef signed char BOOL;\n"; @@ -239,6 +256,7 @@ } StreamString debug_macros_stream; + StreamString lldb_local_var_decls; if (StackFrame *frame = exe_ctx.GetFramePtr()) { const SymbolContext &sc = frame->GetSymbolContext( @@ -253,8 +271,15 @@ AddMacros(dm, sc.comp_unit, state, debug_macros_stream); } } + + ConstString object_name; + if (Language::LanguageIsCPlusPlus(frame->GetLanguage())) + { + lldb::VariableListSP var_list_sp = frame->GetInScopeVariableList(false); + AddLocalVariableDecls(var_list_sp, lldb_local_var_decls); + } } - + if (m_wrap) { switch (wrapping_language) @@ -284,19 +309,23 @@ wrap_stream.Printf("void \n" "%s(void *$__lldb_arg) \n" "{ \n" + " %s; \n" " %s; \n" "} \n", m_name.c_str(), + lldb_local_var_decls.GetData(), m_body.c_str()); break; case lldb::eLanguageTypeC_plus_plus: wrap_stream.Printf("void \n" "$__lldb_class::%s(void *$__lldb_arg) %s\n" "{ \n" + " %s; \n" " %s; \n" "} \n", m_name.c_str(), (const_object ? "const" : ""), + lldb_local_var_decls.GetData(), m_body.c_str()); break; case lldb::eLanguageTypeObjC: @@ -339,6 +368,6 @@ { text.append(m_body); } - + return true; } Index: source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h =================================================================== --- source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h +++ source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h @@ -707,6 +707,9 @@ AddThisType(NameSearchContext &context, TypeFromUser &type, unsigned int current_id); + + ClangASTContext * + GetClangASTContext(); }; } // namespace lldb_private Index: source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp =================================================================== --- source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp +++ source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp @@ -57,6 +57,11 @@ using namespace lldb_private; using namespace clang; +namespace +{ + const char *g_lldb_local_vars_namespace_cstr = "$__lldb_local_vars"; +} // anonymous namespace + ClangExpressionDeclMap::ClangExpressionDeclMap (bool keep_result_in_memory, Materializer::PersistentVariableDelegate *result_delegate, ExecutionContext &exe_ctx) : @@ -1004,6 +1009,24 @@ return VariableSP(); } +ClangASTContext * +ClangExpressionDeclMap::GetClangASTContext () +{ + StackFrame *frame = m_parser_vars->m_exe_ctx.GetFramePtr(); + if (frame == nullptr) + return nullptr; + + SymbolContext sym_ctx = frame->GetSymbolContext(lldb::eSymbolContextFunction|lldb::eSymbolContextBlock); + if (sym_ctx.block == nullptr) + return nullptr; + + CompilerDeclContext frame_decl_context = sym_ctx.block->GetDeclContext(); + if (!frame_decl_context) + return nullptr; + + return llvm::dyn_cast_or_null(frame_decl_context.GetTypeSystem()); +} + // Interface for ClangASTSource void @@ -1039,6 +1062,13 @@ if (const NamespaceDecl *namespace_context = dyn_cast(context.m_decl_context)) { + if (namespace_context->getName().str() == std::string(g_lldb_local_vars_namespace_cstr)) + { + CompilerDeclContext compiler_decl_ctx(GetClangASTContext(), (void*)context.m_decl_context); + FindExternalVisibleDecls(context, lldb::ModuleSP(), compiler_decl_ctx, current_id); + return; + } + ClangASTImporter::NamespaceMapSP namespace_map = m_ast_importer_sp->GetNamespaceMap(namespace_context); if (log && log->GetVerbose()) @@ -1335,6 +1365,32 @@ return; } + if (name == ConstString(g_lldb_local_vars_namespace_cstr)) + { + CompilerDeclContext frame_decl_context = sym_ctx.block != nullptr ? + sym_ctx.block->GetDeclContext() : + CompilerDeclContext(); + + if (frame_decl_context) + { + ClangASTContext *ast = llvm::dyn_cast_or_null(frame_decl_context.GetTypeSystem()); + + if (ast) + { + clang::NamespaceDecl *namespace_decl = ClangASTContext::GetUniqueNamespaceDeclaration( + m_ast_context, name_unique_cstr, nullptr); + if (namespace_decl) + { + context.AddNamedDecl(namespace_decl); + clang::DeclContext *clang_decl_ctx = clang::Decl::castToDeclContext(namespace_decl); + clang_decl_ctx->setHasExternalVisibleStorage(true); + } + } + } + + return; + } + // any other $__lldb names should be weeded out now if (!::strncmp(name_unique_cstr, "$__lldb", sizeof("$__lldb") - 1)) return; @@ -1403,19 +1459,23 @@ ValueObjectSP valobj; VariableSP var; - if (frame && !namespace_decl) + bool local_var_lookup = !namespace_decl || + (namespace_decl.GetName() == ConstString(g_lldb_local_vars_namespace_cstr)); + if (frame && local_var_lookup) { CompilerDeclContext compiler_decl_context = sym_ctx.block != nullptr ? sym_ctx.block->GetDeclContext() : CompilerDeclContext(); if (compiler_decl_context) { - // Make sure that the variables are parsed so that we have the declarations + // Make sure that the variables are parsed so that we have the declarations. VariableListSP vars = frame->GetInScopeVariableList(true); for (size_t i = 0; i < vars->GetSize(); i++) vars->GetVariableAtIndex(i)->GetDecl(); - // Search for declarations matching the name - std::vector found_decls = compiler_decl_context.FindDeclByName(name); + // Search for declarations matching the name. Do not include imported decls + // in the search if we are looking for decls in the artificial namespace + // $__lldb_local_vars. + std::vector found_decls = compiler_decl_context.FindDeclByName(name, namespace_decl.IsValid()); bool variable_found = false; for (CompilerDecl decl : found_decls) Index: source/Symbol/ClangASTContext.cpp =================================================================== --- source/Symbol/ClangASTContext.cpp +++ source/Symbol/ClangASTContext.cpp @@ -1885,6 +1885,17 @@ return namespace_decl; } +NamespaceDecl * +ClangASTContext::GetUniqueNamespaceDeclaration (clang::ASTContext *ast, + const char *name, + clang::DeclContext *decl_ctx) +{ + ClangASTContext *ast_ctx = ClangASTContext::GetASTContext(ast); + if (ast_ctx == nullptr) + return nullptr; + + return ast_ctx->GetUniqueNamespaceDeclaration(name, decl_ctx); +} clang::BlockDecl * ClangASTContext::CreateBlockDeclaration (clang::DeclContext *ctx) @@ -9781,7 +9792,9 @@ //---------------------------------------------------------------------- std::vector -ClangASTContext::DeclContextFindDeclByName(void *opaque_decl_ctx, ConstString name) +ClangASTContext::DeclContextFindDeclByName(void *opaque_decl_ctx, + ConstString name, + const bool ignore_using_decls) { std::vector found_decls; if (opaque_decl_ctx) @@ -9805,12 +9818,16 @@ { if (clang::UsingDirectiveDecl *ud = llvm::dyn_cast(child)) { + if (ignore_using_decls) + continue; clang::DeclContext *from = ud->getCommonAncestor(); if (searched.find(ud->getNominatedNamespace()) == searched.end()) search_queue.insert(std::make_pair(from, ud->getNominatedNamespace())); } else if (clang::UsingDecl *ud = llvm::dyn_cast(child)) { + if (ignore_using_decls) + continue; for (clang::UsingShadowDecl *usd : ud->shadows()) { clang::Decl *target = usd->getTargetDecl(); Index: source/Symbol/CompilerDeclContext.cpp =================================================================== --- source/Symbol/CompilerDeclContext.cpp +++ source/Symbol/CompilerDeclContext.cpp @@ -15,10 +15,11 @@ using namespace lldb_private; std::vector -CompilerDeclContext::FindDeclByName (ConstString name) +CompilerDeclContext::FindDeclByName (ConstString name, const bool ignore_using_decls) { if (IsValid()) - return m_type_system->DeclContextFindDeclByName(m_opaque_decl_ctx, name); + return m_type_system->DeclContextFindDeclByName( + m_opaque_decl_ctx, name, ignore_using_decls); else return std::vector(); } Index: source/Symbol/TypeSystem.cpp =================================================================== --- source/Symbol/TypeSystem.cpp +++ source/Symbol/TypeSystem.cpp @@ -153,7 +153,9 @@ std::vector -TypeSystem::DeclContextFindDeclByName (void *opaque_decl_ctx, ConstString name) +TypeSystem::DeclContextFindDeclByName (void *opaque_decl_ctx, + ConstString name, + bool ignore_imported_decls) { return std::vector(); }