brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.8 KiB · 8aa0820 Raw
238 lines · cpp
1//===-- FileSpecList.cpp --------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Utility/FileSpecList.h"10#include "lldb/Target/Statistics.h"11#include "lldb/Target/Target.h"12#include "lldb/Utility/ConstString.h"13#include "lldb/Utility/LLDBLog.h"14#include "lldb/Utility/Log.h"15#include "lldb/Utility/RealpathPrefixes.h"16#include "lldb/Utility/Stream.h"17 18#include <cstdint>19#include <utility>20 21using namespace lldb_private;22 23FileSpecList::FileSpecList() : m_files() {}24 25FileSpecList::~FileSpecList() = default;26 27// Append the "file_spec" to the end of the file spec list.28void FileSpecList::Append(const FileSpec &file_spec) {29  m_files.push_back(file_spec);30}31 32// Only append the "file_spec" if this list doesn't already contain it.33//34// Returns true if "file_spec" was added, false if this list already contained35// a copy of "file_spec".36bool FileSpecList::AppendIfUnique(const FileSpec &file_spec) {37  collection::iterator end = m_files.end();38  if (find(m_files.begin(), end, file_spec) == end) {39    m_files.push_back(file_spec);40    return true;41  }42  return false;43}44 45// FIXME: Replace this with a DenseSet at the call site. It is inefficient.46bool SupportFileList::AppendIfUnique(const FileSpec &file_spec) {47  collection::iterator end = m_files.end();48  if (find_if(m_files.begin(), end, [&](const SupportFileNSP &support_file) {49        return support_file->GetSpecOnly() == file_spec;50      }) == end) {51    Append(file_spec);52    return true;53  }54  return false;55}56 57// Clears the file list.58void FileSpecList::Clear() { m_files.clear(); }59 60// Dumps the file list to the supplied stream pointer "s".61void FileSpecList::Dump(Stream *s, const char *separator_cstr) const {62  collection::const_iterator pos, end = m_files.end();63  for (pos = m_files.begin(); pos != end; ++pos) {64    pos->Dump(s->AsRawOstream());65    if (separator_cstr && ((pos + 1) != end))66      s->PutCString(separator_cstr);67  }68}69 70// Find the index of the file in the file spec list that matches "file_spec"71// starting "start_idx" entries into the file spec list.72//73// Returns the valid index of the file that matches "file_spec" if it is found,74// else std::numeric_limits<uint32_t>::max() is returned.75static size_t FindFileIndex(size_t start_idx, const FileSpec &file_spec,76                            bool full, size_t num_files,77                            std::function<const FileSpec &(size_t)> get_ith) {78  // When looking for files, we will compare only the filename if the FILE_SPEC79  // argument is empty80  bool compare_filename_only = file_spec.GetDirectory().IsEmpty();81 82  for (size_t idx = start_idx; idx < num_files; ++idx) {83    const FileSpec &ith = get_ith(idx);84    if (compare_filename_only) {85      if (ConstString::Equals(ith.GetFilename(), file_spec.GetFilename(),86                              file_spec.IsCaseSensitive() ||87                                  ith.IsCaseSensitive()))88        return idx;89    } else {90      if (FileSpec::Equal(ith, file_spec, full))91        return idx;92    }93  }94 95  // We didn't find the file, return an invalid index96  return UINT32_MAX;97}98 99size_t FileSpecList::FindFileIndex(size_t start_idx, const FileSpec &file_spec,100                                   bool full) const {101  return ::FindFileIndex(102      start_idx, file_spec, full, m_files.size(),103      [&](size_t idx) -> const FileSpec & { return m_files[idx]; });104}105 106size_t SupportFileList::FindFileIndex(size_t start_idx,107                                      const FileSpec &file_spec,108                                      bool full) const {109  return ::FindFileIndex(start_idx, file_spec, full, m_files.size(),110                         [&](size_t idx) -> const FileSpec & {111                           return m_files[idx]->GetSpecOnly();112                         });113}114 115enum IsCompatibleResult {116  kNoMatch = 0,117  kOnlyFileMatch = 1,118  kBothDirectoryAndFileMatch = 2,119};120 121IsCompatibleResult IsCompatible(const FileSpec &curr_file,122                                const FileSpec &file_spec) {123  const bool file_spec_relative = file_spec.IsRelative();124  const bool file_spec_case_sensitive = file_spec.IsCaseSensitive();125  // When looking for files, we will compare only the filename if the directory126  // argument is empty in file_spec127  const bool full = !file_spec.GetDirectory().IsEmpty();128 129  // Always start by matching the filename first130  if (!curr_file.FileEquals(file_spec))131    return IsCompatibleResult::kNoMatch;132 133  // Only compare the full name if the we were asked to and if the current134  // file entry has a directory. If it doesn't have a directory then we only135  // compare the filename.136  if (FileSpec::Equal(curr_file, file_spec, full)) {137    return IsCompatibleResult::kBothDirectoryAndFileMatch;138  } else if (curr_file.IsRelative() || file_spec_relative) {139    llvm::StringRef curr_file_dir = curr_file.GetDirectory().GetStringRef();140    if (curr_file_dir.empty())141      // Basename match only for this file in the list142      return IsCompatibleResult::kBothDirectoryAndFileMatch;143 144    // Check if we have a relative path in our file list, or if "file_spec" is145    // relative, if so, check if either ends with the other.146    llvm::StringRef file_spec_dir = file_spec.GetDirectory().GetStringRef();147    // We have a relative path in our file list, it matches if the148    // specified path ends with this path, but we must ensure the full149    // component matches (we don't want "foo/bar.cpp" to match "oo/bar.cpp").150    auto is_suffix = [](llvm::StringRef a, llvm::StringRef b,151                        bool case_sensitive) -> bool {152      if (case_sensitive ? a.consume_back(b) : a.consume_back_insensitive(b))153        return a.empty() || a.ends_with("/");154      return false;155    };156    const bool case_sensitive =157        file_spec_case_sensitive || curr_file.IsCaseSensitive();158    if (is_suffix(curr_file_dir, file_spec_dir, case_sensitive) ||159        is_suffix(file_spec_dir, curr_file_dir, case_sensitive))160      return IsCompatibleResult::kBothDirectoryAndFileMatch;161  }162  return IsCompatibleResult::kOnlyFileMatch;163}164 165size_t SupportFileList::FindCompatibleIndex(166    size_t start_idx, const FileSpec &file_spec,167    RealpathPrefixes *realpath_prefixes) const {168  const size_t num_files = m_files.size();169  if (start_idx >= num_files)170    return UINT32_MAX;171 172  for (size_t idx = start_idx; idx < num_files; ++idx) {173    const FileSpec &curr_file = m_files[idx]->GetSpecOnly();174 175    IsCompatibleResult result = IsCompatible(curr_file, file_spec);176    if (result == IsCompatibleResult::kBothDirectoryAndFileMatch)177      return idx;178 179    if (realpath_prefixes && result == IsCompatibleResult::kOnlyFileMatch) {180      if (std::optional<FileSpec> resolved_curr_file =181              realpath_prefixes->ResolveSymlinks(curr_file)) {182        if (IsCompatible(*resolved_curr_file, file_spec) ==183            IsCompatibleResult::kBothDirectoryAndFileMatch) {184          // Stats and logging.185          realpath_prefixes->IncreaseSourceRealpathCompatibleCount();186          Log *log = GetLog(LLDBLog::Source);187          LLDB_LOGF(log,188                    "Realpath'ed support file %s is compatible to input file",189                    resolved_curr_file->GetPath().c_str());190          // We found a match191          return idx;192        }193      }194    }195  }196 197  // We didn't find the file, return an invalid index198  return UINT32_MAX;199}200// Returns the FileSpec object at index "idx". If "idx" is out of range, then201// an empty FileSpec object will be returned.202const FileSpec &FileSpecList::GetFileSpecAtIndex(size_t idx) const {203  if (idx < m_files.size())204    return m_files[idx];205  static FileSpec g_empty_file_spec;206  return g_empty_file_spec;207}208 209const FileSpec &SupportFileList::GetFileSpecAtIndex(size_t idx) const {210  if (idx < m_files.size())211    return m_files[idx]->Materialize();212  static FileSpec g_empty_file_spec;213  return g_empty_file_spec;214}215 216SupportFileNSP SupportFileList::GetSupportFileAtIndex(size_t idx) const {217  if (idx < m_files.size())218    return m_files[idx];219  return std::make_shared<SupportFile>();220}221 222// Return the size in bytes that this object takes in memory. This returns the223// size in bytes of this object's member variables and any FileSpec objects its224// member variables contain, the result doesn't not include the string values225// for the directories any filenames as those are in shared string pools.226size_t FileSpecList::MemorySize() const {227  size_t mem_size = sizeof(FileSpecList);228  collection::const_iterator pos, end = m_files.end();229  for (pos = m_files.begin(); pos != end; ++pos) {230    mem_size += pos->MemorySize();231  }232 233  return mem_size;234}235 236// Return the number of files in the file spec list.237size_t FileSpecList::GetSize() const { return m_files.size(); }238