summaryrefslogtreecommitdiff
path: root/Source/cmListFileCache.h
blob: e4e6eb37ed9593beb89c4f9dddfb197e781f2826 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
   file Copyright.txt or https://cmake.org/licensing for details.  */
#pragma once

#include "cmConfigure.h" // IWYU pragma: keep

#include <iosfwd>
#include <memory>
#include <string>
#include <utility>
#include <vector>

#include <cm/optional>

#include "cmConstStack.h"
#include "cmList.h"
#include "cmSystemTools.h"

/** \class cmListFileCache
 * \brief A class to cache list file contents.
 *
 * cmListFileCache is a class used to cache the contents of parsed
 * cmake list files.
 */

class cmMessenger;

struct cmListFileArgument
{
  enum Delimiter
  {
    Unquoted,
    Quoted,
    Bracket
  };
  cmListFileArgument() = default;
  cmListFileArgument(std::string v, Delimiter d, long line)
    : Value(std::move(v))
    , Delim(d)
    , Line(line)
  {
  }
  bool operator==(const cmListFileArgument& r) const
  {
    return (this->Value == r.Value) && (this->Delim == r.Delim);
  }
  bool operator!=(const cmListFileArgument& r) const { return !(*this == r); }
  std::string Value;
  Delimiter Delim = Unquoted;
  long Line = 0;
};

class cmListFileFunction
{
public:
  cmListFileFunction(std::string name, long line, long lineEnd,
                     std::vector<cmListFileArgument> args)
    : Impl{ std::make_shared<Implementation>(std::move(name), line, lineEnd,
                                             std::move(args)) }
  {
  }

  std::string const& OriginalName() const noexcept
  {
    return this->Impl->OriginalName;
  }

  std::string const& LowerCaseName() const noexcept
  {
    return this->Impl->LowerCaseName;
  }

  long Line() const noexcept { return this->Impl->Line; }
  long LineEnd() const noexcept { return this->Impl->LineEnd; }

  std::vector<cmListFileArgument> const& Arguments() const noexcept
  {
    return this->Impl->Arguments;
  }

private:
  struct Implementation
  {
    Implementation(std::string name, long line, long lineEnd,
                   std::vector<cmListFileArgument> args)
      : OriginalName{ std::move(name) }
      , LowerCaseName{ cmSystemTools::LowerCase(this->OriginalName) }
      , Line{ line }
      , LineEnd{ lineEnd }
      , Arguments{ std::move(args) }
    {
    }

    std::string OriginalName;
    std::string LowerCaseName;
    long Line = 0;
    long LineEnd = 0;
    std::vector<cmListFileArgument> Arguments;
  };

  std::shared_ptr<Implementation const> Impl;
};

class cmListFileContext
{
public:
  std::string Name;
  std::string FilePath;
  long Line = 0;
  static long const DeferPlaceholderLine = -1;
  cm::optional<std::string> DeferId;

  cmListFileContext() = default;
  // This move constructor is marked `noexcept` yet `clang-tidy` 14 reports it
  // as being able to throw an exception. Suppress the warning as there doesn't
  // seem to be any way for this to happen given the member types.
  // NOLINTNEXTLINE(bugprone-exception-escape)
  cmListFileContext(cmListFileContext&& /*other*/) noexcept = default;
  cmListFileContext(const cmListFileContext& /*other*/) = default;
  cmListFileContext& operator=(const cmListFileContext& /*other*/) = default;
#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
  cmListFileContext& operator=(cmListFileContext&& /*other*/) noexcept =
    default;
#else
  // The move assignment operators for several STL classes did not become
  // noexcept until C++17, which causes some tools to warn about this move
  // assignment operator throwing an exception when it shouldn't.
  cmListFileContext& operator=(cmListFileContext&& /*other*/) noexcept =
    delete;
#endif

  cmListFileContext(std::string name, std::string filePath, long line)
    : Name(std::move(name))
    , FilePath(std::move(filePath))
    , Line(line)
  {
  }

