/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 | | }; |