xref: /freebsd-src/contrib/llvm-project/lldb/source/Utility/FileSpecList.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
1*06c3fb27SDimitry Andric //===-- FileSpecList.cpp --------------------------------------------------===//
2*06c3fb27SDimitry Andric //
3*06c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*06c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*06c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*06c3fb27SDimitry Andric //
7*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
8*06c3fb27SDimitry Andric 
9*06c3fb27SDimitry Andric #include "lldb/Utility/FileSpecList.h"
10*06c3fb27SDimitry Andric #include "lldb/Utility/ConstString.h"
11*06c3fb27SDimitry Andric #include "lldb/Utility/Stream.h"
12*06c3fb27SDimitry Andric 
13*06c3fb27SDimitry Andric #include <cstdint>
14*06c3fb27SDimitry Andric #include <utility>
15*06c3fb27SDimitry Andric 
16*06c3fb27SDimitry Andric using namespace lldb_private;
17*06c3fb27SDimitry Andric 
18*06c3fb27SDimitry Andric FileSpecList::FileSpecList() : m_files() {}
19*06c3fb27SDimitry Andric 
20*06c3fb27SDimitry Andric FileSpecList::~FileSpecList() = default;
21*06c3fb27SDimitry Andric 
22*06c3fb27SDimitry Andric // Append the "file_spec" to the end of the file spec list.
23*06c3fb27SDimitry Andric void FileSpecList::Append(const FileSpec &file_spec) {
24*06c3fb27SDimitry Andric   m_files.push_back(file_spec);
25*06c3fb27SDimitry Andric }
26*06c3fb27SDimitry Andric 
27*06c3fb27SDimitry Andric // Only append the "file_spec" if this list doesn't already contain it.
28*06c3fb27SDimitry Andric //
29*06c3fb27SDimitry Andric // Returns true if "file_spec" was added, false if this list already contained
30*06c3fb27SDimitry Andric // a copy of "file_spec".
31*06c3fb27SDimitry Andric bool FileSpecList::AppendIfUnique(const FileSpec &file_spec) {
32*06c3fb27SDimitry Andric   collection::iterator end = m_files.end();
33*06c3fb27SDimitry Andric   if (find(m_files.begin(), end, file_spec) == end) {
34*06c3fb27SDimitry Andric     m_files.push_back(file_spec);
35*06c3fb27SDimitry Andric     return true;
36*06c3fb27SDimitry Andric   }
37*06c3fb27SDimitry Andric   return false;
38*06c3fb27SDimitry Andric }
39*06c3fb27SDimitry Andric 
40*06c3fb27SDimitry Andric // Clears the file list.
41*06c3fb27SDimitry Andric void FileSpecList::Clear() { m_files.clear(); }
42*06c3fb27SDimitry Andric 
43*06c3fb27SDimitry Andric // Dumps the file list to the supplied stream pointer "s".
44*06c3fb27SDimitry Andric void FileSpecList::Dump(Stream *s, const char *separator_cstr) const {
45*06c3fb27SDimitry Andric   collection::const_iterator pos, end = m_files.end();
46*06c3fb27SDimitry Andric   for (pos = m_files.begin(); pos != end; ++pos) {
47*06c3fb27SDimitry Andric     pos->Dump(s->AsRawOstream());
48*06c3fb27SDimitry Andric     if (separator_cstr && ((pos + 1) != end))
49*06c3fb27SDimitry Andric       s->PutCString(separator_cstr);
50*06c3fb27SDimitry Andric   }
51*06c3fb27SDimitry Andric }
52*06c3fb27SDimitry Andric 
53*06c3fb27SDimitry Andric // Find the index of the file in the file spec list that matches "file_spec"
54*06c3fb27SDimitry Andric // starting "start_idx" entries into the file spec list.
55*06c3fb27SDimitry Andric //
56*06c3fb27SDimitry Andric // Returns the valid index of the file that matches "file_spec" if it is found,
57*06c3fb27SDimitry Andric // else std::numeric_limits<uint32_t>::max() is returned.
58*06c3fb27SDimitry Andric size_t FileSpecList::FindFileIndex(size_t start_idx, const FileSpec &file_spec,
59*06c3fb27SDimitry Andric                                    bool full) const {
60*06c3fb27SDimitry Andric   const size_t num_files = m_files.size();
61*06c3fb27SDimitry Andric 
62*06c3fb27SDimitry Andric   // When looking for files, we will compare only the filename if the FILE_SPEC
63*06c3fb27SDimitry Andric   // argument is empty
64*06c3fb27SDimitry Andric   bool compare_filename_only = file_spec.GetDirectory().IsEmpty();
65*06c3fb27SDimitry Andric 
66*06c3fb27SDimitry Andric   for (size_t idx = start_idx; idx < num_files; ++idx) {
67*06c3fb27SDimitry Andric     if (compare_filename_only) {
68*06c3fb27SDimitry Andric       if (ConstString::Equals(
69*06c3fb27SDimitry Andric               m_files[idx].GetFilename(), file_spec.GetFilename(),
70*06c3fb27SDimitry Andric               file_spec.IsCaseSensitive() || m_files[idx].IsCaseSensitive()))
71*06c3fb27SDimitry Andric         return idx;
72*06c3fb27SDimitry Andric     } else {
73*06c3fb27SDimitry Andric       if (FileSpec::Equal(m_files[idx], file_spec, full))
74*06c3fb27SDimitry Andric         return idx;
75*06c3fb27SDimitry Andric     }
76*06c3fb27SDimitry Andric   }
77*06c3fb27SDimitry Andric 
78*06c3fb27SDimitry Andric   // We didn't find the file, return an invalid index
79*06c3fb27SDimitry Andric   return UINT32_MAX;
80*06c3fb27SDimitry Andric }
81*06c3fb27SDimitry Andric 
82*06c3fb27SDimitry Andric size_t FileSpecList::FindCompatibleIndex(size_t start_idx,
83*06c3fb27SDimitry Andric                                          const FileSpec &file_spec) const {
84*06c3fb27SDimitry Andric   const size_t num_files = m_files.size();
85*06c3fb27SDimitry Andric   if (start_idx >= num_files)
86*06c3fb27SDimitry Andric     return UINT32_MAX;
87*06c3fb27SDimitry Andric 
88*06c3fb27SDimitry Andric   const bool file_spec_relative = file_spec.IsRelative();
89*06c3fb27SDimitry Andric   const bool file_spec_case_sensitive = file_spec.IsCaseSensitive();
90*06c3fb27SDimitry Andric   // When looking for files, we will compare only the filename if the directory
91*06c3fb27SDimitry Andric   // argument is empty in file_spec
92*06c3fb27SDimitry Andric   const bool full = !file_spec.GetDirectory().IsEmpty();
93*06c3fb27SDimitry Andric 
94*06c3fb27SDimitry Andric   for (size_t idx = start_idx; idx < num_files; ++idx) {
95*06c3fb27SDimitry Andric     const FileSpec &curr_file = m_files[idx];
96*06c3fb27SDimitry Andric 
97*06c3fb27SDimitry Andric     // Always start by matching the filename first
98*06c3fb27SDimitry Andric     if (!curr_file.FileEquals(file_spec))
99*06c3fb27SDimitry Andric       continue;
100*06c3fb27SDimitry Andric 
101*06c3fb27SDimitry Andric     // Only compare the full name if the we were asked to and if the current
102*06c3fb27SDimitry Andric     // file entry has the a directory. If it doesn't have a directory then we
103*06c3fb27SDimitry Andric     // only compare the filename.
104*06c3fb27SDimitry Andric     if (FileSpec::Equal(curr_file, file_spec, full)) {
105*06c3fb27SDimitry Andric       return idx;
106*06c3fb27SDimitry Andric     } else if (curr_file.IsRelative() || file_spec_relative) {
107*06c3fb27SDimitry Andric       llvm::StringRef curr_file_dir = curr_file.GetDirectory().GetStringRef();
108*06c3fb27SDimitry Andric       if (curr_file_dir.empty())
109*06c3fb27SDimitry Andric         return idx; // Basename match only for this file in the list
110*06c3fb27SDimitry Andric 
111*06c3fb27SDimitry Andric       // Check if we have a relative path in our file list, or if "file_spec" is
112*06c3fb27SDimitry Andric       // relative, if so, check if either ends with the other.
113*06c3fb27SDimitry Andric       llvm::StringRef file_spec_dir = file_spec.GetDirectory().GetStringRef();
114*06c3fb27SDimitry Andric       // We have a relative path in our file list, it matches if the
115*06c3fb27SDimitry Andric       // specified path ends with this path, but we must ensure the full
116*06c3fb27SDimitry Andric       // component matches (we don't want "foo/bar.cpp" to match "oo/bar.cpp").
117*06c3fb27SDimitry Andric       auto is_suffix = [](llvm::StringRef a, llvm::StringRef b,
118*06c3fb27SDimitry Andric                           bool case_sensitive) -> bool {
119*06c3fb27SDimitry Andric         if (case_sensitive ? a.consume_back(b) : a.consume_back_insensitive(b))
120*06c3fb27SDimitry Andric           return a.empty() || a.endswith("/");
121*06c3fb27SDimitry Andric         return false;
122*06c3fb27SDimitry Andric       };
123*06c3fb27SDimitry Andric       const bool case_sensitive =
124*06c3fb27SDimitry Andric           file_spec_case_sensitive || curr_file.IsCaseSensitive();
125*06c3fb27SDimitry Andric       if (is_suffix(curr_file_dir, file_spec_dir, case_sensitive) ||
126*06c3fb27SDimitry Andric           is_suffix(file_spec_dir, curr_file_dir, case_sensitive))
127*06c3fb27SDimitry Andric         return idx;
128*06c3fb27SDimitry Andric     }
129*06c3fb27SDimitry Andric   }
130*06c3fb27SDimitry Andric 
131*06c3fb27SDimitry Andric   // We didn't find the file, return an invalid index
132*06c3fb27SDimitry Andric   return UINT32_MAX;
133*06c3fb27SDimitry Andric }
134*06c3fb27SDimitry Andric // Returns the FileSpec object at index "idx". If "idx" is out of range, then
135*06c3fb27SDimitry Andric // an empty FileSpec object will be returned.
136*06c3fb27SDimitry Andric const FileSpec &FileSpecList::GetFileSpecAtIndex(size_t idx) const {
137*06c3fb27SDimitry Andric   if (idx < m_files.size())
138*06c3fb27SDimitry Andric     return m_files[idx];
139*06c3fb27SDimitry Andric   static FileSpec g_empty_file_spec;
140*06c3fb27SDimitry Andric   return g_empty_file_spec;
141*06c3fb27SDimitry Andric }
142*06c3fb27SDimitry Andric 
143*06c3fb27SDimitry Andric const FileSpec *FileSpecList::GetFileSpecPointerAtIndex(size_t idx) const {
144*06c3fb27SDimitry Andric   if (idx < m_files.size())
145*06c3fb27SDimitry Andric     return &m_files[idx];
146*06c3fb27SDimitry Andric   return nullptr;
147*06c3fb27SDimitry Andric }
148*06c3fb27SDimitry Andric 
149*06c3fb27SDimitry Andric // Return the size in bytes that this object takes in memory. This returns the
150*06c3fb27SDimitry Andric // size in bytes of this object's member variables and any FileSpec objects its
151*06c3fb27SDimitry Andric // member variables contain, the result doesn't not include the string values
152*06c3fb27SDimitry Andric // for the directories any filenames as those are in shared string pools.
153*06c3fb27SDimitry Andric size_t FileSpecList::MemorySize() const {
154*06c3fb27SDimitry Andric   size_t mem_size = sizeof(FileSpecList);
155*06c3fb27SDimitry Andric   collection::const_iterator pos, end = m_files.end();
156*06c3fb27SDimitry Andric   for (pos = m_files.begin(); pos != end; ++pos) {
157*06c3fb27SDimitry Andric     mem_size += pos->MemorySize();
158*06c3fb27SDimitry Andric   }
159*06c3fb27SDimitry Andric 
160*06c3fb27SDimitry Andric   return mem_size;
161*06c3fb27SDimitry Andric }
162*06c3fb27SDimitry Andric 
163*06c3fb27SDimitry Andric // Return the number of files in the file spec list.
164*06c3fb27SDimitry Andric size_t FileSpecList::GetSize() const { return m_files.size(); }
165*06c3fb27SDimitry Andric 
166*06c3fb27SDimitry Andric size_t FileSpecList::GetFilesMatchingPartialPath(const char *path,
167*06c3fb27SDimitry Andric                                                  bool dir_okay,
168*06c3fb27SDimitry Andric                                                  FileSpecList &matches) {
169*06c3fb27SDimitry Andric   return 0;
170*06c3fb27SDimitry Andric }
171