Add support for inline DWARF source files. (#75880)

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.

rdar://110926168
This commit is contained in:
Adrian Prantl 2024-01-04 09:04:05 -08:00 committed by GitHub
parent a7a78fd427
commit 917b404e2c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 335 additions and 123 deletions

View File

@ -112,10 +112,13 @@ public:
/// the compile unit is optimized will be made when /// the compile unit is optimized will be made when
/// CompileUnit::GetIsOptimized() is called. /// CompileUnit::GetIsOptimized() is called.
/// ///
/// \param[in] support_files
/// An rvalue list of already parsed support files.
/// \see lldb::LanguageType /// \see lldb::LanguageType
CompileUnit(const lldb::ModuleSP &module_sp, void *user_data, CompileUnit(const lldb::ModuleSP &module_sp, void *user_data,
const FileSpec &file_spec, lldb::user_id_t uid, 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. /// Add a function to this compile unit.
/// ///
@ -226,6 +229,9 @@ public:
/// Return the primary source file associated with this compile unit. /// Return the primary source file associated with this compile unit.
const FileSpec &GetPrimaryFile() const { return m_file_spec; } 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. /// Get the line table for the compile unit.
/// ///
/// Called by clients and the SymbolFile plug-in. The SymbolFile plug-ins /// Called by clients and the SymbolFile plug-in. The SymbolFile plug-ins
@ -265,7 +271,13 @@ public:
/// ///
/// \return /// \return
/// A support file list object. /// A support file list object.
const FileSpecList &GetSupportFiles(); 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. /// Get the compile unit's imported module list.
/// ///
@ -331,8 +343,6 @@ public:
/// A line table object pointer that this object now owns. /// A line table object pointer that this object now owns.
void SetLineTable(LineTable *line_table); void SetLineTable(LineTable *line_table);
void SetSupportFiles(FileSpecList support_files);
void SetDebugMacros(const DebugMacrosSP &debug_macros); void SetDebugMacros(const DebugMacrosSP &debug_macros);
/// Set accessor for the variable list. /// Set accessor for the variable list.
@ -410,9 +420,8 @@ protected:
std::vector<SourceModule> m_imported_modules; std::vector<SourceModule> m_imported_modules;
/// The primary file associated with this compile unit. /// The primary file associated with this compile unit.
FileSpec m_file_spec; FileSpec m_file_spec;
/// Files associated with this compile unit's line table and /// Files associated with this compile unit's line table and declarations.
/// declarations. SupportFileList m_support_files;
FileSpecList m_support_files;
/// Line table that will get parsed on demand. /// Line table that will get parsed on demand.
std::unique_ptr<LineTable> m_line_table_up; std::unique_ptr<LineTable> m_line_table_up;
/// Debug macros that will get parsed on demand. /// Debug macros that will get parsed on demand.

View File

@ -197,7 +197,7 @@ public:
return false; return false;
} }
virtual bool ParseSupportFiles(CompileUnit &comp_unit, virtual bool ParseSupportFiles(CompileUnit &comp_unit,
FileSpecList &support_files) = 0; SupportFileList &support_files) = 0;
virtual size_t ParseTypes(CompileUnit &comp_unit) = 0; virtual size_t ParseTypes(CompileUnit &comp_unit) = 0;
virtual bool ParseIsOptimized(CompileUnit &comp_unit) { return false; } virtual bool ParseIsOptimized(CompileUnit &comp_unit) { return false; }

View File

@ -81,7 +81,7 @@ public:
llvm::function_ref<bool(lldb_private::Module &)>) override; llvm::function_ref<bool(lldb_private::Module &)>) override;
bool ParseSupportFiles(lldb_private::CompileUnit &comp_unit, 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; bool ParseIsOptimized(lldb_private::CompileUnit &comp_unit) override;

View File

@ -17,6 +17,86 @@
namespace lldb_private { namespace lldb_private {
class Stream; class Stream;
/// Wraps either a FileSpec that represents a local file or 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
/// file yet.
class SupportFile {
protected:
FileSpec m_file_spec;
public:
SupportFile(const FileSpec &spec) : m_file_spec(spec) {}
SupportFile(const SupportFile &other) = delete;
SupportFile(SupportFile &&other) = default;
virtual ~SupportFile() = 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.
virtual const FileSpec &Materialize() { return m_file_spec; }
};
/// A list of support files for a CompileUnit.
class SupportFileList {
public:
SupportFileList(){};
SupportFileList(const SupportFileList &) = delete;
SupportFileList(SupportFileList &&other) = default;
typedef std::vector<std::unique_ptr<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(std::make_unique<SupportFile>(file));
}
void Append(std::unique_ptr<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);
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.push_back(
std::make_unique<SupportFile>(FileSpec(std::forward<Args>(args)...)));
}
protected:
collection m_files; ///< A collection of FileSpec objects.
};
/// \class FileSpecList FileSpecList.h "lldb/Utility/FileSpecList.h" /// \class FileSpecList FileSpecList.h "lldb/Utility/FileSpecList.h"
/// A file collection class. /// A file collection class.
/// ///
@ -114,32 +194,6 @@ public:
/// else UINT32_MAX is returned. /// else UINT32_MAX is returned.
size_t FindFileIndex(size_t idx, const FileSpec &file, bool full) 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;
/// Get file at index. /// Get file at index.
/// ///
/// Gets a file from the file list. If \a idx is not a valid index, an empty /// Gets a file from the file list. If \a idx is not a valid index, an empty

View File

@ -171,7 +171,7 @@ uint32_t SBCompileUnit::FindSupportFileIndex(uint32_t start_idx,
LLDB_INSTRUMENT_VA(this, start_idx, sb_file, full); LLDB_INSTRUMENT_VA(this, start_idx, sb_file, full);
if (m_opaque_ptr) { 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 support_files.FindFileIndex(start_idx, sb_file.ref(), full);
} }
return 0; return 0;

View File

@ -204,7 +204,7 @@ protected:
if (cu) { if (cu) {
assert(file_spec.GetFilename().AsCString()); assert(file_spec.GetFilename().AsCString());
bool has_path = (file_spec.GetDirectory().AsCString() != nullptr); 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); size_t file_idx = cu_file_list.FindFileIndex(0, file_spec, has_path);
if (file_idx != UINT32_MAX) { if (file_idx != UINT32_MAX) {
// Update the file to how it appears in the CU. // Update the file to how it appears in the CU.

View File

@ -164,7 +164,7 @@ void ModuleListProperties::UpdateSymlinkMappings() {
llvm::sys::ScopedWriter lock(m_symlink_paths_mutex); llvm::sys::ScopedWriter lock(m_symlink_paths_mutex);
const bool notify = false; const bool notify = false;
m_symlink_paths.Clear(notify); m_symlink_paths.Clear(notify);
for (FileSpec symlink : list) { for (auto symlink : list) {
FileSpec resolved; FileSpec resolved;
Status status = FileSystem::Instance().Readlink(symlink, resolved); Status status = FileSystem::Instance().Readlink(symlink, resolved);
if (status.Success()) if (status.Success())

View File

@ -488,18 +488,18 @@ CppModuleConfiguration GetModuleConfig(lldb::LanguageType language,
// Build a list of files we need to analyze to build the configuration. // Build a list of files we need to analyze to build the configuration.
FileSpecList files; FileSpecList files;
for (const FileSpec &f : sc.comp_unit->GetSupportFiles()) 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 // 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. // contain the support files for libc++ and the C library.
llvm::DenseSet<SymbolFile *> visited_symbol_files; llvm::DenseSet<SymbolFile *> visited_symbol_files;
sc.comp_unit->ForEachExternalModule( sc.comp_unit->ForEachExternalModule(
visited_symbol_files, [&files](Module &module) { visited_symbol_files, [&files](Module &module) {
for (std::size_t i = 0; i < module.GetNumCompileUnits(); ++i) { for (std::size_t i = 0; i < module.GetNumCompileUnits(); ++i) {
const FileSpecList &support_files = const SupportFileList &support_files =
module.GetCompileUnitAtIndex(i)->GetSupportFiles(); module.GetCompileUnitAtIndex(i)->GetSupportFiles();
for (const FileSpec &f : support_files) { for (auto &f : support_files) {
files.AppendIfUnique(f); files.AppendIfUnique(f->Materialize());
} }
} }
return false; return false;
@ -508,7 +508,7 @@ CppModuleConfiguration GetModuleConfig(lldb::LanguageType language,
LLDB_LOG(log, "[C++ module config] Found {0} support files to analyze", LLDB_LOG(log, "[C++ module config] Found {0} support files to analyze",
files.GetSize()); files.GetSize());
if (log && log->GetVerbose()) { if (log && log->GetVerbose()) {
for (const FileSpec &f : files) for (auto &f : files)
LLDB_LOGV(log, "[C++ module config] Analyzing support file: {0}", LLDB_LOGV(log, "[C++ module config] Analyzing support file: {0}",
f.GetPath()); f.GetPath());
} }

View File

@ -134,9 +134,9 @@ bool CppModuleConfiguration::hasValidConfig() {
CppModuleConfiguration::CppModuleConfiguration( CppModuleConfiguration::CppModuleConfiguration(
const FileSpecList &support_files, const llvm::Triple &triple) { const FileSpecList &support_files, const llvm::Triple &triple) {
// Analyze all files we were given to build the configuration. // Analyze all files we were given to build the configuration.
bool error = !llvm::all_of(support_files, bool error = !llvm::all_of(support_files, [&](auto &file) {
std::bind(&CppModuleConfiguration::analyzeFile, return CppModuleConfiguration::analyzeFile(file, triple);
this, std::placeholders::_1, triple)); });
// If we have a valid configuration at this point, set the // If we have a valid configuration at this point, set the
// include directories and module list that should be used. // include directories and module list that should be used.
if (!error && hasValidConfig()) { if (!error && hasValidConfig()) {

View File

@ -278,13 +278,14 @@ bool SymbolFileBreakpad::ParseLineTable(CompileUnit &comp_unit) {
} }
bool SymbolFileBreakpad::ParseSupportFiles(CompileUnit &comp_unit, bool SymbolFileBreakpad::ParseSupportFiles(CompileUnit &comp_unit,
FileSpecList &support_files) { SupportFileList &support_files) {
std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
CompUnitData &data = m_cu_data->GetEntryRef(comp_unit.GetID()).data; CompUnitData &data = m_cu_data->GetEntryRef(comp_unit.GetID()).data;
if (!data.support_files) if (!data.support_files)
ParseLineTableAndSupportFiles(comp_unit, data); ParseLineTableAndSupportFiles(comp_unit, data);
support_files = std::move(*data.support_files); for (auto &fs : *data.support_files)
support_files.Append(fs);
return true; return true;
} }

View File

@ -73,7 +73,7 @@ public:
bool ParseDebugMacros(CompileUnit &comp_unit) override { return false; } bool ParseDebugMacros(CompileUnit &comp_unit) override { return false; }
bool ParseSupportFiles(CompileUnit &comp_unit, bool ParseSupportFiles(CompileUnit &comp_unit,
FileSpecList &support_files) override; SupportFileList &support_files) override;
size_t ParseTypes(CompileUnit &cu) override { return 0; } size_t ParseTypes(CompileUnit &cu) override { return 0; }
bool ParseImportedModules( bool ParseImportedModules(
@ -195,7 +195,6 @@ private:
Bookmark bookmark; Bookmark bookmark;
std::optional<FileSpecList> support_files; std::optional<FileSpecList> support_files;
std::unique_ptr<LineTable> line_table_up; std::unique_ptr<LineTable> line_table_up;
}; };
uint32_t CalculateNumCompileUnits() override; uint32_t CalculateNumCompileUnits() override;

View File

@ -66,7 +66,7 @@ public:
bool ParseDebugMacros(CompileUnit &comp_unit) override { return false; } bool ParseDebugMacros(CompileUnit &comp_unit) override { return false; }
bool ParseSupportFiles(CompileUnit &comp_unit, bool ParseSupportFiles(CompileUnit &comp_unit,
FileSpecList &support_files) override { SupportFileList &support_files) override {
return false; return false;
} }

View File

@ -10,6 +10,7 @@
#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h" #include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
#include "llvm/Support/Casting.h" #include "llvm/Support/Casting.h"
#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/Format.h" #include "llvm/Support/Format.h"
#include "llvm/Support/Threading.h" #include "llvm/Support/Threading.h"
@ -209,17 +210,14 @@ GetFileByIndex(const llvm::DWARFDebugLine::Prologue &prologue, size_t idx,
return std::move(rel_path); return std::move(rel_path);
} }
static FileSpecList static void ParseSupportFilesFromPrologue(
ParseSupportFilesFromPrologue(const lldb::ModuleSP &module, SupportFileList &support_files, const lldb::ModuleSP &module,
const llvm::DWARFDebugLine::Prologue &prologue, const llvm::DWARFDebugLine::Prologue &prologue, FileSpec::Style style,
FileSpec::Style style, llvm::StringRef compile_dir = {}) {
llvm::StringRef compile_dir = {}) {
FileSpecList support_files;
// Handle the case where there are no files first to avoid having to special // Handle the case where there are no files first to avoid having to special
// case this later. // case this later.
if (prologue.FileNames.empty()) if (prologue.FileNames.empty())
return support_files; return;
// Before DWARF v5, the line table indexes were one based. // Before DWARF v5, the line table indexes were one based.
const bool is_one_based = prologue.getVersion() < 5; const bool is_one_based = prologue.getVersion() < 5;
@ -235,6 +233,53 @@ ParseSupportFilesFromPrologue(const lldb::ModuleSP &module,
for (size_t idx = first_file_idx; idx <= last_file_idx; ++idx) { for (size_t idx = first_file_idx; idx <= last_file_idx; ++idx) {
std::string remapped_file; std::string remapped_file;
if (auto file_path = GetFileByIndex(prologue, idx, compile_dir, style)) { 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 LazyDWARFSourceFile : public SupportFile {
LazyDWARFSourceFile(const FileSpec &fs, llvm::StringRef source,
FileSpec::Style style)
: SupportFile(fs), 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 {
if (tmp_file)
return tmp_file;
llvm::SmallString<0> name;
int fd;
auto orig_name = m_file_spec.GetFilename().GetStringRef();
auto ec = llvm::sys::fs::createTemporaryFile(
"", llvm::sys::path::filename(orig_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(std::make_unique<LazyDWARFSourceFile>(
FileSpec(*file_path), *source, style));
continue;
}
}
if (auto remapped = module->RemapSourceFile(llvm::StringRef(*file_path))) if (auto remapped = module->RemapSourceFile(llvm::StringRef(*file_path)))
remapped_file = *remapped; remapped_file = *remapped;
else else
@ -251,8 +296,6 @@ ParseSupportFilesFromPrologue(const lldb::ModuleSP &module,
// Unconditionally add an entry, so the indices match up. // Unconditionally add an entry, so the indices match up.
support_files.EmplaceBack(remapped_file, style, checksum); support_files.EmplaceBack(remapped_file, style, checksum);
} }
return support_files;
} }
void SymbolFileDWARF::Initialize() { void SymbolFileDWARF::Initialize() {
@ -744,12 +787,13 @@ lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit &dwarf_cu) {
ModuleSP module_sp(m_objfile_sp->GetModule()); ModuleSP module_sp(m_objfile_sp->GetModule());
if (module_sp) { if (module_sp) {
auto initialize_cu = [&](const FileSpec &file_spec, auto initialize_cu = [&](const FileSpec &file_spec,
LanguageType cu_language) { LanguageType cu_language,
SupportFileList &&support_files = {}) {
BuildCuTranslationTable(); BuildCuTranslationTable();
cu_sp = std::make_shared<CompileUnit>( cu_sp = std::make_shared<CompileUnit>(
module_sp, &dwarf_cu, file_spec, module_sp, &dwarf_cu, file_spec,
*GetDWARFUnitIndex(dwarf_cu.GetID()), cu_language, *GetDWARFUnitIndex(dwarf_cu.GetID()), cu_language,
eLazyBoolCalculate); eLazyBoolCalculate, std::move(support_files));
dwarf_cu.SetUserData(cu_sp.get()); dwarf_cu.SetUserData(cu_sp.get());
@ -775,15 +819,13 @@ lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit &dwarf_cu) {
// file is also the name of the compile unit. This // file is also the name of the compile unit. This
// allows us to avoid loading the non-skeleton unit, // allows us to avoid loading the non-skeleton unit,
// which may be in a separate DWO file. // which may be in a separate DWO file.
FileSpecList support_files; SupportFileList support_files;
if (!ParseSupportFiles(dwarf_cu, module_sp, support_files)) if (!ParseSupportFiles(dwarf_cu, module_sp, support_files))
return false; return false;
if (support_files.GetSize() == 0) if (support_files.GetSize() == 0)
return false; return false;
initialize_cu(support_files.GetFileSpecAtIndex(0), initialize_cu(support_files.GetFileSpecAtIndex(0),
eLanguageTypeUnknown); eLanguageTypeUnknown, std::move(support_files));
cu_sp->SetSupportFiles(std::move(support_files));
return true; return true;
}; };
@ -1029,7 +1071,7 @@ bool SymbolFileDWARF::ForEachExternalModule(
} }
bool SymbolFileDWARF::ParseSupportFiles(CompileUnit &comp_unit, bool SymbolFileDWARF::ParseSupportFiles(CompileUnit &comp_unit,
FileSpecList &support_files) { SupportFileList &support_files) {
std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
DWARFUnit *dwarf_cu = GetDWARFCompileUnit(&comp_unit); DWARFUnit *dwarf_cu = GetDWARFCompileUnit(&comp_unit);
if (!dwarf_cu) if (!dwarf_cu)
@ -1038,13 +1080,12 @@ bool SymbolFileDWARF::ParseSupportFiles(CompileUnit &comp_unit,
if (!ParseSupportFiles(*dwarf_cu, comp_unit.GetModule(), support_files)) if (!ParseSupportFiles(*dwarf_cu, comp_unit.GetModule(), support_files))
return false; return false;
comp_unit.SetSupportFiles(support_files);
return true; return true;
} }
bool SymbolFileDWARF::ParseSupportFiles(DWARFUnit &dwarf_cu, bool SymbolFileDWARF::ParseSupportFiles(DWARFUnit &dwarf_cu,
const ModuleSP &module, const ModuleSP &module,
FileSpecList &support_files) { SupportFileList &support_files) {
dw_offset_t offset = dwarf_cu.GetLineTableOffset(); dw_offset_t offset = dwarf_cu.GetLineTableOffset();
if (offset == DW_INVALID_OFFSET) if (offset == DW_INVALID_OFFSET)
@ -1057,8 +1098,8 @@ bool SymbolFileDWARF::ParseSupportFiles(DWARFUnit &dwarf_cu,
return false; return false;
std::string comp_dir = dwarf_cu.GetCompilationDirectory().GetPath(); std::string comp_dir = dwarf_cu.GetCompilationDirectory().GetPath();
support_files = ParseSupportFilesFromPrologue( ParseSupportFilesFromPrologue(support_files, module, prologue,
module, prologue, dwarf_cu.GetPathStyle(), comp_dir); dwarf_cu.GetPathStyle(), comp_dir);
return true; return true;
} }
@ -1070,24 +1111,27 @@ FileSpec SymbolFileDWARF::GetFile(DWARFUnit &unit, size_t file_idx) {
} }
auto &tu = llvm::cast<DWARFTypeUnit>(unit); 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 FileSpecList & const SupportFileList *
SymbolFileDWARF::GetTypeUnitSupportFiles(DWARFTypeUnit &tu) { SymbolFileDWARF::GetTypeUnitSupportFiles(DWARFTypeUnit &tu) {
static FileSpecList empty_list; static SupportFileList empty_list;
dw_offset_t offset = tu.GetLineTableOffset(); dw_offset_t offset = tu.GetLineTableOffset();
if (offset == DW_INVALID_OFFSET || if (offset == DW_INVALID_OFFSET ||
offset == llvm::DenseMapInfo<dw_offset_t>::getEmptyKey() || offset == llvm::DenseMapInfo<dw_offset_t>::getEmptyKey() ||
offset == llvm::DenseMapInfo<dw_offset_t>::getTombstoneKey()) 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 // Many type units can share a line table, so parse the support file list
// once, and cache it based on the offset field. // once, and cache it based on the offset field.
auto iter_bool = m_type_unit_support_files.try_emplace(offset); auto iter_bool = m_type_unit_support_files.try_emplace(offset);
FileSpecList &list = iter_bool.first->second; std::unique_ptr<SupportFileList> &list = iter_bool.first->second;
if (iter_bool.second) { if (iter_bool.second) {
list = std::make_unique<SupportFileList>();
uint64_t line_table_offset = offset; uint64_t line_table_offset = offset;
llvm::DWARFDataExtractor data = llvm::DWARFDataExtractor data =
m_context.getOrLoadLineData().GetAsLLVMDWARF(); m_context.getOrLoadLineData().GetAsLLVMDWARF();
@ -1101,14 +1145,13 @@ SymbolFileDWARF::GetTypeUnitSupportFiles(DWARFTypeUnit &tu) {
}; };
ElapsedTime elapsed(m_parse_time); ElapsedTime elapsed(m_parse_time);
llvm::Error error = prologue.parse(data, &line_table_offset, report, ctx); llvm::Error error = prologue.parse(data, &line_table_offset, report, ctx);
if (error) { if (error)
report(std::move(error)); report(std::move(error));
} else { else
list = ParseSupportFilesFromPrologue(GetObjectFile()->GetModule(), ParseSupportFilesFromPrologue(*list, GetObjectFile()->GetModule(),
prologue, tu.GetPathStyle()); prologue, tu.GetPathStyle());
}
} }
return list; return list.get();
} }
bool SymbolFileDWARF::ParseIsOptimized(CompileUnit &comp_unit) { bool SymbolFileDWARF::ParseIsOptimized(CompileUnit &comp_unit) {

View File

@ -123,7 +123,7 @@ public:
llvm::function_ref<bool(Module &)>) override; llvm::function_ref<bool(Module &)>) override;
bool ParseSupportFiles(CompileUnit &comp_unit, bool ParseSupportFiles(CompileUnit &comp_unit,
FileSpecList &support_files) override; SupportFileList &support_files) override;
bool ParseIsOptimized(CompileUnit &comp_unit) override; bool ParseIsOptimized(CompileUnit &comp_unit) override;
@ -396,7 +396,7 @@ protected:
bool *type_is_new); bool *type_is_new);
bool ParseSupportFiles(DWARFUnit &dwarf_cu, const lldb::ModuleSP &module, bool ParseSupportFiles(DWARFUnit &dwarf_cu, const lldb::ModuleSP &module,
FileSpecList &support_files); SupportFileList &support_files);
lldb::VariableSP ParseVariableDIE(const SymbolContext &sc, lldb::VariableSP ParseVariableDIE(const SymbolContext &sc,
const DWARFDIE &die, const DWARFDIE &die,
@ -489,7 +489,7 @@ protected:
void FindDwpSymbolFile(); void FindDwpSymbolFile();
const FileSpecList &GetTypeUnitSupportFiles(DWARFTypeUnit &tu); const SupportFileList *GetTypeUnitSupportFiles(DWARFTypeUnit &tu);
void InitializeFirstCodeAddressRecursive(const SectionList &section_list); void InitializeFirstCodeAddressRecursive(const SectionList &section_list);
@ -529,7 +529,8 @@ protected:
DIEToVariableSP m_die_to_variable_sp; DIEToVariableSP m_die_to_variable_sp;
DIEToCompilerType m_forward_decl_die_to_compiler_type; DIEToCompilerType m_forward_decl_die_to_compiler_type;
CompilerTypeToDIE m_forward_decl_compiler_type_to_die; CompilerTypeToDIE m_forward_decl_compiler_type_to_die;
llvm::DenseMap<dw_offset_t, FileSpecList> 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; std::vector<uint32_t> m_lldb_cu_to_dwarf_unit;
/// DWARF does not provide a good way for traditional (concatenating) linkers /// DWARF does not provide a good way for traditional (concatenating) linkers
/// to invalidate debug info describing dead-stripped code. These linkers will /// to invalidate debug info describing dead-stripped code. These linkers will

View File

@ -725,8 +725,8 @@ bool SymbolFileDWARFDebugMap::ForEachExternalModule(
return false; return false;
} }
bool SymbolFileDWARFDebugMap::ParseSupportFiles(CompileUnit &comp_unit, bool SymbolFileDWARFDebugMap::ParseSupportFiles(
FileSpecList &support_files) { CompileUnit &comp_unit, SupportFileList &support_files) {
std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
SymbolFileDWARF *oso_dwarf = GetSymbolFile(comp_unit); SymbolFileDWARF *oso_dwarf = GetSymbolFile(comp_unit);
if (oso_dwarf) if (oso_dwarf)

View File

@ -74,7 +74,7 @@ public:
llvm::function_ref<bool(Module &)>) override; llvm::function_ref<bool(Module &)>) override;
bool ParseSupportFiles(CompileUnit &comp_unit, bool ParseSupportFiles(CompileUnit &comp_unit,
FileSpecList &support_files) override; SupportFileList &support_files) override;
bool ParseIsOptimized(CompileUnit &comp_unit) override; bool ParseIsOptimized(CompileUnit &comp_unit) override;

View File

@ -59,7 +59,7 @@ public:
bool ParseDebugMacros(CompileUnit &comp_unit) override { return false; } bool ParseDebugMacros(CompileUnit &comp_unit) override { return false; }
bool ParseSupportFiles(CompileUnit &comp_unit, bool ParseSupportFiles(CompileUnit &comp_unit,
FileSpecList &support_files) override { SupportFileList &support_files) override {
return false; return false;
} }

View File

@ -1369,7 +1369,7 @@ SymbolFileNativePDB::GetFileIndex(const CompilandIndexItem &cii,
} }
bool SymbolFileNativePDB::ParseSupportFiles(CompileUnit &comp_unit, bool SymbolFileNativePDB::ParseSupportFiles(CompileUnit &comp_unit,
FileSpecList &support_files) { SupportFileList &support_files) {
std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
PdbSymUid cu_id(comp_unit.GetID()); PdbSymUid cu_id(comp_unit.GetID());
lldbassert(cu_id.kind() == PdbSymUidKind::Compiland); lldbassert(cu_id.kind() == PdbSymUidKind::Compiland);
@ -1416,7 +1416,7 @@ void SymbolFileNativePDB::ParseInlineSite(PdbCompilandSymId id,
return; return;
InlineeSourceLine inlinee_line = iter->second; InlineeSourceLine inlinee_line = iter->second;
const FileSpecList &files = comp_unit->GetSupportFiles(); const SupportFileList &files = comp_unit->GetSupportFiles();
FileSpec decl_file; FileSpec decl_file;
llvm::Expected<uint32_t> file_index_or_err = llvm::Expected<uint32_t> file_index_or_err =
GetFileIndex(*cii, inlinee_line.Header->FileID); GetFileIndex(*cii, inlinee_line.Header->FileID);

View File

@ -94,7 +94,7 @@ public:
bool ParseDebugMacros(lldb_private::CompileUnit &comp_unit) override; bool ParseDebugMacros(lldb_private::CompileUnit &comp_unit) override;
bool ParseSupportFiles(lldb_private::CompileUnit &comp_unit, bool ParseSupportFiles(lldb_private::CompileUnit &comp_unit,
FileSpecList &support_files) override; SupportFileList &support_files) override;
size_t ParseTypes(lldb_private::CompileUnit &comp_unit) override; size_t ParseTypes(lldb_private::CompileUnit &comp_unit) override;
bool ParseImportedModules( bool ParseImportedModules(

View File

@ -365,7 +365,7 @@ bool SymbolFilePDB::ParseDebugMacros(CompileUnit &comp_unit) {
} }
bool SymbolFilePDB::ParseSupportFiles( 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 // In theory this is unnecessary work for us, because all of this information
// is easily (and quickly) accessible from DebugInfoPDB, so caching it a // is easily (and quickly) accessible from DebugInfoPDB, so caching it a

View File

@ -70,7 +70,7 @@ public:
bool ParseDebugMacros(lldb_private::CompileUnit &comp_unit) override; bool ParseDebugMacros(lldb_private::CompileUnit &comp_unit) override;
bool ParseSupportFiles(lldb_private::CompileUnit &comp_unit, 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; size_t ParseTypes(lldb_private::CompileUnit &comp_unit) override;

View File

@ -211,7 +211,7 @@ bool SymbolFileSymtab::ParseDebugMacros(CompileUnit &comp_unit) {
} }
bool SymbolFileSymtab::ParseSupportFiles(CompileUnit &comp_unit, bool SymbolFileSymtab::ParseSupportFiles(CompileUnit &comp_unit,
FileSpecList &support_files) { SupportFileList &support_files) {
return false; return false;
} }

View File

@ -57,7 +57,7 @@ public:
bool ParseDebugMacros(lldb_private::CompileUnit &comp_unit) override; bool ParseDebugMacros(lldb_private::CompileUnit &comp_unit) override;
bool ParseSupportFiles(lldb_private::CompileUnit &comp_unit, 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; size_t ParseTypes(lldb_private::CompileUnit &comp_unit) override;

View File

@ -28,10 +28,11 @@ CompileUnit::CompileUnit(const lldb::ModuleSP &module_sp, void *user_data,
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, const FileSpec &fspec, const lldb::user_id_t cu_sym_id,
lldb::LanguageType language, 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), : ModuleChild(module_sp), UserID(cu_sym_id), m_user_data(user_data),
m_language(language), m_flags(0), m_file_spec(fspec), 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) if (language != eLanguageTypeUnknown)
m_flags.Set(flagsParsedLanguage); m_flags.Set(flagsParsedLanguage);
assert(module_sp); assert(module_sp);
@ -178,10 +179,6 @@ void CompileUnit::SetLineTable(LineTable *line_table) {
m_line_table_up.reset(line_table); m_line_table_up.reset(line_table);
} }
void CompileUnit::SetSupportFiles(FileSpecList support_files) {
m_support_files = std::move(support_files);
}
DebugMacros *CompileUnit::GetDebugMacros() { DebugMacros *CompileUnit::GetDebugMacros() {
if (m_debug_macros_sp.get() == nullptr) { if (m_debug_macros_sp.get() == nullptr) {
if (m_flags.IsClear(flagsParsedDebugMacros)) { if (m_flags.IsClear(flagsParsedDebugMacros)) {
@ -213,7 +210,7 @@ VariableListSP CompileUnit::GetVariableList(bool can_create) {
return m_variables; return m_variables;
} }
std::vector<uint32_t> FindFileIndexes(const FileSpecList &files, std::vector<uint32_t> FindFileIndexes(const SupportFileList &files,
const FileSpec &file) { const FileSpec &file) {
std::vector<uint32_t> result; std::vector<uint32_t> result;
uint32_t idx = -1; uint32_t idx = -1;
@ -411,7 +408,7 @@ bool CompileUnit::ForEachExternalModule(
return false; return false;
} }
const FileSpecList &CompileUnit::GetSupportFiles() { const SupportFileList &CompileUnit::GetSupportFiles() {
if (m_support_files.GetSize() == 0) { if (m_support_files.GetSize() == 0) {
if (m_flags.IsClear(flagsParsedSupportFiles)) { if (m_flags.IsClear(flagsParsedSupportFiles)) {
m_flags.Set(flagsParsedSupportFiles); m_flags.Set(flagsParsedSupportFiles);

View File

@ -115,7 +115,7 @@ bool SymbolFileOnDemand::ForEachExternalModule(
} }
bool SymbolFileOnDemand::ParseSupportFiles(CompileUnit &comp_unit, bool SymbolFileOnDemand::ParseSupportFiles(CompileUnit &comp_unit,
FileSpecList &support_files) { SupportFileList &support_files) {
LLDB_LOG(GetLog(), LLDB_LOG(GetLog(),
"[{0}] {1} is not skipped: explicitly allowed to support breakpoint", "[{0}] {1} is not skipped: explicitly allowed to support breakpoint",
GetSymbolFileName(), __FUNCTION__); GetSymbolFileName(), __FUNCTION__);

View File

@ -37,6 +37,19 @@ bool FileSpecList::AppendIfUnique(const FileSpec &file_spec) {
return false; 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 std::unique_ptr<SupportFile> &support_file) {
return support_file->GetSpecOnly() == file_spec;
}) == end) {
Append(file_spec);
return true;
}
return false;
}
// Clears the file list. // Clears the file list.
void FileSpecList::Clear() { m_files.clear(); } void FileSpecList::Clear() { m_files.clear(); }
@ -55,22 +68,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, // Returns the valid index of the file that matches "file_spec" if it is found,
// else std::numeric_limits<uint32_t>::max() is returned. // else std::numeric_limits<uint32_t>::max() is returned.
size_t FileSpecList::FindFileIndex(size_t start_idx, const FileSpec &file_spec, static size_t FindFileIndex(size_t start_idx, const FileSpec &file_spec,
bool full) const { bool full, size_t num_files,
const size_t num_files = m_files.size(); std::function<const FileSpec &(size_t)> get_ith) {
// When looking for files, we will compare only the filename if the FILE_SPEC // When looking for files, we will compare only the filename if the FILE_SPEC
// argument is empty // argument is empty
bool compare_filename_only = file_spec.GetDirectory().IsEmpty(); bool compare_filename_only = file_spec.GetDirectory().IsEmpty();
for (size_t idx = start_idx; idx < num_files; ++idx) { for (size_t idx = start_idx; idx < num_files; ++idx) {
const FileSpec &ith = get_ith(idx);
if (compare_filename_only) { if (compare_filename_only) {
if (ConstString::Equals( if (ConstString::Equals(ith.GetFilename(), file_spec.GetFilename(),
m_files[idx].GetFilename(), file_spec.GetFilename(), file_spec.IsCaseSensitive() ||
file_spec.IsCaseSensitive() || m_files[idx].IsCaseSensitive())) ith.IsCaseSensitive()))
return idx; return idx;
} else { } else {
if (FileSpec::Equal(m_files[idx], file_spec, full)) if (FileSpec::Equal(ith, file_spec, full))
return idx; return idx;
} }
} }
@ -79,8 +92,24 @@ size_t FileSpecList::FindFileIndex(size_t start_idx, const FileSpec &file_spec,
return UINT32_MAX; return UINT32_MAX;
} }
size_t FileSpecList::FindCompatibleIndex(size_t start_idx, size_t FileSpecList::FindFileIndex(size_t start_idx, const FileSpec &file_spec,
const FileSpec &file_spec) const { 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(); const size_t num_files = m_files.size();
if (start_idx >= num_files) if (start_idx >= num_files)
return UINT32_MAX; return UINT32_MAX;
@ -92,7 +121,7 @@ size_t FileSpecList::FindCompatibleIndex(size_t start_idx,
const bool full = !file_spec.GetDirectory().IsEmpty(); const bool full = !file_spec.GetDirectory().IsEmpty();
for (size_t idx = start_idx; idx < num_files; ++idx) { 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 // Always start by matching the filename first
if (!curr_file.FileEquals(file_spec)) if (!curr_file.FileEquals(file_spec))
@ -140,6 +169,13 @@ const FileSpec &FileSpecList::GetFileSpecAtIndex(size_t idx) const {
return 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;
return g_empty_file_spec;
}
// Return the size in bytes that this object takes in memory. This returns the // Return the size in bytes that this object takes in memory. This returns the
// size in bytes of this object's member variables and any FileSpec objects its // size in bytes of this object's member variables and any FileSpec objects its
// member variables contain, the result doesn't not include the string values // member variables contain, the result doesn't not include the string values

View File

@ -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 $@

View File

@ -0,0 +1,15 @@
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()
lldbutil.run_to_name_breakpoint(self, 'f')
self.expect("list f", substrs=["This is inline source code"])

View File

@ -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@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@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)

View File

@ -0,0 +1,7 @@
void f();
void stop() {}
int main(int argc, char const *argv[]) {
f();
return 0;
}

View File

@ -20,7 +20,7 @@ static FileSpec WindowsSpec(llvm::StringRef path) {
return FileSpec(path, FileSpec::Style::windows); return FileSpec(path, FileSpec::Style::windows);
} }
TEST(FileSpecListTest, RelativePathMatchesPosix) { TEST(SupportFileListTest, RelativePathMatchesPosix) {
const FileSpec fullpath = PosixSpec("/build/src/main.cpp"); const FileSpec fullpath = PosixSpec("/build/src/main.cpp");
const FileSpec relative = PosixSpec("./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 rel2_wrong = PosixSpec("asrc/main.cpp");
const FileSpec rel3_wrong = PosixSpec("rc/main.cpp"); const FileSpec rel3_wrong = PosixSpec("rc/main.cpp");
FileSpecList files; SupportFileList files;
files.Append(fullpath); files.Append(fullpath);
files.Append(relative); files.Append(relative);
files.Append(basename); files.Append(basename);
@ -72,7 +72,7 @@ TEST(FileSpecListTest, RelativePathMatchesPosix) {
EXPECT_EQ((size_t)6, files.FindCompatibleIndex(3, rel3_wrong)); 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 fullpath = WindowsSpec(R"(C:\build\src\main.cpp)");
const FileSpec relative = WindowsSpec(R"(.\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 rel2_wrong = WindowsSpec(R"(asrc\main.cpp)");
const FileSpec rel3_wrong = WindowsSpec(R"("rc\main.cpp)"); const FileSpec rel3_wrong = WindowsSpec(R"("rc\main.cpp)");
FileSpecList files; SupportFileList files;
files.Append(fullpath); files.Append(fullpath);
files.Append(relative); files.Append(relative);
files.Append(basename); files.Append(basename);