Path: blob/main/contrib/llvm-project/lldb/source/Utility/FileSpecList.cpp
39587 views
//===-- FileSpecList.cpp --------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "lldb/Utility/FileSpecList.h"9#include "lldb/Utility/ConstString.h"10#include "lldb/Utility/Stream.h"1112#include <cstdint>13#include <utility>1415using namespace lldb_private;1617FileSpecList::FileSpecList() : m_files() {}1819FileSpecList::~FileSpecList() = default;2021// Append the "file_spec" to the end of the file spec list.22void FileSpecList::Append(const FileSpec &file_spec) {23m_files.push_back(file_spec);24}2526// Only append the "file_spec" if this list doesn't already contain it.27//28// Returns true if "file_spec" was added, false if this list already contained29// a copy of "file_spec".30bool FileSpecList::AppendIfUnique(const FileSpec &file_spec) {31collection::iterator end = m_files.end();32if (find(m_files.begin(), end, file_spec) == end) {33m_files.push_back(file_spec);34return true;35}36return false;37}3839// FIXME: Replace this with a DenseSet at the call site. It is inefficient.40bool SupportFileList::AppendIfUnique(const FileSpec &file_spec) {41collection::iterator end = m_files.end();42if (find_if(m_files.begin(), end,43[&](const std::shared_ptr<SupportFile> &support_file) {44return support_file->GetSpecOnly() == file_spec;45}) == end) {46Append(file_spec);47return true;48}49return false;50}5152// Clears the file list.53void FileSpecList::Clear() { m_files.clear(); }5455// Dumps the file list to the supplied stream pointer "s".56void FileSpecList::Dump(Stream *s, const char *separator_cstr) const {57collection::const_iterator pos, end = m_files.end();58for (pos = m_files.begin(); pos != end; ++pos) {59pos->Dump(s->AsRawOstream());60if (separator_cstr && ((pos + 1) != end))61s->PutCString(separator_cstr);62}63}6465// Find the index of the file in the file spec list that matches "file_spec"66// starting "start_idx" entries into the file spec list.67//68// Returns the valid index of the file that matches "file_spec" if it is found,69// else std::numeric_limits<uint32_t>::max() is returned.70static size_t FindFileIndex(size_t start_idx, const FileSpec &file_spec,71bool full, size_t num_files,72std::function<const FileSpec &(size_t)> get_ith) {73// When looking for files, we will compare only the filename if the FILE_SPEC74// argument is empty75bool compare_filename_only = file_spec.GetDirectory().IsEmpty();7677for (size_t idx = start_idx; idx < num_files; ++idx) {78const FileSpec &ith = get_ith(idx);79if (compare_filename_only) {80if (ConstString::Equals(ith.GetFilename(), file_spec.GetFilename(),81file_spec.IsCaseSensitive() ||82ith.IsCaseSensitive()))83return idx;84} else {85if (FileSpec::Equal(ith, file_spec, full))86return idx;87}88}8990// We didn't find the file, return an invalid index91return UINT32_MAX;92}9394size_t FileSpecList::FindFileIndex(size_t start_idx, const FileSpec &file_spec,95bool full) const {96return ::FindFileIndex(97start_idx, file_spec, full, m_files.size(),98[&](size_t idx) -> const FileSpec & { return m_files[idx]; });99}100101size_t SupportFileList::FindFileIndex(size_t start_idx,102const FileSpec &file_spec,103bool full) const {104return ::FindFileIndex(start_idx, file_spec, full, m_files.size(),105[&](size_t idx) -> const FileSpec & {106return m_files[idx]->GetSpecOnly();107});108}109110size_t SupportFileList::FindCompatibleIndex(size_t start_idx,111const FileSpec &file_spec) const {112const size_t num_files = m_files.size();113if (start_idx >= num_files)114return UINT32_MAX;115116const bool file_spec_relative = file_spec.IsRelative();117const bool file_spec_case_sensitive = file_spec.IsCaseSensitive();118// When looking for files, we will compare only the filename if the directory119// argument is empty in file_spec120const bool full = !file_spec.GetDirectory().IsEmpty();121122for (size_t idx = start_idx; idx < num_files; ++idx) {123const FileSpec &curr_file = m_files[idx]->GetSpecOnly();124125// Always start by matching the filename first126if (!curr_file.FileEquals(file_spec))127continue;128129// Only compare the full name if the we were asked to and if the current130// file entry has the a directory. If it doesn't have a directory then we131// only compare the filename.132if (FileSpec::Equal(curr_file, file_spec, full)) {133return idx;134} else if (curr_file.IsRelative() || file_spec_relative) {135llvm::StringRef curr_file_dir = curr_file.GetDirectory().GetStringRef();136if (curr_file_dir.empty())137return idx; // Basename match only for this file in the list138139// Check if we have a relative path in our file list, or if "file_spec" is140// relative, if so, check if either ends with the other.141llvm::StringRef file_spec_dir = file_spec.GetDirectory().GetStringRef();142// We have a relative path in our file list, it matches if the143// specified path ends with this path, but we must ensure the full144// component matches (we don't want "foo/bar.cpp" to match "oo/bar.cpp").145auto is_suffix = [](llvm::StringRef a, llvm::StringRef b,146bool case_sensitive) -> bool {147if (case_sensitive ? a.consume_back(b) : a.consume_back_insensitive(b))148return a.empty() || a.ends_with("/");149return false;150};151const bool case_sensitive =152file_spec_case_sensitive || curr_file.IsCaseSensitive();153if (is_suffix(curr_file_dir, file_spec_dir, case_sensitive) ||154is_suffix(file_spec_dir, curr_file_dir, case_sensitive))155return idx;156}157}158159// We didn't find the file, return an invalid index160return UINT32_MAX;161}162// Returns the FileSpec object at index "idx". If "idx" is out of range, then163// an empty FileSpec object will be returned.164const FileSpec &FileSpecList::GetFileSpecAtIndex(size_t idx) const {165if (idx < m_files.size())166return m_files[idx];167static FileSpec g_empty_file_spec;168return g_empty_file_spec;169}170171const FileSpec &SupportFileList::GetFileSpecAtIndex(size_t idx) const {172if (idx < m_files.size())173return m_files[idx]->Materialize();174static FileSpec g_empty_file_spec;175return g_empty_file_spec;176}177178std::shared_ptr<SupportFile>179SupportFileList::GetSupportFileAtIndex(size_t idx) const {180if (idx < m_files.size())181return m_files[idx];182return {};183}184185// Return the size in bytes that this object takes in memory. This returns the186// size in bytes of this object's member variables and any FileSpec objects its187// member variables contain, the result doesn't not include the string values188// for the directories any filenames as those are in shared string pools.189size_t FileSpecList::MemorySize() const {190size_t mem_size = sizeof(FileSpecList);191collection::const_iterator pos, end = m_files.end();192for (pos = m_files.begin(); pos != end; ++pos) {193mem_size += pos->MemorySize();194}195196return mem_size;197}198199// Return the number of files in the file spec list.200size_t FileSpecList::GetSize() const { return m_files.size(); }201202203