diff options
author | vitalyisaev <vitalyisaev@yandex-team.com> | 2023-06-29 10:00:50 +0300 |
---|---|---|
committer | vitalyisaev <vitalyisaev@yandex-team.com> | 2023-06-29 10:00:50 +0300 |
commit | 6ffe9e53658409f212834330e13564e4952558f6 (patch) | |
tree | 85b1e00183517648b228aafa7c8fb07f5276f419 /contrib/libs/clang16/include/clang/Lex | |
parent | 726057070f9c5a91fc10fde0d5024913d10f1ab9 (diff) | |
download | ydb-6ffe9e53658409f212834330e13564e4952558f6.tar.gz |
YQ Connector: support managed ClickHouse
Со стороны dqrun можно обратиться к инстансу коннектора, который работает на streaming стенде, и извлечь данные из облачного CH.
Diffstat (limited to 'contrib/libs/clang16/include/clang/Lex')
28 files changed, 10960 insertions, 0 deletions
diff --git a/contrib/libs/clang16/include/clang/Lex/CodeCompletionHandler.h b/contrib/libs/clang16/include/clang/Lex/CodeCompletionHandler.h new file mode 100644 index 0000000000..febcb96924 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Lex/CodeCompletionHandler.h @@ -0,0 +1,88 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===--- CodeCompletionHandler.h - Preprocessor code completion -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the CodeCompletionHandler interface, which provides +// code-completion callbacks for the preprocessor. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_LEX_CODECOMPLETIONHANDLER_H +#define LLVM_CLANG_LEX_CODECOMPLETIONHANDLER_H + +#include "llvm/ADT/StringRef.h" + +namespace clang { + +class IdentifierInfo; +class MacroInfo; + +/// Callback handler that receives notifications when performing code +/// completion within the preprocessor. +class CodeCompletionHandler { +public: + virtual ~CodeCompletionHandler(); + + /// Callback invoked when performing code completion for a preprocessor + /// directive. + /// + /// This callback will be invoked when the preprocessor processes a '#' at the + /// start of a line, followed by the code-completion token. + /// + /// \param InConditional Whether we're inside a preprocessor conditional + /// already. + virtual void CodeCompleteDirective(bool InConditional) { } + + /// Callback invoked when performing code completion within a block of + /// code that was excluded due to preprocessor conditionals. + virtual void CodeCompleteInConditionalExclusion() { } + + /// Callback invoked when performing code completion in a context + /// where the name of a macro is expected. + /// + /// \param IsDefinition Whether this is the definition of a macro, e.g., + /// in a \#define. + virtual void CodeCompleteMacroName(bool IsDefinition) { } + + /// Callback invoked when performing code completion in a preprocessor + /// expression, such as the condition of an \#if or \#elif directive. + virtual void CodeCompletePreprocessorExpression() { } + + /// Callback invoked when performing code completion inside a + /// function-like macro argument. + /// + /// There will be another callback invocation after the macro arguments are + /// parsed, so this callback should generally be used to note that the next + /// callback is invoked inside a macro argument. + virtual void CodeCompleteMacroArgument(IdentifierInfo *Macro, + MacroInfo *MacroInfo, + unsigned ArgumentIndex) { } + + /// Callback invoked when performing code completion inside the filename + /// part of an #include directive. (Also #import, #include_next, etc). + /// \p Dir is the directory relative to the include path. + virtual void CodeCompleteIncludedFile(llvm::StringRef Dir, bool IsAngled) {} + + /// Callback invoked when performing code completion in a part of the + /// file where we expect natural language, e.g., a comment, string, or + /// \#error directive. + virtual void CodeCompleteNaturalLanguage() { } +}; + +} + +#endif // LLVM_CLANG_LEX_CODECOMPLETIONHANDLER_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Lex/DependencyDirectivesScanner.h b/contrib/libs/clang16/include/clang/Lex/DependencyDirectivesScanner.h new file mode 100644 index 0000000000..9ab24d499b --- /dev/null +++ b/contrib/libs/clang16/include/clang/Lex/DependencyDirectivesScanner.h @@ -0,0 +1,150 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- clang/Lex/DependencyDirectivesScanner.h ---------------------*- C++ -*-// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This is the interface for scanning header and source files to get the +/// minimum necessary preprocessor directives for evaluating includes. It +/// reduces the source down to #define, #include, #import, @import, and any +/// conditional preprocessor logic that contains one of those. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_DEPENDENCYDIRECTIVESSCANNER_H +#define LLVM_CLANG_LEX_DEPENDENCYDIRECTIVESSCANNER_H + +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/ArrayRef.h" + +namespace clang { + +namespace tok { +enum TokenKind : unsigned short; +} + +class DiagnosticsEngine; + +namespace dependency_directives_scan { + +/// Token lexed as part of dependency directive scanning. +struct Token { + /// Offset into the original source input. + unsigned Offset; + unsigned Length; + tok::TokenKind Kind; + unsigned short Flags; + + Token(unsigned Offset, unsigned Length, tok::TokenKind Kind, + unsigned short Flags) + : Offset(Offset), Length(Length), Kind(Kind), Flags(Flags) {} + + unsigned getEnd() const { return Offset + Length; } + + bool is(tok::TokenKind K) const { return Kind == K; } + bool isNot(tok::TokenKind K) const { return Kind != K; } + bool isOneOf(tok::TokenKind K1, tok::TokenKind K2) const { + return is(K1) || is(K2); + } + template <typename... Ts> bool isOneOf(tok::TokenKind K1, Ts... Ks) const { + return is(K1) || isOneOf(Ks...); + } +}; + +/// Represents the kind of preprocessor directive or a module declaration that +/// is tracked by the scanner in its token output. +enum DirectiveKind : uint8_t { + pp_none, + pp_include, + pp___include_macros, + pp_define, + pp_undef, + pp_import, + pp_pragma_import, + pp_pragma_once, + pp_pragma_push_macro, + pp_pragma_pop_macro, + pp_pragma_include_alias, + pp_include_next, + pp_if, + pp_ifdef, + pp_ifndef, + pp_elif, + pp_elifdef, + pp_elifndef, + pp_else, + pp_endif, + decl_at_import, + cxx_module_decl, + cxx_import_decl, + cxx_export_module_decl, + cxx_export_import_decl, + /// Indicates that there are tokens present between the last scanned directive + /// and eof. The \p Directive::Tokens array will be empty for this kind. + tokens_present_before_eof, + pp_eof, +}; + +/// Represents a directive that's lexed as part of the dependency directives +/// scanning. It's used to track various preprocessor directives that could +/// potentially have an effect on the dependencies. +struct Directive { + ArrayRef<Token> Tokens; + + /// The kind of token. + DirectiveKind Kind = pp_none; + + Directive() = default; + Directive(DirectiveKind K, ArrayRef<Token> Tokens) + : Tokens(Tokens), Kind(K) {} +}; + +} // end namespace dependency_directives_scan + +/// Scan the input for the preprocessor directives that might have +/// an effect on the dependencies for a compilation unit. +/// +/// This function ignores all non-preprocessor code and anything that +/// can't affect what gets included. +/// +/// \returns false on success, true on error. If the diagnostic engine is not +/// null, an appropriate error is reported using the given input location +/// with the offset that corresponds to the \p Input buffer offset. +bool scanSourceForDependencyDirectives( + StringRef Input, SmallVectorImpl<dependency_directives_scan::Token> &Tokens, + SmallVectorImpl<dependency_directives_scan::Directive> &Directives, + DiagnosticsEngine *Diags = nullptr, + SourceLocation InputSourceLoc = SourceLocation()); + +/// Print the previously scanned dependency directives as minimized source text. +/// +/// \param Source The original source text that the dependency directives were +/// scanned from. +/// \param Directives The previously scanned dependency +/// directives. +/// \param OS the stream to print the dependency directives on. +/// +/// This is used primarily for testing purposes, during dependency scanning the +/// \p Lexer uses the tokens directly, not their printed version. +void printDependencyDirectivesAsSource( + StringRef Source, + ArrayRef<dependency_directives_scan::Directive> Directives, + llvm::raw_ostream &OS); + +} // end namespace clang + +#endif // LLVM_CLANG_LEX_DEPENDENCYDIRECTIVESSCANNER_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Lex/DirectoryLookup.h b/contrib/libs/clang16/include/clang/Lex/DirectoryLookup.h new file mode 100644 index 0000000000..6bab6b846b --- /dev/null +++ b/contrib/libs/clang16/include/clang/Lex/DirectoryLookup.h @@ -0,0 +1,213 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===--- DirectoryLookup.h - Info for searching for headers -----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the DirectoryLookup interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_DIRECTORYLOOKUP_H +#define LLVM_CLANG_LEX_DIRECTORYLOOKUP_H + +#include "clang/Basic/LLVM.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Lex/ModuleMap.h" + +namespace clang { +class HeaderMap; +class HeaderSearch; +class Module; + +/// DirectoryLookup - This class represents one entry in the search list that +/// specifies the search order for directories in \#include directives. It +/// represents either a directory, a framework, or a headermap. +/// +class DirectoryLookup { +public: + enum LookupType_t { + LT_NormalDir, + LT_Framework, + LT_HeaderMap + }; +private: + union DLU { // This union is discriminated by isHeaderMap. + /// Dir - This is the actual directory that we're referring to for a normal + /// directory or a framework. + DirectoryEntryRef Dir; + + /// Map - This is the HeaderMap if this is a headermap lookup. + /// + const HeaderMap *Map; + + DLU(DirectoryEntryRef Dir) : Dir(Dir) {} + DLU(const HeaderMap *Map) : Map(Map) {} + } u; + + /// DirCharacteristic - The type of directory this is: this is an instance of + /// SrcMgr::CharacteristicKind. + unsigned DirCharacteristic : 3; + + /// LookupType - This indicates whether this DirectoryLookup object is a + /// normal directory, a framework, or a headermap. + unsigned LookupType : 2; + + /// Whether this is a header map used when building a framework. + unsigned IsIndexHeaderMap : 1; + + /// Whether we've performed an exhaustive search for module maps + /// within the subdirectories of this directory. + unsigned SearchedAllModuleMaps : 1; + +public: + /// This ctor *does not take ownership* of 'Dir'. + DirectoryLookup(DirectoryEntryRef Dir, SrcMgr::CharacteristicKind DT, + bool isFramework) + : u(Dir), DirCharacteristic(DT), + LookupType(isFramework ? LT_Framework : LT_NormalDir), + IsIndexHeaderMap(false), SearchedAllModuleMaps(false) {} + + /// This ctor *does not take ownership* of 'Map'. + DirectoryLookup(const HeaderMap *Map, SrcMgr::CharacteristicKind DT, + bool isIndexHeaderMap) + : u(Map), DirCharacteristic(DT), LookupType(LT_HeaderMap), + IsIndexHeaderMap(isIndexHeaderMap), SearchedAllModuleMaps(false) {} + + /// getLookupType - Return the kind of directory lookup that this is: either a + /// normal directory, a framework path, or a HeaderMap. + LookupType_t getLookupType() const { return (LookupType_t)LookupType; } + + /// getName - Return the directory or filename corresponding to this lookup + /// object. + StringRef getName() const; + + /// getDir - Return the directory that this entry refers to. + /// + const DirectoryEntry *getDir() const { + return isNormalDir() ? &u.Dir.getDirEntry() : nullptr; + } + + OptionalDirectoryEntryRef getDirRef() const { + return isNormalDir() ? OptionalDirectoryEntryRef(u.Dir) : std::nullopt; + } + + /// getFrameworkDir - Return the directory that this framework refers to. + /// + const DirectoryEntry *getFrameworkDir() const { + return isFramework() ? &u.Dir.getDirEntry() : nullptr; + } + + OptionalDirectoryEntryRef getFrameworkDirRef() const { + return isFramework() ? OptionalDirectoryEntryRef(u.Dir) : std::nullopt; + } + + /// getHeaderMap - Return the directory that this entry refers to. + /// + const HeaderMap *getHeaderMap() const { + return isHeaderMap() ? u.Map : nullptr; + } + + /// isNormalDir - Return true if this is a normal directory, not a header map. + bool isNormalDir() const { return getLookupType() == LT_NormalDir; } + + /// isFramework - True if this is a framework directory. + /// + bool isFramework() const { return getLookupType() == LT_Framework; } + + /// isHeaderMap - Return true if this is a header map, not a normal directory. + bool isHeaderMap() const { return getLookupType() == LT_HeaderMap; } + + /// Determine whether we have already searched this entire + /// directory for module maps. + bool haveSearchedAllModuleMaps() const { return SearchedAllModuleMaps; } + + /// Specify whether we have already searched all of the subdirectories + /// for module maps. + void setSearchedAllModuleMaps(bool SAMM) { + SearchedAllModuleMaps = SAMM; + } + + /// DirCharacteristic - The type of directory this is, one of the DirType enum + /// values. + SrcMgr::CharacteristicKind getDirCharacteristic() const { + return (SrcMgr::CharacteristicKind)DirCharacteristic; + } + + /// Whether this describes a system header directory. + bool isSystemHeaderDirectory() const { + return getDirCharacteristic() != SrcMgr::C_User; + } + + /// Whether this header map is building a framework or not. + bool isIndexHeaderMap() const { + return isHeaderMap() && IsIndexHeaderMap; + } + + /// LookupFile - Lookup the specified file in this search path, returning it + /// if it exists or returning null if not. + /// + /// \param Filename The file to look up relative to the search paths. + /// + /// \param HS The header search instance to search with. + /// + /// \param IncludeLoc the source location of the #include or #import + /// directive. + /// + /// \param SearchPath If not NULL, will be set to the search path relative + /// to which the file was found. + /// + /// \param RelativePath If not NULL, will be set to the path relative to + /// SearchPath at which the file was found. This only differs from the + /// Filename for framework includes. + /// + /// \param RequestingModule The module in which the lookup was performed. + /// + /// \param SuggestedModule If non-null, and the file found is semantically + /// part of a known module, this will be set to the module that should + /// be imported instead of preprocessing/parsing the file found. + /// + /// \param [out] InUserSpecifiedSystemFramework If the file is found, + /// set to true if the file is located in a framework that has been + /// user-specified to be treated as a system framework. + /// + /// \param [out] IsFrameworkFound For a framework directory set to true if + /// specified '.framework' directory is found. + /// + /// \param [out] MappedName if this is a headermap which maps the filename to + /// a framework include ("Foo.h" -> "Foo/Foo.h"), set the new name to this + /// vector and point Filename to it. + OptionalFileEntryRef + LookupFile(StringRef &Filename, HeaderSearch &HS, SourceLocation IncludeLoc, + SmallVectorImpl<char> *SearchPath, + SmallVectorImpl<char> *RelativePath, Module *RequestingModule, + ModuleMap::KnownHeader *SuggestedModule, + bool &InUserSpecifiedSystemFramework, bool &IsFrameworkFound, + bool &IsInHeaderMap, SmallVectorImpl<char> &MappedName, + bool OpenFile = true) const; + +private: + OptionalFileEntryRef DoFrameworkLookup( + StringRef Filename, HeaderSearch &HS, SmallVectorImpl<char> *SearchPath, + SmallVectorImpl<char> *RelativePath, Module *RequestingModule, + ModuleMap::KnownHeader *SuggestedModule, + bool &InUserSpecifiedSystemFramework, bool &IsFrameworkFound) const; +}; + +} // end namespace clang + +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Lex/ExternalPreprocessorSource.h b/contrib/libs/clang16/include/clang/Lex/ExternalPreprocessorSource.h new file mode 100644 index 0000000000..4c47af39ca --- /dev/null +++ b/contrib/libs/clang16/include/clang/Lex/ExternalPreprocessorSource.h @@ -0,0 +1,58 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- ExternalPreprocessorSource.h - Abstract Macro Interface --*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the ExternalPreprocessorSource interface, which enables +// construction of macro definitions from some external source. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_LEX_EXTERNALPREPROCESSORSOURCE_H +#define LLVM_CLANG_LEX_EXTERNALPREPROCESSORSOURCE_H + +namespace clang { + +class IdentifierInfo; +class Module; + +/// Abstract interface for external sources of preprocessor +/// information. +/// +/// This abstract class allows an external sources (such as the \c ASTReader) +/// to provide additional preprocessing information. +class ExternalPreprocessorSource { +public: + virtual ~ExternalPreprocessorSource(); + + /// Read the set of macros defined by this external macro source. + virtual void ReadDefinedMacros() = 0; + + /// Update an out-of-date identifier. + virtual void updateOutOfDateIdentifier(IdentifierInfo &II) = 0; + + /// Return the identifier associated with the given ID number. + /// + /// The ID 0 is associated with the NULL identifier. + virtual IdentifierInfo *GetIdentifier(unsigned ID) = 0; + + /// Map a module ID to a module. + virtual Module *getModule(unsigned ModuleID) = 0; +}; + +} + +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Lex/HeaderMap.h b/contrib/libs/clang16/include/clang/Lex/HeaderMap.h new file mode 100644 index 0000000000..f1c27e3ded --- /dev/null +++ b/contrib/libs/clang16/include/clang/Lex/HeaderMap.h @@ -0,0 +1,114 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===--- HeaderMap.h - A file that acts like dir of symlinks ----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the HeaderMap interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_HEADERMAP_H +#define LLVM_CLANG_LEX_HEADERMAP_H + +#include "clang/Basic/FileManager.h" +#include "clang/Basic/LLVM.h" +#include "clang/Lex/HeaderMapTypes.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/MemoryBuffer.h" +#include <memory> +#include <optional> + +namespace clang { + +struct HMapBucket; +struct HMapHeader; + +/// Implementation for \a HeaderMap that doesn't depend on \a FileManager. +class HeaderMapImpl { + std::unique_ptr<const llvm::MemoryBuffer> FileBuffer; + bool NeedsBSwap; + mutable llvm::StringMap<StringRef> ReverseMap; + +public: + HeaderMapImpl(std::unique_ptr<const llvm::MemoryBuffer> File, bool NeedsBSwap) + : FileBuffer(std::move(File)), NeedsBSwap(NeedsBSwap) {} + + // Check for a valid header and extract the byte swap. + static bool checkHeader(const llvm::MemoryBuffer &File, bool &NeedsByteSwap); + + // Make a call for every Key in the map. + template <typename Func> void forEachKey(Func Callback) const { + const HMapHeader &Hdr = getHeader(); + unsigned NumBuckets = getEndianAdjustedWord(Hdr.NumBuckets); + + for (unsigned Bucket = 0; Bucket < NumBuckets; ++Bucket) { + HMapBucket B = getBucket(Bucket); + if (B.Key != HMAP_EmptyBucketKey) + if (std::optional<StringRef> Key = getString(B.Key)) + Callback(*Key); + } + } + + /// If the specified relative filename is located in this HeaderMap return + /// the filename it is mapped to, otherwise return an empty StringRef. + StringRef lookupFilename(StringRef Filename, + SmallVectorImpl<char> &DestPath) const; + + /// Return the filename of the headermap. + StringRef getFileName() const; + + /// Print the contents of this headermap to stderr. + void dump() const; + + /// Return key for specifed path. + StringRef reverseLookupFilename(StringRef DestPath) const; + +private: + unsigned getEndianAdjustedWord(unsigned X) const; + const HMapHeader &getHeader() const; + HMapBucket getBucket(unsigned BucketNo) const; + + /// Look up the specified string in the string table. If the string index is + /// not valid, return std::nullopt. + std::optional<StringRef> getString(unsigned StrTabIdx) const; +}; + +/// This class represents an Apple concept known as a 'header map'. To the +/// \#include file resolution process, it basically acts like a directory of +/// symlinks to files. Its advantages are that it is dense and more efficient +/// to create and process than a directory of symlinks. +class HeaderMap : private HeaderMapImpl { + HeaderMap(std::unique_ptr<const llvm::MemoryBuffer> File, bool BSwap) + : HeaderMapImpl(std::move(File), BSwap) {} + +public: + /// This attempts to load the specified file as a header map. If it doesn't + /// look like a HeaderMap, it gives up and returns null. + static std::unique_ptr<HeaderMap> Create(const FileEntry *FE, + FileManager &FM); + + using HeaderMapImpl::dump; + using HeaderMapImpl::forEachKey; + using HeaderMapImpl::getFileName; + using HeaderMapImpl::lookupFilename; + using HeaderMapImpl::reverseLookupFilename; +}; + +} // end namespace clang. + +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Lex/HeaderMapTypes.h b/contrib/libs/clang16/include/clang/Lex/HeaderMapTypes.h new file mode 100644 index 0000000000..80710d8031 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Lex/HeaderMapTypes.h @@ -0,0 +1,53 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- HeaderMapTypes.h - Types for the header map format -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_HEADERMAPTYPES_H +#define LLVM_CLANG_LEX_HEADERMAPTYPES_H + +#include <cstdint> + +namespace clang { + +enum { + HMAP_HeaderMagicNumber = ('h' << 24) | ('m' << 16) | ('a' << 8) | 'p', + HMAP_HeaderVersion = 1, + HMAP_EmptyBucketKey = 0 +}; + +struct HMapBucket { + uint32_t Key; // Offset (into strings) of key. + uint32_t Prefix; // Offset (into strings) of value prefix. + uint32_t Suffix; // Offset (into strings) of value suffix. +}; + +struct HMapHeader { + uint32_t Magic; // Magic word, also indicates byte order. + uint16_t Version; // Version number -- currently 1. + uint16_t Reserved; // Reserved for future use - zero for now. + uint32_t StringsOffset; // Offset to start of string pool. + uint32_t NumEntries; // Number of entries in the string table. + uint32_t NumBuckets; // Number of buckets (always a power of 2). + uint32_t MaxValueLength; // Length of longest result path (excluding nul). + // An array of 'NumBuckets' HMapBucket objects follows this header. + // Strings follow the buckets, at StringsOffset. +}; + +} // end namespace clang. + +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Lex/HeaderSearch.h b/contrib/libs/clang16/include/clang/Lex/HeaderSearch.h new file mode 100644 index 0000000000..9806325025 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Lex/HeaderSearch.h @@ -0,0 +1,952 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- HeaderSearch.h - Resolve Header File Locations -----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the HeaderSearch interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_HEADERSEARCH_H +#define LLVM_CLANG_LEX_HEADERSEARCH_H + +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Lex/DirectoryLookup.h" +#include "clang/Lex/HeaderMap.h" +#include "clang/Lex/ModuleMap.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/Support/Allocator.h" +#include <cassert> +#include <cstddef> +#include <memory> +#include <string> +#include <utility> +#include <vector> + +namespace llvm { + +class Triple; + +} // namespace llvm + +namespace clang { + +class DiagnosticsEngine; +class DirectoryEntry; +class ExternalPreprocessorSource; +class FileEntry; +class FileManager; +class HeaderSearch; +class HeaderSearchOptions; +class IdentifierInfo; +class LangOptions; +class Module; +class Preprocessor; +class TargetInfo; + +/// The preprocessor keeps track of this information for each +/// file that is \#included. +struct HeaderFileInfo { + // TODO: Whether the file was imported is not a property of the file itself. + // It's a preprocessor state, move it there. + /// True if this is a \#import'd file. + unsigned isImport : 1; + + /// True if this is a \#pragma once file. + unsigned isPragmaOnce : 1; + + /// Keep track of whether this is a system header, and if so, + /// whether it is C++ clean or not. This can be set by the include paths or + /// by \#pragma gcc system_header. This is an instance of + /// SrcMgr::CharacteristicKind. + unsigned DirInfo : 3; + + /// Whether this header file info was supplied by an external source, + /// and has not changed since. + unsigned External : 1; + + /// Whether this header is part of a module. + unsigned isModuleHeader : 1; + + /// Whether this header is part of the module that we are building. + unsigned isCompilingModuleHeader : 1; + + /// Whether this structure is considered to already have been + /// "resolved", meaning that it was loaded from the external source. + unsigned Resolved : 1; + + /// Whether this is a header inside a framework that is currently + /// being built. + /// + /// When a framework is being built, the headers have not yet been placed + /// into the appropriate framework subdirectories, and therefore are + /// provided via a header map. This bit indicates when this is one of + /// those framework headers. + unsigned IndexHeaderMapHeader : 1; + + /// Whether this file has been looked up as a header. + unsigned IsValid : 1; + + /// The ID number of the controlling macro. + /// + /// This ID number will be non-zero when there is a controlling + /// macro whose IdentifierInfo may not yet have been loaded from + /// external storage. + unsigned ControllingMacroID = 0; + + /// If this file has a \#ifndef XXX (or equivalent) guard that + /// protects the entire contents of the file, this is the identifier + /// for the macro that controls whether or not it has any effect. + /// + /// Note: Most clients should use getControllingMacro() to access + /// the controlling macro of this header, since + /// getControllingMacro() is able to load a controlling macro from + /// external storage. + const IdentifierInfo *ControllingMacro = nullptr; + + /// If this header came from a framework include, this is the name + /// of the framework. + StringRef Framework; + + HeaderFileInfo() + : isImport(false), isPragmaOnce(false), DirInfo(SrcMgr::C_User), + External(false), isModuleHeader(false), isCompilingModuleHeader(false), + Resolved(false), IndexHeaderMapHeader(false), IsValid(false) {} + + /// Retrieve the controlling macro for this header file, if + /// any. + const IdentifierInfo * + getControllingMacro(ExternalPreprocessorSource *External); +}; + +/// An external source of header file information, which may supply +/// information about header files already included. +class ExternalHeaderFileInfoSource { +public: + virtual ~ExternalHeaderFileInfoSource(); + + /// Retrieve the header file information for the given file entry. + /// + /// \returns Header file information for the given file entry, with the + /// \c External bit set. If the file entry is not known, return a + /// default-constructed \c HeaderFileInfo. + virtual HeaderFileInfo GetHeaderFileInfo(const FileEntry *FE) = 0; +}; + +/// This structure is used to record entries in our framework cache. +struct FrameworkCacheEntry { + /// The directory entry which should be used for the cached framework. + OptionalDirectoryEntryRef Directory; + + /// Whether this framework has been "user-specified" to be treated as if it + /// were a system framework (even if it was found outside a system framework + /// directory). + bool IsUserSpecifiedSystemFramework; +}; + +namespace detail { +template <bool Const, typename T> +using Qualified = std::conditional_t<Const, const T, T>; + +/// Forward iterator over the search directories of \c HeaderSearch. +template <bool IsConst> +struct SearchDirIteratorImpl + : llvm::iterator_facade_base<SearchDirIteratorImpl<IsConst>, + std::forward_iterator_tag, + Qualified<IsConst, DirectoryLookup>> { + /// Const -> non-const iterator conversion. + template <typename Enable = std::enable_if<IsConst, bool>> + SearchDirIteratorImpl(const SearchDirIteratorImpl<false> &Other) + : HS(Other.HS), Idx(Other.Idx) {} + + SearchDirIteratorImpl(const SearchDirIteratorImpl &) = default; + + SearchDirIteratorImpl &operator=(const SearchDirIteratorImpl &) = default; + + bool operator==(const SearchDirIteratorImpl &RHS) const { + return HS == RHS.HS && Idx == RHS.Idx; + } + + SearchDirIteratorImpl &operator++() { + assert(*this && "Invalid iterator."); + ++Idx; + return *this; + } + + Qualified<IsConst, DirectoryLookup> &operator*() const { + assert(*this && "Invalid iterator."); + return HS->SearchDirs[Idx]; + } + + /// Creates an invalid iterator. + SearchDirIteratorImpl(std::nullptr_t) : HS(nullptr), Idx(0) {} + + /// Checks whether the iterator is valid. + explicit operator bool() const { return HS != nullptr; } + +private: + /// The parent \c HeaderSearch. This is \c nullptr for invalid iterator. + Qualified<IsConst, HeaderSearch> *HS; + + /// The index of the current element. + size_t Idx; + + /// The constructor that creates a valid iterator. + SearchDirIteratorImpl(Qualified<IsConst, HeaderSearch> &HS, size_t Idx) + : HS(&HS), Idx(Idx) {} + + /// Only HeaderSearch is allowed to instantiate valid iterators. + friend HeaderSearch; + + /// Enables const -> non-const conversion. + friend SearchDirIteratorImpl<!IsConst>; +}; +} // namespace detail + +using ConstSearchDirIterator = detail::SearchDirIteratorImpl<true>; +using SearchDirIterator = detail::SearchDirIteratorImpl<false>; + +using ConstSearchDirRange = llvm::iterator_range<ConstSearchDirIterator>; +using SearchDirRange = llvm::iterator_range<SearchDirIterator>; + +/// Encapsulates the information needed to find the file referenced +/// by a \#include or \#include_next, (sub-)framework lookup, etc. +class HeaderSearch { + friend class DirectoryLookup; + + friend ConstSearchDirIterator; + friend SearchDirIterator; + + /// Header-search options used to initialize this header search. + std::shared_ptr<HeaderSearchOptions> HSOpts; + + /// Mapping from SearchDir to HeaderSearchOptions::UserEntries indices. + llvm::DenseMap<unsigned, unsigned> SearchDirToHSEntry; + + DiagnosticsEngine &Diags; + FileManager &FileMgr; + + /// \#include search path information. Requests for \#include "x" search the + /// directory of the \#including file first, then each directory in SearchDirs + /// consecutively. Requests for <x> search the current dir first, then each + /// directory in SearchDirs, starting at AngledDirIdx, consecutively. If + /// NoCurDirSearch is true, then the check for the file in the current + /// directory is suppressed. + std::vector<DirectoryLookup> SearchDirs; + /// Whether the DirectoryLookup at the corresponding index in SearchDirs has + /// been successfully used to lookup a file. + std::vector<bool> SearchDirsUsage; + unsigned AngledDirIdx = 0; + unsigned SystemDirIdx = 0; + bool NoCurDirSearch = false; + + /// Maps HeaderMap keys to SearchDir indices. When HeaderMaps are used + /// heavily, SearchDirs can start with thousands of HeaderMaps, so this Index + /// lets us avoid scanning them all to find a match. + llvm::StringMap<unsigned, llvm::BumpPtrAllocator> SearchDirHeaderMapIndex; + + /// The index of the first SearchDir that isn't a header map. + unsigned FirstNonHeaderMapSearchDirIdx = 0; + + /// \#include prefixes for which the 'system header' property is + /// overridden. + /// + /// For a \#include "x" or \#include \<x> directive, the last string in this + /// list which is a prefix of 'x' determines whether the file is treated as + /// a system header. + std::vector<std::pair<std::string, bool>> SystemHeaderPrefixes; + + /// The hash used for module cache paths. + std::string ModuleHash; + + /// The path to the module cache. + std::string ModuleCachePath; + + /// All of the preprocessor-specific data about files that are + /// included, indexed by the FileEntry's UID. + mutable std::vector<HeaderFileInfo> FileInfo; + + /// Keeps track of each lookup performed by LookupFile. + struct LookupFileCacheInfo { + /// Starting search directory iterator that the cached search was performed + /// from. If there is a hit and this value doesn't match the current query, + /// the cache has to be ignored. + ConstSearchDirIterator StartIt = nullptr; + + /// The search directory iterator that satisfied the query. + ConstSearchDirIterator HitIt = nullptr; + + /// This is non-null if the original filename was mapped to a framework + /// include via a headermap. + const char *MappedName = nullptr; + + /// Default constructor -- Initialize all members with zero. + LookupFileCacheInfo() = default; + + void reset(ConstSearchDirIterator NewStartIt) { + StartIt = NewStartIt; + MappedName = nullptr; + } + }; + llvm::StringMap<LookupFileCacheInfo, llvm::BumpPtrAllocator> LookupFileCache; + + /// Collection mapping a framework or subframework + /// name like "Carbon" to the Carbon.framework directory. + llvm::StringMap<FrameworkCacheEntry, llvm::BumpPtrAllocator> FrameworkMap; + + /// Maps include file names (including the quotes or + /// angle brackets) to other include file names. This is used to support the + /// include_alias pragma for Microsoft compatibility. + using IncludeAliasMap = + llvm::StringMap<std::string, llvm::BumpPtrAllocator>; + std::unique_ptr<IncludeAliasMap> IncludeAliases; + + /// This is a mapping from FileEntry -> HeaderMap, uniquing headermaps. + std::vector<std::pair<const FileEntry *, std::unique_ptr<HeaderMap>>> HeaderMaps; + + /// The mapping between modules and headers. + mutable ModuleMap ModMap; + + /// Describes whether a given directory has a module map in it. + llvm::DenseMap<const DirectoryEntry *, bool> DirectoryHasModuleMap; + + /// Set of module map files we've already loaded, and a flag indicating + /// whether they were valid or not. + llvm::DenseMap<const FileEntry *, bool> LoadedModuleMaps; + + // A map of discovered headers with their associated include file name. + llvm::DenseMap<const FileEntry *, llvm::SmallString<64>> IncludeNames; + + /// Uniqued set of framework names, which is used to track which + /// headers were included as framework headers. + llvm::StringSet<llvm::BumpPtrAllocator> FrameworkNames; + + /// Entity used to resolve the identifier IDs of controlling + /// macros into IdentifierInfo pointers, and keep the identifire up to date, + /// as needed. + ExternalPreprocessorSource *ExternalLookup = nullptr; + + /// Entity used to look up stored header file information. + ExternalHeaderFileInfoSource *ExternalSource = nullptr; + + /// Scan all of the header maps at the beginning of SearchDirs and + /// map their keys to the SearchDir index of their header map. + void indexInitialHeaderMaps(); + +public: + HeaderSearch(std::shared_ptr<HeaderSearchOptions> HSOpts, + SourceManager &SourceMgr, DiagnosticsEngine &Diags, + const LangOptions &LangOpts, const TargetInfo *Target); + HeaderSearch(const HeaderSearch &) = delete; + HeaderSearch &operator=(const HeaderSearch &) = delete; + + /// Retrieve the header-search options with which this header search + /// was initialized. + HeaderSearchOptions &getHeaderSearchOpts() const { return *HSOpts; } + + FileManager &getFileMgr() const { return FileMgr; } + + DiagnosticsEngine &getDiags() const { return Diags; } + + /// Interface for setting the file search paths. + void SetSearchPaths(std::vector<DirectoryLookup> dirs, unsigned angledDirIdx, + unsigned systemDirIdx, bool noCurDirSearch, + llvm::DenseMap<unsigned, unsigned> searchDirToHSEntry); + + /// Add an additional search path. + void AddSearchPath(const DirectoryLookup &dir, bool isAngled); + + /// Add an additional system search path. + void AddSystemSearchPath(const DirectoryLookup &dir) { + SearchDirs.push_back(dir); + SearchDirsUsage.push_back(false); + } + + /// Set the list of system header prefixes. + void SetSystemHeaderPrefixes(ArrayRef<std::pair<std::string, bool>> P) { + SystemHeaderPrefixes.assign(P.begin(), P.end()); + } + + /// Checks whether the map exists or not. + bool HasIncludeAliasMap() const { return (bool)IncludeAliases; } + + /// Map the source include name to the dest include name. + /// + /// The Source should include the angle brackets or quotes, the dest + /// should not. This allows for distinction between <> and "" headers. + void AddIncludeAlias(StringRef Source, StringRef Dest) { + if (!IncludeAliases) + IncludeAliases.reset(new IncludeAliasMap); + (*IncludeAliases)[Source] = std::string(Dest); + } + + /// Maps one header file name to a different header + /// file name, for use with the include_alias pragma. Note that the source + /// file name should include the angle brackets or quotes. Returns StringRef + /// as null if the header cannot be mapped. + StringRef MapHeaderToIncludeAlias(StringRef Source) { + assert(IncludeAliases && "Trying to map headers when there's no map"); + + // Do any filename replacements before anything else + IncludeAliasMap::const_iterator Iter = IncludeAliases->find(Source); + if (Iter != IncludeAliases->end()) + return Iter->second; + return {}; + } + + /// Set the hash to use for module cache paths. + void setModuleHash(StringRef Hash) { ModuleHash = std::string(Hash); } + + /// Set the path to the module cache. + void setModuleCachePath(StringRef CachePath) { + ModuleCachePath = std::string(CachePath); + } + + /// Retrieve the module hash. + StringRef getModuleHash() const { return ModuleHash; } + + /// Retrieve the path to the module cache. + StringRef getModuleCachePath() const { return ModuleCachePath; } + + /// Consider modules when including files from this directory. + void setDirectoryHasModuleMap(const DirectoryEntry* Dir) { + DirectoryHasModuleMap[Dir] = true; + } + + /// Forget everything we know about headers so far. + void ClearFileInfo() { + FileInfo.clear(); + } + + void SetExternalLookup(ExternalPreprocessorSource *EPS) { + ExternalLookup = EPS; + } + + ExternalPreprocessorSource *getExternalLookup() const { + return ExternalLookup; + } + + /// Set the external source of header information. + void SetExternalSource(ExternalHeaderFileInfoSource *ES) { + ExternalSource = ES; + } + + /// Set the target information for the header search, if not + /// already known. + void setTarget(const TargetInfo &Target); + + /// Given a "foo" or \<foo> reference, look up the indicated file, + /// return null on failure. + /// + /// \returns If successful, this returns 'UsedDir', the DirectoryLookup member + /// the file was found in, or null if not applicable. + /// + /// \param IncludeLoc Used for diagnostics if valid. + /// + /// \param isAngled indicates whether the file reference is a <> reference. + /// + /// \param CurDir If non-null, the file was found in the specified directory + /// search location. This is used to implement \#include_next. + /// + /// \param Includers Indicates where the \#including file(s) are, in case + /// relative searches are needed. In reverse order of inclusion. + /// + /// \param SearchPath If non-null, will be set to the search path relative + /// to which the file was found. If the include path is absolute, SearchPath + /// will be set to an empty string. + /// + /// \param RelativePath If non-null, will be set to the path relative to + /// SearchPath at which the file was found. This only differs from the + /// Filename for framework includes. + /// + /// \param SuggestedModule If non-null, and the file found is semantically + /// part of a known module, this will be set to the module that should + /// be imported instead of preprocessing/parsing the file found. + /// + /// \param IsMapped If non-null, and the search involved header maps, set to + /// true. + /// + /// \param IsFrameworkFound If non-null, will be set to true if a framework is + /// found in any of searched SearchDirs. Will be set to false if a framework + /// is found only through header maps. Doesn't guarantee the requested file is + /// found. + OptionalFileEntryRef LookupFile( + StringRef Filename, SourceLocation IncludeLoc, bool isAngled, + ConstSearchDirIterator FromDir, ConstSearchDirIterator *CurDir, + ArrayRef<std::pair<const FileEntry *, const DirectoryEntry *>> Includers, + SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath, + Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule, + bool *IsMapped, bool *IsFrameworkFound, bool SkipCache = false, + bool BuildSystemModule = false, bool OpenFile = true, + bool CacheFailures = true); + + /// Look up a subframework for the specified \#include file. + /// + /// For example, if \#include'ing <HIToolbox/HIToolbox.h> from + /// within ".../Carbon.framework/Headers/Carbon.h", check to see if + /// HIToolbox is a subframework within Carbon.framework. If so, return + /// the FileEntry for the designated file, otherwise return null. + OptionalFileEntryRef LookupSubframeworkHeader( + StringRef Filename, const FileEntry *ContextFileEnt, + SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath, + Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule); + + /// Look up the specified framework name in our framework cache. + /// \returns The DirectoryEntry it is in if we know, null otherwise. + FrameworkCacheEntry &LookupFrameworkCache(StringRef FWName) { + return FrameworkMap[FWName]; + } + + /// Mark the specified file as a target of a \#include, + /// \#include_next, or \#import directive. + /// + /// \return false if \#including the file will have no effect or true + /// if we should include it. + bool ShouldEnterIncludeFile(Preprocessor &PP, const FileEntry *File, + bool isImport, bool ModulesEnabled, Module *M, + bool &IsFirstIncludeOfFile); + + /// Return whether the specified file is a normal header, + /// a system header, or a C++ friendly system header. + SrcMgr::CharacteristicKind getFileDirFlavor(const FileEntry *File) { + return (SrcMgr::CharacteristicKind)getFileInfo(File).DirInfo; + } + + /// Mark the specified file as a "once only" file due to + /// \#pragma once. + void MarkFileIncludeOnce(const FileEntry *File) { + HeaderFileInfo &FI = getFileInfo(File); + FI.isPragmaOnce = true; + } + + /// Mark the specified file as a system header, e.g. due to + /// \#pragma GCC system_header. + void MarkFileSystemHeader(const FileEntry *File) { + getFileInfo(File).DirInfo = SrcMgr::C_System; + } + + /// Mark the specified file as part of a module. + void MarkFileModuleHeader(const FileEntry *FE, + ModuleMap::ModuleHeaderRole Role, + bool isCompilingModuleHeader); + + /// Mark the specified file as having a controlling macro. + /// + /// This is used by the multiple-include optimization to eliminate + /// no-op \#includes. + void SetFileControllingMacro(const FileEntry *File, + const IdentifierInfo *ControllingMacro) { + getFileInfo(File).ControllingMacro = ControllingMacro; + } + + /// Determine whether this file is intended to be safe from + /// multiple inclusions, e.g., it has \#pragma once or a controlling + /// macro. + /// + /// This routine does not consider the effect of \#import + bool isFileMultipleIncludeGuarded(const FileEntry *File); + + /// Determine whether the given file is known to have ever been \#imported. + bool hasFileBeenImported(const FileEntry *File) { + const HeaderFileInfo *FI = getExistingFileInfo(File); + return FI && FI->isImport; + } + + /// Determine which HeaderSearchOptions::UserEntries have been successfully + /// used so far and mark their index with 'true' in the resulting bit vector. + /// Note: implicit module maps don't contribute to entry usage. + std::vector<bool> computeUserEntryUsage() const; + + /// This method returns a HeaderMap for the specified + /// FileEntry, uniquing them through the 'HeaderMaps' datastructure. + const HeaderMap *CreateHeaderMap(const FileEntry *FE); + + /// Get filenames for all registered header maps. + void getHeaderMapFileNames(SmallVectorImpl<std::string> &Names) const; + + /// Retrieve the name of the cached module file that should be used + /// to load the given module. + /// + /// \param Module The module whose module file name will be returned. + /// + /// \returns The name of the module file that corresponds to this module, + /// or an empty string if this module does not correspond to any module file. + std::string getCachedModuleFileName(Module *Module); + + /// Retrieve the name of the prebuilt module file that should be used + /// to load a module with the given name. + /// + /// \param ModuleName The module whose module file name will be returned. + /// + /// \param FileMapOnly If true, then only look in the explicit module name + // to file name map and skip the directory search. + /// + /// \returns The name of the module file that corresponds to this module, + /// or an empty string if this module does not correspond to any module file. + std::string getPrebuiltModuleFileName(StringRef ModuleName, + bool FileMapOnly = false); + + /// Retrieve the name of the prebuilt module file that should be used + /// to load the given module. + /// + /// \param Module The module whose module file name will be returned. + /// + /// \returns The name of the module file that corresponds to this module, + /// or an empty string if this module does not correspond to any module file. + std::string getPrebuiltImplicitModuleFileName(Module *Module); + + /// Retrieve the name of the (to-be-)cached module file that should + /// be used to load a module with the given name. + /// + /// \param ModuleName The module whose module file name will be returned. + /// + /// \param ModuleMapPath A path that when combined with \c ModuleName + /// uniquely identifies this module. See Module::ModuleMap. + /// + /// \returns The name of the module file that corresponds to this module, + /// or an empty string if this module does not correspond to any module file. + std::string getCachedModuleFileName(StringRef ModuleName, + StringRef ModuleMapPath); + + /// Lookup a module Search for a module with the given name. + /// + /// \param ModuleName The name of the module we're looking for. + /// + /// \param ImportLoc Location of the module include/import. + /// + /// \param AllowSearch Whether we are allowed to search in the various + /// search directories to produce a module definition. If not, this lookup + /// will only return an already-known module. + /// + /// \param AllowExtraModuleMapSearch Whether we allow to search modulemaps + /// in subdirectories. + /// + /// \returns The module with the given name. + Module *lookupModule(StringRef ModuleName, + SourceLocation ImportLoc = SourceLocation(), + bool AllowSearch = true, + bool AllowExtraModuleMapSearch = false); + + /// Try to find a module map file in the given directory, returning + /// \c nullptr if none is found. + const FileEntry *lookupModuleMapFile(const DirectoryEntry *Dir, + bool IsFramework); + + /// Determine whether there is a module map that may map the header + /// with the given file name to a (sub)module. + /// Always returns false if modules are disabled. + /// + /// \param Filename The name of the file. + /// + /// \param Root The "root" directory, at which we should stop looking for + /// module maps. + /// + /// \param IsSystem Whether the directories we're looking at are system + /// header directories. + bool hasModuleMap(StringRef Filename, const DirectoryEntry *Root, + bool IsSystem); + + /// Retrieve the module that corresponds to the given file, if any. + /// + /// \param File The header that we wish to map to a module. + /// \param AllowTextual Whether we want to find textual headers too. + ModuleMap::KnownHeader findModuleForHeader(const FileEntry *File, + bool AllowTextual = false, + bool AllowExcluded = false) const; + + /// Retrieve all the modules corresponding to the given file. + /// + /// \ref findModuleForHeader should typically be used instead of this. + ArrayRef<ModuleMap::KnownHeader> + findAllModulesForHeader(const FileEntry *File) const; + + /// Read the contents of the given module map file. + /// + /// \param File The module map file. + /// \param IsSystem Whether this file is in a system header directory. + /// \param ID If the module map file is already mapped (perhaps as part of + /// processing a preprocessed module), the ID of the file. + /// \param Offset [inout] An offset within ID to start parsing. On exit, + /// filled by the end of the parsed contents (either EOF or the + /// location of an end-of-module-map pragma). + /// \param OriginalModuleMapFile The original path to the module map file, + /// used to resolve paths within the module (this is required when + /// building the module from preprocessed source). + /// \returns true if an error occurred, false otherwise. + bool loadModuleMapFile(const FileEntry *File, bool IsSystem, + FileID ID = FileID(), unsigned *Offset = nullptr, + StringRef OriginalModuleMapFile = StringRef()); + + /// Collect the set of all known, top-level modules. + /// + /// \param Modules Will be filled with the set of known, top-level modules. + void collectAllModules(SmallVectorImpl<Module *> &Modules); + + /// Load all known, top-level system modules. + void loadTopLevelSystemModules(); + +private: + /// Lookup a module with the given module name and search-name. + /// + /// \param ModuleName The name of the module we're looking for. + /// + /// \param SearchName The "search-name" to derive filesystem paths from + /// when looking for the module map; this is usually equal to ModuleName, + /// but for compatibility with some buggy frameworks, additional attempts + /// may be made to find the module under a related-but-different search-name. + /// + /// \param ImportLoc Location of the module include/import. + /// + /// \param AllowExtraModuleMapSearch Whether we allow to search modulemaps + /// in subdirectories. + /// + /// \returns The module named ModuleName. + Module *lookupModule(StringRef ModuleName, StringRef SearchName, + SourceLocation ImportLoc, + bool AllowExtraModuleMapSearch = false); + + /// Retrieve the name of the (to-be-)cached module file that should + /// be used to load a module with the given name. + /// + /// \param ModuleName The module whose module file name will be returned. + /// + /// \param ModuleMapPath A path that when combined with \c ModuleName + /// uniquely identifies this module. See Module::ModuleMap. + /// + /// \param CachePath A path to the module cache. + /// + /// \returns The name of the module file that corresponds to this module, + /// or an empty string if this module does not correspond to any module file. + std::string getCachedModuleFileNameImpl(StringRef ModuleName, + StringRef ModuleMapPath, + StringRef CachePath); + + /// Retrieve a module with the given name, which may be part of the + /// given framework. + /// + /// \param Name The name of the module to retrieve. + /// + /// \param Dir The framework directory (e.g., ModuleName.framework). + /// + /// \param IsSystem Whether the framework directory is part of the system + /// frameworks. + /// + /// \returns The module, if found; otherwise, null. + Module *loadFrameworkModule(StringRef Name, DirectoryEntryRef Dir, + bool IsSystem); + + /// Load all of the module maps within the immediate subdirectories + /// of the given search directory. + void loadSubdirectoryModuleMaps(DirectoryLookup &SearchDir); + + /// Find and suggest a usable module for the given file. + /// + /// \return \c true if the file can be used, \c false if we are not permitted to + /// find this file due to requirements from \p RequestingModule. + bool findUsableModuleForHeader(const FileEntry *File, + const DirectoryEntry *Root, + Module *RequestingModule, + ModuleMap::KnownHeader *SuggestedModule, + bool IsSystemHeaderDir); + + /// Find and suggest a usable module for the given file, which is part of + /// the specified framework. + /// + /// \return \c true if the file can be used, \c false if we are not permitted to + /// find this file due to requirements from \p RequestingModule. + bool findUsableModuleForFrameworkHeader( + const FileEntry *File, StringRef FrameworkName, Module *RequestingModule, + ModuleMap::KnownHeader *SuggestedModule, bool IsSystemFramework); + + /// Look up the file with the specified name and determine its owning + /// module. + OptionalFileEntryRef + getFileAndSuggestModule(StringRef FileName, SourceLocation IncludeLoc, + const DirectoryEntry *Dir, bool IsSystemHeaderDir, + Module *RequestingModule, + ModuleMap::KnownHeader *SuggestedModule, + bool OpenFile = true, bool CacheFailures = true); + + /// Cache the result of a successful lookup at the given include location + /// using the search path at \c HitIt. + void cacheLookupSuccess(LookupFileCacheInfo &CacheLookup, + ConstSearchDirIterator HitIt, + SourceLocation IncludeLoc); + + /// Note that a lookup at the given include location was successful using the + /// search path at index `HitIdx`. + void noteLookupUsage(unsigned HitIdx, SourceLocation IncludeLoc); + +public: + /// Retrieve the module map. + ModuleMap &getModuleMap() { return ModMap; } + + /// Retrieve the module map. + const ModuleMap &getModuleMap() const { return ModMap; } + + unsigned header_file_size() const { return FileInfo.size(); } + + /// Return the HeaderFileInfo structure for the specified FileEntry, + /// in preparation for updating it in some way. + HeaderFileInfo &getFileInfo(const FileEntry *FE); + + /// Return the HeaderFileInfo structure for the specified FileEntry, + /// if it has ever been filled in. + /// \param WantExternal Whether the caller wants purely-external header file + /// info (where \p External is true). + const HeaderFileInfo *getExistingFileInfo(const FileEntry *FE, + bool WantExternal = true) const; + + SearchDirIterator search_dir_begin() { return {*this, 0}; } + SearchDirIterator search_dir_end() { return {*this, SearchDirs.size()}; } + SearchDirRange search_dir_range() { + return {search_dir_begin(), search_dir_end()}; + } + + ConstSearchDirIterator search_dir_begin() const { return quoted_dir_begin(); } + ConstSearchDirIterator search_dir_nth(size_t n) const { + assert(n < SearchDirs.size()); + return {*this, n}; + } + ConstSearchDirIterator search_dir_end() const { return system_dir_end(); } + ConstSearchDirRange search_dir_range() const { + return {search_dir_begin(), search_dir_end()}; + } + + unsigned search_dir_size() const { return SearchDirs.size(); } + + ConstSearchDirIterator quoted_dir_begin() const { return {*this, 0}; } + ConstSearchDirIterator quoted_dir_end() const { return angled_dir_begin(); } + + ConstSearchDirIterator angled_dir_begin() const { + return {*this, AngledDirIdx}; + } + ConstSearchDirIterator angled_dir_end() const { return system_dir_begin(); } + + ConstSearchDirIterator system_dir_begin() const { + return {*this, SystemDirIdx}; + } + ConstSearchDirIterator system_dir_end() const { + return {*this, SearchDirs.size()}; + } + + /// Get the index of the given search directory. + unsigned searchDirIdx(const DirectoryLookup &DL) const; + + /// Retrieve a uniqued framework name. + StringRef getUniqueFrameworkName(StringRef Framework); + + /// Retrieve the include name for the header. + /// + /// \param File The entry for a given header. + /// \returns The name of how the file was included when the header's location + /// was resolved. + StringRef getIncludeNameForHeader(const FileEntry *File) const; + + /// Suggest a path by which the specified file could be found, for use in + /// diagnostics to suggest a #include. Returned path will only contain forward + /// slashes as separators. MainFile is the absolute path of the file that we + /// are generating the diagnostics for. It will try to shorten the path using + /// MainFile location, if none of the include search directories were prefix + /// of File. + /// + /// \param IsSystem If non-null, filled in to indicate whether the suggested + /// path is relative to a system header directory. + std::string suggestPathToFileForDiagnostics(const FileEntry *File, + llvm::StringRef MainFile, + bool *IsSystem = nullptr); + + /// Suggest a path by which the specified file could be found, for use in + /// diagnostics to suggest a #include. Returned path will only contain forward + /// slashes as separators. MainFile is the absolute path of the file that we + /// are generating the diagnostics for. It will try to shorten the path using + /// MainFile location, if none of the include search directories were prefix + /// of File. + /// + /// \param WorkingDir If non-empty, this will be prepended to search directory + /// paths that are relative. + std::string suggestPathToFileForDiagnostics(llvm::StringRef File, + llvm::StringRef WorkingDir, + llvm::StringRef MainFile, + bool *IsSystem = nullptr); + + void PrintStats(); + + size_t getTotalMemory() const; + +private: + /// Describes what happened when we tried to load a module map file. + enum LoadModuleMapResult { + /// The module map file had already been loaded. + LMM_AlreadyLoaded, + + /// The module map file was loaded by this invocation. + LMM_NewlyLoaded, + + /// There is was directory with the given name. + LMM_NoDirectory, + + /// There was either no module map file or the module map file was + /// invalid. + LMM_InvalidModuleMap + }; + + LoadModuleMapResult loadModuleMapFileImpl(const FileEntry *File, + bool IsSystem, + DirectoryEntryRef Dir, + FileID ID = FileID(), + unsigned *Offset = nullptr); + + /// Try to load the module map file in the given directory. + /// + /// \param DirName The name of the directory where we will look for a module + /// map file. + /// \param IsSystem Whether this is a system header directory. + /// \param IsFramework Whether this is a framework directory. + /// + /// \returns The result of attempting to load the module map file from the + /// named directory. + LoadModuleMapResult loadModuleMapFile(StringRef DirName, bool IsSystem, + bool IsFramework); + + /// Try to load the module map file in the given directory. + /// + /// \param Dir The directory where we will look for a module map file. + /// \param IsSystem Whether this is a system header directory. + /// \param IsFramework Whether this is a framework directory. + /// + /// \returns The result of attempting to load the module map file from the + /// named directory. + LoadModuleMapResult loadModuleMapFile(DirectoryEntryRef Dir, bool IsSystem, + bool IsFramework); +}; + +/// Apply the header search options to get given HeaderSearch object. +void ApplyHeaderSearchOptions(HeaderSearch &HS, + const HeaderSearchOptions &HSOpts, + const LangOptions &Lang, + const llvm::Triple &triple); + +} // namespace clang + +#endif // LLVM_CLANG_LEX_HEADERSEARCH_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Lex/HeaderSearchOptions.h b/contrib/libs/clang16/include/clang/Lex/HeaderSearchOptions.h new file mode 100644 index 0000000000..6103349f72 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Lex/HeaderSearchOptions.h @@ -0,0 +1,299 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- HeaderSearchOptions.h ------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_HEADERSEARCHOPTIONS_H +#define LLVM_CLANG_LEX_HEADERSEARCHOPTIONS_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/CachedHashString.h" +#include "llvm/ADT/Hashing.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/HashBuilder.h" +#include <cstdint> +#include <map> +#include <string> +#include <vector> + +namespace clang { + +namespace frontend { + +/// IncludeDirGroup - Identifies the group an include Entry belongs to, +/// representing its relative positive in the search list. +/// \#include directives whose paths are enclosed by string quotes ("") +/// start searching at the Quoted group (specified by '-iquote'), +/// then search the Angled group, then the System group, etc. +enum IncludeDirGroup { + /// '\#include ""' paths, added by 'gcc -iquote'. + Quoted = 0, + + /// Paths for '\#include <>' added by '-I'. + Angled, + + /// Like Angled, but marks header maps used when building frameworks. + IndexHeaderMap, + + /// Like Angled, but marks system directories. + System, + + /// Like System, but headers are implicitly wrapped in extern "C". + ExternCSystem, + + /// Like System, but only used for C. + CSystem, + + /// Like System, but only used for C++. + CXXSystem, + + /// Like System, but only used for ObjC. + ObjCSystem, + + /// Like System, but only used for ObjC++. + ObjCXXSystem, + + /// Like System, but searched after the system directories. + After +}; + +} // namespace frontend + +/// HeaderSearchOptions - Helper class for storing options related to the +/// initialization of the HeaderSearch object. +class HeaderSearchOptions { +public: + struct Entry { + std::string Path; + frontend::IncludeDirGroup Group; + unsigned IsFramework : 1; + + /// IgnoreSysRoot - This is false if an absolute path should be treated + /// relative to the sysroot, or true if it should always be the absolute + /// path. + unsigned IgnoreSysRoot : 1; + + Entry(StringRef path, frontend::IncludeDirGroup group, bool isFramework, + bool ignoreSysRoot) + : Path(path), Group(group), IsFramework(isFramework), + IgnoreSysRoot(ignoreSysRoot) {} + }; + + struct SystemHeaderPrefix { + /// A prefix to be matched against paths in \#include directives. + std::string Prefix; + + /// True if paths beginning with this prefix should be treated as system + /// headers. + bool IsSystemHeader; + + SystemHeaderPrefix(StringRef Prefix, bool IsSystemHeader) + : Prefix(Prefix), IsSystemHeader(IsSystemHeader) {} + }; + + /// If non-empty, the directory to use as a "virtual system root" for include + /// paths. + std::string Sysroot; + + /// User specified include entries. + std::vector<Entry> UserEntries; + + /// User-specified system header prefixes. + std::vector<SystemHeaderPrefix> SystemHeaderPrefixes; + + /// The directory which holds the compiler resource files (builtin includes, + /// etc.). + std::string ResourceDir; + + /// The directory used for the module cache. + std::string ModuleCachePath; + + /// The directory used for a user build. + std::string ModuleUserBuildPath; + + /// The mapping of module names to prebuilt module files. + std::map<std::string, std::string, std::less<>> PrebuiltModuleFiles; + + /// The directories used to load prebuilt module files. + std::vector<std::string> PrebuiltModulePaths; + + /// The module/pch container format. + std::string ModuleFormat; + + /// Whether we should disable the use of the hash string within the + /// module cache. + /// + /// Note: Only used for testing! + unsigned DisableModuleHash : 1; + + /// Implicit module maps. This option is enabld by default when + /// modules is enabled. + unsigned ImplicitModuleMaps : 1; + + /// Set the 'home directory' of a module map file to the current + /// working directory (or the home directory of the module map file that + /// contained the 'extern module' directive importing this module map file + /// if any) rather than the directory containing the module map file. + // + /// The home directory is where we look for files named in the module map + /// file. + unsigned ModuleMapFileHomeIsCwd : 1; + + /// Set the base path of a built module file to be the current working + /// directory. This is useful for sharing module files across machines + /// that build with different paths without having to rewrite all + /// modulemap files to have working directory relative paths. + unsigned ModuleFileHomeIsCwd : 1; + + /// Also search for prebuilt implicit modules in the prebuilt module cache + /// path. + unsigned EnablePrebuiltImplicitModules : 1; + + /// The interval (in seconds) between pruning operations. + /// + /// This operation is expensive, because it requires Clang to walk through + /// the directory structure of the module cache, stat()'ing and removing + /// files. + /// + /// The default value is large, e.g., the operation runs once a week. + unsigned ModuleCachePruneInterval = 7 * 24 * 60 * 60; + + /// The time (in seconds) after which an unused module file will be + /// considered unused and will, therefore, be pruned. + /// + /// When the module cache is pruned, any module file that has not been + /// accessed in this many seconds will be removed. The default value is + /// large, e.g., a month, to avoid forcing infrequently-used modules to be + /// regenerated often. + unsigned ModuleCachePruneAfter = 31 * 24 * 60 * 60; + + /// The time in seconds when the build session started. + /// + /// This time is used by other optimizations in header search and module + /// loading. + uint64_t BuildSessionTimestamp = 0; + + /// The set of macro names that should be ignored for the purposes + /// of computing the module hash. + llvm::SmallSetVector<llvm::CachedHashString, 16> ModulesIgnoreMacros; + + /// The set of user-provided virtual filesystem overlay files. + std::vector<std::string> VFSOverlayFiles; + + /// Include the compiler builtin includes. + unsigned UseBuiltinIncludes : 1; + + /// Include the system standard include search directories. + unsigned UseStandardSystemIncludes : 1; + + /// Include the system standard C++ library include search directories. + unsigned UseStandardCXXIncludes : 1; + + /// Use libc++ instead of the default libstdc++. + unsigned UseLibcxx : 1; + + /// Whether header search information should be output as for -v. + unsigned Verbose : 1; + + /// Whether header search should be case-insensitive. + unsigned CaseInsensitive : 1; + + /// If true, skip verifying input files used by modules if the + /// module was already verified during this build session (see + /// \c BuildSessionTimestamp). + unsigned ModulesValidateOncePerBuildSession : 1; + + /// Whether to validate system input files when a module is loaded. + unsigned ModulesValidateSystemHeaders : 1; + + // Whether the content of input files should be hashed and used to + // validate consistency. + unsigned ValidateASTInputFilesContent : 1; + + /// Whether the module includes debug information (-gmodules). + unsigned UseDebugInfo : 1; + + unsigned ModulesValidateDiagnosticOptions : 1; + + unsigned ModulesHashContent : 1; + + /// Whether we should include all things that could impact the module in the + /// hash. + /// + /// This includes things like the full header search path, and enabled + /// diagnostics. + unsigned ModulesStrictContextHash : 1; + + HeaderSearchOptions(StringRef _Sysroot = "/") + : Sysroot(_Sysroot), ModuleFormat("raw"), DisableModuleHash(false), + ImplicitModuleMaps(false), ModuleMapFileHomeIsCwd(false), + ModuleFileHomeIsCwd(false), EnablePrebuiltImplicitModules(false), + UseBuiltinIncludes(true), UseStandardSystemIncludes(true), + UseStandardCXXIncludes(true), UseLibcxx(false), Verbose(false), CaseInsensitive(false), + ModulesValidateOncePerBuildSession(false), + ModulesValidateSystemHeaders(false), + ValidateASTInputFilesContent(false), UseDebugInfo(false), + ModulesValidateDiagnosticOptions(true), ModulesHashContent(false), + ModulesStrictContextHash(false) {} + + /// AddPath - Add the \p Path path to the specified \p Group list. + void AddPath(StringRef Path, frontend::IncludeDirGroup Group, + bool IsFramework, bool IgnoreSysRoot) { + UserEntries.emplace_back(Path, Group, IsFramework, IgnoreSysRoot); + } + + /// AddSystemHeaderPrefix - Override whether \#include directives naming a + /// path starting with \p Prefix should be considered as naming a system + /// header. + void AddSystemHeaderPrefix(StringRef Prefix, bool IsSystemHeader) { + SystemHeaderPrefixes.emplace_back(Prefix, IsSystemHeader); + } + + void AddVFSOverlayFile(StringRef Name) { + VFSOverlayFiles.push_back(std::string(Name)); + } + + void AddPrebuiltModulePath(StringRef Name) { + PrebuiltModulePaths.push_back(std::string(Name)); + } +}; + +inline llvm::hash_code hash_value(const HeaderSearchOptions::Entry &E) { + return llvm::hash_combine(E.Path, E.Group, E.IsFramework, E.IgnoreSysRoot); +} + +template <typename HasherT, llvm::support::endianness Endianness> +inline void addHash(llvm::HashBuilderImpl<HasherT, Endianness> &HBuilder, + const HeaderSearchOptions::Entry &E) { + HBuilder.add(E.Path, E.Group, E.IsFramework, E.IgnoreSysRoot); +} + +inline llvm::hash_code +hash_value(const HeaderSearchOptions::SystemHeaderPrefix &SHP) { + return llvm::hash_combine(SHP.Prefix, SHP.IsSystemHeader); +} + +template <typename HasherT, llvm::support::endianness Endianness> +inline void addHash(llvm::HashBuilderImpl<HasherT, Endianness> &HBuilder, + const HeaderSearchOptions::SystemHeaderPrefix &SHP) { + HBuilder.add(SHP.Prefix, SHP.IsSystemHeader); +} + +} // namespace clang + +#endif // LLVM_CLANG_LEX_HEADERSEARCHOPTIONS_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Lex/LexDiagnostic.h b/contrib/libs/clang16/include/clang/Lex/LexDiagnostic.h new file mode 100644 index 0000000000..3c34d317e8 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Lex/LexDiagnostic.h @@ -0,0 +1,25 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===--- DiagnosticLex.h - Diagnostics for liblex ---------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_LEXDIAGNOSTIC_H +#define LLVM_CLANG_LEX_LEXDIAGNOSTIC_H + +#include "clang/Basic/DiagnosticLex.h" + +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Lex/Lexer.h b/contrib/libs/clang16/include/clang/Lex/Lexer.h new file mode 100644 index 0000000000..3cab47f9d3 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Lex/Lexer.h @@ -0,0 +1,826 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- Lexer.h - C Language Family Lexer ------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the Lexer interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_LEXER_H +#define LLVM_CLANG_LEX_LEXER_H + +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/TokenKinds.h" +#include "clang/Lex/DependencyDirectivesScanner.h" +#include "clang/Lex/PreprocessorLexer.h" +#include "clang/Lex/Token.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include <cassert> +#include <cstdint> +#include <optional> +#include <string> + +namespace llvm { + +class MemoryBufferRef; + +} // namespace llvm + +namespace clang { + +class DiagnosticBuilder; +class Preprocessor; +class SourceManager; +class LangOptions; + +/// ConflictMarkerKind - Kinds of conflict marker which the lexer might be +/// recovering from. +enum ConflictMarkerKind { + /// Not within a conflict marker. + CMK_None, + + /// A normal or diff3 conflict marker, initiated by at least 7 "<"s, + /// separated by at least 7 "="s or "|"s, and terminated by at least 7 ">"s. + CMK_Normal, + + /// A Perforce-style conflict marker, initiated by 4 ">"s, + /// separated by 4 "="s, and terminated by 4 "<"s. + CMK_Perforce +}; + +/// Describes the bounds (start, size) of the preamble and a flag required by +/// PreprocessorOptions::PrecompiledPreambleBytes. +/// The preamble includes the BOM, if any. +struct PreambleBounds { + /// Size of the preamble in bytes. + unsigned Size; + + /// Whether the preamble ends at the start of a new line. + /// + /// Used to inform the lexer as to whether it's starting at the beginning of + /// a line after skipping the preamble. + bool PreambleEndsAtStartOfLine; + + PreambleBounds(unsigned Size, bool PreambleEndsAtStartOfLine) + : Size(Size), PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) {} +}; + +/// Lexer - This provides a simple interface that turns a text buffer into a +/// stream of tokens. This provides no support for file reading or buffering, +/// or buffering/seeking of tokens, only forward lexing is supported. It relies +/// on the specified Preprocessor object to handle preprocessor directives, etc. +class Lexer : public PreprocessorLexer { + friend class Preprocessor; + + void anchor() override; + + //===--------------------------------------------------------------------===// + // Constant configuration values for this lexer. + + // Start of the buffer. + const char *BufferStart; + + // End of the buffer. + const char *BufferEnd; + + // Location for start of file. + SourceLocation FileLoc; + + // LangOpts enabled by this language. + // Storing LangOptions as reference here is important from performance point + // of view. Lack of reference means that LangOptions copy constructor would be + // called by Lexer(..., const LangOptions &LangOpts,...). Given that local + // Lexer objects are created thousands times (in Lexer::getRawToken, + // Preprocessor::EnterSourceFile and other places) during single module + // processing in frontend it would make std::vector<std::string> copy + // constructors surprisingly hot. + const LangOptions &LangOpts; + + // True if '//' line comments are enabled. + bool LineComment; + + // True if lexer for _Pragma handling. + bool Is_PragmaLexer; + + //===--------------------------------------------------------------------===// + // Context-specific lexing flags set by the preprocessor. + // + + /// ExtendedTokenMode - The lexer can optionally keep comments and whitespace + /// and return them as tokens. This is used for -C and -CC modes, and + /// whitespace preservation can be useful for some clients that want to lex + /// the file in raw mode and get every character from the file. + /// + /// When this is set to 2 it returns comments and whitespace. When set to 1 + /// it returns comments, when it is set to 0 it returns normal tokens only. + unsigned char ExtendedTokenMode; + + //===--------------------------------------------------------------------===// + // Context that changes as the file is lexed. + // NOTE: any state that mutates when in raw mode must have save/restore code + // in Lexer::isNextPPTokenLParen. + + // BufferPtr - Current pointer into the buffer. This is the next character + // to be lexed. + const char *BufferPtr; + + // IsAtStartOfLine - True if the next lexed token should get the "start of + // line" flag set on it. + bool IsAtStartOfLine; + + bool IsAtPhysicalStartOfLine; + + bool HasLeadingSpace; + + bool HasLeadingEmptyMacro; + + /// True if this is the first time we're lexing the input file. + bool IsFirstTimeLexingFile; + + // NewLinePtr - A pointer to new line character '\n' being lexed. For '\r\n', + // it also points to '\n.' + const char *NewLinePtr; + + // CurrentConflictMarkerState - The kind of conflict marker we are handling. + ConflictMarkerKind CurrentConflictMarkerState; + + /// Non-empty if this \p Lexer is \p isDependencyDirectivesLexer(). + ArrayRef<dependency_directives_scan::Directive> DepDirectives; + + /// If this \p Lexer is \p isDependencyDirectivesLexer(), it represents the + /// next token to use from the current dependency directive. + unsigned NextDepDirectiveTokenIndex = 0; + + void InitLexer(const char *BufStart, const char *BufPtr, const char *BufEnd); + +public: + /// Lexer constructor - Create a new lexer object for the specified buffer + /// with the specified preprocessor managing the lexing process. This lexer + /// assumes that the associated file buffer and Preprocessor objects will + /// outlive it, so it doesn't take ownership of either of them. + Lexer(FileID FID, const llvm::MemoryBufferRef &InputFile, Preprocessor &PP, + bool IsFirstIncludeOfFile = true); + + /// Lexer constructor - Create a new raw lexer object. This object is only + /// suitable for calls to 'LexFromRawLexer'. This lexer assumes that the + /// text range will outlive it, so it doesn't take ownership of it. + Lexer(SourceLocation FileLoc, const LangOptions &LangOpts, + const char *BufStart, const char *BufPtr, const char *BufEnd, + bool IsFirstIncludeOfFile = true); + + /// Lexer constructor - Create a new raw lexer object. This object is only + /// suitable for calls to 'LexFromRawLexer'. This lexer assumes that the + /// text range will outlive it, so it doesn't take ownership of it. + Lexer(FileID FID, const llvm::MemoryBufferRef &FromFile, + const SourceManager &SM, const LangOptions &LangOpts, + bool IsFirstIncludeOfFile = true); + + Lexer(const Lexer &) = delete; + Lexer &operator=(const Lexer &) = delete; + + /// Create_PragmaLexer: Lexer constructor - Create a new lexer object for + /// _Pragma expansion. This has a variety of magic semantics that this method + /// sets up. It returns a new'd Lexer that must be delete'd when done. + static Lexer *Create_PragmaLexer(SourceLocation SpellingLoc, + SourceLocation ExpansionLocStart, + SourceLocation ExpansionLocEnd, + unsigned TokLen, Preprocessor &PP); + + /// getFileLoc - Return the File Location for the file we are lexing out of. + /// The physical location encodes the location where the characters come from, + /// the virtual location encodes where we should *claim* the characters came + /// from. Currently this is only used by _Pragma handling. + SourceLocation getFileLoc() const { return FileLoc; } + +private: + /// Lex - Return the next token in the file. If this is the end of file, it + /// return the tok::eof token. This implicitly involves the preprocessor. + bool Lex(Token &Result); + + /// Called when the preprocessor is in 'dependency scanning lexing mode'. + bool LexDependencyDirectiveToken(Token &Result); + + /// Called when the preprocessor is in 'dependency scanning lexing mode' and + /// is skipping a conditional block. + bool LexDependencyDirectiveTokenWhileSkipping(Token &Result); + + /// True when the preprocessor is in 'dependency scanning lexing mode' and + /// created this \p Lexer for lexing a set of dependency directive tokens. + bool isDependencyDirectivesLexer() const { return !DepDirectives.empty(); } + + /// Initializes \p Result with data from \p DDTok and advances \p BufferPtr to + /// the position just after the token. + /// \returns the buffer pointer at the beginning of the token. + const char *convertDependencyDirectiveToken( + const dependency_directives_scan::Token &DDTok, Token &Result); + +public: + /// isPragmaLexer - Returns true if this Lexer is being used to lex a pragma. + bool isPragmaLexer() const { return Is_PragmaLexer; } + +private: + /// IndirectLex - An indirect call to 'Lex' that can be invoked via + /// the PreprocessorLexer interface. + void IndirectLex(Token &Result) override { Lex(Result); } + +public: + /// LexFromRawLexer - Lex a token from a designated raw lexer (one with no + /// associated preprocessor object. Return true if the 'next character to + /// read' pointer points at the end of the lexer buffer, false otherwise. + bool LexFromRawLexer(Token &Result) { + assert(LexingRawMode && "Not already in raw mode!"); + Lex(Result); + // Note that lexing to the end of the buffer doesn't implicitly delete the + // lexer when in raw mode. + return BufferPtr == BufferEnd; + } + + /// isKeepWhitespaceMode - Return true if the lexer should return tokens for + /// every character in the file, including whitespace and comments. This + /// should only be used in raw mode, as the preprocessor is not prepared to + /// deal with the excess tokens. + bool isKeepWhitespaceMode() const { + return ExtendedTokenMode > 1; + } + + /// SetKeepWhitespaceMode - This method lets clients enable or disable + /// whitespace retention mode. + void SetKeepWhitespaceMode(bool Val) { + assert((!Val || LexingRawMode || LangOpts.TraditionalCPP) && + "Can only retain whitespace in raw mode or -traditional-cpp"); + ExtendedTokenMode = Val ? 2 : 0; + } + + /// inKeepCommentMode - Return true if the lexer should return comments as + /// tokens. + bool inKeepCommentMode() const { + return ExtendedTokenMode > 0; + } + + /// SetCommentRetentionMode - Change the comment retention mode of the lexer + /// to the specified mode. This is really only useful when lexing in raw + /// mode, because otherwise the lexer needs to manage this. + void SetCommentRetentionState(bool Mode) { + assert(!isKeepWhitespaceMode() && + "Can't play with comment retention state when retaining whitespace"); + ExtendedTokenMode = Mode ? 1 : 0; + } + + /// Sets the extended token mode back to its initial value, according to the + /// language options and preprocessor. This controls whether the lexer + /// produces comment and whitespace tokens. + /// + /// This requires the lexer to have an associated preprocessor. A standalone + /// lexer has nothing to reset to. + void resetExtendedTokenMode(); + + /// Gets source code buffer. + StringRef getBuffer() const { + return StringRef(BufferStart, BufferEnd - BufferStart); + } + + /// ReadToEndOfLine - Read the rest of the current preprocessor line as an + /// uninterpreted string. This switches the lexer out of directive mode. + void ReadToEndOfLine(SmallVectorImpl<char> *Result = nullptr); + + + /// Diag - Forwarding function for diagnostics. This translate a source + /// position in the current buffer into a SourceLocation object for rendering. + DiagnosticBuilder Diag(const char *Loc, unsigned DiagID) const; + + /// getSourceLocation - Return a source location identifier for the specified + /// offset in the current file. + SourceLocation getSourceLocation(const char *Loc, unsigned TokLen = 1) const; + + /// getSourceLocation - Return a source location for the next character in + /// the current file. + SourceLocation getSourceLocation() override { + return getSourceLocation(BufferPtr); + } + + /// Return the current location in the buffer. + const char *getBufferLocation() const { return BufferPtr; } + + /// Returns the current lexing offset. + unsigned getCurrentBufferOffset() { + assert(BufferPtr >= BufferStart && "Invalid buffer state"); + return BufferPtr - BufferStart; + } + + /// Set the lexer's buffer pointer to \p Offset. + void seek(unsigned Offset, bool IsAtStartOfLine); + + /// Stringify - Convert the specified string into a C string by i) escaping + /// '\\' and " characters and ii) replacing newline character(s) with "\\n". + /// If Charify is true, this escapes the ' character instead of ". + static std::string Stringify(StringRef Str, bool Charify = false); + + /// Stringify - Convert the specified string into a C string by i) escaping + /// '\\' and " characters and ii) replacing newline character(s) with "\\n". + static void Stringify(SmallVectorImpl<char> &Str); + + /// getSpelling - This method is used to get the spelling of a token into a + /// preallocated buffer, instead of as an std::string. The caller is required + /// to allocate enough space for the token, which is guaranteed to be at least + /// Tok.getLength() bytes long. The length of the actual result is returned. + /// + /// Note that this method may do two possible things: it may either fill in + /// the buffer specified with characters, or it may *change the input pointer* + /// to point to a constant buffer with the data already in it (avoiding a + /// copy). The caller is not allowed to modify the returned buffer pointer + /// if an internal buffer is returned. + static unsigned getSpelling(const Token &Tok, const char *&Buffer, + const SourceManager &SourceMgr, + const LangOptions &LangOpts, + bool *Invalid = nullptr); + + /// getSpelling() - Return the 'spelling' of the Tok token. The spelling of a + /// token is the characters used to represent the token in the source file + /// after trigraph expansion and escaped-newline folding. In particular, this + /// wants to get the true, uncanonicalized, spelling of things like digraphs + /// UCNs, etc. + static std::string getSpelling(const Token &Tok, + const SourceManager &SourceMgr, + const LangOptions &LangOpts, + bool *Invalid = nullptr); + + /// getSpelling - This method is used to get the spelling of the + /// token at the given source location. If, as is usually true, it + /// is not necessary to copy any data, then the returned string may + /// not point into the provided buffer. + /// + /// This method lexes at the expansion depth of the given + /// location and does not jump to the expansion or spelling + /// location. + static StringRef getSpelling(SourceLocation loc, + SmallVectorImpl<char> &buffer, + const SourceManager &SM, + const LangOptions &options, + bool *invalid = nullptr); + + /// MeasureTokenLength - Relex the token at the specified location and return + /// its length in bytes in the input file. If the token needs cleaning (e.g. + /// includes a trigraph or an escaped newline) then this count includes bytes + /// that are part of that. + static unsigned MeasureTokenLength(SourceLocation Loc, + const SourceManager &SM, + const LangOptions &LangOpts); + + /// Relex the token at the specified location. + /// \returns true if there was a failure, false on success. + static bool getRawToken(SourceLocation Loc, Token &Result, + const SourceManager &SM, + const LangOptions &LangOpts, + bool IgnoreWhiteSpace = false); + + /// Given a location any where in a source buffer, find the location + /// that corresponds to the beginning of the token in which the original + /// source location lands. + static SourceLocation GetBeginningOfToken(SourceLocation Loc, + const SourceManager &SM, + const LangOptions &LangOpts); + + /// Get the physical length (including trigraphs and escaped newlines) of the + /// first \p Characters characters of the token starting at TokStart. + static unsigned getTokenPrefixLength(SourceLocation TokStart, + unsigned CharNo, + const SourceManager &SM, + const LangOptions &LangOpts); + + /// AdvanceToTokenCharacter - If the current SourceLocation specifies a + /// location at the start of a token, return a new location that specifies a + /// character within the token. This handles trigraphs and escaped newlines. + static SourceLocation AdvanceToTokenCharacter(SourceLocation TokStart, + unsigned Characters, + const SourceManager &SM, + const LangOptions &LangOpts) { + return TokStart.getLocWithOffset( + getTokenPrefixLength(TokStart, Characters, SM, LangOpts)); + } + + /// Computes the source location just past the end of the + /// token at this source location. + /// + /// This routine can be used to produce a source location that + /// points just past the end of the token referenced by \p Loc, and + /// is generally used when a diagnostic needs to point just after a + /// token where it expected something different that it received. If + /// the returned source location would not be meaningful (e.g., if + /// it points into a macro), this routine returns an invalid + /// source location. + /// + /// \param Offset an offset from the end of the token, where the source + /// location should refer to. The default offset (0) produces a source + /// location pointing just past the end of the token; an offset of 1 produces + /// a source location pointing to the last character in the token, etc. + static SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset, + const SourceManager &SM, + const LangOptions &LangOpts); + + /// Given a token range, produce a corresponding CharSourceRange that + /// is not a token range. This allows the source range to be used by + /// components that don't have access to the lexer and thus can't find the + /// end of the range for themselves. + static CharSourceRange getAsCharRange(SourceRange Range, + const SourceManager &SM, + const LangOptions &LangOpts) { + SourceLocation End = getLocForEndOfToken(Range.getEnd(), 0, SM, LangOpts); + return End.isInvalid() ? CharSourceRange() + : CharSourceRange::getCharRange( + Range.getBegin(), End); + } + static CharSourceRange getAsCharRange(CharSourceRange Range, + const SourceManager &SM, + const LangOptions &LangOpts) { + return Range.isTokenRange() + ? getAsCharRange(Range.getAsRange(), SM, LangOpts) + : Range; + } + + /// Returns true if the given MacroID location points at the first + /// token of the macro expansion. + /// + /// \param MacroBegin If non-null and function returns true, it is set to + /// begin location of the macro. + static bool isAtStartOfMacroExpansion(SourceLocation loc, + const SourceManager &SM, + const LangOptions &LangOpts, + SourceLocation *MacroBegin = nullptr); + + /// Returns true if the given MacroID location points at the last + /// token of the macro expansion. + /// + /// \param MacroEnd If non-null and function returns true, it is set to + /// end location of the macro. + static bool isAtEndOfMacroExpansion(SourceLocation loc, + const SourceManager &SM, + const LangOptions &LangOpts, + SourceLocation *MacroEnd = nullptr); + + /// Accepts a range and returns a character range with file locations. + /// + /// Returns a null range if a part of the range resides inside a macro + /// expansion or the range does not reside on the same FileID. + /// + /// This function is trying to deal with macros and return a range based on + /// file locations. The cases where it can successfully handle macros are: + /// + /// -begin or end range lies at the start or end of a macro expansion, in + /// which case the location will be set to the expansion point, e.g: + /// \#define M 1 2 + /// a M + /// If you have a range [a, 2] (where 2 came from the macro), the function + /// will return a range for "a M" + /// if you have range [a, 1], the function will fail because the range + /// overlaps with only a part of the macro + /// + /// -The macro is a function macro and the range can be mapped to the macro + /// arguments, e.g: + /// \#define M 1 2 + /// \#define FM(x) x + /// FM(a b M) + /// if you have range [b, 2], the function will return the file range "b M" + /// inside the macro arguments. + /// if you have range [a, 2], the function will return the file range + /// "FM(a b M)" since the range includes all of the macro expansion. + static CharSourceRange makeFileCharRange(CharSourceRange Range, + const SourceManager &SM, + const LangOptions &LangOpts); + + /// Returns a string for the source that the range encompasses. + static StringRef getSourceText(CharSourceRange Range, + const SourceManager &SM, + const LangOptions &LangOpts, + bool *Invalid = nullptr); + + /// Retrieve the name of the immediate macro expansion. + /// + /// This routine starts from a source location, and finds the name of the macro + /// responsible for its immediate expansion. It looks through any intervening + /// macro argument expansions to compute this. It returns a StringRef which + /// refers to the SourceManager-owned buffer of the source where that macro + /// name is spelled. Thus, the result shouldn't out-live that SourceManager. + static StringRef getImmediateMacroName(SourceLocation Loc, + const SourceManager &SM, + const LangOptions &LangOpts); + + /// Retrieve the name of the immediate macro expansion. + /// + /// This routine starts from a source location, and finds the name of the + /// macro responsible for its immediate expansion. It looks through any + /// intervening macro argument expansions to compute this. It returns a + /// StringRef which refers to the SourceManager-owned buffer of the source + /// where that macro name is spelled. Thus, the result shouldn't out-live + /// that SourceManager. + /// + /// This differs from Lexer::getImmediateMacroName in that any macro argument + /// location will result in the topmost function macro that accepted it. + /// e.g. + /// \code + /// MAC1( MAC2(foo) ) + /// \endcode + /// for location of 'foo' token, this function will return "MAC1" while + /// Lexer::getImmediateMacroName will return "MAC2". + static StringRef getImmediateMacroNameForDiagnostics( + SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts); + + /// Compute the preamble of the given file. + /// + /// The preamble of a file contains the initial comments, include directives, + /// and other preprocessor directives that occur before the code in this + /// particular file actually begins. The preamble of the main source file is + /// a potential prefix header. + /// + /// \param Buffer The memory buffer containing the file's contents. + /// + /// \param MaxLines If non-zero, restrict the length of the preamble + /// to fewer than this number of lines. + /// + /// \returns The offset into the file where the preamble ends and the rest + /// of the file begins along with a boolean value indicating whether + /// the preamble ends at the beginning of a new line. + static PreambleBounds ComputePreamble(StringRef Buffer, + const LangOptions &LangOpts, + unsigned MaxLines = 0); + + /// Finds the token that comes right after the given location. + /// + /// Returns the next token, or none if the location is inside a macro. + static std::optional<Token> findNextToken(SourceLocation Loc, + const SourceManager &SM, + const LangOptions &LangOpts); + + /// Checks that the given token is the first token that occurs after + /// the given location (this excludes comments and whitespace). Returns the + /// location immediately after the specified token. If the token is not found + /// or the location is inside a macro, the returned source location will be + /// invalid. + static SourceLocation findLocationAfterToken(SourceLocation loc, + tok::TokenKind TKind, + const SourceManager &SM, + const LangOptions &LangOpts, + bool SkipTrailingWhitespaceAndNewLine); + + /// Returns true if the given character could appear in an identifier. + static bool isAsciiIdentifierContinueChar(char c, + const LangOptions &LangOpts); + + /// Checks whether new line pointed by Str is preceded by escape + /// sequence. + static bool isNewLineEscaped(const char *BufferStart, const char *Str); + + /// getCharAndSizeNoWarn - Like the getCharAndSize method, but does not ever + /// emit a warning. + static inline char getCharAndSizeNoWarn(const char *Ptr, unsigned &Size, + const LangOptions &LangOpts) { + // If this is not a trigraph and not a UCN or escaped newline, return + // quickly. + if (isObviouslySimpleCharacter(Ptr[0])) { + Size = 1; + return *Ptr; + } + + Size = 0; + return getCharAndSizeSlowNoWarn(Ptr, Size, LangOpts); + } + + /// Returns the leading whitespace for line that corresponds to the given + /// location \p Loc. + static StringRef getIndentationForLine(SourceLocation Loc, + const SourceManager &SM); + + /// Check if this is the first time we're lexing the input file. + bool isFirstTimeLexingFile() const { return IsFirstTimeLexingFile; } + +private: + //===--------------------------------------------------------------------===// + // Internal implementation interfaces. + + /// LexTokenInternal - Internal interface to lex a preprocessing token. Called + /// by Lex. + /// + bool LexTokenInternal(Token &Result, bool TokAtPhysicalStartOfLine); + + bool CheckUnicodeWhitespace(Token &Result, uint32_t C, const char *CurPtr); + + bool LexUnicodeIdentifierStart(Token &Result, uint32_t C, const char *CurPtr); + + /// FormTokenWithChars - When we lex a token, we have identified a span + /// starting at BufferPtr, going to TokEnd that forms the token. This method + /// takes that range and assigns it to the token as its location and size. In + /// addition, since tokens cannot overlap, this also updates BufferPtr to be + /// TokEnd. + void FormTokenWithChars(Token &Result, const char *TokEnd, + tok::TokenKind Kind) { + unsigned TokLen = TokEnd-BufferPtr; + Result.setLength(TokLen); + Result.setLocation(getSourceLocation(BufferPtr, TokLen)); + Result.setKind(Kind); + BufferPtr = TokEnd; + } + + /// isNextPPTokenLParen - Return 1 if the next unexpanded token will return a + /// tok::l_paren token, 0 if it is something else and 2 if there are no more + /// tokens in the buffer controlled by this lexer. + unsigned isNextPPTokenLParen(); + + //===--------------------------------------------------------------------===// + // Lexer character reading interfaces. + + // This lexer is built on two interfaces for reading characters, both of which + // automatically provide phase 1/2 translation. getAndAdvanceChar is used + // when we know that we will be reading a character from the input buffer and + // that this character will be part of the result token. This occurs in (f.e.) + // string processing, because we know we need to read until we find the + // closing '"' character. + // + // The second interface is the combination of getCharAndSize with + // ConsumeChar. getCharAndSize reads a phase 1/2 translated character, + // returning it and its size. If the lexer decides that this character is + // part of the current token, it calls ConsumeChar on it. This two stage + // approach allows us to emit diagnostics for characters (e.g. warnings about + // trigraphs), knowing that they only are emitted if the character is + // consumed. + + /// isObviouslySimpleCharacter - Return true if the specified character is + /// obviously the same in translation phase 1 and translation phase 3. This + /// can return false for characters that end up being the same, but it will + /// never return true for something that needs to be mapped. + static bool isObviouslySimpleCharacter(char C) { + return C != '?' && C != '\\'; + } + + /// getAndAdvanceChar - Read a single 'character' from the specified buffer, + /// advance over it, and return it. This is tricky in several cases. Here we + /// just handle the trivial case and fall-back to the non-inlined + /// getCharAndSizeSlow method to handle the hard case. + inline char getAndAdvanceChar(const char *&Ptr, Token &Tok) { + // If this is not a trigraph and not a UCN or escaped newline, return + // quickly. + if (isObviouslySimpleCharacter(Ptr[0])) return *Ptr++; + + unsigned Size = 0; + char C = getCharAndSizeSlow(Ptr, Size, &Tok); + Ptr += Size; + return C; + } + + /// ConsumeChar - When a character (identified by getCharAndSize) is consumed + /// and added to a given token, check to see if there are diagnostics that + /// need to be emitted or flags that need to be set on the token. If so, do + /// it. + const char *ConsumeChar(const char *Ptr, unsigned Size, Token &Tok) { + // Normal case, we consumed exactly one token. Just return it. + if (Size == 1) + return Ptr+Size; + + // Otherwise, re-lex the character with a current token, allowing + // diagnostics to be emitted and flags to be set. + Size = 0; + getCharAndSizeSlow(Ptr, Size, &Tok); + return Ptr+Size; + } + + /// getCharAndSize - Peek a single 'character' from the specified buffer, + /// get its size, and return it. This is tricky in several cases. Here we + /// just handle the trivial case and fall-back to the non-inlined + /// getCharAndSizeSlow method to handle the hard case. + inline char getCharAndSize(const char *Ptr, unsigned &Size) { + // If this is not a trigraph and not a UCN or escaped newline, return + // quickly. + if (isObviouslySimpleCharacter(Ptr[0])) { + Size = 1; + return *Ptr; + } + + Size = 0; + return getCharAndSizeSlow(Ptr, Size); + } + + /// getCharAndSizeSlow - Handle the slow/uncommon case of the getCharAndSize + /// method. + char getCharAndSizeSlow(const char *Ptr, unsigned &Size, + Token *Tok = nullptr); + + /// getEscapedNewLineSize - Return the size of the specified escaped newline, + /// or 0 if it is not an escaped newline. P[-1] is known to be a "\" on entry + /// to this function. + static unsigned getEscapedNewLineSize(const char *P); + + /// SkipEscapedNewLines - If P points to an escaped newline (or a series of + /// them), skip over them and return the first non-escaped-newline found, + /// otherwise return P. + static const char *SkipEscapedNewLines(const char *P); + + /// getCharAndSizeSlowNoWarn - Same as getCharAndSizeSlow, but never emits a + /// diagnostic. + static char getCharAndSizeSlowNoWarn(const char *Ptr, unsigned &Size, + const LangOptions &LangOpts); + + //===--------------------------------------------------------------------===// + // Other lexer functions. + + void SetByteOffset(unsigned Offset, bool StartOfLine); + + void PropagateLineStartLeadingSpaceInfo(Token &Result); + + const char *LexUDSuffix(Token &Result, const char *CurPtr, + bool IsStringLiteral); + + // Helper functions to lex the remainder of a token of the specific type. + + // This function handles both ASCII and Unicode identifiers after + // the first codepoint of the identifyier has been parsed. + bool LexIdentifierContinue(Token &Result, const char *CurPtr); + + bool LexNumericConstant (Token &Result, const char *CurPtr); + bool LexStringLiteral (Token &Result, const char *CurPtr, + tok::TokenKind Kind); + bool LexRawStringLiteral (Token &Result, const char *CurPtr, + tok::TokenKind Kind); + bool LexAngledStringLiteral(Token &Result, const char *CurPtr); + bool LexCharConstant (Token &Result, const char *CurPtr, + tok::TokenKind Kind); + bool LexEndOfFile (Token &Result, const char *CurPtr); + bool SkipWhitespace (Token &Result, const char *CurPtr, + bool &TokAtPhysicalStartOfLine); + bool SkipLineComment (Token &Result, const char *CurPtr, + bool &TokAtPhysicalStartOfLine); + bool SkipBlockComment (Token &Result, const char *CurPtr, + bool &TokAtPhysicalStartOfLine); + bool SaveLineComment (Token &Result, const char *CurPtr); + + bool IsStartOfConflictMarker(const char *CurPtr); + bool HandleEndOfConflictMarker(const char *CurPtr); + + bool lexEditorPlaceholder(Token &Result, const char *CurPtr); + + bool isCodeCompletionPoint(const char *CurPtr) const; + void cutOffLexing() { BufferPtr = BufferEnd; } + + bool isHexaLiteral(const char *Start, const LangOptions &LangOpts); + + void codeCompleteIncludedFile(const char *PathStart, + const char *CompletionPoint, bool IsAngled); + + std::optional<uint32_t> + tryReadNumericUCN(const char *&StartPtr, const char *SlashLoc, Token *Result); + std::optional<uint32_t> tryReadNamedUCN(const char *&StartPtr, + const char *SlashLoc, Token *Result); + + /// Read a universal character name. + /// + /// \param StartPtr The position in the source buffer after the initial '\'. + /// If the UCN is syntactically well-formed (but not + /// necessarily valid), this parameter will be updated to + /// point to the character after the UCN. + /// \param SlashLoc The position in the source buffer of the '\'. + /// \param Result The token being formed. Pass \c nullptr to suppress + /// diagnostics and handle token formation in the caller. + /// + /// \return The Unicode codepoint specified by the UCN, or 0 if the UCN is + /// invalid. + uint32_t tryReadUCN(const char *&StartPtr, const char *SlashLoc, Token *Result); + + /// Try to consume a UCN as part of an identifier at the current + /// location. + /// \param CurPtr Initially points to the range of characters in the source + /// buffer containing the '\'. Updated to point past the end of + /// the UCN on success. + /// \param Size The number of characters occupied by the '\' (including + /// trigraphs and escaped newlines). + /// \param Result The token being produced. Marked as containing a UCN on + /// success. + /// \return \c true if a UCN was lexed and it produced an acceptable + /// identifier character, \c false otherwise. + bool tryConsumeIdentifierUCN(const char *&CurPtr, unsigned Size, + Token &Result); + + /// Try to consume an identifier character encoded in UTF-8. + /// \param CurPtr Points to the start of the (potential) UTF-8 code unit + /// sequence. On success, updated to point past the end of it. + /// \return \c true if a UTF-8 sequence mapping to an acceptable identifier + /// character was lexed, \c false otherwise. + bool tryConsumeIdentifierUTF8Char(const char *&CurPtr); +}; + +} // namespace clang + +#endif // LLVM_CLANG_LEX_LEXER_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Lex/LiteralSupport.h b/contrib/libs/clang16/include/clang/Lex/LiteralSupport.h new file mode 100644 index 0000000000..d20058ca1f --- /dev/null +++ b/contrib/libs/clang16/include/clang/Lex/LiteralSupport.h @@ -0,0 +1,308 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===--- LiteralSupport.h ---------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the NumericLiteralParser, CharLiteralParser, and +// StringLiteralParser interfaces. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_LITERALSUPPORT_H +#define LLVM_CLANG_LEX_LITERALSUPPORT_H + +#include "clang/Basic/CharInfo.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/TokenKinds.h" +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/DataTypes.h" + +namespace clang { + +class DiagnosticsEngine; +class Preprocessor; +class Token; +class SourceLocation; +class TargetInfo; +class SourceManager; +class LangOptions; + +/// Copy characters from Input to Buf, expanding any UCNs. +void expandUCNs(SmallVectorImpl<char> &Buf, StringRef Input); + +/// NumericLiteralParser - This performs strict semantic analysis of the content +/// of a ppnumber, classifying it as either integer, floating, or erroneous, +/// determines the radix of the value and can convert it to a useful value. +class NumericLiteralParser { + const SourceManager &SM; + const LangOptions &LangOpts; + DiagnosticsEngine &Diags; + + const char *const ThisTokBegin; + const char *const ThisTokEnd; + const char *DigitsBegin, *SuffixBegin; // markers + const char *s; // cursor + + unsigned radix; + + bool saw_exponent, saw_period, saw_ud_suffix, saw_fixed_point_suffix; + + SmallString<32> UDSuffixBuf; + +public: + NumericLiteralParser(StringRef TokSpelling, SourceLocation TokLoc, + const SourceManager &SM, const LangOptions &LangOpts, + const TargetInfo &Target, DiagnosticsEngine &Diags); + bool hadError : 1; + bool isUnsigned : 1; + bool isLong : 1; // This is *not* set for long long. + bool isLongLong : 1; + bool isSizeT : 1; // 1z, 1uz (C++2b) + bool isHalf : 1; // 1.0h + bool isFloat : 1; // 1.0f + bool isImaginary : 1; // 1.0i + bool isFloat16 : 1; // 1.0f16 + bool isFloat128 : 1; // 1.0q + bool isFract : 1; // 1.0hr/r/lr/uhr/ur/ulr + bool isAccum : 1; // 1.0hk/k/lk/uhk/uk/ulk + bool isBitInt : 1; // 1wb, 1uwb (C2x) + uint8_t MicrosoftInteger; // Microsoft suffix extension i8, i16, i32, or i64. + + + bool isFixedPointLiteral() const { + return (saw_period || saw_exponent) && saw_fixed_point_suffix; + } + + bool isIntegerLiteral() const { + return !saw_period && !saw_exponent && !isFixedPointLiteral(); + } + bool isFloatingLiteral() const { + return (saw_period || saw_exponent) && !isFixedPointLiteral(); + } + + bool hasUDSuffix() const { + return saw_ud_suffix; + } + StringRef getUDSuffix() const { + assert(saw_ud_suffix); + return UDSuffixBuf; + } + unsigned getUDSuffixOffset() const { + assert(saw_ud_suffix); + return SuffixBegin - ThisTokBegin; + } + + static bool isValidUDSuffix(const LangOptions &LangOpts, StringRef Suffix); + + unsigned getRadix() const { return radix; } + + /// GetIntegerValue - Convert this numeric literal value to an APInt that + /// matches Val's input width. If there is an overflow (i.e., if the unsigned + /// value read is larger than the APInt's bits will hold), set Val to the low + /// bits of the result and return true. Otherwise, return false. + bool GetIntegerValue(llvm::APInt &Val); + + /// GetFloatValue - Convert this numeric literal to a floating value, using + /// the specified APFloat fltSemantics (specifying float, double, etc). + /// The optional bool isExact (passed-by-reference) has its value + /// set to true if the returned APFloat can represent the number in the + /// literal exactly, and false otherwise. + llvm::APFloat::opStatus GetFloatValue(llvm::APFloat &Result); + + /// GetFixedPointValue - Convert this numeric literal value into a + /// scaled integer that represents this value. Returns true if an overflow + /// occurred when calculating the integral part of the scaled integer or + /// calculating the digit sequence of the exponent. + bool GetFixedPointValue(llvm::APInt &StoreVal, unsigned Scale); + + /// Get the digits that comprise the literal. This excludes any prefix or + /// suffix associated with the literal. + StringRef getLiteralDigits() const { + assert(!hadError && "cannot reliably get the literal digits with an error"); + return StringRef(DigitsBegin, SuffixBegin - DigitsBegin); + } + +private: + + void ParseNumberStartingWithZero(SourceLocation TokLoc); + void ParseDecimalOrOctalCommon(SourceLocation TokLoc); + + static bool isDigitSeparator(char C) { return C == '\''; } + + /// Determine whether the sequence of characters [Start, End) contains + /// any real digits (not digit separators). + bool containsDigits(const char *Start, const char *End) { + return Start != End && (Start + 1 != End || !isDigitSeparator(Start[0])); + } + + enum CheckSeparatorKind { CSK_BeforeDigits, CSK_AfterDigits }; + + /// Ensure that we don't have a digit separator here. + void checkSeparator(SourceLocation TokLoc, const char *Pos, + CheckSeparatorKind IsAfterDigits); + + /// SkipHexDigits - Read and skip over any hex digits, up to End. + /// Return a pointer to the first non-hex digit or End. + const char *SkipHexDigits(const char *ptr) { + while (ptr != ThisTokEnd && (isHexDigit(*ptr) || isDigitSeparator(*ptr))) + ptr++; + return ptr; + } + + /// SkipOctalDigits - Read and skip over any octal digits, up to End. + /// Return a pointer to the first non-hex digit or End. + const char *SkipOctalDigits(const char *ptr) { + while (ptr != ThisTokEnd && + ((*ptr >= '0' && *ptr <= '7') || isDigitSeparator(*ptr))) + ptr++; + return ptr; + } + + /// SkipDigits - Read and skip over any digits, up to End. + /// Return a pointer to the first non-hex digit or End. + const char *SkipDigits(const char *ptr) { + while (ptr != ThisTokEnd && (isDigit(*ptr) || isDigitSeparator(*ptr))) + ptr++; + return ptr; + } + + /// SkipBinaryDigits - Read and skip over any binary digits, up to End. + /// Return a pointer to the first non-binary digit or End. + const char *SkipBinaryDigits(const char *ptr) { + while (ptr != ThisTokEnd && + (*ptr == '0' || *ptr == '1' || isDigitSeparator(*ptr))) + ptr++; + return ptr; + } + +}; + +/// CharLiteralParser - Perform interpretation and semantic analysis of a +/// character literal. +class CharLiteralParser { + uint64_t Value; + tok::TokenKind Kind; + bool IsMultiChar; + bool HadError; + SmallString<32> UDSuffixBuf; + unsigned UDSuffixOffset; +public: + CharLiteralParser(const char *begin, const char *end, + SourceLocation Loc, Preprocessor &PP, + tok::TokenKind kind); + + bool hadError() const { return HadError; } + bool isOrdinary() const { return Kind == tok::char_constant; } + bool isWide() const { return Kind == tok::wide_char_constant; } + bool isUTF8() const { return Kind == tok::utf8_char_constant; } + bool isUTF16() const { return Kind == tok::utf16_char_constant; } + bool isUTF32() const { return Kind == tok::utf32_char_constant; } + bool isMultiChar() const { return IsMultiChar; } + uint64_t getValue() const { return Value; } + StringRef getUDSuffix() const { return UDSuffixBuf; } + unsigned getUDSuffixOffset() const { + assert(!UDSuffixBuf.empty() && "no ud-suffix"); + return UDSuffixOffset; + } +}; + +/// StringLiteralParser - This decodes string escape characters and performs +/// wide string analysis and Translation Phase #6 (concatenation of string +/// literals) (C99 5.1.1.2p1). +class StringLiteralParser { + const SourceManager &SM; + const LangOptions &Features; + const TargetInfo &Target; + DiagnosticsEngine *Diags; + + unsigned MaxTokenLength; + unsigned SizeBound; + unsigned CharByteWidth; + tok::TokenKind Kind; + SmallString<512> ResultBuf; + char *ResultPtr; // cursor + SmallString<32> UDSuffixBuf; + unsigned UDSuffixToken; + unsigned UDSuffixOffset; +public: + StringLiteralParser(ArrayRef<Token> StringToks, + Preprocessor &PP); + StringLiteralParser(ArrayRef<Token> StringToks, + const SourceManager &sm, const LangOptions &features, + const TargetInfo &target, + DiagnosticsEngine *diags = nullptr) + : SM(sm), Features(features), Target(target), Diags(diags), + MaxTokenLength(0), SizeBound(0), CharByteWidth(0), Kind(tok::unknown), + ResultPtr(ResultBuf.data()), hadError(false), Pascal(false) { + init(StringToks); + } + + + bool hadError; + bool Pascal; + + StringRef GetString() const { + return StringRef(ResultBuf.data(), GetStringLength()); + } + unsigned GetStringLength() const { return ResultPtr-ResultBuf.data(); } + + unsigned GetNumStringChars() const { + return GetStringLength() / CharByteWidth; + } + /// getOffsetOfStringByte - This function returns the offset of the + /// specified byte of the string data represented by Token. This handles + /// advancing over escape sequences in the string. + /// + /// If the Diagnostics pointer is non-null, then this will do semantic + /// checking of the string literal and emit errors and warnings. + unsigned getOffsetOfStringByte(const Token &TheTok, unsigned ByteNo) const; + + bool isOrdinary() const { return Kind == tok::string_literal; } + bool isWide() const { return Kind == tok::wide_string_literal; } + bool isUTF8() const { return Kind == tok::utf8_string_literal; } + bool isUTF16() const { return Kind == tok::utf16_string_literal; } + bool isUTF32() const { return Kind == tok::utf32_string_literal; } + bool isPascal() const { return Pascal; } + + StringRef getUDSuffix() const { return UDSuffixBuf; } + + /// Get the index of a token containing a ud-suffix. + unsigned getUDSuffixToken() const { + assert(!UDSuffixBuf.empty() && "no ud-suffix"); + return UDSuffixToken; + } + /// Get the spelling offset of the first byte of the ud-suffix. + unsigned getUDSuffixOffset() const { + assert(!UDSuffixBuf.empty() && "no ud-suffix"); + return UDSuffixOffset; + } + + static bool isValidUDSuffix(const LangOptions &LangOpts, StringRef Suffix); + +private: + void init(ArrayRef<Token> StringToks); + bool CopyStringFragment(const Token &Tok, const char *TokBegin, + StringRef Fragment); + void DiagnoseLexingError(SourceLocation Loc); +}; + +} // end namespace clang + +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Lex/MacroArgs.h b/contrib/libs/clang16/include/clang/Lex/MacroArgs.h new file mode 100644 index 0000000000..db4680423c --- /dev/null +++ b/contrib/libs/clang16/include/clang/Lex/MacroArgs.h @@ -0,0 +1,148 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===--- MacroArgs.h - Formal argument info for Macros ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the MacroArgs interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_MACROARGS_H +#define LLVM_CLANG_LEX_MACROARGS_H + +#include "clang/Basic/LLVM.h" +#include "clang/Lex/Token.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/TrailingObjects.h" +#include <vector> + +namespace clang { + class MacroInfo; + class Preprocessor; + class SourceLocation; + +/// MacroArgs - An instance of this class captures information about +/// the formal arguments specified to a function-like macro invocation. +class MacroArgs final + : private llvm::TrailingObjects<MacroArgs, Token> { + + friend TrailingObjects; + /// NumUnexpArgTokens - The number of raw, unexpanded tokens for the + /// arguments. All of the actual argument tokens are allocated immediately + /// after the MacroArgs object in memory. This is all of the arguments + /// concatenated together, with 'EOF' markers at the end of each argument. + unsigned NumUnexpArgTokens; + + /// VarargsElided - True if this is a C99 style varargs macro invocation and + /// there was no argument specified for the "..." argument. If the argument + /// was specified (even empty) or this isn't a C99 style varargs function, or + /// if in strict mode and the C99 varargs macro had only a ... argument, this + /// is false. + bool VarargsElided; + + /// PreExpArgTokens - Pre-expanded tokens for arguments that need them. Empty + /// if not yet computed. This includes the EOF marker at the end of the + /// stream. + std::vector<std::vector<Token> > PreExpArgTokens; + + /// ArgCache - This is a linked list of MacroArgs objects that the + /// Preprocessor owns which we use to avoid thrashing malloc/free. + MacroArgs *ArgCache; + + /// MacroArgs - The number of arguments the invoked macro expects. + unsigned NumMacroArgs; + + MacroArgs(unsigned NumToks, bool varargsElided, unsigned MacroArgs) + : NumUnexpArgTokens(NumToks), VarargsElided(varargsElided), + ArgCache(nullptr), NumMacroArgs(MacroArgs) {} + ~MacroArgs() = default; + +public: + /// MacroArgs ctor function - Create a new MacroArgs object with the specified + /// macro and argument info. + static MacroArgs *create(const MacroInfo *MI, + ArrayRef<Token> UnexpArgTokens, + bool VarargsElided, Preprocessor &PP); + + /// destroy - Destroy and deallocate the memory for this object. + /// + void destroy(Preprocessor &PP); + + /// ArgNeedsPreexpansion - If we can prove that the argument won't be affected + /// by pre-expansion, return false. Otherwise, conservatively return true. + bool ArgNeedsPreexpansion(const Token *ArgTok, Preprocessor &PP) const; + + /// getUnexpArgument - Return a pointer to the first token of the unexpanded + /// token list for the specified formal. + /// + const Token *getUnexpArgument(unsigned Arg) const; + + /// getArgLength - Given a pointer to an expanded or unexpanded argument, + /// return the number of tokens, not counting the EOF, that make up the + /// argument. + static unsigned getArgLength(const Token *ArgPtr); + + /// getPreExpArgument - Return the pre-expanded form of the specified + /// argument. + const std::vector<Token> & + getPreExpArgument(unsigned Arg, Preprocessor &PP); + + /// getNumMacroArguments - Return the number of arguments the invoked macro + /// expects. + unsigned getNumMacroArguments() const { return NumMacroArgs; } + + /// isVarargsElidedUse - Return true if this is a C99 style varargs macro + /// invocation and there was no argument specified for the "..." argument. If + /// the argument was specified (even empty) or this isn't a C99 style varargs + /// function, or if in strict mode and the C99 varargs macro had only a ... + /// argument, this returns false. + bool isVarargsElidedUse() const { return VarargsElided; } + + /// Returns true if the macro was defined with a variadic (ellipsis) parameter + /// AND was invoked with at least one token supplied as a variadic argument + /// (after pre-expansion). + /// + /// \code + /// #define F(a) a + /// #define V(a, ...) __VA_OPT__(a) + /// F() <-- returns false on this invocation. + /// V(,a) <-- returns true on this invocation. + /// V(,) <-- returns false on this invocation. + /// V(,F()) <-- returns false on this invocation. + /// \endcode + /// + bool invokedWithVariadicArgument(const MacroInfo *const MI, Preprocessor &PP); + + /// StringifyArgument - Implement C99 6.10.3.2p2, converting a sequence of + /// tokens into the literal string token that should be produced by the C # + /// preprocessor operator. If Charify is true, then it should be turned into + /// a character literal for the Microsoft charize (#@) extension. + /// + static Token StringifyArgument(const Token *ArgToks, + Preprocessor &PP, bool Charify, + SourceLocation ExpansionLocStart, + SourceLocation ExpansionLocEnd); + + + /// deallocate - This should only be called by the Preprocessor when managing + /// its freelist. + MacroArgs *deallocate(); +}; + +} // end namespace clang + +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Lex/MacroInfo.h b/contrib/libs/clang16/include/clang/Lex/MacroInfo.h new file mode 100644 index 0000000000..7176553f5d --- /dev/null +++ b/contrib/libs/clang16/include/clang/Lex/MacroInfo.h @@ -0,0 +1,644 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- MacroInfo.h - Information about #defined identifiers -----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +/// \file +/// Defines the clang::MacroInfo and clang::MacroDirective classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_MACROINFO_H +#define LLVM_CLANG_LEX_MACROINFO_H + +#include "clang/Lex/Token.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Allocator.h" +#include <algorithm> +#include <cassert> + +namespace clang { + +class DefMacroDirective; +class IdentifierInfo; +class Module; +class Preprocessor; +class SourceManager; + +/// Encapsulates the data about a macro definition (e.g. its tokens). +/// +/// There's an instance of this class for every #define. +class MacroInfo { + //===--------------------------------------------------------------------===// + // State set when the macro is defined. + + /// The location the macro is defined. + SourceLocation Location; + + /// The location of the last token in the macro. + SourceLocation EndLocation; + + /// The list of arguments for a function-like macro. + /// + /// ParameterList points to the first of NumParameters pointers. + /// + /// This can be empty, for, e.g. "#define X()". In a C99-style variadic + /// macro, this includes the \c __VA_ARGS__ identifier on the list. + IdentifierInfo **ParameterList = nullptr; + + /// This is the list of tokens that the macro is defined to. + const Token *ReplacementTokens = nullptr; + + /// \see ParameterList + unsigned NumParameters = 0; + + /// \see ReplacementTokens + unsigned NumReplacementTokens = 0; + + /// Length in characters of the macro definition. + mutable unsigned DefinitionLength; + mutable bool IsDefinitionLengthCached : 1; + + /// True if this macro is function-like, false if it is object-like. + bool IsFunctionLike : 1; + + /// True if this macro is of the form "#define X(...)" or + /// "#define X(Y,Z,...)". + /// + /// The __VA_ARGS__ token should be replaced with the contents of "..." in an + /// invocation. + bool IsC99Varargs : 1; + + /// True if this macro is of the form "#define X(a...)". + /// + /// The "a" identifier in the replacement list will be replaced with all + /// arguments of the macro starting with the specified one. + bool IsGNUVarargs : 1; + + /// True if this macro requires processing before expansion. + /// + /// This is the case for builtin macros such as __LINE__, so long as they have + /// not been redefined, but not for regular predefined macros from the + /// "<built-in>" memory buffer (see Preprocessing::getPredefinesFileID). + bool IsBuiltinMacro : 1; + + /// Whether this macro contains the sequence ", ## __VA_ARGS__" + bool HasCommaPasting : 1; + + //===--------------------------------------------------------------------===// + // State that changes as the macro is used. + + /// True if we have started an expansion of this macro already. + /// + /// This disables recursive expansion, which would be quite bad for things + /// like \#define A A. + bool IsDisabled : 1; + + /// True if this macro is either defined in the main file and has + /// been used, or if it is not defined in the main file. + /// + /// This is used to emit -Wunused-macros diagnostics. + bool IsUsed : 1; + + /// True if this macro can be redefined without emitting a warning. + bool IsAllowRedefinitionsWithoutWarning : 1; + + /// Must warn if the macro is unused at the end of translation unit. + bool IsWarnIfUnused : 1; + + /// Whether this macro was used as header guard. + bool UsedForHeaderGuard : 1; + + // Only the Preprocessor gets to create these. + MacroInfo(SourceLocation DefLoc); + +public: + /// Return the location that the macro was defined at. + SourceLocation getDefinitionLoc() const { return Location; } + + /// Set the location of the last token in the macro. + void setDefinitionEndLoc(SourceLocation EndLoc) { EndLocation = EndLoc; } + + /// Return the location of the last token in the macro. + SourceLocation getDefinitionEndLoc() const { return EndLocation; } + + /// Get length in characters of the macro definition. + unsigned getDefinitionLength(const SourceManager &SM) const { + if (IsDefinitionLengthCached) + return DefinitionLength; + return getDefinitionLengthSlow(SM); + } + + /// Return true if the specified macro definition is equal to + /// this macro in spelling, arguments, and whitespace. + /// + /// \param Syntactically if true, the macro definitions can be identical even + /// if they use different identifiers for the function macro parameters. + /// Otherwise the comparison is lexical and this implements the rules in + /// C99 6.10.3. + bool isIdenticalTo(const MacroInfo &Other, Preprocessor &PP, + bool Syntactically) const; + + /// Set or clear the isBuiltinMacro flag. + void setIsBuiltinMacro(bool Val = true) { IsBuiltinMacro = Val; } + + /// Set the value of the IsUsed flag. + void setIsUsed(bool Val) { IsUsed = Val; } + + /// Set the value of the IsAllowRedefinitionsWithoutWarning flag. + void setIsAllowRedefinitionsWithoutWarning(bool Val) { + IsAllowRedefinitionsWithoutWarning = Val; + } + + /// Set the value of the IsWarnIfUnused flag. + void setIsWarnIfUnused(bool val) { IsWarnIfUnused = val; } + + /// Set the specified list of identifiers as the parameter list for + /// this macro. + void setParameterList(ArrayRef<IdentifierInfo *> List, + llvm::BumpPtrAllocator &PPAllocator) { + assert(ParameterList == nullptr && NumParameters == 0 && + "Parameter list already set!"); + if (List.empty()) + return; + + NumParameters = List.size(); + ParameterList = PPAllocator.Allocate<IdentifierInfo *>(List.size()); + std::copy(List.begin(), List.end(), ParameterList); + } + + /// Parameters - The list of parameters for a function-like macro. This can + /// be empty, for, e.g. "#define X()". + using param_iterator = IdentifierInfo *const *; + bool param_empty() const { return NumParameters == 0; } + param_iterator param_begin() const { return ParameterList; } + param_iterator param_end() const { return ParameterList + NumParameters; } + unsigned getNumParams() const { return NumParameters; } + ArrayRef<const IdentifierInfo *> params() const { + return ArrayRef<const IdentifierInfo *>(ParameterList, NumParameters); + } + + /// Return the parameter number of the specified identifier, + /// or -1 if the identifier is not a formal parameter identifier. + int getParameterNum(const IdentifierInfo *Arg) const { + for (param_iterator I = param_begin(), E = param_end(); I != E; ++I) + if (*I == Arg) + return I - param_begin(); + return -1; + } + + /// Function/Object-likeness. Keep track of whether this macro has formal + /// parameters. + void setIsFunctionLike() { IsFunctionLike = true; } + bool isFunctionLike() const { return IsFunctionLike; } + bool isObjectLike() const { return !IsFunctionLike; } + + /// Varargs querying methods. This can only be set for function-like macros. + void setIsC99Varargs() { IsC99Varargs = true; } + void setIsGNUVarargs() { IsGNUVarargs = true; } + bool isC99Varargs() const { return IsC99Varargs; } + bool isGNUVarargs() const { return IsGNUVarargs; } + bool isVariadic() const { return IsC99Varargs | IsGNUVarargs; } + + /// Return true if this macro requires processing before expansion. + /// + /// This is true only for builtin macro, such as \__LINE__, whose values + /// are not given by fixed textual expansions. Regular predefined macros + /// from the "<built-in>" buffer are not reported as builtins by this + /// function. + bool isBuiltinMacro() const { return IsBuiltinMacro; } + + bool hasCommaPasting() const { return HasCommaPasting; } + void setHasCommaPasting() { HasCommaPasting = true; } + + /// Return false if this macro is defined in the main file and has + /// not yet been used. + bool isUsed() const { return IsUsed; } + + /// Return true if this macro can be redefined without warning. + bool isAllowRedefinitionsWithoutWarning() const { + return IsAllowRedefinitionsWithoutWarning; + } + + /// Return true if we should emit a warning if the macro is unused. + bool isWarnIfUnused() const { return IsWarnIfUnused; } + + /// Return the number of tokens that this macro expands to. + unsigned getNumTokens() const { return NumReplacementTokens; } + + const Token &getReplacementToken(unsigned Tok) const { + assert(Tok < NumReplacementTokens && "Invalid token #"); + return ReplacementTokens[Tok]; + } + + using const_tokens_iterator = const Token *; + + const_tokens_iterator tokens_begin() const { return ReplacementTokens; } + const_tokens_iterator tokens_end() const { + return ReplacementTokens + NumReplacementTokens; + } + bool tokens_empty() const { return NumReplacementTokens == 0; } + ArrayRef<Token> tokens() const { + return llvm::ArrayRef(ReplacementTokens, NumReplacementTokens); + } + + llvm::MutableArrayRef<Token> + allocateTokens(unsigned NumTokens, llvm::BumpPtrAllocator &PPAllocator) { + assert(ReplacementTokens == nullptr && NumReplacementTokens == 0 && + "Token list already allocated!"); + NumReplacementTokens = NumTokens; + Token *NewReplacementTokens = PPAllocator.Allocate<Token>(NumTokens); + ReplacementTokens = NewReplacementTokens; + return llvm::MutableArrayRef(NewReplacementTokens, NumTokens); + } + + void setTokens(ArrayRef<Token> Tokens, llvm::BumpPtrAllocator &PPAllocator) { + assert( + !IsDefinitionLengthCached && + "Changing replacement tokens after definition length got calculated"); + assert(ReplacementTokens == nullptr && NumReplacementTokens == 0 && + "Token list already set!"); + if (Tokens.empty()) + return; + + NumReplacementTokens = Tokens.size(); + Token *NewReplacementTokens = PPAllocator.Allocate<Token>(Tokens.size()); + std::copy(Tokens.begin(), Tokens.end(), NewReplacementTokens); + ReplacementTokens = NewReplacementTokens; + } + + /// Return true if this macro is enabled. + /// + /// In other words, that we are not currently in an expansion of this macro. + bool isEnabled() const { return !IsDisabled; } + + void EnableMacro() { + assert(IsDisabled && "Cannot enable an already-enabled macro!"); + IsDisabled = false; + } + + void DisableMacro() { + assert(!IsDisabled && "Cannot disable an already-disabled macro!"); + IsDisabled = true; + } + + /// Determine whether this macro was used for a header guard. + bool isUsedForHeaderGuard() const { return UsedForHeaderGuard; } + + void setUsedForHeaderGuard(bool Val) { UsedForHeaderGuard = Val; } + + void dump() const; + +private: + friend class Preprocessor; + + unsigned getDefinitionLengthSlow(const SourceManager &SM) const; +}; + +/// Encapsulates changes to the "macros namespace" (the location where +/// the macro name became active, the location where it was undefined, etc.). +/// +/// MacroDirectives, associated with an identifier, are used to model the macro +/// history. Usually a macro definition (MacroInfo) is where a macro name +/// becomes active (MacroDirective) but #pragma push_macro / pop_macro can +/// create additional DefMacroDirectives for the same MacroInfo. +class MacroDirective { +public: + enum Kind { + MD_Define, + MD_Undefine, + MD_Visibility + }; + +protected: + /// Previous macro directive for the same identifier, or nullptr. + MacroDirective *Previous = nullptr; + + SourceLocation Loc; + + /// MacroDirective kind. + unsigned MDKind : 2; + + /// True if the macro directive was loaded from a PCH file. + unsigned IsFromPCH : 1; + + // Used by VisibilityMacroDirective ----------------------------------------// + + /// Whether the macro has public visibility (when described in a + /// module). + unsigned IsPublic : 1; + + MacroDirective(Kind K, SourceLocation Loc) + : Loc(Loc), MDKind(K), IsFromPCH(false), IsPublic(true) {} + +public: + Kind getKind() const { return Kind(MDKind); } + + SourceLocation getLocation() const { return Loc; } + + /// Set previous definition of the macro with the same name. + void setPrevious(MacroDirective *Prev) { Previous = Prev; } + + /// Get previous definition of the macro with the same name. + const MacroDirective *getPrevious() const { return Previous; } + + /// Get previous definition of the macro with the same name. + MacroDirective *getPrevious() { return Previous; } + + /// Return true if the macro directive was loaded from a PCH file. + bool isFromPCH() const { return IsFromPCH; } + + void setIsFromPCH() { IsFromPCH = true; } + + class DefInfo { + DefMacroDirective *DefDirective = nullptr; + SourceLocation UndefLoc; + bool IsPublic = true; + + public: + DefInfo() = default; + DefInfo(DefMacroDirective *DefDirective, SourceLocation UndefLoc, + bool isPublic) + : DefDirective(DefDirective), UndefLoc(UndefLoc), IsPublic(isPublic) {} + + const DefMacroDirective *getDirective() const { return DefDirective; } + DefMacroDirective *getDirective() { return DefDirective; } + + inline SourceLocation getLocation() const; + inline MacroInfo *getMacroInfo(); + + const MacroInfo *getMacroInfo() const { + return const_cast<DefInfo *>(this)->getMacroInfo(); + } + + SourceLocation getUndefLocation() const { return UndefLoc; } + bool isUndefined() const { return UndefLoc.isValid(); } + + bool isPublic() const { return IsPublic; } + + bool isValid() const { return DefDirective != nullptr; } + bool isInvalid() const { return !isValid(); } + + explicit operator bool() const { return isValid(); } + + inline DefInfo getPreviousDefinition(); + + const DefInfo getPreviousDefinition() const { + return const_cast<DefInfo *>(this)->getPreviousDefinition(); + } + }; + + /// Traverses the macro directives history and returns the next + /// macro definition directive along with info about its undefined location + /// (if there is one) and if it is public or private. + DefInfo getDefinition(); + const DefInfo getDefinition() const { + return const_cast<MacroDirective *>(this)->getDefinition(); + } + + bool isDefined() const { + if (const DefInfo Def = getDefinition()) + return !Def.isUndefined(); + return false; + } + + const MacroInfo *getMacroInfo() const { + return getDefinition().getMacroInfo(); + } + MacroInfo *getMacroInfo() { return getDefinition().getMacroInfo(); } + + /// Find macro definition active in the specified source location. If + /// this macro was not defined there, return NULL. + const DefInfo findDirectiveAtLoc(SourceLocation L, + const SourceManager &SM) const; + + void dump() const; + + static bool classof(const MacroDirective *) { return true; } +}; + +/// A directive for a defined macro or a macro imported from a module. +class DefMacroDirective : public MacroDirective { + MacroInfo *Info; + +public: + DefMacroDirective(MacroInfo *MI, SourceLocation Loc) + : MacroDirective(MD_Define, Loc), Info(MI) { + assert(MI && "MacroInfo is null"); + } + explicit DefMacroDirective(MacroInfo *MI) + : DefMacroDirective(MI, MI->getDefinitionLoc()) {} + + /// The data for the macro definition. + const MacroInfo *getInfo() const { return Info; } + MacroInfo *getInfo() { return Info; } + + static bool classof(const MacroDirective *MD) { + return MD->getKind() == MD_Define; + } + + static bool classof(const DefMacroDirective *) { return true; } +}; + +/// A directive for an undefined macro. +class UndefMacroDirective : public MacroDirective { +public: + explicit UndefMacroDirective(SourceLocation UndefLoc) + : MacroDirective(MD_Undefine, UndefLoc) { + assert(UndefLoc.isValid() && "Invalid UndefLoc!"); + } + + static bool classof(const MacroDirective *MD) { + return MD->getKind() == MD_Undefine; + } + + static bool classof(const UndefMacroDirective *) { return true; } +}; + +/// A directive for setting the module visibility of a macro. +class VisibilityMacroDirective : public MacroDirective { +public: + explicit VisibilityMacroDirective(SourceLocation Loc, bool Public) + : MacroDirective(MD_Visibility, Loc) { + IsPublic = Public; + } + + /// Determine whether this macro is part of the public API of its + /// module. + bool isPublic() const { return IsPublic; } + + static bool classof(const MacroDirective *MD) { + return MD->getKind() == MD_Visibility; + } + + static bool classof(const VisibilityMacroDirective *) { return true; } +}; + +inline SourceLocation MacroDirective::DefInfo::getLocation() const { + if (isInvalid()) + return {}; + return DefDirective->getLocation(); +} + +inline MacroInfo *MacroDirective::DefInfo::getMacroInfo() { + if (isInvalid()) + return nullptr; + return DefDirective->getInfo(); +} + +inline MacroDirective::DefInfo +MacroDirective::DefInfo::getPreviousDefinition() { + if (isInvalid() || DefDirective->getPrevious() == nullptr) + return {}; + return DefDirective->getPrevious()->getDefinition(); +} + +/// Represents a macro directive exported by a module. +/// +/// There's an instance of this class for every macro #define or #undef that is +/// the final directive for a macro name within a module. These entities also +/// represent the macro override graph. +/// +/// These are stored in a FoldingSet in the preprocessor. +class ModuleMacro : public llvm::FoldingSetNode { + friend class Preprocessor; + + /// The name defined by the macro. + IdentifierInfo *II; + + /// The body of the #define, or nullptr if this is a #undef. + MacroInfo *Macro; + + /// The module that exports this macro. + Module *OwningModule; + + /// The number of module macros that override this one. + unsigned NumOverriddenBy = 0; + + /// The number of modules whose macros are directly overridden by this one. + unsigned NumOverrides; + + ModuleMacro(Module *OwningModule, IdentifierInfo *II, MacroInfo *Macro, + ArrayRef<ModuleMacro *> Overrides) + : II(II), Macro(Macro), OwningModule(OwningModule), + NumOverrides(Overrides.size()) { + std::copy(Overrides.begin(), Overrides.end(), + reinterpret_cast<ModuleMacro **>(this + 1)); + } + +public: + static ModuleMacro *create(Preprocessor &PP, Module *OwningModule, + IdentifierInfo *II, MacroInfo *Macro, + ArrayRef<ModuleMacro *> Overrides); + + void Profile(llvm::FoldingSetNodeID &ID) const { + return Profile(ID, OwningModule, II); + } + + static void Profile(llvm::FoldingSetNodeID &ID, Module *OwningModule, + const IdentifierInfo *II) { + ID.AddPointer(OwningModule); + ID.AddPointer(II); + } + + /// Get the name of the macro. + IdentifierInfo *getName() const { return II; } + + /// Get the ID of the module that exports this macro. + Module *getOwningModule() const { return OwningModule; } + + /// Get definition for this exported #define, or nullptr if this + /// represents a #undef. + MacroInfo *getMacroInfo() const { return Macro; } + + /// Iterators over the overridden module IDs. + /// \{ + using overrides_iterator = ModuleMacro *const *; + + overrides_iterator overrides_begin() const { + return reinterpret_cast<overrides_iterator>(this + 1); + } + + overrides_iterator overrides_end() const { + return overrides_begin() + NumOverrides; + } + + ArrayRef<ModuleMacro *> overrides() const { + return llvm::ArrayRef(overrides_begin(), overrides_end()); + } + /// \} + + /// Get the number of macros that override this one. + unsigned getNumOverridingMacros() const { return NumOverriddenBy; } +}; + +/// A description of the current definition of a macro. +/// +/// The definition of a macro comprises a set of (at least one) defining +/// entities, which are either local MacroDirectives or imported ModuleMacros. +class MacroDefinition { + llvm::PointerIntPair<DefMacroDirective *, 1, bool> LatestLocalAndAmbiguous; + ArrayRef<ModuleMacro *> ModuleMacros; + +public: + MacroDefinition() = default; + MacroDefinition(DefMacroDirective *MD, ArrayRef<ModuleMacro *> MMs, + bool IsAmbiguous) + : LatestLocalAndAmbiguous(MD, IsAmbiguous), ModuleMacros(MMs) {} + + /// Determine whether there is a definition of this macro. + explicit operator bool() const { + return getLocalDirective() || !ModuleMacros.empty(); + } + + /// Get the MacroInfo that should be used for this definition. + MacroInfo *getMacroInfo() const { + if (!ModuleMacros.empty()) + return ModuleMacros.back()->getMacroInfo(); + if (auto *MD = getLocalDirective()) + return MD->getMacroInfo(); + return nullptr; + } + + /// \c true if the definition is ambiguous, \c false otherwise. + bool isAmbiguous() const { return LatestLocalAndAmbiguous.getInt(); } + + /// Get the latest non-imported, non-\#undef'd macro definition + /// for this macro. + DefMacroDirective *getLocalDirective() const { + return LatestLocalAndAmbiguous.getPointer(); + } + + /// Get the active module macros for this macro. + ArrayRef<ModuleMacro *> getModuleMacros() const { return ModuleMacros; } + + template <typename Fn> void forAllDefinitions(Fn F) const { + if (auto *MD = getLocalDirective()) + F(MD->getMacroInfo()); + for (auto *MM : getModuleMacros()) + F(MM->getMacroInfo()); + } +}; + +} // namespace clang + +#endif // LLVM_CLANG_LEX_MACROINFO_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Lex/ModuleLoader.h b/contrib/libs/clang16/include/clang/Lex/ModuleLoader.h new file mode 100644 index 0000000000..ef6108e3ff --- /dev/null +++ b/contrib/libs/clang16/include/clang/Lex/ModuleLoader.h @@ -0,0 +1,203 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- ModuleLoader.h - Module Loader Interface -----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the ModuleLoader interface, which is responsible for +// loading named modules. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_MODULELOADER_H +#define LLVM_CLANG_LEX_MODULELOADER_H + +#include "clang/Basic/LLVM.h" +#include "clang/Basic/Module.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/StringRef.h" +#include <utility> + +namespace clang { + +class GlobalModuleIndex; +class IdentifierInfo; + +/// A sequence of identifier/location pairs used to describe a particular +/// module or submodule, e.g., std.vector. +using ModuleIdPath = ArrayRef<std::pair<IdentifierInfo *, SourceLocation>>; + +/// Describes the result of attempting to load a module. +class ModuleLoadResult { +public: + enum LoadResultKind { + // We either succeeded or failed to load the named module. + Normal, + + // The module exists, but does not actually contain the named submodule. + // This should only happen if the named submodule was inferred from an + // umbrella directory, but not actually part of the umbrella header. + MissingExpected, + + // The module exists but cannot be imported due to a configuration mismatch. + ConfigMismatch, + }; + llvm::PointerIntPair<Module *, 2, LoadResultKind> Storage; + + ModuleLoadResult() = default; + ModuleLoadResult(Module *M) : Storage(M, Normal) {} + ModuleLoadResult(LoadResultKind Kind) : Storage(nullptr, Kind) {} + ModuleLoadResult(Module *M, LoadResultKind Kind) : Storage(M, Kind) {} + + operator bool() const { + return Storage.getInt() == Normal && Storage.getPointer(); + } + + operator Module *() const { return Storage.getPointer(); } + + /// Determines whether this is a normal return, whether or not loading the + /// module was successful. + bool isNormal() const { return Storage.getInt() == Normal; } + + /// Determines whether the module, which failed to load, was + /// actually a submodule that we expected to see (based on implying the + /// submodule from header structure), but didn't materialize in the actual + /// module. + bool isMissingExpected() const { return Storage.getInt() == MissingExpected; } + + /// Determines whether the module failed to load due to a configuration + /// mismatch with an explicitly-named .pcm file from the command line. + bool isConfigMismatch() const { return Storage.getInt() == ConfigMismatch; } +}; + +/// Abstract interface for a module loader. +/// +/// This abstract interface describes a module loader, which is responsible +/// for resolving a module name (e.g., "std") to an actual module file, and +/// then loading that module. +class ModuleLoader { + // Building a module if true. + bool BuildingModule; + +public: + explicit ModuleLoader(bool BuildingModule = false) + : BuildingModule(BuildingModule) {} + + virtual ~ModuleLoader(); + + /// Returns true if this instance is building a module. + bool buildingModule() const { + return BuildingModule; + } + + /// Flag indicating whether this instance is building a module. + void setBuildingModule(bool BuildingModuleFlag) { + BuildingModule = BuildingModuleFlag; + } + + /// Attempt to load the given module. + /// + /// This routine attempts to load the module described by the given + /// parameters. If there is a module cache, this may implicitly compile the + /// module before loading it. + /// + /// \param ImportLoc The location of the 'import' keyword. + /// + /// \param Path The identifiers (and their locations) of the module + /// "path", e.g., "std.vector" would be split into "std" and "vector". + /// + /// \param Visibility The visibility provided for the names in the loaded + /// module. + /// + /// \param IsInclusionDirective Indicates that this module is being loaded + /// implicitly, due to the presence of an inclusion directive. Otherwise, + /// it is being loaded due to an import declaration. + /// + /// \returns If successful, returns the loaded module. Otherwise, returns + /// NULL to indicate that the module could not be loaded. + virtual ModuleLoadResult loadModule(SourceLocation ImportLoc, + ModuleIdPath Path, + Module::NameVisibilityKind Visibility, + bool IsInclusionDirective) = 0; + + /// Attempt to create the given module from the specified source buffer. + /// Does not load the module or make any submodule visible; for that, use + /// loadModule and makeModuleVisible. + /// + /// \param Loc The location at which to create the module. + /// \param ModuleName The name of the module to create. + /// \param Source The source of the module: a (preprocessed) module map. + virtual void createModuleFromSource(SourceLocation Loc, StringRef ModuleName, + StringRef Source) = 0; + + /// Make the given module visible. + virtual void makeModuleVisible(Module *Mod, + Module::NameVisibilityKind Visibility, + SourceLocation ImportLoc) = 0; + + /// Load, create, or return global module. + /// This function returns an existing global module index, if one + /// had already been loaded or created, or loads one if it + /// exists, or creates one if it doesn't exist. + /// Also, importantly, if the index doesn't cover all the modules + /// in the module map, it will be update to do so here, because + /// of its use in searching for needed module imports and + /// associated fixit messages. + /// \param TriggerLoc The location for what triggered the load. + /// \returns Returns null if load failed. + virtual GlobalModuleIndex *loadGlobalModuleIndex( + SourceLocation TriggerLoc) = 0; + + /// Check global module index for missing imports. + /// \param Name The symbol name to look for. + /// \param TriggerLoc The location for what triggered the load. + /// \returns Returns true if any modules with that symbol found. + virtual bool lookupMissingImports(StringRef Name, + SourceLocation TriggerLoc) = 0; + + bool HadFatalFailure = false; +}; + +/// A module loader that doesn't know how to create or load modules. +class TrivialModuleLoader : public ModuleLoader { +public: + ModuleLoadResult loadModule(SourceLocation ImportLoc, ModuleIdPath Path, + Module::NameVisibilityKind Visibility, + bool IsInclusionDirective) override { + return {}; + } + + void createModuleFromSource(SourceLocation ImportLoc, StringRef ModuleName, + StringRef Source) override {} + + void makeModuleVisible(Module *Mod, Module::NameVisibilityKind Visibility, + SourceLocation ImportLoc) override {} + + GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override { + return nullptr; + } + + bool lookupMissingImports(StringRef Name, + SourceLocation TriggerLoc) override { + return false; + } +}; + +} // namespace clang + +#endif // LLVM_CLANG_LEX_MODULELOADER_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Lex/ModuleMap.h b/contrib/libs/clang16/include/clang/Lex/ModuleMap.h new file mode 100644 index 0000000000..0791e0b5de --- /dev/null +++ b/contrib/libs/clang16/include/clang/Lex/ModuleMap.h @@ -0,0 +1,757 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- ModuleMap.h - Describe the layout of modules -------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the ModuleMap interface, which describes the layout of a +// module as it relates to headers. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_MODULEMAP_H +#define LLVM_CLANG_LEX_MODULEMAP_H + +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/Module.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/ADT/TinyPtrVector.h" +#include "llvm/ADT/Twine.h" +#include <ctime> +#include <memory> +#include <optional> +#include <string> +#include <utility> + +namespace clang { + +class DiagnosticsEngine; +class DirectoryEntry; +class FileEntry; +class FileManager; +class HeaderSearch; +class SourceManager; + +/// A mechanism to observe the actions of the module map parser as it +/// reads module map files. +class ModuleMapCallbacks { + virtual void anchor(); + +public: + virtual ~ModuleMapCallbacks() = default; + + /// Called when a module map file has been read. + /// + /// \param FileStart A SourceLocation referring to the start of the file's + /// contents. + /// \param File The file itself. + /// \param IsSystem Whether this is a module map from a system include path. + virtual void moduleMapFileRead(SourceLocation FileStart, + const FileEntry &File, bool IsSystem) {} + + /// Called when a header is added during module map parsing. + /// + /// \param Filename The header file itself. + virtual void moduleMapAddHeader(StringRef Filename) {} + + /// Called when an umbrella header is added during module map parsing. + /// + /// \param FileMgr FileManager instance + /// \param Header The umbrella header to collect. + virtual void moduleMapAddUmbrellaHeader(FileManager *FileMgr, + const FileEntry *Header) {} +}; + +class ModuleMap { + SourceManager &SourceMgr; + DiagnosticsEngine &Diags; + const LangOptions &LangOpts; + const TargetInfo *Target; + HeaderSearch &HeaderInfo; + + llvm::SmallVector<std::unique_ptr<ModuleMapCallbacks>, 1> Callbacks; + + /// The directory used for Clang-supplied, builtin include headers, + /// such as "stdint.h". + const DirectoryEntry *BuiltinIncludeDir = nullptr; + + /// Language options used to parse the module map itself. + /// + /// These are always simple C language options. + LangOptions MMapLangOpts; + + /// The module that the main source file is associated with (the module + /// named LangOpts::CurrentModule, if we've loaded it). + Module *SourceModule = nullptr; + + /// Submodules of the current module that have not yet been attached to it. + /// (Ownership is transferred if/when we create an enclosing module.) + llvm::SmallVector<std::unique_ptr<Module>, 8> PendingSubmodules; + + /// The top-level modules that are known. + llvm::StringMap<Module *> Modules; + + /// Module loading cache that includes submodules, indexed by IdentifierInfo. + /// nullptr is stored for modules that are known to fail to load. + llvm::DenseMap<const IdentifierInfo *, Module *> CachedModuleLoads; + + /// Shadow modules created while building this module map. + llvm::SmallVector<Module*, 2> ShadowModules; + + /// The number of modules we have created in total. + unsigned NumCreatedModules = 0; + + /// In case a module has a export_as entry, it might have a pending link + /// name to be determined if that module is imported. + llvm::StringMap<llvm::StringSet<>> PendingLinkAsModule; + +public: + /// Use PendingLinkAsModule information to mark top level link names that + /// are going to be replaced by export_as aliases. + void resolveLinkAsDependencies(Module *Mod); + + /// Make module to use export_as as the link dependency name if enough + /// information is available or add it to a pending list otherwise. + void addLinkAsDependency(Module *Mod); + + /// Flags describing the role of a module header. + enum ModuleHeaderRole { + /// This header is normally included in the module. + NormalHeader = 0x0, + + /// This header is included but private. + PrivateHeader = 0x1, + + /// This header is part of the module (for layering purposes) but + /// should be textually included. + TextualHeader = 0x2, + + /// This header is explicitly excluded from the module. + ExcludedHeader = 0x4, + + // Caution: Adding an enumerator needs other changes. + // Adjust the number of bits for KnownHeader::Storage. + // Adjust the HeaderFileInfoTrait::ReadData streaming. + // Adjust the HeaderFileInfoTrait::EmitData streaming. + // Adjust ModuleMap::addHeader. + }; + + /// Convert a header kind to a role. Requires Kind to not be HK_Excluded. + static ModuleHeaderRole headerKindToRole(Module::HeaderKind Kind); + + /// Convert a header role to a kind. + static Module::HeaderKind headerRoleToKind(ModuleHeaderRole Role); + + /// Check if the header with the given role is a modular one. + static bool isModular(ModuleHeaderRole Role); + + /// A header that is known to reside within a given module, + /// whether it was included or excluded. + class KnownHeader { + llvm::PointerIntPair<Module *, 3, ModuleHeaderRole> Storage; + + public: + KnownHeader() : Storage(nullptr, NormalHeader) {} + KnownHeader(Module *M, ModuleHeaderRole Role) : Storage(M, Role) {} + + friend bool operator==(const KnownHeader &A, const KnownHeader &B) { + return A.Storage == B.Storage; + } + friend bool operator!=(const KnownHeader &A, const KnownHeader &B) { + return A.Storage != B.Storage; + } + + /// Retrieve the module the header is stored in. + Module *getModule() const { return Storage.getPointer(); } + + /// The role of this header within the module. + ModuleHeaderRole getRole() const { return Storage.getInt(); } + + /// Whether this header is available in the module. + bool isAvailable() const { + return getRole() != ExcludedHeader && getModule()->isAvailable(); + } + + /// Whether this header is accessible from the specified module. + bool isAccessibleFrom(Module *M) const { + return !(getRole() & PrivateHeader) || + (M && M->getTopLevelModule() == getModule()->getTopLevelModule()); + } + + // Whether this known header is valid (i.e., it has an + // associated module). + explicit operator bool() const { + return Storage.getPointer() != nullptr; + } + }; + + using AdditionalModMapsSet = llvm::SmallPtrSet<const FileEntry *, 1>; + +private: + friend class ModuleMapParser; + + using HeadersMap = + llvm::DenseMap<const FileEntry *, SmallVector<KnownHeader, 1>>; + + /// Mapping from each header to the module that owns the contents of + /// that header. + HeadersMap Headers; + + /// Map from file sizes to modules with lazy header directives of that size. + mutable llvm::DenseMap<off_t, llvm::TinyPtrVector<Module*>> LazyHeadersBySize; + + /// Map from mtimes to modules with lazy header directives with those mtimes. + mutable llvm::DenseMap<time_t, llvm::TinyPtrVector<Module*>> + LazyHeadersByModTime; + + /// Mapping from directories with umbrella headers to the module + /// that is generated from the umbrella header. + /// + /// This mapping is used to map headers that haven't explicitly been named + /// in the module map over to the module that includes them via its umbrella + /// header. + llvm::DenseMap<const DirectoryEntry *, Module *> UmbrellaDirs; + + /// A generation counter that is used to test whether modules of the + /// same name may shadow or are illegal redefinitions. + /// + /// Modules from earlier scopes may shadow modules from later ones. + /// Modules from the same scope may not have the same name. + unsigned CurrentModuleScopeID = 0; + + llvm::DenseMap<Module *, unsigned> ModuleScopeIDs; + + /// The set of attributes that can be attached to a module. + struct Attributes { + /// Whether this is a system module. + unsigned IsSystem : 1; + + /// Whether this is an extern "C" module. + unsigned IsExternC : 1; + + /// Whether this is an exhaustive set of configuration macros. + unsigned IsExhaustive : 1; + + /// Whether files in this module can only include non-modular headers + /// and headers from used modules. + unsigned NoUndeclaredIncludes : 1; + + Attributes() + : IsSystem(false), IsExternC(false), IsExhaustive(false), + NoUndeclaredIncludes(false) {} + }; + + /// A directory for which framework modules can be inferred. + struct InferredDirectory { + /// Whether to infer modules from this directory. + unsigned InferModules : 1; + + /// The attributes to use for inferred modules. + Attributes Attrs; + + /// If \c InferModules is non-zero, the module map file that allowed + /// inferred modules. Otherwise, nullptr. + const FileEntry *ModuleMapFile; + + /// The names of modules that cannot be inferred within this + /// directory. + SmallVector<std::string, 2> ExcludedModules; + + InferredDirectory() : InferModules(false) {} + }; + + /// A mapping from directories to information about inferring + /// framework modules from within those directories. + llvm::DenseMap<const DirectoryEntry *, InferredDirectory> InferredDirectories; + + /// A mapping from an inferred module to the module map that allowed the + /// inference. + llvm::DenseMap<const Module *, const FileEntry *> InferredModuleAllowedBy; + + llvm::DenseMap<const Module *, AdditionalModMapsSet> AdditionalModMaps; + + /// Describes whether we haved parsed a particular file as a module + /// map. + llvm::DenseMap<const FileEntry *, bool> ParsedModuleMap; + + /// Resolve the given export declaration into an actual export + /// declaration. + /// + /// \param Mod The module in which we're resolving the export declaration. + /// + /// \param Unresolved The export declaration to resolve. + /// + /// \param Complain Whether this routine should complain about unresolvable + /// exports. + /// + /// \returns The resolved export declaration, which will have a NULL pointer + /// if the export could not be resolved. + Module::ExportDecl + resolveExport(Module *Mod, const Module::UnresolvedExportDecl &Unresolved, + bool Complain) const; + + /// Resolve the given module id to an actual module. + /// + /// \param Id The module-id to resolve. + /// + /// \param Mod The module in which we're resolving the module-id. + /// + /// \param Complain Whether this routine should complain about unresolvable + /// module-ids. + /// + /// \returns The resolved module, or null if the module-id could not be + /// resolved. + Module *resolveModuleId(const ModuleId &Id, Module *Mod, bool Complain) const; + + /// Add an unresolved header to a module. + /// + /// \param Mod The module in which we're adding the unresolved header + /// directive. + /// \param Header The unresolved header directive. + /// \param NeedsFramework If Mod is not a framework but a missing header would + /// be found in case Mod was, set it to true. False otherwise. + void addUnresolvedHeader(Module *Mod, + Module::UnresolvedHeaderDirective Header, + bool &NeedsFramework); + + /// Look up the given header directive to find an actual header file. + /// + /// \param M The module in which we're resolving the header directive. + /// \param Header The header directive to resolve. + /// \param RelativePathName Filled in with the relative path name from the + /// module to the resolved header. + /// \param NeedsFramework If M is not a framework but a missing header would + /// be found in case M was, set it to true. False otherwise. + /// \return The resolved file, if any. + OptionalFileEntryRef + findHeader(Module *M, const Module::UnresolvedHeaderDirective &Header, + SmallVectorImpl<char> &RelativePathName, bool &NeedsFramework); + + /// Resolve the given header directive. + /// + /// \param M The module in which we're resolving the header directive. + /// \param Header The header directive to resolve. + /// \param NeedsFramework If M is not a framework but a missing header would + /// be found in case M was, set it to true. False otherwise. + void resolveHeader(Module *M, const Module::UnresolvedHeaderDirective &Header, + bool &NeedsFramework); + + /// Attempt to resolve the specified header directive as naming a builtin + /// header. + /// \return \c true if a corresponding builtin header was found. + bool resolveAsBuiltinHeader(Module *M, + const Module::UnresolvedHeaderDirective &Header); + + /// Looks up the modules that \p File corresponds to. + /// + /// If \p File represents a builtin header within Clang's builtin include + /// directory, this also loads all of the module maps to see if it will get + /// associated with a specific module (e.g. in /usr/include). + HeadersMap::iterator findKnownHeader(const FileEntry *File); + + /// Searches for a module whose umbrella directory contains \p File. + /// + /// \param File The header to search for. + /// + /// \param IntermediateDirs On success, contains the set of directories + /// searched before finding \p File. + KnownHeader findHeaderInUmbrellaDirs(const FileEntry *File, + SmallVectorImpl<const DirectoryEntry *> &IntermediateDirs); + + /// Given that \p File is not in the Headers map, look it up within + /// umbrella directories and find or create a module for it. + KnownHeader findOrCreateModuleForHeaderInUmbrellaDir(const FileEntry *File); + + /// A convenience method to determine if \p File is (possibly nested) + /// in an umbrella directory. + bool isHeaderInUmbrellaDirs(const FileEntry *File) { + SmallVector<const DirectoryEntry *, 2> IntermediateDirs; + return static_cast<bool>(findHeaderInUmbrellaDirs(File, IntermediateDirs)); + } + + Module *inferFrameworkModule(const DirectoryEntry *FrameworkDir, + Attributes Attrs, Module *Parent); + +public: + /// Construct a new module map. + /// + /// \param SourceMgr The source manager used to find module files and headers. + /// This source manager should be shared with the header-search mechanism, + /// since they will refer to the same headers. + /// + /// \param Diags A diagnostic engine used for diagnostics. + /// + /// \param LangOpts Language options for this translation unit. + /// + /// \param Target The target for this translation unit. + ModuleMap(SourceManager &SourceMgr, DiagnosticsEngine &Diags, + const LangOptions &LangOpts, const TargetInfo *Target, + HeaderSearch &HeaderInfo); + + /// Destroy the module map. + ~ModuleMap(); + + /// Set the target information. + void setTarget(const TargetInfo &Target); + + /// Set the directory that contains Clang-supplied include + /// files, such as our stdarg.h or tgmath.h. + void setBuiltinIncludeDir(const DirectoryEntry *Dir) { + BuiltinIncludeDir = Dir; + } + + /// Get the directory that contains Clang-supplied include files. + const DirectoryEntry *getBuiltinDir() const { + return BuiltinIncludeDir; + } + + /// Is this a compiler builtin header? + static bool isBuiltinHeader(StringRef FileName); + bool isBuiltinHeader(const FileEntry *File); + + /// Add a module map callback. + void addModuleMapCallbacks(std::unique_ptr<ModuleMapCallbacks> Callback) { + Callbacks.push_back(std::move(Callback)); + } + + /// Retrieve the module that owns the given header file, if any. Note that + /// this does not implicitly load module maps, except for builtin headers, + /// and does not consult the external source. (Those checks are the + /// responsibility of \ref HeaderSearch.) + /// + /// \param File The header file that is likely to be included. + /// + /// \param AllowTextual If \c true and \p File is a textual header, return + /// its owning module. Otherwise, no KnownHeader will be returned if the + /// file is only known as a textual header. + /// + /// \returns The module KnownHeader, which provides the module that owns the + /// given header file. The KnownHeader is default constructed to indicate + /// that no module owns this header file. + KnownHeader findModuleForHeader(const FileEntry *File, + bool AllowTextual = false, + bool AllowExcluded = false); + + /// Retrieve all the modules that contain the given header file. Note that + /// this does not implicitly load module maps, except for builtin headers, + /// and does not consult the external source. (Those checks are the + /// responsibility of \ref HeaderSearch.) + /// + /// Typically, \ref findModuleForHeader should be used instead, as it picks + /// the preferred module for the header. + ArrayRef<KnownHeader> findAllModulesForHeader(const FileEntry *File); + + /// Like \ref findAllModulesForHeader, but do not attempt to infer module + /// ownership from umbrella headers if we've not already done so. + ArrayRef<KnownHeader> + findResolvedModulesForHeader(const FileEntry *File) const; + + /// Resolve all lazy header directives for the specified file. + /// + /// This ensures that the HeaderFileInfo on HeaderSearch is up to date. This + /// is effectively internal, but is exposed so HeaderSearch can call it. + void resolveHeaderDirectives(const FileEntry *File) const; + + /// Resolve lazy header directives for the specified module. If File is + /// provided, only headers with same size and modtime are resolved. If File + /// is not set, all headers are resolved. + void resolveHeaderDirectives(Module *Mod, + std::optional<const FileEntry *> File) const; + + /// Reports errors if a module must not include a specific file. + /// + /// \param RequestingModule The module including a file. + /// + /// \param RequestingModuleIsModuleInterface \c true if the inclusion is in + /// the interface of RequestingModule, \c false if it's in the + /// implementation of RequestingModule. Value is ignored and + /// meaningless if RequestingModule is nullptr. + /// + /// \param FilenameLoc The location of the inclusion's filename. + /// + /// \param Filename The included filename as written. + /// + /// \param File The included file. + void diagnoseHeaderInclusion(Module *RequestingModule, + bool RequestingModuleIsModuleInterface, + SourceLocation FilenameLoc, StringRef Filename, + FileEntryRef File); + + /// Determine whether the given header is part of a module + /// marked 'unavailable'. + bool isHeaderInUnavailableModule(const FileEntry *Header) const; + + /// Determine whether the given header is unavailable as part + /// of the specified module. + bool isHeaderUnavailableInModule(const FileEntry *Header, + const Module *RequestingModule) const; + + /// Retrieve a module with the given name. + /// + /// \param Name The name of the module to look up. + /// + /// \returns The named module, if known; otherwise, returns null. + Module *findModule(StringRef Name) const; + + /// Retrieve a module with the given name using lexical name lookup, + /// starting at the given context. + /// + /// \param Name The name of the module to look up. + /// + /// \param Context The module context, from which we will perform lexical + /// name lookup. + /// + /// \returns The named module, if known; otherwise, returns null. + Module *lookupModuleUnqualified(StringRef Name, Module *Context) const; + + /// Retrieve a module with the given name within the given context, + /// using direct (qualified) name lookup. + /// + /// \param Name The name of the module to look up. + /// + /// \param Context The module for which we will look for a submodule. If + /// null, we will look for a top-level module. + /// + /// \returns The named submodule, if known; otherwose, returns null. + Module *lookupModuleQualified(StringRef Name, Module *Context) const; + + /// Find a new module or submodule, or create it if it does not already + /// exist. + /// + /// \param Name The name of the module to find or create. + /// + /// \param Parent The module that will act as the parent of this submodule, + /// or nullptr to indicate that this is a top-level module. + /// + /// \param IsFramework Whether this is a framework module. + /// + /// \param IsExplicit Whether this is an explicit submodule. + /// + /// \returns The found or newly-created module, along with a boolean value + /// that will be true if the module is newly-created. + std::pair<Module *, bool> findOrCreateModule(StringRef Name, Module *Parent, + bool IsFramework, + bool IsExplicit); + + /// Create a global module fragment for a C++ module unit. + /// + /// We model the global module fragment as a submodule of the module + /// interface unit. Unfortunately, we can't create the module interface + /// unit's Module until later, because we don't know what it will be called + /// usually. See C++20 [module.unit]/7.2 for the case we could know its + /// parent. + Module *createGlobalModuleFragmentForModuleUnit(SourceLocation Loc, + Module *Parent = nullptr); + + /// Create a global module fragment for a C++ module interface unit. + Module *createPrivateModuleFragmentForInterfaceUnit(Module *Parent, + SourceLocation Loc); + + /// Create a new module for a C++ module interface unit. + /// The module must not already exist, and will be configured for the current + /// compilation. + /// + /// Note that this also sets the current module to the newly-created module. + /// + /// \returns The newly-created module. + Module *createModuleForInterfaceUnit(SourceLocation Loc, StringRef Name); + + /// Create a C++20 header unit. + Module *createHeaderUnit(SourceLocation Loc, StringRef Name, + Module::Header H); + + /// Infer the contents of a framework module map from the given + /// framework directory. + Module *inferFrameworkModule(const DirectoryEntry *FrameworkDir, + bool IsSystem, Module *Parent); + + /// Create a new top-level module that is shadowed by + /// \p ShadowingModule. + Module *createShadowedModule(StringRef Name, bool IsFramework, + Module *ShadowingModule); + + /// Creates a new declaration scope for module names, allowing + /// previously defined modules to shadow definitions from the new scope. + /// + /// \note Module names from earlier scopes will shadow names from the new + /// scope, which is the opposite of how shadowing works for variables. + void finishModuleDeclarationScope() { CurrentModuleScopeID += 1; } + + bool mayShadowNewModule(Module *ExistingModule) { + assert(!ExistingModule->Parent && "expected top-level module"); + assert(ModuleScopeIDs.count(ExistingModule) && "unknown module"); + return ModuleScopeIDs[ExistingModule] < CurrentModuleScopeID; + } + + /// Check whether a framework module can be inferred in the given directory. + bool canInferFrameworkModule(const DirectoryEntry *Dir) const { + auto It = InferredDirectories.find(Dir); + return It != InferredDirectories.end() && It->getSecond().InferModules; + } + + /// Retrieve the module map file containing the definition of the given + /// module. + /// + /// \param Module The module whose module map file will be returned, if known. + /// + /// \returns The file entry for the module map file containing the given + /// module, or nullptr if the module definition was inferred. + OptionalFileEntryRef getContainingModuleMapFile(const Module *Module) const; + + /// Get the module map file that (along with the module name) uniquely + /// identifies this module. + /// + /// The particular module that \c Name refers to may depend on how the module + /// was found in header search. However, the combination of \c Name and + /// this module map will be globally unique for top-level modules. In the case + /// of inferred modules, returns the module map that allowed the inference + /// (e.g. contained 'module *'). Otherwise, returns + /// getContainingModuleMapFile(). + OptionalFileEntryRef getModuleMapFileForUniquing(const Module *M) const; + + void setInferredModuleAllowedBy(Module *M, const FileEntry *ModMap); + + /// Canonicalize \p Path in a manner suitable for a module map file. In + /// particular, this canonicalizes the parent directory separately from the + /// filename so that it does not affect header resolution relative to the + /// modulemap. + /// + /// \returns an error code if any filesystem operations failed. In this case + /// \p Path is not modified. + std::error_code canonicalizeModuleMapPath(SmallVectorImpl<char> &Path); + + /// Get any module map files other than getModuleMapFileForUniquing(M) + /// that define submodules of a top-level module \p M. This is cheaper than + /// getting the module map file for each submodule individually, since the + /// expected number of results is very small. + AdditionalModMapsSet *getAdditionalModuleMapFiles(const Module *M) { + auto I = AdditionalModMaps.find(M); + if (I == AdditionalModMaps.end()) + return nullptr; + return &I->second; + } + + void addAdditionalModuleMapFile(const Module *M, const FileEntry *ModuleMap); + + /// Resolve all of the unresolved exports in the given module. + /// + /// \param Mod The module whose exports should be resolved. + /// + /// \param Complain Whether to emit diagnostics for failures. + /// + /// \returns true if any errors were encountered while resolving exports, + /// false otherwise. + bool resolveExports(Module *Mod, bool Complain); + + /// Resolve all of the unresolved uses in the given module. + /// + /// \param Mod The module whose uses should be resolved. + /// + /// \param Complain Whether to emit diagnostics for failures. + /// + /// \returns true if any errors were encountered while resolving uses, + /// false otherwise. + bool resolveUses(Module *Mod, bool Complain); + + /// Resolve all of the unresolved conflicts in the given module. + /// + /// \param Mod The module whose conflicts should be resolved. + /// + /// \param Complain Whether to emit diagnostics for failures. + /// + /// \returns true if any errors were encountered while resolving conflicts, + /// false otherwise. + bool resolveConflicts(Module *Mod, bool Complain); + + /// Sets the umbrella header of the given module to the given + /// header. + void setUmbrellaHeader(Module *Mod, FileEntryRef UmbrellaHeader, + const Twine &NameAsWritten, + const Twine &PathRelativeToRootModuleDirectory); + + /// Sets the umbrella directory of the given module to the given + /// directory. + void setUmbrellaDir(Module *Mod, const DirectoryEntry *UmbrellaDir, + const Twine &NameAsWritten, + const Twine &PathRelativeToRootModuleDirectory); + + /// Adds this header to the given module. + /// \param Role The role of the header wrt the module. + void addHeader(Module *Mod, Module::Header Header, + ModuleHeaderRole Role, bool Imported = false); + + /// Parse the given module map file, and record any modules we + /// encounter. + /// + /// \param File The file to be parsed. + /// + /// \param IsSystem Whether this module map file is in a system header + /// directory, and therefore should be considered a system module. + /// + /// \param HomeDir The directory in which relative paths within this module + /// map file will be resolved. + /// + /// \param ID The FileID of the file to process, if we've already entered it. + /// + /// \param Offset [inout] On input the offset at which to start parsing. On + /// output, the offset at which the module map terminated. + /// + /// \param ExternModuleLoc The location of the "extern module" declaration + /// that caused us to load this module map file, if any. + /// + /// \returns true if an error occurred, false otherwise. + bool parseModuleMapFile(const FileEntry *File, bool IsSystem, + const DirectoryEntry *HomeDir, + FileID ID = FileID(), unsigned *Offset = nullptr, + SourceLocation ExternModuleLoc = SourceLocation()); + + /// Dump the contents of the module map, for debugging purposes. + void dump(); + + using module_iterator = llvm::StringMap<Module *>::const_iterator; + + module_iterator module_begin() const { return Modules.begin(); } + module_iterator module_end() const { return Modules.end(); } + llvm::iterator_range<module_iterator> modules() const { + return {module_begin(), module_end()}; + } + + /// Cache a module load. M might be nullptr. + void cacheModuleLoad(const IdentifierInfo &II, Module *M) { + CachedModuleLoads[&II] = M; + } + + /// Return a cached module load. + std::optional<Module *> getCachedModuleLoad(const IdentifierInfo &II) { + auto I = CachedModuleLoads.find(&II); + if (I == CachedModuleLoads.end()) + return std::nullopt; + return I->second; + } +}; + +} // namespace clang + +#endif // LLVM_CLANG_LEX_MODULEMAP_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Lex/MultipleIncludeOpt.h b/contrib/libs/clang16/include/clang/Lex/MultipleIncludeOpt.h new file mode 100644 index 0000000000..78cf69fd74 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Lex/MultipleIncludeOpt.h @@ -0,0 +1,191 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===--- MultipleIncludeOpt.h - Header Multiple-Include Optzn ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Defines the MultipleIncludeOpt interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_MULTIPLEINCLUDEOPT_H +#define LLVM_CLANG_LEX_MULTIPLEINCLUDEOPT_H + +#include "clang/Basic/SourceLocation.h" + +namespace clang { +class IdentifierInfo; + +/// Implements the simple state machine that the Lexer class uses to +/// detect files subject to the 'multiple-include' optimization. +/// +/// The public methods in this class are triggered by various +/// events that occur when a file is lexed, and after the entire file is lexed, +/// information about which macro (if any) controls the header is returned. +class MultipleIncludeOpt { + /// ReadAnyTokens - This is set to false when a file is first opened and true + /// any time a token is returned to the client or a (non-multiple-include) + /// directive is parsed. When the final \#endif is parsed this is reset back + /// to false, that way any tokens before the first \#ifdef or after the last + /// \#endif can be easily detected. + bool ReadAnyTokens; + + /// ImmediatelyAfterTopLevelIfndef - This is true when the only tokens + /// processed in the file so far is an #ifndef and an identifier. Used in + /// the detection of header guards in a file. + bool ImmediatelyAfterTopLevelIfndef; + + /// ReadAnyTokens - This is set to false when a file is first opened and true + /// any time a token is returned to the client or a (non-multiple-include) + /// directive is parsed. When the final #endif is parsed this is reset back + /// to false, that way any tokens before the first #ifdef or after the last + /// #endif can be easily detected. + bool DidMacroExpansion; + + /// TheMacro - The controlling macro for a file, if valid. + /// + const IdentifierInfo *TheMacro; + + /// DefinedMacro - The macro defined right after TheMacro, if any. + const IdentifierInfo *DefinedMacro; + + SourceLocation MacroLoc; + SourceLocation DefinedLoc; +public: + MultipleIncludeOpt() { + ReadAnyTokens = false; + ImmediatelyAfterTopLevelIfndef = false; + DidMacroExpansion = false; + TheMacro = nullptr; + DefinedMacro = nullptr; + } + + SourceLocation GetMacroLocation() const { + return MacroLoc; + } + + SourceLocation GetDefinedLocation() const { + return DefinedLoc; + } + + void resetImmediatelyAfterTopLevelIfndef() { + ImmediatelyAfterTopLevelIfndef = false; + } + + void SetDefinedMacro(IdentifierInfo *M, SourceLocation Loc) { + DefinedMacro = M; + DefinedLoc = Loc; + } + + /// Invalidate - Permanently mark this file as not being suitable for the + /// include-file optimization. + void Invalidate() { + // If we have read tokens but have no controlling macro, the state-machine + // below can never "accept". + ReadAnyTokens = true; + ImmediatelyAfterTopLevelIfndef = false; + DefinedMacro = nullptr; + TheMacro = nullptr; + } + + /// getHasReadAnyTokensVal - This is used for the \#ifndef handshake at the + /// top of the file when reading preprocessor directives. Otherwise, reading + /// the "ifndef x" would count as reading tokens. + bool getHasReadAnyTokensVal() const { return ReadAnyTokens; } + + /// getImmediatelyAfterTopLevelIfndef - returns true if the last directive + /// was an #ifndef at the beginning of the file. + bool getImmediatelyAfterTopLevelIfndef() const { + return ImmediatelyAfterTopLevelIfndef; + } + + // If a token is read, remember that we have seen a side-effect in this file. + void ReadToken() { + ReadAnyTokens = true; + ImmediatelyAfterTopLevelIfndef = false; + } + + /// ExpandedMacro - When a macro is expanded with this lexer as the current + /// buffer, this method is called to disable the MIOpt if needed. + void ExpandedMacro() { DidMacroExpansion = true; } + + /// Called when entering a top-level \#ifndef directive (or the + /// "\#if !defined" equivalent) without any preceding tokens. + /// + /// Note, we don't care about the input value of 'ReadAnyTokens'. The caller + /// ensures that this is only called if there are no tokens read before the + /// \#ifndef. The caller is required to do this, because reading the \#if + /// line obviously reads in tokens. + void EnterTopLevelIfndef(const IdentifierInfo *M, SourceLocation Loc) { + // If the macro is already set, this is after the top-level #endif. + if (TheMacro) + return Invalidate(); + + // If we have already expanded a macro by the end of the #ifndef line, then + // there is a macro expansion *in* the #ifndef line. This means that the + // condition could evaluate differently when subsequently #included. Reject + // this. + if (DidMacroExpansion) + return Invalidate(); + + // Remember that we're in the #if and that we have the macro. + ReadAnyTokens = true; + ImmediatelyAfterTopLevelIfndef = true; + TheMacro = M; + MacroLoc = Loc; + } + + /// Invoked when a top level conditional (except \#ifndef) is found. + void EnterTopLevelConditional() { + // If a conditional directive (except #ifndef) is found at the top level, + // there is a chunk of the file not guarded by the controlling macro. + Invalidate(); + } + + /// Called when the lexer exits the top-level conditional. + void ExitTopLevelConditional() { + // If we have a macro, that means the top of the file was ok. Set our state + // back to "not having read any tokens" so we can detect anything after the + // #endif. + if (!TheMacro) return Invalidate(); + + // At this point, we haven't "read any tokens" but we do have a controlling + // macro. + ReadAnyTokens = false; + ImmediatelyAfterTopLevelIfndef = false; + } + + /// Once the entire file has been lexed, if there is a controlling + /// macro, return it. + const IdentifierInfo *GetControllingMacroAtEndOfFile() const { + // If we haven't read any tokens after the #endif, return the controlling + // macro if it's valid (if it isn't, it will be null). + if (!ReadAnyTokens) + return TheMacro; + return nullptr; + } + + /// If the ControllingMacro is followed by a macro definition, return + /// the macro that was defined. + const IdentifierInfo *GetDefinedMacro() const { + return DefinedMacro; + } +}; + +} // end namespace clang + +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Lex/PPCallbacks.h b/contrib/libs/clang16/include/clang/Lex/PPCallbacks.h new file mode 100644 index 0000000000..84e6b96985 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Lex/PPCallbacks.h @@ -0,0 +1,720 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===--- PPCallbacks.h - Callbacks for Preprocessor actions -----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Defines the PPCallbacks interface. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_PPCALLBACKS_H +#define LLVM_CLANG_LEX_PPCALLBACKS_H + +#include "clang/Basic/DiagnosticIDs.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Lex/ModuleLoader.h" +#include "clang/Lex/Pragma.h" +#include "llvm/ADT/StringRef.h" + +namespace clang { + class Token; + class IdentifierInfo; + class MacroDefinition; + class MacroDirective; + class MacroArgs; + +/// This interface provides a way to observe the actions of the +/// preprocessor as it does its thing. +/// +/// Clients can define their hooks here to implement preprocessor level tools. +class PPCallbacks { +public: + virtual ~PPCallbacks(); + + enum FileChangeReason { + EnterFile, ExitFile, SystemHeaderPragma, RenameFile + }; + + /// Callback invoked whenever a source file is entered or exited. + /// + /// \param Loc Indicates the new location. + /// \param PrevFID the file that was exited if \p Reason is ExitFile or the + /// the file before the new one entered for \p Reason EnterFile. + virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason, + SrcMgr::CharacteristicKind FileType, + FileID PrevFID = FileID()) { + } + + enum class LexedFileChangeReason { EnterFile, ExitFile }; + + /// Callback invoked whenever the \p Lexer moves to a different file for + /// lexing. Unlike \p FileChanged line number directives and other related + /// pragmas do not trigger callbacks to \p LexedFileChanged. + /// + /// \param FID The \p FileID that the \p Lexer moved to. + /// + /// \param Reason Whether the \p Lexer entered a new file or exited one. + /// + /// \param FileType The \p CharacteristicKind of the file the \p Lexer moved + /// to. + /// + /// \param PrevFID The \p FileID the \p Lexer was using before the change. + /// + /// \param Loc The location where the \p Lexer entered a new file from or the + /// location that the \p Lexer moved into after exiting a file. + virtual void LexedFileChanged(FileID FID, LexedFileChangeReason Reason, + SrcMgr::CharacteristicKind FileType, + FileID PrevFID, SourceLocation Loc) {} + + /// Callback invoked whenever a source file is skipped as the result + /// of header guard optimization. + /// + /// \param SkippedFile The file that is skipped instead of entering \#include + /// + /// \param FilenameTok The file name token in \#include "FileName" directive + /// or macro expanded file name token from \#include MACRO(PARAMS) directive. + /// Note that FilenameTok contains corresponding quotes/angles symbols. + virtual void FileSkipped(const FileEntryRef &SkippedFile, + const Token &FilenameTok, + SrcMgr::CharacteristicKind FileType) {} + + /// Callback invoked whenever the preprocessor cannot find a file for an + /// inclusion directive. + /// + /// \param FileName The name of the file being included, as written in the + /// source code. + /// + /// \returns true to indicate that the preprocessor should skip this file + /// and not issue any diagnostic. + virtual bool FileNotFound(StringRef FileName) { return false; } + + /// Callback invoked whenever an inclusion directive of + /// any kind (\c \#include, \c \#import, etc.) has been processed, regardless + /// of whether the inclusion will actually result in an inclusion. + /// + /// \param HashLoc The location of the '#' that starts the inclusion + /// directive. + /// + /// \param IncludeTok The token that indicates the kind of inclusion + /// directive, e.g., 'include' or 'import'. + /// + /// \param FileName The name of the file being included, as written in the + /// source code. + /// + /// \param IsAngled Whether the file name was enclosed in angle brackets; + /// otherwise, it was enclosed in quotes. + /// + /// \param FilenameRange The character range of the quotes or angle brackets + /// for the written file name. + /// + /// \param File The actual file that may be included by this inclusion + /// directive. + /// + /// \param SearchPath Contains the search path which was used to find the file + /// in the file system. If the file was found via an absolute include path, + /// SearchPath will be empty. For framework includes, the SearchPath and + /// RelativePath will be split up. For example, if an include of "Some/Some.h" + /// is found via the framework path + /// "path/to/Frameworks/Some.framework/Headers/Some.h", SearchPath will be + /// "path/to/Frameworks/Some.framework/Headers" and RelativePath will be + /// "Some.h". + /// + /// \param RelativePath The path relative to SearchPath, at which the include + /// file was found. This is equal to FileName except for framework includes. + /// + /// \param Imported The module, whenever an inclusion directive was + /// automatically turned into a module import or null otherwise. + /// + /// \param FileType The characteristic kind, indicates whether a file or + /// directory holds normal user code, system code, or system code which is + /// implicitly 'extern "C"' in C++ mode. + /// + virtual void InclusionDirective(SourceLocation HashLoc, + const Token &IncludeTok, StringRef FileName, + bool IsAngled, CharSourceRange FilenameRange, + OptionalFileEntryRef File, + StringRef SearchPath, StringRef RelativePath, + const Module *Imported, + SrcMgr::CharacteristicKind FileType) {} + + /// Callback invoked whenever a submodule was entered. + /// + /// \param M The submodule we have entered. + /// + /// \param ImportLoc The location of import directive token. + /// + /// \param ForPragma If entering from pragma directive. + /// + virtual void EnteredSubmodule(Module *M, SourceLocation ImportLoc, + bool ForPragma) { } + + /// Callback invoked whenever a submodule was left. + /// + /// \param M The submodule we have left. + /// + /// \param ImportLoc The location of import directive token. + /// + /// \param ForPragma If entering from pragma directive. + /// + virtual void LeftSubmodule(Module *M, SourceLocation ImportLoc, + bool ForPragma) { } + + /// Callback invoked whenever there was an explicit module-import + /// syntax. + /// + /// \param ImportLoc The location of import directive token. + /// + /// \param Path The identifiers (and their locations) of the module + /// "path", e.g., "std.vector" would be split into "std" and "vector". + /// + /// \param Imported The imported module; can be null if importing failed. + /// + virtual void moduleImport(SourceLocation ImportLoc, + ModuleIdPath Path, + const Module *Imported) { + } + + /// Callback invoked when the end of the main file is reached. + /// + /// No subsequent callbacks will be made. + virtual void EndOfMainFile() { + } + + /// Callback invoked when a \#ident or \#sccs directive is read. + /// \param Loc The location of the directive. + /// \param str The text of the directive. + /// + virtual void Ident(SourceLocation Loc, StringRef str) { + } + + /// Callback invoked when start reading any pragma directive. + virtual void PragmaDirective(SourceLocation Loc, + PragmaIntroducerKind Introducer) { + } + + /// Callback invoked when a \#pragma comment directive is read. + virtual void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind, + StringRef Str) { + } + + /// Callback invoked when a \#pragma mark comment is read. + virtual void PragmaMark(SourceLocation Loc, StringRef Trivia) { + } + + /// Callback invoked when a \#pragma detect_mismatch directive is + /// read. + virtual void PragmaDetectMismatch(SourceLocation Loc, StringRef Name, + StringRef Value) { + } + + /// Callback invoked when a \#pragma clang __debug directive is read. + /// \param Loc The location of the debug directive. + /// \param DebugType The identifier following __debug. + virtual void PragmaDebug(SourceLocation Loc, StringRef DebugType) { + } + + /// Determines the kind of \#pragma invoking a call to PragmaMessage. + enum PragmaMessageKind { + /// \#pragma message has been invoked. + PMK_Message, + + /// \#pragma GCC warning has been invoked. + PMK_Warning, + + /// \#pragma GCC error has been invoked. + PMK_Error + }; + + /// Callback invoked when a \#pragma message directive is read. + /// \param Loc The location of the message directive. + /// \param Namespace The namespace of the message directive. + /// \param Kind The type of the message directive. + /// \param Str The text of the message directive. + virtual void PragmaMessage(SourceLocation Loc, StringRef Namespace, + PragmaMessageKind Kind, StringRef Str) { + } + + /// Callback invoked when a \#pragma gcc diagnostic push directive + /// is read. + virtual void PragmaDiagnosticPush(SourceLocation Loc, + StringRef Namespace) { + } + + /// Callback invoked when a \#pragma gcc diagnostic pop directive + /// is read. + virtual void PragmaDiagnosticPop(SourceLocation Loc, + StringRef Namespace) { + } + + /// Callback invoked when a \#pragma gcc diagnostic directive is read. + virtual void PragmaDiagnostic(SourceLocation Loc, StringRef Namespace, + diag::Severity mapping, StringRef Str) {} + + /// Called when an OpenCL extension is either disabled or + /// enabled with a pragma. + virtual void PragmaOpenCLExtension(SourceLocation NameLoc, + const IdentifierInfo *Name, + SourceLocation StateLoc, unsigned State) { + } + + /// Callback invoked when a \#pragma warning directive is read. + enum PragmaWarningSpecifier { + PWS_Default, + PWS_Disable, + PWS_Error, + PWS_Once, + PWS_Suppress, + PWS_Level1, + PWS_Level2, + PWS_Level3, + PWS_Level4, + }; + virtual void PragmaWarning(SourceLocation Loc, + PragmaWarningSpecifier WarningSpec, + ArrayRef<int> Ids) {} + + /// Callback invoked when a \#pragma warning(push) directive is read. + virtual void PragmaWarningPush(SourceLocation Loc, int Level) { + } + + /// Callback invoked when a \#pragma warning(pop) directive is read. + virtual void PragmaWarningPop(SourceLocation Loc) { + } + + /// Callback invoked when a \#pragma execution_character_set(push) directive + /// is read. + virtual void PragmaExecCharsetPush(SourceLocation Loc, StringRef Str) {} + + /// Callback invoked when a \#pragma execution_character_set(pop) directive + /// is read. + virtual void PragmaExecCharsetPop(SourceLocation Loc) {} + + /// Callback invoked when a \#pragma clang assume_nonnull begin directive + /// is read. + virtual void PragmaAssumeNonNullBegin(SourceLocation Loc) {} + + /// Callback invoked when a \#pragma clang assume_nonnull end directive + /// is read. + virtual void PragmaAssumeNonNullEnd(SourceLocation Loc) {} + + /// Called by Preprocessor::HandleMacroExpandedIdentifier when a + /// macro invocation is found. + virtual void MacroExpands(const Token &MacroNameTok, + const MacroDefinition &MD, SourceRange Range, + const MacroArgs *Args) {} + + /// Hook called whenever a macro definition is seen. + virtual void MacroDefined(const Token &MacroNameTok, + const MacroDirective *MD) { + } + + /// Hook called whenever a macro \#undef is seen. + /// \param MacroNameTok The active Token + /// \param MD A MacroDefinition for the named macro. + /// \param Undef New MacroDirective if the macro was defined, null otherwise. + /// + /// MD is released immediately following this callback. + virtual void MacroUndefined(const Token &MacroNameTok, + const MacroDefinition &MD, + const MacroDirective *Undef) { + } + + /// Hook called whenever the 'defined' operator is seen. + /// \param MD The MacroDirective if the name was a macro, null otherwise. + virtual void Defined(const Token &MacroNameTok, const MacroDefinition &MD, + SourceRange Range) { + } + + /// Hook called when a '__has_include' or '__has_include_next' directive is + /// read. + virtual void HasInclude(SourceLocation Loc, StringRef FileName, bool IsAngled, + OptionalFileEntryRef File, + SrcMgr::CharacteristicKind FileType); + + /// Hook called when a source range is skipped. + /// \param Range The SourceRange that was skipped. The range begins at the + /// \#if/\#else directive and ends after the \#endif/\#else directive. + /// \param EndifLoc The end location of the 'endif' token, which may precede + /// the range skipped by the directive (e.g excluding comments after an + /// 'endif'). + virtual void SourceRangeSkipped(SourceRange Range, SourceLocation EndifLoc) { + } + + enum ConditionValueKind { + CVK_NotEvaluated, CVK_False, CVK_True + }; + + /// Hook called whenever an \#if is seen. + /// \param Loc the source location of the directive. + /// \param ConditionRange The SourceRange of the expression being tested. + /// \param ConditionValue The evaluated value of the condition. + /// + // FIXME: better to pass in a list (or tree!) of Tokens. + virtual void If(SourceLocation Loc, SourceRange ConditionRange, + ConditionValueKind ConditionValue) { + } + + /// Hook called whenever an \#elif is seen. + /// \param Loc the source location of the directive. + /// \param ConditionRange The SourceRange of the expression being tested. + /// \param ConditionValue The evaluated value of the condition. + /// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive. + // FIXME: better to pass in a list (or tree!) of Tokens. + virtual void Elif(SourceLocation Loc, SourceRange ConditionRange, + ConditionValueKind ConditionValue, SourceLocation IfLoc) { + } + + /// Hook called whenever an \#ifdef is seen. + /// \param Loc the source location of the directive. + /// \param MacroNameTok Information on the token being tested. + /// \param MD The MacroDefinition if the name was a macro, null otherwise. + virtual void Ifdef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) { + } + + /// Hook called whenever an \#elifdef branch is taken. + /// \param Loc the source location of the directive. + /// \param MacroNameTok Information on the token being tested. + /// \param MD The MacroDefinition if the name was a macro, null otherwise. + virtual void Elifdef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) { + } + /// Hook called whenever an \#elifdef is skipped. + /// \param Loc the source location of the directive. + /// \param ConditionRange The SourceRange of the expression being tested. + /// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive. + // FIXME: better to pass in a list (or tree!) of Tokens. + virtual void Elifdef(SourceLocation Loc, SourceRange ConditionRange, + SourceLocation IfLoc) { + } + + /// Hook called whenever an \#ifndef is seen. + /// \param Loc the source location of the directive. + /// \param MacroNameTok Information on the token being tested. + /// \param MD The MacroDefiniton if the name was a macro, null otherwise. + virtual void Ifndef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) { + } + + /// Hook called whenever an \#elifndef branch is taken. + /// \param Loc the source location of the directive. + /// \param MacroNameTok Information on the token being tested. + /// \param MD The MacroDefinition if the name was a macro, null otherwise. + virtual void Elifndef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) { + } + /// Hook called whenever an \#elifndef is skipped. + /// \param Loc the source location of the directive. + /// \param ConditionRange The SourceRange of the expression being tested. + /// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive. + // FIXME: better to pass in a list (or tree!) of Tokens. + virtual void Elifndef(SourceLocation Loc, SourceRange ConditionRange, + SourceLocation IfLoc) { + } + + /// Hook called whenever an \#else is seen. + /// \param Loc the source location of the directive. + /// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive. + virtual void Else(SourceLocation Loc, SourceLocation IfLoc) { + } + + /// Hook called whenever an \#endif is seen. + /// \param Loc the source location of the directive. + /// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive. + virtual void Endif(SourceLocation Loc, SourceLocation IfLoc) { + } +}; + +/// Simple wrapper class for chaining callbacks. +class PPChainedCallbacks : public PPCallbacks { + std::unique_ptr<PPCallbacks> First, Second; + +public: + PPChainedCallbacks(std::unique_ptr<PPCallbacks> _First, + std::unique_ptr<PPCallbacks> _Second) + : First(std::move(_First)), Second(std::move(_Second)) {} + + ~PPChainedCallbacks() override; + + void FileChanged(SourceLocation Loc, FileChangeReason Reason, + SrcMgr::CharacteristicKind FileType, + FileID PrevFID) override { + First->FileChanged(Loc, Reason, FileType, PrevFID); + Second->FileChanged(Loc, Reason, FileType, PrevFID); + } + + void LexedFileChanged(FileID FID, LexedFileChangeReason Reason, + SrcMgr::CharacteristicKind FileType, FileID PrevFID, + SourceLocation Loc) override { + First->LexedFileChanged(FID, Reason, FileType, PrevFID, Loc); + Second->LexedFileChanged(FID, Reason, FileType, PrevFID, Loc); + } + + void FileSkipped(const FileEntryRef &SkippedFile, const Token &FilenameTok, + SrcMgr::CharacteristicKind FileType) override { + First->FileSkipped(SkippedFile, FilenameTok, FileType); + Second->FileSkipped(SkippedFile, FilenameTok, FileType); + } + + bool FileNotFound(StringRef FileName) override { + bool Skip = First->FileNotFound(FileName); + // Make sure to invoke the second callback, no matter if the first already + // returned true to skip the file. + Skip |= Second->FileNotFound(FileName); + return Skip; + } + + void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, + StringRef FileName, bool IsAngled, + CharSourceRange FilenameRange, + OptionalFileEntryRef File, StringRef SearchPath, + StringRef RelativePath, const Module *Imported, + SrcMgr::CharacteristicKind FileType) override { + First->InclusionDirective(HashLoc, IncludeTok, FileName, IsAngled, + FilenameRange, File, SearchPath, RelativePath, + Imported, FileType); + Second->InclusionDirective(HashLoc, IncludeTok, FileName, IsAngled, + FilenameRange, File, SearchPath, RelativePath, + Imported, FileType); + } + + void EnteredSubmodule(Module *M, SourceLocation ImportLoc, + bool ForPragma) override { + First->EnteredSubmodule(M, ImportLoc, ForPragma); + Second->EnteredSubmodule(M, ImportLoc, ForPragma); + } + + void LeftSubmodule(Module *M, SourceLocation ImportLoc, + bool ForPragma) override { + First->LeftSubmodule(M, ImportLoc, ForPragma); + Second->LeftSubmodule(M, ImportLoc, ForPragma); + } + + void moduleImport(SourceLocation ImportLoc, ModuleIdPath Path, + const Module *Imported) override { + First->moduleImport(ImportLoc, Path, Imported); + Second->moduleImport(ImportLoc, Path, Imported); + } + + void EndOfMainFile() override { + First->EndOfMainFile(); + Second->EndOfMainFile(); + } + + void Ident(SourceLocation Loc, StringRef str) override { + First->Ident(Loc, str); + Second->Ident(Loc, str); + } + + void PragmaDirective(SourceLocation Loc, + PragmaIntroducerKind Introducer) override { + First->PragmaDirective(Loc, Introducer); + Second->PragmaDirective(Loc, Introducer); + } + + void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind, + StringRef Str) override { + First->PragmaComment(Loc, Kind, Str); + Second->PragmaComment(Loc, Kind, Str); + } + + void PragmaMark(SourceLocation Loc, StringRef Trivia) override { + First->PragmaMark(Loc, Trivia); + Second->PragmaMark(Loc, Trivia); + } + + void PragmaDetectMismatch(SourceLocation Loc, StringRef Name, + StringRef Value) override { + First->PragmaDetectMismatch(Loc, Name, Value); + Second->PragmaDetectMismatch(Loc, Name, Value); + } + + void PragmaDebug(SourceLocation Loc, StringRef DebugType) override { + First->PragmaDebug(Loc, DebugType); + Second->PragmaDebug(Loc, DebugType); + } + + void PragmaMessage(SourceLocation Loc, StringRef Namespace, + PragmaMessageKind Kind, StringRef Str) override { + First->PragmaMessage(Loc, Namespace, Kind, Str); + Second->PragmaMessage(Loc, Namespace, Kind, Str); + } + + void PragmaDiagnosticPush(SourceLocation Loc, StringRef Namespace) override { + First->PragmaDiagnosticPush(Loc, Namespace); + Second->PragmaDiagnosticPush(Loc, Namespace); + } + + void PragmaDiagnosticPop(SourceLocation Loc, StringRef Namespace) override { + First->PragmaDiagnosticPop(Loc, Namespace); + Second->PragmaDiagnosticPop(Loc, Namespace); + } + + void PragmaDiagnostic(SourceLocation Loc, StringRef Namespace, + diag::Severity mapping, StringRef Str) override { + First->PragmaDiagnostic(Loc, Namespace, mapping, Str); + Second->PragmaDiagnostic(Loc, Namespace, mapping, Str); + } + + void HasInclude(SourceLocation Loc, StringRef FileName, bool IsAngled, + OptionalFileEntryRef File, + SrcMgr::CharacteristicKind FileType) override; + + void PragmaOpenCLExtension(SourceLocation NameLoc, const IdentifierInfo *Name, + SourceLocation StateLoc, unsigned State) override { + First->PragmaOpenCLExtension(NameLoc, Name, StateLoc, State); + Second->PragmaOpenCLExtension(NameLoc, Name, StateLoc, State); + } + + void PragmaWarning(SourceLocation Loc, PragmaWarningSpecifier WarningSpec, + ArrayRef<int> Ids) override { + First->PragmaWarning(Loc, WarningSpec, Ids); + Second->PragmaWarning(Loc, WarningSpec, Ids); + } + + void PragmaWarningPush(SourceLocation Loc, int Level) override { + First->PragmaWarningPush(Loc, Level); + Second->PragmaWarningPush(Loc, Level); + } + + void PragmaWarningPop(SourceLocation Loc) override { + First->PragmaWarningPop(Loc); + Second->PragmaWarningPop(Loc); + } + + void PragmaExecCharsetPush(SourceLocation Loc, StringRef Str) override { + First->PragmaExecCharsetPush(Loc, Str); + Second->PragmaExecCharsetPush(Loc, Str); + } + + void PragmaExecCharsetPop(SourceLocation Loc) override { + First->PragmaExecCharsetPop(Loc); + Second->PragmaExecCharsetPop(Loc); + } + + void PragmaAssumeNonNullBegin(SourceLocation Loc) override { + First->PragmaAssumeNonNullBegin(Loc); + Second->PragmaAssumeNonNullBegin(Loc); + } + + void PragmaAssumeNonNullEnd(SourceLocation Loc) override { + First->PragmaAssumeNonNullEnd(Loc); + Second->PragmaAssumeNonNullEnd(Loc); + } + + void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD, + SourceRange Range, const MacroArgs *Args) override { + First->MacroExpands(MacroNameTok, MD, Range, Args); + Second->MacroExpands(MacroNameTok, MD, Range, Args); + } + + void MacroDefined(const Token &MacroNameTok, + const MacroDirective *MD) override { + First->MacroDefined(MacroNameTok, MD); + Second->MacroDefined(MacroNameTok, MD); + } + + void MacroUndefined(const Token &MacroNameTok, + const MacroDefinition &MD, + const MacroDirective *Undef) override { + First->MacroUndefined(MacroNameTok, MD, Undef); + Second->MacroUndefined(MacroNameTok, MD, Undef); + } + + void Defined(const Token &MacroNameTok, const MacroDefinition &MD, + SourceRange Range) override { + First->Defined(MacroNameTok, MD, Range); + Second->Defined(MacroNameTok, MD, Range); + } + + void SourceRangeSkipped(SourceRange Range, SourceLocation EndifLoc) override { + First->SourceRangeSkipped(Range, EndifLoc); + Second->SourceRangeSkipped(Range, EndifLoc); + } + + /// Hook called whenever an \#if is seen. + void If(SourceLocation Loc, SourceRange ConditionRange, + ConditionValueKind ConditionValue) override { + First->If(Loc, ConditionRange, ConditionValue); + Second->If(Loc, ConditionRange, ConditionValue); + } + + /// Hook called whenever an \#elif is seen. + void Elif(SourceLocation Loc, SourceRange ConditionRange, + ConditionValueKind ConditionValue, SourceLocation IfLoc) override { + First->Elif(Loc, ConditionRange, ConditionValue, IfLoc); + Second->Elif(Loc, ConditionRange, ConditionValue, IfLoc); + } + + /// Hook called whenever an \#ifdef is seen. + void Ifdef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) override { + First->Ifdef(Loc, MacroNameTok, MD); + Second->Ifdef(Loc, MacroNameTok, MD); + } + + /// Hook called whenever an \#elifdef is taken. + void Elifdef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) override { + First->Elifdef(Loc, MacroNameTok, MD); + Second->Elifdef(Loc, MacroNameTok, MD); + } + /// Hook called whenever an \#elifdef is skipped. + void Elifdef(SourceLocation Loc, SourceRange ConditionRange, + SourceLocation IfLoc) override { + First->Elifdef(Loc, ConditionRange, IfLoc); + Second->Elifdef(Loc, ConditionRange, IfLoc); + } + + /// Hook called whenever an \#ifndef is seen. + void Ifndef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) override { + First->Ifndef(Loc, MacroNameTok, MD); + Second->Ifndef(Loc, MacroNameTok, MD); + } + + /// Hook called whenever an \#elifndef is taken. + void Elifndef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) override { + First->Elifndef(Loc, MacroNameTok, MD); + Second->Elifndef(Loc, MacroNameTok, MD); + } + /// Hook called whenever an \#elifndef is skipped. + void Elifndef(SourceLocation Loc, SourceRange ConditionRange, + SourceLocation IfLoc) override { + First->Elifndef(Loc, ConditionRange, IfLoc); + Second->Elifndef(Loc, ConditionRange, IfLoc); + } + + /// Hook called whenever an \#else is seen. + void Else(SourceLocation Loc, SourceLocation IfLoc) override { + First->Else(Loc, IfLoc); + Second->Else(Loc, IfLoc); + } + + /// Hook called whenever an \#endif is seen. + void Endif(SourceLocation Loc, SourceLocation IfLoc) override { + First->Endif(Loc, IfLoc); + Second->Endif(Loc, IfLoc); + } +}; + +} // end namespace clang + +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Lex/PPConditionalDirectiveRecord.h b/contrib/libs/clang16/include/clang/Lex/PPConditionalDirectiveRecord.h new file mode 100644 index 0000000000..b5d06776e4 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Lex/PPConditionalDirectiveRecord.h @@ -0,0 +1,121 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===--- PPConditionalDirectiveRecord.h - Preprocessing Directives-*- C++ -*-=// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the PPConditionalDirectiveRecord class, which maintains +// a record of conditional directive regions. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_LEX_PPCONDITIONALDIRECTIVERECORD_H +#define LLVM_CLANG_LEX_PPCONDITIONALDIRECTIVERECORD_H + +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/PPCallbacks.h" +#include "llvm/ADT/SmallVector.h" +#include <vector> + +namespace clang { + +/// Records preprocessor conditional directive regions and allows +/// querying in which region source locations belong to. +class PPConditionalDirectiveRecord : public PPCallbacks { + SourceManager &SourceMgr; + + SmallVector<SourceLocation, 6> CondDirectiveStack; + + class CondDirectiveLoc { + SourceLocation Loc; + SourceLocation RegionLoc; + + public: + CondDirectiveLoc(SourceLocation Loc, SourceLocation RegionLoc) + : Loc(Loc), RegionLoc(RegionLoc) {} + + SourceLocation getLoc() const { return Loc; } + SourceLocation getRegionLoc() const { return RegionLoc; } + + class Comp { + SourceManager &SM; + public: + explicit Comp(SourceManager &SM) : SM(SM) {} + bool operator()(const CondDirectiveLoc &LHS, + const CondDirectiveLoc &RHS) { + return SM.isBeforeInTranslationUnit(LHS.getLoc(), RHS.getLoc()); + } + bool operator()(const CondDirectiveLoc &LHS, SourceLocation RHS) { + return SM.isBeforeInTranslationUnit(LHS.getLoc(), RHS); + } + bool operator()(SourceLocation LHS, const CondDirectiveLoc &RHS) { + return SM.isBeforeInTranslationUnit(LHS, RHS.getLoc()); + } + }; + }; + + typedef std::vector<CondDirectiveLoc> CondDirectiveLocsTy; + /// The locations of conditional directives in source order. + CondDirectiveLocsTy CondDirectiveLocs; + + void addCondDirectiveLoc(CondDirectiveLoc DirLoc); + +public: + /// Construct a new preprocessing record. + explicit PPConditionalDirectiveRecord(SourceManager &SM); + + size_t getTotalMemory() const; + + SourceManager &getSourceManager() const { return SourceMgr; } + + /// Returns true if the given range intersects with a conditional + /// directive. if a \#if/\#endif block is fully contained within the range, + /// this function will return false. + bool rangeIntersectsConditionalDirective(SourceRange Range) const; + + /// Returns true if the given locations are in different regions, + /// separated by conditional directive blocks. + bool areInDifferentConditionalDirectiveRegion(SourceLocation LHS, + SourceLocation RHS) const { + return findConditionalDirectiveRegionLoc(LHS) != + findConditionalDirectiveRegionLoc(RHS); + } + + SourceLocation findConditionalDirectiveRegionLoc(SourceLocation Loc) const; + +private: + void If(SourceLocation Loc, SourceRange ConditionRange, + ConditionValueKind ConditionValue) override; + void Elif(SourceLocation Loc, SourceRange ConditionRange, + ConditionValueKind ConditionValue, SourceLocation IfLoc) override; + void Ifdef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) override; + void Ifndef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) override; + void Elifdef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) override; + void Elifdef(SourceLocation Loc, SourceRange ConditionRange, + SourceLocation IfLoc) override; + void Elifndef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) override; + void Elifndef(SourceLocation Loc, SourceRange ConditionRange, + SourceLocation IfLoc) override; + void Else(SourceLocation Loc, SourceLocation IfLoc) override; + void Endif(SourceLocation Loc, SourceLocation IfLoc) override; +}; + +} // end namespace clang + +#endif // LLVM_CLANG_LEX_PPCONDITIONALDIRECTIVERECORD_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Lex/Pragma.h b/contrib/libs/clang16/include/clang/Lex/Pragma.h new file mode 100644 index 0000000000..2bbf3eb332 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Lex/Pragma.h @@ -0,0 +1,139 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- Pragma.h - Pragma registration and handling --------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the PragmaHandler and PragmaTable interfaces. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_PRAGMA_H +#define LLVM_CLANG_LEX_PRAGMA_H + +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include <string> + +namespace clang { + +class PragmaNamespace; +class Preprocessor; +class Token; + + /** + * Describes how the pragma was introduced, e.g., with \#pragma, + * _Pragma, or __pragma. + */ + enum PragmaIntroducerKind { + /** + * The pragma was introduced via \#pragma. + */ + PIK_HashPragma, + + /** + * The pragma was introduced via the C99 _Pragma(string-literal). + */ + PIK__Pragma, + + /** + * The pragma was introduced via the Microsoft + * __pragma(token-string). + */ + PIK___pragma + }; + + /// Describes how and where the pragma was introduced. + struct PragmaIntroducer { + PragmaIntroducerKind Kind; + SourceLocation Loc; + }; + +/// PragmaHandler - Instances of this interface defined to handle the various +/// pragmas that the language front-end uses. Each handler optionally has a +/// name (e.g. "pack") and the HandlePragma method is invoked when a pragma with +/// that identifier is found. If a handler does not match any of the declared +/// pragmas the handler with a null identifier is invoked, if it exists. +/// +/// Note that the PragmaNamespace class can be used to subdivide pragmas, e.g. +/// we treat "\#pragma STDC" and "\#pragma GCC" as namespaces that contain other +/// pragmas. +class PragmaHandler { + std::string Name; + +public: + PragmaHandler() = default; + explicit PragmaHandler(StringRef name) : Name(name) {} + virtual ~PragmaHandler(); + + StringRef getName() const { return Name; } + virtual void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, + Token &FirstToken) = 0; + + /// getIfNamespace - If this is a namespace, return it. This is equivalent to + /// using a dynamic_cast, but doesn't require RTTI. + virtual PragmaNamespace *getIfNamespace() { return nullptr; } +}; + +/// EmptyPragmaHandler - A pragma handler which takes no action, which can be +/// used to ignore particular pragmas. +class EmptyPragmaHandler : public PragmaHandler { +public: + explicit EmptyPragmaHandler(StringRef Name = StringRef()); + + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, + Token &FirstToken) override; +}; + +/// PragmaNamespace - This PragmaHandler subdivides the namespace of pragmas, +/// allowing hierarchical pragmas to be defined. Common examples of namespaces +/// are "\#pragma GCC", "\#pragma STDC", and "\#pragma omp", but any namespaces +/// may be (potentially recursively) defined. +class PragmaNamespace : public PragmaHandler { + /// Handlers - This is a map of the handlers in this namespace with their name + /// as key. + llvm::StringMap<std::unique_ptr<PragmaHandler>> Handlers; + +public: + explicit PragmaNamespace(StringRef Name) : PragmaHandler(Name) {} + + /// FindHandler - Check to see if there is already a handler for the + /// specified name. If not, return the handler for the null name if it + /// exists, otherwise return null. If IgnoreNull is true (the default) then + /// the null handler isn't returned on failure to match. + PragmaHandler *FindHandler(StringRef Name, + bool IgnoreNull = true) const; + + /// AddPragma - Add a pragma to this namespace. + void AddPragma(PragmaHandler *Handler); + + /// RemovePragmaHandler - Remove the given handler from the + /// namespace. + void RemovePragmaHandler(PragmaHandler *Handler); + + bool IsEmpty() const { return Handlers.empty(); } + + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, + Token &Tok) override; + + PragmaNamespace *getIfNamespace() override { return this; } +}; + +} // namespace clang + +#endif // LLVM_CLANG_LEX_PRAGMA_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Lex/PreprocessingRecord.h b/contrib/libs/clang16/include/clang/Lex/PreprocessingRecord.h new file mode 100644 index 0000000000..263057ad9c --- /dev/null +++ b/contrib/libs/clang16/include/clang/Lex/PreprocessingRecord.h @@ -0,0 +1,589 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- PreprocessingRecord.h - Record of Preprocessing ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the PreprocessingRecord class, which maintains a record +// of what occurred during preprocessing. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_PREPROCESSINGRECORD_H +#define LLVM_CLANG_LEX_PREPROCESSINGRECORD_H + +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/PPCallbacks.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/iterator.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Compiler.h" +#include <cassert> +#include <cstddef> +#include <iterator> +#include <optional> +#include <utility> +#include <vector> + +namespace clang { + +class PreprocessingRecord; + +} // namespace clang + +/// Allocates memory within a Clang preprocessing record. +void *operator new(size_t bytes, clang::PreprocessingRecord &PR, + unsigned alignment = 8) noexcept; + +/// Frees memory allocated in a Clang preprocessing record. +void operator delete(void *ptr, clang::PreprocessingRecord &PR, + unsigned) noexcept; + +namespace clang { + +class IdentifierInfo; +class MacroInfo; +class SourceManager; +class Token; + + /// Base class that describes a preprocessed entity, which may be a + /// preprocessor directive or macro expansion. + class PreprocessedEntity { + public: + /// The kind of preprocessed entity an object describes. + enum EntityKind { + /// Indicates a problem trying to load the preprocessed entity. + InvalidKind, + + /// A macro expansion. + MacroExpansionKind, + + /// \defgroup Preprocessing directives + /// @{ + + /// A macro definition. + MacroDefinitionKind, + + /// An inclusion directive, such as \c \#include, \c + /// \#import, or \c \#include_next. + InclusionDirectiveKind, + + /// @} + + FirstPreprocessingDirective = MacroDefinitionKind, + LastPreprocessingDirective = InclusionDirectiveKind + }; + + private: + /// The kind of preprocessed entity that this object describes. + EntityKind Kind; + + /// The source range that covers this preprocessed entity. + SourceRange Range; + + protected: + friend class PreprocessingRecord; + + PreprocessedEntity(EntityKind Kind, SourceRange Range) + : Kind(Kind), Range(Range) {} + + public: + /// Retrieve the kind of preprocessed entity stored in this object. + EntityKind getKind() const { return Kind; } + + /// Retrieve the source range that covers this entire preprocessed + /// entity. + SourceRange getSourceRange() const LLVM_READONLY { return Range; } + + /// Returns true if there was a problem loading the preprocessed + /// entity. + bool isInvalid() const { return Kind == InvalidKind; } + + // Only allow allocation of preprocessed entities using the allocator + // in PreprocessingRecord or by doing a placement new. + void *operator new(size_t bytes, PreprocessingRecord &PR, + unsigned alignment = 8) noexcept { + return ::operator new(bytes, PR, alignment); + } + + void *operator new(size_t bytes, void *mem) noexcept { return mem; } + + void operator delete(void *ptr, PreprocessingRecord &PR, + unsigned alignment) noexcept { + return ::operator delete(ptr, PR, alignment); + } + + void operator delete(void *, std::size_t) noexcept {} + void operator delete(void *, void *) noexcept {} + + private: + // Make vanilla 'new' and 'delete' illegal for preprocessed entities. + void *operator new(size_t bytes) noexcept; + void operator delete(void *data) noexcept; + }; + + /// Records the presence of a preprocessor directive. + class PreprocessingDirective : public PreprocessedEntity { + public: + PreprocessingDirective(EntityKind Kind, SourceRange Range) + : PreprocessedEntity(Kind, Range) {} + + // Implement isa/cast/dyncast/etc. + static bool classof(const PreprocessedEntity *PD) { + return PD->getKind() >= FirstPreprocessingDirective && + PD->getKind() <= LastPreprocessingDirective; + } + }; + + /// Record the location of a macro definition. + class MacroDefinitionRecord : public PreprocessingDirective { + /// The name of the macro being defined. + const IdentifierInfo *Name; + + public: + explicit MacroDefinitionRecord(const IdentifierInfo *Name, + SourceRange Range) + : PreprocessingDirective(MacroDefinitionKind, Range), Name(Name) {} + + /// Retrieve the name of the macro being defined. + const IdentifierInfo *getName() const { return Name; } + + /// Retrieve the location of the macro name in the definition. + SourceLocation getLocation() const { return getSourceRange().getBegin(); } + + // Implement isa/cast/dyncast/etc. + static bool classof(const PreprocessedEntity *PE) { + return PE->getKind() == MacroDefinitionKind; + } + }; + + /// Records the location of a macro expansion. + class MacroExpansion : public PreprocessedEntity { + /// The definition of this macro or the name of the macro if it is + /// a builtin macro. + llvm::PointerUnion<IdentifierInfo *, MacroDefinitionRecord *> NameOrDef; + + public: + MacroExpansion(IdentifierInfo *BuiltinName, SourceRange Range) + : PreprocessedEntity(MacroExpansionKind, Range), + NameOrDef(BuiltinName) {} + + MacroExpansion(MacroDefinitionRecord *Definition, SourceRange Range) + : PreprocessedEntity(MacroExpansionKind, Range), NameOrDef(Definition) { + } + + /// True if it is a builtin macro. + bool isBuiltinMacro() const { return NameOrDef.is<IdentifierInfo *>(); } + + /// The name of the macro being expanded. + const IdentifierInfo *getName() const { + if (MacroDefinitionRecord *Def = getDefinition()) + return Def->getName(); + return NameOrDef.get<IdentifierInfo *>(); + } + + /// The definition of the macro being expanded. May return null if + /// this is a builtin macro. + MacroDefinitionRecord *getDefinition() const { + return NameOrDef.dyn_cast<MacroDefinitionRecord *>(); + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const PreprocessedEntity *PE) { + return PE->getKind() == MacroExpansionKind; + } + }; + + /// Record the location of an inclusion directive, such as an + /// \c \#include or \c \#import statement. + class InclusionDirective : public PreprocessingDirective { + public: + /// The kind of inclusion directives known to the + /// preprocessor. + enum InclusionKind { + /// An \c \#include directive. + Include, + + /// An Objective-C \c \#import directive. + Import, + + /// A GNU \c \#include_next directive. + IncludeNext, + + /// A Clang \c \#__include_macros directive. + IncludeMacros + }; + + private: + /// The name of the file that was included, as written in + /// the source. + StringRef FileName; + + /// Whether the file name was in quotation marks; otherwise, it was + /// in angle brackets. + unsigned InQuotes : 1; + + /// The kind of inclusion directive we have. + /// + /// This is a value of type InclusionKind. + unsigned Kind : 2; + + /// Whether the inclusion directive was automatically turned into + /// a module import. + unsigned ImportedModule : 1; + + /// The file that was included. + OptionalFileEntryRef File; + + public: + InclusionDirective(PreprocessingRecord &PPRec, InclusionKind Kind, + StringRef FileName, bool InQuotes, bool ImportedModule, + OptionalFileEntryRef File, SourceRange Range); + + /// Determine what kind of inclusion directive this is. + InclusionKind getKind() const { return static_cast<InclusionKind>(Kind); } + + /// Retrieve the included file name as it was written in the source. + StringRef getFileName() const { return FileName; } + + /// Determine whether the included file name was written in quotes; + /// otherwise, it was written in angle brackets. + bool wasInQuotes() const { return InQuotes; } + + /// Determine whether the inclusion directive was automatically + /// turned into a module import. + bool importedModule() const { return ImportedModule; } + + /// Retrieve the file entry for the actual file that was included + /// by this directive. + OptionalFileEntryRef getFile() const { return File; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const PreprocessedEntity *PE) { + return PE->getKind() == InclusionDirectiveKind; + } + }; + + /// An abstract class that should be subclassed by any external source + /// of preprocessing record entries. + class ExternalPreprocessingRecordSource { + public: + virtual ~ExternalPreprocessingRecordSource(); + + /// Read a preallocated preprocessed entity from the external source. + /// + /// \returns null if an error occurred that prevented the preprocessed + /// entity from being loaded. + virtual PreprocessedEntity *ReadPreprocessedEntity(unsigned Index) = 0; + + /// Returns a pair of [Begin, End) indices of preallocated + /// preprocessed entities that \p Range encompasses. + virtual std::pair<unsigned, unsigned> + findPreprocessedEntitiesInRange(SourceRange Range) = 0; + + /// Optionally returns true or false if the preallocated preprocessed + /// entity with index \p Index came from file \p FID. + virtual std::optional<bool> isPreprocessedEntityInFileID(unsigned Index, + FileID FID) { + return std::nullopt; + } + + /// Read a preallocated skipped range from the external source. + virtual SourceRange ReadSkippedRange(unsigned Index) = 0; + }; + + /// A record of the steps taken while preprocessing a source file, + /// including the various preprocessing directives processed, macros + /// expanded, etc. + class PreprocessingRecord : public PPCallbacks { + SourceManager &SourceMgr; + + /// Allocator used to store preprocessing objects. + llvm::BumpPtrAllocator BumpAlloc; + + /// The set of preprocessed entities in this record, in order they + /// were seen. + std::vector<PreprocessedEntity *> PreprocessedEntities; + + /// The set of preprocessed entities in this record that have been + /// loaded from external sources. + /// + /// The entries in this vector are loaded lazily from the external source, + /// and are referenced by the iterator using negative indices. + std::vector<PreprocessedEntity *> LoadedPreprocessedEntities; + + /// The set of ranges that were skipped by the preprocessor, + std::vector<SourceRange> SkippedRanges; + + bool SkippedRangesAllLoaded = true; + + /// Global (loaded or local) ID for a preprocessed entity. + /// Negative values are used to indicate preprocessed entities + /// loaded from the external source while non-negative values are used to + /// indicate preprocessed entities introduced by the current preprocessor. + /// Value -1 corresponds to element 0 in the loaded entities vector, + /// value -2 corresponds to element 1 in the loaded entities vector, etc. + /// Value 0 is an invalid value, the index to local entities is 1-based, + /// value 1 corresponds to element 0 in the local entities vector, + /// value 2 corresponds to element 1 in the local entities vector, etc. + class PPEntityID { + friend class PreprocessingRecord; + + int ID = 0; + + explicit PPEntityID(int ID) : ID(ID) {} + + public: + PPEntityID() = default; + }; + + static PPEntityID getPPEntityID(unsigned Index, bool isLoaded) { + return isLoaded ? PPEntityID(-int(Index)-1) : PPEntityID(Index+1); + } + + /// Mapping from MacroInfo structures to their definitions. + llvm::DenseMap<const MacroInfo *, MacroDefinitionRecord *> MacroDefinitions; + + /// External source of preprocessed entities. + ExternalPreprocessingRecordSource *ExternalSource = nullptr; + + /// Retrieve the preprocessed entity at the given ID. + PreprocessedEntity *getPreprocessedEntity(PPEntityID PPID); + + /// Retrieve the loaded preprocessed entity at the given index. + PreprocessedEntity *getLoadedPreprocessedEntity(unsigned Index); + + /// Determine the number of preprocessed entities that were + /// loaded (or can be loaded) from an external source. + unsigned getNumLoadedPreprocessedEntities() const { + return LoadedPreprocessedEntities.size(); + } + + /// Returns a pair of [Begin, End) indices of local preprocessed + /// entities that \p Range encompasses. + std::pair<unsigned, unsigned> + findLocalPreprocessedEntitiesInRange(SourceRange Range) const; + unsigned findBeginLocalPreprocessedEntity(SourceLocation Loc) const; + unsigned findEndLocalPreprocessedEntity(SourceLocation Loc) const; + + /// Allocate space for a new set of loaded preprocessed entities. + /// + /// \returns The index into the set of loaded preprocessed entities, which + /// corresponds to the first newly-allocated entity. + unsigned allocateLoadedEntities(unsigned NumEntities); + + /// Allocate space for a new set of loaded preprocessed skipped + /// ranges. + /// + /// \returns The index into the set of loaded preprocessed ranges, which + /// corresponds to the first newly-allocated range. + unsigned allocateSkippedRanges(unsigned NumRanges); + + /// Ensures that all external skipped ranges have been loaded. + void ensureSkippedRangesLoaded(); + + /// Register a new macro definition. + void RegisterMacroDefinition(MacroInfo *Macro, MacroDefinitionRecord *Def); + + public: + /// Construct a new preprocessing record. + explicit PreprocessingRecord(SourceManager &SM); + + /// Allocate memory in the preprocessing record. + void *Allocate(unsigned Size, unsigned Align = 8) { + return BumpAlloc.Allocate(Size, Align); + } + + /// Deallocate memory in the preprocessing record. + void Deallocate(void *Ptr) {} + + size_t getTotalMemory() const; + + SourceManager &getSourceManager() const { return SourceMgr; } + + /// Iteration over the preprocessed entities. + /// + /// In a complete iteration, the iterator walks the range [-M, N), + /// where negative values are used to indicate preprocessed entities + /// loaded from the external source while non-negative values are used to + /// indicate preprocessed entities introduced by the current preprocessor. + /// However, to provide iteration in source order (for, e.g., chained + /// precompiled headers), dereferencing the iterator flips the negative + /// values (corresponding to loaded entities), so that position -M + /// corresponds to element 0 in the loaded entities vector, position -M+1 + /// corresponds to element 1 in the loaded entities vector, etc. This + /// gives us a reasonably efficient, source-order walk. + /// + /// We define this as a wrapping iterator around an int. The + /// iterator_adaptor_base class forwards the iterator methods to basic + /// integer arithmetic. + class iterator : public llvm::iterator_adaptor_base< + iterator, int, std::random_access_iterator_tag, + PreprocessedEntity *, int, PreprocessedEntity *, + PreprocessedEntity *> { + friend class PreprocessingRecord; + + PreprocessingRecord *Self; + + iterator(PreprocessingRecord *Self, int Position) + : iterator::iterator_adaptor_base(Position), Self(Self) {} + + public: + iterator() : iterator(nullptr, 0) {} + + PreprocessedEntity *operator*() const { + bool isLoaded = this->I < 0; + unsigned Index = isLoaded ? + Self->LoadedPreprocessedEntities.size() + this->I : this->I; + PPEntityID ID = Self->getPPEntityID(Index, isLoaded); + return Self->getPreprocessedEntity(ID); + } + PreprocessedEntity *operator->() const { return **this; } + }; + + /// Begin iterator for all preprocessed entities. + iterator begin() { + return iterator(this, -(int)LoadedPreprocessedEntities.size()); + } + + /// End iterator for all preprocessed entities. + iterator end() { + return iterator(this, PreprocessedEntities.size()); + } + + /// Begin iterator for local, non-loaded, preprocessed entities. + iterator local_begin() { + return iterator(this, 0); + } + + /// End iterator for local, non-loaded, preprocessed entities. + iterator local_end() { + return iterator(this, PreprocessedEntities.size()); + } + + /// iterator range for the given range of loaded + /// preprocessed entities. + llvm::iterator_range<iterator> getIteratorsForLoadedRange(unsigned start, + unsigned count) { + unsigned end = start + count; + assert(end <= LoadedPreprocessedEntities.size()); + return llvm::make_range( + iterator(this, int(start) - LoadedPreprocessedEntities.size()), + iterator(this, int(end) - LoadedPreprocessedEntities.size())); + } + + /// Returns a range of preprocessed entities that source range \p R + /// encompasses. + /// + /// \param R the range to look for preprocessed entities. + llvm::iterator_range<iterator> + getPreprocessedEntitiesInRange(SourceRange R); + + /// Returns true if the preprocessed entity that \p PPEI iterator + /// points to is coming from the file \p FID. + /// + /// Can be used to avoid implicit deserializations of preallocated + /// preprocessed entities if we only care about entities of a specific file + /// and not from files \#included in the range given at + /// \see getPreprocessedEntitiesInRange. + bool isEntityInFileID(iterator PPEI, FileID FID); + + /// Add a new preprocessed entity to this record. + PPEntityID addPreprocessedEntity(PreprocessedEntity *Entity); + + /// Set the external source for preprocessed entities. + void SetExternalSource(ExternalPreprocessingRecordSource &Source); + + /// Retrieve the external source for preprocessed entities. + ExternalPreprocessingRecordSource *getExternalSource() const { + return ExternalSource; + } + + /// Retrieve the macro definition that corresponds to the given + /// \c MacroInfo. + MacroDefinitionRecord *findMacroDefinition(const MacroInfo *MI); + + /// Retrieve all ranges that got skipped while preprocessing. + const std::vector<SourceRange> &getSkippedRanges() { + ensureSkippedRangesLoaded(); + return SkippedRanges; + } + + private: + friend class ASTReader; + friend class ASTWriter; + + void MacroExpands(const Token &Id, const MacroDefinition &MD, + SourceRange Range, const MacroArgs *Args) override; + void MacroDefined(const Token &Id, const MacroDirective *MD) override; + void MacroUndefined(const Token &Id, const MacroDefinition &MD, + const MacroDirective *Undef) override; + void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, + StringRef FileName, bool IsAngled, + CharSourceRange FilenameRange, + OptionalFileEntryRef File, StringRef SearchPath, + StringRef RelativePath, const Module *Imported, + SrcMgr::CharacteristicKind FileType) override; + void Ifdef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) override; + void Ifndef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) override; + + using PPCallbacks::Elifdef; + using PPCallbacks::Elifndef; + void Elifdef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) override; + void Elifndef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) override; + + /// Hook called whenever the 'defined' operator is seen. + void Defined(const Token &MacroNameTok, const MacroDefinition &MD, + SourceRange Range) override; + + void SourceRangeSkipped(SourceRange Range, + SourceLocation EndifLoc) override; + + void addMacroExpansion(const Token &Id, const MacroInfo *MI, + SourceRange Range); + + /// Cached result of the last \see getPreprocessedEntitiesInRange + /// query. + struct { + SourceRange Range; + std::pair<int, int> Result; + } CachedRangeQuery; + + std::pair<int, int> getPreprocessedEntitiesInRangeSlow(SourceRange R); + }; + +} // namespace clang + +inline void *operator new(size_t bytes, clang::PreprocessingRecord &PR, + unsigned alignment) noexcept { + return PR.Allocate(bytes, alignment); +} + +inline void operator delete(void *ptr, clang::PreprocessingRecord &PR, + unsigned) noexcept { + PR.Deallocate(ptr); +} + +#endif // LLVM_CLANG_LEX_PREPROCESSINGRECORD_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Lex/Preprocessor.h b/contrib/libs/clang16/include/clang/Lex/Preprocessor.h new file mode 100644 index 0000000000..83f4c1f476 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Lex/Preprocessor.h @@ -0,0 +1,2888 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- Preprocessor.h - C Language Family Preprocessor ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +/// \file +/// Defines the clang::Preprocessor interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_PREPROCESSOR_H +#define LLVM_CLANG_LEX_PREPROCESSOR_H + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticIDs.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/Module.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TokenKinds.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/Lexer.h" +#include "clang/Lex/MacroInfo.h" +#include "clang/Lex/ModuleLoader.h" +#include "clang/Lex/ModuleMap.h" +#include "clang/Lex/PPCallbacks.h" +#include "clang/Lex/Token.h" +#include "clang/Lex/TokenLexer.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/FunctionExtras.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/TinyPtrVector.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Registry.h" +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <map> +#include <memory> +#include <optional> +#include <string> +#include <utility> +#include <vector> + +namespace llvm { + +template<unsigned InternalLen> class SmallString; + +} // namespace llvm + +namespace clang { + +class CodeCompletionHandler; +class CommentHandler; +class DirectoryEntry; +class EmptylineHandler; +class ExternalPreprocessorSource; +class FileEntry; +class FileManager; +class HeaderSearch; +class MacroArgs; +class PragmaHandler; +class PragmaNamespace; +class PreprocessingRecord; +class PreprocessorLexer; +class PreprocessorOptions; +class ScratchBuffer; +class TargetInfo; + +namespace Builtin { +class Context; +} + +/// Stores token information for comparing actual tokens with +/// predefined values. Only handles simple tokens and identifiers. +class TokenValue { + tok::TokenKind Kind; + IdentifierInfo *II; + +public: + TokenValue(tok::TokenKind Kind) : Kind(Kind), II(nullptr) { + assert(Kind != tok::raw_identifier && "Raw identifiers are not supported."); + assert(Kind != tok::identifier && + "Identifiers should be created by TokenValue(IdentifierInfo *)"); + assert(!tok::isLiteral(Kind) && "Literals are not supported."); + assert(!tok::isAnnotation(Kind) && "Annotations are not supported."); + } + + TokenValue(IdentifierInfo *II) : Kind(tok::identifier), II(II) {} + + bool operator==(const Token &Tok) const { + return Tok.getKind() == Kind && + (!II || II == Tok.getIdentifierInfo()); + } +}; + +/// Context in which macro name is used. +enum MacroUse { + // other than #define or #undef + MU_Other = 0, + + // macro name specified in #define + MU_Define = 1, + + // macro name specified in #undef + MU_Undef = 2 +}; + +/// Engages in a tight little dance with the lexer to efficiently +/// preprocess tokens. +/// +/// Lexers know only about tokens within a single source file, and don't +/// know anything about preprocessor-level issues like the \#include stack, +/// token expansion, etc. +class Preprocessor { + friend class VAOptDefinitionContext; + friend class VariadicMacroScopeGuard; + + llvm::unique_function<void(const clang::Token &)> OnToken; + std::shared_ptr<PreprocessorOptions> PPOpts; + DiagnosticsEngine *Diags; + LangOptions &LangOpts; + const TargetInfo *Target = nullptr; + const TargetInfo *AuxTarget = nullptr; + FileManager &FileMgr; + SourceManager &SourceMgr; + std::unique_ptr<ScratchBuffer> ScratchBuf; + HeaderSearch &HeaderInfo; + ModuleLoader &TheModuleLoader; + + /// External source of macros. + ExternalPreprocessorSource *ExternalSource; + + /// A BumpPtrAllocator object used to quickly allocate and release + /// objects internal to the Preprocessor. + llvm::BumpPtrAllocator BP; + + /// Identifiers for builtin macros and other builtins. + IdentifierInfo *Ident__LINE__, *Ident__FILE__; // __LINE__, __FILE__ + IdentifierInfo *Ident__DATE__, *Ident__TIME__; // __DATE__, __TIME__ + IdentifierInfo *Ident__INCLUDE_LEVEL__; // __INCLUDE_LEVEL__ + IdentifierInfo *Ident__BASE_FILE__; // __BASE_FILE__ + IdentifierInfo *Ident__FILE_NAME__; // __FILE_NAME__ + IdentifierInfo *Ident__TIMESTAMP__; // __TIMESTAMP__ + IdentifierInfo *Ident__COUNTER__; // __COUNTER__ + IdentifierInfo *Ident_Pragma, *Ident__pragma; // _Pragma, __pragma + IdentifierInfo *Ident__identifier; // __identifier + IdentifierInfo *Ident__VA_ARGS__; // __VA_ARGS__ + IdentifierInfo *Ident__VA_OPT__; // __VA_OPT__ + IdentifierInfo *Ident__has_feature; // __has_feature + IdentifierInfo *Ident__has_extension; // __has_extension + IdentifierInfo *Ident__has_builtin; // __has_builtin + IdentifierInfo *Ident__has_constexpr_builtin; // __has_constexpr_builtin + IdentifierInfo *Ident__has_attribute; // __has_attribute + IdentifierInfo *Ident__has_include; // __has_include + IdentifierInfo *Ident__has_include_next; // __has_include_next + IdentifierInfo *Ident__has_warning; // __has_warning + IdentifierInfo *Ident__is_identifier; // __is_identifier + IdentifierInfo *Ident__building_module; // __building_module + IdentifierInfo *Ident__MODULE__; // __MODULE__ + IdentifierInfo *Ident__has_cpp_attribute; // __has_cpp_attribute + IdentifierInfo *Ident__has_c_attribute; // __has_c_attribute + IdentifierInfo *Ident__has_declspec; // __has_declspec_attribute + IdentifierInfo *Ident__is_target_arch; // __is_target_arch + IdentifierInfo *Ident__is_target_vendor; // __is_target_vendor + IdentifierInfo *Ident__is_target_os; // __is_target_os + IdentifierInfo *Ident__is_target_environment; // __is_target_environment + IdentifierInfo *Ident__is_target_variant_os; + IdentifierInfo *Ident__is_target_variant_environment; + IdentifierInfo *Ident__FLT_EVAL_METHOD__; // __FLT_EVAL_METHOD + + // Weak, only valid (and set) while InMacroArgs is true. + Token* ArgMacro; + + SourceLocation DATELoc, TIMELoc; + + // FEM_UnsetOnCommandLine means that an explicit evaluation method was + // not specified on the command line. The target is queried to set the + // default evaluation method. + LangOptions::FPEvalMethodKind CurrentFPEvalMethod = + LangOptions::FPEvalMethodKind::FEM_UnsetOnCommandLine; + + // The most recent pragma location where the floating point evaluation + // method was modified. This is used to determine whether the + // 'pragma clang fp eval_method' was used whithin the current scope. + SourceLocation LastFPEvalPragmaLocation; + + LangOptions::FPEvalMethodKind TUFPEvalMethod = + LangOptions::FPEvalMethodKind::FEM_UnsetOnCommandLine; + + // Next __COUNTER__ value, starts at 0. + unsigned CounterValue = 0; + + enum { + /// Maximum depth of \#includes. + MaxAllowedIncludeStackDepth = 200 + }; + + // State that is set before the preprocessor begins. + bool KeepComments : 1; + bool KeepMacroComments : 1; + bool SuppressIncludeNotFoundError : 1; + + // State that changes while the preprocessor runs: + bool InMacroArgs : 1; // True if parsing fn macro invocation args. + + /// Whether the preprocessor owns the header search object. + bool OwnsHeaderSearch : 1; + + /// True if macro expansion is disabled. + bool DisableMacroExpansion : 1; + + /// Temporarily disables DisableMacroExpansion (i.e. enables expansion) + /// when parsing preprocessor directives. + bool MacroExpansionInDirectivesOverride : 1; + + class ResetMacroExpansionHelper; + + /// Whether we have already loaded macros from the external source. + mutable bool ReadMacrosFromExternalSource : 1; + + /// True if pragmas are enabled. + bool PragmasEnabled : 1; + + /// True if the current build action is a preprocessing action. + bool PreprocessedOutput : 1; + + /// True if we are currently preprocessing a #if or #elif directive + bool ParsingIfOrElifDirective; + + /// True if we are pre-expanding macro arguments. + bool InMacroArgPreExpansion; + + /// Mapping/lookup information for all identifiers in + /// the program, including program keywords. + mutable IdentifierTable Identifiers; + + /// This table contains all the selectors in the program. + /// + /// Unlike IdentifierTable above, this table *isn't* populated by the + /// preprocessor. It is declared/expanded here because its role/lifetime is + /// conceptually similar to the IdentifierTable. In addition, the current + /// control flow (in clang::ParseAST()), make it convenient to put here. + /// + /// FIXME: Make sure the lifetime of Identifiers/Selectors *isn't* tied to + /// the lifetime of the preprocessor. + SelectorTable Selectors; + + /// Information about builtins. + std::unique_ptr<Builtin::Context> BuiltinInfo; + + /// Tracks all of the pragmas that the client registered + /// with this preprocessor. + std::unique_ptr<PragmaNamespace> PragmaHandlers; + + /// Pragma handlers of the original source is stored here during the + /// parsing of a model file. + std::unique_ptr<PragmaNamespace> PragmaHandlersBackup; + + /// Tracks all of the comment handlers that the client registered + /// with this preprocessor. + std::vector<CommentHandler *> CommentHandlers; + + /// Empty line handler. + EmptylineHandler *Emptyline = nullptr; + +public: + /// The kind of translation unit we are processing. + const TranslationUnitKind TUKind; + +private: + /// The code-completion handler. + CodeCompletionHandler *CodeComplete = nullptr; + + /// The file that we're performing code-completion for, if any. + const FileEntry *CodeCompletionFile = nullptr; + + /// The offset in file for the code-completion point. + unsigned CodeCompletionOffset = 0; + + /// The location for the code-completion point. This gets instantiated + /// when the CodeCompletionFile gets \#include'ed for preprocessing. + SourceLocation CodeCompletionLoc; + + /// The start location for the file of the code-completion point. + /// + /// This gets instantiated when the CodeCompletionFile gets \#include'ed + /// for preprocessing. + SourceLocation CodeCompletionFileLoc; + + /// The source location of the \c import contextual keyword we just + /// lexed, if any. + SourceLocation ModuleImportLoc; + + /// The import path for named module that we're currently processing. + SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> NamedModuleImportPath; + + /// Whether the import is an `@import` or a standard c++ modules import. + bool IsAtImport = false; + + /// Whether the last token we lexed was an '@'. + bool LastTokenWasAt = false; + + /// A position within a C++20 import-seq. + class StdCXXImportSeq { + public: + enum State : int { + // Positive values represent a number of unclosed brackets. + AtTopLevel = 0, + AfterTopLevelTokenSeq = -1, + AfterExport = -2, + AfterImportSeq = -3, + }; + + StdCXXImportSeq(State S) : S(S) {} + + /// Saw any kind of open bracket. + void handleOpenBracket() { + S = static_cast<State>(std::max<int>(S, 0) + 1); + } + /// Saw any kind of close bracket other than '}'. + void handleCloseBracket() { + S = static_cast<State>(std::max<int>(S, 1) - 1); + } + /// Saw a close brace. + void handleCloseBrace() { + handleCloseBracket(); + if (S == AtTopLevel && !AfterHeaderName) + S = AfterTopLevelTokenSeq; + } + /// Saw a semicolon. + void handleSemi() { + if (atTopLevel()) { + S = AfterTopLevelTokenSeq; + AfterHeaderName = false; + } + } + + /// Saw an 'export' identifier. + void handleExport() { + if (S == AfterTopLevelTokenSeq) + S = AfterExport; + else if (S <= 0) + S = AtTopLevel; + } + /// Saw an 'import' identifier. + void handleImport() { + if (S == AfterTopLevelTokenSeq || S == AfterExport) + S = AfterImportSeq; + else if (S <= 0) + S = AtTopLevel; + } + + /// Saw a 'header-name' token; do not recognize any more 'import' tokens + /// until we reach a top-level semicolon. + void handleHeaderName() { + if (S == AfterImportSeq) + AfterHeaderName = true; + handleMisc(); + } + + /// Saw any other token. + void handleMisc() { + if (S <= 0) + S = AtTopLevel; + } + + bool atTopLevel() { return S <= 0; } + bool afterImportSeq() { return S == AfterImportSeq; } + bool afterTopLevelSeq() { return S == AfterTopLevelTokenSeq; } + + private: + State S; + /// Whether we're in the pp-import-suffix following the header-name in a + /// pp-import. If so, a close-brace is not sufficient to end the + /// top-level-token-seq of an import-seq. + bool AfterHeaderName = false; + }; + + /// Our current position within a C++20 import-seq. + StdCXXImportSeq StdCXXImportSeqState = StdCXXImportSeq::AfterTopLevelTokenSeq; + + /// Track whether we are in a Global Module Fragment + class TrackGMF { + public: + enum GMFState : int { + GMFActive = 1, + MaybeGMF = 0, + BeforeGMFIntroducer = -1, + GMFAbsentOrEnded = -2, + }; + + TrackGMF(GMFState S) : S(S) {} + + /// Saw a semicolon. + void handleSemi() { + // If it is immediately after the first instance of the module keyword, + // then that introduces the GMF. + if (S == MaybeGMF) + S = GMFActive; + } + + /// Saw an 'export' identifier. + void handleExport() { + // The presence of an 'export' keyword always ends or excludes a GMF. + S = GMFAbsentOrEnded; + } + + /// Saw an 'import' identifier. + void handleImport(bool AfterTopLevelTokenSeq) { + // If we see this before any 'module' kw, then we have no GMF. + if (AfterTopLevelTokenSeq && S == BeforeGMFIntroducer) + S = GMFAbsentOrEnded; + } + + /// Saw a 'module' identifier. + void handleModule(bool AfterTopLevelTokenSeq) { + // This was the first module identifier and not preceded by any token + // that would exclude a GMF. It could begin a GMF, but only if directly + // followed by a semicolon. + if (AfterTopLevelTokenSeq && S == BeforeGMFIntroducer) + S = MaybeGMF; + else + S = GMFAbsentOrEnded; + } + + /// Saw any other token. + void handleMisc() { + // We saw something other than ; after the 'module' kw, so not a GMF. + if (S == MaybeGMF) + S = GMFAbsentOrEnded; + } + + bool inGMF() { return S == GMFActive; } + + private: + /// Track the transitions into and out of a Global Module Fragment, + /// if one is present. + GMFState S; + }; + + TrackGMF TrackGMFState = TrackGMF::BeforeGMFIntroducer; + + /// Track the status of the c++20 module decl. + /// + /// module-declaration: + /// 'export'[opt] 'module' module-name module-partition[opt] + /// attribute-specifier-seq[opt] ';' + /// + /// module-name: + /// module-name-qualifier[opt] identifier + /// + /// module-partition: + /// ':' module-name-qualifier[opt] identifier + /// + /// module-name-qualifier: + /// identifier '.' + /// module-name-qualifier identifier '.' + /// + /// Transition state: + /// + /// NotAModuleDecl --- export ---> FoundExport + /// NotAModuleDecl --- module ---> ImplementationCandidate + /// FoundExport --- module ---> InterfaceCandidate + /// ImplementationCandidate --- Identifier ---> ImplementationCandidate + /// ImplementationCandidate --- period ---> ImplementationCandidate + /// ImplementationCandidate --- colon ---> ImplementationCandidate + /// InterfaceCandidate --- Identifier ---> InterfaceCandidate + /// InterfaceCandidate --- period ---> InterfaceCandidate + /// InterfaceCandidate --- colon ---> InterfaceCandidate + /// ImplementationCandidate --- Semi ---> NamedModuleImplementation + /// NamedModuleInterface --- Semi ---> NamedModuleInterface + /// NamedModuleImplementation --- Anything ---> NamedModuleImplementation + /// NamedModuleInterface --- Anything ---> NamedModuleInterface + /// + /// FIXME: We haven't handle attribute-specifier-seq here. It may not be bad + /// soon since we don't support any module attributes yet. + class ModuleDeclSeq { + enum ModuleDeclState : int { + NotAModuleDecl, + FoundExport, + InterfaceCandidate, + ImplementationCandidate, + NamedModuleInterface, + NamedModuleImplementation, + }; + + public: + ModuleDeclSeq() : State(NotAModuleDecl) {} + + void handleExport() { + if (State == NotAModuleDecl) + State = FoundExport; + else if (!isNamedModule()) + reset(); + } + + void handleModule() { + if (State == FoundExport) + State = InterfaceCandidate; + else if (State == NotAModuleDecl) + State = ImplementationCandidate; + else if (!isNamedModule()) + reset(); + } + + void handleIdentifier(IdentifierInfo *Identifier) { + if (isModuleCandidate() && Identifier) + Name += Identifier->getName().str(); + else if (!isNamedModule()) + reset(); + } + + void handleColon() { + if (isModuleCandidate()) + Name += ":"; + else if (!isNamedModule()) + reset(); + } + + void handlePeriod() { + if (isModuleCandidate()) + Name += "."; + else if (!isNamedModule()) + reset(); + } + + void handleSemi() { + if (!Name.empty() && isModuleCandidate()) { + if (State == InterfaceCandidate) + State = NamedModuleInterface; + else if (State == ImplementationCandidate) + State = NamedModuleImplementation; + else + llvm_unreachable("Unimaged ModuleDeclState."); + } else if (!isNamedModule()) + reset(); + } + + void handleMisc() { + if (!isNamedModule()) + reset(); + } + + bool isModuleCandidate() const { + return State == InterfaceCandidate || State == ImplementationCandidate; + } + + bool isNamedModule() const { + return State == NamedModuleInterface || + State == NamedModuleImplementation; + } + + bool isNamedInterface() const { return State == NamedModuleInterface; } + + bool isImplementationUnit() const { + return State == NamedModuleImplementation && !getName().contains(':'); + } + + StringRef getName() const { + assert(isNamedModule() && "Can't get name from a non named module"); + return Name; + } + + StringRef getPrimaryName() const { + assert(isNamedModule() && "Can't get name from a non named module"); + return getName().split(':').first; + } + + void reset() { + Name.clear(); + State = NotAModuleDecl; + } + + private: + ModuleDeclState State; + std::string Name; + }; + + ModuleDeclSeq ModuleDeclState; + + /// Whether the module import expects an identifier next. Otherwise, + /// it expects a '.' or ';'. + bool ModuleImportExpectsIdentifier = false; + + /// The identifier and source location of the currently-active + /// \#pragma clang arc_cf_code_audited begin. + std::pair<IdentifierInfo *, SourceLocation> PragmaARCCFCodeAuditedInfo; + + /// The source location of the currently-active + /// \#pragma clang assume_nonnull begin. + SourceLocation PragmaAssumeNonNullLoc; + + /// Set only for preambles which end with an active + /// \#pragma clang assume_nonnull begin. + /// + /// When the preamble is loaded into the main file, + /// `PragmaAssumeNonNullLoc` will be set to this to + /// replay the unterminated assume_nonnull. + SourceLocation PreambleRecordedPragmaAssumeNonNullLoc; + + /// True if we hit the code-completion point. + bool CodeCompletionReached = false; + + /// The code completion token containing the information + /// on the stem that is to be code completed. + IdentifierInfo *CodeCompletionII = nullptr; + + /// Range for the code completion token. + SourceRange CodeCompletionTokenRange; + + /// The directory that the main file should be considered to occupy, + /// if it does not correspond to a real file (as happens when building a + /// module). + const DirectoryEntry *MainFileDir = nullptr; + + /// The number of bytes that we will initially skip when entering the + /// main file, along with a flag that indicates whether skipping this number + /// of bytes will place the lexer at the start of a line. + /// + /// This is used when loading a precompiled preamble. + std::pair<int, bool> SkipMainFilePreamble; + + /// Whether we hit an error due to reaching max allowed include depth. Allows + /// to avoid hitting the same error over and over again. + bool HasReachedMaxIncludeDepth = false; + + /// The number of currently-active calls to Lex. + /// + /// Lex is reentrant, and asking for an (end-of-phase-4) token can often + /// require asking for multiple additional tokens. This counter makes it + /// possible for Lex to detect whether it's producing a token for the end + /// of phase 4 of translation or for some other situation. + unsigned LexLevel = 0; + + /// The number of (LexLevel 0) preprocessor tokens. + unsigned TokenCount = 0; + + /// Preprocess every token regardless of LexLevel. + bool PreprocessToken = false; + + /// The maximum number of (LexLevel 0) tokens before issuing a -Wmax-tokens + /// warning, or zero for unlimited. + unsigned MaxTokens = 0; + SourceLocation MaxTokensOverrideLoc; + +public: + struct PreambleSkipInfo { + SourceLocation HashTokenLoc; + SourceLocation IfTokenLoc; + bool FoundNonSkipPortion; + bool FoundElse; + SourceLocation ElseLoc; + + PreambleSkipInfo(SourceLocation HashTokenLoc, SourceLocation IfTokenLoc, + bool FoundNonSkipPortion, bool FoundElse, + SourceLocation ElseLoc) + : HashTokenLoc(HashTokenLoc), IfTokenLoc(IfTokenLoc), + FoundNonSkipPortion(FoundNonSkipPortion), FoundElse(FoundElse), + ElseLoc(ElseLoc) {} + }; + + using IncludedFilesSet = llvm::DenseSet<const FileEntry *>; + +private: + friend class ASTReader; + friend class MacroArgs; + + class PreambleConditionalStackStore { + enum State { + Off = 0, + Recording = 1, + Replaying = 2, + }; + + public: + PreambleConditionalStackStore() = default; + + void startRecording() { ConditionalStackState = Recording; } + void startReplaying() { ConditionalStackState = Replaying; } + bool isRecording() const { return ConditionalStackState == Recording; } + bool isReplaying() const { return ConditionalStackState == Replaying; } + + ArrayRef<PPConditionalInfo> getStack() const { + return ConditionalStack; + } + + void doneReplaying() { + ConditionalStack.clear(); + ConditionalStackState = Off; + } + + void setStack(ArrayRef<PPConditionalInfo> s) { + if (!isRecording() && !isReplaying()) + return; + ConditionalStack.clear(); + ConditionalStack.append(s.begin(), s.end()); + } + + bool hasRecordedPreamble() const { return !ConditionalStack.empty(); } + + bool reachedEOFWhileSkipping() const { return SkipInfo.has_value(); } + + void clearSkipInfo() { SkipInfo.reset(); } + + std::optional<PreambleSkipInfo> SkipInfo; + + private: + SmallVector<PPConditionalInfo, 4> ConditionalStack; + State ConditionalStackState = Off; + } PreambleConditionalStack; + + /// The current top of the stack that we're lexing from if + /// not expanding a macro and we are lexing directly from source code. + /// + /// Only one of CurLexer, or CurTokenLexer will be non-null. + std::unique_ptr<Lexer> CurLexer; + + /// The current top of the stack what we're lexing from + /// if not expanding a macro. + /// + /// This is an alias for CurLexer. + PreprocessorLexer *CurPPLexer = nullptr; + + /// Used to find the current FileEntry, if CurLexer is non-null + /// and if applicable. + /// + /// This allows us to implement \#include_next and find directory-specific + /// properties. + ConstSearchDirIterator CurDirLookup = nullptr; + + /// The current macro we are expanding, if we are expanding a macro. + /// + /// One of CurLexer and CurTokenLexer must be null. + std::unique_ptr<TokenLexer> CurTokenLexer; + + /// The kind of lexer we're currently working with. + enum CurLexerKind { + CLK_Lexer, + CLK_TokenLexer, + CLK_CachingLexer, + CLK_DependencyDirectivesLexer, + CLK_LexAfterModuleImport + } CurLexerKind = CLK_Lexer; + + /// If the current lexer is for a submodule that is being built, this + /// is that submodule. + Module *CurLexerSubmodule = nullptr; + + /// Keeps track of the stack of files currently + /// \#included, and macros currently being expanded from, not counting + /// CurLexer/CurTokenLexer. + struct IncludeStackInfo { + enum CurLexerKind CurLexerKind; + Module *TheSubmodule; + std::unique_ptr<Lexer> TheLexer; + PreprocessorLexer *ThePPLexer; + std::unique_ptr<TokenLexer> TheTokenLexer; + ConstSearchDirIterator TheDirLookup; + + // The following constructors are completely useless copies of the default + // versions, only needed to pacify MSVC. + IncludeStackInfo(enum CurLexerKind CurLexerKind, Module *TheSubmodule, + std::unique_ptr<Lexer> &&TheLexer, + PreprocessorLexer *ThePPLexer, + std::unique_ptr<TokenLexer> &&TheTokenLexer, + ConstSearchDirIterator TheDirLookup) + : CurLexerKind(std::move(CurLexerKind)), + TheSubmodule(std::move(TheSubmodule)), TheLexer(std::move(TheLexer)), + ThePPLexer(std::move(ThePPLexer)), + TheTokenLexer(std::move(TheTokenLexer)), + TheDirLookup(std::move(TheDirLookup)) {} + }; + std::vector<IncludeStackInfo> IncludeMacroStack; + + /// Actions invoked when some preprocessor activity is + /// encountered (e.g. a file is \#included, etc). + std::unique_ptr<PPCallbacks> Callbacks; + + struct MacroExpandsInfo { + Token Tok; + MacroDefinition MD; + SourceRange Range; + + MacroExpandsInfo(Token Tok, MacroDefinition MD, SourceRange Range) + : Tok(Tok), MD(MD), Range(Range) {} + }; + SmallVector<MacroExpandsInfo, 2> DelayedMacroExpandsCallbacks; + + /// Information about a name that has been used to define a module macro. + struct ModuleMacroInfo { + /// The most recent macro directive for this identifier. + MacroDirective *MD; + + /// The active module macros for this identifier. + llvm::TinyPtrVector<ModuleMacro *> ActiveModuleMacros; + + /// The generation number at which we last updated ActiveModuleMacros. + /// \see Preprocessor::VisibleModules. + unsigned ActiveModuleMacrosGeneration = 0; + + /// Whether this macro name is ambiguous. + bool IsAmbiguous = false; + + /// The module macros that are overridden by this macro. + llvm::TinyPtrVector<ModuleMacro *> OverriddenMacros; + + ModuleMacroInfo(MacroDirective *MD) : MD(MD) {} + }; + + /// The state of a macro for an identifier. + class MacroState { + mutable llvm::PointerUnion<MacroDirective *, ModuleMacroInfo *> State; + + ModuleMacroInfo *getModuleInfo(Preprocessor &PP, + const IdentifierInfo *II) const { + if (II->isOutOfDate()) + PP.updateOutOfDateIdentifier(const_cast<IdentifierInfo&>(*II)); + // FIXME: Find a spare bit on IdentifierInfo and store a + // HasModuleMacros flag. + if (!II->hasMacroDefinition() || + (!PP.getLangOpts().Modules && + !PP.getLangOpts().ModulesLocalVisibility) || + !PP.CurSubmoduleState->VisibleModules.getGeneration()) + return nullptr; + + auto *Info = State.dyn_cast<ModuleMacroInfo*>(); + if (!Info) { + Info = new (PP.getPreprocessorAllocator()) + ModuleMacroInfo(State.get<MacroDirective *>()); + State = Info; + } + + if (PP.CurSubmoduleState->VisibleModules.getGeneration() != + Info->ActiveModuleMacrosGeneration) + PP.updateModuleMacroInfo(II, *Info); + return Info; + } + + public: + MacroState() : MacroState(nullptr) {} + MacroState(MacroDirective *MD) : State(MD) {} + + MacroState(MacroState &&O) noexcept : State(O.State) { + O.State = (MacroDirective *)nullptr; + } + + MacroState &operator=(MacroState &&O) noexcept { + auto S = O.State; + O.State = (MacroDirective *)nullptr; + State = S; + return *this; + } + + ~MacroState() { + if (auto *Info = State.dyn_cast<ModuleMacroInfo*>()) + Info->~ModuleMacroInfo(); + } + + MacroDirective *getLatest() const { + if (auto *Info = State.dyn_cast<ModuleMacroInfo*>()) + return Info->MD; + return State.get<MacroDirective*>(); + } + + void setLatest(MacroDirective *MD) { + if (auto *Info = State.dyn_cast<ModuleMacroInfo*>()) + Info->MD = MD; + else + State = MD; + } + + bool isAmbiguous(Preprocessor &PP, const IdentifierInfo *II) const { + auto *Info = getModuleInfo(PP, II); + return Info ? Info->IsAmbiguous : false; + } + + ArrayRef<ModuleMacro *> + getActiveModuleMacros(Preprocessor &PP, const IdentifierInfo *II) const { + if (auto *Info = getModuleInfo(PP, II)) + return Info->ActiveModuleMacros; + return std::nullopt; + } + + MacroDirective::DefInfo findDirectiveAtLoc(SourceLocation Loc, + SourceManager &SourceMgr) const { + // FIXME: Incorporate module macros into the result of this. + if (auto *Latest = getLatest()) + return Latest->findDirectiveAtLoc(Loc, SourceMgr); + return {}; + } + + void overrideActiveModuleMacros(Preprocessor &PP, IdentifierInfo *II) { + if (auto *Info = getModuleInfo(PP, II)) { + Info->OverriddenMacros.insert(Info->OverriddenMacros.end(), + Info->ActiveModuleMacros.begin(), + Info->ActiveModuleMacros.end()); + Info->ActiveModuleMacros.clear(); + Info->IsAmbiguous = false; + } + } + + ArrayRef<ModuleMacro*> getOverriddenMacros() const { + if (auto *Info = State.dyn_cast<ModuleMacroInfo*>()) + return Info->OverriddenMacros; + return std::nullopt; + } + + void setOverriddenMacros(Preprocessor &PP, + ArrayRef<ModuleMacro *> Overrides) { + auto *Info = State.dyn_cast<ModuleMacroInfo*>(); + if (!Info) { + if (Overrides.empty()) + return; + Info = new (PP.getPreprocessorAllocator()) + ModuleMacroInfo(State.get<MacroDirective *>()); + State = Info; + } + Info->OverriddenMacros.clear(); + Info->OverriddenMacros.insert(Info->OverriddenMacros.end(), + Overrides.begin(), Overrides.end()); + Info->ActiveModuleMacrosGeneration = 0; + } + }; + + /// For each IdentifierInfo that was associated with a macro, we + /// keep a mapping to the history of all macro definitions and #undefs in + /// the reverse order (the latest one is in the head of the list). + /// + /// This mapping lives within the \p CurSubmoduleState. + using MacroMap = llvm::DenseMap<const IdentifierInfo *, MacroState>; + + struct SubmoduleState; + + /// Information about a submodule that we're currently building. + struct BuildingSubmoduleInfo { + /// The module that we are building. + Module *M; + + /// The location at which the module was included. + SourceLocation ImportLoc; + + /// Whether we entered this submodule via a pragma. + bool IsPragma; + + /// The previous SubmoduleState. + SubmoduleState *OuterSubmoduleState; + + /// The number of pending module macro names when we started building this. + unsigned OuterPendingModuleMacroNames; + + BuildingSubmoduleInfo(Module *M, SourceLocation ImportLoc, bool IsPragma, + SubmoduleState *OuterSubmoduleState, + unsigned OuterPendingModuleMacroNames) + : M(M), ImportLoc(ImportLoc), IsPragma(IsPragma), + OuterSubmoduleState(OuterSubmoduleState), + OuterPendingModuleMacroNames(OuterPendingModuleMacroNames) {} + }; + SmallVector<BuildingSubmoduleInfo, 8> BuildingSubmoduleStack; + + /// Information about a submodule's preprocessor state. + struct SubmoduleState { + /// The macros for the submodule. + MacroMap Macros; + + /// The set of modules that are visible within the submodule. + VisibleModuleSet VisibleModules; + + // FIXME: CounterValue? + // FIXME: PragmaPushMacroInfo? + }; + std::map<Module *, SubmoduleState> Submodules; + + /// The preprocessor state for preprocessing outside of any submodule. + SubmoduleState NullSubmoduleState; + + /// The current submodule state. Will be \p NullSubmoduleState if we're not + /// in a submodule. + SubmoduleState *CurSubmoduleState; + + /// The files that have been included. + IncludedFilesSet IncludedFiles; + + /// The set of top-level modules that affected preprocessing, but were not + /// imported. + llvm::SmallSetVector<Module *, 2> AffectingClangModules; + + /// The set of known macros exported from modules. + llvm::FoldingSet<ModuleMacro> ModuleMacros; + + /// The names of potential module macros that we've not yet processed. + llvm::SmallVector<const IdentifierInfo *, 32> PendingModuleMacroNames; + + /// The list of module macros, for each identifier, that are not overridden by + /// any other module macro. + llvm::DenseMap<const IdentifierInfo *, llvm::TinyPtrVector<ModuleMacro *>> + LeafModuleMacros; + + /// Macros that we want to warn because they are not used at the end + /// of the translation unit. + /// + /// We store just their SourceLocations instead of + /// something like MacroInfo*. The benefit of this is that when we are + /// deserializing from PCH, we don't need to deserialize identifier & macros + /// just so that we can report that they are unused, we just warn using + /// the SourceLocations of this set (that will be filled by the ASTReader). + using WarnUnusedMacroLocsTy = llvm::SmallDenseSet<SourceLocation, 32>; + WarnUnusedMacroLocsTy WarnUnusedMacroLocs; + + /// This is a pair of an optional message and source location used for pragmas + /// that annotate macros like pragma clang restrict_expansion and pragma clang + /// deprecated. This pair stores the optional message and the location of the + /// annotation pragma for use producing diagnostics and notes. + using MsgLocationPair = std::pair<std::string, SourceLocation>; + + struct MacroAnnotationInfo { + SourceLocation Location; + std::string Message; + }; + + struct MacroAnnotations { + std::optional<MacroAnnotationInfo> DeprecationInfo; + std::optional<MacroAnnotationInfo> RestrictExpansionInfo; + std::optional<SourceLocation> FinalAnnotationLoc; + + static MacroAnnotations makeDeprecation(SourceLocation Loc, + std::string Msg) { + return MacroAnnotations{MacroAnnotationInfo{Loc, std::move(Msg)}, + std::nullopt, std::nullopt}; + } + + static MacroAnnotations makeRestrictExpansion(SourceLocation Loc, + std::string Msg) { + return MacroAnnotations{ + std::nullopt, MacroAnnotationInfo{Loc, std::move(Msg)}, std::nullopt}; + } + + static MacroAnnotations makeFinal(SourceLocation Loc) { + return MacroAnnotations{std::nullopt, std::nullopt, Loc}; + } + }; + + /// Warning information for macro annotations. + llvm::DenseMap<const IdentifierInfo *, MacroAnnotations> AnnotationInfos; + + /// A "freelist" of MacroArg objects that can be + /// reused for quick allocation. + MacroArgs *MacroArgCache = nullptr; + + /// For each IdentifierInfo used in a \#pragma push_macro directive, + /// we keep a MacroInfo stack used to restore the previous macro value. + llvm::DenseMap<IdentifierInfo *, std::vector<MacroInfo *>> + PragmaPushMacroInfo; + + // Various statistics we track for performance analysis. + unsigned NumDirectives = 0; + unsigned NumDefined = 0; + unsigned NumUndefined = 0; + unsigned NumPragma = 0; + unsigned NumIf = 0; + unsigned NumElse = 0; + unsigned NumEndif = 0; + unsigned NumEnteredSourceFiles = 0; + unsigned MaxIncludeStackDepth = 0; + unsigned NumMacroExpanded = 0; + unsigned NumFnMacroExpanded = 0; + unsigned NumBuiltinMacroExpanded = 0; + unsigned NumFastMacroExpanded = 0; + unsigned NumTokenPaste = 0; + unsigned NumFastTokenPaste = 0; + unsigned NumSkipped = 0; + + /// The predefined macros that preprocessor should use from the + /// command line etc. + std::string Predefines; + + /// The file ID for the preprocessor predefines. + FileID PredefinesFileID; + + /// The file ID for the PCH through header. + FileID PCHThroughHeaderFileID; + + /// Whether tokens are being skipped until a #pragma hdrstop is seen. + bool SkippingUntilPragmaHdrStop = false; + + /// Whether tokens are being skipped until the through header is seen. + bool SkippingUntilPCHThroughHeader = false; + + /// \{ + /// Cache of macro expanders to reduce malloc traffic. + enum { TokenLexerCacheSize = 8 }; + unsigned NumCachedTokenLexers; + std::unique_ptr<TokenLexer> TokenLexerCache[TokenLexerCacheSize]; + /// \} + + /// Keeps macro expanded tokens for TokenLexers. + // + /// Works like a stack; a TokenLexer adds the macro expanded tokens that is + /// going to lex in the cache and when it finishes the tokens are removed + /// from the end of the cache. + SmallVector<Token, 16> MacroExpandedTokens; + std::vector<std::pair<TokenLexer *, size_t>> MacroExpandingLexersStack; + + /// A record of the macro definitions and expansions that + /// occurred during preprocessing. + /// + /// This is an optional side structure that can be enabled with + /// \c createPreprocessingRecord() prior to preprocessing. + PreprocessingRecord *Record = nullptr; + + /// Cached tokens state. + using CachedTokensTy = SmallVector<Token, 1>; + + /// Cached tokens are stored here when we do backtracking or + /// lookahead. They are "lexed" by the CachingLex() method. + CachedTokensTy CachedTokens; + + /// The position of the cached token that CachingLex() should + /// "lex" next. + /// + /// If it points beyond the CachedTokens vector, it means that a normal + /// Lex() should be invoked. + CachedTokensTy::size_type CachedLexPos = 0; + + /// Stack of backtrack positions, allowing nested backtracks. + /// + /// The EnableBacktrackAtThisPos() method pushes a position to + /// indicate where CachedLexPos should be set when the BackTrack() method is + /// invoked (at which point the last position is popped). + std::vector<CachedTokensTy::size_type> BacktrackPositions; + + /// True if \p Preprocessor::SkipExcludedConditionalBlock() is running. + /// This is used to guard against calling this function recursively. + /// + /// See comments at the use-site for more context about why it is needed. + bool SkippingExcludedConditionalBlock = false; + + /// Keeps track of skipped range mappings that were recorded while skipping + /// excluded conditional directives. It maps the source buffer pointer at + /// the beginning of a skipped block, to the number of bytes that should be + /// skipped. + llvm::DenseMap<const char *, unsigned> RecordedSkippedRanges; + + void updateOutOfDateIdentifier(IdentifierInfo &II) const; + +public: + Preprocessor(std::shared_ptr<PreprocessorOptions> PPOpts, + DiagnosticsEngine &diags, LangOptions &opts, SourceManager &SM, + HeaderSearch &Headers, ModuleLoader &TheModuleLoader, + IdentifierInfoLookup *IILookup = nullptr, + bool OwnsHeaderSearch = false, + TranslationUnitKind TUKind = TU_Complete); + + ~Preprocessor(); + + /// Initialize the preprocessor using information about the target. + /// + /// \param Target is owned by the caller and must remain valid for the + /// lifetime of the preprocessor. + /// \param AuxTarget is owned by the caller and must remain valid for + /// the lifetime of the preprocessor. + void Initialize(const TargetInfo &Target, + const TargetInfo *AuxTarget = nullptr); + + /// Initialize the preprocessor to parse a model file + /// + /// To parse model files the preprocessor of the original source is reused to + /// preserver the identifier table. However to avoid some duplicate + /// information in the preprocessor some cleanup is needed before it is used + /// to parse model files. This method does that cleanup. + void InitializeForModelFile(); + + /// Cleanup after model file parsing + void FinalizeForModelFile(); + + /// Retrieve the preprocessor options used to initialize this + /// preprocessor. + PreprocessorOptions &getPreprocessorOpts() const { return *PPOpts; } + + DiagnosticsEngine &getDiagnostics() const { return *Diags; } + void setDiagnostics(DiagnosticsEngine &D) { Diags = &D; } + + const LangOptions &getLangOpts() const { return LangOpts; } + const TargetInfo &getTargetInfo() const { return *Target; } + const TargetInfo *getAuxTargetInfo() const { return AuxTarget; } + FileManager &getFileManager() const { return FileMgr; } + SourceManager &getSourceManager() const { return SourceMgr; } + HeaderSearch &getHeaderSearchInfo() const { return HeaderInfo; } + + IdentifierTable &getIdentifierTable() { return Identifiers; } + const IdentifierTable &getIdentifierTable() const { return Identifiers; } + SelectorTable &getSelectorTable() { return Selectors; } + Builtin::Context &getBuiltinInfo() { return *BuiltinInfo; } + llvm::BumpPtrAllocator &getPreprocessorAllocator() { return BP; } + + void setExternalSource(ExternalPreprocessorSource *Source) { + ExternalSource = Source; + } + + ExternalPreprocessorSource *getExternalSource() const { + return ExternalSource; + } + + /// Retrieve the module loader associated with this preprocessor. + ModuleLoader &getModuleLoader() const { return TheModuleLoader; } + + bool hadModuleLoaderFatalFailure() const { + return TheModuleLoader.HadFatalFailure; + } + + /// Retrieve the number of Directives that have been processed by the + /// Preprocessor. + unsigned getNumDirectives() const { + return NumDirectives; + } + + /// True if we are currently preprocessing a #if or #elif directive + bool isParsingIfOrElifDirective() const { + return ParsingIfOrElifDirective; + } + + /// Control whether the preprocessor retains comments in output. + void SetCommentRetentionState(bool KeepComments, bool KeepMacroComments) { + this->KeepComments = KeepComments | KeepMacroComments; + this->KeepMacroComments = KeepMacroComments; + } + + bool getCommentRetentionState() const { return KeepComments; } + + void setPragmasEnabled(bool Enabled) { PragmasEnabled = Enabled; } + bool getPragmasEnabled() const { return PragmasEnabled; } + + void SetSuppressIncludeNotFoundError(bool Suppress) { + SuppressIncludeNotFoundError = Suppress; + } + + bool GetSuppressIncludeNotFoundError() { + return SuppressIncludeNotFoundError; + } + + /// Sets whether the preprocessor is responsible for producing output or if + /// it is producing tokens to be consumed by Parse and Sema. + void setPreprocessedOutput(bool IsPreprocessedOutput) { + PreprocessedOutput = IsPreprocessedOutput; + } + + /// Returns true if the preprocessor is responsible for generating output, + /// false if it is producing tokens to be consumed by Parse and Sema. + bool isPreprocessedOutput() const { return PreprocessedOutput; } + + /// Return true if we are lexing directly from the specified lexer. + bool isCurrentLexer(const PreprocessorLexer *L) const { + return CurPPLexer == L; + } + + /// Return the current lexer being lexed from. + /// + /// Note that this ignores any potentially active macro expansions and _Pragma + /// expansions going on at the time. + PreprocessorLexer *getCurrentLexer() const { return CurPPLexer; } + + /// Return the current file lexer being lexed from. + /// + /// Note that this ignores any potentially active macro expansions and _Pragma + /// expansions going on at the time. + PreprocessorLexer *getCurrentFileLexer() const; + + /// Return the submodule owning the file being lexed. This may not be + /// the current module if we have changed modules since entering the file. + Module *getCurrentLexerSubmodule() const { return CurLexerSubmodule; } + + /// Returns the FileID for the preprocessor predefines. + FileID getPredefinesFileID() const { return PredefinesFileID; } + + /// \{ + /// Accessors for preprocessor callbacks. + /// + /// Note that this class takes ownership of any PPCallbacks object given to + /// it. + PPCallbacks *getPPCallbacks() const { return Callbacks.get(); } + void addPPCallbacks(std::unique_ptr<PPCallbacks> C) { + if (Callbacks) + C = std::make_unique<PPChainedCallbacks>(std::move(C), + std::move(Callbacks)); + Callbacks = std::move(C); + } + /// \} + + /// Get the number of tokens processed so far. + unsigned getTokenCount() const { return TokenCount; } + + /// Get the max number of tokens before issuing a -Wmax-tokens warning. + unsigned getMaxTokens() const { return MaxTokens; } + + void overrideMaxTokens(unsigned Value, SourceLocation Loc) { + MaxTokens = Value; + MaxTokensOverrideLoc = Loc; + }; + + SourceLocation getMaxTokensOverrideLoc() const { return MaxTokensOverrideLoc; } + + /// Register a function that would be called on each token in the final + /// expanded token stream. + /// This also reports annotation tokens produced by the parser. + void setTokenWatcher(llvm::unique_function<void(const clang::Token &)> F) { + OnToken = std::move(F); + } + + void setPreprocessToken(bool Preprocess) { PreprocessToken = Preprocess; } + + bool isMacroDefined(StringRef Id) { + return isMacroDefined(&Identifiers.get(Id)); + } + bool isMacroDefined(const IdentifierInfo *II) { + return II->hasMacroDefinition() && + (!getLangOpts().Modules || (bool)getMacroDefinition(II)); + } + + /// Determine whether II is defined as a macro within the module M, + /// if that is a module that we've already preprocessed. Does not check for + /// macros imported into M. + bool isMacroDefinedInLocalModule(const IdentifierInfo *II, Module *M) { + if (!II->hasMacroDefinition()) + return false; + auto I = Submodules.find(M); + if (I == Submodules.end()) + return false; + auto J = I->second.Macros.find(II); + if (J == I->second.Macros.end()) + return false; + auto *MD = J->second.getLatest(); + return MD && MD->isDefined(); + } + + MacroDefinition getMacroDefinition(const IdentifierInfo *II) { + if (!II->hasMacroDefinition()) + return {}; + + MacroState &S = CurSubmoduleState->Macros[II]; + auto *MD = S.getLatest(); + while (MD && isa<VisibilityMacroDirective>(MD)) + MD = MD->getPrevious(); + return MacroDefinition(dyn_cast_or_null<DefMacroDirective>(MD), + S.getActiveModuleMacros(*this, II), + S.isAmbiguous(*this, II)); + } + + MacroDefinition getMacroDefinitionAtLoc(const IdentifierInfo *II, + SourceLocation Loc) { + if (!II->hadMacroDefinition()) + return {}; + + MacroState &S = CurSubmoduleState->Macros[II]; + MacroDirective::DefInfo DI; + if (auto *MD = S.getLatest()) + DI = MD->findDirectiveAtLoc(Loc, getSourceManager()); + // FIXME: Compute the set of active module macros at the specified location. + return MacroDefinition(DI.getDirective(), + S.getActiveModuleMacros(*this, II), + S.isAmbiguous(*this, II)); + } + + /// Given an identifier, return its latest non-imported MacroDirective + /// if it is \#define'd and not \#undef'd, or null if it isn't \#define'd. + MacroDirective *getLocalMacroDirective(const IdentifierInfo *II) const { + if (!II->hasMacroDefinition()) + return nullptr; + + auto *MD = getLocalMacroDirectiveHistory(II); + if (!MD || MD->getDefinition().isUndefined()) + return nullptr; + + return MD; + } + + const MacroInfo *getMacroInfo(const IdentifierInfo *II) const { + return const_cast<Preprocessor*>(this)->getMacroInfo(II); + } + + MacroInfo *getMacroInfo(const IdentifierInfo *II) { + if (!II->hasMacroDefinition()) + return nullptr; + if (auto MD = getMacroDefinition(II)) + return MD.getMacroInfo(); + return nullptr; + } + + /// Given an identifier, return the latest non-imported macro + /// directive for that identifier. + /// + /// One can iterate over all previous macro directives from the most recent + /// one. + MacroDirective *getLocalMacroDirectiveHistory(const IdentifierInfo *II) const; + + /// Add a directive to the macro directive history for this identifier. + void appendMacroDirective(IdentifierInfo *II, MacroDirective *MD); + DefMacroDirective *appendDefMacroDirective(IdentifierInfo *II, MacroInfo *MI, + SourceLocation Loc) { + DefMacroDirective *MD = AllocateDefMacroDirective(MI, Loc); + appendMacroDirective(II, MD); + return MD; + } + DefMacroDirective *appendDefMacroDirective(IdentifierInfo *II, + MacroInfo *MI) { + return appendDefMacroDirective(II, MI, MI->getDefinitionLoc()); + } + + /// Set a MacroDirective that was loaded from a PCH file. + void setLoadedMacroDirective(IdentifierInfo *II, MacroDirective *ED, + MacroDirective *MD); + + /// Register an exported macro for a module and identifier. + ModuleMacro *addModuleMacro(Module *Mod, IdentifierInfo *II, MacroInfo *Macro, + ArrayRef<ModuleMacro *> Overrides, bool &IsNew); + ModuleMacro *getModuleMacro(Module *Mod, const IdentifierInfo *II); + + /// Get the list of leaf (non-overridden) module macros for a name. + ArrayRef<ModuleMacro*> getLeafModuleMacros(const IdentifierInfo *II) const { + if (II->isOutOfDate()) + updateOutOfDateIdentifier(const_cast<IdentifierInfo&>(*II)); + auto I = LeafModuleMacros.find(II); + if (I != LeafModuleMacros.end()) + return I->second; + return std::nullopt; + } + + /// Get the list of submodules that we're currently building. + ArrayRef<BuildingSubmoduleInfo> getBuildingSubmodules() const { + return BuildingSubmoduleStack; + } + + /// \{ + /// Iterators for the macro history table. Currently defined macros have + /// IdentifierInfo::hasMacroDefinition() set and an empty + /// MacroInfo::getUndefLoc() at the head of the list. + using macro_iterator = MacroMap::const_iterator; + + macro_iterator macro_begin(bool IncludeExternalMacros = true) const; + macro_iterator macro_end(bool IncludeExternalMacros = true) const; + + llvm::iterator_range<macro_iterator> + macros(bool IncludeExternalMacros = true) const { + macro_iterator begin = macro_begin(IncludeExternalMacros); + macro_iterator end = macro_end(IncludeExternalMacros); + return llvm::make_range(begin, end); + } + + /// \} + + /// Mark the given clang module as affecting the current clang module or translation unit. + void markClangModuleAsAffecting(Module *M) { + assert(M->isModuleMapModule()); + if (!BuildingSubmoduleStack.empty()) { + if (M != BuildingSubmoduleStack.back().M) + BuildingSubmoduleStack.back().M->AffectingClangModules.insert(M); + } else { + AffectingClangModules.insert(M); + } + } + + /// Get the set of top-level clang modules that affected preprocessing, but were not + /// imported. + const llvm::SmallSetVector<Module *, 2> &getAffectingClangModules() const { + return AffectingClangModules; + } + + /// Mark the file as included. + /// Returns true if this is the first time the file was included. + bool markIncluded(const FileEntry *File) { + HeaderInfo.getFileInfo(File); + return IncludedFiles.insert(File).second; + } + + /// Return true if this header has already been included. + bool alreadyIncluded(const FileEntry *File) const { + return IncludedFiles.count(File); + } + + /// Get the set of included files. + IncludedFilesSet &getIncludedFiles() { return IncludedFiles; } + const IncludedFilesSet &getIncludedFiles() const { return IncludedFiles; } + + /// Return the name of the macro defined before \p Loc that has + /// spelling \p Tokens. If there are multiple macros with same spelling, + /// return the last one defined. + StringRef getLastMacroWithSpelling(SourceLocation Loc, + ArrayRef<TokenValue> Tokens) const; + + /// Get the predefines for this processor. + /// Used by some third-party tools to inspect and add predefines (see + /// https://github.com/llvm/llvm-project/issues/57483). + const std::string &getPredefines() const { return Predefines; } + + /// Set the predefines for this Preprocessor. + /// + /// These predefines are automatically injected when parsing the main file. + void setPredefines(std::string P) { Predefines = std::move(P); } + + /// Return information about the specified preprocessor + /// identifier token. + IdentifierInfo *getIdentifierInfo(StringRef Name) const { + return &Identifiers.get(Name); + } + + /// Add the specified pragma handler to this preprocessor. + /// + /// If \p Namespace is non-null, then it is a token required to exist on the + /// pragma line before the pragma string starts, e.g. "STDC" or "GCC". + void AddPragmaHandler(StringRef Namespace, PragmaHandler *Handler); + void AddPragmaHandler(PragmaHandler *Handler) { + AddPragmaHandler(StringRef(), Handler); + } + + /// Remove the specific pragma handler from this preprocessor. + /// + /// If \p Namespace is non-null, then it should be the namespace that + /// \p Handler was added to. It is an error to remove a handler that + /// has not been registered. + void RemovePragmaHandler(StringRef Namespace, PragmaHandler *Handler); + void RemovePragmaHandler(PragmaHandler *Handler) { + RemovePragmaHandler(StringRef(), Handler); + } + + /// Install empty handlers for all pragmas (making them ignored). + void IgnorePragmas(); + + /// Set empty line handler. + void setEmptylineHandler(EmptylineHandler *Handler) { Emptyline = Handler; } + + EmptylineHandler *getEmptylineHandler() const { return Emptyline; } + + /// Add the specified comment handler to the preprocessor. + void addCommentHandler(CommentHandler *Handler); + + /// Remove the specified comment handler. + /// + /// It is an error to remove a handler that has not been registered. + void removeCommentHandler(CommentHandler *Handler); + + /// Set the code completion handler to the given object. + void setCodeCompletionHandler(CodeCompletionHandler &Handler) { + CodeComplete = &Handler; + } + + /// Retrieve the current code-completion handler. + CodeCompletionHandler *getCodeCompletionHandler() const { + return CodeComplete; + } + + /// Clear out the code completion handler. + void clearCodeCompletionHandler() { + CodeComplete = nullptr; + } + + /// Hook used by the lexer to invoke the "included file" code + /// completion point. + void CodeCompleteIncludedFile(llvm::StringRef Dir, bool IsAngled); + + /// Hook used by the lexer to invoke the "natural language" code + /// completion point. + void CodeCompleteNaturalLanguage(); + + /// Set the code completion token for filtering purposes. + void setCodeCompletionIdentifierInfo(IdentifierInfo *Filter) { + CodeCompletionII = Filter; + } + + /// Set the code completion token range for detecting replacement range later + /// on. + void setCodeCompletionTokenRange(const SourceLocation Start, + const SourceLocation End) { + CodeCompletionTokenRange = {Start, End}; + } + SourceRange getCodeCompletionTokenRange() const { + return CodeCompletionTokenRange; + } + + /// Get the code completion token for filtering purposes. + StringRef getCodeCompletionFilter() { + if (CodeCompletionII) + return CodeCompletionII->getName(); + return {}; + } + + /// Retrieve the preprocessing record, or NULL if there is no + /// preprocessing record. + PreprocessingRecord *getPreprocessingRecord() const { return Record; } + + /// Create a new preprocessing record, which will keep track of + /// all macro expansions, macro definitions, etc. + void createPreprocessingRecord(); + + /// Returns true if the FileEntry is the PCH through header. + bool isPCHThroughHeader(const FileEntry *FE); + + /// True if creating a PCH with a through header. + bool creatingPCHWithThroughHeader(); + + /// True if using a PCH with a through header. + bool usingPCHWithThroughHeader(); + + /// True if creating a PCH with a #pragma hdrstop. + bool creatingPCHWithPragmaHdrStop(); + + /// True if using a PCH with a #pragma hdrstop. + bool usingPCHWithPragmaHdrStop(); + + /// Skip tokens until after the #include of the through header or + /// until after a #pragma hdrstop. + void SkipTokensWhileUsingPCH(); + + /// Process directives while skipping until the through header or + /// #pragma hdrstop is found. + void HandleSkippedDirectiveWhileUsingPCH(Token &Result, + SourceLocation HashLoc); + + /// Enter the specified FileID as the main source file, + /// which implicitly adds the builtin defines etc. + void EnterMainSourceFile(); + + /// Inform the preprocessor callbacks that processing is complete. + void EndSourceFile(); + + /// Add a source file to the top of the include stack and + /// start lexing tokens from it instead of the current buffer. + /// + /// Emits a diagnostic, doesn't enter the file, and returns true on error. + bool EnterSourceFile(FileID FID, ConstSearchDirIterator Dir, + SourceLocation Loc, bool IsFirstIncludeOfFile = true); + + /// Add a Macro to the top of the include stack and start lexing + /// tokens from it instead of the current buffer. + /// + /// \param Args specifies the tokens input to a function-like macro. + /// \param ILEnd specifies the location of the ')' for a function-like macro + /// or the identifier for an object-like macro. + void EnterMacro(Token &Tok, SourceLocation ILEnd, MacroInfo *Macro, + MacroArgs *Args); + +private: + /// Add a "macro" context to the top of the include stack, + /// which will cause the lexer to start returning the specified tokens. + /// + /// If \p DisableMacroExpansion is true, tokens lexed from the token stream + /// will not be subject to further macro expansion. Otherwise, these tokens + /// will be re-macro-expanded when/if expansion is enabled. + /// + /// If \p OwnsTokens is false, this method assumes that the specified stream + /// of tokens has a permanent owner somewhere, so they do not need to be + /// copied. If it is true, it assumes the array of tokens is allocated with + /// \c new[] and the Preprocessor will delete[] it. + /// + /// If \p IsReinject the resulting tokens will have Token::IsReinjected flag + /// set, see the flag documentation for details. + void EnterTokenStream(const Token *Toks, unsigned NumToks, + bool DisableMacroExpansion, bool OwnsTokens, + bool IsReinject); + +public: + void EnterTokenStream(std::unique_ptr<Token[]> Toks, unsigned NumToks, + bool DisableMacroExpansion, bool IsReinject) { + EnterTokenStream(Toks.release(), NumToks, DisableMacroExpansion, true, + IsReinject); + } + + void EnterTokenStream(ArrayRef<Token> Toks, bool DisableMacroExpansion, + bool IsReinject) { + EnterTokenStream(Toks.data(), Toks.size(), DisableMacroExpansion, false, + IsReinject); + } + + /// Pop the current lexer/macro exp off the top of the lexer stack. + /// + /// This should only be used in situations where the current state of the + /// top-of-stack lexer is known. + void RemoveTopOfLexerStack(); + + /// From the point that this method is called, and until + /// CommitBacktrackedTokens() or Backtrack() is called, the Preprocessor + /// keeps track of the lexed tokens so that a subsequent Backtrack() call will + /// make the Preprocessor re-lex the same tokens. + /// + /// Nested backtracks are allowed, meaning that EnableBacktrackAtThisPos can + /// be called multiple times and CommitBacktrackedTokens/Backtrack calls will + /// be combined with the EnableBacktrackAtThisPos calls in reverse order. + /// + /// NOTE: *DO NOT* forget to call either CommitBacktrackedTokens or Backtrack + /// at some point after EnableBacktrackAtThisPos. If you don't, caching of + /// tokens will continue indefinitely. + /// + void EnableBacktrackAtThisPos(); + + /// Disable the last EnableBacktrackAtThisPos call. + void CommitBacktrackedTokens(); + + /// Make Preprocessor re-lex the tokens that were lexed since + /// EnableBacktrackAtThisPos() was previously called. + void Backtrack(); + + /// True if EnableBacktrackAtThisPos() was called and + /// caching of tokens is on. + bool isBacktrackEnabled() const { return !BacktrackPositions.empty(); } + + /// Lex the next token for this preprocessor. + void Lex(Token &Result); + + /// Lex a token, forming a header-name token if possible. + bool LexHeaderName(Token &Result, bool AllowMacroExpansion = true); + + bool LexAfterModuleImport(Token &Result); + void CollectPpImportSuffix(SmallVectorImpl<Token> &Toks); + + void makeModuleVisible(Module *M, SourceLocation Loc); + + SourceLocation getModuleImportLoc(Module *M) const { + return CurSubmoduleState->VisibleModules.getImportLoc(M); + } + + /// Lex a string literal, which may be the concatenation of multiple + /// string literals and may even come from macro expansion. + /// \returns true on success, false if a error diagnostic has been generated. + bool LexStringLiteral(Token &Result, std::string &String, + const char *DiagnosticTag, bool AllowMacroExpansion) { + if (AllowMacroExpansion) + Lex(Result); + else + LexUnexpandedToken(Result); + return FinishLexStringLiteral(Result, String, DiagnosticTag, + AllowMacroExpansion); + } + + /// Complete the lexing of a string literal where the first token has + /// already been lexed (see LexStringLiteral). + bool FinishLexStringLiteral(Token &Result, std::string &String, + const char *DiagnosticTag, + bool AllowMacroExpansion); + + /// Lex a token. If it's a comment, keep lexing until we get + /// something not a comment. + /// + /// This is useful in -E -C mode where comments would foul up preprocessor + /// directive handling. + void LexNonComment(Token &Result) { + do + Lex(Result); + while (Result.getKind() == tok::comment); + } + + /// Just like Lex, but disables macro expansion of identifier tokens. + void LexUnexpandedToken(Token &Result) { + // Disable macro expansion. + bool OldVal = DisableMacroExpansion; + DisableMacroExpansion = true; + // Lex the token. + Lex(Result); + + // Reenable it. + DisableMacroExpansion = OldVal; + } + + /// Like LexNonComment, but this disables macro expansion of + /// identifier tokens. + void LexUnexpandedNonComment(Token &Result) { + do + LexUnexpandedToken(Result); + while (Result.getKind() == tok::comment); + } + + /// Parses a simple integer literal to get its numeric value. Floating + /// point literals and user defined literals are rejected. Used primarily to + /// handle pragmas that accept integer arguments. + bool parseSimpleIntegerLiteral(Token &Tok, uint64_t &Value); + + /// Disables macro expansion everywhere except for preprocessor directives. + void SetMacroExpansionOnlyInDirectives() { + DisableMacroExpansion = true; + MacroExpansionInDirectivesOverride = true; + } + + /// Peeks ahead N tokens and returns that token without consuming any + /// tokens. + /// + /// LookAhead(0) returns the next token that would be returned by Lex(), + /// LookAhead(1) returns the token after it, etc. This returns normal + /// tokens after phase 5. As such, it is equivalent to using + /// 'Lex', not 'LexUnexpandedToken'. + const Token &LookAhead(unsigned N) { + assert(LexLevel == 0 && "cannot use lookahead while lexing"); + if (CachedLexPos + N < CachedTokens.size()) + return CachedTokens[CachedLexPos+N]; + else + return PeekAhead(N+1); + } + + /// When backtracking is enabled and tokens are cached, + /// this allows to revert a specific number of tokens. + /// + /// Note that the number of tokens being reverted should be up to the last + /// backtrack position, not more. + void RevertCachedTokens(unsigned N) { + assert(isBacktrackEnabled() && + "Should only be called when tokens are cached for backtracking"); + assert(signed(CachedLexPos) - signed(N) >= signed(BacktrackPositions.back()) + && "Should revert tokens up to the last backtrack position, not more"); + assert(signed(CachedLexPos) - signed(N) >= 0 && + "Corrupted backtrack positions ?"); + CachedLexPos -= N; + } + + /// Enters a token in the token stream to be lexed next. + /// + /// If BackTrack() is called afterwards, the token will remain at the + /// insertion point. + /// If \p IsReinject is true, resulting token will have Token::IsReinjected + /// flag set. See the flag documentation for details. + void EnterToken(const Token &Tok, bool IsReinject) { + if (LexLevel) { + // It's not correct in general to enter caching lex mode while in the + // middle of a nested lexing action. + auto TokCopy = std::make_unique<Token[]>(1); + TokCopy[0] = Tok; + EnterTokenStream(std::move(TokCopy), 1, true, IsReinject); + } else { + EnterCachingLexMode(); + assert(IsReinject && "new tokens in the middle of cached stream"); + CachedTokens.insert(CachedTokens.begin()+CachedLexPos, Tok); + } + } + + /// We notify the Preprocessor that if it is caching tokens (because + /// backtrack is enabled) it should replace the most recent cached tokens + /// with the given annotation token. This function has no effect if + /// backtracking is not enabled. + /// + /// Note that the use of this function is just for optimization, so that the + /// cached tokens doesn't get re-parsed and re-resolved after a backtrack is + /// invoked. + void AnnotateCachedTokens(const Token &Tok) { + assert(Tok.isAnnotation() && "Expected annotation token"); + if (CachedLexPos != 0 && isBacktrackEnabled()) + AnnotatePreviousCachedTokens(Tok); + } + + /// Get the location of the last cached token, suitable for setting the end + /// location of an annotation token. + SourceLocation getLastCachedTokenLocation() const { + assert(CachedLexPos != 0); + return CachedTokens[CachedLexPos-1].getLastLoc(); + } + + /// Whether \p Tok is the most recent token (`CachedLexPos - 1`) in + /// CachedTokens. + bool IsPreviousCachedToken(const Token &Tok) const; + + /// Replace token in `CachedLexPos - 1` in CachedTokens by the tokens + /// in \p NewToks. + /// + /// Useful when a token needs to be split in smaller ones and CachedTokens + /// most recent token must to be updated to reflect that. + void ReplacePreviousCachedToken(ArrayRef<Token> NewToks); + + /// Replace the last token with an annotation token. + /// + /// Like AnnotateCachedTokens(), this routine replaces an + /// already-parsed (and resolved) token with an annotation + /// token. However, this routine only replaces the last token with + /// the annotation token; it does not affect any other cached + /// tokens. This function has no effect if backtracking is not + /// enabled. + void ReplaceLastTokenWithAnnotation(const Token &Tok) { + assert(Tok.isAnnotation() && "Expected annotation token"); + if (CachedLexPos != 0 && isBacktrackEnabled()) + CachedTokens[CachedLexPos-1] = Tok; + } + + /// Enter an annotation token into the token stream. + void EnterAnnotationToken(SourceRange Range, tok::TokenKind Kind, + void *AnnotationVal); + + /// Determine whether it's possible for a future call to Lex to produce an + /// annotation token created by a previous call to EnterAnnotationToken. + bool mightHavePendingAnnotationTokens() { + return CurLexerKind != CLK_Lexer; + } + + /// Update the current token to represent the provided + /// identifier, in order to cache an action performed by typo correction. + void TypoCorrectToken(const Token &Tok) { + assert(Tok.getIdentifierInfo() && "Expected identifier token"); + if (CachedLexPos != 0 && isBacktrackEnabled()) + CachedTokens[CachedLexPos-1] = Tok; + } + + /// Recompute the current lexer kind based on the CurLexer/ + /// CurTokenLexer pointers. + void recomputeCurLexerKind(); + + /// Returns true if incremental processing is enabled + bool isIncrementalProcessingEnabled() const { + return getLangOpts().IncrementalExtensions; + } + + /// Enables the incremental processing + void enableIncrementalProcessing(bool value = true) { + // FIXME: Drop this interface. + const_cast<LangOptions &>(getLangOpts()).IncrementalExtensions = value; + } + + /// Specify the point at which code-completion will be performed. + /// + /// \param File the file in which code completion should occur. If + /// this file is included multiple times, code-completion will + /// perform completion the first time it is included. If NULL, this + /// function clears out the code-completion point. + /// + /// \param Line the line at which code completion should occur + /// (1-based). + /// + /// \param Column the column at which code completion should occur + /// (1-based). + /// + /// \returns true if an error occurred, false otherwise. + bool SetCodeCompletionPoint(const FileEntry *File, + unsigned Line, unsigned Column); + + /// Determine if we are performing code completion. + bool isCodeCompletionEnabled() const { return CodeCompletionFile != nullptr; } + + /// Returns the location of the code-completion point. + /// + /// Returns an invalid location if code-completion is not enabled or the file + /// containing the code-completion point has not been lexed yet. + SourceLocation getCodeCompletionLoc() const { return CodeCompletionLoc; } + + /// Returns the start location of the file of code-completion point. + /// + /// Returns an invalid location if code-completion is not enabled or the file + /// containing the code-completion point has not been lexed yet. + SourceLocation getCodeCompletionFileLoc() const { + return CodeCompletionFileLoc; + } + + /// Returns true if code-completion is enabled and we have hit the + /// code-completion point. + bool isCodeCompletionReached() const { return CodeCompletionReached; } + + /// Note that we hit the code-completion point. + void setCodeCompletionReached() { + assert(isCodeCompletionEnabled() && "Code-completion not enabled!"); + CodeCompletionReached = true; + // Silence any diagnostics that occur after we hit the code-completion. + getDiagnostics().setSuppressAllDiagnostics(true); + } + + /// The location of the currently-active \#pragma clang + /// arc_cf_code_audited begin. + /// + /// Returns an invalid location if there is no such pragma active. + std::pair<IdentifierInfo *, SourceLocation> + getPragmaARCCFCodeAuditedInfo() const { + return PragmaARCCFCodeAuditedInfo; + } + + /// Set the location of the currently-active \#pragma clang + /// arc_cf_code_audited begin. An invalid location ends the pragma. + void setPragmaARCCFCodeAuditedInfo(IdentifierInfo *Ident, + SourceLocation Loc) { + PragmaARCCFCodeAuditedInfo = {Ident, Loc}; + } + + /// The location of the currently-active \#pragma clang + /// assume_nonnull begin. + /// + /// Returns an invalid location if there is no such pragma active. + SourceLocation getPragmaAssumeNonNullLoc() const { + return PragmaAssumeNonNullLoc; + } + + /// Set the location of the currently-active \#pragma clang + /// assume_nonnull begin. An invalid location ends the pragma. + void setPragmaAssumeNonNullLoc(SourceLocation Loc) { + PragmaAssumeNonNullLoc = Loc; + } + + /// Get the location of the recorded unterminated \#pragma clang + /// assume_nonnull begin in the preamble, if one exists. + /// + /// Returns an invalid location if the premable did not end with + /// such a pragma active or if there is no recorded preamble. + SourceLocation getPreambleRecordedPragmaAssumeNonNullLoc() const { + return PreambleRecordedPragmaAssumeNonNullLoc; + } + + /// Record the location of the unterminated \#pragma clang + /// assume_nonnull begin in the preamble. + void setPreambleRecordedPragmaAssumeNonNullLoc(SourceLocation Loc) { + PreambleRecordedPragmaAssumeNonNullLoc = Loc; + } + + /// Set the directory in which the main file should be considered + /// to have been found, if it is not a real file. + void setMainFileDir(const DirectoryEntry *Dir) { + MainFileDir = Dir; + } + + /// Instruct the preprocessor to skip part of the main source file. + /// + /// \param Bytes The number of bytes in the preamble to skip. + /// + /// \param StartOfLine Whether skipping these bytes puts the lexer at the + /// start of a line. + void setSkipMainFilePreamble(unsigned Bytes, bool StartOfLine) { + SkipMainFilePreamble.first = Bytes; + SkipMainFilePreamble.second = StartOfLine; + } + + /// Forwarding function for diagnostics. This emits a diagnostic at + /// the specified Token's location, translating the token's start + /// position in the current buffer into a SourcePosition object for rendering. + DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) const { + return Diags->Report(Loc, DiagID); + } + + DiagnosticBuilder Diag(const Token &Tok, unsigned DiagID) const { + return Diags->Report(Tok.getLocation(), DiagID); + } + + /// Return the 'spelling' of the token at the given + /// location; does not go up to the spelling location or down to the + /// expansion location. + /// + /// \param buffer A buffer which will be used only if the token requires + /// "cleaning", e.g. if it contains trigraphs or escaped newlines + /// \param invalid If non-null, will be set \c true if an error occurs. + StringRef getSpelling(SourceLocation loc, + SmallVectorImpl<char> &buffer, + bool *invalid = nullptr) const { + return Lexer::getSpelling(loc, buffer, SourceMgr, LangOpts, invalid); + } + + /// Return the 'spelling' of the Tok token. + /// + /// The spelling of a token is the characters used to represent the token in + /// the source file after trigraph expansion and escaped-newline folding. In + /// particular, this wants to get the true, uncanonicalized, spelling of + /// things like digraphs, UCNs, etc. + /// + /// \param Invalid If non-null, will be set \c true if an error occurs. + std::string getSpelling(const Token &Tok, bool *Invalid = nullptr) const { + return Lexer::getSpelling(Tok, SourceMgr, LangOpts, Invalid); + } + + /// Get the spelling of a token into a preallocated buffer, instead + /// of as an std::string. + /// + /// The caller is required to allocate enough space for the token, which is + /// guaranteed to be at least Tok.getLength() bytes long. The length of the + /// actual result is returned. + /// + /// Note that this method may do two possible things: it may either fill in + /// the buffer specified with characters, or it may *change the input pointer* + /// to point to a constant buffer with the data already in it (avoiding a + /// copy). The caller is not allowed to modify the returned buffer pointer + /// if an internal buffer is returned. + unsigned getSpelling(const Token &Tok, const char *&Buffer, + bool *Invalid = nullptr) const { + return Lexer::getSpelling(Tok, Buffer, SourceMgr, LangOpts, Invalid); + } + + /// Get the spelling of a token into a SmallVector. + /// + /// Note that the returned StringRef may not point to the + /// supplied buffer if a copy can be avoided. + StringRef getSpelling(const Token &Tok, + SmallVectorImpl<char> &Buffer, + bool *Invalid = nullptr) const; + + /// Relex the token at the specified location. + /// \returns true if there was a failure, false on success. + bool getRawToken(SourceLocation Loc, Token &Result, + bool IgnoreWhiteSpace = false) { + return Lexer::getRawToken(Loc, Result, SourceMgr, LangOpts, IgnoreWhiteSpace); + } + + /// Given a Token \p Tok that is a numeric constant with length 1, + /// return the character. + char + getSpellingOfSingleCharacterNumericConstant(const Token &Tok, + bool *Invalid = nullptr) const { + assert(Tok.is(tok::numeric_constant) && + Tok.getLength() == 1 && "Called on unsupported token"); + assert(!Tok.needsCleaning() && "Token can't need cleaning with length 1"); + + // If the token is carrying a literal data pointer, just use it. + if (const char *D = Tok.getLiteralData()) + return *D; + + // Otherwise, fall back on getCharacterData, which is slower, but always + // works. + return *SourceMgr.getCharacterData(Tok.getLocation(), Invalid); + } + + /// Retrieve the name of the immediate macro expansion. + /// + /// This routine starts from a source location, and finds the name of the + /// macro responsible for its immediate expansion. It looks through any + /// intervening macro argument expansions to compute this. It returns a + /// StringRef that refers to the SourceManager-owned buffer of the source + /// where that macro name is spelled. Thus, the result shouldn't out-live + /// the SourceManager. + StringRef getImmediateMacroName(SourceLocation Loc) { + return Lexer::getImmediateMacroName(Loc, SourceMgr, getLangOpts()); + } + + /// Plop the specified string into a scratch buffer and set the + /// specified token's location and length to it. + /// + /// If specified, the source location provides a location of the expansion + /// point of the token. + void CreateString(StringRef Str, Token &Tok, + SourceLocation ExpansionLocStart = SourceLocation(), + SourceLocation ExpansionLocEnd = SourceLocation()); + + /// Split the first Length characters out of the token starting at TokLoc + /// and return a location pointing to the split token. Re-lexing from the + /// split token will return the split token rather than the original. + SourceLocation SplitToken(SourceLocation TokLoc, unsigned Length); + + /// Computes the source location just past the end of the + /// token at this source location. + /// + /// This routine can be used to produce a source location that + /// points just past the end of the token referenced by \p Loc, and + /// is generally used when a diagnostic needs to point just after a + /// token where it expected something different that it received. If + /// the returned source location would not be meaningful (e.g., if + /// it points into a macro), this routine returns an invalid + /// source location. + /// + /// \param Offset an offset from the end of the token, where the source + /// location should refer to. The default offset (0) produces a source + /// location pointing just past the end of the token; an offset of 1 produces + /// a source location pointing to the last character in the token, etc. + SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset = 0) { + return Lexer::getLocForEndOfToken(Loc, Offset, SourceMgr, LangOpts); + } + + /// Returns true if the given MacroID location points at the first + /// token of the macro expansion. + /// + /// \param MacroBegin If non-null and function returns true, it is set to + /// begin location of the macro. + bool isAtStartOfMacroExpansion(SourceLocation loc, + SourceLocation *MacroBegin = nullptr) const { + return Lexer::isAtStartOfMacroExpansion(loc, SourceMgr, LangOpts, + MacroBegin); + } + + /// Returns true if the given MacroID location points at the last + /// token of the macro expansion. + /// + /// \param MacroEnd If non-null and function returns true, it is set to + /// end location of the macro. + bool isAtEndOfMacroExpansion(SourceLocation loc, + SourceLocation *MacroEnd = nullptr) const { + return Lexer::isAtEndOfMacroExpansion(loc, SourceMgr, LangOpts, MacroEnd); + } + + /// Print the token to stderr, used for debugging. + void DumpToken(const Token &Tok, bool DumpFlags = false) const; + void DumpLocation(SourceLocation Loc) const; + void DumpMacro(const MacroInfo &MI) const; + void dumpMacroInfo(const IdentifierInfo *II); + + /// Given a location that specifies the start of a + /// token, return a new location that specifies a character within the token. + SourceLocation AdvanceToTokenCharacter(SourceLocation TokStart, + unsigned Char) const { + return Lexer::AdvanceToTokenCharacter(TokStart, Char, SourceMgr, LangOpts); + } + + /// Increment the counters for the number of token paste operations + /// performed. + /// + /// If fast was specified, this is a 'fast paste' case we handled. + void IncrementPasteCounter(bool isFast) { + if (isFast) + ++NumFastTokenPaste; + else + ++NumTokenPaste; + } + + void PrintStats(); + + size_t getTotalMemory() const; + + /// When the macro expander pastes together a comment (/##/) in Microsoft + /// mode, this method handles updating the current state, returning the + /// token on the next source line. + void HandleMicrosoftCommentPaste(Token &Tok); + + //===--------------------------------------------------------------------===// + // Preprocessor callback methods. These are invoked by a lexer as various + // directives and events are found. + + /// Given a tok::raw_identifier token, look up the + /// identifier information for the token and install it into the token, + /// updating the token kind accordingly. + IdentifierInfo *LookUpIdentifierInfo(Token &Identifier) const; + +private: + llvm::DenseMap<IdentifierInfo*,unsigned> PoisonReasons; + +public: + /// Specifies the reason for poisoning an identifier. + /// + /// If that identifier is accessed while poisoned, then this reason will be + /// used instead of the default "poisoned" diagnostic. + void SetPoisonReason(IdentifierInfo *II, unsigned DiagID); + + /// Display reason for poisoned identifier. + void HandlePoisonedIdentifier(Token & Identifier); + + void MaybeHandlePoisonedIdentifier(Token & Identifier) { + if(IdentifierInfo * II = Identifier.getIdentifierInfo()) { + if(II->isPoisoned()) { + HandlePoisonedIdentifier(Identifier); + } + } + } + +private: + /// Identifiers used for SEH handling in Borland. These are only + /// allowed in particular circumstances + // __except block + IdentifierInfo *Ident__exception_code, + *Ident___exception_code, + *Ident_GetExceptionCode; + // __except filter expression + IdentifierInfo *Ident__exception_info, + *Ident___exception_info, + *Ident_GetExceptionInfo; + // __finally + IdentifierInfo *Ident__abnormal_termination, + *Ident___abnormal_termination, + *Ident_AbnormalTermination; + + const char *getCurLexerEndPos(); + void diagnoseMissingHeaderInUmbrellaDir(const Module &Mod); + +public: + void PoisonSEHIdentifiers(bool Poison = true); // Borland + + /// Callback invoked when the lexer reads an identifier and has + /// filled in the tokens IdentifierInfo member. + /// + /// This callback potentially macro expands it or turns it into a named + /// token (like 'for'). + /// + /// \returns true if we actually computed a token, false if we need to + /// lex again. + bool HandleIdentifier(Token &Identifier); + + /// Callback invoked when the lexer hits the end of the current file. + /// + /// This either returns the EOF token and returns true, or + /// pops a level off the include stack and returns false, at which point the + /// client should call lex again. + bool HandleEndOfFile(Token &Result, bool isEndOfMacro = false); + + /// Callback invoked when the current TokenLexer hits the end of its + /// token stream. + bool HandleEndOfTokenLexer(Token &Result); + + /// Callback invoked when the lexer sees a # token at the start of a + /// line. + /// + /// This consumes the directive, modifies the lexer/preprocessor state, and + /// advances the lexer(s) so that the next token read is the correct one. + void HandleDirective(Token &Result); + + /// Ensure that the next token is a tok::eod token. + /// + /// If not, emit a diagnostic and consume up until the eod. + /// If \p EnableMacros is true, then we consider macros that expand to zero + /// tokens as being ok. + /// + /// \return The location of the end of the directive (the terminating + /// newline). + SourceLocation CheckEndOfDirective(const char *DirType, + bool EnableMacros = false); + + /// Read and discard all tokens remaining on the current line until + /// the tok::eod token is found. Returns the range of the skipped tokens. + SourceRange DiscardUntilEndOfDirective(); + + /// Returns true if the preprocessor has seen a use of + /// __DATE__ or __TIME__ in the file so far. + bool SawDateOrTime() const { + return DATELoc != SourceLocation() || TIMELoc != SourceLocation(); + } + unsigned getCounterValue() const { return CounterValue; } + void setCounterValue(unsigned V) { CounterValue = V; } + + LangOptions::FPEvalMethodKind getCurrentFPEvalMethod() const { + assert(CurrentFPEvalMethod != LangOptions::FEM_UnsetOnCommandLine && + "FPEvalMethod should be set either from command line or from the " + "target info"); + return CurrentFPEvalMethod; + } + + LangOptions::FPEvalMethodKind getTUFPEvalMethod() const { + return TUFPEvalMethod; + } + + SourceLocation getLastFPEvalPragmaLocation() const { + return LastFPEvalPragmaLocation; + } + + void setCurrentFPEvalMethod(SourceLocation PragmaLoc, + LangOptions::FPEvalMethodKind Val) { + assert(Val != LangOptions::FEM_UnsetOnCommandLine && + "FPEvalMethod should never be set to FEM_UnsetOnCommandLine"); + // This is the location of the '#pragma float_control" where the + // execution state is modifed. + LastFPEvalPragmaLocation = PragmaLoc; + CurrentFPEvalMethod = Val; + TUFPEvalMethod = Val; + } + + void setTUFPEvalMethod(LangOptions::FPEvalMethodKind Val) { + assert(Val != LangOptions::FEM_UnsetOnCommandLine && + "TUPEvalMethod should never be set to FEM_UnsetOnCommandLine"); + TUFPEvalMethod = Val; + } + + /// Retrieves the module that we're currently building, if any. + Module *getCurrentModule(); + + /// Retrieves the module whose implementation we're current compiling, if any. + Module *getCurrentModuleImplementation(); + + /// If we are preprocessing a named module. + bool isInNamedModule() const { return ModuleDeclState.isNamedModule(); } + + /// If we are proprocessing a named interface unit. + /// Note that a module implementation partition is not considered as an + /// named interface unit here although it is importable + /// to ease the parsing. + bool isInNamedInterfaceUnit() const { + return ModuleDeclState.isNamedInterface(); + } + + /// Get the named module name we're preprocessing. + /// Requires we're preprocessing a named module. + StringRef getNamedModuleName() const { return ModuleDeclState.getName(); } + + /// If we are implementing an implementation module unit. + /// Note that the module implementation partition is not considered as an + /// implementation unit. + bool isInImplementationUnit() const { + return ModuleDeclState.isImplementationUnit(); + } + + /// If we're importing a standard C++20 Named Modules. + bool isInImportingCXXNamedModules() const { + // NamedModuleImportPath will be non-empty only if we're importing + // Standard C++ named modules. + return !NamedModuleImportPath.empty() && getLangOpts().CPlusPlusModules && + !IsAtImport; + } + + /// Allocate a new MacroInfo object with the provided SourceLocation. + MacroInfo *AllocateMacroInfo(SourceLocation L); + + /// Turn the specified lexer token into a fully checked and spelled + /// filename, e.g. as an operand of \#include. + /// + /// The caller is expected to provide a buffer that is large enough to hold + /// the spelling of the filename, but is also expected to handle the case + /// when this method decides to use a different buffer. + /// + /// \returns true if the input filename was in <>'s or false if it was + /// in ""'s. + bool GetIncludeFilenameSpelling(SourceLocation Loc,StringRef &Buffer); + + /// Given a "foo" or \<foo> reference, look up the indicated file. + /// + /// Returns std::nullopt on failure. \p isAngled indicates whether the file + /// reference is for system \#include's or not (i.e. using <> instead of ""). + OptionalFileEntryRef + LookupFile(SourceLocation FilenameLoc, StringRef Filename, bool isAngled, + ConstSearchDirIterator FromDir, const FileEntry *FromFile, + ConstSearchDirIterator *CurDir, SmallVectorImpl<char> *SearchPath, + SmallVectorImpl<char> *RelativePath, + ModuleMap::KnownHeader *SuggestedModule, bool *IsMapped, + bool *IsFrameworkFound, bool SkipCache = false, + bool OpenFile = true, bool CacheFailures = true); + + /// Return true if we're in the top-level file, not in a \#include. + bool isInPrimaryFile() const; + + /// Lex an on-off-switch (C99 6.10.6p2) and verify that it is + /// followed by EOD. Return true if the token is not a valid on-off-switch. + bool LexOnOffSwitch(tok::OnOffSwitch &Result); + + bool CheckMacroName(Token &MacroNameTok, MacroUse isDefineUndef, + bool *ShadowFlag = nullptr); + + void EnterSubmodule(Module *M, SourceLocation ImportLoc, bool ForPragma); + Module *LeaveSubmodule(bool ForPragma); + +private: + friend void TokenLexer::ExpandFunctionArguments(); + + void PushIncludeMacroStack() { + assert(CurLexerKind != CLK_CachingLexer && "cannot push a caching lexer"); + IncludeMacroStack.emplace_back(CurLexerKind, CurLexerSubmodule, + std::move(CurLexer), CurPPLexer, + std::move(CurTokenLexer), CurDirLookup); + CurPPLexer = nullptr; + } + + void PopIncludeMacroStack() { + CurLexer = std::move(IncludeMacroStack.back().TheLexer); + CurPPLexer = IncludeMacroStack.back().ThePPLexer; + CurTokenLexer = std::move(IncludeMacroStack.back().TheTokenLexer); + CurDirLookup = IncludeMacroStack.back().TheDirLookup; + CurLexerSubmodule = IncludeMacroStack.back().TheSubmodule; + CurLexerKind = IncludeMacroStack.back().CurLexerKind; + IncludeMacroStack.pop_back(); + } + + void PropagateLineStartLeadingSpaceInfo(Token &Result); + + /// Determine whether we need to create module macros for #defines in the + /// current context. + bool needModuleMacros() const; + + /// Update the set of active module macros and ambiguity flag for a module + /// macro name. + void updateModuleMacroInfo(const IdentifierInfo *II, ModuleMacroInfo &Info); + + DefMacroDirective *AllocateDefMacroDirective(MacroInfo *MI, + SourceLocation Loc); + UndefMacroDirective *AllocateUndefMacroDirective(SourceLocation UndefLoc); + VisibilityMacroDirective *AllocateVisibilityMacroDirective(SourceLocation Loc, + bool isPublic); + + /// Lex and validate a macro name, which occurs after a + /// \#define or \#undef. + /// + /// \param MacroNameTok Token that represents the name defined or undefined. + /// \param IsDefineUndef Kind if preprocessor directive. + /// \param ShadowFlag Points to flag that is set if macro name shadows + /// a keyword. + /// + /// This emits a diagnostic, sets the token kind to eod, + /// and discards the rest of the macro line if the macro name is invalid. + void ReadMacroName(Token &MacroNameTok, MacroUse IsDefineUndef = MU_Other, + bool *ShadowFlag = nullptr); + + /// ReadOptionalMacroParameterListAndBody - This consumes all (i.e. the + /// entire line) of the macro's tokens and adds them to MacroInfo, and while + /// doing so performs certain validity checks including (but not limited to): + /// - # (stringization) is followed by a macro parameter + /// \param MacroNameTok - Token that represents the macro name + /// \param ImmediatelyAfterHeaderGuard - Macro follows an #ifdef header guard + /// + /// Either returns a pointer to a MacroInfo object OR emits a diagnostic and + /// returns a nullptr if an invalid sequence of tokens is encountered. + MacroInfo *ReadOptionalMacroParameterListAndBody( + const Token &MacroNameTok, bool ImmediatelyAfterHeaderGuard); + + /// The ( starting an argument list of a macro definition has just been read. + /// Lex the rest of the parameters and the closing ), updating \p MI with + /// what we learn and saving in \p LastTok the last token read. + /// Return true if an error occurs parsing the arg list. + bool ReadMacroParameterList(MacroInfo *MI, Token& LastTok); + + /// Provide a suggestion for a typoed directive. If there is no typo, then + /// just skip suggesting. + /// + /// \param Tok - Token that represents the directive + /// \param Directive - String reference for the directive name + void SuggestTypoedDirective(const Token &Tok, StringRef Directive) const; + + /// We just read a \#if or related directive and decided that the + /// subsequent tokens are in the \#if'd out portion of the + /// file. Lex the rest of the file, until we see an \#endif. If \p + /// FoundNonSkipPortion is true, then we have already emitted code for part of + /// this \#if directive, so \#else/\#elif blocks should never be entered. If + /// \p FoundElse is false, then \#else directives are ok, if not, then we have + /// already seen one so a \#else directive is a duplicate. When this returns, + /// the caller can lex the first valid token. + void SkipExcludedConditionalBlock(SourceLocation HashTokenLoc, + SourceLocation IfTokenLoc, + bool FoundNonSkipPortion, bool FoundElse, + SourceLocation ElseLoc = SourceLocation()); + + /// Information about the result for evaluating an expression for a + /// preprocessor directive. + struct DirectiveEvalResult { + /// Whether the expression was evaluated as true or not. + bool Conditional; + + /// True if the expression contained identifiers that were undefined. + bool IncludedUndefinedIds; + + /// The source range for the expression. + SourceRange ExprRange; + }; + + /// Evaluate an integer constant expression that may occur after a + /// \#if or \#elif directive and return a \p DirectiveEvalResult object. + /// + /// If the expression is equivalent to "!defined(X)" return X in IfNDefMacro. + DirectiveEvalResult EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro); + + /// Process a '__has_include("path")' expression. + /// + /// Returns true if successful. + bool EvaluateHasInclude(Token &Tok, IdentifierInfo *II); + + /// Process '__has_include_next("path")' expression. + /// + /// Returns true if successful. + bool EvaluateHasIncludeNext(Token &Tok, IdentifierInfo *II); + + /// Get the directory and file from which to start \#include_next lookup. + std::pair<ConstSearchDirIterator, const FileEntry *> + getIncludeNextStart(const Token &IncludeNextTok) const; + + /// Install the standard preprocessor pragmas: + /// \#pragma GCC poison/system_header/dependency and \#pragma once. + void RegisterBuiltinPragmas(); + + /// Register builtin macros such as __LINE__ with the identifier table. + void RegisterBuiltinMacros(); + + /// If an identifier token is read that is to be expanded as a macro, handle + /// it and return the next token as 'Tok'. If we lexed a token, return true; + /// otherwise the caller should lex again. + bool HandleMacroExpandedIdentifier(Token &Identifier, const MacroDefinition &MD); + + /// Cache macro expanded tokens for TokenLexers. + // + /// Works like a stack; a TokenLexer adds the macro expanded tokens that is + /// going to lex in the cache and when it finishes the tokens are removed + /// from the end of the cache. + Token *cacheMacroExpandedTokens(TokenLexer *tokLexer, + ArrayRef<Token> tokens); + + void removeCachedMacroExpandedTokensOfLastLexer(); + + /// Determine whether the next preprocessor token to be + /// lexed is a '('. If so, consume the token and return true, if not, this + /// method should have no observable side-effect on the lexed tokens. + bool isNextPPTokenLParen(); + + /// After reading "MACRO(", this method is invoked to read all of the formal + /// arguments specified for the macro invocation. Returns null on error. + MacroArgs *ReadMacroCallArgumentList(Token &MacroName, MacroInfo *MI, + SourceLocation &MacroEnd); + + /// If an identifier token is read that is to be expanded + /// as a builtin macro, handle it and return the next token as 'Tok'. + void ExpandBuiltinMacro(Token &Tok); + + /// Read a \c _Pragma directive, slice it up, process it, then + /// return the first token after the directive. + /// This assumes that the \c _Pragma token has just been read into \p Tok. + void Handle_Pragma(Token &Tok); + + /// Like Handle_Pragma except the pragma text is not enclosed within + /// a string literal. + void HandleMicrosoft__pragma(Token &Tok); + + /// Add a lexer to the top of the include stack and + /// start lexing tokens from it instead of the current buffer. + void EnterSourceFileWithLexer(Lexer *TheLexer, ConstSearchDirIterator Dir); + + /// Set the FileID for the preprocessor predefines. + void setPredefinesFileID(FileID FID) { + assert(PredefinesFileID.isInvalid() && "PredefinesFileID already set!"); + PredefinesFileID = FID; + } + + /// Set the FileID for the PCH through header. + void setPCHThroughHeaderFileID(FileID FID); + + /// Returns true if we are lexing from a file and not a + /// pragma or a macro. + static bool IsFileLexer(const Lexer* L, const PreprocessorLexer* P) { + return L ? !L->isPragmaLexer() : P != nullptr; + } + + static bool IsFileLexer(const IncludeStackInfo& I) { + return IsFileLexer(I.TheLexer.get(), I.ThePPLexer); + } + + bool IsFileLexer() const { + return IsFileLexer(CurLexer.get(), CurPPLexer); + } + + //===--------------------------------------------------------------------===// + // Caching stuff. + void CachingLex(Token &Result); + + bool InCachingLexMode() const { + // If the Lexer pointers are 0 and IncludeMacroStack is empty, it means + // that we are past EOF, not that we are in CachingLex mode. + return !CurPPLexer && !CurTokenLexer && !IncludeMacroStack.empty(); + } + + void EnterCachingLexMode(); + void EnterCachingLexModeUnchecked(); + + void ExitCachingLexMode() { + if (InCachingLexMode()) + RemoveTopOfLexerStack(); + } + + const Token &PeekAhead(unsigned N); + void AnnotatePreviousCachedTokens(const Token &Tok); + + //===--------------------------------------------------------------------===// + /// Handle*Directive - implement the various preprocessor directives. These + /// should side-effect the current preprocessor object so that the next call + /// to Lex() will return the appropriate token next. + void HandleLineDirective(); + void HandleDigitDirective(Token &Tok); + void HandleUserDiagnosticDirective(Token &Tok, bool isWarning); + void HandleIdentSCCSDirective(Token &Tok); + void HandleMacroPublicDirective(Token &Tok); + void HandleMacroPrivateDirective(); + + /// An additional notification that can be produced by a header inclusion or + /// import to tell the parser what happened. + struct ImportAction { + enum ActionKind { + None, + ModuleBegin, + ModuleImport, + HeaderUnitImport, + SkippedModuleImport, + Failure, + } Kind; + Module *ModuleForHeader = nullptr; + + ImportAction(ActionKind AK, Module *Mod = nullptr) + : Kind(AK), ModuleForHeader(Mod) { + assert((AK == None || Mod || AK == Failure) && + "no module for module action"); + } + }; + + OptionalFileEntryRef LookupHeaderIncludeOrImport( + ConstSearchDirIterator *CurDir, StringRef &Filename, + SourceLocation FilenameLoc, CharSourceRange FilenameRange, + const Token &FilenameTok, bool &IsFrameworkFound, bool IsImportDecl, + bool &IsMapped, ConstSearchDirIterator LookupFrom, + const FileEntry *LookupFromFile, StringRef &LookupFilename, + SmallVectorImpl<char> &RelativePath, SmallVectorImpl<char> &SearchPath, + ModuleMap::KnownHeader &SuggestedModule, bool isAngled); + + // File inclusion. + void HandleIncludeDirective(SourceLocation HashLoc, Token &Tok, + ConstSearchDirIterator LookupFrom = nullptr, + const FileEntry *LookupFromFile = nullptr); + ImportAction + HandleHeaderIncludeOrImport(SourceLocation HashLoc, Token &IncludeTok, + Token &FilenameTok, SourceLocation EndLoc, + ConstSearchDirIterator LookupFrom = nullptr, + const FileEntry *LookupFromFile = nullptr); + void HandleIncludeNextDirective(SourceLocation HashLoc, Token &Tok); + void HandleIncludeMacrosDirective(SourceLocation HashLoc, Token &Tok); + void HandleImportDirective(SourceLocation HashLoc, Token &Tok); + void HandleMicrosoftImportDirective(Token &Tok); + +public: + /// Check that the given module is available, producing a diagnostic if not. + /// \return \c true if the check failed (because the module is not available). + /// \c false if the module appears to be usable. + static bool checkModuleIsAvailable(const LangOptions &LangOpts, + const TargetInfo &TargetInfo, + DiagnosticsEngine &Diags, Module *M); + + // Module inclusion testing. + /// Find the module that owns the source or header file that + /// \p Loc points to. If the location is in a file that was included + /// into a module, or is outside any module, returns nullptr. + Module *getModuleForLocation(SourceLocation Loc, bool AllowTextual); + + /// We want to produce a diagnostic at location IncLoc concerning an + /// unreachable effect at location MLoc (eg, where a desired entity was + /// declared or defined). Determine whether the right way to make MLoc + /// reachable is by #include, and if so, what header should be included. + /// + /// This is not necessarily fast, and might load unexpected module maps, so + /// should only be called by code that intends to produce an error. + /// + /// \param IncLoc The location at which the missing effect was detected. + /// \param MLoc A location within an unimported module at which the desired + /// effect occurred. + /// \return A file that can be #included to provide the desired effect. Null + /// if no such file could be determined or if a #include is not + /// appropriate (eg, if a module should be imported instead). + const FileEntry *getHeaderToIncludeForDiagnostics(SourceLocation IncLoc, + SourceLocation MLoc); + + bool isRecordingPreamble() const { + return PreambleConditionalStack.isRecording(); + } + + bool hasRecordedPreamble() const { + return PreambleConditionalStack.hasRecordedPreamble(); + } + + ArrayRef<PPConditionalInfo> getPreambleConditionalStack() const { + return PreambleConditionalStack.getStack(); + } + + void setRecordedPreambleConditionalStack(ArrayRef<PPConditionalInfo> s) { + PreambleConditionalStack.setStack(s); + } + + void setReplayablePreambleConditionalStack( + ArrayRef<PPConditionalInfo> s, std::optional<PreambleSkipInfo> SkipInfo) { + PreambleConditionalStack.startReplaying(); + PreambleConditionalStack.setStack(s); + PreambleConditionalStack.SkipInfo = SkipInfo; + } + + std::optional<PreambleSkipInfo> getPreambleSkipInfo() const { + return PreambleConditionalStack.SkipInfo; + } + +private: + /// After processing predefined file, initialize the conditional stack from + /// the preamble. + void replayPreambleConditionalStack(); + + // Macro handling. + void HandleDefineDirective(Token &Tok, bool ImmediatelyAfterHeaderGuard); + void HandleUndefDirective(); + + // Conditional Inclusion. + void HandleIfdefDirective(Token &Result, const Token &HashToken, + bool isIfndef, bool ReadAnyTokensBeforeDirective); + void HandleIfDirective(Token &IfToken, const Token &HashToken, + bool ReadAnyTokensBeforeDirective); + void HandleEndifDirective(Token &EndifToken); + void HandleElseDirective(Token &Result, const Token &HashToken); + void HandleElifFamilyDirective(Token &ElifToken, const Token &HashToken, + tok::PPKeywordKind Kind); + + // Pragmas. + void HandlePragmaDirective(PragmaIntroducer Introducer); + +public: + void HandlePragmaOnce(Token &OnceTok); + void HandlePragmaMark(Token &MarkTok); + void HandlePragmaPoison(); + void HandlePragmaSystemHeader(Token &SysHeaderTok); + void HandlePragmaDependency(Token &DependencyTok); + void HandlePragmaPushMacro(Token &Tok); + void HandlePragmaPopMacro(Token &Tok); + void HandlePragmaIncludeAlias(Token &Tok); + void HandlePragmaModuleBuild(Token &Tok); + void HandlePragmaHdrstop(Token &Tok); + IdentifierInfo *ParsePragmaPushOrPopMacro(Token &Tok); + + // Return true and store the first token only if any CommentHandler + // has inserted some tokens and getCommentRetentionState() is false. + bool HandleComment(Token &result, SourceRange Comment); + + /// A macro is used, update information about macros that need unused + /// warnings. + void markMacroAsUsed(MacroInfo *MI); + + void addMacroDeprecationMsg(const IdentifierInfo *II, std::string Msg, + SourceLocation AnnotationLoc) { + auto Annotations = AnnotationInfos.find(II); + if (Annotations == AnnotationInfos.end()) + AnnotationInfos.insert(std::make_pair( + II, + MacroAnnotations::makeDeprecation(AnnotationLoc, std::move(Msg)))); + else + Annotations->second.DeprecationInfo = + MacroAnnotationInfo{AnnotationLoc, std::move(Msg)}; + } + + void addRestrictExpansionMsg(const IdentifierInfo *II, std::string Msg, + SourceLocation AnnotationLoc) { + auto Annotations = AnnotationInfos.find(II); + if (Annotations == AnnotationInfos.end()) + AnnotationInfos.insert( + std::make_pair(II, MacroAnnotations::makeRestrictExpansion( + AnnotationLoc, std::move(Msg)))); + else + Annotations->second.RestrictExpansionInfo = + MacroAnnotationInfo{AnnotationLoc, std::move(Msg)}; + } + + void addFinalLoc(const IdentifierInfo *II, SourceLocation AnnotationLoc) { + auto Annotations = AnnotationInfos.find(II); + if (Annotations == AnnotationInfos.end()) + AnnotationInfos.insert( + std::make_pair(II, MacroAnnotations::makeFinal(AnnotationLoc))); + else + Annotations->second.FinalAnnotationLoc = AnnotationLoc; + } + + const MacroAnnotations &getMacroAnnotations(const IdentifierInfo *II) const { + return AnnotationInfos.find(II)->second; + } + + void emitMacroExpansionWarnings(const Token &Identifier) const { + if (Identifier.getIdentifierInfo()->isDeprecatedMacro()) + emitMacroDeprecationWarning(Identifier); + + if (Identifier.getIdentifierInfo()->isRestrictExpansion() && + !SourceMgr.isInMainFile(Identifier.getLocation())) + emitRestrictExpansionWarning(Identifier); + } + + static void processPathForFileMacro(SmallVectorImpl<char> &Path, + const LangOptions &LangOpts, + const TargetInfo &TI); + +private: + void emitMacroDeprecationWarning(const Token &Identifier) const; + void emitRestrictExpansionWarning(const Token &Identifier) const; + void emitFinalMacroWarning(const Token &Identifier, bool IsUndef) const; +}; + +/// Abstract base class that describes a handler that will receive +/// source ranges for each of the comments encountered in the source file. +class CommentHandler { +public: + virtual ~CommentHandler(); + + // The handler shall return true if it has pushed any tokens + // to be read using e.g. EnterToken or EnterTokenStream. + virtual bool HandleComment(Preprocessor &PP, SourceRange Comment) = 0; +}; + +/// Abstract base class that describes a handler that will receive +/// source ranges for empty lines encountered in the source file. +class EmptylineHandler { +public: + virtual ~EmptylineHandler(); + + // The handler handles empty lines. + virtual void HandleEmptyline(SourceRange Range) = 0; +}; + +/// Registry of pragma handlers added by plugins +using PragmaHandlerRegistry = llvm::Registry<PragmaHandler>; + +} // namespace clang + +#endif // LLVM_CLANG_LEX_PREPROCESSOR_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Lex/PreprocessorLexer.h b/contrib/libs/clang16/include/clang/Lex/PreprocessorLexer.h new file mode 100644 index 0000000000..a97d0f0926 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Lex/PreprocessorLexer.h @@ -0,0 +1,194 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- PreprocessorLexer.h - C Language Family Lexer ------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +/// \file +/// Defines the PreprocessorLexer interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_PREPROCESSORLEXER_H +#define LLVM_CLANG_LEX_PREPROCESSORLEXER_H + +#include "clang/Basic/FileEntry.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/MultipleIncludeOpt.h" +#include "clang/Lex/Token.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" +#include <cassert> + +namespace clang { + +class FileEntry; +class Preprocessor; + +class PreprocessorLexer { + virtual void anchor(); + +protected: + friend class Preprocessor; + + // Preprocessor object controlling lexing. + Preprocessor *PP = nullptr; + + /// The SourceManager FileID corresponding to the file being lexed. + const FileID FID; + + /// Number of SLocEntries before lexing the file. + unsigned InitialNumSLocEntries = 0; + + //===--------------------------------------------------------------------===// + // Context-specific lexing flags set by the preprocessor. + //===--------------------------------------------------------------------===// + + /// True when parsing \#XXX; turns '\\n' into a tok::eod token. + bool ParsingPreprocessorDirective = false; + + /// True after \#include; turns \<xx> or "xxx" into a tok::header_name token. + bool ParsingFilename = false; + + /// True if in raw mode. + /// + /// Raw mode disables interpretation of tokens and is a far faster mode to + /// lex in than non-raw-mode. This flag: + /// 1. If EOF of the current lexer is found, the include stack isn't popped. + /// 2. Identifier information is not looked up for identifier tokens. As an + /// effect of this, implicit macro expansion is naturally disabled. + /// 3. "#" tokens at the start of a line are treated as normal tokens, not + /// implicitly transformed by the lexer. + /// 4. All diagnostic messages are disabled. + /// 5. No callbacks are made into the preprocessor. + /// + /// Note that in raw mode that the PP pointer may be null. + bool LexingRawMode = false; + + /// A state machine that detects the \#ifndef-wrapping a file + /// idiom for the multiple-include optimization. + MultipleIncludeOpt MIOpt; + + /// Information about the set of \#if/\#ifdef/\#ifndef blocks + /// we are currently in. + SmallVector<PPConditionalInfo, 4> ConditionalStack; + + PreprocessorLexer() : FID() {} + PreprocessorLexer(Preprocessor *pp, FileID fid); + virtual ~PreprocessorLexer() = default; + + virtual void IndirectLex(Token& Result) = 0; + + /// Return the source location for the next observable location. + virtual SourceLocation getSourceLocation() = 0; + + //===--------------------------------------------------------------------===// + // #if directive handling. + + /// pushConditionalLevel - When we enter a \#if directive, this keeps track of + /// what we are currently in for diagnostic emission (e.g. \#if with missing + /// \#endif). + void pushConditionalLevel(SourceLocation DirectiveStart, bool WasSkipping, + bool FoundNonSkip, bool FoundElse) { + PPConditionalInfo CI; + CI.IfLoc = DirectiveStart; + CI.WasSkipping = WasSkipping; + CI.FoundNonSkip = FoundNonSkip; + CI.FoundElse = FoundElse; + ConditionalStack.push_back(CI); + } + void pushConditionalLevel(const PPConditionalInfo &CI) { + ConditionalStack.push_back(CI); + } + + /// popConditionalLevel - Remove an entry off the top of the conditional + /// stack, returning information about it. If the conditional stack is empty, + /// this returns true and does not fill in the arguments. + bool popConditionalLevel(PPConditionalInfo &CI) { + if (ConditionalStack.empty()) + return true; + CI = ConditionalStack.pop_back_val(); + return false; + } + + /// Return the top of the conditional stack. + /// \pre This requires that there be a conditional active. + PPConditionalInfo &peekConditionalLevel() { + assert(!ConditionalStack.empty() && "No conditionals active!"); + return ConditionalStack.back(); + } + + unsigned getConditionalStackDepth() const { return ConditionalStack.size(); } + +public: + PreprocessorLexer(const PreprocessorLexer &) = delete; + PreprocessorLexer &operator=(const PreprocessorLexer &) = delete; + + //===--------------------------------------------------------------------===// + // Misc. lexing methods. + + /// Lex a token, producing a header-name token if possible. + void LexIncludeFilename(Token &FilenameTok); + + /// Inform the lexer whether or not we are currently lexing a + /// preprocessor directive. + void setParsingPreprocessorDirective(bool f) { + ParsingPreprocessorDirective = f; + } + + /// Return true if this lexer is in raw mode or not. + bool isLexingRawMode() const { return LexingRawMode; } + + /// Return the preprocessor object for this lexer. + Preprocessor *getPP() const { return PP; } + + FileID getFileID() const { + assert(PP && + "PreprocessorLexer::getFileID() should only be used with a Preprocessor"); + return FID; + } + + /// Number of SLocEntries before lexing the file. + unsigned getInitialNumSLocEntries() const { + return InitialNumSLocEntries; + } + + /// getFileEntry - Return the FileEntry corresponding to this FileID. Like + /// getFileID(), this only works for lexers with attached preprocessors. + OptionalFileEntryRefDegradesToFileEntryPtr getFileEntry() const; + + /// Iterator that traverses the current stack of preprocessor + /// conditional directives (\#if/\#ifdef/\#ifndef). + using conditional_iterator = + SmallVectorImpl<PPConditionalInfo>::const_iterator; + + conditional_iterator conditional_begin() const { + return ConditionalStack.begin(); + } + + conditional_iterator conditional_end() const { + return ConditionalStack.end(); + } + + void setConditionalLevels(ArrayRef<PPConditionalInfo> CL) { + ConditionalStack.clear(); + ConditionalStack.append(CL.begin(), CL.end()); + } +}; + +} // namespace clang + +#endif // LLVM_CLANG_LEX_PREPROCESSORLEXER_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Lex/PreprocessorOptions.h b/contrib/libs/clang16/include/clang/Lex/PreprocessorOptions.h new file mode 100644 index 0000000000..205d7762e8 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Lex/PreprocessorOptions.h @@ -0,0 +1,280 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- PreprocessorOptions.h ------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_PREPROCESSOROPTIONS_H_ +#define LLVM_CLANG_LEX_PREPROCESSOROPTIONS_H_ + +#include "clang/Basic/BitmaskEnum.h" +#include "clang/Basic/FileEntry.h" +#include "clang/Basic/LLVM.h" +#include "clang/Lex/DependencyDirectivesScanner.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSet.h" +#include <functional> +#include <map> +#include <memory> +#include <optional> +#include <set> +#include <string> +#include <utility> +#include <vector> + +namespace llvm { + +class MemoryBuffer; + +} // namespace llvm + +namespace clang { + +/// Enumerate the kinds of standard library that +enum ObjCXXARCStandardLibraryKind { + ARCXX_nolib, + + /// libc++ + ARCXX_libcxx, + + /// libstdc++ + ARCXX_libstdcxx +}; + +/// Whether to disable the normal validation performed on precompiled +/// headers and module files when they are loaded. +enum class DisableValidationForModuleKind { + /// Perform validation, don't disable it. + None = 0, + + /// Disable validation for a precompiled header and the modules it depends on. + PCH = 0x1, + + /// Disable validation for module files. + Module = 0x2, + + /// Disable validation for all kinds. + All = PCH | Module, + + LLVM_MARK_AS_BITMASK_ENUM(Module) +}; + +/// PreprocessorOptions - This class is used for passing the various options +/// used in preprocessor initialization to InitializePreprocessor(). +class PreprocessorOptions { +public: + std::vector<std::pair<std::string, bool/*isUndef*/>> Macros; + std::vector<std::string> Includes; + std::vector<std::string> MacroIncludes; + + /// Initialize the preprocessor with the compiler and target specific + /// predefines. + bool UsePredefines = true; + + /// Whether we should maintain a detailed record of all macro + /// definitions and expansions. + bool DetailedRecord = false; + + /// When true, we are creating or using a PCH where a #pragma hdrstop is + /// expected to indicate the beginning or end of the PCH. + bool PCHWithHdrStop = false; + + /// When true, we are creating a PCH or creating the PCH object while + /// expecting a #pragma hdrstop to separate the two. Allow for a + /// missing #pragma hdrstop, which generates a PCH for the whole file, + /// and creates an empty PCH object. + bool PCHWithHdrStopCreate = false; + + /// If non-empty, the filename used in an #include directive in the primary + /// source file (or command-line preinclude) that is used to implement + /// MSVC-style precompiled headers. When creating a PCH, after the #include + /// of this header, the PCH generation stops. When using a PCH, tokens are + /// skipped until after an #include of this header is seen. + std::string PCHThroughHeader; + + /// The implicit PCH included at the start of the translation unit, or empty. + std::string ImplicitPCHInclude; + + /// Headers that will be converted to chained PCHs in memory. + std::vector<std::string> ChainedIncludes; + + /// Whether to disable most of the normal validation performed on + /// precompiled headers and module files. + DisableValidationForModuleKind DisablePCHOrModuleValidation = + DisableValidationForModuleKind::None; + + /// When true, a PCH with compiler errors will not be rejected. + bool AllowPCHWithCompilerErrors = false; + + /// When true, a PCH with modules cache path different to the current + /// compilation will not be rejected. + bool AllowPCHWithDifferentModulesCachePath = false; + + /// Dump declarations that are deserialized from PCH, for testing. + bool DumpDeserializedPCHDecls = false; + + /// This is a set of names for decls that we do not want to be + /// deserialized, and we emit an error if they are; for testing purposes. + std::set<std::string> DeserializedPCHDeclsToErrorOn; + + /// If non-zero, the implicit PCH include is actually a precompiled + /// preamble that covers this number of bytes in the main source file. + /// + /// The boolean indicates whether the preamble ends at the start of a new + /// line. + std::pair<unsigned, bool> PrecompiledPreambleBytes; + + /// True indicates that a preamble is being generated. + /// + /// When the lexer is done, one of the things that need to be preserved is the + /// conditional #if stack, so the ASTWriter/ASTReader can save/restore it when + /// processing the rest of the file. Similarly, we track an unterminated + /// #pragma assume_nonnull. + bool GeneratePreamble = false; + + /// Whether to write comment locations into the PCH when building it. + /// Reading the comments from the PCH can be a performance hit even if the + /// clients don't use them. + bool WriteCommentListToPCH = true; + + /// When enabled, preprocessor is in a mode for parsing a single file only. + /// + /// Disables #includes of other files and if there are unresolved identifiers + /// in preprocessor directive conditions it causes all blocks to be parsed so + /// that the client can get the maximum amount of information from the parser. + bool SingleFileParseMode = false; + + /// When enabled, the preprocessor will construct editor placeholder tokens. + bool LexEditorPlaceholders = true; + + /// True if the SourceManager should report the original file name for + /// contents of files that were remapped to other files. Defaults to true. + bool RemappedFilesKeepOriginalName = true; + + /// The set of file remappings, which take existing files on + /// the system (the first part of each pair) and gives them the + /// contents of other files on the system (the second part of each + /// pair). + std::vector<std::pair<std::string, std::string>> RemappedFiles; + + /// The set of file-to-buffer remappings, which take existing files + /// on the system (the first part of each pair) and gives them the contents + /// of the specified memory buffer (the second part of each pair). + std::vector<std::pair<std::string, llvm::MemoryBuffer *>> RemappedFileBuffers; + + /// Whether the compiler instance should retain (i.e., not free) + /// the buffers associated with remapped files. + /// + /// This flag defaults to false; it can be set true only through direct + /// manipulation of the compiler invocation object, in cases where the + /// compiler invocation and its buffers will be reused. + bool RetainRemappedFileBuffers = false; + + /// When enabled, excluded conditional blocks retain in the main file. + bool RetainExcludedConditionalBlocks = false; + + /// The Objective-C++ ARC standard library that we should support, + /// by providing appropriate definitions to retrofit the standard library + /// with support for lifetime-qualified pointers. + ObjCXXARCStandardLibraryKind ObjCXXARCStandardLibrary = ARCXX_nolib; + + /// Records the set of modules + class FailedModulesSet { + llvm::StringSet<> Failed; + + public: + bool hasAlreadyFailed(StringRef module) { + return Failed.count(module) > 0; + } + + void addFailed(StringRef module) { + Failed.insert(module); + } + }; + + /// The set of modules that failed to build. + /// + /// This pointer will be shared among all of the compiler instances created + /// to (re)build modules, so that once a module fails to build anywhere, + /// other instances will see that the module has failed and won't try to + /// build it again. + std::shared_ptr<FailedModulesSet> FailedModules; + + /// Function for getting the dependency preprocessor directives of a file. + /// + /// These are directives derived from a special form of lexing where the + /// source input is scanned for the preprocessor directives that might have an + /// effect on the dependencies for a compilation unit. + /// + /// Enables a client to cache the directives for a file and provide them + /// across multiple compiler invocations. + /// FIXME: Allow returning an error. + std::function<std::optional<ArrayRef<dependency_directives_scan::Directive>>( + FileEntryRef)> + DependencyDirectivesForFile; + + /// Set up preprocessor for RunAnalysis action. + bool SetUpStaticAnalyzer = false; + + /// Prevents intended crashes when using #pragma clang __debug. For testing. + bool DisablePragmaDebugCrash = false; + + /// If set, the UNIX timestamp specified by SOURCE_DATE_EPOCH. + std::optional<uint64_t> SourceDateEpoch; + +public: + PreprocessorOptions() : PrecompiledPreambleBytes(0, false) {} + + void addMacroDef(StringRef Name) { + Macros.emplace_back(std::string(Name), false); + } + void addMacroUndef(StringRef Name) { + Macros.emplace_back(std::string(Name), true); + } + + void addRemappedFile(StringRef From, StringRef To) { + RemappedFiles.emplace_back(std::string(From), std::string(To)); + } + + void addRemappedFile(StringRef From, llvm::MemoryBuffer *To) { + RemappedFileBuffers.emplace_back(std::string(From), To); + } + + void clearRemappedFiles() { + RemappedFiles.clear(); + RemappedFileBuffers.clear(); + } + + /// Reset any options that are not considered when building a + /// module. + void resetNonModularOptions() { + Includes.clear(); + MacroIncludes.clear(); + ChainedIncludes.clear(); + DumpDeserializedPCHDecls = false; + ImplicitPCHInclude.clear(); + SingleFileParseMode = false; + LexEditorPlaceholders = true; + RetainRemappedFileBuffers = true; + PrecompiledPreambleBytes.first = 0; + PrecompiledPreambleBytes.second = false; + RetainExcludedConditionalBlocks = false; + } +}; + +} // namespace clang + +#endif // LLVM_CLANG_LEX_PREPROCESSOROPTIONS_H_ + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Lex/ScratchBuffer.h b/contrib/libs/clang16/include/clang/Lex/ScratchBuffer.h new file mode 100644 index 0000000000..6b6c792f21 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Lex/ScratchBuffer.h @@ -0,0 +1,55 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===--- ScratchBuffer.h - Scratch space for forming tokens -----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the ScratchBuffer interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_SCRATCHBUFFER_H +#define LLVM_CLANG_LEX_SCRATCHBUFFER_H + +#include "clang/Basic/SourceLocation.h" + +namespace clang { + class SourceManager; + +/// ScratchBuffer - This class exposes a simple interface for the dynamic +/// construction of tokens. This is used for builtin macros (e.g. __LINE__) as +/// well as token pasting, etc. +class ScratchBuffer { + SourceManager &SourceMgr; + char *CurBuffer; + SourceLocation BufferStartLoc; + unsigned BytesUsed; +public: + ScratchBuffer(SourceManager &SM); + + /// getToken - Splat the specified text into a temporary MemoryBuffer and + /// return a SourceLocation that refers to the token. This is just like the + /// previous method, but returns a location that indicates the physloc of the + /// token. + SourceLocation getToken(const char *Buf, unsigned Len, const char *&DestPtr); + +private: + void AllocScratchBuffer(unsigned RequestLen); +}; + +} // end namespace clang + +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Lex/Token.h b/contrib/libs/clang16/include/clang/Lex/Token.h new file mode 100644 index 0000000000..72103d77c8 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Lex/Token.h @@ -0,0 +1,353 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===--- Token.h - Token interface ------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the Token interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_TOKEN_H +#define LLVM_CLANG_LEX_TOKEN_H + +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/TokenKinds.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include <cassert> + +namespace clang { + +class IdentifierInfo; + +/// Token - This structure provides full information about a lexed token. +/// It is not intended to be space efficient, it is intended to return as much +/// information as possible about each returned token. This is expected to be +/// compressed into a smaller form if memory footprint is important. +/// +/// The parser can create a special "annotation token" representing a stream of +/// tokens that were parsed and semantically resolved, e.g.: "foo::MyClass<int>" +/// can be represented by a single typename annotation token that carries +/// information about the SourceRange of the tokens and the type object. +class Token { + /// The location of the token. This is actually a SourceLocation. + SourceLocation::UIntTy Loc; + + // Conceptually these next two fields could be in a union. However, this + // causes gcc 4.2 to pessimize LexTokenInternal, a very performance critical + // routine. Keeping as separate members with casts until a more beautiful fix + // presents itself. + + /// UintData - This holds either the length of the token text, when + /// a normal token, or the end of the SourceRange when an annotation + /// token. + SourceLocation::UIntTy UintData; + + /// PtrData - This is a union of four different pointer types, which depends + /// on what type of token this is: + /// Identifiers, keywords, etc: + /// This is an IdentifierInfo*, which contains the uniqued identifier + /// spelling. + /// Literals: isLiteral() returns true. + /// This is a pointer to the start of the token in a text buffer, which + /// may be dirty (have trigraphs / escaped newlines). + /// Annotations (resolved type names, C++ scopes, etc): isAnnotation(). + /// This is a pointer to sema-specific data for the annotation token. + /// Eof: + // This is a pointer to a Decl. + /// Other: + /// This is null. + void *PtrData; + + /// Kind - The actual flavor of token this is. + tok::TokenKind Kind; + + /// Flags - Bits we track about this token, members of the TokenFlags enum. + unsigned short Flags; + +public: + // Various flags set per token: + enum TokenFlags { + StartOfLine = 0x01, // At start of line or only after whitespace + // (considering the line after macro expansion). + LeadingSpace = 0x02, // Whitespace exists before this token (considering + // whitespace after macro expansion). + DisableExpand = 0x04, // This identifier may never be macro expanded. + NeedsCleaning = 0x08, // Contained an escaped newline or trigraph. + LeadingEmptyMacro = 0x10, // Empty macro exists before this token. + HasUDSuffix = 0x20, // This string or character literal has a ud-suffix. + HasUCN = 0x40, // This identifier contains a UCN. + IgnoredComma = 0x80, // This comma is not a macro argument separator (MS). + StringifiedInMacro = 0x100, // This string or character literal is formed by + // macro stringizing or charizing operator. + CommaAfterElided = 0x200, // The comma following this token was elided (MS). + IsEditorPlaceholder = 0x400, // This identifier is a placeholder. + IsReinjected = 0x800, // A phase 4 token that was produced before and + // re-added, e.g. via EnterTokenStream. Annotation + // tokens are *not* reinjected. + }; + + tok::TokenKind getKind() const { return Kind; } + void setKind(tok::TokenKind K) { Kind = K; } + + /// is/isNot - Predicates to check if this token is a specific kind, as in + /// "if (Tok.is(tok::l_brace)) {...}". + bool is(tok::TokenKind K) const { return Kind == K; } + bool isNot(tok::TokenKind K) const { return Kind != K; } + bool isOneOf(tok::TokenKind K1, tok::TokenKind K2) const { + return is(K1) || is(K2); + } + template <typename... Ts> bool isOneOf(tok::TokenKind K1, Ts... Ks) const { + return is(K1) || isOneOf(Ks...); + } + + /// Return true if this is a raw identifier (when lexing + /// in raw mode) or a non-keyword identifier (when lexing in non-raw mode). + bool isAnyIdentifier() const { + return tok::isAnyIdentifier(getKind()); + } + + /// Return true if this is a "literal", like a numeric + /// constant, string, etc. + bool isLiteral() const { + return tok::isLiteral(getKind()); + } + + /// Return true if this is any of tok::annot_* kind tokens. + bool isAnnotation() const { + return tok::isAnnotation(getKind()); + } + + /// Return a source location identifier for the specified + /// offset in the current file. + SourceLocation getLocation() const { + return SourceLocation::getFromRawEncoding(Loc); + } + unsigned getLength() const { + assert(!isAnnotation() && "Annotation tokens have no length field"); + return UintData; + } + + void setLocation(SourceLocation L) { Loc = L.getRawEncoding(); } + void setLength(unsigned Len) { + assert(!isAnnotation() && "Annotation tokens have no length field"); + UintData = Len; + } + + SourceLocation getAnnotationEndLoc() const { + assert(isAnnotation() && "Used AnnotEndLocID on non-annotation token"); + return SourceLocation::getFromRawEncoding(UintData ? UintData : Loc); + } + void setAnnotationEndLoc(SourceLocation L) { + assert(isAnnotation() && "Used AnnotEndLocID on non-annotation token"); + UintData = L.getRawEncoding(); + } + + SourceLocation getLastLoc() const { + return isAnnotation() ? getAnnotationEndLoc() : getLocation(); + } + + SourceLocation getEndLoc() const { + return isAnnotation() ? getAnnotationEndLoc() + : getLocation().getLocWithOffset(getLength()); + } + + /// SourceRange of the group of tokens that this annotation token + /// represents. + SourceRange getAnnotationRange() const { + return SourceRange(getLocation(), getAnnotationEndLoc()); + } + void setAnnotationRange(SourceRange R) { + setLocation(R.getBegin()); + setAnnotationEndLoc(R.getEnd()); + } + + const char *getName() const { return tok::getTokenName(Kind); } + + /// Reset all flags to cleared. + void startToken() { + Kind = tok::unknown; + Flags = 0; + PtrData = nullptr; + UintData = 0; + Loc = SourceLocation().getRawEncoding(); + } + + bool hasPtrData() const { return PtrData != nullptr; } + + IdentifierInfo *getIdentifierInfo() const { + assert(isNot(tok::raw_identifier) && + "getIdentifierInfo() on a tok::raw_identifier token!"); + assert(!isAnnotation() && + "getIdentifierInfo() on an annotation token!"); + if (isLiteral()) return nullptr; + if (is(tok::eof)) return nullptr; + return (IdentifierInfo*) PtrData; + } + void setIdentifierInfo(IdentifierInfo *II) { + PtrData = (void*) II; + } + + const void *getEofData() const { + assert(is(tok::eof)); + return reinterpret_cast<const void *>(PtrData); + } + void setEofData(const void *D) { + assert(is(tok::eof)); + assert(!PtrData); + PtrData = const_cast<void *>(D); + } + + /// getRawIdentifier - For a raw identifier token (i.e., an identifier + /// lexed in raw mode), returns a reference to the text substring in the + /// buffer if known. + StringRef getRawIdentifier() const { + assert(is(tok::raw_identifier)); + return StringRef(reinterpret_cast<const char *>(PtrData), getLength()); + } + void setRawIdentifierData(const char *Ptr) { + assert(is(tok::raw_identifier)); + PtrData = const_cast<char*>(Ptr); + } + + /// getLiteralData - For a literal token (numeric constant, string, etc), this + /// returns a pointer to the start of it in the text buffer if known, null + /// otherwise. + const char *getLiteralData() const { + assert(isLiteral() && "Cannot get literal data of non-literal"); + return reinterpret_cast<const char*>(PtrData); + } + void setLiteralData(const char *Ptr) { + assert(isLiteral() && "Cannot set literal data of non-literal"); + PtrData = const_cast<char*>(Ptr); + } + + void *getAnnotationValue() const { + assert(isAnnotation() && "Used AnnotVal on non-annotation token"); + return PtrData; + } + void setAnnotationValue(void *val) { + assert(isAnnotation() && "Used AnnotVal on non-annotation token"); + PtrData = val; + } + + /// Set the specified flag. + void setFlag(TokenFlags Flag) { + Flags |= Flag; + } + + /// Get the specified flag. + bool getFlag(TokenFlags Flag) const { + return (Flags & Flag) != 0; + } + + /// Unset the specified flag. + void clearFlag(TokenFlags Flag) { + Flags &= ~Flag; + } + + /// Return the internal represtation of the flags. + /// + /// This is only intended for low-level operations such as writing tokens to + /// disk. + unsigned getFlags() const { + return Flags; + } + + /// Set a flag to either true or false. + void setFlagValue(TokenFlags Flag, bool Val) { + if (Val) + setFlag(Flag); + else + clearFlag(Flag); + } + + /// isAtStartOfLine - Return true if this token is at the start of a line. + /// + bool isAtStartOfLine() const { return getFlag(StartOfLine); } + + /// Return true if this token has whitespace before it. + /// + bool hasLeadingSpace() const { return getFlag(LeadingSpace); } + + /// Return true if this identifier token should never + /// be expanded in the future, due to C99 6.10.3.4p2. + bool isExpandDisabled() const { return getFlag(DisableExpand); } + + /// Return true if we have an ObjC keyword identifier. + bool isObjCAtKeyword(tok::ObjCKeywordKind objcKey) const; + + /// Return the ObjC keyword kind. + tok::ObjCKeywordKind getObjCKeywordID() const; + + /// Return true if this token has trigraphs or escaped newlines in it. + bool needsCleaning() const { return getFlag(NeedsCleaning); } + + /// Return true if this token has an empty macro before it. + /// + bool hasLeadingEmptyMacro() const { return getFlag(LeadingEmptyMacro); } + + /// Return true if this token is a string or character literal which + /// has a ud-suffix. + bool hasUDSuffix() const { return getFlag(HasUDSuffix); } + + /// Returns true if this token contains a universal character name. + bool hasUCN() const { return getFlag(HasUCN); } + + /// Returns true if this token is formed by macro by stringizing or charizing + /// operator. + bool stringifiedInMacro() const { return getFlag(StringifiedInMacro); } + + /// Returns true if the comma after this token was elided. + bool commaAfterElided() const { return getFlag(CommaAfterElided); } + + /// Returns true if this token is an editor placeholder. + /// + /// Editor placeholders are produced by the code-completion engine and are + /// represented as characters between '<#' and '#>' in the source code. The + /// lexer uses identifier tokens to represent placeholders. + bool isEditorPlaceholder() const { return getFlag(IsEditorPlaceholder); } +}; + +/// Information about the conditional stack (\#if directives) +/// currently active. +struct PPConditionalInfo { + /// Location where the conditional started. + SourceLocation IfLoc; + + /// True if this was contained in a skipping directive, e.g., + /// in a "\#if 0" block. + bool WasSkipping; + + /// True if we have emitted tokens already, and now we're in + /// an \#else block or something. Only useful in Skipping blocks. + bool FoundNonSkip; + + /// True if we've seen a \#else in this block. If so, + /// \#elif/\#else directives are not allowed. + bool FoundElse; +}; + +// Extra information needed for annonation tokens. +struct PragmaLoopHintInfo { + Token PragmaName; + Token Option; + ArrayRef<Token> Toks; +}; +} // end namespace clang + +#endif // LLVM_CLANG_LEX_TOKEN_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Lex/TokenConcatenation.h b/contrib/libs/clang16/include/clang/Lex/TokenConcatenation.h new file mode 100644 index 0000000000..7eb482fe6a --- /dev/null +++ b/contrib/libs/clang16/include/clang/Lex/TokenConcatenation.h @@ -0,0 +1,82 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===--- TokenConcatenation.h - Token Concatenation Avoidance ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the TokenConcatenation class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_TOKENCONCATENATION_H +#define LLVM_CLANG_LEX_TOKENCONCATENATION_H + +#include "clang/Basic/TokenKinds.h" + +namespace clang { + class Preprocessor; + class Token; + + /// TokenConcatenation class, which answers the question of + /// "Is it safe to emit two tokens without a whitespace between them, or + /// would that cause implicit concatenation of the tokens?" + /// + /// For example, it emitting two identifiers "foo" and "bar" next to each + /// other would cause the lexer to produce one "foobar" token. Emitting "1" + /// and ")" next to each other is safe. + /// + class TokenConcatenation { + const Preprocessor &PP; + + enum AvoidConcatInfo { + /// By default, a token never needs to avoid concatenation. Most tokens + /// (e.g. ',', ')', etc) don't cause a problem when concatenated. + aci_never_avoid_concat = 0, + + /// aci_custom_firstchar - AvoidConcat contains custom code to handle this + /// token's requirements, and it needs to know the first character of the + /// token. + aci_custom_firstchar = 1, + + /// aci_custom - AvoidConcat contains custom code to handle this token's + /// requirements, but it doesn't need to know the first character of the + /// token. + aci_custom = 2, + + /// aci_avoid_equal - Many tokens cannot be safely followed by an '=' + /// character. For example, "<<" turns into "<<=" when followed by an =. + aci_avoid_equal = 4 + }; + + /// TokenInfo - This array contains information for each token on what + /// action to take when avoiding concatenation of tokens in the AvoidConcat + /// method. + char TokenInfo[tok::NUM_TOKENS]; + public: + TokenConcatenation(const Preprocessor &PP); + + bool AvoidConcat(const Token &PrevPrevTok, + const Token &PrevTok, + const Token &Tok) const; + + private: + /// IsIdentifierStringPrefix - Return true if the spelling of the token + /// is literally 'L', 'u', 'U', or 'u8'. + bool IsIdentifierStringPrefix(const Token &Tok) const; + }; + } // end clang namespace + +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Lex/TokenLexer.h b/contrib/libs/clang16/include/clang/Lex/TokenLexer.h new file mode 100644 index 0000000000..70bf6839fa --- /dev/null +++ b/contrib/libs/clang16/include/clang/Lex/TokenLexer.h @@ -0,0 +1,256 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- TokenLexer.h - Lex from a token buffer -------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the TokenLexer interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_TOKENLEXER_H +#define LLVM_CLANG_LEX_TOKENLEXER_H + +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/ArrayRef.h" + +namespace clang { + +class MacroArgs; +class MacroInfo; +class Preprocessor; +class Token; +class VAOptExpansionContext; + +/// TokenLexer - This implements a lexer that returns tokens from a macro body +/// or token stream instead of lexing from a character buffer. This is used for +/// macro expansion and _Pragma handling, for example. +class TokenLexer { + friend class Preprocessor; + + /// The macro we are expanding from. This is null if expanding a token stream. + MacroInfo *Macro = nullptr; + + /// The actual arguments specified for a function-like macro, or null. The + /// TokenLexer owns the pointed-to object. + MacroArgs *ActualArgs = nullptr; + + /// The current preprocessor object we are expanding for. + Preprocessor &PP; + + /// This is the pointer to an array of tokens that the macro is + /// defined to, with arguments expanded for function-like macros. If this is + /// a token stream, these are the tokens we are returning. This points into + /// the macro definition we are lexing from, a cache buffer that is owned by + /// the preprocessor, or some other buffer that we may or may not own + /// (depending on OwnsTokens). + /// Note that if it points into Preprocessor's cache buffer, the Preprocessor + /// may update the pointer as needed. + const Token *Tokens; + + /// This is the length of the Tokens array. + unsigned NumTokens; + + /// This is the index of the next token that Lex will return. + unsigned CurTokenIdx; + + /// The source location range where this macro was expanded. + SourceLocation ExpandLocStart, ExpandLocEnd; + + /// Source location pointing at the source location entry chunk that + /// was reserved for the current macro expansion. + SourceLocation MacroExpansionStart; + + /// The offset of the macro expansion in the + /// "source location address space". + unsigned MacroStartSLocOffset; + + /// Location of the macro definition. + SourceLocation MacroDefStart; + + /// Length of the macro definition. + unsigned MacroDefLength; + + /// Lexical information about the expansion point of the macro: the identifier + /// that the macro expanded from had these properties. + bool AtStartOfLine : 1; + bool HasLeadingSpace : 1; + + // When this is true, the next token appended to the + // output list during function argument expansion will get a leading space, + // regardless of whether it had one to begin with or not. This is used for + // placemarker support. If still true after function argument expansion, the + // leading space will be applied to the first token following the macro + // expansion. + bool NextTokGetsSpace : 1; + + /// This is true if this TokenLexer allocated the Tokens + /// array, and thus needs to free it when destroyed. For simple object-like + /// macros (for example) we just point into the token buffer of the macro + /// definition, we don't make a copy of it. + bool OwnsTokens : 1; + + /// This is true when tokens lexed from the TokenLexer + /// should not be subject to further macro expansion. + bool DisableMacroExpansion : 1; + + /// When true, the produced tokens have Token::IsReinjected flag set. + /// See the flag documentation for details. + bool IsReinject : 1; + +public: + /// Create a TokenLexer for the specified macro with the specified actual + /// arguments. Note that this ctor takes ownership of the ActualArgs pointer. + /// ILEnd specifies the location of the ')' for a function-like macro or the + /// identifier for an object-like macro. + TokenLexer(Token &Tok, SourceLocation ILEnd, MacroInfo *MI, + MacroArgs *ActualArgs, Preprocessor &pp) + : PP(pp), OwnsTokens(false) { + Init(Tok, ILEnd, MI, ActualArgs); + } + + /// Create a TokenLexer for the specified token stream. If 'OwnsTokens' is + /// specified, this takes ownership of the tokens and delete[]'s them when + /// the token lexer is empty. + TokenLexer(const Token *TokArray, unsigned NumToks, bool DisableExpansion, + bool ownsTokens, bool isReinject, Preprocessor &pp) + : PP(pp), OwnsTokens(false) { + Init(TokArray, NumToks, DisableExpansion, ownsTokens, isReinject); + } + + TokenLexer(const TokenLexer &) = delete; + TokenLexer &operator=(const TokenLexer &) = delete; + ~TokenLexer() { destroy(); } + + /// Initialize this TokenLexer to expand from the specified macro + /// with the specified argument information. Note that this ctor takes + /// ownership of the ActualArgs pointer. ILEnd specifies the location of the + /// ')' for a function-like macro or the identifier for an object-like macro. + void Init(Token &Tok, SourceLocation ELEnd, MacroInfo *MI, + MacroArgs *Actuals); + + /// Initialize this TokenLexer with the specified token stream. + /// This does not take ownership of the specified token vector. + /// + /// DisableExpansion is true when macro expansion of tokens lexed from this + /// stream should be disabled. + void Init(const Token *TokArray, unsigned NumToks, bool DisableMacroExpansion, + bool OwnsTokens, bool IsReinject); + + /// If the next token lexed will pop this macro off the + /// expansion stack, return 2. If the next unexpanded token is a '(', return + /// 1, otherwise return 0. + unsigned isNextTokenLParen() const; + + /// Lex and return a token from this macro stream. + bool Lex(Token &Tok); + + /// isParsingPreprocessorDirective - Return true if we are in the middle of a + /// preprocessor directive. + bool isParsingPreprocessorDirective() const; + +private: + void destroy(); + + /// Return true if the next lex call will pop this macro off the include + /// stack. + bool isAtEnd() const { + return CurTokenIdx == NumTokens; + } + + /// Concatenates the next (sub-)sequence of \p Tokens separated by '##' + /// starting with LHSTok - stopping when we encounter a token that is neither + /// '##' nor preceded by '##'. Places the result back into \p LHSTok and sets + /// \p CurIdx to point to the token following the last one that was pasted. + /// + /// Also performs the MSVC extension wide-literal token pasting involved with: + /// \code L #macro-arg. \endcode + /// + /// \param[in,out] LHSTok - Contains the token to the left of '##' in \p + /// Tokens upon entry and will contain the resulting concatenated Token upon + /// exit. + /// + /// \param[in] TokenStream - The stream of Tokens we are lexing from. + /// + /// \param[in,out] CurIdx - Upon entry, \pTokens[\pCurIdx] must equal '##' + /// (with the exception of the MSVC extension mentioned above). Upon exit, it + /// is set to the index of the token following the last token that was + /// concatenated together. + /// + /// \returns If this returns true, the caller should immediately return the + /// token. + bool pasteTokens(Token &LHSTok, ArrayRef<Token> TokenStream, + unsigned int &CurIdx); + + /// Calls pasteTokens above, passing in the '*this' object's Tokens and + /// CurTokenIdx data members. + bool pasteTokens(Token &Tok); + + + /// Takes the tail sequence of tokens within ReplacementToks that represent + /// the just expanded __VA_OPT__ tokens (possibly zero tokens) and transforms + /// them into a string. \p VCtx is used to determine which token represents + /// the first __VA_OPT__ replacement token. + /// + /// \param[in,out] ResultToks - Contains the current Replacement Tokens + /// (prior to rescanning and token pasting), the tail end of which represents + /// the tokens just expanded through __VA_OPT__ processing. These (sub) + /// sequence of tokens are folded into one stringified token. + /// + /// \param[in] VCtx - contains relevant contextual information about the + /// state of the tokens around and including the __VA_OPT__ token, necessary + /// for stringification. + void stringifyVAOPTContents(SmallVectorImpl<Token> &ResultToks, + const VAOptExpansionContext &VCtx, + SourceLocation VAOPTClosingParenLoc); + + /// Expand the arguments of a function-like macro so that we can quickly + /// return preexpanded tokens from Tokens. + void ExpandFunctionArguments(); + + /// In microsoft compatibility mode, /##/ pastes + /// together to form a comment that comments out everything in the current + /// macro, other active macros, and anything left on the current physical + /// source line of the expanded buffer. Handle this by returning the + /// first token on the next line. + void HandleMicrosoftCommentPaste(Token &Tok, SourceLocation OpLoc); + + /// If \p loc is a FileID and points inside the current macro + /// definition, returns the appropriate source location pointing at the + /// macro expansion source location entry. + SourceLocation getExpansionLocForMacroDefLoc(SourceLocation loc) const; + + /// Creates SLocEntries and updates the locations of macro argument + /// tokens to their new expanded locations. + /// + /// \param ArgIdSpellLoc the location of the macro argument id inside the + /// macro definition. + void updateLocForMacroArgTokens(SourceLocation ArgIdSpellLoc, + Token *begin_tokens, Token *end_tokens); + + /// Remove comma ahead of __VA_ARGS__, if present, according to compiler + /// dialect settings. Returns true if the comma is removed. + bool MaybeRemoveCommaBeforeVaArgs(SmallVectorImpl<Token> &ResultToks, + bool HasPasteOperator, + MacroInfo *Macro, unsigned MacroArgNo, + Preprocessor &PP); + + void PropagateLineStartLeadingSpaceInfo(Token &Result); +}; + +} // namespace clang + +#endif // LLVM_CLANG_LEX_TOKENLEXER_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Lex/VariadicMacroSupport.h b/contrib/libs/clang16/include/clang/Lex/VariadicMacroSupport.h new file mode 100644 index 0000000000..dcb0c5dd9d --- /dev/null +++ b/contrib/libs/clang16/include/clang/Lex/VariadicMacroSupport.h @@ -0,0 +1,254 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- VariadicMacroSupport.h - state machines and scope guards -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines support types to help with preprocessing variadic macro +// (i.e. macros that use: ellipses __VA_ARGS__ ) definitions and +// expansions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_VARIADICMACROSUPPORT_H +#define LLVM_CLANG_LEX_VARIADICMACROSUPPORT_H + +#include "clang/Lex/Preprocessor.h" +#include "llvm/ADT/SmallVector.h" + +namespace clang { + class Preprocessor; + + /// An RAII class that tracks when the Preprocessor starts and stops lexing + /// the definition of a (ISO C/C++) variadic macro. As an example, this is + /// useful for unpoisoning and repoisoning certain identifiers (such as + /// __VA_ARGS__) that are only allowed in this context. Also, being a friend + /// of the Preprocessor class allows it to access PP's cached identifiers + /// directly (as opposed to performing a lookup each time). + class VariadicMacroScopeGuard { + const Preprocessor &PP; + IdentifierInfo *const Ident__VA_ARGS__; + IdentifierInfo *const Ident__VA_OPT__; + + public: + VariadicMacroScopeGuard(const Preprocessor &P) + : PP(P), Ident__VA_ARGS__(PP.Ident__VA_ARGS__), + Ident__VA_OPT__(PP.Ident__VA_OPT__) { + assert(Ident__VA_ARGS__->isPoisoned() && "__VA_ARGS__ should be poisoned " + "outside an ISO C/C++ variadic " + "macro definition!"); + assert(Ident__VA_OPT__->isPoisoned() && "__VA_OPT__ should be poisoned!"); + } + + /// Client code should call this function just before the Preprocessor is + /// about to Lex tokens from the definition of a variadic (ISO C/C++) macro. + void enterScope() { + Ident__VA_ARGS__->setIsPoisoned(false); + Ident__VA_OPT__->setIsPoisoned(false); + } + + /// Client code should call this function as soon as the Preprocessor has + /// either completed lexing the macro's definition tokens, or an error + /// occurred and the context is being exited. This function is idempotent + /// (might be explicitly called, and then reinvoked via the destructor). + void exitScope() { + Ident__VA_ARGS__->setIsPoisoned(true); + Ident__VA_OPT__->setIsPoisoned(true); + } + + ~VariadicMacroScopeGuard() { exitScope(); } + }; + + /// A class for tracking whether we're inside a VA_OPT during a + /// traversal of the tokens of a variadic macro definition. + class VAOptDefinitionContext { + /// Contains all the locations of so far unmatched lparens. + SmallVector<SourceLocation, 8> UnmatchedOpeningParens; + + const IdentifierInfo *const Ident__VA_OPT__; + + + public: + VAOptDefinitionContext(Preprocessor &PP) + : Ident__VA_OPT__(PP.Ident__VA_OPT__) {} + + bool isVAOptToken(const Token &T) const { + return Ident__VA_OPT__ && T.getIdentifierInfo() == Ident__VA_OPT__; + } + + /// Returns true if we have seen the __VA_OPT__ and '(' but before having + /// seen the matching ')'. + bool isInVAOpt() const { return UnmatchedOpeningParens.size(); } + + /// Call this function as soon as you see __VA_OPT__ and '('. + void sawVAOptFollowedByOpeningParens(const SourceLocation LParenLoc) { + assert(!isInVAOpt() && "Must NOT be within VAOPT context to call this"); + UnmatchedOpeningParens.push_back(LParenLoc); + + } + + SourceLocation getUnmatchedOpeningParenLoc() const { + assert(isInVAOpt() && "Must be within VAOPT context to call this"); + return UnmatchedOpeningParens.back(); + } + + /// Call this function each time an rparen is seen. It returns true only if + /// the rparen that was just seen was the eventual (non-nested) closing + /// paren for VAOPT, and ejects us out of the VAOPT context. + bool sawClosingParen() { + assert(isInVAOpt() && "Must be within VAOPT context to call this"); + UnmatchedOpeningParens.pop_back(); + return !UnmatchedOpeningParens.size(); + } + + /// Call this function each time an lparen is seen. + void sawOpeningParen(SourceLocation LParenLoc) { + assert(isInVAOpt() && "Must be within VAOPT context to call this"); + UnmatchedOpeningParens.push_back(LParenLoc); + } + + /// Are we at the top level within the __VA_OPT__? + bool isAtTopLevel() const { return UnmatchedOpeningParens.size() == 1; } + }; + + /// A class for tracking whether we're inside a VA_OPT during a + /// traversal of the tokens of a macro during macro expansion. + class VAOptExpansionContext : VAOptDefinitionContext { + + Token SyntheticEOFToken; + + // The (spelling) location of the current __VA_OPT__ in the replacement list + // of the function-like macro being expanded. + SourceLocation VAOptLoc; + + // NumOfTokensPriorToVAOpt : when != -1, contains the index *of* the first + // token of the current VAOPT contents (so we know where to start eager + // token-pasting and stringification) *within* the substituted tokens of + // the function-like macro's new replacement list. + int NumOfTokensPriorToVAOpt = -1; + + unsigned LeadingSpaceForStringifiedToken : 1; + + unsigned StringifyBefore : 1; + unsigned CharifyBefore : 1; + unsigned BeginsWithPlaceholder : 1; + unsigned EndsWithPlaceholder : 1; + + bool hasStringifyBefore() const { + assert(!isReset() && + "Must only be called if the state has not been reset"); + return StringifyBefore; + } + + bool isReset() const { + return NumOfTokensPriorToVAOpt == -1 || + VAOptLoc.isInvalid(); + } + + public: + VAOptExpansionContext(Preprocessor &PP) + : VAOptDefinitionContext(PP), LeadingSpaceForStringifiedToken(false), + StringifyBefore(false), CharifyBefore(false), + BeginsWithPlaceholder(false), EndsWithPlaceholder(false) { + SyntheticEOFToken.startToken(); + SyntheticEOFToken.setKind(tok::eof); + } + + void reset() { + VAOptLoc = SourceLocation(); + NumOfTokensPriorToVAOpt = -1; + LeadingSpaceForStringifiedToken = false; + StringifyBefore = false; + CharifyBefore = false; + BeginsWithPlaceholder = false; + EndsWithPlaceholder = false; + } + + const Token &getEOFTok() const { return SyntheticEOFToken; } + + void sawHashOrHashAtBefore(const bool HasLeadingSpace, + const bool IsHashAt) { + + StringifyBefore = !IsHashAt; + CharifyBefore = IsHashAt; + LeadingSpaceForStringifiedToken = HasLeadingSpace; + } + + void hasPlaceholderAfterHashhashAtStart() { BeginsWithPlaceholder = true; } + void hasPlaceholderBeforeRParen() { + if (isAtTopLevel()) + EndsWithPlaceholder = true; + } + + + bool beginsWithPlaceholder() const { + assert(!isReset() && + "Must only be called if the state has not been reset"); + return BeginsWithPlaceholder; + } + bool endsWithPlaceholder() const { + assert(!isReset() && + "Must only be called if the state has not been reset"); + return EndsWithPlaceholder; + } + + bool hasCharifyBefore() const { + assert(!isReset() && + "Must only be called if the state has not been reset"); + return CharifyBefore; + } + bool hasStringifyOrCharifyBefore() const { + return hasStringifyBefore() || hasCharifyBefore(); + } + + unsigned int getNumberOfTokensPriorToVAOpt() const { + assert(!isReset() && + "Must only be called if the state has not been reset"); + return NumOfTokensPriorToVAOpt; + } + + bool getLeadingSpaceForStringifiedToken() const { + assert(hasStringifyBefore() && + "Must only be called if this has been marked for stringification"); + return LeadingSpaceForStringifiedToken; + } + + void sawVAOptFollowedByOpeningParens(const SourceLocation VAOptLoc, + const unsigned int NumPriorTokens) { + assert(VAOptLoc.isFileID() && "Must not come from a macro expansion"); + assert(isReset() && "Must only be called if the state has been reset"); + VAOptDefinitionContext::sawVAOptFollowedByOpeningParens(SourceLocation()); + this->VAOptLoc = VAOptLoc; + NumOfTokensPriorToVAOpt = NumPriorTokens; + assert(NumOfTokensPriorToVAOpt > -1 && + "Too many prior tokens"); + } + + SourceLocation getVAOptLoc() const { + assert(!isReset() && + "Must only be called if the state has not been reset"); + assert(VAOptLoc.isValid() && "__VA_OPT__ location must be valid"); + return VAOptLoc; + } + using VAOptDefinitionContext::isVAOptToken; + using VAOptDefinitionContext::isInVAOpt; + using VAOptDefinitionContext::sawClosingParen; + using VAOptDefinitionContext::sawOpeningParen; + + }; +} // end namespace clang + +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif |