| /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying | |
| file LICENSE.rst or https://cmake.org/licensing for details. */ | |
| #pragma once | |
| #include "cmConfigure.h" // IWYU pragma: keep | |
| #include <iosfwd> | |
| #include <memory> | |
| #include <set> | |
| #include <string> | |
| #include <utility> | |
| #include <vector> | |
| #include <cm/optional> | |
| #include <cm/string_view> | |
| #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 cmMakefile; | |
| struct cmListFileArgument | |
| { | |
| enum Delimiter | |
| { | |
| Unquoted, | |
| Quoted, | |
| Bracket | |
| }; | |
| cmListFileArgument() = default; | |
| cmListFileArgument(cm::string_view v, Delimiter d, long line) | |
| : Value(v.data(), v.size()) | |
| , Delim(d) | |
| , Line(line) | |
| { | |
| } | |
| bool operator==(cmListFileArgument const& r) const | |
| { | |
| return (this->Value == r.Value) && (this->Delim == r.Delim); | |
| } | |
| bool operator!=(cmListFileArgument const& 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(cmListFileContext const& /*other*/) = default; | |
| cmListFileContext& operator=(cmListFileContext const& /*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 if preceded by a more specific entry. | |
| 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<(cmListFileContext const& lhs, cmListFileContext const& 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); | |
| namespace cm { | |
| // Helpers for basic type retrieval | |
| template <typename T> | |
| T remove_BT(BT<T> const& bt) | |
| { | |
| return bt.Value; | |
| } | |
| template <typename T> | |
| std::vector<T> remove_BT(std::vector<BT<T>> const& container) | |
| { | |
| std::vector<T> result; | |
| result.reserve(container.size()); | |
| for (auto const& entry : container) { | |
| result.emplace_back(entry.Value); | |
| } | |
| return result; | |
| } | |
| template <typename T> | |
| std::set<T> remove_BT(std::set<BT<T>> const& container) | |
| { | |
| std::set<T> result; | |
| for (auto const& entry : container) { | |
| result.emplace(entry.Value); | |
| } | |
| return result; | |
| } | |
| } | |
| // 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(std::string const& path, cmMakefile const* mf, | |
| cmListFileBacktrace const& lfbt); | |
| bool ParseString(cm::string_view str, std::string const& virtual_filename, | |
| cmMakefile const* mf, cmListFileBacktrace const& lfbt); | |
| std::vector<cmListFileFunction> Functions; | |
| }; |