Coverage Report

Created: 2026-04-29 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/cmListFileCache.h
Line
Count
Source
1
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2
   file LICENSE.rst or https://cmake.org/licensing for details.  */
3
#pragma once
4
5
#include "cmConfigure.h" // IWYU pragma: keep
6
7
#include <iosfwd>
8
#include <memory>
9
#include <set>
10
#include <string>
11
#include <utility>
12
#include <vector>
13
14
#include <cm/optional>
15
#include <cm/string_view>
16
17
#include "cmConstStack.h"
18
#include "cmList.h"
19
#include "cmSystemTools.h"
20
21
/** \class cmListFileCache
22
 * \brief A class to cache list file contents.
23
 *
24
 * cmListFileCache is a class used to cache the contents of parsed
25
 * cmake list files.
26
 */
27
28
class cmMakefile;
29
30
struct cmListFileArgument
31
{
32
  enum Delimiter
33
  {
34
    Unquoted,
35
    Quoted,
36
    Bracket
37
  };
38
0
  cmListFileArgument() = default;
39
  cmListFileArgument(cm::string_view v, Delimiter d, long line)
40
0
    : Value(v.data(), v.size())
41
0
    , Delim(d)
42
0
    , Line(line)
43
0
  {
44
0
  }
45
  bool operator==(cmListFileArgument const& r) const
46
0
  {
47
0
    return (this->Value == r.Value) && (this->Delim == r.Delim);
48
0
  }
49
0
  bool operator!=(cmListFileArgument const& r) const { return !(*this == r); }
50
  std::string Value;
51
  Delimiter Delim = Unquoted;
52
  long Line = 0;
53
};
54
55
class cmListFileFunction
56
{
57
public:
58
  cmListFileFunction(std::string name, long line, long lineEnd,
59
                     std::vector<cmListFileArgument> args)
60
0
    : Impl{ std::make_shared<Implementation>(std::move(name), line, lineEnd,
61
0
                                             std::move(args)) }
62
0
  {
63
0
  }
64
65
  std::string const& OriginalName() const noexcept
66
0
  {
67
0
    return this->Impl->OriginalName;
68
0
  }
69
70
  std::string const& LowerCaseName() const noexcept
71
0
  {
72
0
    return this->Impl->LowerCaseName;
73
0
  }
74
75
0
  long Line() const noexcept { return this->Impl->Line; }
76
0
  long LineEnd() const noexcept { return this->Impl->LineEnd; }
77
78
  std::vector<cmListFileArgument> const& Arguments() const noexcept
79
0
  {
80
0
    return this->Impl->Arguments;
81
0
  }
82
83
private:
84
  struct Implementation
85
  {
86
    Implementation(std::string name, long line, long lineEnd,
87
                   std::vector<cmListFileArgument> args)
88
0
      : OriginalName{ std::move(name) }
89
0
      , LowerCaseName{ cmSystemTools::LowerCase(this->OriginalName) }
90
0
      , Line{ line }
91
0
      , LineEnd{ lineEnd }
92
0
      , Arguments{ std::move(args) }
93
0
    {
94
0
    }
95
96
    std::string OriginalName;
97
    std::string LowerCaseName;
98
    long Line = 0;
99
    long LineEnd = 0;
100
    std::vector<cmListFileArgument> Arguments;
101
  };
102
103
  std::shared_ptr<Implementation const> Impl;
104
};
105
106
class cmListFileContext
107
{
108
public:
109
  std::string Name;
110
  std::string FilePath;
111
  long Line = 0;
112
  static long const DeferPlaceholderLine = -1;
113
  cm::optional<std::string> DeferId;
114
115
2
  cmListFileContext() = default;
116
  // This move constructor is marked `noexcept` yet `clang-tidy` 14 reports it
117
  // as being able to throw an exception. Suppress the warning as there doesn't
118
  // seem to be any way for this to happen given the member types.
119
  // NOLINTNEXTLINE(bugprone-exception-escape)
120
6
  cmListFileContext(cmListFileContext&& /*other*/) noexcept = default;
121
3
  cmListFileContext(cmListFileContext const& /*other*/) = default;
122
0
  cmListFileContext& operator=(cmListFileContext const& /*other*/) = default;
123
#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
124
  cmListFileContext& operator=(cmListFileContext&& /*other*/) noexcept =
125
0
    default;
126
#else
127
  // The move assignment operators for several STL classes did not become
128
  // noexcept until C++17, which causes some tools to warn about this move
129
  // assignment operator throwing an exception when it shouldn't.
130
  cmListFileContext& operator=(cmListFileContext&& /*other*/) noexcept =
131
    delete;
132
#endif
133
134
  cmListFileContext(std::string name, std::string filePath, long line)
135
0
    : Name(std::move(name))
136
0
    , FilePath(std::move(filePath))
137
0
    , Line(line)
138
0
  {
139
0
  }
140
141
  static cmListFileContext FromListFilePath(std::string const& filePath)
142
1
  {
143
    // We are entering a file-level scope but have not yet reached any specific
144
    // line or command invocation within it.  This context is useful to print
145
    // when it is at the top, but otherwise can be skipped during call stack
146
    // printing if preceded by a more specific entry.
147
1
    cmListFileContext lfc;
148
1
    lfc.FilePath = filePath;
149
1
    return lfc;
150
1
  }
151
152
  static cmListFileContext FromListFileFunction(
153
    cmListFileFunction const& lff, std::string const& fileName,
154
    cm::optional<std::string> deferId = {})
155
0
  {
156
0
    cmListFileContext lfc;
157
0
    lfc.FilePath = fileName;
158
0
    lfc.Line = lff.Line();
159
0
    lfc.Name = lff.OriginalName();
160
0
    lfc.DeferId = std::move(deferId);
161
0
    return lfc;
162
0
  }
163
};
164
165
std::ostream& operator<<(std::ostream&, cmListFileContext const&);
166
bool operator<(cmListFileContext const& lhs, cmListFileContext const& rhs);
167
bool operator==(cmListFileContext const& lhs, cmListFileContext const& rhs);
168
bool operator!=(cmListFileContext const& lhs, cmListFileContext const& rhs);
169
170
// Represent a backtrace (call stack) with efficient value semantics.
171
class cmListFileBacktrace
172
  : public cmConstStack<cmListFileContext, cmListFileBacktrace>
