Index: include/lldb/Symbol/Block.h =================================================================== --- include/lldb/Symbol/Block.h +++ include/lldb/Symbol/Block.h @@ -18,6 +18,7 @@ #include "lldb/Symbol/LineEntry.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/CompilerType.h" +#include "lldb/Symbol/CompilerDeclContext.h" namespace lldb_private { @@ -358,6 +359,18 @@ CompilerDeclContext GetDeclContext(); + CompilerDeclContext + GetClangDecl() + { + return m_clang_decl_context; + } + + void + SetClangDecl(CompilerDeclContext decl) + { + m_clang_decl_context = decl; + } + //------------------------------------------------------------------ /// Get the memory cost of this object. /// @@ -476,6 +489,7 @@ bool m_parsed_block_info:1, ///< Set to true if this block and it's children have all been parsed m_parsed_block_variables:1, m_parsed_child_blocks:1; + CompilerDeclContext m_clang_decl_context; // A parent of child blocks can be asked to find a sibling block given // one of its child blocks Index: include/lldb/Symbol/ClangASTContext.h =================================================================== --- include/lldb/Symbol/ClangASTContext.h +++ include/lldb/Symbol/ClangASTContext.h @@ -23,13 +23,17 @@ #include "llvm/ADT/SmallVector.h" #include "clang/AST/ASTContext.h" #include "clang/AST/TemplateBase.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" // Project includes #include "lldb/lldb-enumerations.h" #include "lldb/Core/ClangForward.h" #include "lldb/Core/ConstString.h" +#include "lldb/Symbol/Block.h" #include "lldb/Symbol/CompilerType.h" #include "lldb/Symbol/TypeSystem.h" +#include "lldb/Symbol/Variable.h" namespace lldb_private { @@ -1069,6 +1073,73 @@ int tag_decl_kind, const ClangASTContext::TemplateParameterInfos &template_param_infos); + clang::DeclContext * + CreateBlockDeclaration (clang::DeclContext *ctx, lldb_private::Block *block) + { + if (ctx != nullptr && block != nullptr) + { + clang::BlockDecl *decl = clang::BlockDecl::Create(*getASTContext(), ctx, clang::SourceLocation()); + ctx->addDecl(decl); + CompilerDeclContext decl_context(this, llvm::dyn_cast(decl)); + block->SetClangDecl(decl_context); + return decl; + } + return nullptr; + } + + clang::UsingDirectiveDecl * + CreateUsingDirectiveDeclaration (clang::DeclContext *decl_ctx, clang::NamespaceDecl *ns_decl) + { + if (decl_ctx != nullptr && ns_decl != nullptr) + { + // TODO: run LCA between decl_tx and ns_decl + clang::UsingDirectiveDecl *using_decl = clang::UsingDirectiveDecl::Create(*getASTContext(), + decl_ctx, + clang::SourceLocation(), + clang::SourceLocation(), + clang::NestedNameSpecifierLoc(), + clang::SourceLocation(), + ns_decl, + GetTranslationUnitDecl(getASTContext())); + decl_ctx->addDecl(using_decl); + return using_decl; + } + return nullptr; + } + + clang::VarDecl * + CreateVariableDeclaration (clang::DeclContext *decl_ctx, lldb::VariableSP var_sp, CompilerType clang_type) + { + if (decl_ctx != nullptr && var_sp && clang_type.IsValid()) + { + const char *name = var_sp->GetUnqualifiedName().AsCString(nullptr); + clang::VarDecl *var_decl = clang::VarDecl::Create(*getASTContext(), + decl_ctx, + clang::SourceLocation(), + clang::SourceLocation(), + name && name[0] ? &getASTContext()->Idents.getOwn(name) : nullptr, + GetQualType(clang_type), + nullptr, + clang::SC_None); + var_decl->setAccess(clang::AS_public); + decl_ctx->addDecl(var_decl); + decl_ctx->makeDeclVisibleInContext(var_decl); + m_decl_to_var.insert(std::make_pair(var_decl, var_sp)); + var_sp->SetVarDecl(CompilerDeclContext(this, var_decl)); + return var_decl; + } + return nullptr; + } + + lldb::VariableSP + GetVariableFromDecl (clang::VarDecl *var_decl) + { + auto decl_to_var_it = m_decl_to_var.find(var_decl); + if (decl_to_var_it != m_decl_to_var.end()) + return decl_to_var_it->second; + return lldb::VariableSP(); + } + protected: static clang::QualType GetQualType (void *type) @@ -1108,6 +1179,7 @@ void * m_callback_baton; uint32_t m_pointer_byte_size; bool m_ast_owned; + std::map m_decl_to_var; private: //------------------------------------------------------------------ Index: include/lldb/Symbol/Variable.h =================================================================== --- include/lldb/Symbol/Variable.h +++ include/lldb/Symbol/Variable.h @@ -18,6 +18,7 @@ #include "lldb/Core/UserID.h" #include "lldb/Expression/DWARFExpression.h" #include "lldb/Symbol/Declaration.h" +#include "lldb/Symbol/CompilerDeclContext.h" namespace lldb_private { @@ -59,6 +60,9 @@ ConstString GetName() const; + ConstString + GetUnqualifiedName() const; + SymbolContextScope * GetSymbolContextScope() const { @@ -167,6 +171,21 @@ StringList &matches, bool &word_complete); + CompilerDeclContext + GetParentDeclContext (); + + CompilerDeclContext + GetVarDecl () + { + return m_var_decl; + } + + void + SetVarDecl (CompilerDeclContext var_decl) + { + m_var_decl = var_decl; + } + protected: ConstString m_name; // The basename of the variable (no namespaces) Mangled m_mangled; // The mangled name of the variable @@ -179,6 +198,7 @@ m_artificial:1, // Non-zero if the variable is not explicitly declared in source m_loc_is_const_data:1, // The m_location expression contains the constant variable value data, not a DWARF location m_static_member:1; // Non-zero if variable is static member of a class or struct. + CompilerDeclContext m_var_decl; private: Variable(const Variable& rhs); Variable& operator=(const Variable& rhs); Index: source/Expression/ClangASTSource.cpp =================================================================== --- source/Expression/ClangASTSource.cpp +++ source/Expression/ClangASTSource.cpp @@ -515,7 +515,7 @@ else log->Printf(" FELD[%d] Adding lexical %sDecl %s", current_id, decl->getDeclKindName(), ast_dumper.GetCString()); } - + Decl *copied_decl = m_ast_importer->CopyDecl(m_ast_context, original_ctx, decl); if (!copied_decl) Index: source/Expression/ClangExpressionDeclMap.cpp =================================================================== --- source/Expression/ClangExpressionDeclMap.cpp +++ source/Expression/ClangExpressionDeclMap.cpp @@ -1031,6 +1031,9 @@ // doesn't start with our phony prefix of '$' Target *target = m_parser_vars->m_exe_ctx.GetTargetPtr(); StackFrame *frame = m_parser_vars->m_exe_ctx.GetFramePtr(); + SymbolContext sym_ctx; + if (frame != nullptr) + sym_ctx = frame->GetSymbolContext(lldb::eSymbolContextFunction|lldb::eSymbolContextBlock); if (name_unique_cstr[0] == '$' && !namespace_decl) { static ConstString g_lldb_class_name ("$__lldb_class"); @@ -1042,7 +1045,6 @@ if (frame == NULL) return; - SymbolContext sym_ctx = frame->GetSymbolContext(lldb::eSymbolContextFunction|lldb::eSymbolContextBlock); // Find the block that defines the function represented by "sym_ctx" Block *function_block = sym_ctx.GetFunctionBlock(); @@ -1348,6 +1350,72 @@ if (frame && !namespace_decl) { + CompilerDeclContext compiler_decl_context = sym_ctx.block != nullptr ? sym_ctx.block->GetClangDecl() : CompilerDeclContext(); + ClangASTContext *ast_context = (ClangASTContext *)compiler_decl_context.GetTypeSystem(); + + if (ast_context != nullptr && compiler_decl_context.IsValid()) + { + std::vector found_vars; + + // Make sure that the variables are parsed so that we have the declarations + frame->GetInScopeVariableList(true); + + std::multimap imported_contexts; + std::set already_imported; + + for (clang::DeclContext *decl_context = ClangASTContext::DeclContextGetAsDeclContext(compiler_decl_context); decl_context != nullptr && found_vars.empty(); decl_context = decl_context->getParent()) + { + for (clang::Decl *child : decl_context->decls()) + { + if (clang::VarDecl *vd = llvm::dyn_cast(child)) + { + if (ast_context->GetVariableFromDecl(vd) && vd->getName().equals(name_unique_cstr)) + found_vars.push_back(vd); + } + else if (clang::UsingDirectiveDecl *ud = llvm::dyn_cast(child)) + { + clang::DeclContext *from = ud->getCommonAncestor(); + if (already_imported.find(ud->getNominatedNamespace()) == already_imported.end()) + imported_contexts.insert(std::make_pair(from, ud->getNominatedNamespace())); + } + } + + for (auto imported_decl_ctx_it = imported_contexts.find(decl_context); imported_decl_ctx_it != imported_contexts.end(); imported_decl_ctx_it++) + { + clang::DeclContext *imported_decl_ctx = imported_decl_ctx_it->second; + if (already_imported.find(imported_decl_ctx) == already_imported.end()) + { + already_imported.insert(imported_decl_ctx); + for (clang::Decl *child : decl_context->decls()) + { + if (clang::VarDecl *vd = llvm::dyn_cast(child)) + { + if (ast_context->GetVariableFromDecl(vd) && vd->getName().equals(name_unique_cstr)) + found_vars.push_back(vd); + } + else if (clang::UsingDirectiveDecl *ud = llvm::dyn_cast(child)) + { + clang::DeclContext *from = ud->getCommonAncestor(); + if (already_imported.find(ud->getNominatedNamespace()) == already_imported.end()) + imported_contexts.insert(std::make_pair(from, ud->getNominatedNamespace())); + } + } + } + } + } + + for (clang::VarDecl *var_decl : found_vars) + { + var = ast_context->GetVariableFromDecl(var_decl); + valobj = ValueObjectVariable::Create(frame, var); + AddOneVariable(context, var, valobj, current_id); + context.m_found.variable = true; + return; + } + } + } + /*if (frame && !namespace_decl) + { valobj = frame->GetValueForVariableExpressionPath(name_unique_cstr, eNoDynamicValues, StackFrame::eExpressionPathOptionCheckPtrVsMember | @@ -1364,8 +1432,7 @@ context.m_found.variable = true; return; } - } - + }*/ if (target) { var = FindGlobalVariable (*target, Index: source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -3200,7 +3200,6 @@ decl_ctx = ResolveNamespaceDIE (die); try_parsing_type = false; break; - default: break; } Index: source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h =================================================================== --- source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -396,6 +396,12 @@ bool parse_children, lldb_private::VariableList* cc_variable_list = NULL); + void + ParseImportedNamespace ( + const lldb_private::SymbolContext &sc, + const DWARFDIE die, + const lldb::addr_t func_low_pc); + bool ClassOrStructIsVirtual (const DWARFDIE &die); Index: source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -1321,6 +1321,17 @@ block->SetInlinedFunctionInfo (name, mangled_name, decl_ap.get(), call_ap.get()); } + CompilerDeclContext parent_decl_ctx; + if (block->GetParent() != nullptr && block->GetParent()->GetClangDecl().IsValid()) + parent_decl_ctx = block->GetParent()->GetClangDecl(); + else + parent_decl_ctx = block->GetDeclContext(); + + clang::DeclContext *containing_decl_context = ClangASTContext::DeclContextGetAsDeclContext(parent_decl_ctx); + if (containing_decl_context != nullptr) + GetClangASTContext().CreateBlockDeclaration(containing_decl_context, block); + + ++blocks_added; if (die.HasChildren()) @@ -3730,6 +3741,9 @@ } } + if (DWARFDIE cu_die = dwarf_cu->GetDIE(dwarf_cu->GetFirstDIEOffset())) + for (auto d = cu_die.GetFirstChild(); d; d = d.GetSibling()) + ParseImportedNamespace(sc, d, LLDB_INVALID_ADDRESS); } return vars_added; } @@ -3737,6 +3751,55 @@ return 0; } +void +SymbolFileDWARF::ParseImportedNamespace +( + const SymbolContext &sc, + const DWARFDIE die, + const lldb::addr_t func_low_pc +) +{ + if (!die || (die.Tag() != DW_TAG_imported_module && die.Tag() != DW_TAG_imported_declaration)) + return; + + dw_offset_t imported_uid = die.GetAttributeValueAsReference(DW_AT_import, DW_INVALID_OFFSET); + if (UserIDMatches(imported_uid)) + { + DWARFDebugInfo *debug_info = DebugInfo(); + if (debug_info) + { + const DWARFDIE imported_die = debug_info->GetDIE(imported_uid); + TypeSystem *type_system = GetTypeSystemForLanguage(die.GetCU()->GetLanguageType()); + if (type_system) + { + DWARFASTParser *dwarf_ast = type_system->GetDWARFParser(); + if (dwarf_ast != nullptr) + { + if (die.Tag() == DW_TAG_imported_module) + { + CompilerDeclContext decl_context = dwarf_ast->GetDeclContextForUIDFromDWARF(imported_die); + if (clang::NamespaceDecl *ns_decl = ClangASTContext::DeclContextGetAsNamespaceDecl(decl_context)) + { + clang::DeclContext *context = nullptr; + if (sc.block != nullptr) + context = ClangASTContext::DeclContextGetAsDeclContext(sc.block->GetClangDecl()); + else + context = GetClangASTContext().GetTranslationUnitDecl(GetClangASTContext().getASTContext()); + + if (context != nullptr) + GetClangASTContext().CreateUsingDirectiveDeclaration(context, ns_decl); + } + } + else if (die.Tag() == DW_TAG_imported_declaration) + { + // TODO: handle imported declarations (using Namespace::Symbol) + } + } + } + } + } +} + VariableSP SymbolFileDWARF::ParseVariableDIE ( @@ -3762,6 +3825,7 @@ { DWARFAttributes attributes; const size_t num_attributes = die.GetAttributes(attributes); + DWARFDIE spec_die; if (num_attributes > 0) { const char *name = NULL; @@ -3883,7 +3947,17 @@ } } break; - + case DW_AT_specification: + { + dw_offset_t spec_uid = form_value.Reference(); + if (UserIDMatches(spec_uid)) + { + DWARFDebugInfo* debug_info = DebugInfo(); + if (debug_info) + spec_die = debug_info->GetDIE(spec_uid); + } + break; + } case DW_AT_artificial: is_artificial = form_value.Boolean(); break; case DW_AT_accessibility: break; //accessibility = DW_ACCESS_to_AccessType(form_value.Unsigned()); break; case DW_AT_declaration: @@ -3895,7 +3969,6 @@ default: case DW_AT_abstract_origin: case DW_AT_sibling: - case DW_AT_specification: break; } } @@ -3903,7 +3976,7 @@ const DWARFDIE parent_context_die = GetDeclContextDIEContainingDIE(die); const dw_tag_t parent_tag = die.GetParent().Tag(); - bool is_static_member = parent_tag == DW_TAG_compile_unit && (parent_context_die.Tag() == DW_TAG_class_type || parent_context_die.Tag() == DW_TAG_structure_type); + bool is_static_member = parent_tag == DW_TAG_compile_unit && (parent_context_die.Tag() == DW_TAG_class_type || parent_context_die.Tag() == DW_TAG_structure_type ); ValueType scope = eValueTypeInvalid; @@ -4099,6 +4172,22 @@ // (missing location due to optimization, etc)) so we don't re-parse // this DIE over and over later... m_die_to_variable_sp[die.GetDIE()] = var_sp; + if (spec_die) + m_die_to_variable_sp[spec_die.GetDIE()] = var_sp; + + if (var_sp && var_sp->GetType()) + { + SymbolContext sc; + var_sp->CalculateSymbolContext(&sc); + CompilerDeclContext var_decl_context; + if (sc.block != nullptr) + var_decl_context = sc.block->GetClangDecl(); + else + var_decl_context = var_sp->GetParentDeclContext(); + + if (var_decl_context) + GetClangASTContext().CreateVariableDeclaration(ClangASTContext::DeclContextGetAsDeclContext(var_decl_context), var_sp, var_sp->GetType()->GetForwardCompilerType()); + } } return var_sp; } @@ -4262,6 +4351,8 @@ } } } + else if (tag == DW_TAG_imported_module || tag == DW_TAG_imported_declaration) + ParseImportedNamespace(sc, die, func_low_pc); } bool skip_children = (sc.function == NULL && tag == DW_TAG_subprogram); Index: source/Symbol/Block.cpp =================================================================== --- source/Symbol/Block.cpp +++ source/Symbol/Block.cpp @@ -566,6 +566,7 @@ return CompilerDeclContext(); } + void Block::SetBlockInfoHasBeenParsed (bool b, bool set_children) { Index: source/Symbol/Variable.cpp =================================================================== --- source/Symbol/Variable.cpp +++ source/Symbol/Variable.cpp @@ -18,6 +18,7 @@ #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/SymbolContext.h" +#include "lldb/Symbol/SymbolFile.h" #include "lldb/Symbol/Type.h" #include "lldb/Symbol/VariableList.h" #include "lldb/Target/ABI.h" @@ -89,6 +90,13 @@ return m_name; } +ConstString +Variable::GetUnqualifiedName() const +{ + return m_name; +} + + bool Variable::NameMatches (const ConstString &name) const { @@ -230,6 +238,12 @@ return sizeof(Variable); } +CompilerDeclContext +Variable::GetParentDeclContext () +{ + Type *type = GetType(); + return type->GetSymbolFile()->GetDeclContextContainingUID(GetID()); +} void Variable::CalculateSymbolContext (SymbolContext *sc) Index: test/lang/cpp/nsimport/TestCppNsImport.py =================================================================== --- test/lang/cpp/nsimport/TestCppNsImport.py +++ test/lang/cpp/nsimport/TestCppNsImport.py @@ -45,6 +45,8 @@ # Break on main function break_0 = target.BreakpointCreateBySourceRegex("// break 0", src_file_spec) self.assertTrue(break_0.IsValid() and break_0.GetNumLocations() >= 1, VALID_BREAKPOINT) + break_1 = target.BreakpointCreateBySourceRegex("// break 1", src_file_spec) + self.assertTrue(break_1.IsValid() and break_1.GetNumLocations() >= 1, VALID_BREAKPOINT) # Launch the process args = None @@ -72,6 +74,29 @@ test_result = frame.EvaluateExpression("anon") self.assertTrue(test_result.IsValid() and test_result.GetValueAsSigned() == 2, "anon = 2") + test_result = frame.EvaluateExpression("global") + self.assertTrue(test_result.IsValid() and test_result.GetValueAsSigned() == 4, "global = 4") + + test_result = frame.EvaluateExpression("fun_var") + self.assertTrue(test_result.IsValid() and test_result.GetValueAsSigned() == 9, "fun_var = 9") + + test_result = frame.EvaluateExpression("not_imported") + self.assertTrue(test_result.IsValid() and test_result.GetValueAsSigned() == 35, "not_imported = 35") + + # Continue to second breakpoint + process.Continue() + + # 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 function inside namespace + test_result = frame.EvaluateExpression("fun_var") + self.assertTrue(test_result.IsValid() and test_result.GetValueAsSigned() == 5, "fun_var = 5") + if __name__ == '__main__': import atexit Index: test/lang/cpp/nsimport/main.cpp =================================================================== --- test/lang/cpp/nsimport/main.cpp +++ test/lang/cpp/nsimport/main.cpp @@ -16,13 +16,43 @@ } } -using namespace N; -using namespace Nested; +namespace Global +{ + int global; +} + +namespace Fun +{ + int fun_var; + int fun() + { + fun_var = 5; + return 0; // break 1 + } +} + +namespace NotImportedBefore +{ + int not_imported = 45; +} + +using namespace Global; + +int not_imported = 35; +int fun_var = 9; + +namespace NotImportedAfter +{ + int not_imported = 55; +} int main() { + using namespace N; + using namespace Nested; n = 1; anon = 2; nested = 3; - return 0; // break 0 + global = 4; + return Fun::fun(); // break 0 }