  static cmListFileContext FromListFilePath(std::string const& filePath)
  {
    // We are entering a file-level scope but have not yet reached
    // any specific line or command invocation within it.  This context
    // is useful to print when it is at the top but otherwise can be
    // skipped during call stack printing.
    cmListFileContext lfc;
    lfc.FilePath = filePath;
    return lfc;
  }

  static cmListFileContext FromListFileFunction(
    cmListFileFunction const& lff, std::string const& fileName,
    cm::optional<std::string> deferId = {})
  {
    cmListFileContext lfc;
    lfc.FilePath = fileName;
    lfc.Line = lff.Line();
    lfc.Name = lff.OriginalName();
    lfc.DeferId = std::move(deferId);
    return lfc;
  }
};

std::ostream& operator<<(std::ostream&, cmListFileContext const&);
bool operator<(const cmListFileContext& lhs, const cmListFileContext& rhs);
bool operator==(cmListFileContext const& lhs, cmListFileContext const& rhs);
bool operator!=(cmListFileContext const& lhs, cmListFileContext const& rhs);

// Represent a backtrace (call stack) with efficient value semantics.
class cmListFileBacktrace
  : public cmConstStack<cmListFileContext, cmListFileBacktrace>
{
  using cmConstStack::cmConstStack;
  friend class cmConstStack<cmListFileContext, cmListFileBacktrace>;
};
#ifndef cmListFileCache_cxx
extern template class cmConstStack<cmListFileContext, cmListFileBacktrace>;
#endif

// Wrap type T as a value with a backtrace.  For purposes of
// ordering and equality comparison, only the original value is
// used.  The backtrace is considered incidental.
template <typename T>
class BT
{
public:
  BT(T v = T(), cmListFileBacktrace bt = cmListFileBacktrace())
    : Value(std::move(v))
    , Backtrace(std::move(bt))
  {
  }
  T Value;
  cmListFileBacktrace Backtrace;
  friend bool operator==(BT<T> const& l, BT<T> const& r)
  {
    return l.Value == r.Value;
  }
  friend bool operator<(BT<T> const& l, BT<T> const& r)
  {
    return l.Value < r.Value;
  }
  friend bool operator==(BT<T> const& l, T const& r) { return l.Value == r; }
  friend bool operator==(T const& l, BT<T> const& r) { return l == r.Value; }
};

std::ostream& operator<<(std::ostream& os, BT<std::string> const& s);

// Wrap type T as a value with potentially multiple backtraces.  For purposes
// of ordering and equality comparison, only the original value is used.  The
// backtrace is considered incidental.
template <typename T>
class BTs
{
public:
  BTs(T v = T(), cmListFileBacktrace bt = cmListFileBacktrace())
    : Value(std::move(v))
  {
    this->Backtraces.emplace_back(std::move(bt));
  }
  T Value;
  std::vector<cmListFileBacktrace> Backtraces;
  friend bool operator==(BTs<T> const& l, BTs<T> const& r)
  {
    return l.Value == r.Value;
  }
  friend bool operator<(BTs<T> const& l, BTs<T> const& r)
  {
    return l.Value < r.Value;
  }
  friend bool operator==(BTs<T> const& l, T const& r) { return l.Value == r; }
  friend bool operator==(T const& l, BTs<T> const& r) { return l == r.Value; }
};

std::vector<BT<std::string>> cmExpandListWithBacktrace(
  std::string const& list,
  cmListFileBacktrace const& bt = cmListFileBacktrace(),
  cmList::EmptyElements emptyArgs = cmList::EmptyElements::No);

struct cmListFile
{
  bool ParseFile(const char* path, cmMessenger* messenger,
                 cmListFileBacktrace const& lfbt);

  bool ParseString(const char* str, const char* virtual_filename,
                   cmMessenger* messenger, cmListFileBacktrace const& lfbt);

  std::vector<cmListFileFunction> Functions;
};