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 { @@ -1075,6 +1079,96 @@ 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::UsingDecl * + CreateUsingDeclaration (clang::DeclContext *current_decl_ctx, clang::NamedDecl *target) + { + if (current_decl_ctx != nullptr && target != nullptr) + { + clang::UsingDecl *using_decl = clang::UsingDecl::Create(*getASTContext(), + current_decl_ctx, + clang::SourceLocation(), + clang::NestedNameSpecifierLoc(), + clang::DeclarationNameInfo(), + false); + clang::UsingShadowDecl *shadow_decl = clang::UsingShadowDecl::Create(*getASTContext(), + current_decl_ctx, + clang::SourceLocation(), + using_decl, + target); + using_decl->addShadowDecl(shadow_decl); + current_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) @@ -1114,6 +1208,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 @@ -1035,6 +1035,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"); @@ -1046,7 +1049,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(); @@ -1352,24 +1354,80 @@ if (frame && !namespace_decl) { - valobj = frame->GetValueForVariableExpressionPath(name_unique_cstr, - eNoDynamicValues, - StackFrame::eExpressionPathOptionCheckPtrVsMember | - StackFrame::eExpressionPathOptionsNoFragileObjcIvar | - StackFrame::eExpressionPathOptionsNoSyntheticChildren | - StackFrame::eExpressionPathOptionsNoSyntheticArrayRange, - var, - err); - - // If we found a variable in scope, no need to pull up function names - if (err.Success() && var) + 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()) { - AddOneVariable(context, var, valobj, current_id); - context.m_found.variable = true; - return; + 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())); + } + else if (clang::UsingDecl *ud = llvm::dyn_cast(child)) + { + for (clang::UsingShadowDecl *usd : ud->shadows()) + { + clang::Decl *target = usd->getTargetDecl(); + if (clang::VarDecl *vd = llvm::dyn_cast(target)) + if (ast_context->GetVariableFromDecl(vd) && vd->getName().equals(name_unique_cstr)) + found_vars.push_back(vd); + } + } + } + + 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 (target) { var = FindGlobalVariable (*target, Index: source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -3196,7 +3196,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 @@ -400,6 +400,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 @@ -1326,6 +1326,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()) @@ -3697,6 +3708,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; } @@ -3704,6 +3718,69 @@ 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(DIERef(imported_uid)); + TypeSystem *type_system = GetTypeSystemForLanguage(die.GetCU()->GetLanguageType()); + if (type_system) + { + DWARFASTParser *dwarf_ast = type_system->GetDWARFParser(); + if (dwarf_ast != nullptr) + { + sc.comp_unit->GetVariableList(true); + clang::DeclContext *context = nullptr; + if (sc.block != nullptr) + context = ClangASTContext::DeclContextGetAsDeclContext(sc.block->GetClangDecl()); + else + context = GetClangASTContext().GetTranslationUnitDecl(GetClangASTContext().getASTContext()); + + if (context != nullptr) + { + if (die.Tag() == DW_TAG_imported_module) + { + CompilerDeclContext ns_decl_context = dwarf_ast->GetDeclContextForUIDFromDWARF(imported_die); + if (clang::NamespaceDecl *ns_decl = ClangASTContext::DeclContextGetAsNamespaceDecl(ns_decl_context)) + GetClangASTContext().CreateUsingDirectiveDeclaration(context, ns_decl); + } + else if (die.Tag() == DW_TAG_imported_declaration) + { + // TODO: handle imported declarations (using Namespace::Symbol) for other tags + if (imported_die.Tag() == DW_TAG_variable) + { + VariableSP var = ParseVariableDIE(sc, imported_die, func_low_pc); + if (var) + { + CompilerDeclContext clang_var_decl = var->GetVarDecl(); + if (clang_var_decl) + { + clang::VarDecl *var_decl = (clang::VarDecl *)clang_var_decl.GetOpaqueDeclContext(); + GetClangASTContext().CreateUsingDeclaration(context, var_decl); + } + } + } + } + } + } + } + } + } +} + VariableSP SymbolFileDWARF::ParseVariableDIE ( @@ -3732,6 +3809,7 @@ { DWARFAttributes attributes; const size_t num_attributes = die.GetAttributes(attributes); + DWARFDIE spec_die; if (num_attributes > 0) { const char *name = NULL; @@ -3853,7 +3931,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(DIERef(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: @@ -3865,7 +3953,6 @@ default: case DW_AT_abstract_origin: case DW_AT_sibling: - case DW_AT_specification: break; } } @@ -3873,7 +3960,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; @@ -4069,6 +4156,22 @@ // (missing location due to optimization, etc)) so we don't re-parse // this DIE over and over later... GetDIEToVariable()[die.GetDIE()] = var_sp; + if (spec_die) + GetDIEToVariable()[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; } @@ -4232,6 +4335,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,32 @@ 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") + + test_result = frame.EvaluateExpression("single") + self.assertTrue(test_result.IsValid() and test_result.GetValueAsSigned() == 3, "single = 3") + + # 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,49 @@ } } -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 Single +{ + int single = 3; +} + +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; + using Single::single; n = 1; anon = 2; nested = 3; - return 0; // break 0 + global = 4; + return Fun::fun(); // break 0 }