/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/include/clang/Lex/PreprocessorLexer.h
Line | Count | Source (jump to first uncovered line) |
1 | | //===- PreprocessorLexer.h - C Language Family Lexer ------------*- 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 | | /// Defines the PreprocessorLexer interface. |
11 | | // |
12 | | //===----------------------------------------------------------------------===// |
13 | | |
14 | | #ifndef LLVM_CLANG_LEX_PREPROCESSORLEXER_H |
15 | | #define LLVM_CLANG_LEX_PREPROCESSORLEXER_H |
16 | | |
17 | | #include "clang/Lex/MultipleIncludeOpt.h" |
18 | | #include "clang/Lex/Token.h" |
19 | | #include "clang/Basic/SourceLocation.h" |
20 | | #include "llvm/ADT/ArrayRef.h" |
21 | | #include "llvm/ADT/SmallVector.h" |
22 | | #include <cassert> |
23 | | |
24 | | namespace clang { |
25 | | |
26 | | class FileEntry; |
27 | | class Preprocessor; |
28 | | |
29 | | class PreprocessorLexer { |
30 | | virtual void anchor(); |
31 | | |
32 | | protected: |
33 | | friend class Preprocessor; |
34 | | |
35 | | // Preprocessor object controlling lexing. |
36 | | Preprocessor *PP = nullptr; |
37 | | |
38 | | /// The SourceManager FileID corresponding to the file being lexed. |
39 | | const FileID FID; |
40 | | |
41 | | /// Number of SLocEntries before lexing the file. |
42 | | unsigned InitialNumSLocEntries = 0; |
43 | | |
44 | | //===--------------------------------------------------------------------===// |
45 | | // Context-specific lexing flags set by the preprocessor. |
46 | | //===--------------------------------------------------------------------===// |
47 | | |
48 | | /// True when parsing \#XXX; turns '\\n' into a tok::eod token. |
49 | | bool ParsingPreprocessorDirective = false; |
50 | | |
51 | | /// True after \#include; turns \<xx> or "xxx" into a tok::header_name token. |
52 | | bool ParsingFilename = false; |
53 | | |
54 | | /// True if in raw mode. |
55 | | /// |
56 | | /// Raw mode disables interpretation of tokens and is a far faster mode to |
57 | | /// lex in than non-raw-mode. This flag: |
58 | | /// 1. If EOF of the current lexer is found, the include stack isn't popped. |
59 | | /// 2. Identifier information is not looked up for identifier tokens. As an |
60 | | /// effect of this, implicit macro expansion is naturally disabled. |
61 | | /// 3. "#" tokens at the start of a line are treated as normal tokens, not |
62 | | /// implicitly transformed by the lexer. |
63 | | /// 4. All diagnostic messages are disabled. |
64 | | /// 5. No callbacks are made into the preprocessor. |
65 | | /// |
66 | | /// Note that in raw mode that the PP pointer may be null. |
67 | | bool LexingRawMode = false; |
68 | | |
69 | | /// A state machine that detects the \#ifndef-wrapping a file |
70 | | /// idiom for the multiple-include optimization. |
71 | | MultipleIncludeOpt MIOpt; |
72 | | |
73 | | /// Information about the set of \#if/\#ifdef/\#ifndef blocks |
74 | | /// we are currently in. |
75 | | SmallVector<PPConditionalInfo, 4> ConditionalStack; |
76 | | |
77 | 41.7M | PreprocessorLexer() : FID() {} |
78 | | PreprocessorLexer(Preprocessor *pp, FileID fid); |
79 | 42.8M | virtual ~PreprocessorLexer() = default; |
80 | | |
81 | | virtual void IndirectLex(Token& Result) = 0; |
82 | | |
83 | | /// Return the source location for the next observable location. |
84 | | virtual SourceLocation getSourceLocation() = 0; |
85 | | |
86 | | //===--------------------------------------------------------------------===// |
87 | | // #if directive handling. |
88 | | |
89 | | /// pushConditionalLevel - When we enter a \#if directive, this keeps track of |
90 | | /// what we are currently in for diagnostic emission (e.g. \#if with missing |
91 | | /// \#endif). |
92 | | void pushConditionalLevel(SourceLocation DirectiveStart, bool WasSkipping, |
93 | 17.2M | bool FoundNonSkip, bool FoundElse) { |
94 | 17.2M | PPConditionalInfo CI; |
95 | 17.2M | CI.IfLoc = DirectiveStart; |
96 | 17.2M | CI.WasSkipping = WasSkipping; |
97 | 17.2M | CI.FoundNonSkip = FoundNonSkip; |
98 | 17.2M | CI.FoundElse = FoundElse; |
99 | 17.2M | ConditionalStack.push_back(CI); |
100 | 17.2M | } |
101 | 0 | void pushConditionalLevel(const PPConditionalInfo &CI) { |
102 | 0 | ConditionalStack.push_back(CI); |
103 | 0 | } |
104 | | |
105 | | /// popConditionalLevel - Remove an entry off the top of the conditional |
106 | | /// stack, returning information about it. If the conditional stack is empty, |
107 | | /// this returns true and does not fill in the arguments. |
108 | 17.2M | bool popConditionalLevel(PPConditionalInfo &CI) { |
109 | 17.2M | if (ConditionalStack.empty()) |
110 | 2 | return true; |
111 | 17.2M | CI = ConditionalStack.pop_back_val(); |
112 | 17.2M | return false; |
113 | 17.2M | } |
114 | | |
115 | | /// Return the top of the conditional stack. |
116 | | /// \pre This requires that there be a conditional active. |
117 | 4.71M | PPConditionalInfo &peekConditionalLevel() { |
118 | 4.71M | assert(!ConditionalStack.empty() && "No conditionals active!"); |
119 | 4.71M | return ConditionalStack.back(); |
120 | 4.71M | } |
121 | | |
122 | 15.3M | unsigned getConditionalStackDepth() const { return ConditionalStack.size(); } |
123 | | |
124 | | public: |
125 | | PreprocessorLexer(const PreprocessorLexer &) = delete; |
126 | | PreprocessorLexer &operator=(const PreprocessorLexer &) = delete; |
127 | | |
128 | | //===--------------------------------------------------------------------===// |
129 | | // Misc. lexing methods. |
130 | | |
131 | | /// Lex a token, producing a header-name token if possible. |
132 | | void LexIncludeFilename(Token &FilenameTok); |
133 | | |
134 | | /// Inform the lexer whether or not we are currently lexing a |
135 | | /// preprocessor directive. |
136 | 41.3k | void setParsingPreprocessorDirective(bool f) { |
137 | 41.3k | ParsingPreprocessorDirective = f; |
138 | 41.3k | } |
139 | | |
140 | | /// Return true if this lexer is in raw mode or not. |
141 | 1.52G | bool isLexingRawMode() const { return LexingRawMode; } |
142 | | |
143 | | /// Return the preprocessor object for this lexer. |
144 | 0 | Preprocessor *getPP() const { return PP; } |
145 | | |
146 | 3.64M | FileID getFileID() const { |
147 | 3.64M | assert(PP && |
148 | 3.64M | "PreprocessorLexer::getFileID() should only be used with a Preprocessor"); |
149 | 3.64M | return FID; |
150 | 3.64M | } |
151 | | |
152 | | /// Number of SLocEntries before lexing the file. |
153 | 614k | unsigned getInitialNumSLocEntries() const { |
154 | 614k | return InitialNumSLocEntries; |
155 | 614k | } |
156 | | |
157 | | /// getFileEntry - Return the FileEntry corresponding to this FileID. Like |
158 | | /// getFileID(), this only works for lexers with attached preprocessors. |
159 | | const FileEntry *getFileEntry() const; |
160 | | |
161 | | /// Iterator that traverses the current stack of preprocessor |
162 | | /// conditional directives (\#if/\#ifdef/\#ifndef). |
163 | | using conditional_iterator = |
164 | | SmallVectorImpl<PPConditionalInfo>::const_iterator; |
165 | | |
166 | 0 | conditional_iterator conditional_begin() const { |
167 | 0 | return ConditionalStack.begin(); |
168 | 0 | } |
169 | | |
170 | 0 | conditional_iterator conditional_end() const { |
171 | 0 | return ConditionalStack.end(); |
172 | 0 | } |
173 | | |
174 | 28 | void setConditionalLevels(ArrayRef<PPConditionalInfo> CL) { |
175 | 28 | ConditionalStack.clear(); |
176 | 28 | ConditionalStack.append(CL.begin(), CL.end()); |
177 | 28 | } |
178 | | }; |
179 | | |
180 | | } // namespace clang |
181 | | |
182 | | #endif // LLVM_CLANG_LEX_PREPROCESSORLEXER_H |