Coverage Report

Created: 2026-02-09 06:05

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 <string>
10
#include <utility>
11
#include <vector>
12
13
#include <cm/optional>
14
#include <cm/string_view>
15
16
#include "cmList.h"
17
#include "cmStack.h"
18
#include "cmSystemTools.h"
19
20
/** \class cmListFileCache
21
 * \brief A class to cache list file contents.
22
 *
23
 * cmListFileCache is a class used to cache the contents of parsed
24
 * cmake list files.
25
 */
26
27
class cmMessenger;
28
29
struct cmListFileArgument
30
{
31
  enum Delimiter
32
  {
33
    Unquoted,
34
    Quoted,
35
    Bracket
36
  };
37
0
  cmListFileArgument() = default;
38
  cmListFileArgument(cm::string_view v, Delimiter d, long line)
39
0
    : Value(v.data(), v.size())
40
0
    , Delim(d)
41
0
    , Line(line)
42
0
  {
43
0
  }
44
  bool operator==(cmListFileArgument const& r) const
45
0
  {
46
0
    return (this->Value == r.Value) && (this->Delim == r.Delim);
47
0
  }
48
0
  bool operator!=(cmListFileArgument const& r) const { return !(*this == r); }
49
  std::string Value;
50
  Delimiter Delim = Unquoted;
51
  long Line = 0;
52
};
53
54
class cmListFileFunction
55
{
56
public:
57
  cmListFileFunction(std::string name, long line, long lineEnd,
58
                     std::vector<cmListFileArgument> args)
59
0
    : Impl{ std::make_shared<Implementation>(std::move(name), line, lineEnd,
60
0
                                             std::move(args)) }
61
0
  {
62
0
  }
63
64
  std::string const& OriginalName() const noexcept
65
0
  {
66
0
    return this->Impl->OriginalName;
67
0
  }
68
69
  std::string const& LowerCaseName() const noexcept
70
0
  {
71
0
    return this->Impl->LowerCaseName;
72
0
  }
73
74
0
  long Line() const noexcept { return this->Impl->Line; }
75
0
  long LineEnd() const noexcept { return this->Impl->LineEnd; }
76
77
  std::vector<cmListFileArgument> const& Arguments() const noexcept
78
0
  {
79
0
    return this->Impl->Arguments;
80
0
  }
81
82
private:
83
  struct Implementation
84
  {
85
    Implementation(std::string name, long line, long lineEnd,
86
                   std::vector<cmListFileArgument> args)
87
0
      : OriginalName{ std::move(name) }
88
0
      , LowerCaseName{ cmSystemTools::LowerCase(this->OriginalName) }
89
0
      , Line{ line }
90
0
      , LineEnd{ lineEnd }
91
0
      , Arguments{ std::move(args) }
92
0
    {
93
0
    }
94
95
    std::string OriginalName;
96
    std::string LowerCaseName;
97
    long Line = 0;
98
    long LineEnd = 0;
99
    std::vector<cmListFileArgument> Arguments;
100
  };
101
102
  std::shared_ptr<Implementation const> Impl;
103
};
104
105
class cmListFileContext
106
{
107
public:
108
  std::string Name;
109
  std::string FilePath;
110
  long Line = 0;
111
  static long const DeferPlaceholderLine = -1;
112
  cm::optional<std::string> DeferId;
113
114
2
  cmListFileContext() = default;
115
  // This move constructor is marked `noexcept` yet `clang-tidy` 14 reports it
116
  // as being able to throw an exception. Suppress the warning as there doesn't
117
  // seem to be any way for this to happen given the member types.
118
  // NOLINTNEXTLINE(bugprone-exception-escape)
119
0
  cmListFileContext(cmListFileContext&& /*other*/) noexcept = default;
120
9
  cmListFileContext(cmListFileContext const& /*other*/) = default;
121
0
  cmListFileContext& operator=(cmListFileContext const& /*other*/) = default;
122
#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
123
  cmListFileContext& operator=(cmListFileContext&& /*other*/) noexcept =
124
0
    default;
125
#else
126
  // The move assignment operators for several STL classes did not become
127
  // noexcept until C++17, which causes some tools to warn about this move
128
  // assignment operator throwing an exception when it shouldn't.
129
  cmListFileContext& operator=(cmListFileContext&& /*other*/) noexcept =
130
    delete;
131
#endif
132
133
  cmListFileContext(std::string name, std::string filePath, long line)
134
0
    : Name(std::move(name))
135
0
    , FilePath(std::move(filePath))
136
0
    , Line(line)
137
0
  {
138
0
  }
139
140
  static cmListFileContext FromListFilePath(std::string const& filePath)
141
1
  {
142
    // We are entering a file-level scope but have not yet reached any specific
143
    // line or command invocation within it.  This context is useful to print
144
    // when it is at the top, but otherwise can be skipped during call stack
145
    // printing if preceded by a more specific entry.
146
1
    cmListFileContext lfc;
147
1
    lfc.FilePath = filePath;
148
1
    return lfc;
149
1
  }
150
151
  static cmListFileContext FromListFileFunction(
152
    cmListFileFunction const& lff, std::string const& fileName,
153
    cm::optional<std::string> deferId = {})
154
0
  {
155
0
    cmListFileContext lfc;
156
0
    lfc.FilePath = fileName;
157
0
    lfc.Line = lff.Line();
158
0
    lfc.Name = lff.OriginalName();
159
0
    lfc.DeferId = std::move(deferId);
160
0
    return lfc;
161
0
  }
162
};
163
164
std::ostream& operator<<(std::ostream&, cmListFileContext const&);
165
bool operator<(cmListFileContext const& lhs, cmListFileContext const& rhs);
166
bool operator==(cmListFileContext const& lhs, cmListFileContext const& rhs);
167
bool operator!=(cmListFileContext const& lhs, cmListFileContext const& rhs);
168
169
// Represent a backtrace (call stack) with efficient value semantics.
170
class cmListFileBacktrace
171
  : public cmConstStack<cmListFileContext, cmListFileBacktrace>
