Index: lldb/include/lldb/Symbol/CompileUnit.h =================================================================== --- lldb/include/lldb/Symbol/CompileUnit.h +++ lldb/include/lldb/Symbol/CompileUnit.h @@ -243,6 +243,16 @@ /// A list of imported modules. const std::vector &GetImportedModules(); + /// Get all modules used to compile this compile unit. + /// + /// This reports all modules used directly or indirectly by this compile unit. + /// For example, if this compile unit uses a module A which in turn uses a + /// module B, this function returns both A and B. + /// + /// \return + /// A list of used modules. + const std::vector &GetAllUsedModules(); + /// Get the SymbolFile plug-in user data. /// /// SymbolFile plug-ins can store user data to internal state or objects to @@ -384,6 +394,9 @@ /// All modules, including the current module, imported by this /// compile unit. std::vector m_imported_modules; + /// All modules, including the current module, used directly or indirectly + /// by this compile unit. + std::vector m_all_used_modules; /// Files associated with this compile unit's line table and /// declarations. FileSpecList m_support_files; @@ -404,14 +417,15 @@ flagsParsedVariables = (1u << 1), ///< Have we already parsed globals and statics? flagsParsedSupportFiles = (1u << 2), ///< Have we already parsed the support - ///files for this compile unit? + /// files for this compile unit? flagsParsedLineTable = (1u << 3), ///< Have we parsed the line table already? flagsParsedLanguage = (1u << 4), ///< Have we parsed the language already? flagsParsedImportedModules = (1u << 5), ///< Have we parsed the imported modules already? + flagsParsedAllModules = (1u << 6), ///< Have we parsed all modules already? flagsParsedDebugMacros = - (1u << 6) ///< Have we parsed the debug macros already? + (1u << 7) ///< Have we parsed the debug macros already? }; DISALLOW_COPY_AND_ASSIGN(CompileUnit); Index: lldb/include/lldb/Symbol/SourceModule.h =================================================================== --- lldb/include/lldb/Symbol/SourceModule.h +++ lldb/include/lldb/Symbol/SourceModule.h @@ -20,6 +20,18 @@ std::vector path; ConstString search_path; ConstString sysroot; + + /// Comparison operator for two SourceModules. Only useful for imposing a + /// total order on list of SourceModules so that they can be std::sorted. + bool operator<(const SourceModule &o) const { + return std::tie(path, search_path, sysroot) < + std::tie(o.path, o.search_path, o.sysroot); + } + + bool operator==(const SourceModule &o) const { + return std::tie(path, search_path, sysroot) == + std::tie(o.path, o.search_path, o.sysroot); + } }; } // namespace lldb_private Index: lldb/include/lldb/Symbol/SymbolFile.h =================================================================== --- lldb/include/lldb/Symbol/SymbolFile.h +++ lldb/include/lldb/Symbol/SymbolFile.h @@ -125,6 +125,9 @@ virtual bool ParseImportedModules(const SymbolContext &sc, std::vector &imported_modules) = 0; + virtual bool ParseAllModules(const SymbolContext &sc, + std::vector &all_modules) = 0; + virtual size_t ParseBlocksRecursive(Function &func) = 0; virtual size_t ParseVariablesForContext(const SymbolContext &sc) = 0; virtual Type *ResolveTypeUID(lldb::user_id_t type_uid) = 0; Index: lldb/include/lldb/Symbol/SymbolVendor.h =================================================================== --- lldb/include/lldb/Symbol/SymbolVendor.h +++ lldb/include/lldb/Symbol/SymbolVendor.h @@ -61,6 +61,9 @@ ParseImportedModules(const SymbolContext &sc, std::vector &imported_modules); + virtual bool ParseAllUsedModules(const SymbolContext &sc, + std::vector &all_modules); + virtual size_t ParseBlocksRecursive(Function &func); virtual size_t ParseVariablesForContext(const SymbolContext &sc); Index: lldb/include/lldb/Target/Target.h =================================================================== --- lldb/include/lldb/Target/Target.h +++ lldb/include/lldb/Target/Target.h @@ -131,6 +131,8 @@ bool GetEnableImportStdModule() const; + bool GetEnableImportCxxModules() const; + bool GetEnableAutoApplyFixIts() const; bool GetEnableNotifyAboutFixIts() const; Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/functions/Makefile =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/functions/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make +USE_LIBCPP := 1 +CXXFLAGS += $(MANDATORY_CXXMODULE_BUILD_CFLAGS) +CXX_SOURCES := main.cpp +include $(LEVEL)/Makefile.rules Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/functions/TestFunctionImportCxxModules.py =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/functions/TestFunctionImportCxxModules.py @@ -0,0 +1,24 @@ +""" +Test importing a C++ module and using its functions. +""" + +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class ImportCxxModuleMacros(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @add_test_categories(["gmodules"]) + def test(self): + self.build() + + lldbutil.run_to_source_breakpoint(self, + "// Set break point at this line.", lldb.SBFileSpec("main.cpp")) + + # Activate importing of std module. + self.runCmd("settings set target.import-c++-modules true") + # Call our functions. + self.expect("expr add(2, 3)", substrs=['(int)', '= 5']) Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/functions/foo.h =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/functions/foo.h @@ -0,0 +1,8 @@ +#ifndef FOO_H +#define FOO_H + +int add(int a, int b) { + return a + b; +} + +#endif Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/functions/main.cpp =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/functions/main.cpp @@ -0,0 +1,6 @@ +#include "foo.h" + +int main(int argc, char **argv) { + // Set break point at this line. + return 0; +} Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/functions/module.modulemap =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/functions/module.modulemap @@ -0,0 +1 @@ +module Foo { header "foo.h" export * } Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/macro/Makefile =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/macro/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make +USE_LIBCPP := 1 +CXXFLAGS += $(MANDATORY_CXXMODULE_BUILD_CFLAGS) +CXX_SOURCES := main.cpp +include $(LEVEL)/Makefile.rules Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/macro/TestMacroImportCxxModules.py =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/macro/TestMacroImportCxxModules.py @@ -0,0 +1,32 @@ +""" +Test importing a C++ module and using its macros. +""" + +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class ImportCxxModuleMacros(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @add_test_categories(["gmodules"]) + # As ASTReader's generations are currently out of sync when + # multiplexing ExternalASTSources (which is what we do in LLDB), + # this test currently fails. + @expectedFailureAll(bugnumber="reviews.llvm.org/D39714") + def test(self): + self.build() + + lldbutil.run_to_source_breakpoint(self, + "// Set break point at this line.", lldb.SBFileSpec("main.cpp")) + + # Activate importing of std module. + self.runCmd("settings set target.import-c++-modules true") + # Call our macro. + self.expect("expr my_abs(-42)", substrs=['(int) $0 = 42']) + # Call it again. The first macro may be defined from the module built + # process, but the second time we are reusing an on-disk module where + # we fail due to out of sync ASTReader generation. + self.expect("expr my_abs(-42)", substrs=['(int) $0 = 42']) Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/macro/foo.h =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/macro/foo.h @@ -0,0 +1,6 @@ +#ifndef FOO_H +#define FOO_H + +#define my_abs(x) (x)<0?-(x):(x) + +#endif Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/macro/main.cpp =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/macro/main.cpp @@ -0,0 +1,6 @@ +#include "foo.h" + +int main(int argc, char **argv) { + // Set break point at this line. + return 0; +} Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/macro/module.modulemap =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/macro/module.modulemap @@ -0,0 +1 @@ +module Foo { header "foo.h" export * } Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/Makefile =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make +USE_LIBCPP := 1 +CXXFLAGS += $(MANDATORY_CXXMODULE_BUILD_CFLAGS) -I $(SRCDIR)/inc1 -I $(SRCDIR)/inc2 +CXX_SOURCES := main.cpp +include $(LEVEL)/Makefile.rules Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/TestMultiIncDirImportCxxModules.py =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/TestMultiIncDirImportCxxModules.py @@ -0,0 +1,25 @@ +""" +Test importing a C++ module with multiple include directories. +""" + +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class ImportCxxModuleMacros(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @add_test_categories(["gmodules"]) + def test(self): + self.build() + + lldbutil.run_to_source_breakpoint(self, + "// Set break point at this line.", lldb.SBFileSpec("main.cpp")) + + # Activate importing of std module. + self.runCmd("settings set target.import-c++-modules true") + self.runCmd("log enable lldb expr") + # Call our function in the nested module. + self.expect("expr foo()", substrs=['(int)', '= 33']) Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/foo.h =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/foo.h @@ -0,0 +1,4 @@ +#ifndef FOO_H +#define FOO_H +#include "a.h" +#endif Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/inc1/a.h =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/inc1/a.h @@ -0,0 +1,4 @@ +#ifndef A_H +#define A_H +#include "b.h" +#endif Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/inc1/module.modulemap =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/inc1/module.modulemap @@ -0,0 +1 @@ +module Inc1 { header "a.h" export * } Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/inc2/b.h =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/inc2/b.h @@ -0,0 +1,4 @@ +#ifndef B_H +#define B_H +int foo() { return 33; } +#endif Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/inc2/module.modulemap =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/inc2/module.modulemap @@ -0,0 +1 @@ +module Inc2 { header "b.h" export * } Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/main.cpp =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/main.cpp @@ -0,0 +1,6 @@ +#include "foo.h" + +int main(int argc, char **argv) { + // Set break point at this line. + return 0; +} Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/module.modulemap =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/module.modulemap @@ -0,0 +1 @@ +module Foo { header "foo.h" export * } Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/templates/Makefile =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/templates/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make +USE_LIBCPP := 1 +CXXFLAGS += $(MANDATORY_CXXMODULE_BUILD_CFLAGS) +CXX_SOURCES := main.cpp +include $(LEVEL)/Makefile.rules Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/templates/TestTemplateImportCxxModules.py =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/templates/TestTemplateImportCxxModules.py @@ -0,0 +1,25 @@ +""" +Test importing a C++ module and using its templates. +""" + +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class ImportCxxModuleMacros(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @add_test_categories(["gmodules"]) + def test(self): + self.build() + + lldbutil.run_to_source_breakpoint(self, + "// Set break point at this line.", lldb.SBFileSpec("main.cpp")) + + # Activate importing of std module. + self.runCmd("settings set target.import-c++-modules true") + # Call our template functions. + self.expect("expr add(2, 3)", substrs=['(int) $0 = 5']) + self.expect("expr Foo<42>::get()", substrs=['(unsigned int)', '= 42']) Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/templates/foo.h =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/templates/foo.h @@ -0,0 +1,14 @@ +#ifndef FOO_H +#define FOO_H + +template +int add(T a, T b) { + return a + b; +} + +template +struct Foo { + static unsigned get() { return I; } +}; + +#endif Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/templates/main.cpp =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/templates/main.cpp @@ -0,0 +1,6 @@ +#include "foo.h" + +int main(int argc, char **argv) { + // Set break point at this line. + return 0; +} Index: lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/templates/module.modulemap =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/templates/module.modulemap @@ -0,0 +1 @@ +module Foo { header "foo.h" export * } Index: lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp =================================================================== --- lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp +++ lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp @@ -220,8 +220,10 @@ HeaderSearchOptions &search_opts = compiler->getHeaderSearchOpts(); + std::set added_inc_dirs; for (ConstString dir : include_directories) { - search_opts.AddPath(dir.AsCString(), frontend::System, false, true); + search_opts.AddPath(dir.AsCString(), frontend::IncludeDirGroup::Angled, + false, true); LLDB_LOG(log, "Added user include dir: {0}", dir); } Index: lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp =================================================================== --- lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp +++ lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp @@ -445,7 +445,11 @@ return {}; Target *target = exe_ctx.GetTargetPtr(); - if (!target || !target->GetEnableImportStdModule()) + if (!target) + return {}; + + if (!target->GetEnableImportStdModule() && + !target->GetEnableImportCxxModules()) return {}; StackFrame *frame = exe_ctx.GetFramePtr(); @@ -461,24 +465,47 @@ if (!sc.comp_unit) return {}; + // Get the list of modules we need to to import. For the `std` module it's + // enough to search the list of directly imported modules, but for a general + // module import we need to get all used modules to reconstruct the relevant + // include directories. + const std::vector &module_list = + target->GetEnableImportCxxModules() ? sc.comp_unit->GetAllUsedModules() + : sc.comp_unit->GetImportedModules(); + if (log) { - for (const SourceModule &m : sc.comp_unit->GetImportedModules()) { + for (const SourceModule &m : module_list) { LLDB_LOG(log, "Found module in compile unit: {0:$[.]} - include dir: {1}", llvm::make_range(m.path.begin(), m.path.end()), m.search_path); } } - for (const SourceModule &m : sc.comp_unit->GetImportedModules()) - m_include_directories.push_back(m.search_path); + // Build a list of include directories used by these modules. + for (const SourceModule &m : module_list) { + if (!m.search_path.IsEmpty()) + m_include_directories.push_back(m.search_path); + } + + // If we only need the `std` module we can just iterate the list and check + // if `std` or any of its submodule was imported. + if (target->GetEnableImportStdModule()) { + // Check if we imported 'std' or any of its submodules. + for (const SourceModule &m : module_list) + if (!m.path.empty() && m.path.front() == "std") + return {"std"}; + return {}; + } - // Check if we imported 'std' or any of its submodules. - // We currently don't support importing any other modules in the expression - // parser. - for (const SourceModule &m : sc.comp_unit->GetImportedModules()) - if (!m.path.empty() && m.path.front() == "std") - return {"std"}; + // If we want to import all C++ modules we have to + assert(target->GetEnableImportCxxModules()); + std::vector result; + for (const SourceModule &m : module_list) + result.push_back(m.path.front().GetCString()); - return {}; + // Filter out any duplicates as importing a module once is enough. + std::sort(result.begin(), result.end()); + result.erase(std::unique(result.begin(), result.end()), result.end()); + return result; } bool ClangUserExpression::PrepareForParsing( Index: lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h =================================================================== --- lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h +++ lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h @@ -69,6 +69,12 @@ return false; } + bool ParseAllModules( + const SymbolContext &sc, + std::vector &imported_modules) override { + return false; + } + size_t ParseBlocksRecursive(Function &func) override { return 0; } uint32_t FindGlobalVariables(ConstString name, Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -117,6 +117,9 @@ bool ParseImportedModules( const lldb_private::SymbolContext &sc, std::vector &imported_modules) override; + bool ParseAllModules( + const lldb_private::SymbolContext &sc, + std::vector &imported_modules) override; size_t ParseBlocksRecursive(lldb_private::Function &func) override; Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -896,36 +896,46 @@ return false; } -bool SymbolFileDWARF::ParseImportedModules( - const lldb_private::SymbolContext &sc, - std::vector &imported_modules) { - ASSERT_MODULE_LOCK(this); - assert(sc.comp_unit); - DWARFUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); - if (!dwarf_cu) - return false; - if (!ClangModulesDeclVendor::LanguageSupportsClangModules( - sc.comp_unit->GetLanguage())) - return false; - UpdateExternalModuleListIfNeeded(); - +/// Parses the modules in the given DWARFUnit. +/// \param dwarf_cu The DWARFUnit that should be searched for modules. +/// \param only_imported_modules True if only modules that are imported should +/// be parsed. False if all modules should be +/// parsed. +/// \param modules A list of SourceModules found in the DWARFUnit. +/// \return True iff no error occurred while parsing the modules. +static bool ParseModules(DWARFUnit *dwarf_cu, bool only_imported_modules, + std::vector &modules) { const DWARFDIE die = dwarf_cu->DIE(); if (!die) return false; for (DWARFDIE child_die = die.GetFirstChild(); child_die; child_die = child_die.GetSibling()) { - if (child_die.Tag() != DW_TAG_imported_declaration) - continue; + DWARFDIE module_die; + + if (only_imported_modules) { + if (child_die.Tag() != DW_TAG_imported_declaration) + continue; + + module_die = child_die.GetReferencedDIE(DW_AT_import); + } else + module_die = child_die; - DWARFDIE module_die = child_die.GetReferencedDIE(DW_AT_import); if (module_die.Tag() != DW_TAG_module) continue; - if (const char *name = + if (const char *name_str = module_die.GetAttributeValueAsString(DW_AT_name, nullptr)) { + + ConstString name(name_str); + + // Clang emits some modulemap files as module tags, so we have to + // filter them out here as they are not actual SourceModules. + if (name == "module.modulemap") + continue; + SourceModule module; - module.path.push_back(ConstString(name)); + module.path.push_back(name); DWARFDIE parent_die = module_die; while ((parent_die = parent_die.GetParent())) { @@ -942,12 +952,59 @@ if (const char *sysroot = module_die.GetAttributeValueAsString( DW_AT_LLVM_isysroot, nullptr)) module.sysroot = ConstString(sysroot); - imported_modules.push_back(module); + modules.push_back(module); } } return true; } +bool SymbolFileDWARF::ParseImportedModules( + const lldb_private::SymbolContext &sc, + std::vector &imported_modules) { + ASSERT_MODULE_LOCK(this); + assert(sc.comp_unit); + + DWARFUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); + if (!dwarf_cu) + return false; + if (!ClangModulesDeclVendor::LanguageSupportsClangModules( + sc.comp_unit->GetLanguage())) + return false; + UpdateExternalModuleListIfNeeded(); + + return ParseModules(dwarf_cu, /*only_imported*/ true, imported_modules); +} + +bool SymbolFileDWARF::ParseAllModules(const lldb_private::SymbolContext &sc, + std::vector &all_modules) { + ASSERT_MODULE_LOCK(this); + assert(sc.comp_unit); + DWARFUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); + if (!dwarf_cu) + return false; + if (!ClangModulesDeclVendor::LanguageSupportsClangModules( + sc.comp_unit->GetLanguage())) + return false; + UpdateExternalModuleListIfNeeded(); + + // Recursively descend into the referenced modules and add their used + // modules to our list. + for (auto &n : m_external_type_modules) { + ModuleSP module = n.second; + + // The first compile unit should contain all used modules. + if (module->GetNumCompileUnits() == 0) + continue; + CompUnitSP comp_unit = module->GetCompileUnitAtIndex(0); + + const std::vector &m = comp_unit->GetAllUsedModules(); + all_modules.insert(all_modules.end(), m.begin(), m.end()); + } + + // Parse all used modules in the current compile unit. + return ParseModules(dwarf_cu, /*only_imported*/ false, all_modules); +} + struct ParseDWARFLineTableCallbackInfo { LineTable *line_table; std::unique_ptr sequence_up; Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h +++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h @@ -66,6 +66,9 @@ bool ParseImportedModules( const lldb_private::SymbolContext &sc, std::vector &imported_modules) override; + bool ParseAllModules( + const lldb_private::SymbolContext &sc, + std::vector &imported_modules) override; size_t ParseBlocksRecursive(lldb_private::Function &func) override; size_t ParseVariablesForContext(const lldb_private::SymbolContext &sc) override; Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp +++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp @@ -675,6 +675,14 @@ return false; } +bool SymbolFileDWARFDebugMap::ParseAllModules( + const SymbolContext &sc, std::vector &imported_modules) { + SymbolFileDWARF *oso_dwarf = GetSymbolFile(sc); + if (oso_dwarf) + return oso_dwarf->ParseAllModules(sc, imported_modules); + return false; +} + size_t SymbolFileDWARFDebugMap::ParseBlocksRecursive(Function &func) { CompileUnit *comp_unit = func.GetCompileUnit(); if (!comp_unit) Index: lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h =================================================================== --- lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h +++ lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h @@ -92,6 +92,12 @@ const SymbolContext &sc, std::vector &imported_modules) override; + bool ParseAllModules( + const SymbolContext &sc, + std::vector &imported_modules) override { + return false; + } + size_t ParseBlocksRecursive(Function &func) override; uint32_t FindGlobalVariables(ConstString name, Index: lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h =================================================================== --- lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h +++ lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h @@ -70,6 +70,12 @@ const lldb_private::SymbolContext &sc, std::vector &imported_modules) override; + bool ParseAllModules( + const lldb_private::SymbolContext &sc, + std::vector &imported_modules) override { + return false; + } + size_t ParseBlocksRecursive(lldb_private::Function &func) override; size_t Index: lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h =================================================================== --- lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h +++ lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h @@ -59,6 +59,12 @@ const lldb_private::SymbolContext &sc, std::vector &imported_modules) override; + bool ParseAllModules( + const lldb_private::SymbolContext &sc, + std::vector &imported_modules) override { + return false; + } + size_t ParseBlocksRecursive(lldb_private::Function &func) override; size_t Index: lldb/source/Symbol/CompileUnit.cpp =================================================================== --- lldb/source/Symbol/CompileUnit.cpp +++ lldb/source/Symbol/CompileUnit.cpp @@ -397,6 +397,19 @@ return m_imported_modules; } +const std::vector &CompileUnit::GetAllUsedModules() { + if (m_all_used_modules.empty() && m_flags.IsClear(flagsParsedAllModules)) { + m_flags.Set(flagsParsedAllModules); + if (SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor()) { + SymbolContext sc; + CalculateSymbolContext(&sc); + + symbol_vendor->ParseAllUsedModules(sc, m_all_used_modules); + } + } + return m_all_used_modules; +} + FileSpecList &CompileUnit::GetSupportFiles() { if (m_support_files.GetSize() == 0) { if (m_flags.IsClear(flagsParsedSupportFiles)) { Index: lldb/source/Symbol/SymbolVendor.cpp =================================================================== --- lldb/source/Symbol/SymbolVendor.cpp +++ lldb/source/Symbol/SymbolVendor.cpp @@ -187,6 +187,17 @@ return false; } +bool SymbolVendor::ParseAllUsedModules(const SymbolContext &sc, + std::vector &all_modules) { + ModuleSP module_sp(GetModule()); + if (module_sp) { + std::lock_guard guard(module_sp->GetMutex()); + if (m_sym_file_up) + return m_sym_file_up->ParseAllModules(sc, all_modules); + } + return false; +} + size_t SymbolVendor::ParseBlocksRecursive(Function &func) { ModuleSP module_sp(GetModule()); if (module_sp) { Index: lldb/source/Target/Target.cpp =================================================================== --- lldb/source/Target/Target.cpp +++ lldb/source/Target/Target.cpp @@ -3339,6 +3339,9 @@ {"import-std-module", OptionValue::eTypeBoolean, false, false, nullptr, {}, "Import the C++ std module to improve debugging STL containers."}, + {"import-c++-modules", OptionValue::eTypeBoolean, false, false, + nullptr, {}, + "Import the executable's C++ modules to improve debugging."}, {"auto-apply-fixits", OptionValue::eTypeBoolean, false, true, nullptr, {}, "Automatically apply fix-it hints to expressions."}, {"notify-about-fixits", OptionValue::eTypeBoolean, false, true, nullptr, @@ -3478,6 +3481,7 @@ ePropertyClangModuleSearchPaths, ePropertyAutoImportClangModules, ePropertyImportStdModule, + ePropertyImportCxxModules, ePropertyAutoApplyFixIts, ePropertyNotifyAboutFixIts, ePropertySaveObjects, @@ -3911,6 +3915,12 @@ nullptr, idx, g_properties[idx].default_uint_value != 0); } +bool TargetProperties::GetEnableImportCxxModules() const { + const uint32_t idx = ePropertyImportCxxModules; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_properties[idx].default_uint_value != 0); +} + bool TargetProperties::GetEnableAutoApplyFixIts() const { const uint32_t idx = ePropertyAutoApplyFixIts; return m_collection_sp->GetPropertyAtIndexAsBoolean(