clang 22.0.0git
NoTrivialPPDirectiveTracer.h
Go to the documentation of this file.
1//===--- NoTrivialPPDirectiveTracer.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// This file defines the NoTrivialPPDirectiveTracer interface.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_CLANG_LEX_NO_TRIVIAL_PPDIRECTIVE_TRACER_H
14#define LLVM_CLANG_LEX_NO_TRIVIAL_PPDIRECTIVE_TRACER_H
15
17
18namespace clang {
19class Preprocessor;
20
21/// Consider the following code:
22///
23/// # 1 __FILE__ 1 3
24/// export module a;
25///
26/// According to the wording in
27/// [P1857R3](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1857r3.html):
28///
29/// A module directive may only appear as the first preprocessing tokens in a
30/// file (excluding the global module fragment.)
31///
32/// and the wording in
33/// [[cpp.pre]](https://eel.is/c++draft/cpp.pre#nt:module-file):
34/// module-file:
35/// pp-global-module-fragment[opt] pp-module group[opt]
36/// pp-private-module-fragment[opt]
37///
38/// `#` is the first pp-token in the translation unit, and it was rejected by
39/// clang, but they really should be exempted from this rule. The goal is to not
40/// allow any preprocessor conditionals or most state changes, but these don't
41/// fit that.
42///
43/// State change would mean most semantically observable preprocessor state,
44/// particularly anything that is order dependent. Global flags like being a
45/// system header/module shouldn't matter.
46///
47/// We should exempt a brunch of directives, even though it violates the current
48/// standard wording.
49///
50/// This class used to trace 'no-trivial' pp-directives in main file, which may
51/// change the preprocessing state.
52///
53/// FIXME: Once the wording of the standard is revised, we need to follow the
54/// wording of the standard. Currently this is just a workaround
56 Preprocessor &PP;
57
58 /// Whether preprocessing main file. We only focus on the main file.
59 bool InMainFile = true;
60
61 /// Whether one or more conditional, include or other 'no-trivial'
62 /// pp-directives has seen before.
63 bool SeenNoTrivialPPDirective = false;
64
65 void setSeenNoTrivialPPDirective();
66
67public:
69
70 bool hasSeenNoTrivialPPDirective() const;
71
72 /// Callback invoked whenever the \p Lexer moves to a different file for
73 /// lexing. Unlike \p FileChanged line number directives and other related
74 /// pragmas do not trigger callbacks to \p LexedFileChanged.
75 ///
76 /// \param FID The \p FileID that the \p Lexer moved to.
77 ///
78 /// \param Reason Whether the \p Lexer entered a new file or exited one.
79 ///
80 /// \param FileType The \p CharacteristicKind of the file the \p Lexer moved
81 /// to.
82 ///
83 /// \param PrevFID The \p FileID the \p Lexer was using before the change.
84 ///
85 /// \param Loc The location where the \p Lexer entered a new file from or the
86 /// location that the \p Lexer moved into after exiting a file.
89 SourceLocation Loc) override;
90
91 /// Callback invoked whenever an embed directive has been processed,
92 /// regardless of whether the embed will actually find a file.
93 ///
94 /// \param HashLoc The location of the '#' that starts the embed directive.
95 ///
96 /// \param FileName The name of the file being included, as written in the
97 /// source code.
98 ///
99 /// \param IsAngled Whether the file name was enclosed in angle brackets;
100 /// otherwise, it was enclosed in quotes.
101 ///
102 /// \param File The actual file that may be included by this embed directive.
103 ///
104 /// \param Params The parameters used by the directive.
105 void EmbedDirective(SourceLocation HashLoc, StringRef FileName, bool IsAngled,
107 const LexEmbedParametersResult &Params) override {
108 setSeenNoTrivialPPDirective();
109 }
110
111 /// Callback invoked whenever an inclusion directive of
112 /// any kind (\c \#include, \c \#import, etc.) has been processed, regardless
113 /// of whether the inclusion will actually result in an inclusion.
114 ///
115 /// \param HashLoc The location of the '#' that starts the inclusion
116 /// directive.
117 ///
118 /// \param IncludeTok The token that indicates the kind of inclusion
119 /// directive, e.g., 'include' or 'import'.
120 ///
121 /// \param FileName The name of the file being included, as written in the
122 /// source code.
123 ///
124 /// \param IsAngled Whether the file name was enclosed in angle brackets;
125 /// otherwise, it was enclosed in quotes.
126 ///
127 /// \param FilenameRange The character range of the quotes or angle brackets
128 /// for the written file name.
129 ///
130 /// \param File The actual file that may be included by this inclusion
131 /// directive.
132 ///
133 /// \param SearchPath Contains the search path which was used to find the file
134 /// in the file system. If the file was found via an absolute include path,
135 /// SearchPath will be empty. For framework includes, the SearchPath and
136 /// RelativePath will be split up. For example, if an include of "Some/Some.h"
137 /// is found via the framework path
138 /// "path/to/Frameworks/Some.framework/Headers/Some.h", SearchPath will be
139 /// "path/to/Frameworks/Some.framework/Headers" and RelativePath will be
140 /// "Some.h".
141 ///
142 /// \param RelativePath The path relative to SearchPath, at which the include
143 /// file was found. This is equal to FileName except for framework includes.
144 ///
145 /// \param SuggestedModule The module suggested for this header, if any.
146 ///
147 /// \param ModuleImported Whether this include was translated into import of
148 /// \p SuggestedModule.
149 ///
150 /// \param FileType The characteristic kind, indicates whether a file or
151 /// directory holds normal user code, system code, or system code which is
152 /// implicitly 'extern "C"' in C++ mode.
153 ///
154 void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
155 StringRef FileName, bool IsAngled,
156 CharSourceRange FilenameRange,
157 OptionalFileEntryRef File, StringRef SearchPath,
158 StringRef RelativePath, const Module *SuggestedModule,
159 bool ModuleImported,
161 setSeenNoTrivialPPDirective();
162 }
163
164 /// Callback invoked whenever there was an explicit module-import
165 /// syntax.
166 ///
167 /// \param ImportLoc The location of import directive token.
168 ///
169 /// \param Path The identifiers (and their locations) of the module
170 /// "path", e.g., "std.vector" would be split into "std" and "vector".
171 ///
172 /// \param Imported The imported module; can be null if importing failed.
173 ///
175 const Module *Imported) override {
176 setSeenNoTrivialPPDirective();
177 }
178
179 /// Callback invoked when the end of the main file is reached.
180 ///
181 /// No subsequent callbacks will be made.
182 void EndOfMainFile() override { setSeenNoTrivialPPDirective(); }
183
184 /// Callback invoked when start reading any pragma directive.
186 PragmaIntroducerKind Introducer) override {}
187
188 /// Called by Preprocessor::HandleMacroExpandedIdentifier when a
189 /// macro invocation is found.
190 void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD,
191 SourceRange Range, const MacroArgs *Args) override;
192
193 /// Hook called whenever a macro definition is seen.
194 void MacroDefined(const Token &MacroNameTok,
195 const MacroDirective *MD) override {
196 setSeenNoTrivialPPDirective();
197 }
198
199 /// Hook called whenever a macro \#undef is seen.
200 /// \param MacroNameTok The active Token
201 /// \param MD A MacroDefinition for the named macro.
202 /// \param Undef New MacroDirective if the macro was defined, null otherwise.
203 ///
204 /// MD is released immediately following this callback.
205 void MacroUndefined(const Token &MacroNameTok, const MacroDefinition &MD,
206 const MacroDirective *Undef) override {
207 setSeenNoTrivialPPDirective();
208 }
209
210 /// Hook called whenever the 'defined' operator is seen.
211 /// \param MD The MacroDirective if the name was a macro, null otherwise.
212 void Defined(const Token &MacroNameTok, const MacroDefinition &MD,
213 SourceRange Range) override {
214 setSeenNoTrivialPPDirective();
215 }
216
217 /// Hook called whenever an \#if is seen.
218 /// \param Loc the source location of the directive.
219 /// \param ConditionRange The SourceRange of the expression being tested.
220 /// \param ConditionValue The evaluated value of the condition.
221 ///
222 // FIXME: better to pass in a list (or tree!) of Tokens.
223 void If(SourceLocation Loc, SourceRange ConditionRange,
224 ConditionValueKind ConditionValue) override {
225 setSeenNoTrivialPPDirective();
226 }
227
228 /// Hook called whenever an \#elif is seen.
229 /// \param Loc the source location of the directive.
230 /// \param ConditionRange The SourceRange of the expression being tested.
231 /// \param ConditionValue The evaluated value of the condition.
232 /// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive.
233 // FIXME: better to pass in a list (or tree!) of Tokens.
234 void Elif(SourceLocation Loc, SourceRange ConditionRange,
235 ConditionValueKind ConditionValue, SourceLocation IfLoc) override {
236 setSeenNoTrivialPPDirective();
237 }
238
239 /// Hook called whenever an \#ifdef is seen.
240 /// \param Loc the source location of the directive.
241 /// \param MacroNameTok Information on the token being tested.
242 /// \param MD The MacroDefinition if the name was a macro, null otherwise.
243 void Ifdef(SourceLocation Loc, const Token &MacroNameTok,
244 const MacroDefinition &MD) override {
245 setSeenNoTrivialPPDirective();
246 }
247
248 /// Hook called whenever an \#elifdef branch is taken.
249 /// \param Loc the source location of the directive.
250 /// \param MacroNameTok Information on the token being tested.
251 /// \param MD The MacroDefinition if the name was a macro, null otherwise.
252 void Elifdef(SourceLocation Loc, const Token &MacroNameTok,
253 const MacroDefinition &MD) override {
254 setSeenNoTrivialPPDirective();
255 }
256 /// Hook called whenever an \#elifdef is skipped.
257 /// \param Loc the source location of the directive.
258 /// \param ConditionRange The SourceRange of the expression being tested.
259 /// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive.
260 // FIXME: better to pass in a list (or tree!) of Tokens.
261 void Elifdef(SourceLocation Loc, SourceRange ConditionRange,
262 SourceLocation IfLoc) override {
263 setSeenNoTrivialPPDirective();
264 }
265
266 /// Hook called whenever an \#ifndef is seen.
267 /// \param Loc the source location of the directive.
268 /// \param MacroNameTok Information on the token being tested.
269 /// \param MD The MacroDefiniton if the name was a macro, null otherwise.
270 void Ifndef(SourceLocation Loc, const Token &MacroNameTok,
271 const MacroDefinition &MD) override {
272 setSeenNoTrivialPPDirective();
273 }
274
275 /// Hook called whenever an \#elifndef branch is taken.
276 /// \param Loc the source location of the directive.
277 /// \param MacroNameTok Information on the token being tested.
278 /// \param MD The MacroDefinition if the name was a macro, null otherwise.
279 void Elifndef(SourceLocation Loc, const Token &MacroNameTok,
280 const MacroDefinition &MD) override {
281 setSeenNoTrivialPPDirective();
282 }
283 /// Hook called whenever an \#elifndef is skipped.
284 /// \param Loc the source location of the directive.
285 /// \param ConditionRange The SourceRange of the expression being tested.
286 /// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive.
287 // FIXME: better to pass in a list (or tree!) of Tokens.
288 void Elifndef(SourceLocation Loc, SourceRange ConditionRange,
289 SourceLocation IfLoc) override {
290 setSeenNoTrivialPPDirective();
291 }
292
293 /// Hook called whenever an \#else is seen.
294 /// \param Loc the source location of the directive.
295 /// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive.
296 void Else(SourceLocation Loc, SourceLocation IfLoc) override {
297 setSeenNoTrivialPPDirective();
298 }
299
300 /// Hook called whenever an \#endif is seen.
301 /// \param Loc the source location of the directive.
302 /// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive.
303 void Endif(SourceLocation Loc, SourceLocation IfLoc) override {
304 setSeenNoTrivialPPDirective();
305 }
306};
307
308} // namespace clang
309
310#endif // LLVM_CLANG_LEX_NO_TRIVIAL_PPDIRECTIVE_TRACER_H
llvm::MachO::FileType FileType
Definition MachO.h:46
Defines the PPCallbacks interface.
Represents a character-granular source range.
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
MacroArgs - An instance of this class captures information about the formal arguments specified to a ...
Definition MacroArgs.h:30
A description of the current definition of a macro.
Definition MacroInfo.h:590
Encapsulates changes to the "macros namespace" (the location where the macro name became active,...
Definition MacroInfo.h:313
Describes a module or submodule.
Definition Module.h:144
void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName, bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File, StringRef SearchPath, StringRef RelativePath, const Module *SuggestedModule, bool ModuleImported, SrcMgr::CharacteristicKind FileType) override
Callback invoked whenever an inclusion directive of any kind (#include, #import, etc....
void Ifndef(SourceLocation Loc, const Token &MacroNameTok, const MacroDefinition &MD) override
Hook called whenever an #ifndef is seen.
void If(SourceLocation Loc, SourceRange ConditionRange, ConditionValueKind ConditionValue) override
Hook called whenever an #if is seen.
void EmbedDirective(SourceLocation HashLoc, StringRef FileName, bool IsAngled, OptionalFileEntryRef File, const LexEmbedParametersResult &Params) override
Callback invoked whenever an embed directive has been processed, regardless of whether the embed will...
void MacroUndefined(const Token &MacroNameTok, const MacroDefinition &MD, const MacroDirective *Undef) override
Hook called whenever a macro #undef is seen.
void Else(SourceLocation Loc, SourceLocation IfLoc) override
Hook called whenever an #else is seen.
void PragmaDirective(SourceLocation Loc, PragmaIntroducerKind Introducer) override
Callback invoked when start reading any pragma directive.
void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD, SourceRange Range, const MacroArgs *Args) override
Called by Preprocessor::HandleMacroExpandedIdentifier when a macro invocation is found.
void moduleImport(SourceLocation ImportLoc, ModuleIdPath Path, const Module *Imported) override
Callback invoked whenever there was an explicit module-import syntax.
void Elifdef(SourceLocation Loc, SourceRange ConditionRange, SourceLocation IfLoc) override
Hook called whenever an #elifdef is skipped.
void LexedFileChanged(FileID FID, LexedFileChangeReason Reason, SrcMgr::CharacteristicKind FileType, FileID PrevFID, SourceLocation Loc) override
Callback invoked whenever the Lexer moves to a different file for lexing.
void Elifdef(SourceLocation Loc, const Token &MacroNameTok, const MacroDefinition &MD) override
Hook called whenever an #elifdef branch is taken.
void Elif(SourceLocation Loc, SourceRange ConditionRange, ConditionValueKind ConditionValue, SourceLocation IfLoc) override
Hook called whenever an #elif is seen.
void Endif(SourceLocation Loc, SourceLocation IfLoc) override
Hook called whenever an #endif is seen.
void EndOfMainFile() override
Callback invoked when the end of the main file is reached.
void Ifdef(SourceLocation Loc, const Token &MacroNameTok, const MacroDefinition &MD) override
Hook called whenever an #ifdef is seen.
void MacroDefined(const Token &MacroNameTok, const MacroDirective *MD) override
Hook called whenever a macro definition is seen.
void Elifndef(SourceLocation Loc, const Token &MacroNameTok, const MacroDefinition &MD) override
Hook called whenever an #elifndef branch is taken.
void Defined(const Token &MacroNameTok, const MacroDefinition &MD, SourceRange Range) override
Hook called whenever the 'defined' operator is seen.
void Elifndef(SourceLocation Loc, SourceRange ConditionRange, SourceLocation IfLoc) override
Hook called whenever an #elifndef is skipped.
This interface provides a way to observe the actions of the preprocessor as it does its thing.
Definition PPCallbacks.h:37
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Encodes a location in the source.
A trivial tuple used to represent a source range.
Token - This structure provides full information about a lexed token.
Definition Token.h:36
CharacteristicKind
Indicates whether a file or directory holds normal user code, system code, or system code which is im...
The JSON file list parser is used to communicate input to InstallAPI.
CustomizableOptional< FileEntryRef > OptionalFileEntryRef
Definition FileEntry.h:208
ArrayRef< IdentifierLoc > ModuleIdPath
A sequence of identifier/location pairs used to describe a particular module or submodule,...
PragmaIntroducerKind
Describes how the pragma was introduced, e.g., with #pragma, _Pragma, or __pragma.
Definition Pragma.h:32