teemperor created this revision.
teemperor added reviewers: aprantl, shafik.
teemperor added a project: C++ modules in LLDB.
Herald added subscribers: lldb-commits, jdoerfert, abidh, mgrang.
Herald added a project: LLDB.

This patch adds basic support for importing C++ modules in general into the 
LLDB expression evaluator. It mostly reuses
the code we already use for the std module prototype for building/importing the 
modules, but is using a different logic
for querying the modules from the executable. The current functionality is 
limited - like the first std module patch - to
only reading module information but not merging or substituting debug 
information.

Unlike the std module prototype, this feature now requires that we compile with 
`-gmodules`, as this is the only way we
have all modules (even modules that were just imported but not actually used) 
in the debug information. Without this,
we run into frequent build errors as soon as some module includes another 
module without actually using it. This leads
to the situation where Clang will not emit the module in the debug information 
(as it's unused), but LLDB will fail to
compile the C++ module as it still needs the include paths of the unused 
module. This is why we now have a
`GetAllUsedModules` that works similar to `GetImportedModules` but actually 
creates a complete list of all modules we
have used in a given compilation unit. This allows LLDB to fully reconstruct 
the original include directories.


Repository:
  rLLDB LLDB

https://reviews.llvm.org/D61606

Files:
  lldb/include/lldb/Symbol/CompileUnit.h
  lldb/include/lldb/Symbol/SourceModule.h
  lldb/include/lldb/Symbol/SymbolFile.h
  lldb/include/lldb/Symbol/SymbolVendor.h
  lldb/include/lldb/Target/Target.h
  
lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/functions/Makefile
  
lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/functions/TestFunctionImportCxxModules.py
  
lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/functions/foo.h
  
lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/functions/main.cpp
  
lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/functions/module.modulemap
  
lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/macro/Makefile
  
lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/macro/TestMacroImportCxxModules.py
  
lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/macro/foo.h
  
lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/macro/main.cpp
  
lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/macro/module.modulemap
  
lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/Makefile
  
lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/TestMultiIncDirImportCxxModules.py
  
lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/foo.h
  
lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/inc1/a.h
  
lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/inc1/module.modulemap
  
lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/inc2/b.h
  
lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/inc2/module.modulemap
  
lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/main.cpp
  
lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/multiple-include-dirs/module.modulemap
  
lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/templates/Makefile
  
lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/templates/TestTemplateImportCxxModules.py
  
lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/templates/foo.h
  
lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/templates/main.cpp
  
lldb/packages/Python/lldbsuite/test/expression_command/import-c++-modules/templates/module.modulemap
  lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
  lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
  lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
  lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
  lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h
  lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h
  lldb/source/Symbol/CompileUnit.cpp
  lldb/source/Symbol/SymbolVendor.cpp
  lldb/source/Target/Target.cpp

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(
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<SourceModule> &all_modules) {
+  ModuleSP module_sp(GetModule());
+  if (module_sp) {
+    std::lock_guard<std::recursive_mutex> 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/Symbol/CompileUnit.cpp
===================================================================
--- lldb/source/Symbol/CompileUnit.cpp
+++ lldb/source/Symbol/CompileUnit.cpp
@@ -397,6 +397,19 @@
   return m_imported_modules;
 }
 
+const std::vector<SourceModule> &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/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<lldb_private::SourceModule> &imported_modules) override;
 
+  bool ParseAllModules(
+      const lldb_private::SymbolContext &sc,
+      std::vector<lldb_private::SourceModule> &imported_modules) override {
+    return false;
+  }
+
   size_t ParseBlocksRecursive(lldb_private::Function &func) override;
 
   size_t
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<lldb_private::SourceModule> &imported_modules) override;
 
+  bool ParseAllModules(
+      const lldb_private::SymbolContext &sc,
+      std::vector<lldb_private::SourceModule> &imported_modules) override {
+    return false;
+  }
+
   size_t ParseBlocksRecursive(lldb_private::Function &func) override;
 
   size_t
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<lldb_private::SourceModule> &imported_modules) override;
 
+  bool ParseAllModules(
+      const SymbolContext &sc,
+      std::vector<lldb_private::SourceModule> &imported_modules) override {
+    return false;
+  }
+
   size_t ParseBlocksRecursive(Function &func) override;
 
   uint32_t FindGlobalVariables(ConstString name,
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<lldb_private::SourceModule> &imported_modules) override;
+  bool ParseAllModules(
+      const lldb_private::SymbolContext &sc,
+      std::vector<lldb_private::SourceModule> &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<SourceModule> &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/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<lldb_private::SourceModule> &imported_modules) override;
+  bool ParseAllModules(
+      const lldb_private::SymbolContext &sc,
+      std::vector<lldb_private::SourceModule> &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<SourceModule> &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<SourceModule> &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<SourceModule> &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<SourceModule> &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<SourceModule> &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<LineSequence> sequence_up;
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<lldb_private::SourceModule> &imported_modules) override {
+    return false;
+  }
+
   size_t ParseBlocksRecursive(Function &func) override { return 0; }
 
   uint32_t FindGlobalVariables(ConstString name,
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<SourceModule> &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<std::string> 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/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<ConstString> 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/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/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/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<typename T>
+int add(T a, T b) {
+  return a + b;
+}
+
+template<unsigned I>
+struct Foo {
+  static unsigned get() { return I; }
+};
+
+#endif
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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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<SourceModule> &imported_modules);
 
+  virtual bool ParseAllUsedModules(const SymbolContext &sc,
+                                   std::vector<SourceModule> &all_modules);
+
   virtual size_t ParseBlocksRecursive(Function &func);
 
   virtual size_t ParseVariablesForContext(const SymbolContext &sc);
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<SourceModule> &imported_modules) = 0;
+  virtual bool ParseAllModules(const SymbolContext &sc,
+                               std::vector<SourceModule> &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/SourceModule.h
===================================================================
--- lldb/include/lldb/Symbol/SourceModule.h
+++ lldb/include/lldb/Symbol/SourceModule.h
@@ -20,6 +20,18 @@
   std::vector<ConstString> 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/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<SourceModule> &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<SourceModule> &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<SourceModule> m_imported_modules;
+  /// All modules, including the current module, used directly or indirectly
+  /// by this compile unit.
+  std::vector<SourceModule> 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);
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
  • [Lldb-commits] [PATCH] D6... Raphael Isemann via Phabricator via lldb-commits

Reply via email to