/* 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 #include #include #include #include #include #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 args) : Impl{ std::make_shared(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 const& Arguments() const noexcept { return this->Impl->Arguments; } private: struct Implementation { Implementation(std::string name, long line, long lineEnd, std::vector 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 Arguments; }; std::shared_ptr Impl; }; class cmListFileContext { public: std::string Name; std::string FilePath; long Line = 0; static long const DeferPlaceholderLine = -1; cm::optional 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 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 { using cmConstStack::cmConstStack; friend class cmConstStack; }; #ifndef cmListFileCache_cxx extern template class cmConstStack; #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 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 const& l, BT const& r) { return l.Value == r.Value; } friend bool operator<(BT const& l, BT const& r) { return l.Value < r.Value; } friend bool operator==(BT const& l, T const& r) { return l.Value == r; } friend bool operator==(T const& l, BT const& r) { return l == r.Value; } }; std::ostream& operator<<(std::ostream& os, BT 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 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 Backtraces; friend bool operator==(BTs const& l, BTs const& r) { return l.Value == r.Value; } friend bool operator<(BTs const& l, BTs const& r) { return l.Value < r.Value; } friend bool operator==(BTs const& l, T const& r) { return l.Value == r; } friend bool operator==(T const& l, BTs const& r) { return l == r.Value; } }; std::vector> 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 Functions; };