[Lldb-commits] [lldb] [DRAFT] Add support for inline DWARF source files. (PR #75880)

Adrian Prantl via lldb-commits lldb-commits at lists.llvm.org
Wed Jan 3 14:30:23 PST 2024


https://github.com/adrian-prantl updated https://github.com/llvm/llvm-project/pull/75880

>From e089e1d67c01a42da16b7544abf8c4935cde4aed Mon Sep 17 00:00:00 2001
From: Adrian Prantl <aprantl at apple.com>
Date: Mon, 18 Dec 2023 15:59:00 -0800
Subject: [PATCH 1/3] Add support for inline DWARF source files.

LLVM supports DWARF 5 linetable extension to store source files inline
in DWARF. This is particularly useful for compiler-generated source
code. This implementation tries to materialize them as temporary files
lazily, so SBAPI clients don't need to be aware of them.
---
 lldb/include/lldb/Utility/FileSpecList.h      | 45 +++++++++++++++---
 lldb/source/Core/ModuleList.cpp               |  8 ++--
 .../Clang/ClangUserExpression.cpp             | 12 ++---
 .../Clang/CppModuleConfiguration.cpp          |  6 +--
 .../SymbolFile/DWARF/SymbolFileDWARF.cpp      | 47 +++++++++++++++++++
 lldb/source/Utility/FileSpecList.cpp          | 21 +++++----
 .../inline-sourcefile/Makefile                | 11 +++++
 .../TestInlineSourceFiles.py                  | 17 +++++++
 .../inline-sourcefile/inline.ll               | 39 +++++++++++++++
 .../functionalities/inline-sourcefile/main.c  |  7 +++
 10 files changed, 186 insertions(+), 27 deletions(-)
 create mode 100644 lldb/test/API/functionalities/inline-sourcefile/Makefile
 create mode 100644 lldb/test/API/functionalities/inline-sourcefile/TestInlineSourceFiles.py
 create mode 100644 lldb/test/API/functionalities/inline-sourcefile/inline.ll
 create mode 100644 lldb/test/API/functionalities/inline-sourcefile/main.c

diff --git a/lldb/include/lldb/Utility/FileSpecList.h b/lldb/include/lldb/Utility/FileSpecList.h
index 77587aa917916b..8eda721b607fd6 100644
--- a/lldb/include/lldb/Utility/FileSpecList.h
+++ b/lldb/include/lldb/Utility/FileSpecList.h
@@ -17,13 +17,41 @@
 namespace lldb_private {
 class Stream;
 
+/// Represents a source file whose contents is known (for example
+/// because it can be reconstructed from debug info), but that
+/// hasn't been written to a local disk yet.
+struct LazyFileSpec {
+  virtual ~LazyFileSpec() {}
+  virtual const FileSpec &Materialize() = 0;
+};
+
+/// Wraps either a FileSpec that represents a local file or a
+/// LazyFileSpec that could be materialized into a local file.
+class FileSpecHolder {
+  FileSpec m_file_spec;
+  std::shared_ptr<LazyFileSpec> m_lazy;
+
+public:
+  FileSpecHolder(const FileSpec &spec, std::shared_ptr<LazyFileSpec> lazy = {})
+      : m_file_spec(spec), m_lazy(lazy) {}
+  FileSpecHolder(const FileSpecHolder &other) = default;
+  FileSpecHolder(FileSpecHolder &&other) = default;
+  FileSpecHolder &operator=(const FileSpecHolder &other) = default;
+  const FileSpec &GetSpecOnly() const { return m_file_spec; };
+  const FileSpec &Materialize() const {
+    if (m_lazy)
+      return m_lazy->Materialize();
+    return m_file_spec;
+  }
+};
+
 /// \class FileSpecList FileSpecList.h "lldb/Utility/FileSpecList.h"
 /// A file collection class.
 ///
 /// A class that contains a mutable list of FileSpec objects.
 class FileSpecList {
 public:
-  typedef std::vector<FileSpec> collection;
+  typedef std::vector<FileSpecHolder> collection;
   typedef collection::const_iterator const_iterator;
 
   /// Default constructor.
@@ -38,7 +66,10 @@ class FileSpecList {
   FileSpecList(FileSpecList &&rhs) = default;
 
   /// Initialize this object from a vector of FileSpecs
-  FileSpecList(std::vector<FileSpec> &&rhs) : m_files(std::move(rhs)) {}
+  FileSpecList(std::vector<FileSpec> &&rhs) {
+    for (auto &fs : rhs)
+      m_files.emplace_back(fs);
+  }
 
   /// Destructor.
   ~FileSpecList();
@@ -83,9 +114,11 @@ class FileSpecList {
   /// \param[in] args
   ///     Arguments to create the FileSpec
   template <class... Args> void EmplaceBack(Args &&...args) {
-    m_files.emplace_back(std::forward<Args>(args)...);
+    m_files.emplace_back(FileSpec(std::forward<Args>(args)...));
   }
 
+  void Append(FileSpecHolder &&fsh) { m_files.push_back(std::move(fsh)); }
+
   /// Clears the file list.
   void Clear();
 
@@ -175,10 +208,10 @@ class FileSpecList {
 
   bool Insert(size_t idx, const FileSpec &file) {
     if (idx < m_files.size()) {
-      m_files.insert(m_files.begin() + idx, file);
+      m_files.insert(m_files.begin() + idx, FileSpecHolder(file));
       return true;
     } else if (idx == m_files.size()) {
-      m_files.push_back(file);
+      m_files.push_back(FileSpecHolder(file));
       return true;
     }
     return false;
@@ -186,7 +219,7 @@ class FileSpecList {
 
   bool Replace(size_t idx, const FileSpec &file) {
     if (idx < m_files.size()) {
-      m_files[idx] = file;
+      m_files[idx] = FileSpecHolder(file);
       return true;
     }
     return false;
diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp
index aa89c93c8d0521..3b6c3ea899caf7 100644
--- a/lldb/source/Core/ModuleList.cpp
+++ b/lldb/source/Core/ModuleList.cpp
@@ -164,11 +164,13 @@ void ModuleListProperties::UpdateSymlinkMappings() {
   llvm::sys::ScopedWriter lock(m_symlink_paths_mutex);
   const bool notify = false;
   m_symlink_paths.Clear(notify);
-  for (FileSpec symlink : list) {
+  for (auto symlink : list) {
     FileSpec resolved;
-    Status status = FileSystem::Instance().Readlink(symlink, resolved);
+    Status status =
+        FileSystem::Instance().Readlink(symlink.Materialize(), resolved);
     if (status.Success())
-      m_symlink_paths.Append(symlink.GetPath(), resolved.GetPath(), notify);
+      m_symlink_paths.Append(symlink.Materialize().GetPath(),
+                             resolved.GetPath(), notify);
   }
 }
 
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
index 68bdd96e8adb03..ec03a38752c2fe 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
@@ -488,8 +488,8 @@ CppModuleConfiguration GetModuleConfig(lldb::LanguageType language,
 
   // Build a list of files we need to analyze to build the configuration.
   FileSpecList files;
-  for (const FileSpec &f : sc.comp_unit->GetSupportFiles())
-    files.AppendIfUnique(f);
+  for (auto &f : sc.comp_unit->GetSupportFiles())
+    files.AppendIfUnique(f.Materialize());
   // We also need to look at external modules in the case of -gmodules as they
   // contain the support files for libc++ and the C library.
   llvm::DenseSet<SymbolFile *> visited_symbol_files;
@@ -498,8 +498,8 @@ CppModuleConfiguration GetModuleConfig(lldb::LanguageType language,
         for (std::size_t i = 0; i < module.GetNumCompileUnits(); ++i) {
           const FileSpecList &support_files =
               module.GetCompileUnitAtIndex(i)->GetSupportFiles();
-          for (const FileSpec &f : support_files) {
-            files.AppendIfUnique(f);
+          for (auto &f : support_files) {
+            files.AppendIfUnique(f.Materialize());
           }
         }
         return false;
@@ -508,9 +508,9 @@ CppModuleConfiguration GetModuleConfig(lldb::LanguageType language,
   LLDB_LOG(log, "[C++ module config] Found {0} support files to analyze",
            files.GetSize());
   if (log && log->GetVerbose()) {
-    for (const FileSpec &f : files)
+    for (auto &f : files)
       LLDB_LOGV(log, "[C++ module config] Analyzing support file: {0}",
-                f.GetPath());
+                f.Materialize().GetPath());
   }
 
   // Try to create a configuration from the files. If there is no valid
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp b/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp
index 62443d1290dc72..0cd52db97521a1 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp
@@ -134,9 +134,9 @@ bool CppModuleConfiguration::hasValidConfig() {
 CppModuleConfiguration::CppModuleConfiguration(
     const FileSpecList &support_files, const llvm::Triple &triple) {
   // Analyze all files we were given to build the configuration.
-  bool error = !llvm::all_of(support_files,
-                             std::bind(&CppModuleConfiguration::analyzeFile,
-                                       this, std::placeholders::_1, triple));
+  bool error = !llvm::all_of(support_files, [&](auto &file) {
+    return CppModuleConfiguration::analyzeFile(file.Materialize(), triple);
+  });
   // If we have a valid configuration at this point, set the
   // include directories and module list that should be used.
   if (!error && hasValidConfig()) {
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index 505ea29ca4d4f5..52caa5885baac2 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -10,6 +10,7 @@
 
 #include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
 #include "llvm/Support/Casting.h"
+#include "llvm/Support/FileUtilities.h"
 #include "llvm/Support/Format.h"
 #include "llvm/Support/Threading.h"
 
@@ -235,6 +236,52 @@ ParseSupportFilesFromPrologue(const lldb::ModuleSP &module,
   for (size_t idx = first_file_idx; idx <= last_file_idx; ++idx) {
     std::string remapped_file;
     if (auto file_path = GetFileByIndex(prologue, idx, compile_dir, style)) {
+      auto entry = prologue.getFileNameEntry(idx);
+      auto source = entry.Source.getAsCString();
+      if (!source)
+        consumeError(source.takeError());
+      else {
+        llvm::StringRef source_ref(*source);
+        if (!source_ref.empty()) {
+          /// Wrap a path for an in-DWARF source file. Lazily write it
+          /// to disk when Materialize() is called.
+          struct LazyDWARFFile : public LazyFileSpec {
+            LazyDWARFFile(std::string file_name, llvm::StringRef source,
+                          FileSpec::Style style)
+                : file_name(file_name), source(source), style(style) {}
+            std::string file_name;
+            FileSpec tmp_file;
+            llvm::StringRef source;
+            std::unique_ptr<llvm::FileRemover> remover;
+            FileSpec::Style style;
+
+            /// Write the file contents to a temporary file.
+            const FileSpec &Materialize() override {
+              if (tmp_file)
+                return tmp_file;
+              llvm::SmallString<0> name;
+              int fd;
+              auto ec = llvm::sys::fs::createTemporaryFile(
+                  "", llvm::sys::path::filename(file_name, style), fd, name);
+              if (ec || fd <= 0) {
+                LLDB_LOG(GetLog(DWARFLog::DebugInfo),
+                         "Could not create temporary file");
+                return tmp_file;
+              }
+              remover = std::make_unique<llvm::FileRemover>(name);
+              NativeFile file(fd, File::eOpenOptionWriteOnly, true);
+              size_t num_bytes = source.size();
+              file.Write(source.data(), num_bytes);
+              tmp_file.SetPath(name);
+              return tmp_file;
+            }
+          };
+          support_files.Append(FileSpecHolder(
+              FileSpec(*file_path),
+              std::make_shared<LazyDWARFFile>(*file_path, *source, style)));
+          continue;
+        }
+      }
       if (auto remapped = module->RemapSourceFile(llvm::StringRef(*file_path)))
         remapped_file = *remapped;
       else
diff --git a/lldb/source/Utility/FileSpecList.cpp b/lldb/source/Utility/FileSpecList.cpp
index e3d8ea650c75dc..c2ebbfd5ec854f 100644
--- a/lldb/source/Utility/FileSpecList.cpp
+++ b/lldb/source/Utility/FileSpecList.cpp
@@ -30,7 +30,9 @@ void FileSpecList::Append(const FileSpec &file_spec) {
 // a copy of "file_spec".
 bool FileSpecList::AppendIfUnique(const FileSpec &file_spec) {
   collection::iterator end = m_files.end();
-  if (find(m_files.begin(), end, file_spec) == end) {
+  if (find_if(m_files.begin(), end, [&](auto &holder) {
+        return holder.GetSpecOnly() == file_spec;
+      }) == end) {
     m_files.push_back(file_spec);
     return true;
   }
@@ -44,7 +46,7 @@ void FileSpecList::Clear() { m_files.clear(); }
 void FileSpecList::Dump(Stream *s, const char *separator_cstr) const {
   collection::const_iterator pos, end = m_files.end();
   for (pos = m_files.begin(); pos != end; ++pos) {
-    pos->Dump(s->AsRawOstream());
+    pos->GetSpecOnly().Dump(s->AsRawOstream());
     if (separator_cstr && ((pos + 1) != end))
       s->PutCString(separator_cstr);
   }
@@ -64,13 +66,14 @@ size_t FileSpecList::FindFileIndex(size_t start_idx, const FileSpec &file_spec,
   bool compare_filename_only = file_spec.GetDirectory().IsEmpty();
 
   for (size_t idx = start_idx; idx < num_files; ++idx) {
+    auto f = m_files[idx].GetSpecOnly();
     if (compare_filename_only) {
-      if (ConstString::Equals(
-              m_files[idx].GetFilename(), file_spec.GetFilename(),
-              file_spec.IsCaseSensitive() || m_files[idx].IsCaseSensitive()))
+      if (ConstString::Equals(f.GetFilename(), file_spec.GetFilename(),
+                              file_spec.IsCaseSensitive() ||
+                                  f.IsCaseSensitive()))
         return idx;
     } else {
-      if (FileSpec::Equal(m_files[idx], file_spec, full))
+      if (FileSpec::Equal(f, file_spec, full))
         return idx;
     }
   }
@@ -92,7 +95,7 @@ size_t FileSpecList::FindCompatibleIndex(size_t start_idx,
   const bool full = !file_spec.GetDirectory().IsEmpty();
 
   for (size_t idx = start_idx; idx < num_files; ++idx) {
-    const FileSpec &curr_file = m_files[idx];
+    const FileSpec &curr_file = m_files[idx].GetSpecOnly();
 
     // Always start by matching the filename first
     if (!curr_file.FileEquals(file_spec))
@@ -135,7 +138,7 @@ size_t FileSpecList::FindCompatibleIndex(size_t start_idx,
 // an empty FileSpec object will be returned.
 const FileSpec &FileSpecList::GetFileSpecAtIndex(size_t idx) const {
   if (idx < m_files.size())
-    return m_files[idx];
+    return m_files[idx].Materialize();
   static FileSpec g_empty_file_spec;
   return g_empty_file_spec;
 }
@@ -148,7 +151,7 @@ size_t FileSpecList::MemorySize() const {
   size_t mem_size = sizeof(FileSpecList);
   collection::const_iterator pos, end = m_files.end();
   for (pos = m_files.begin(); pos != end; ++pos) {
-    mem_size += pos->MemorySize();
+    mem_size += pos->GetSpecOnly().MemorySize();
   }
 
   return mem_size;
diff --git a/lldb/test/API/functionalities/inline-sourcefile/Makefile b/lldb/test/API/functionalities/inline-sourcefile/Makefile
new file mode 100644
index 00000000000000..adb29d3a88e26c
--- /dev/null
+++ b/lldb/test/API/functionalities/inline-sourcefile/Makefile
@@ -0,0 +1,11 @@
+C_SOURCES := main.c
+CFLAGS_EXTRAS := -gdwarf-5
+
+include Makefile.rules
+
+OBJECTS += inline.o
+
+$(EXE): main.c inline.o
+
+%.o: %.ll
+	$(CC) $< -c -o $@
diff --git a/lldb/test/API/functionalities/inline-sourcefile/TestInlineSourceFiles.py b/lldb/test/API/functionalities/inline-sourcefile/TestInlineSourceFiles.py
new file mode 100644
index 00000000000000..6daf970b895b0f
--- /dev/null
+++ b/lldb/test/API/functionalities/inline-sourcefile/TestInlineSourceFiles.py
@@ -0,0 +1,17 @@
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbplatform
+from lldbsuite.test import lldbutil
+
+
+class InlineSourceFilesTestCase(TestBase):
+    @skipIf(compiler="gcc")
+    @skipIf(compiler="clang", compiler_version=["<", "18.0"])
+    def test(self):
+        """Test DWARF inline source files."""
+        self.build()
+        #target, process, thread, bkpt = lldbutil.run_to_source_breakpoint(
+        #    self, 'break here', lldb.SBFileSpec('inlined.c'))
+        target, process, thread, bkpt = lldbutil.run_to_name_breakpoint(
+            self, 'f')
diff --git a/lldb/test/API/functionalities/inline-sourcefile/inline.ll b/lldb/test/API/functionalities/inline-sourcefile/inline.ll
new file mode 100644
index 00000000000000..56194e45b81387
--- /dev/null
+++ b/lldb/test/API/functionalities/inline-sourcefile/inline.ll
@@ -0,0 +1,39 @@
+; ModuleID = '/tmp/t.c'
+source_filename = "/tmp/t.c"
+target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
+
+; Function Attrs: noinline nounwind optnone ssp uwtable(sync)
+define void @f() #0 !dbg !9 {
+entry:
+  call void @stop(), !dbg !13
+  ret void, !dbg !14
+}
+
+declare void @stop(...) #1
+
+attributes #0 = { noinline nounwind optnone ssp uwtable(sync) }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3, !4, !5, !6, !7}
+!llvm.ident = !{!8}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 18.0.0git (git at github.com:llvm/llvm-project.git 29ee66f4a0967e43a035f147c960743c7b640f2f)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: Apple, sysroot: "/")
+!1 = !DIFile(filename: "/INLINE/inlined.c", directory: "/Volumes/Data/llvm-project", checksumkind: CSK_MD5, checksum: "3183154a5cb31debe9a8e27ca500bc3c")
+!2 = !{i32 7, !"Dwarf Version", i32 5}
+!3 = !{i32 2, !"Debug Info Version", i32 3}
+!4 = !{i32 1, !"wchar_size", i32 4}
+!5 = !{i32 8, !"PIC Level", i32 2}
+!6 = !{i32 7, !"uwtable", i32 1}
+!7 = !{i32 7, !"frame-pointer", i32 1}
+!8 = !{!"clang version 18.0.0git (git at github.com:llvm/llvm-project.git 29ee66f4a0967e43a035f147c960743c7b640f2f)"}
+!9 = distinct !DISubprogram(name: "f", scope: !10, file: !10, line: 2, type: !11, scopeLine: 2, spFlags: DISPFlagDefinition, unit: !0)
+!10 = !DIFile(filename: "/INLINE/inlined.c", directory: "", source: "void stop();
+void f() {
+  // This is inline source code.
+  stop(); // break here
+}
+")
+!11 = !DISubroutineType(types: !12)
+!12 = !{null}
+!13 = !DILocation(line: 4, column: 3, scope: !9)
+!14 = !DILocation(line: 5, column: 1, scope: !9)
diff --git a/lldb/test/API/functionalities/inline-sourcefile/main.c b/lldb/test/API/functionalities/inline-sourcefile/main.c
new file mode 100644
index 00000000000000..c030d7773fa70a
--- /dev/null
+++ b/lldb/test/API/functionalities/inline-sourcefile/main.c
@@ -0,0 +1,7 @@
+void f();
+void stop() {}
+
+int main(int argc, char const *argv[]) {
+  f();
+  return 0;
+}

>From f66f34faac71c87aa1692c24f835a46fb8e1f023 Mon Sep 17 00:00:00 2001
From: Adrian Prantl <aprantl at apple.com>
Date: Tue, 19 Dec 2023 17:47:06 -0800
Subject: [PATCH 2/3] Separate FileSpecList from SupportFileList

---
 lldb/include/lldb/Symbol/CompileUnit.h        |  6 +-
 lldb/include/lldb/Symbol/SymbolFile.h         |  2 +-
 lldb/include/lldb/Symbol/SymbolFileOnDemand.h |  2 +-
 lldb/include/lldb/Utility/FileSpecList.h      | 94 +++++++++++--------
 lldb/source/API/SBCompileUnit.cpp             |  2 +-
 lldb/source/Commands/CommandObjectSource.cpp  |  2 +-
 lldb/source/Core/ModuleList.cpp               |  6 +-
 .../Clang/ClangUserExpression.cpp             |  8 +-
 .../Clang/CppModuleConfiguration.cpp          |  2 +-
 .../Clang/CppModuleConfiguration.h            |  2 +-
 .../Breakpad/SymbolFileBreakpad.cpp           |  5 +-
 .../SymbolFile/Breakpad/SymbolFileBreakpad.h  |  3 +-
 .../Plugins/SymbolFile/CTF/SymbolFileCTF.h    |  2 +-
 .../SymbolFile/DWARF/SymbolFileDWARF.cpp      | 16 ++--
 .../SymbolFile/DWARF/SymbolFileDWARF.h        |  8 +-
 .../DWARF/SymbolFileDWARFDebugMap.cpp         |  4 +-
 .../DWARF/SymbolFileDWARFDebugMap.h           |  2 +-
 .../Plugins/SymbolFile/JSON/SymbolFileJSON.h  |  2 +-
 .../NativePDB/SymbolFileNativePDB.cpp         |  4 +-
 .../NativePDB/SymbolFileNativePDB.h           |  2 +-
 .../Plugins/SymbolFile/PDB/SymbolFilePDB.cpp  |  2 +-
 .../Plugins/SymbolFile/PDB/SymbolFilePDB.h    |  2 +-
 .../SymbolFile/Symtab/SymbolFileSymtab.cpp    |  2 +-
 .../SymbolFile/Symtab/SymbolFileSymtab.h      |  2 +-
 lldb/source/Symbol/CompileUnit.cpp            |  6 +-
 lldb/source/Symbol/SymbolFileOnDemand.cpp     |  2 +-
 lldb/source/Utility/FileSpecList.cpp          | 68 +++++++++++---
 lldb/unittests/Core/FileSpecListTest.cpp      |  8 +-
 .../Expression/CppModuleConfigurationTest.cpp |  4 +-
 29 files changed, 165 insertions(+), 105 deletions(-)

diff --git a/lldb/include/lldb/Symbol/CompileUnit.h b/lldb/include/lldb/Symbol/CompileUnit.h
index 93f191b4998584..4b7119c6c5cdcf 100644
--- a/lldb/include/lldb/Symbol/CompileUnit.h
+++ b/lldb/include/lldb/Symbol/CompileUnit.h
@@ -265,7 +265,7 @@ class CompileUnit : public std::enable_shared_from_this<CompileUnit>,
   ///
   /// \return
   ///     A support file list object.
-  const FileSpecList &GetSupportFiles();
+  const SupportFileList &GetSupportFiles();
 
   /// Get the compile unit's imported module list.
   ///
@@ -331,7 +331,7 @@ class CompileUnit : public std::enable_shared_from_this<CompileUnit>,
   ///     A line table object pointer that this object now owns.
   void SetLineTable(LineTable *line_table);
 
-  void SetSupportFiles(FileSpecList support_files);
+  void SetSupportFiles(SupportFileList support_files);
 
   void SetDebugMacros(const DebugMacrosSP &debug_macros);
 
@@ -412,7 +412,7 @@ class CompileUnit : public std::enable_shared_from_this<CompileUnit>,
   FileSpec m_file_spec;
   /// Files associated with this compile unit's line table and
   /// declarations.
-  FileSpecList m_support_files;
+  SupportFileList m_support_files;
   /// Line table that will get parsed on demand.
   std::unique_ptr<LineTable> m_line_table_up;
   /// Debug macros that will get parsed on demand.
diff --git a/lldb/include/lldb/Symbol/SymbolFile.h b/lldb/include/lldb/Symbol/SymbolFile.h
index c9a2a647a039dc..f356f7b789fa38 100644
--- a/lldb/include/lldb/Symbol/SymbolFile.h
+++ b/lldb/include/lldb/Symbol/SymbolFile.h
@@ -197,7 +197,7 @@ class SymbolFile : public PluginInterface {
     return false;
   }
   virtual bool ParseSupportFiles(CompileUnit &comp_unit,
-                                 FileSpecList &support_files) = 0;
+                                 SupportFileList &support_files) = 0;
   virtual size_t ParseTypes(CompileUnit &comp_unit) = 0;
   virtual bool ParseIsOptimized(CompileUnit &comp_unit) { return false; }
 
diff --git a/lldb/include/lldb/Symbol/SymbolFileOnDemand.h b/lldb/include/lldb/Symbol/SymbolFileOnDemand.h
index cde9f3c3b8ce1f..4e3009941aa7d6 100644
--- a/lldb/include/lldb/Symbol/SymbolFileOnDemand.h
+++ b/lldb/include/lldb/Symbol/SymbolFileOnDemand.h
@@ -81,7 +81,7 @@ class SymbolFileOnDemand : public lldb_private::SymbolFile {
       llvm::function_ref<bool(lldb_private::Module &)>) override;
 
   bool ParseSupportFiles(lldb_private::CompileUnit &comp_unit,
-                         lldb_private::FileSpecList &support_files) override;
+                         lldb_private::SupportFileList &support_files) override;
 
   bool ParseIsOptimized(lldb_private::CompileUnit &comp_unit) override;
 
diff --git a/lldb/include/lldb/Utility/FileSpecList.h b/lldb/include/lldb/Utility/FileSpecList.h
index 8eda721b607fd6..80ab3294e1395d 100644
--- a/lldb/include/lldb/Utility/FileSpecList.h
+++ b/lldb/include/lldb/Utility/FileSpecList.h
@@ -37,6 +37,9 @@ class FileSpecHolder {
   FileSpecHolder(const FileSpecHolder &other) = default;
   FileSpecHolder(FileSpecHolder &&other) = default;
   FileSpecHolder &operator=(const FileSpecHolder &other) = default;
+  bool operator==(const FileSpecHolder &other) {
+    return m_file_spec == other.m_file_spec;
+  }
   const FileSpec &GetSpecOnly() const { return m_file_spec; };
   const FileSpec &Materialize() const {
     if (m_lazy)
@@ -45,13 +48,61 @@ class FileSpecHolder {
   }
 };
 
+class SupportFileList {
+public:
+  typedef std::vector<FileSpecHolder> collection;
+  typedef collection::const_iterator const_iterator;
+  const_iterator begin() const { return m_files.begin(); }
+  const_iterator end() const { return m_files.end(); }
+
+  void Append(const FileSpec &file) { return Append(FileSpecHolder(file)); }
+  void Append(const FileSpecHolder &file) { m_files.push_back(file); }
+  bool AppendIfUnique(const FileSpec &file);
+  bool AppendIfUnique(const FileSpecHolder &file);
+  size_t GetSize() const { return m_files.size(); }
+  const FileSpec &GetFileSpecAtIndex(size_t idx) const;
+  size_t FindFileIndex(size_t idx, const FileSpec &file, bool full) const;
+  /// Find a compatible file index.
+  ///
+  /// Find the index of a compatible file in the file spec list that matches \a
+  /// file starting \a idx entries into the file spec list. A file is considered
+  /// compatible if:
+  /// - The file matches exactly (only filename if \a file has no directory)
+  /// - If \a file is relative and any file in the list has this same suffix
+  /// - If any file in the list is relative and the relative path is a suffix
+  ///   of \a file
+  ///
+  /// This is used to implement better matching for setting breakpoints in
+  /// source files where an IDE might specify a full path when setting the
+  /// breakpoint and debug info contains relative paths, if a user specifies
+  /// a relative path when setting a breakpoint.
+  ///
+  /// \param[in] idx
+  ///     An index into the file list.
+  ///
+  /// \param[in] file
+  ///     The file specification to search for.
+  ///
+  /// \return
+  ///     The index of the file that matches \a file if it is found,
+  ///     else UINT32_MAX is returned.
+  size_t FindCompatibleIndex(size_t idx, const FileSpec &file) const;
+
+  template <class... Args> void EmplaceBack(Args &&...args) {
+    m_files.emplace_back(FileSpec(std::forward<Args>(args)...));
+  }
+
+protected:
+  collection m_files; ///< A collection of FileSpec objects.
+};
+
 /// \class FileSpecList FileSpecList.h "lldb/Utility/FileSpecList.h"
 /// A file collection class.
 ///
 /// A class that contains a mutable list of FileSpec objects.
 class FileSpecList {
 public:
-  typedef std::vector<FileSpecHolder> collection;
+  typedef std::vector<FileSpec> collection;
   typedef collection::const_iterator const_iterator;
 
   /// Default constructor.
@@ -66,10 +117,7 @@ class FileSpecList {
   FileSpecList(FileSpecList &&rhs) = default;
 
   /// Initialize this object from a vector of FileSpecs
-  FileSpecList(std::vector<FileSpec> &&rhs) {
-    for (auto &fs : rhs)
-      m_files.emplace_back(fs);
-  }
+  FileSpecList(std::vector<FileSpec> &&rhs) : m_files(std::move(rhs)) {}
 
   /// Destructor.
   ~FileSpecList();
@@ -114,11 +162,9 @@ class FileSpecList {
   /// \param[in] args
   ///     Arguments to create the FileSpec
   template <class... Args> void EmplaceBack(Args &&...args) {
-    m_files.emplace_back(FileSpec(std::forward<Args>(args)...));
+    m_files.emplace_back(std::forward<Args>(args)...);
   }
 
-  void Append(FileSpecHolder &&fsh) { m_files.push_back(std::move(fsh)); }
-
   /// Clears the file list.
   void Clear();
 
@@ -147,32 +193,6 @@ class FileSpecList {
   ///     else UINT32_MAX is returned.
   size_t FindFileIndex(size_t idx, const FileSpec &file, bool full) const;
 
-  /// Find a compatible file index.
-  ///
-  /// Find the index of a compatible file in the file spec list that matches \a
-  /// file starting \a idx entries into the file spec list. A file is considered
-  /// compatible if:
-  /// - The file matches exactly (only filename if \a file has no directory)
-  /// - If \a file is relative and any file in the list has this same suffix
-  /// - If any file in the list is relative and the relative path is a suffix
-  ///   of \a file
-  ///
-  /// This is used to implement better matching for setting breakpoints in
-  /// source files where an IDE might specify a full path when setting the
-  /// breakpoint and debug info contains relative paths, if a user specifies
-  /// a relative path when setting a breakpoint.
-  ///
-  /// \param[in] idx
-  ///     An index into the file list.
-  ///
-  /// \param[in] file
-  ///     The file specification to search for.
-  ///
-  /// \return
-  ///     The index of the file that matches \a file if it is found,
-  ///     else UINT32_MAX is returned.
-  size_t FindCompatibleIndex(size_t idx, const FileSpec &file) const;
-
   /// Get file at index.
   ///
   /// Gets a file from the file list. If \a idx is not a valid index, an empty
@@ -208,10 +228,10 @@ class FileSpecList {
 
   bool Insert(size_t idx, const FileSpec &file) {
     if (idx < m_files.size()) {
-      m_files.insert(m_files.begin() + idx, FileSpecHolder(file));
+      m_files.insert(m_files.begin() + idx, file);
       return true;
     } else if (idx == m_files.size()) {
-      m_files.push_back(FileSpecHolder(file));
+      m_files.push_back(file);
       return true;
     }
     return false;
@@ -219,7 +239,7 @@ class FileSpecList {
 
   bool Replace(size_t idx, const FileSpec &file) {
     if (idx < m_files.size()) {
-      m_files[idx] = FileSpecHolder(file);
+      m_files[idx] = file;
       return true;
     }
     return false;
diff --git a/lldb/source/API/SBCompileUnit.cpp b/lldb/source/API/SBCompileUnit.cpp
index 3aa65e225d7aba..65fdb11032b9c0 100644
--- a/lldb/source/API/SBCompileUnit.cpp
+++ b/lldb/source/API/SBCompileUnit.cpp
@@ -171,7 +171,7 @@ uint32_t SBCompileUnit::FindSupportFileIndex(uint32_t start_idx,
   LLDB_INSTRUMENT_VA(this, start_idx, sb_file, full);
 
   if (m_opaque_ptr) {
-    const FileSpecList &support_files = m_opaque_ptr->GetSupportFiles();
+    const SupportFileList &support_files = m_opaque_ptr->GetSupportFiles();
     return support_files.FindFileIndex(start_idx, sb_file.ref(), full);
   }
   return 0;
diff --git a/lldb/source/Commands/CommandObjectSource.cpp b/lldb/source/Commands/CommandObjectSource.cpp
index db158a7f526305..cabf6f0436f176 100644
--- a/lldb/source/Commands/CommandObjectSource.cpp
+++ b/lldb/source/Commands/CommandObjectSource.cpp
@@ -204,7 +204,7 @@ class CommandObjectSourceInfo : public CommandObjectParsed {
     if (cu) {
       assert(file_spec.GetFilename().AsCString());
       bool has_path = (file_spec.GetDirectory().AsCString() != nullptr);
-      const FileSpecList &cu_file_list = cu->GetSupportFiles();
+      const SupportFileList &cu_file_list = cu->GetSupportFiles();
       size_t file_idx = cu_file_list.FindFileIndex(0, file_spec, has_path);
       if (file_idx != UINT32_MAX) {
         // Update the file to how it appears in the CU.
diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp
index 3b6c3ea899caf7..2180f29f369427 100644
--- a/lldb/source/Core/ModuleList.cpp
+++ b/lldb/source/Core/ModuleList.cpp
@@ -166,11 +166,9 @@ void ModuleListProperties::UpdateSymlinkMappings() {
   m_symlink_paths.Clear(notify);
   for (auto symlink : list) {
     FileSpec resolved;
-    Status status =
-        FileSystem::Instance().Readlink(symlink.Materialize(), resolved);
+    Status status = FileSystem::Instance().Readlink(symlink, resolved);
     if (status.Success())
-      m_symlink_paths.Append(symlink.Materialize().GetPath(),
-                             resolved.GetPath(), notify);
+      m_symlink_paths.Append(symlink.GetPath(), resolved.GetPath(), notify);
   }
 }
 
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
index ec03a38752c2fe..619f70f565a364 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
@@ -487,19 +487,19 @@ CppModuleConfiguration GetModuleConfig(lldb::LanguageType language,
     return LogConfigError("Couldn't calculate symbol context");
 
   // Build a list of files we need to analyze to build the configuration.
-  FileSpecList files;
+  SupportFileList files;
   for (auto &f : sc.comp_unit->GetSupportFiles())
-    files.AppendIfUnique(f.Materialize());
+    files.AppendIfUnique(f);
   // We also need to look at external modules in the case of -gmodules as they
   // contain the support files for libc++ and the C library.
   llvm::DenseSet<SymbolFile *> visited_symbol_files;
   sc.comp_unit->ForEachExternalModule(
       visited_symbol_files, [&files](Module &module) {
         for (std::size_t i = 0; i < module.GetNumCompileUnits(); ++i) {
-          const FileSpecList &support_files =
+          const SupportFileList &support_files =
               module.GetCompileUnitAtIndex(i)->GetSupportFiles();
           for (auto &f : support_files) {
-            files.AppendIfUnique(f.Materialize());
+            files.AppendIfUnique(f);
           }
         }
         return false;
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp b/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp
index 0cd52db97521a1..ff9abd05d30a8e 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp
@@ -132,7 +132,7 @@ bool CppModuleConfiguration::hasValidConfig() {
 }
 
 CppModuleConfiguration::CppModuleConfiguration(
-    const FileSpecList &support_files, const llvm::Triple &triple) {
+    const SupportFileList &support_files, const llvm::Triple &triple) {
   // Analyze all files we were given to build the configuration.
   bool error = !llvm::all_of(support_files, [&](auto &file) {
     return CppModuleConfiguration::analyzeFile(file.Materialize(), triple);
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.h b/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.h
index 7be0ce6c7ae579..0e3408bae06ba2 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.h
+++ b/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.h
@@ -65,7 +65,7 @@ class CppModuleConfiguration {
 public:
   /// Creates a configuration by analyzing the given list of used source files.
   /// The triple (if valid) is used to search for target-specific include paths.
-  explicit CppModuleConfiguration(const FileSpecList &support_files,
+  explicit CppModuleConfiguration(const SupportFileList &support_files,
                                   const llvm::Triple &triple);
   /// Creates an empty and invalid configuration.
   CppModuleConfiguration() = default;
diff --git a/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp b/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp
index 729d6af02402d8..47c8074adc5b7c 100644
--- a/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp
+++ b/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp
@@ -278,13 +278,14 @@ bool SymbolFileBreakpad::ParseLineTable(CompileUnit &comp_unit) {
 }
 
 bool SymbolFileBreakpad::ParseSupportFiles(CompileUnit &comp_unit,
-                                           FileSpecList &support_files) {
+                                           SupportFileList &support_files) {
   std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
   CompUnitData &data = m_cu_data->GetEntryRef(comp_unit.GetID()).data;
   if (!data.support_files)
     ParseLineTableAndSupportFiles(comp_unit, data);
 
-  support_files = std::move(*data.support_files);
+  for (auto &fs : *data.support_files)
+    support_files.Append(fs);
   return true;
 }
 
diff --git a/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h b/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h
index 214fbdd3ff3aa0..41e4e3b258014c 100644
--- a/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h
+++ b/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h
@@ -73,7 +73,7 @@ class SymbolFileBreakpad : public SymbolFileCommon {
   bool ParseDebugMacros(CompileUnit &comp_unit) override { return false; }
 
   bool ParseSupportFiles(CompileUnit &comp_unit,
-                         FileSpecList &support_files) override;
+                         SupportFileList &support_files) override;
   size_t ParseTypes(CompileUnit &cu) override { return 0; }
 
   bool ParseImportedModules(
@@ -195,7 +195,6 @@ class SymbolFileBreakpad : public SymbolFileCommon {
     Bookmark bookmark;
     std::optional<FileSpecList> support_files;
     std::unique_ptr<LineTable> line_table_up;
-
   };
 
   uint32_t CalculateNumCompileUnits() override;
diff --git a/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.h b/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.h
index f111937dbd6ef0..3a80138fffbc37 100644
--- a/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.h
+++ b/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.h
@@ -66,7 +66,7 @@ class SymbolFileCTF : public lldb_private::SymbolFileCommon {
   bool ParseDebugMacros(CompileUnit &comp_unit) override { return false; }
 
   bool ParseSupportFiles(CompileUnit &comp_unit,
-                         FileSpecList &support_files) override {
+                         SupportFileList &support_files) override {
     return false;
   }
 
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index 52caa5885baac2..1b1b3cdbe557be 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -210,12 +210,12 @@ GetFileByIndex(const llvm::DWARFDebugLine::Prologue &prologue, size_t idx,
   return std::move(rel_path);
 }
 
-static FileSpecList
+static SupportFileList
 ParseSupportFilesFromPrologue(const lldb::ModuleSP &module,
                               const llvm::DWARFDebugLine::Prologue &prologue,
                               FileSpec::Style style,
                               llvm::StringRef compile_dir = {}) {
-  FileSpecList support_files;
+  SupportFileList support_files;
 
   // Handle the case where there are no files first to avoid having to special
   // case this later.
@@ -822,7 +822,7 @@ lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit &dwarf_cu) {
           // file is also the name of the compile unit. This
           // allows us to avoid loading the non-skeleton unit,
           // which may be in a separate DWO file.
-          FileSpecList support_files;
+          SupportFileList support_files;
           if (!ParseSupportFiles(dwarf_cu, module_sp, support_files))
             return false;
           if (support_files.GetSize() == 0)
@@ -1076,7 +1076,7 @@ bool SymbolFileDWARF::ForEachExternalModule(
 }
 
 bool SymbolFileDWARF::ParseSupportFiles(CompileUnit &comp_unit,
-                                        FileSpecList &support_files) {
+                                        SupportFileList &support_files) {
   std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
   DWARFUnit *dwarf_cu = GetDWARFCompileUnit(&comp_unit);
   if (!dwarf_cu)
@@ -1091,7 +1091,7 @@ bool SymbolFileDWARF::ParseSupportFiles(CompileUnit &comp_unit,
 
 bool SymbolFileDWARF::ParseSupportFiles(DWARFUnit &dwarf_cu,
                                         const ModuleSP &module,
-                                        FileSpecList &support_files) {
+                                        SupportFileList &support_files) {
 
   dw_offset_t offset = dwarf_cu.GetLineTableOffset();
   if (offset == DW_INVALID_OFFSET)
@@ -1120,9 +1120,9 @@ FileSpec SymbolFileDWARF::GetFile(DWARFUnit &unit, size_t file_idx) {
   return GetTypeUnitSupportFiles(tu).GetFileSpecAtIndex(file_idx);
 }
 
-const FileSpecList &
+const SupportFileList &
 SymbolFileDWARF::GetTypeUnitSupportFiles(DWARFTypeUnit &tu) {
-  static FileSpecList empty_list;
+  static SupportFileList empty_list;
 
   dw_offset_t offset = tu.GetLineTableOffset();
   if (offset == DW_INVALID_OFFSET ||
@@ -1133,7 +1133,7 @@ SymbolFileDWARF::GetTypeUnitSupportFiles(DWARFTypeUnit &tu) {
   // Many type units can share a line table, so parse the support file list
   // once, and cache it based on the offset field.
   auto iter_bool = m_type_unit_support_files.try_emplace(offset);
-  FileSpecList &list = iter_bool.first->second;
+  SupportFileList &list = iter_bool.first->second;
   if (iter_bool.second) {
     uint64_t line_table_offset = offset;
     llvm::DWARFDataExtractor data =
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
index 78819edd0062bf..f4de005af59fb1 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -123,7 +123,7 @@ class SymbolFileDWARF : public SymbolFileCommon {
                              llvm::function_ref<bool(Module &)>) override;
 
   bool ParseSupportFiles(CompileUnit &comp_unit,
-                         FileSpecList &support_files) override;
+                         SupportFileList &support_files) override;
 
   bool ParseIsOptimized(CompileUnit &comp_unit) override;
 
@@ -396,7 +396,7 @@ class SymbolFileDWARF : public SymbolFileCommon {
                          bool *type_is_new);
 
   bool ParseSupportFiles(DWARFUnit &dwarf_cu, const lldb::ModuleSP &module,
-                         FileSpecList &support_files);
+                         SupportFileList &support_files);
 
   lldb::VariableSP ParseVariableDIE(const SymbolContext &sc,
                                     const DWARFDIE &die,
@@ -489,7 +489,7 @@ class SymbolFileDWARF : public SymbolFileCommon {
 
   void FindDwpSymbolFile();
 
-  const FileSpecList &GetTypeUnitSupportFiles(DWARFTypeUnit &tu);
+  const SupportFileList &GetTypeUnitSupportFiles(DWARFTypeUnit &tu);
 
   void InitializeFirstCodeAddressRecursive(const SectionList &section_list);
 
@@ -529,7 +529,7 @@ class SymbolFileDWARF : public SymbolFileCommon {
   DIEToVariableSP m_die_to_variable_sp;
   DIEToCompilerType m_forward_decl_die_to_compiler_type;
   CompilerTypeToDIE m_forward_decl_compiler_type_to_die;
-  llvm::DenseMap<dw_offset_t, FileSpecList> m_type_unit_support_files;
+  llvm::DenseMap<dw_offset_t, SupportFileList> m_type_unit_support_files;
   std::vector<uint32_t> m_lldb_cu_to_dwarf_unit;
   /// DWARF does not provide a good way for traditional (concatenating) linkers
   /// to invalidate debug info describing dead-stripped code. These linkers will
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
index e5b59460cb85d5..9094a5e21e690c 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
@@ -725,8 +725,8 @@ bool SymbolFileDWARFDebugMap::ForEachExternalModule(
   return false;
 }
 
-bool SymbolFileDWARFDebugMap::ParseSupportFiles(CompileUnit &comp_unit,
-                                                FileSpecList &support_files) {
+bool SymbolFileDWARFDebugMap::ParseSupportFiles(
+    CompileUnit &comp_unit, SupportFileList &support_files) {
   std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
   SymbolFileDWARF *oso_dwarf = GetSymbolFile(comp_unit);
   if (oso_dwarf)
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
index cd0a4bb6e41c2f..d639ee500080d5 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
@@ -74,7 +74,7 @@ class SymbolFileDWARFDebugMap : public SymbolFileCommon {
                              llvm::function_ref<bool(Module &)>) override;
 
   bool ParseSupportFiles(CompileUnit &comp_unit,
-                         FileSpecList &support_files) override;
+                         SupportFileList &support_files) override;
 
   bool ParseIsOptimized(CompileUnit &comp_unit) override;
 
diff --git a/lldb/source/Plugins/SymbolFile/JSON/SymbolFileJSON.h b/lldb/source/Plugins/SymbolFile/JSON/SymbolFileJSON.h
index 4dd0d65da46583..3dd33b3dc82fba 100644
--- a/lldb/source/Plugins/SymbolFile/JSON/SymbolFileJSON.h
+++ b/lldb/source/Plugins/SymbolFile/JSON/SymbolFileJSON.h
@@ -59,7 +59,7 @@ class SymbolFileJSON : public lldb_private::SymbolFileCommon {
   bool ParseDebugMacros(CompileUnit &comp_unit) override { return false; }
 
   bool ParseSupportFiles(CompileUnit &comp_unit,
-                         FileSpecList &support_files) override {
+                         SupportFileList &support_files) override {
     return false;
   }
 
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
index ad08013399369e..8375010ae3dedd 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -1369,7 +1369,7 @@ SymbolFileNativePDB::GetFileIndex(const CompilandIndexItem &cii,
 }
 
 bool SymbolFileNativePDB::ParseSupportFiles(CompileUnit &comp_unit,
-                                            FileSpecList &support_files) {
+                                            SupportFileList &support_files) {
   std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
   PdbSymUid cu_id(comp_unit.GetID());
   lldbassert(cu_id.kind() == PdbSymUidKind::Compiland);
@@ -1416,7 +1416,7 @@ void SymbolFileNativePDB::ParseInlineSite(PdbCompilandSymId id,
     return;
   InlineeSourceLine inlinee_line = iter->second;
 
-  const FileSpecList &files = comp_unit->GetSupportFiles();
+  const SupportFileList &files = comp_unit->GetSupportFiles();
   FileSpec decl_file;
   llvm::Expected<uint32_t> file_index_or_err =
       GetFileIndex(*cii, inlinee_line.Header->FileID);
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
index 9d0458cf7ebfeb..82577771f355c8 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
@@ -94,7 +94,7 @@ class SymbolFileNativePDB : public SymbolFileCommon {
   bool ParseDebugMacros(lldb_private::CompileUnit &comp_unit) override;
 
   bool ParseSupportFiles(lldb_private::CompileUnit &comp_unit,
-                         FileSpecList &support_files) override;
+                         SupportFileList &support_files) override;
   size_t ParseTypes(lldb_private::CompileUnit &comp_unit) override;
 
   bool ParseImportedModules(
diff --git a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
index 9e1cd836066021..b26beecc6d1263 100644
--- a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
@@ -365,7 +365,7 @@ bool SymbolFilePDB::ParseDebugMacros(CompileUnit &comp_unit) {
 }
 
 bool SymbolFilePDB::ParseSupportFiles(
-    CompileUnit &comp_unit, lldb_private::FileSpecList &support_files) {
+    CompileUnit &comp_unit, lldb_private::SupportFileList &support_files) {
 
   // In theory this is unnecessary work for us, because all of this information
   // is easily (and quickly) accessible from DebugInfoPDB, so caching it a
diff --git a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h
index 01851f1418f3a8..ea495c575f1f1a 100644
--- a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h
+++ b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h
@@ -70,7 +70,7 @@ class SymbolFilePDB : public lldb_private::SymbolFileCommon {
   bool ParseDebugMacros(lldb_private::CompileUnit &comp_unit) override;
 
   bool ParseSupportFiles(lldb_private::CompileUnit &comp_unit,
-                         lldb_private::FileSpecList &support_files) override;
+                         lldb_private::SupportFileList &support_files) override;
 
   size_t ParseTypes(lldb_private::CompileUnit &comp_unit) override;
 
diff --git a/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp b/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp
index 6e4c6439974e95..8c17017442b1f8 100644
--- a/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp
+++ b/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp
@@ -211,7 +211,7 @@ bool SymbolFileSymtab::ParseDebugMacros(CompileUnit &comp_unit) {
 }
 
 bool SymbolFileSymtab::ParseSupportFiles(CompileUnit &comp_unit,
-                                         FileSpecList &support_files) {
+                                         SupportFileList &support_files) {
   return false;
 }
 
diff --git a/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h b/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h
index 1bbc4de9c9425b..a36311525334e4 100644
--- a/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h
+++ b/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h
@@ -57,7 +57,7 @@ class SymbolFileSymtab : public lldb_private::SymbolFileCommon {
   bool ParseDebugMacros(lldb_private::CompileUnit &comp_unit) override;
 
   bool ParseSupportFiles(lldb_private::CompileUnit &comp_unit,
-                         lldb_private::FileSpecList &support_files) override;
+                         lldb_private::SupportFileList &support_files) override;
 
   size_t ParseTypes(lldb_private::CompileUnit &comp_unit) override;
 
diff --git a/lldb/source/Symbol/CompileUnit.cpp b/lldb/source/Symbol/CompileUnit.cpp
index c9796973940a24..6ba3e0d7bd909c 100644
--- a/lldb/source/Symbol/CompileUnit.cpp
+++ b/lldb/source/Symbol/CompileUnit.cpp
@@ -178,7 +178,7 @@ void CompileUnit::SetLineTable(LineTable *line_table) {
   m_line_table_up.reset(line_table);
 }
 
-void CompileUnit::SetSupportFiles(FileSpecList support_files) {
+void CompileUnit::SetSupportFiles(SupportFileList support_files) {
   m_support_files = std::move(support_files);
 }
 
@@ -213,7 +213,7 @@ VariableListSP CompileUnit::GetVariableList(bool can_create) {
   return m_variables;
 }
 
-std::vector<uint32_t> FindFileIndexes(const FileSpecList &files,
+std::vector<uint32_t> FindFileIndexes(const SupportFileList &files,
                                       const FileSpec &file) {
   std::vector<uint32_t> result;
   uint32_t idx = -1;
@@ -411,7 +411,7 @@ bool CompileUnit::ForEachExternalModule(
   return false;
 }
 
-const FileSpecList &CompileUnit::GetSupportFiles() {
+const SupportFileList &CompileUnit::GetSupportFiles() {
   if (m_support_files.GetSize() == 0) {
     if (m_flags.IsClear(flagsParsedSupportFiles)) {
       m_flags.Set(flagsParsedSupportFiles);
diff --git a/lldb/source/Symbol/SymbolFileOnDemand.cpp b/lldb/source/Symbol/SymbolFileOnDemand.cpp
index 33995252bfe2c9..bdb1951d51259d 100644
--- a/lldb/source/Symbol/SymbolFileOnDemand.cpp
+++ b/lldb/source/Symbol/SymbolFileOnDemand.cpp
@@ -115,7 +115,7 @@ bool SymbolFileOnDemand::ForEachExternalModule(
 }
 
 bool SymbolFileOnDemand::ParseSupportFiles(CompileUnit &comp_unit,
-                                           FileSpecList &support_files) {
+                                           SupportFileList &support_files) {
   LLDB_LOG(GetLog(),
            "[{0}] {1} is not skipped: explicitly allowed to support breakpoint",
            GetSymbolFileName(), __FUNCTION__);
diff --git a/lldb/source/Utility/FileSpecList.cpp b/lldb/source/Utility/FileSpecList.cpp
index c2ebbfd5ec854f..3c1d41bc846d9a 100644
--- a/lldb/source/Utility/FileSpecList.cpp
+++ b/lldb/source/Utility/FileSpecList.cpp
@@ -30,7 +30,17 @@ void FileSpecList::Append(const FileSpec &file_spec) {
 // a copy of "file_spec".
 bool FileSpecList::AppendIfUnique(const FileSpec &file_spec) {
   collection::iterator end = m_files.end();
-  if (find_if(m_files.begin(), end, [&](auto &holder) {
+  if (find(m_files.begin(), end, file_spec) == end) {
+    m_files.push_back(file_spec);
+    return true;
+  }
+  return false;
+}
+
+// FIXME: Replace this with a DenseSet at the call site. It is inefficient.
+bool SupportFileList::AppendIfUnique(const FileSpec &file_spec) {
+  collection::iterator end = m_files.end();
+  if (find_if(m_files.begin(), end, [&](const FileSpecHolder &holder) {
         return holder.GetSpecOnly() == file_spec;
       }) == end) {
     m_files.push_back(file_spec);
@@ -39,6 +49,16 @@ bool FileSpecList::AppendIfUnique(const FileSpec &file_spec) {
   return false;
 }
 
+// FIXME: Replace this with a DenseSet at the call site. It is inefficient.
+bool SupportFileList::AppendIfUnique(const FileSpecHolder &holder) {
+  collection::iterator end = m_files.end();
+  if (find(m_files.begin(), end, holder) == end) {
+    m_files.push_back(holder);
+    return true;
+  }
+  return false;
+}
+
 // Clears the file list.
 void FileSpecList::Clear() { m_files.clear(); }
 
@@ -46,7 +66,7 @@ void FileSpecList::Clear() { m_files.clear(); }
 void FileSpecList::Dump(Stream *s, const char *separator_cstr) const {
   collection::const_iterator pos, end = m_files.end();
   for (pos = m_files.begin(); pos != end; ++pos) {
-    pos->GetSpecOnly().Dump(s->AsRawOstream());
+    pos->Dump(s->AsRawOstream());
     if (separator_cstr && ((pos + 1) != end))
       s->PutCString(separator_cstr);
   }
@@ -57,23 +77,22 @@ void FileSpecList::Dump(Stream *s, const char *separator_cstr) const {
 //
 // Returns the valid index of the file that matches "file_spec" if it is found,
 // else std::numeric_limits<uint32_t>::max() is returned.
-size_t FileSpecList::FindFileIndex(size_t start_idx, const FileSpec &file_spec,
-                                   bool full) const {
-  const size_t num_files = m_files.size();
-
+static size_t FindFileIndex(size_t start_idx, const FileSpec &file_spec,
+                            bool full, size_t num_files,
+                            std::function<const FileSpec &(size_t)> get_ith) {
   // When looking for files, we will compare only the filename if the FILE_SPEC
   // argument is empty
   bool compare_filename_only = file_spec.GetDirectory().IsEmpty();
 
   for (size_t idx = start_idx; idx < num_files; ++idx) {
-    auto f = m_files[idx].GetSpecOnly();
+    const FileSpec &ith = get_ith(idx);
     if (compare_filename_only) {
-      if (ConstString::Equals(f.GetFilename(), file_spec.GetFilename(),
+      if (ConstString::Equals(ith.GetFilename(), file_spec.GetFilename(),
                               file_spec.IsCaseSensitive() ||
-                                  f.IsCaseSensitive()))
+                                  ith.IsCaseSensitive()))
         return idx;
     } else {
-      if (FileSpec::Equal(f, file_spec, full))
+      if (FileSpec::Equal(ith, file_spec, full))
         return idx;
     }
   }
@@ -82,8 +101,24 @@ size_t FileSpecList::FindFileIndex(size_t start_idx, const FileSpec &file_spec,
   return UINT32_MAX;
 }
 
-size_t FileSpecList::FindCompatibleIndex(size_t start_idx,
-                                         const FileSpec &file_spec) const {
+size_t FileSpecList::FindFileIndex(size_t start_idx, const FileSpec &file_spec,
+                                   bool full) const {
+  return ::FindFileIndex(
+      start_idx, file_spec, full, m_files.size(),
+      [&](size_t idx) -> const FileSpec & { return m_files[idx]; });
+}
+
+size_t SupportFileList::FindFileIndex(size_t start_idx,
+                                      const FileSpec &file_spec,
+                                      bool full) const {
+  return ::FindFileIndex(start_idx, file_spec, full, m_files.size(),
+                         [&](size_t idx) -> const FileSpec & {
+                           return m_files[idx].GetSpecOnly();
+                         });
+}
+
+size_t SupportFileList::FindCompatibleIndex(size_t start_idx,
+                                            const FileSpec &file_spec) const {
   const size_t num_files = m_files.size();
   if (start_idx >= num_files)
     return UINT32_MAX;
@@ -137,6 +172,13 @@ size_t FileSpecList::FindCompatibleIndex(size_t start_idx,
 // Returns the FileSpec object at index "idx". If "idx" is out of range, then
 // an empty FileSpec object will be returned.
 const FileSpec &FileSpecList::GetFileSpecAtIndex(size_t idx) const {
+  if (idx < m_files.size())
+    return m_files[idx];
+  static FileSpec g_empty_file_spec;
+  return g_empty_file_spec;
+}
+
+const FileSpec &SupportFileList::GetFileSpecAtIndex(size_t idx) const {
   if (idx < m_files.size())
     return m_files[idx].Materialize();
   static FileSpec g_empty_file_spec;
@@ -151,7 +193,7 @@ size_t FileSpecList::MemorySize() const {
   size_t mem_size = sizeof(FileSpecList);
   collection::const_iterator pos, end = m_files.end();
   for (pos = m_files.begin(); pos != end; ++pos) {
-    mem_size += pos->GetSpecOnly().MemorySize();
+    mem_size += pos->MemorySize();
   }
 
   return mem_size;
diff --git a/lldb/unittests/Core/FileSpecListTest.cpp b/lldb/unittests/Core/FileSpecListTest.cpp
index d65e7cd2d0586b..e63f4a00bc3a94 100644
--- a/lldb/unittests/Core/FileSpecListTest.cpp
+++ b/lldb/unittests/Core/FileSpecListTest.cpp
@@ -20,7 +20,7 @@ static FileSpec WindowsSpec(llvm::StringRef path) {
   return FileSpec(path, FileSpec::Style::windows);
 }
 
-TEST(FileSpecListTest, RelativePathMatchesPosix) {
+TEST(SupportFileListTest, RelativePathMatchesPosix) {
 
   const FileSpec fullpath = PosixSpec("/build/src/main.cpp");
   const FileSpec relative = PosixSpec("./src/main.cpp");
@@ -32,7 +32,7 @@ TEST(FileSpecListTest, RelativePathMatchesPosix) {
   const FileSpec rel2_wrong = PosixSpec("asrc/main.cpp");
   const FileSpec rel3_wrong = PosixSpec("rc/main.cpp");
 
-  FileSpecList files;
+  SupportFileList files;
   files.Append(fullpath);
   files.Append(relative);
   files.Append(basename);
@@ -72,7 +72,7 @@ TEST(FileSpecListTest, RelativePathMatchesPosix) {
   EXPECT_EQ((size_t)6, files.FindCompatibleIndex(3, rel3_wrong));
 }
 
-TEST(FileSpecListTest, RelativePathMatchesWindows) {
+TEST(SupportFileListTest, RelativePathMatchesWindows) {
 
   const FileSpec fullpath = WindowsSpec(R"(C:\build\src\main.cpp)");
   const FileSpec relative = WindowsSpec(R"(.\src\main.cpp)");
@@ -84,7 +84,7 @@ TEST(FileSpecListTest, RelativePathMatchesWindows) {
   const FileSpec rel2_wrong = WindowsSpec(R"(asrc\main.cpp)");
   const FileSpec rel3_wrong = WindowsSpec(R"("rc\main.cpp)");
 
-  FileSpecList files;
+  SupportFileList files;
   files.Append(fullpath);
   files.Append(relative);
   files.Append(basename);
diff --git a/lldb/unittests/Expression/CppModuleConfigurationTest.cpp b/lldb/unittests/Expression/CppModuleConfigurationTest.cpp
index 017a0748c2243c..3c395938f1af86 100644
--- a/lldb/unittests/Expression/CppModuleConfigurationTest.cpp
+++ b/lldb/unittests/Expression/CppModuleConfigurationTest.cpp
@@ -37,8 +37,8 @@ struct CppModuleConfigurationTest : public testing::Test {
   }
 
   /// Utility function turning a list of paths into a FileSpecList.
-  FileSpecList makeFiles(llvm::ArrayRef<std::string> paths) {
-    FileSpecList result;
+  SupportFileList makeFiles(llvm::ArrayRef<std::string> paths) {
+    SupportFileList result;
     for (const std::string &path : paths) {
       result.Append(FileSpec(path, FileSpec::Style::posix));
       if (!m_fs->addFileNoOwn(path, static_cast<time_t>(0), m_empty_buffer))

>From d5c6055a3893c118dcdb3c99917c5ef4ebb1b24a Mon Sep 17 00:00:00 2001
From: Adrian Prantl <aprantl at apple.com>
Date: Wed, 3 Jan 2024 14:17:52 -0800
Subject: [PATCH 3/3] Make FileSpecList non-copyable

---
 lldb/include/lldb/Symbol/CompileUnit.h        | 19 ++++--
 lldb/include/lldb/Utility/FileSpecList.h      | 49 ++++++++------
 .../Clang/ClangUserExpression.cpp             |  8 +--
 .../Clang/CppModuleConfiguration.cpp          |  4 +-
 .../Clang/CppModuleConfiguration.h            |  2 +-
 .../SymbolFile/DWARF/SymbolFileDWARF.cpp      | 67 +++++++++----------
 .../SymbolFile/DWARF/SymbolFileDWARF.h        |  5 +-
 lldb/source/Symbol/CompileUnit.cpp            |  9 +--
 lldb/source/Utility/FileSpecList.cpp          | 14 +---
 .../Expression/CppModuleConfigurationTest.cpp | 48 ++++++++-----
 10 files changed, 120 insertions(+), 105 deletions(-)

diff --git a/lldb/include/lldb/Symbol/CompileUnit.h b/lldb/include/lldb/Symbol/CompileUnit.h
index 4b7119c6c5cdcf..89e853ab599d0f 100644
--- a/lldb/include/lldb/Symbol/CompileUnit.h
+++ b/lldb/include/lldb/Symbol/CompileUnit.h
@@ -112,10 +112,13 @@ class CompileUnit : public std::enable_shared_from_this<CompileUnit>,
   ///     the compile unit is optimized will be made when
   ///     CompileUnit::GetIsOptimized() is called.
   ///
+  /// \param[in] support_files
+  ///     An rvalue list of already parsed support files.
   /// \see lldb::LanguageType
   CompileUnit(const lldb::ModuleSP &module_sp, void *user_data,
               const FileSpec &file_spec, lldb::user_id_t uid,
-              lldb::LanguageType language, lldb_private::LazyBool is_optimized);
+              lldb::LanguageType language, lldb_private::LazyBool is_optimized,
+              SupportFileList &&support_files = {});
 
   /// Add a function to this compile unit.
   ///
@@ -226,6 +229,9 @@ class CompileUnit : public std::enable_shared_from_this<CompileUnit>,
   /// Return the primary source file associated with this compile unit.
   const FileSpec &GetPrimaryFile() const { return m_file_spec; }
 
+  /// Return the primary source file associated with this compile unit.
+  void SetPrimaryFile(const FileSpec &fs) { m_file_spec = fs; }
+
   /// Get the line table for the compile unit.
   ///
   /// Called by clients and the SymbolFile plug-in. The SymbolFile plug-ins
@@ -267,6 +273,12 @@ class CompileUnit : public std::enable_shared_from_this<CompileUnit>,
   ///     A support file list object.
   const SupportFileList &GetSupportFiles();
 
+  /// Used by plugins that parse the support file list.
+  SupportFileList &GetSupportFileList() {
+    m_flags.Set(flagsParsedSupportFiles);
+    return m_support_files;
+  }
+
   /// Get the compile unit's imported module list.
   ///
   /// This reports all the imports that the compile unit made, including the
@@ -331,8 +343,6 @@ class CompileUnit : public std::enable_shared_from_this<CompileUnit>,
   ///     A line table object pointer that this object now owns.
   void SetLineTable(LineTable *line_table);
 
-  void SetSupportFiles(SupportFileList support_files);
-
   void SetDebugMacros(const DebugMacrosSP &debug_macros);
 
   /// Set accessor for the variable list.
@@ -410,8 +420,7 @@ class CompileUnit : public std::enable_shared_from_this<CompileUnit>,
   std::vector<SourceModule> m_imported_modules;
   /// The primary file associated with this compile unit.
   FileSpec m_file_spec;
-  /// Files associated with this compile unit's line table and
-  /// declarations.
+  /// Files associated with this compile unit's line table and declarations.
   SupportFileList m_support_files;
   /// Line table that will get parsed on demand.
   std::unique_ptr<LineTable> m_line_table_up;
diff --git a/lldb/include/lldb/Utility/FileSpecList.h b/lldb/include/lldb/Utility/FileSpecList.h
index 80ab3294e1395d..ece2bcabd5dff4 100644
--- a/lldb/include/lldb/Utility/FileSpecList.h
+++ b/lldb/include/lldb/Utility/FileSpecList.h
@@ -19,46 +19,55 @@ class Stream;
 
 /// Represents a source file whose contents is known (for example
 /// because it can be reconstructed from debug info), but that
-/// hasn't been written to a local disk yet.
-struct LazyFileSpec {
-  virtual ~LazyFileSpec() {}
-  virtual const FileSpec &Materialize() = 0;
+/// hasn't been written to a file yet.
+struct UnspooledSupportFile {
+  virtual ~UnspooledSupportFile() {}
+  /// Materialize the file to disk and return the path to that temporary file.
+  virtual const FileSpec &Materialize(llvm::StringRef file_name) = 0;
 };
 
-/// Wraps either a FileSpec that represents a local file or a
-/// LazyFileSpec that could be materialized into a local file.
-class FileSpecHolder {
+/// Wraps either a FileSpec that represents a local file or an
+/// UnspooledSupportFile that could be materialized into a local file.
+class SupportFile {
   FileSpec m_file_spec;
-  std::shared_ptr<LazyFileSpec> m_lazy;
+  std::unique_ptr<UnspooledSupportFile> m_unspooled;
 
 public:
-  FileSpecHolder(const FileSpec &spec, std::shared_ptr<LazyFileSpec> lazy = {})
-      : m_file_spec(spec), m_lazy(lazy) {}
-  FileSpecHolder(const FileSpecHolder &other) = default;
-  FileSpecHolder(FileSpecHolder &&other) = default;
-  FileSpecHolder &operator=(const FileSpecHolder &other) = default;
-  bool operator==(const FileSpecHolder &other) {
+  SupportFile(const FileSpec &spec,
+              std::unique_ptr<UnspooledSupportFile> &&unspooled = {})
+      : m_file_spec(spec), m_unspooled(std::move(unspooled)) {}
+  SupportFile(const SupportFile &other) = delete;
+  SupportFile(SupportFile &&other) = default;
+  bool operator==(const SupportFile &other) {
     return m_file_spec == other.m_file_spec;
   }
+  /// Return the file name only. Useful for resolving breakpoints by file name.
   const FileSpec &GetSpecOnly() const { return m_file_spec; };
+  /// Materialize the file to disk and return the path to that temporary file.
   const FileSpec &Materialize() const {
-    if (m_lazy)
-      return m_lazy->Materialize();
+    if (m_unspooled)
+      return m_unspooled->Materialize(m_file_spec.GetFilename().GetStringRef());
     return m_file_spec;
   }
 };
 
+/// A list of support files for a CompileUnit.
 class SupportFileList {
 public:
-  typedef std::vector<FileSpecHolder> collection;
+  SupportFileList(){};
+  SupportFileList(const SupportFileList &) = delete;
+  SupportFileList(SupportFileList &&other)
+      : m_files(std::move(other.m_files)) {}
+
+  typedef std::vector<SupportFile> collection;
   typedef collection::const_iterator const_iterator;
   const_iterator begin() const { return m_files.begin(); }
   const_iterator end() const { return m_files.end(); }
 
-  void Append(const FileSpec &file) { return Append(FileSpecHolder(file)); }
-  void Append(const FileSpecHolder &file) { m_files.push_back(file); }
+  void Append(const FileSpec &file) { return Append(SupportFile(file)); }
+  void Append(SupportFile &&file) { m_files.push_back(std::move(file)); }
+  // FIXME: Only used by SymbolFilePDB. Replace with a DenseSet at call site.
   bool AppendIfUnique(const FileSpec &file);
-  bool AppendIfUnique(const FileSpecHolder &file);
   size_t GetSize() const { return m_files.size(); }
   const FileSpec &GetFileSpecAtIndex(size_t idx) const;
   size_t FindFileIndex(size_t idx, const FileSpec &file, bool full) const;
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
index 619f70f565a364..d1e05d250edea7 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
@@ -487,9 +487,9 @@ CppModuleConfiguration GetModuleConfig(lldb::LanguageType language,
     return LogConfigError("Couldn't calculate symbol context");
 
   // Build a list of files we need to analyze to build the configuration.
-  SupportFileList files;
+  FileSpecList files;
   for (auto &f : sc.comp_unit->GetSupportFiles())
-    files.AppendIfUnique(f);
+    files.AppendIfUnique(f.Materialize());
   // We also need to look at external modules in the case of -gmodules as they
   // contain the support files for libc++ and the C library.
   llvm::DenseSet<SymbolFile *> visited_symbol_files;
@@ -499,7 +499,7 @@ CppModuleConfiguration GetModuleConfig(lldb::LanguageType language,
           const SupportFileList &support_files =
               module.GetCompileUnitAtIndex(i)->GetSupportFiles();
           for (auto &f : support_files) {
-            files.AppendIfUnique(f);
+            files.AppendIfUnique(f.Materialize());
           }
         }
         return false;
@@ -510,7 +510,7 @@ CppModuleConfiguration GetModuleConfig(lldb::LanguageType language,
   if (log && log->GetVerbose()) {
     for (auto &f : files)
       LLDB_LOGV(log, "[C++ module config] Analyzing support file: {0}",
-                f.Materialize().GetPath());
+                f.GetPath());
   }
 
   // Try to create a configuration from the files. If there is no valid
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp b/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp
index ff9abd05d30a8e..f43a04488230f0 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp
@@ -132,10 +132,10 @@ bool CppModuleConfiguration::hasValidConfig() {
 }
 
 CppModuleConfiguration::CppModuleConfiguration(
-    const SupportFileList &support_files, const llvm::Triple &triple) {
+    const FileSpecList &support_files, const llvm::Triple &triple) {
   // Analyze all files we were given to build the configuration.
   bool error = !llvm::all_of(support_files, [&](auto &file) {
-    return CppModuleConfiguration::analyzeFile(file.Materialize(), triple);
+    return CppModuleConfiguration::analyzeFile(file, triple);
   });
   // If we have a valid configuration at this point, set the
   // include directories and module list that should be used.
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.h b/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.h
index 0e3408bae06ba2..7be0ce6c7ae579 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.h
+++ b/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.h
@@ -65,7 +65,7 @@ class CppModuleConfiguration {
 public:
   /// Creates a configuration by analyzing the given list of used source files.
   /// The triple (if valid) is used to search for target-specific include paths.
-  explicit CppModuleConfiguration(const SupportFileList &support_files,
+  explicit CppModuleConfiguration(const FileSpecList &support_files,
                                   const llvm::Triple &triple);
   /// Creates an empty and invalid configuration.
   CppModuleConfiguration() = default;
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index 1b1b3cdbe557be..8e84c07a2abfbd 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -210,17 +210,14 @@ GetFileByIndex(const llvm::DWARFDebugLine::Prologue &prologue, size_t idx,
   return std::move(rel_path);
 }
 
-static SupportFileList
-ParseSupportFilesFromPrologue(const lldb::ModuleSP &module,
-                              const llvm::DWARFDebugLine::Prologue &prologue,
-                              FileSpec::Style style,
-                              llvm::StringRef compile_dir = {}) {
-  SupportFileList support_files;
-
+static void ParseSupportFilesFromPrologue(
+    SupportFileList &support_files, const lldb::ModuleSP &module,
+    const llvm::DWARFDebugLine::Prologue &prologue, FileSpec::Style style,
+    llvm::StringRef compile_dir = {}) {
   // Handle the case where there are no files first to avoid having to special
   // case this later.
   if (prologue.FileNames.empty())
-    return support_files;
+    return;
 
   // Before DWARF v5, the line table indexes were one based.
   const bool is_one_based = prologue.getVersion() < 5;
@@ -245,18 +242,18 @@ ParseSupportFilesFromPrologue(const lldb::ModuleSP &module,
         if (!source_ref.empty()) {
           /// Wrap a path for an in-DWARF source file. Lazily write it
           /// to disk when Materialize() is called.
-          struct LazyDWARFFile : public LazyFileSpec {
-            LazyDWARFFile(std::string file_name, llvm::StringRef source,
-                          FileSpec::Style style)
-                : file_name(file_name), source(source), style(style) {}
-            std::string file_name;
+          struct LazyDWARFSourceFile : public UnspooledSupportFile {
+            LazyDWARFSourceFile(llvm::StringRef source, FileSpec::Style style)
+                : source(source), style(style) {}
             FileSpec tmp_file;
+            /// The file contents buffer.
             llvm::StringRef source;
+            /// Deletes the temporary file at the end.
             std::unique_ptr<llvm::FileRemover> remover;
             FileSpec::Style style;
 
             /// Write the file contents to a temporary file.
-            const FileSpec &Materialize() override {
+            const FileSpec &Materialize(llvm::StringRef file_name) override {
               if (tmp_file)
                 return tmp_file;
               llvm::SmallString<0> name;
@@ -276,9 +273,9 @@ ParseSupportFilesFromPrologue(const lldb::ModuleSP &module,
               return tmp_file;
             }
           };
-          support_files.Append(FileSpecHolder(
+          support_files.Append(SupportFile(
               FileSpec(*file_path),
-              std::make_shared<LazyDWARFFile>(*file_path, *source, style)));
+              std::make_unique<LazyDWARFSourceFile>(*source, style)));
           continue;
         }
       }
@@ -298,8 +295,6 @@ ParseSupportFilesFromPrologue(const lldb::ModuleSP &module,
     // Unconditionally add an entry, so the indices match up.
     support_files.EmplaceBack(remapped_file, style, checksum);
   }
-
-  return support_files;
 }
 
 void SymbolFileDWARF::Initialize() {
@@ -791,12 +786,13 @@ lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit &dwarf_cu) {
       ModuleSP module_sp(m_objfile_sp->GetModule());
       if (module_sp) {
         auto initialize_cu = [&](const FileSpec &file_spec,
-                                 LanguageType cu_language) {
+                                 LanguageType cu_language,
+                                 SupportFileList &&support_files = {}) {
           BuildCuTranslationTable();
           cu_sp = std::make_shared<CompileUnit>(
               module_sp, &dwarf_cu, file_spec,
               *GetDWARFUnitIndex(dwarf_cu.GetID()), cu_language,
-              eLazyBoolCalculate);
+              eLazyBoolCalculate, std::move(support_files));
 
           dwarf_cu.SetUserData(cu_sp.get());
 
@@ -827,10 +823,8 @@ lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit &dwarf_cu) {
             return false;
           if (support_files.GetSize() == 0)
             return false;
-
           initialize_cu(support_files.GetFileSpecAtIndex(0),
-                        eLanguageTypeUnknown);
-          cu_sp->SetSupportFiles(std::move(support_files));
+                        eLanguageTypeUnknown, std::move(support_files));
           return true;
         };
 
@@ -1085,7 +1079,6 @@ bool SymbolFileDWARF::ParseSupportFiles(CompileUnit &comp_unit,
   if (!ParseSupportFiles(*dwarf_cu, comp_unit.GetModule(), support_files))
     return false;
 
-  comp_unit.SetSupportFiles(support_files);
   return true;
 }
 
@@ -1104,8 +1097,8 @@ bool SymbolFileDWARF::ParseSupportFiles(DWARFUnit &dwarf_cu,
     return false;
 
   std::string comp_dir = dwarf_cu.GetCompilationDirectory().GetPath();
-  support_files = ParseSupportFilesFromPrologue(
-      module, prologue, dwarf_cu.GetPathStyle(), comp_dir);
+  ParseSupportFilesFromPrologue(support_files, module, prologue,
+                                dwarf_cu.GetPathStyle(), comp_dir);
   return true;
 }
 
@@ -1117,10 +1110,12 @@ FileSpec SymbolFileDWARF::GetFile(DWARFUnit &unit, size_t file_idx) {
   }
 
   auto &tu = llvm::cast<DWARFTypeUnit>(unit);
-  return GetTypeUnitSupportFiles(tu).GetFileSpecAtIndex(file_idx);
+  if (const SupportFileList *support_files = GetTypeUnitSupportFiles(tu))
+    return support_files->GetFileSpecAtIndex(file_idx);
+  return {};
 }
 
-const SupportFileList &
+const SupportFileList *
 SymbolFileDWARF::GetTypeUnitSupportFiles(DWARFTypeUnit &tu) {
   static SupportFileList empty_list;
 
@@ -1128,13 +1123,14 @@ SymbolFileDWARF::GetTypeUnitSupportFiles(DWARFTypeUnit &tu) {
   if (offset == DW_INVALID_OFFSET ||
       offset == llvm::DenseMapInfo<dw_offset_t>::getEmptyKey() ||
       offset == llvm::DenseMapInfo<dw_offset_t>::getTombstoneKey())
-    return empty_list;
+    return nullptr;
 
   // Many type units can share a line table, so parse the support file list
   // once, and cache it based on the offset field.
   auto iter_bool = m_type_unit_support_files.try_emplace(offset);
-  SupportFileList &list = iter_bool.first->second;
+  std::unique_ptr<SupportFileList> &list = iter_bool.first->second;
   if (iter_bool.second) {
+    list = std::make_unique<SupportFileList>();
     uint64_t line_table_offset = offset;
     llvm::DWARFDataExtractor data =
         m_context.getOrLoadLineData().GetAsLLVMDWARF();
@@ -1148,14 +1144,13 @@ SymbolFileDWARF::GetTypeUnitSupportFiles(DWARFTypeUnit &tu) {
     };
     ElapsedTime elapsed(m_parse_time);
     llvm::Error error = prologue.parse(data, &line_table_offset, report, ctx);
-    if (error) {
+    if (error)
       report(std::move(error));
-    } else {
-      list = ParseSupportFilesFromPrologue(GetObjectFile()->GetModule(),
-                                           prologue, tu.GetPathStyle());
-    }
+    else
+      ParseSupportFilesFromPrologue(*list, GetObjectFile()->GetModule(),
+                                    prologue, tu.GetPathStyle());
   }
-  return list;
+  return list.get();
 }
 
 bool SymbolFileDWARF::ParseIsOptimized(CompileUnit &comp_unit) {
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
index f4de005af59fb1..26a9502f90aa00 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -489,7 +489,7 @@ class SymbolFileDWARF : public SymbolFileCommon {
 
   void FindDwpSymbolFile();
 
-  const SupportFileList &GetTypeUnitSupportFiles(DWARFTypeUnit &tu);
+  const SupportFileList *GetTypeUnitSupportFiles(DWARFTypeUnit &tu);
 
   void InitializeFirstCodeAddressRecursive(const SectionList &section_list);
 
@@ -529,7 +529,8 @@ class SymbolFileDWARF : public SymbolFileCommon {
   DIEToVariableSP m_die_to_variable_sp;
   DIEToCompilerType m_forward_decl_die_to_compiler_type;
   CompilerTypeToDIE m_forward_decl_compiler_type_to_die;
-  llvm::DenseMap<dw_offset_t, SupportFileList> m_type_unit_support_files;
+  llvm::DenseMap<dw_offset_t, std::unique_ptr<SupportFileList>>
+      m_type_unit_support_files;
   std::vector<uint32_t> m_lldb_cu_to_dwarf_unit;
   /// DWARF does not provide a good way for traditional (concatenating) linkers
   /// to invalidate debug info describing dead-stripped code. These linkers will
diff --git a/lldb/source/Symbol/CompileUnit.cpp b/lldb/source/Symbol/CompileUnit.cpp
index 6ba3e0d7bd909c..a6b6c8e57eec01 100644
--- a/lldb/source/Symbol/CompileUnit.cpp
+++ b/lldb/source/Symbol/CompileUnit.cpp
@@ -28,10 +28,11 @@ CompileUnit::CompileUnit(const lldb::ModuleSP &module_sp, void *user_data,
 CompileUnit::CompileUnit(const lldb::ModuleSP &module_sp, void *user_data,
                          const FileSpec &fspec, const lldb::user_id_t cu_sym_id,
                          lldb::LanguageType language,
-                         lldb_private::LazyBool is_optimized)
+                         lldb_private::LazyBool is_optimized,
+                         SupportFileList &&support_files)
     : ModuleChild(module_sp), UserID(cu_sym_id), m_user_data(user_data),
       m_language(language), m_flags(0), m_file_spec(fspec),
-      m_is_optimized(is_optimized) {
+      m_support_files(std::move(support_files)), m_is_optimized(is_optimized) {
   if (language != eLanguageTypeUnknown)
     m_flags.Set(flagsParsedLanguage);
   assert(module_sp);
@@ -178,10 +179,6 @@ void CompileUnit::SetLineTable(LineTable *line_table) {
   m_line_table_up.reset(line_table);
 }
 
-void CompileUnit::SetSupportFiles(SupportFileList support_files) {
-  m_support_files = std::move(support_files);
-}
-
 DebugMacros *CompileUnit::GetDebugMacros() {
   if (m_debug_macros_sp.get() == nullptr) {
     if (m_flags.IsClear(flagsParsedDebugMacros)) {
diff --git a/lldb/source/Utility/FileSpecList.cpp b/lldb/source/Utility/FileSpecList.cpp
index 3c1d41bc846d9a..67266808412a79 100644
--- a/lldb/source/Utility/FileSpecList.cpp
+++ b/lldb/source/Utility/FileSpecList.cpp
@@ -40,8 +40,8 @@ bool FileSpecList::AppendIfUnique(const FileSpec &file_spec) {
 // FIXME: Replace this with a DenseSet at the call site. It is inefficient.
 bool SupportFileList::AppendIfUnique(const FileSpec &file_spec) {
   collection::iterator end = m_files.end();
-  if (find_if(m_files.begin(), end, [&](const FileSpecHolder &holder) {
-        return holder.GetSpecOnly() == file_spec;
+  if (find_if(m_files.begin(), end, [&](const SupportFile &support_file) {
+        return support_file.GetSpecOnly() == file_spec;
       }) == end) {
     m_files.push_back(file_spec);
     return true;
@@ -49,16 +49,6 @@ bool SupportFileList::AppendIfUnique(const FileSpec &file_spec) {
   return false;
 }
 
-// FIXME: Replace this with a DenseSet at the call site. It is inefficient.
-bool SupportFileList::AppendIfUnique(const FileSpecHolder &holder) {
-  collection::iterator end = m_files.end();
-  if (find(m_files.begin(), end, holder) == end) {
-    m_files.push_back(holder);
-    return true;
-  }
-  return false;
-}
-
 // Clears the file list.
 void FileSpecList::Clear() { m_files.clear(); }
 
diff --git a/lldb/unittests/Expression/CppModuleConfigurationTest.cpp b/lldb/unittests/Expression/CppModuleConfigurationTest.cpp
index 3c395938f1af86..c01e1c1c70d34d 100644
--- a/lldb/unittests/Expression/CppModuleConfigurationTest.cpp
+++ b/lldb/unittests/Expression/CppModuleConfigurationTest.cpp
@@ -37,10 +37,10 @@ struct CppModuleConfigurationTest : public testing::Test {
   }
 
   /// Utility function turning a list of paths into a FileSpecList.
-  SupportFileList makeFiles(llvm::ArrayRef<std::string> paths) {
-    SupportFileList result;
+  std::unique_ptr<SupportFileList> makeFiles(llvm::ArrayRef<std::string> paths) {
+    auto result = std::make_unique<SupportFileList>();
     for (const std::string &path : paths) {
-      result.Append(FileSpec(path, FileSpec::Style::posix));
+      result->Append(FileSpec(path, FileSpec::Style::posix));
       if (!m_fs->addFileNoOwn(path, static_cast<time_t>(0), m_empty_buffer))
         llvm_unreachable("Invalid test configuration?");
     }
@@ -67,7 +67,8 @@ TEST_F(CppModuleConfigurationTest, Linux) {
                                     // C++ library
                                     libcpp + "/vector",
                                     libcpp + "/module.modulemap"};
-  CppModuleConfiguration config(makeFiles(files), llvm::Triple());
+  auto support_files = makeFiles(files);
+  CppModuleConfiguration config(*support_files, llvm::Triple());
   EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std"));
   EXPECT_THAT(config.GetIncludeDirs(),
               testing::ElementsAre(libcpp, ResourceInc(), usr));
@@ -85,7 +86,8 @@ TEST_F(CppModuleConfigurationTest, LinuxTargetSpecificInclude) {
       usr + "/stdio.h", usr_target + "/sys/cdefs.h",
       // C++ library
       libcpp + "/vector", libcpp + "/module.modulemap"};
-  CppModuleConfiguration config(makeFiles(files),
+  auto support_files = makeFiles(files);
+  CppModuleConfiguration config(*support_files,
                                 llvm::Triple("x86_64-unknown-linux-gnu"));
   EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std"));
   EXPECT_THAT(config.GetIncludeDirs(),
@@ -103,7 +105,8 @@ TEST_F(CppModuleConfigurationTest, Sysroot) {
                                     // C++ library
                                     libcpp + "/vector",
                                     libcpp + "/module.modulemap"};
-  CppModuleConfiguration config(makeFiles(files), llvm::Triple());
+  auto support_files = makeFiles(files);
+  CppModuleConfiguration config(*support_files, llvm::Triple());
   EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std"));
   EXPECT_THAT(config.GetIncludeDirs(),
               testing::ElementsAre(libcpp, ResourceInc(), usr));
@@ -119,7 +122,8 @@ TEST_F(CppModuleConfigurationTest, LinuxLocalLibCpp) {
                                     // C++ library
                                     libcpp + "/vector",
                                     libcpp + "/module.modulemap"};
-  CppModuleConfiguration config(makeFiles(files), llvm::Triple());
+  auto support_files = makeFiles(files);
+  CppModuleConfiguration config(*support_files, llvm::Triple());
   EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std"));
   EXPECT_THAT(config.GetIncludeDirs(),
               testing::ElementsAre(libcpp, ResourceInc(), usr));
@@ -137,7 +141,8 @@ TEST_F(CppModuleConfigurationTest, UnrelatedLibrary) {
                                     // C++ library
                                     libcpp + "/vector",
                                     libcpp + "/module.modulemap"};
-  CppModuleConfiguration config(makeFiles(files), llvm::Triple());
+  auto support_files = makeFiles(files);
+  CppModuleConfiguration config(*support_files, llvm::Triple());
   EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std"));
   EXPECT_THAT(config.GetIncludeDirs(),
               testing::ElementsAre(libcpp, ResourceInc(), usr));
@@ -157,7 +162,8 @@ TEST_F(CppModuleConfigurationTest, UnrelatedLibraryWithTargetSpecificInclude) {
                                     // C++ library
                                     libcpp + "/vector",
                                     libcpp + "/module.modulemap"};
-  CppModuleConfiguration config(makeFiles(files),
+  auto support_files = makeFiles(files);
+  CppModuleConfiguration config(*support_files,
                                 llvm::Triple("x86_64-unknown-linux-gnu"));
   EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std"));
   EXPECT_THAT(config.GetIncludeDirs(),
@@ -178,7 +184,8 @@ TEST_F(CppModuleConfigurationTest, Xcode) {
       libcpp + "/vector",
       libcpp + "/module.modulemap",
   };
-  CppModuleConfiguration config(makeFiles(files), llvm::Triple());
+  auto support_files = makeFiles(files);
+  CppModuleConfiguration config(*support_files, llvm::Triple());
   EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std"));
   EXPECT_THAT(config.GetIncludeDirs(),
               testing::ElementsAre(libcpp, ResourceInc(), usr));
@@ -193,7 +200,8 @@ TEST_F(CppModuleConfigurationTest, LibCppV2) {
                                     // C++ library
                                     libcpp + "/vector",
                                     libcpp + "/module.modulemap"};
-  CppModuleConfiguration config(makeFiles(files), llvm::Triple());
+  auto support_files = makeFiles(files);
+  CppModuleConfiguration config(*support_files, llvm::Triple());
   EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std"));
   EXPECT_THAT(config.GetIncludeDirs(),
               testing::ElementsAre("/usr/include/c++/v2", ResourceInc(),
@@ -211,7 +219,8 @@ TEST_F(CppModuleConfigurationTest, UnknownLibCppFile) {
                                     libcpp + "/non_existing_file",
                                     libcpp + "/module.modulemap",
                                     libcpp + "/vector"};
-  CppModuleConfiguration config(makeFiles(files), llvm::Triple());
+  auto support_files = makeFiles(files);
+  CppModuleConfiguration config(*support_files, llvm::Triple());
   EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std"));
   EXPECT_THAT(config.GetIncludeDirs(),
               testing::ElementsAre("/usr/include/c++/v1", ResourceInc(),
@@ -225,7 +234,8 @@ TEST_F(CppModuleConfigurationTest, MissingUsrInclude) {
   std::vector<std::string> files = {// C++ library
                                     libcpp + "/vector",
                                     libcpp + "/module.modulemap"};
-  CppModuleConfiguration config(makeFiles(files), llvm::Triple());
+  auto support_files = makeFiles(files);
+  CppModuleConfiguration config(*support_files, llvm::Triple());
   EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre());
   EXPECT_THAT(config.GetIncludeDirs(), testing::ElementsAre());
 }
@@ -238,7 +248,8 @@ TEST_F(CppModuleConfigurationTest, MissingLibCpp) {
       // C library
       usr + "/stdio.h",
   };
-  CppModuleConfiguration config(makeFiles(files), llvm::Triple());
+  auto support_files = makeFiles(files);
+  CppModuleConfiguration config(*support_files, llvm::Triple());
   EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre());
   EXPECT_THAT(config.GetIncludeDirs(), testing::ElementsAre());
 }
@@ -253,7 +264,8 @@ TEST_F(CppModuleConfigurationTest, IgnoreLibStdCpp) {
       // C++ library
       usr + "/c++/8.0.1/vector",
   };
-  CppModuleConfiguration config(makeFiles(files), llvm::Triple());
+  auto support_files = makeFiles(files);
+  CppModuleConfiguration config(*support_files, llvm::Triple());
   EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre());
   EXPECT_THAT(config.GetIncludeDirs(), testing::ElementsAre());
 }
@@ -274,7 +286,8 @@ TEST_F(CppModuleConfigurationTest, AmbiguousCLib) {
       libcpp + "/vector",
       libcpp + "/module.modulemap",
   };
-  CppModuleConfiguration config(makeFiles(files), llvm::Triple());
+  auto support_files = makeFiles(files);
+  CppModuleConfiguration config(*support_files, llvm::Triple());
   EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre());
   EXPECT_THAT(config.GetIncludeDirs(), testing::ElementsAre());
 }
@@ -296,7 +309,8 @@ TEST_F(CppModuleConfigurationTest, AmbiguousLibCpp) {
       libcpp2 + "/vector",
       libcpp2 + "/module.modulemap",
   };
-  CppModuleConfiguration config(makeFiles(files), llvm::Triple());
+  auto support_files = makeFiles(files);
+  CppModuleConfiguration config(*support_files, llvm::Triple());
   EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre());
   EXPECT_THAT(config.GetIncludeDirs(), testing::ElementsAre());
 }



More information about the lldb-commits mailing list