172
{
173
  using cmStack::cmStack;
174
  friend cmListFileBacktrace::Base;
175
};
176
#ifndef cmListFileCache_cxx
177
extern template class cmStack<cmListFileContext const, cmListFileBacktrace,
178
                              cmStackType::Const>;
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
// Wrap type T as a value with potentially multiple backtraces.  For purposes
210
// of ordering and equality comparison, only the original value is used.  The
211
// backtrace is considered incidental.
212
template <typename T>
213
class BTs
214
{
215
public:
216
  BTs(T v = T(), cmListFileBacktrace bt = cmListFileBacktrace())
217
0
    : Value(std::move(v))
218
0
  {
219
0
    this->Backtraces.emplace_back(std::move(bt));
220
0
  }
221
  T Value;
222
  std::vector<cmListFileBacktrace> Backtraces;
223
  friend bool operator==(BTs<T> const& l, BTs<T> const& r)
224
  {
225
    return l.Value == r.Value;
226
  }
227
  friend bool operator<(BTs<T> const& l, BTs<T> const& r)
228
  {
229
    return l.Value < r.Value;
230
  }
231
  friend bool operator==(BTs<T> const& l, T const& r) { return l.Value == r; }
232
  friend bool operator==(T const& l, BTs<T> const& r) { return l == r.Value; }
233
};
234
235
std::vector<BT<std::string>> cmExpandListWithBacktrace(
236
  std::string const& list,
237
  cmListFileBacktrace const& bt = cmListFileBacktrace(),
238
  cmList::EmptyElements emptyArgs = cmList::EmptyElements::No);
239
240
struct cmListFile
241
{
242
  bool ParseFile(char const* path, cmMessenger* messenger,
243
                 cmListFileBacktrace const& lfbt);
244
245
  bool ParseString(cm::string_view str, char const* virtual_filename,
246
                   cmMessenger* messenger, cmListFileBacktrace const& lfbt);
247
248
  std::vector<cmListFileFunction> Functions;
249
};