173
{
174
  using cmConstStack::cmConstStack;
175
  friend class cmConstStack<cmListFileContext, cmListFileBacktrace>;
176
};
177
#ifndef cmListFileCache_cxx
178
extern template class cmConstStack<cmListFileContext, cmListFileBacktrace>;
179
#endif
180
181
// Wrap type T as a value with a backtrace.  For purposes of
182
// ordering and equality comparison, only the original value is
183
// used.  The backtrace is considered incidental.
184
template <typename T>
185
class BT
186
{
187
public:
188
  BT(T v = T(), cmListFileBacktrace bt = cmListFileBacktrace())
189
0
    : Value(std::move(v))
190
0
    , Backtrace(std::move(bt))
191
0
  {
192
0
  }
Unexecuted instantiation: BT<std::__1::function<bool (std::__1::vector<cmListFileArgument, std::__1::allocator<cmListFileArgument> > const&, cmExecutionStatus&)> >::BT(std::__1::function<bool (std::__1::vector<cmListFileArgument, std::__1::allocator<cmListFileArgument> > const&, cmExecutionStatus&)>, cmListFileBacktrace)
Unexecuted instantiation: BT<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::BT(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, cmListFileBacktrace)
Unexecuted instantiation: BT<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool> >::BT(std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool>, cmListFileBacktrace)
Unexecuted instantiation: BT<cmMakefile::GeneratorAction>::BT(cmMakefile::GeneratorAction, cmListFileBacktrace)
Unexecuted instantiation: BT<cmGeneratorTarget*>::BT(cmGeneratorTarget*, cmListFileBacktrace)
Unexecuted instantiation: BT<cmSourceFile*>::BT(cmSourceFile*, cmListFileBacktrace)
193
  T Value;
194
  cmListFileBacktrace Backtrace;
195
  friend bool operator==(BT<T> const& l, BT<T> const& r)
196
0
  {
197
0
    return l.Value == r.Value;
198
0
  }
199
  friend bool operator<(BT<T> const& l, BT<T> const& r)
200
0
  {
201
0
    return l.Value < r.Value;
202
0
  }
Unexecuted instantiation: operator<(BT<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool> > const&, BT<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool> > const&)
Unexecuted instantiation: operator<(BT<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > const&, BT<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > const&)
203
0
  friend bool operator==(BT<T> const& l, T const& r) { return l.Value == r; }
204
  friend bool operator==(T const& l, BT<T> const& r) { return l == r.Value; }
205
};
206
207
std::ostream& operator<<(std::ostream& os, BT<std::string> const& s);
208
209
namespace cm {
210
// Helpers for basic type retrieval
211
template <typename T>
212
T remove_BT(BT<T> const& bt)
213
{
214
  return bt.Value;
215
}
216
217
template <typename T>
218
std::vector<T> remove_BT(std::vector<BT<T>> const& container)
219
0
{
220
0
  std::vector<T> result;
221
0
  result.reserve(container.size());
222
0
  for (auto const& entry : container) {
223
0
    result.emplace_back(entry.Value);
224
0
  }
225
226
0
  return result;
227
0
}
228
template <typename T>
229
std::set<T> remove_BT(std::set<BT<T>> const& container)
230
{
231
  std::set<T> result;
232
  for (auto const& entry : container) {
233
    result.emplace(entry.Value);
234
  }
235
236
  return result;
237
}
238
}
239
240
// Wrap type T as a value with potentially multiple backtraces.  For purposes
241
// of ordering and equality comparison, only the original value is used.  The
242
// backtrace is considered incidental.
243
template <typename T>
244
class BTs
245
{
246
public:
247
  BTs(T v = T(), cmListFileBacktrace bt = cmListFileBacktrace())
248
0
    : Value(std::move(v))
249
0
  {
250
0
    this->Backtraces.emplace_back(std::move(bt));
251
0
  }
252
  T Value;
253
  std::vector<cmListFileBacktrace> Backtraces;
254
  friend bool operator==(BTs<T> const& l, BTs<T> const& r)
255
  {
256
    return l.Value == r.Value;
257
  }
258
  friend bool operator<(BTs<T> const& l, BTs<T> const& r)
259
  {
260
    return l.Value < r.Value;
261
  }
262
  friend bool operator==(BTs<T> const& l, T const& r) { return l.Value == r; }
263
  friend bool operator==(T const& l, BTs<T> const& r) { return l == r.Value; }
264
};
265
266
std::vector<BT<std::string>> cmExpandListWithBacktrace(
267
  std::string const& list,
268
  cmListFileBacktrace const& bt = cmListFileBacktrace(),
269
  cmList::EmptyElements emptyArgs = cmList::EmptyElements::No);
270
271
struct cmListFile
272
{
273
  bool ParseFile(std::string const& path, cmMakefile const* mf,
274
                 cmListFileBacktrace const& lfbt);
275
276
  bool ParseString(cm::string_view str, std::string const& virtual_filename,
277
                   cmMakefile const* mf, cmListFileBacktrace const& lfbt);
278
279
  std::vector<cmListFileFunction> Functions;
280
};