1 //===- clang/Lex/DependencyDirectivesScanner.h ---------------------*- C++ -*-// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 /// 9 /// \file 10 /// This is the interface for scanning header and source files to get the 11 /// minimum necessary preprocessor directives for evaluating includes. It 12 /// reduces the source down to #define, #include, #import, @import, and any 13 /// conditional preprocessor logic that contains one of those. 14 /// 15 //===----------------------------------------------------------------------===// 16 17 #ifndef LLVM_CLANG_LEX_DEPENDENCYDIRECTIVESSCANNER_H 18 #define LLVM_CLANG_LEX_DEPENDENCYDIRECTIVESSCANNER_H 19 20 #include "clang/Basic/SourceLocation.h" 21 #include "llvm/ADT/ArrayRef.h" 22 23 namespace clang { 24 class FileManager; 25 26 namespace tok { 27 enum TokenKind : unsigned short; 28 } 29 30 class DiagnosticsEngine; 31 32 namespace dependency_directives_scan { 33 34 /// Token lexed as part of dependency directive scanning. 35 struct Token { 36 /// Offset into the original source input. 37 unsigned Offset; 38 unsigned Length; 39 tok::TokenKind Kind; 40 unsigned short Flags; 41 TokenToken42 Token(unsigned Offset, unsigned Length, tok::TokenKind Kind, 43 unsigned short Flags) 44 : Offset(Offset), Length(Length), Kind(Kind), Flags(Flags) {} 45 getEndToken46 unsigned getEnd() const { return Offset + Length; } 47 isToken48 bool is(tok::TokenKind K) const { return Kind == K; } isNotToken49 bool isNot(tok::TokenKind K) const { return Kind != K; } isOneOfToken50 bool isOneOf(tok::TokenKind K1, tok::TokenKind K2) const { 51 return is(K1) || is(K2); 52 } isOneOfToken53 template <typename... Ts> bool isOneOf(tok::TokenKind K1, Ts... Ks) const { 54 return is(K1) || isOneOf(Ks...); 55 } 56 }; 57 58 /// Represents the kind of preprocessor directive or a module declaration that 59 /// is tracked by the scanner in its token output. 60 enum DirectiveKind : uint8_t { 61 pp_none, 62 pp_include, 63 pp___include_macros, 64 pp_define, 65 pp_undef, 66 pp_import, 67 pp_pragma_import, 68 pp_pragma_once, 69 pp_pragma_push_macro, 70 pp_pragma_pop_macro, 71 pp_pragma_include_alias, 72 pp_pragma_system_header, 73 pp_include_next, 74 pp_if, 75 pp_ifdef, 76 pp_ifndef, 77 pp_elif, 78 pp_elifdef, 79 pp_elifndef, 80 pp_else, 81 pp_endif, 82 decl_at_import, 83 cxx_module_decl, 84 cxx_import_decl, 85 cxx_export_module_decl, 86 cxx_export_import_decl, 87 /// Indicates that there are tokens present between the last scanned directive 88 /// and eof. The \p Directive::Tokens array will be empty for this kind. 89 tokens_present_before_eof, 90 pp_eof, 91 }; 92 93 /// Represents a directive that's lexed as part of the dependency directives 94 /// scanning. It's used to track various preprocessor directives that could 95 /// potentially have an effect on the dependencies. 96 struct Directive { 97 ArrayRef<Token> Tokens; 98 99 /// The kind of token. 100 DirectiveKind Kind = pp_none; 101 102 Directive() = default; DirectiveDirective103 Directive(DirectiveKind K, ArrayRef<Token> Tokens) 104 : Tokens(Tokens), Kind(K) {} 105 }; 106 107 } // end namespace dependency_directives_scan 108 109 /// Scan the input for the preprocessor directives that might have 110 /// an effect on the dependencies for a compilation unit. 111 /// 112 /// This function ignores all non-preprocessor code and anything that 113 /// can't affect what gets included. 114 /// 115 /// \returns false on success, true on error. If the diagnostic engine is not 116 /// null, an appropriate error is reported using the given input location 117 /// with the offset that corresponds to the \p Input buffer offset. 118 bool scanSourceForDependencyDirectives( 119 StringRef Input, SmallVectorImpl<dependency_directives_scan::Token> &Tokens, 120 SmallVectorImpl<dependency_directives_scan::Directive> &Directives, 121 DiagnosticsEngine *Diags = nullptr, 122 SourceLocation InputSourceLoc = SourceLocation()); 123 124 /// Print the previously scanned dependency directives as minimized source text. 125 /// 126 /// \param Source The original source text that the dependency directives were 127 /// scanned from. 128 /// \param Directives The previously scanned dependency 129 /// directives. 130 /// \param OS the stream to print the dependency directives on. 131 /// 132 /// This is used primarily for testing purposes, during dependency scanning the 133 /// \p Lexer uses the tokens directly, not their printed version. 134 void printDependencyDirectivesAsSource( 135 StringRef Source, 136 ArrayRef<dependency_directives_scan::Directive> Directives, 137 llvm::raw_ostream &OS); 138 139 /// Functor that returns the dependency directives for a given file. 140 class DependencyDirectivesGetter { 141 public: 142 /// Clone the getter for a new \c FileManager instance. 143 virtual std::unique_ptr<DependencyDirectivesGetter> 144 cloneFor(FileManager &FileMgr) = 0; 145 146 /// Get the dependency directives for the given file. 147 virtual std::optional<ArrayRef<dependency_directives_scan::Directive>> 148 operator()(FileEntryRef File) = 0; 149 150 virtual ~DependencyDirectivesGetter() = default; 151 }; 152 } // end namespace clang 153 154 #endif // LLVM_CLANG_LEX_DEPENDENCYDIRECTIVESSCANNER_H 155