/src/llvm-project/clang/lib/Frontend/PrintPreprocessedOutput.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===--- PrintPreprocessedOutput.cpp - Implement the -E mode --------------===// |
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 code simply runs the preprocessor on the input file and prints out the |
10 | | // result. This is the traditional behavior of the -E option. |
11 | | // |
12 | | //===----------------------------------------------------------------------===// |
13 | | |
14 | | #include "clang/Frontend/Utils.h" |
15 | | #include "clang/Basic/CharInfo.h" |
16 | | #include "clang/Basic/Diagnostic.h" |
17 | | #include "clang/Basic/SourceManager.h" |
18 | | #include "clang/Frontend/PreprocessorOutputOptions.h" |
19 | | #include "clang/Lex/MacroInfo.h" |
20 | | #include "clang/Lex/PPCallbacks.h" |
21 | | #include "clang/Lex/Pragma.h" |
22 | | #include "clang/Lex/Preprocessor.h" |
23 | | #include "clang/Lex/TokenConcatenation.h" |
24 | | #include "llvm/ADT/STLExtras.h" |
25 | | #include "llvm/ADT/SmallString.h" |
26 | | #include "llvm/ADT/StringRef.h" |
27 | | #include "llvm/Support/ErrorHandling.h" |
28 | | #include "llvm/Support/raw_ostream.h" |
29 | | #include <cstdio> |
30 | | using namespace clang; |
31 | | |
32 | | /// PrintMacroDefinition - Print a macro definition in a form that will be |
33 | | /// properly accepted back as a definition. |
34 | | static void PrintMacroDefinition(const IdentifierInfo &II, const MacroInfo &MI, |
35 | 0 | Preprocessor &PP, raw_ostream *OS) { |
36 | 0 | *OS << "#define " << II.getName(); |
37 | |
|
38 | 0 | if (MI.isFunctionLike()) { |
39 | 0 | *OS << '('; |
40 | 0 | if (!MI.param_empty()) { |
41 | 0 | MacroInfo::param_iterator AI = MI.param_begin(), E = MI.param_end(); |
42 | 0 | for (; AI+1 != E; ++AI) { |
43 | 0 | *OS << (*AI)->getName(); |
44 | 0 | *OS << ','; |
45 | 0 | } |
46 | | |
47 | | // Last argument. |
48 | 0 | if ((*AI)->getName() == "__VA_ARGS__") |
49 | 0 | *OS << "..."; |
50 | 0 | else |
51 | 0 | *OS << (*AI)->getName(); |
52 | 0 | } |
53 | |
|
54 | 0 | if (MI.isGNUVarargs()) |
55 | 0 | *OS << "..."; // #define foo(x...) |
56 | |
|
57 | 0 | *OS << ')'; |
58 | 0 | } |
59 | | |
60 | | // GCC always emits a space, even if the macro body is empty. However, do not |
61 | | // want to emit two spaces if the first token has a leading space. |
62 | 0 | if (MI.tokens_empty() || !MI.tokens_begin()->hasLeadingSpace()) |
63 | 0 | *OS << ' '; |
64 | |
|
65 | 0 | SmallString<128> SpellingBuffer; |
66 | 0 | for (const auto &T : MI.tokens()) { |
67 | 0 | if (T.hasLeadingSpace()) |
68 | 0 | *OS << ' '; |
69 | |
|
70 | 0 | *OS << PP.getSpelling(T, SpellingBuffer); |
71 | 0 | } |
72 | 0 | } |
73 | | |
74 | | //===----------------------------------------------------------------------===// |
75 | | // Preprocessed token printer |
76 | | //===----------------------------------------------------------------------===// |
77 | | |
78 | | namespace { |
79 | | class PrintPPOutputPPCallbacks : public PPCallbacks { |
80 | | Preprocessor &PP; |
81 | | SourceManager &SM; |
82 | | TokenConcatenation ConcatInfo; |
83 | | public: |
84 | | raw_ostream *OS; |
85 | | private: |
86 | | unsigned CurLine; |
87 | | |
88 | | bool EmittedTokensOnThisLine; |
89 | | bool EmittedDirectiveOnThisLine; |
90 | | SrcMgr::CharacteristicKind FileType; |
91 | | SmallString<512> CurFilename; |
92 | | bool Initialized; |
93 | | bool DisableLineMarkers; |
94 | | bool DumpDefines; |
95 | | bool DumpIncludeDirectives; |
96 | | bool UseLineDirectives; |
97 | | bool IsFirstFileEntered; |
98 | | bool MinimizeWhitespace; |
99 | | bool DirectivesOnly; |
100 | | bool KeepSystemIncludes; |
101 | | raw_ostream *OrigOS; |
102 | | std::unique_ptr<llvm::raw_null_ostream> NullOS; |
103 | | |
104 | | Token PrevTok; |
105 | | Token PrevPrevTok; |
106 | | |
107 | | public: |
108 | | PrintPPOutputPPCallbacks(Preprocessor &pp, raw_ostream *os, bool lineMarkers, |
109 | | bool defines, bool DumpIncludeDirectives, |
110 | | bool UseLineDirectives, bool MinimizeWhitespace, |
111 | | bool DirectivesOnly, bool KeepSystemIncludes) |
112 | | : PP(pp), SM(PP.getSourceManager()), ConcatInfo(PP), OS(os), |
113 | | DisableLineMarkers(lineMarkers), DumpDefines(defines), |
114 | | DumpIncludeDirectives(DumpIncludeDirectives), |
115 | | UseLineDirectives(UseLineDirectives), |
116 | | MinimizeWhitespace(MinimizeWhitespace), DirectivesOnly(DirectivesOnly), |
117 | 0 | KeepSystemIncludes(KeepSystemIncludes), OrigOS(os) { |
118 | 0 | CurLine = 0; |
119 | 0 | CurFilename += "<uninit>"; |
120 | 0 | EmittedTokensOnThisLine = false; |
121 | 0 | EmittedDirectiveOnThisLine = false; |
122 | 0 | FileType = SrcMgr::C_User; |
123 | 0 | Initialized = false; |
124 | 0 | IsFirstFileEntered = false; |
125 | 0 | if (KeepSystemIncludes) |
126 | 0 | NullOS = std::make_unique<llvm::raw_null_ostream>(); |
127 | |
|
128 | 0 | PrevTok.startToken(); |
129 | 0 | PrevPrevTok.startToken(); |
130 | 0 | } |
131 | | |
132 | 0 | bool isMinimizeWhitespace() const { return MinimizeWhitespace; } |
133 | | |
134 | 0 | void setEmittedTokensOnThisLine() { EmittedTokensOnThisLine = true; } |
135 | 0 | bool hasEmittedTokensOnThisLine() const { return EmittedTokensOnThisLine; } |
136 | | |
137 | 0 | void setEmittedDirectiveOnThisLine() { EmittedDirectiveOnThisLine = true; } |
138 | 0 | bool hasEmittedDirectiveOnThisLine() const { |
139 | 0 | return EmittedDirectiveOnThisLine; |
140 | 0 | } |
141 | | |
142 | | /// Ensure that the output stream position is at the beginning of a new line |
143 | | /// and inserts one if it does not. It is intended to ensure that directives |
144 | | /// inserted by the directives not from the input source (such as #line) are |
145 | | /// in the first column. To insert newlines that represent the input, use |
146 | | /// MoveToLine(/*...*/, /*RequireStartOfLine=*/true). |
147 | | void startNewLineIfNeeded(); |
148 | | |
149 | | void FileChanged(SourceLocation Loc, FileChangeReason Reason, |
150 | | SrcMgr::CharacteristicKind FileType, |
151 | | FileID PrevFID) override; |
152 | | void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, |
153 | | StringRef FileName, bool IsAngled, |
154 | | CharSourceRange FilenameRange, |
155 | | OptionalFileEntryRef File, StringRef SearchPath, |
156 | | StringRef RelativePath, const Module *Imported, |
157 | | SrcMgr::CharacteristicKind FileType) override; |
158 | | void Ident(SourceLocation Loc, StringRef str) override; |
159 | | void PragmaMessage(SourceLocation Loc, StringRef Namespace, |
160 | | PragmaMessageKind Kind, StringRef Str) override; |
161 | | void PragmaDebug(SourceLocation Loc, StringRef DebugType) override; |
162 | | void PragmaDiagnosticPush(SourceLocation Loc, StringRef Namespace) override; |
163 | | void PragmaDiagnosticPop(SourceLocation Loc, StringRef Namespace) override; |
164 | | void PragmaDiagnostic(SourceLocation Loc, StringRef Namespace, |
165 | | diag::Severity Map, StringRef Str) override; |
166 | | void PragmaWarning(SourceLocation Loc, PragmaWarningSpecifier WarningSpec, |
167 | | ArrayRef<int> Ids) override; |
168 | | void PragmaWarningPush(SourceLocation Loc, int Level) override; |
169 | | void PragmaWarningPop(SourceLocation Loc) override; |
170 | | void PragmaExecCharsetPush(SourceLocation Loc, StringRef Str) override; |
171 | | void PragmaExecCharsetPop(SourceLocation Loc) override; |
172 | | void PragmaAssumeNonNullBegin(SourceLocation Loc) override; |
173 | | void PragmaAssumeNonNullEnd(SourceLocation Loc) override; |
174 | | |
175 | | /// Insert whitespace before emitting the next token. |
176 | | /// |
177 | | /// @param Tok Next token to be emitted. |
178 | | /// @param RequireSpace Ensure at least one whitespace is emitted. Useful |
179 | | /// if non-tokens have been emitted to the stream. |
180 | | /// @param RequireSameLine Never emit newlines. Useful when semantics depend |
181 | | /// on being on the same line, such as directives. |
182 | | void HandleWhitespaceBeforeTok(const Token &Tok, bool RequireSpace, |
183 | | bool RequireSameLine); |
184 | | |
185 | | /// Move to the line of the provided source location. This will |
186 | | /// return true if a newline was inserted or if |
187 | | /// the requested location is the first token on the first line. |
188 | | /// In these cases the next output will be the first column on the line and |
189 | | /// make it possible to insert indention. The newline was inserted |
190 | | /// implicitly when at the beginning of the file. |
191 | | /// |
192 | | /// @param Tok Token where to move to. |
193 | | /// @param RequireStartOfLine Whether the next line depends on being in the |
194 | | /// first column, such as a directive. |
195 | | /// |
196 | | /// @return Whether column adjustments are necessary. |
197 | 0 | bool MoveToLine(const Token &Tok, bool RequireStartOfLine) { |
198 | 0 | PresumedLoc PLoc = SM.getPresumedLoc(Tok.getLocation()); |
199 | 0 | unsigned TargetLine = PLoc.isValid() ? PLoc.getLine() : CurLine; |
200 | 0 | bool IsFirstInFile = |
201 | 0 | Tok.isAtStartOfLine() && PLoc.isValid() && PLoc.getLine() == 1; |
202 | 0 | return MoveToLine(TargetLine, RequireStartOfLine) || IsFirstInFile; |
203 | 0 | } |
204 | | |
205 | | /// Move to the line of the provided source location. Returns true if a new |
206 | | /// line was inserted. |
207 | 0 | bool MoveToLine(SourceLocation Loc, bool RequireStartOfLine) { |
208 | 0 | PresumedLoc PLoc = SM.getPresumedLoc(Loc); |
209 | 0 | unsigned TargetLine = PLoc.isValid() ? PLoc.getLine() : CurLine; |
210 | 0 | return MoveToLine(TargetLine, RequireStartOfLine); |
211 | 0 | } |
212 | | bool MoveToLine(unsigned LineNo, bool RequireStartOfLine); |
213 | | |
214 | | bool AvoidConcat(const Token &PrevPrevTok, const Token &PrevTok, |
215 | 0 | const Token &Tok) { |
216 | 0 | return ConcatInfo.AvoidConcat(PrevPrevTok, PrevTok, Tok); |
217 | 0 | } |
218 | | void WriteLineInfo(unsigned LineNo, const char *Extra=nullptr, |
219 | | unsigned ExtraLen=0); |
220 | 0 | bool LineMarkersAreDisabled() const { return DisableLineMarkers; } |
221 | | void HandleNewlinesInToken(const char *TokStr, unsigned Len); |
222 | | |
223 | | /// MacroDefined - This hook is called whenever a macro definition is seen. |
224 | | void MacroDefined(const Token &MacroNameTok, |
225 | | const MacroDirective *MD) override; |
226 | | |
227 | | /// MacroUndefined - This hook is called whenever a macro #undef is seen. |
228 | | void MacroUndefined(const Token &MacroNameTok, |
229 | | const MacroDefinition &MD, |
230 | | const MacroDirective *Undef) override; |
231 | | |
232 | | void BeginModule(const Module *M); |
233 | | void EndModule(const Module *M); |
234 | | }; |
235 | | } // end anonymous namespace |
236 | | |
237 | | void PrintPPOutputPPCallbacks::WriteLineInfo(unsigned LineNo, |
238 | | const char *Extra, |
239 | 0 | unsigned ExtraLen) { |
240 | 0 | startNewLineIfNeeded(); |
241 | | |
242 | | // Emit #line directives or GNU line markers depending on what mode we're in. |
243 | 0 | if (UseLineDirectives) { |
244 | 0 | *OS << "#line" << ' ' << LineNo << ' ' << '"'; |
245 | 0 | OS->write_escaped(CurFilename); |
246 | 0 | *OS << '"'; |
247 | 0 | } else { |
248 | 0 | *OS << '#' << ' ' << LineNo << ' ' << '"'; |
249 | 0 | OS->write_escaped(CurFilename); |
250 | 0 | *OS << '"'; |
251 | |
|
252 | 0 | if (ExtraLen) |
253 | 0 | OS->write(Extra, ExtraLen); |
254 | |
|
255 | 0 | if (FileType == SrcMgr::C_System) |
256 | 0 | OS->write(" 3", 2); |
257 | 0 | else if (FileType == SrcMgr::C_ExternCSystem) |
258 | 0 | OS->write(" 3 4", 4); |
259 | 0 | } |
260 | 0 | *OS << '\n'; |
261 | 0 | } |
262 | | |
263 | | /// MoveToLine - Move the output to the source line specified by the location |
264 | | /// object. We can do this by emitting some number of \n's, or be emitting a |
265 | | /// #line directive. This returns false if already at the specified line, true |
266 | | /// if some newlines were emitted. |
267 | | bool PrintPPOutputPPCallbacks::MoveToLine(unsigned LineNo, |
268 | 0 | bool RequireStartOfLine) { |
269 | | // If it is required to start a new line or finish the current, insert |
270 | | // vertical whitespace now and take it into account when moving to the |
271 | | // expected line. |
272 | 0 | bool StartedNewLine = false; |
273 | 0 | if ((RequireStartOfLine && EmittedTokensOnThisLine) || |
274 | 0 | EmittedDirectiveOnThisLine) { |
275 | 0 | *OS << '\n'; |
276 | 0 | StartedNewLine = true; |
277 | 0 | CurLine += 1; |
278 | 0 | EmittedTokensOnThisLine = false; |
279 | 0 | EmittedDirectiveOnThisLine = false; |
280 | 0 | } |
281 | | |
282 | | // If this line is "close enough" to the original line, just print newlines, |
283 | | // otherwise print a #line directive. |
284 | 0 | if (CurLine == LineNo) { |
285 | | // Nothing to do if we are already on the correct line. |
286 | 0 | } else if (MinimizeWhitespace && DisableLineMarkers) { |
287 | | // With -E -P -fminimize-whitespace, don't emit anything if not necessary. |
288 | 0 | } else if (!StartedNewLine && LineNo - CurLine == 1) { |
289 | | // Printing a single line has priority over printing a #line directive, even |
290 | | // when minimizing whitespace which otherwise would print #line directives |
291 | | // for every single line. |
292 | 0 | *OS << '\n'; |
293 | 0 | StartedNewLine = true; |
294 | 0 | } else if (!DisableLineMarkers) { |
295 | 0 | if (LineNo - CurLine <= 8) { |
296 | 0 | const char *NewLines = "\n\n\n\n\n\n\n\n"; |
297 | 0 | OS->write(NewLines, LineNo - CurLine); |
298 | 0 | } else { |
299 | | // Emit a #line or line marker. |
300 | 0 | WriteLineInfo(LineNo, nullptr, 0); |
301 | 0 | } |
302 | 0 | StartedNewLine = true; |
303 | 0 | } else if (EmittedTokensOnThisLine) { |
304 | | // If we are not on the correct line and don't need to be line-correct, |
305 | | // at least ensure we start on a new line. |
306 | 0 | *OS << '\n'; |
307 | 0 | StartedNewLine = true; |
308 | 0 | } |
309 | |
|
310 | 0 | if (StartedNewLine) { |
311 | 0 | EmittedTokensOnThisLine = false; |
312 | 0 | EmittedDirectiveOnThisLine = false; |
313 | 0 | } |
314 | |
|
315 | 0 | CurLine = LineNo; |
316 | 0 | return StartedNewLine; |
317 | 0 | } |
318 | | |
319 | 0 | void PrintPPOutputPPCallbacks::startNewLineIfNeeded() { |
320 | 0 | if (EmittedTokensOnThisLine || EmittedDirectiveOnThisLine) { |
321 | 0 | *OS << '\n'; |
322 | 0 | EmittedTokensOnThisLine = false; |
323 | 0 | EmittedDirectiveOnThisLine = false; |
324 | 0 | } |
325 | 0 | } |
326 | | |
327 | | /// FileChanged - Whenever the preprocessor enters or exits a #include file |
328 | | /// it invokes this handler. Update our conception of the current source |
329 | | /// position. |
330 | | void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc, |
331 | | FileChangeReason Reason, |
332 | | SrcMgr::CharacteristicKind NewFileType, |
333 | 0 | FileID PrevFID) { |
334 | | // Unless we are exiting a #include, make sure to skip ahead to the line the |
335 | | // #include directive was at. |
336 | 0 | SourceManager &SourceMgr = SM; |
337 | |
|
338 | 0 | PresumedLoc UserLoc = SourceMgr.getPresumedLoc(Loc); |
339 | 0 | if (UserLoc.isInvalid()) |
340 | 0 | return; |
341 | | |
342 | 0 | unsigned NewLine = UserLoc.getLine(); |
343 | |
|
344 | 0 | if (Reason == PPCallbacks::EnterFile) { |
345 | 0 | SourceLocation IncludeLoc = UserLoc.getIncludeLoc(); |
346 | 0 | if (IncludeLoc.isValid()) |
347 | 0 | MoveToLine(IncludeLoc, /*RequireStartOfLine=*/false); |
348 | 0 | } else if (Reason == PPCallbacks::SystemHeaderPragma) { |
349 | | // GCC emits the # directive for this directive on the line AFTER the |
350 | | // directive and emits a bunch of spaces that aren't needed. This is because |
351 | | // otherwise we will emit a line marker for THIS line, which requires an |
352 | | // extra blank line after the directive to avoid making all following lines |
353 | | // off by one. We can do better by simply incrementing NewLine here. |
354 | 0 | NewLine += 1; |
355 | 0 | } |
356 | |
|
357 | 0 | CurLine = NewLine; |
358 | | |
359 | | // In KeepSystemIncludes mode, redirect OS as needed. |
360 | 0 | if (KeepSystemIncludes && (isSystem(FileType) != isSystem(NewFileType))) |
361 | 0 | OS = isSystem(FileType) ? OrigOS : NullOS.get(); |
362 | |
|
363 | 0 | CurFilename.clear(); |
364 | 0 | CurFilename += UserLoc.getFilename(); |
365 | 0 | FileType = NewFileType; |
366 | |
|
367 | 0 | if (DisableLineMarkers) { |
368 | 0 | if (!MinimizeWhitespace) |
369 | 0 | startNewLineIfNeeded(); |
370 | 0 | return; |
371 | 0 | } |
372 | | |
373 | 0 | if (!Initialized) { |
374 | 0 | WriteLineInfo(CurLine); |
375 | 0 | Initialized = true; |
376 | 0 | } |
377 | | |
378 | | // Do not emit an enter marker for the main file (which we expect is the first |
379 | | // entered file). This matches gcc, and improves compatibility with some tools |
380 | | // which track the # line markers as a way to determine when the preprocessed |
381 | | // output is in the context of the main file. |
382 | 0 | if (Reason == PPCallbacks::EnterFile && !IsFirstFileEntered) { |
383 | 0 | IsFirstFileEntered = true; |
384 | 0 | return; |
385 | 0 | } |
386 | | |
387 | 0 | switch (Reason) { |
388 | 0 | case PPCallbacks::EnterFile: |
389 | 0 | WriteLineInfo(CurLine, " 1", 2); |
390 | 0 | break; |
391 | 0 | case PPCallbacks::ExitFile: |
392 | 0 | WriteLineInfo(CurLine, " 2", 2); |
393 | 0 | break; |
394 | 0 | case PPCallbacks::SystemHeaderPragma: |
395 | 0 | case PPCallbacks::RenameFile: |
396 | 0 | WriteLineInfo(CurLine); |
397 | 0 | break; |
398 | 0 | } |
399 | 0 | } |
400 | | |
401 | | void PrintPPOutputPPCallbacks::InclusionDirective( |
402 | | SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName, |
403 | | bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File, |
404 | | StringRef SearchPath, StringRef RelativePath, const Module *Imported, |
405 | 0 | SrcMgr::CharacteristicKind FileType) { |
406 | | // In -dI mode, dump #include directives prior to dumping their content or |
407 | | // interpretation. Similar for -fkeep-system-includes. |
408 | 0 | if (DumpIncludeDirectives || (KeepSystemIncludes && isSystem(FileType))) { |
409 | 0 | MoveToLine(HashLoc, /*RequireStartOfLine=*/true); |
410 | 0 | const std::string TokenText = PP.getSpelling(IncludeTok); |
411 | 0 | assert(!TokenText.empty()); |
412 | 0 | *OS << "#" << TokenText << " " |
413 | 0 | << (IsAngled ? '<' : '"') << FileName << (IsAngled ? '>' : '"') |
414 | 0 | << " /* clang -E " |
415 | 0 | << (DumpIncludeDirectives ? "-dI" : "-fkeep-system-includes") |
416 | 0 | << " */"; |
417 | 0 | setEmittedDirectiveOnThisLine(); |
418 | 0 | } |
419 | | |
420 | | // When preprocessing, turn implicit imports into module import pragmas. |
421 | 0 | if (Imported) { |
422 | 0 | switch (IncludeTok.getIdentifierInfo()->getPPKeywordID()) { |
423 | 0 | case tok::pp_include: |
424 | 0 | case tok::pp_import: |
425 | 0 | case tok::pp_include_next: |
426 | 0 | MoveToLine(HashLoc, /*RequireStartOfLine=*/true); |
427 | 0 | *OS << "#pragma clang module import " |
428 | 0 | << Imported->getFullModuleName(true) |
429 | 0 | << " /* clang -E: implicit import for " |
430 | 0 | << "#" << PP.getSpelling(IncludeTok) << " " |
431 | 0 | << (IsAngled ? '<' : '"') << FileName << (IsAngled ? '>' : '"') |
432 | 0 | << " */"; |
433 | 0 | setEmittedDirectiveOnThisLine(); |
434 | 0 | break; |
435 | | |
436 | 0 | case tok::pp___include_macros: |
437 | | // #__include_macros has no effect on a user of a preprocessed source |
438 | | // file; the only effect is on preprocessing. |
439 | | // |
440 | | // FIXME: That's not *quite* true: it causes the module in question to |
441 | | // be loaded, which can affect downstream diagnostics. |
442 | 0 | break; |
443 | | |
444 | 0 | default: |
445 | 0 | llvm_unreachable("unknown include directive kind"); |
446 | 0 | break; |
447 | 0 | } |
448 | 0 | } |
449 | 0 | } |
450 | | |
451 | | /// Handle entering the scope of a module during a module compilation. |
452 | 0 | void PrintPPOutputPPCallbacks::BeginModule(const Module *M) { |
453 | 0 | startNewLineIfNeeded(); |
454 | 0 | *OS << "#pragma clang module begin " << M->getFullModuleName(true); |
455 | 0 | setEmittedDirectiveOnThisLine(); |
456 | 0 | } |
457 | | |
458 | | /// Handle leaving the scope of a module during a module compilation. |
459 | 0 | void PrintPPOutputPPCallbacks::EndModule(const Module *M) { |
460 | 0 | startNewLineIfNeeded(); |
461 | 0 | *OS << "#pragma clang module end /*" << M->getFullModuleName(true) << "*/"; |
462 | 0 | setEmittedDirectiveOnThisLine(); |
463 | 0 | } |
464 | | |
465 | | /// Ident - Handle #ident directives when read by the preprocessor. |
466 | | /// |
467 | 0 | void PrintPPOutputPPCallbacks::Ident(SourceLocation Loc, StringRef S) { |
468 | 0 | MoveToLine(Loc, /*RequireStartOfLine=*/true); |
469 | |
|
470 | 0 | OS->write("#ident ", strlen("#ident ")); |
471 | 0 | OS->write(S.begin(), S.size()); |
472 | 0 | setEmittedTokensOnThisLine(); |
473 | 0 | } |
474 | | |
475 | | /// MacroDefined - This hook is called whenever a macro definition is seen. |
476 | | void PrintPPOutputPPCallbacks::MacroDefined(const Token &MacroNameTok, |
477 | 0 | const MacroDirective *MD) { |
478 | 0 | const MacroInfo *MI = MD->getMacroInfo(); |
479 | | // Print out macro definitions in -dD mode and when we have -fdirectives-only |
480 | | // for C++20 header units. |
481 | 0 | if ((!DumpDefines && !DirectivesOnly) || |
482 | | // Ignore __FILE__ etc. |
483 | 0 | MI->isBuiltinMacro()) |
484 | 0 | return; |
485 | | |
486 | 0 | SourceLocation DefLoc = MI->getDefinitionLoc(); |
487 | 0 | if (DirectivesOnly && !MI->isUsed()) { |
488 | 0 | SourceManager &SM = PP.getSourceManager(); |
489 | 0 | if (SM.isWrittenInBuiltinFile(DefLoc) || |
490 | 0 | SM.isWrittenInCommandLineFile(DefLoc)) |
491 | 0 | return; |
492 | 0 | } |
493 | 0 | MoveToLine(DefLoc, /*RequireStartOfLine=*/true); |
494 | 0 | PrintMacroDefinition(*MacroNameTok.getIdentifierInfo(), *MI, PP, OS); |
495 | 0 | setEmittedDirectiveOnThisLine(); |
496 | 0 | } |
497 | | |
498 | | void PrintPPOutputPPCallbacks::MacroUndefined(const Token &MacroNameTok, |
499 | | const MacroDefinition &MD, |
500 | 0 | const MacroDirective *Undef) { |
501 | | // Print out macro definitions in -dD mode and when we have -fdirectives-only |
502 | | // for C++20 header units. |
503 | 0 | if (!DumpDefines && !DirectivesOnly) |
504 | 0 | return; |
505 | | |
506 | 0 | MoveToLine(MacroNameTok.getLocation(), /*RequireStartOfLine=*/true); |
507 | 0 | *OS << "#undef " << MacroNameTok.getIdentifierInfo()->getName(); |
508 | 0 | setEmittedDirectiveOnThisLine(); |
509 | 0 | } |
510 | | |
511 | 0 | static void outputPrintable(raw_ostream *OS, StringRef Str) { |
512 | 0 | for (unsigned char Char : Str) { |
513 | 0 | if (isPrintable(Char) && Char != '\\' && Char != '"') |
514 | 0 | *OS << (char)Char; |
515 | 0 | else // Output anything hard as an octal escape. |
516 | 0 | *OS << '\\' |
517 | 0 | << (char)('0' + ((Char >> 6) & 7)) |
518 | 0 | << (char)('0' + ((Char >> 3) & 7)) |
519 | 0 | << (char)('0' + ((Char >> 0) & 7)); |
520 | 0 | } |
521 | 0 | } |
522 | | |
523 | | void PrintPPOutputPPCallbacks::PragmaMessage(SourceLocation Loc, |
524 | | StringRef Namespace, |
525 | | PragmaMessageKind Kind, |
526 | 0 | StringRef Str) { |
527 | 0 | MoveToLine(Loc, /*RequireStartOfLine=*/true); |
528 | 0 | *OS << "#pragma "; |
529 | 0 | if (!Namespace.empty()) |
530 | 0 | *OS << Namespace << ' '; |
531 | 0 | switch (Kind) { |
532 | 0 | case PMK_Message: |
533 | 0 | *OS << "message(\""; |
534 | 0 | break; |
535 | 0 | case PMK_Warning: |
536 | 0 | *OS << "warning \""; |
537 | 0 | break; |
538 | 0 | case PMK_Error: |
539 | 0 | *OS << "error \""; |
540 | 0 | break; |
541 | 0 | } |
542 | | |
543 | 0 | outputPrintable(OS, Str); |
544 | 0 | *OS << '"'; |
545 | 0 | if (Kind == PMK_Message) |
546 | 0 | *OS << ')'; |
547 | 0 | setEmittedDirectiveOnThisLine(); |
548 | 0 | } |
549 | | |
550 | | void PrintPPOutputPPCallbacks::PragmaDebug(SourceLocation Loc, |
551 | 0 | StringRef DebugType) { |
552 | 0 | MoveToLine(Loc, /*RequireStartOfLine=*/true); |
553 | |
|
554 | 0 | *OS << "#pragma clang __debug "; |
555 | 0 | *OS << DebugType; |
556 | |
|
557 | 0 | setEmittedDirectiveOnThisLine(); |
558 | 0 | } |
559 | | |
560 | | void PrintPPOutputPPCallbacks:: |
561 | 0 | PragmaDiagnosticPush(SourceLocation Loc, StringRef Namespace) { |
562 | 0 | MoveToLine(Loc, /*RequireStartOfLine=*/true); |
563 | 0 | *OS << "#pragma " << Namespace << " diagnostic push"; |
564 | 0 | setEmittedDirectiveOnThisLine(); |
565 | 0 | } |
566 | | |
567 | | void PrintPPOutputPPCallbacks:: |
568 | 0 | PragmaDiagnosticPop(SourceLocation Loc, StringRef Namespace) { |
569 | 0 | MoveToLine(Loc, /*RequireStartOfLine=*/true); |
570 | 0 | *OS << "#pragma " << Namespace << " diagnostic pop"; |
571 | 0 | setEmittedDirectiveOnThisLine(); |
572 | 0 | } |
573 | | |
574 | | void PrintPPOutputPPCallbacks::PragmaDiagnostic(SourceLocation Loc, |
575 | | StringRef Namespace, |
576 | | diag::Severity Map, |
577 | 0 | StringRef Str) { |
578 | 0 | MoveToLine(Loc, /*RequireStartOfLine=*/true); |
579 | 0 | *OS << "#pragma " << Namespace << " diagnostic "; |
580 | 0 | switch (Map) { |
581 | 0 | case diag::Severity::Remark: |
582 | 0 | *OS << "remark"; |
583 | 0 | break; |
584 | 0 | case diag::Severity::Warning: |
585 | 0 | *OS << "warning"; |
586 | 0 | break; |
587 | 0 | case diag::Severity::Error: |
588 | 0 | *OS << "error"; |
589 | 0 | break; |
590 | 0 | case diag::Severity::Ignored: |
591 | 0 | *OS << "ignored"; |
592 | 0 | break; |
593 | 0 | case diag::Severity::Fatal: |
594 | 0 | *OS << "fatal"; |
595 | 0 | break; |
596 | 0 | } |
597 | 0 | *OS << " \"" << Str << '"'; |
598 | 0 | setEmittedDirectiveOnThisLine(); |
599 | 0 | } |
600 | | |
601 | | void PrintPPOutputPPCallbacks::PragmaWarning(SourceLocation Loc, |
602 | | PragmaWarningSpecifier WarningSpec, |
603 | 0 | ArrayRef<int> Ids) { |
604 | 0 | MoveToLine(Loc, /*RequireStartOfLine=*/true); |
605 | |
|
606 | 0 | *OS << "#pragma warning("; |
607 | 0 | switch(WarningSpec) { |
608 | 0 | case PWS_Default: *OS << "default"; break; |
609 | 0 | case PWS_Disable: *OS << "disable"; break; |
610 | 0 | case PWS_Error: *OS << "error"; break; |
611 | 0 | case PWS_Once: *OS << "once"; break; |
612 | 0 | case PWS_Suppress: *OS << "suppress"; break; |
613 | 0 | case PWS_Level1: *OS << '1'; break; |
614 | 0 | case PWS_Level2: *OS << '2'; break; |
615 | 0 | case PWS_Level3: *OS << '3'; break; |
616 | 0 | case PWS_Level4: *OS << '4'; break; |
617 | 0 | } |
618 | 0 | *OS << ':'; |
619 | |
|
620 | 0 | for (ArrayRef<int>::iterator I = Ids.begin(), E = Ids.end(); I != E; ++I) |
621 | 0 | *OS << ' ' << *I; |
622 | 0 | *OS << ')'; |
623 | 0 | setEmittedDirectiveOnThisLine(); |
624 | 0 | } |
625 | | |
626 | | void PrintPPOutputPPCallbacks::PragmaWarningPush(SourceLocation Loc, |
627 | 0 | int Level) { |
628 | 0 | MoveToLine(Loc, /*RequireStartOfLine=*/true); |
629 | 0 | *OS << "#pragma warning(push"; |
630 | 0 | if (Level >= 0) |
631 | 0 | *OS << ", " << Level; |
632 | 0 | *OS << ')'; |
633 | 0 | setEmittedDirectiveOnThisLine(); |
634 | 0 | } |
635 | | |
636 | 0 | void PrintPPOutputPPCallbacks::PragmaWarningPop(SourceLocation Loc) { |
637 | 0 | MoveToLine(Loc, /*RequireStartOfLine=*/true); |
638 | 0 | *OS << "#pragma warning(pop)"; |
639 | 0 | setEmittedDirectiveOnThisLine(); |
640 | 0 | } |
641 | | |
642 | | void PrintPPOutputPPCallbacks::PragmaExecCharsetPush(SourceLocation Loc, |
643 | 0 | StringRef Str) { |
644 | 0 | MoveToLine(Loc, /*RequireStartOfLine=*/true); |
645 | 0 | *OS << "#pragma character_execution_set(push"; |
646 | 0 | if (!Str.empty()) |
647 | 0 | *OS << ", " << Str; |
648 | 0 | *OS << ')'; |
649 | 0 | setEmittedDirectiveOnThisLine(); |
650 | 0 | } |
651 | | |
652 | 0 | void PrintPPOutputPPCallbacks::PragmaExecCharsetPop(SourceLocation Loc) { |
653 | 0 | MoveToLine(Loc, /*RequireStartOfLine=*/true); |
654 | 0 | *OS << "#pragma character_execution_set(pop)"; |
655 | 0 | setEmittedDirectiveOnThisLine(); |
656 | 0 | } |
657 | | |
658 | | void PrintPPOutputPPCallbacks:: |
659 | 0 | PragmaAssumeNonNullBegin(SourceLocation Loc) { |
660 | 0 | MoveToLine(Loc, /*RequireStartOfLine=*/true); |
661 | 0 | *OS << "#pragma clang assume_nonnull begin"; |
662 | 0 | setEmittedDirectiveOnThisLine(); |
663 | 0 | } |
664 | | |
665 | | void PrintPPOutputPPCallbacks:: |
666 | 0 | PragmaAssumeNonNullEnd(SourceLocation Loc) { |
667 | 0 | MoveToLine(Loc, /*RequireStartOfLine=*/true); |
668 | 0 | *OS << "#pragma clang assume_nonnull end"; |
669 | 0 | setEmittedDirectiveOnThisLine(); |
670 | 0 | } |
671 | | |
672 | | void PrintPPOutputPPCallbacks::HandleWhitespaceBeforeTok(const Token &Tok, |
673 | | bool RequireSpace, |
674 | 0 | bool RequireSameLine) { |
675 | | // These tokens are not expanded to anything and don't need whitespace before |
676 | | // them. |
677 | 0 | if (Tok.is(tok::eof) || |
678 | 0 | (Tok.isAnnotation() && !Tok.is(tok::annot_header_unit) && |
679 | 0 | !Tok.is(tok::annot_module_begin) && !Tok.is(tok::annot_module_end) && |
680 | 0 | !Tok.is(tok::annot_repl_input_end))) |
681 | 0 | return; |
682 | | |
683 | | // EmittedDirectiveOnThisLine takes priority over RequireSameLine. |
684 | 0 | if ((!RequireSameLine || EmittedDirectiveOnThisLine) && |
685 | 0 | MoveToLine(Tok, /*RequireStartOfLine=*/EmittedDirectiveOnThisLine)) { |
686 | 0 | if (MinimizeWhitespace) { |
687 | | // Avoid interpreting hash as a directive under -fpreprocessed. |
688 | 0 | if (Tok.is(tok::hash)) |
689 | 0 | *OS << ' '; |
690 | 0 | } else { |
691 | | // Print out space characters so that the first token on a line is |
692 | | // indented for easy reading. |
693 | 0 | unsigned ColNo = SM.getExpansionColumnNumber(Tok.getLocation()); |
694 | | |
695 | | // The first token on a line can have a column number of 1, yet still |
696 | | // expect leading white space, if a macro expansion in column 1 starts |
697 | | // with an empty macro argument, or an empty nested macro expansion. In |
698 | | // this case, move the token to column 2. |
699 | 0 | if (ColNo == 1 && Tok.hasLeadingSpace()) |
700 | 0 | ColNo = 2; |
701 | | |
702 | | // This hack prevents stuff like: |
703 | | // #define HASH # |
704 | | // HASH define foo bar |
705 | | // From having the # character end up at column 1, which makes it so it |
706 | | // is not handled as a #define next time through the preprocessor if in |
707 | | // -fpreprocessed mode. |
708 | 0 | if (ColNo <= 1 && Tok.is(tok::hash)) |
709 | 0 | *OS << ' '; |
710 | | |
711 | | // Otherwise, indent the appropriate number of spaces. |
712 | 0 | for (; ColNo > 1; --ColNo) |
713 | 0 | *OS << ' '; |
714 | 0 | } |
715 | 0 | } else { |
716 | | // Insert whitespace between the previous and next token if either |
717 | | // - The caller requires it |
718 | | // - The input had whitespace between them and we are not in |
719 | | // whitespace-minimization mode |
720 | | // - The whitespace is necessary to keep the tokens apart and there is not |
721 | | // already a newline between them |
722 | 0 | if (RequireSpace || (!MinimizeWhitespace && Tok.hasLeadingSpace()) || |
723 | 0 | ((EmittedTokensOnThisLine || EmittedDirectiveOnThisLine) && |
724 | 0 | AvoidConcat(PrevPrevTok, PrevTok, Tok))) |
725 | 0 | *OS << ' '; |
726 | 0 | } |
727 | |
|
728 | 0 | PrevPrevTok = PrevTok; |
729 | 0 | PrevTok = Tok; |
730 | 0 | } |
731 | | |
732 | | void PrintPPOutputPPCallbacks::HandleNewlinesInToken(const char *TokStr, |
733 | 0 | unsigned Len) { |
734 | 0 | unsigned NumNewlines = 0; |
735 | 0 | for (; Len; --Len, ++TokStr) { |
736 | 0 | if (*TokStr != '\n' && |
737 | 0 | *TokStr != '\r') |
738 | 0 | continue; |
739 | | |
740 | 0 | ++NumNewlines; |
741 | | |
742 | | // If we have \n\r or \r\n, skip both and count as one line. |
743 | 0 | if (Len != 1 && |
744 | 0 | (TokStr[1] == '\n' || TokStr[1] == '\r') && |
745 | 0 | TokStr[0] != TokStr[1]) { |
746 | 0 | ++TokStr; |
747 | 0 | --Len; |
748 | 0 | } |
749 | 0 | } |
750 | |
|
751 | 0 | if (NumNewlines == 0) return; |
752 | | |
753 | 0 | CurLine += NumNewlines; |
754 | 0 | } |
755 | | |
756 | | |
757 | | namespace { |
758 | | struct UnknownPragmaHandler : public PragmaHandler { |
759 | | const char *Prefix; |
760 | | PrintPPOutputPPCallbacks *Callbacks; |
761 | | |
762 | | // Set to true if tokens should be expanded |
763 | | bool ShouldExpandTokens; |
764 | | |
765 | | UnknownPragmaHandler(const char *prefix, PrintPPOutputPPCallbacks *callbacks, |
766 | | bool RequireTokenExpansion) |
767 | | : Prefix(prefix), Callbacks(callbacks), |
768 | 0 | ShouldExpandTokens(RequireTokenExpansion) {} |
769 | | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, |
770 | 0 | Token &PragmaTok) override { |
771 | | // Figure out what line we went to and insert the appropriate number of |
772 | | // newline characters. |
773 | 0 | Callbacks->MoveToLine(PragmaTok.getLocation(), /*RequireStartOfLine=*/true); |
774 | 0 | Callbacks->OS->write(Prefix, strlen(Prefix)); |
775 | 0 | Callbacks->setEmittedTokensOnThisLine(); |
776 | |
|
777 | 0 | if (ShouldExpandTokens) { |
778 | | // The first token does not have expanded macros. Expand them, if |
779 | | // required. |
780 | 0 | auto Toks = std::make_unique<Token[]>(1); |
781 | 0 | Toks[0] = PragmaTok; |
782 | 0 | PP.EnterTokenStream(std::move(Toks), /*NumToks=*/1, |
783 | 0 | /*DisableMacroExpansion=*/false, |
784 | 0 | /*IsReinject=*/false); |
785 | 0 | PP.Lex(PragmaTok); |
786 | 0 | } |
787 | | |
788 | | // Read and print all of the pragma tokens. |
789 | 0 | bool IsFirst = true; |
790 | 0 | while (PragmaTok.isNot(tok::eod)) { |
791 | 0 | Callbacks->HandleWhitespaceBeforeTok(PragmaTok, /*RequireSpace=*/IsFirst, |
792 | 0 | /*RequireSameLine=*/true); |
793 | 0 | IsFirst = false; |
794 | 0 | std::string TokSpell = PP.getSpelling(PragmaTok); |
795 | 0 | Callbacks->OS->write(&TokSpell[0], TokSpell.size()); |
796 | 0 | Callbacks->setEmittedTokensOnThisLine(); |
797 | |
|
798 | 0 | if (ShouldExpandTokens) |
799 | 0 | PP.Lex(PragmaTok); |
800 | 0 | else |
801 | 0 | PP.LexUnexpandedToken(PragmaTok); |
802 | 0 | } |
803 | 0 | Callbacks->setEmittedDirectiveOnThisLine(); |
804 | 0 | } |
805 | | }; |
806 | | } // end anonymous namespace |
807 | | |
808 | | |
809 | | static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok, |
810 | 0 | PrintPPOutputPPCallbacks *Callbacks) { |
811 | 0 | bool DropComments = PP.getLangOpts().TraditionalCPP && |
812 | 0 | !PP.getCommentRetentionState(); |
813 | |
|
814 | 0 | bool IsStartOfLine = false; |
815 | 0 | char Buffer[256]; |
816 | 0 | while (true) { |
817 | | // Two lines joined with line continuation ('\' as last character on the |
818 | | // line) must be emitted as one line even though Tok.getLine() returns two |
819 | | // different values. In this situation Tok.isAtStartOfLine() is false even |
820 | | // though it may be the first token on the lexical line. When |
821 | | // dropping/skipping a token that is at the start of a line, propagate the |
822 | | // start-of-line-ness to the next token to not append it to the previous |
823 | | // line. |
824 | 0 | IsStartOfLine = IsStartOfLine || Tok.isAtStartOfLine(); |
825 | |
|
826 | 0 | Callbacks->HandleWhitespaceBeforeTok(Tok, /*RequireSpace=*/false, |
827 | 0 | /*RequireSameLine=*/!IsStartOfLine); |
828 | |
|
829 | 0 | if (DropComments && Tok.is(tok::comment)) { |
830 | | // Skip comments. Normally the preprocessor does not generate |
831 | | // tok::comment nodes at all when not keeping comments, but under |
832 | | // -traditional-cpp the lexer keeps /all/ whitespace, including comments. |
833 | 0 | PP.Lex(Tok); |
834 | 0 | continue; |
835 | 0 | } else if (Tok.is(tok::annot_repl_input_end)) { |
836 | 0 | PP.Lex(Tok); |
837 | 0 | continue; |
838 | 0 | } else if (Tok.is(tok::eod)) { |
839 | | // Don't print end of directive tokens, since they are typically newlines |
840 | | // that mess up our line tracking. These come from unknown pre-processor |
841 | | // directives or hash-prefixed comments in standalone assembly files. |
842 | 0 | PP.Lex(Tok); |
843 | | // FIXME: The token on the next line after #include should have |
844 | | // Tok.isAtStartOfLine() set. |
845 | 0 | IsStartOfLine = true; |
846 | 0 | continue; |
847 | 0 | } else if (Tok.is(tok::annot_module_include)) { |
848 | | // PrintPPOutputPPCallbacks::InclusionDirective handles producing |
849 | | // appropriate output here. Ignore this token entirely. |
850 | 0 | PP.Lex(Tok); |
851 | 0 | IsStartOfLine = true; |
852 | 0 | continue; |
853 | 0 | } else if (Tok.is(tok::annot_module_begin)) { |
854 | | // FIXME: We retrieve this token after the FileChanged callback, and |
855 | | // retrieve the module_end token before the FileChanged callback, so |
856 | | // we render this within the file and render the module end outside the |
857 | | // file, but this is backwards from the token locations: the module_begin |
858 | | // token is at the include location (outside the file) and the module_end |
859 | | // token is at the EOF location (within the file). |
860 | 0 | Callbacks->BeginModule( |
861 | 0 | reinterpret_cast<Module *>(Tok.getAnnotationValue())); |
862 | 0 | PP.Lex(Tok); |
863 | 0 | IsStartOfLine = true; |
864 | 0 | continue; |
865 | 0 | } else if (Tok.is(tok::annot_module_end)) { |
866 | 0 | Callbacks->EndModule( |
867 | 0 | reinterpret_cast<Module *>(Tok.getAnnotationValue())); |
868 | 0 | PP.Lex(Tok); |
869 | 0 | IsStartOfLine = true; |
870 | 0 | continue; |
871 | 0 | } else if (Tok.is(tok::annot_header_unit)) { |
872 | | // This is a header-name that has been (effectively) converted into a |
873 | | // module-name. |
874 | | // FIXME: The module name could contain non-identifier module name |
875 | | // components. We don't have a good way to round-trip those. |
876 | 0 | Module *M = reinterpret_cast<Module *>(Tok.getAnnotationValue()); |
877 | 0 | std::string Name = M->getFullModuleName(); |
878 | 0 | Callbacks->OS->write(Name.data(), Name.size()); |
879 | 0 | Callbacks->HandleNewlinesInToken(Name.data(), Name.size()); |
880 | 0 | } else if (Tok.isAnnotation()) { |
881 | | // Ignore annotation tokens created by pragmas - the pragmas themselves |
882 | | // will be reproduced in the preprocessed output. |
883 | 0 | PP.Lex(Tok); |
884 | 0 | continue; |
885 | 0 | } else if (IdentifierInfo *II = Tok.getIdentifierInfo()) { |
886 | 0 | *Callbacks->OS << II->getName(); |
887 | 0 | } else if (Tok.isLiteral() && !Tok.needsCleaning() && |
888 | 0 | Tok.getLiteralData()) { |
889 | 0 | Callbacks->OS->write(Tok.getLiteralData(), Tok.getLength()); |
890 | 0 | } else if (Tok.getLength() < std::size(Buffer)) { |
891 | 0 | const char *TokPtr = Buffer; |
892 | 0 | unsigned Len = PP.getSpelling(Tok, TokPtr); |
893 | 0 | Callbacks->OS->write(TokPtr, Len); |
894 | | |
895 | | // Tokens that can contain embedded newlines need to adjust our current |
896 | | // line number. |
897 | | // FIXME: The token may end with a newline in which case |
898 | | // setEmittedDirectiveOnThisLine/setEmittedTokensOnThisLine afterwards is |
899 | | // wrong. |
900 | 0 | if (Tok.getKind() == tok::comment || Tok.getKind() == tok::unknown) |
901 | 0 | Callbacks->HandleNewlinesInToken(TokPtr, Len); |
902 | 0 | if (Tok.is(tok::comment) && Len >= 2 && TokPtr[0] == '/' && |
903 | 0 | TokPtr[1] == '/') { |
904 | | // It's a line comment; |
905 | | // Ensure that we don't concatenate anything behind it. |
906 | 0 | Callbacks->setEmittedDirectiveOnThisLine(); |
907 | 0 | } |
908 | 0 | } else { |
909 | 0 | std::string S = PP.getSpelling(Tok); |
910 | 0 | Callbacks->OS->write(S.data(), S.size()); |
911 | | |
912 | | // Tokens that can contain embedded newlines need to adjust our current |
913 | | // line number. |
914 | 0 | if (Tok.getKind() == tok::comment || Tok.getKind() == tok::unknown) |
915 | 0 | Callbacks->HandleNewlinesInToken(S.data(), S.size()); |
916 | 0 | if (Tok.is(tok::comment) && S.size() >= 2 && S[0] == '/' && S[1] == '/') { |
917 | | // It's a line comment; |
918 | | // Ensure that we don't concatenate anything behind it. |
919 | 0 | Callbacks->setEmittedDirectiveOnThisLine(); |
920 | 0 | } |
921 | 0 | } |
922 | 0 | Callbacks->setEmittedTokensOnThisLine(); |
923 | 0 | IsStartOfLine = false; |
924 | |
|
925 | 0 | if (Tok.is(tok::eof)) break; |
926 | | |
927 | 0 | PP.Lex(Tok); |
928 | 0 | } |
929 | 0 | } |
930 | | |
931 | | typedef std::pair<const IdentifierInfo *, MacroInfo *> id_macro_pair; |
932 | 0 | static int MacroIDCompare(const id_macro_pair *LHS, const id_macro_pair *RHS) { |
933 | 0 | return LHS->first->getName().compare(RHS->first->getName()); |
934 | 0 | } |
935 | | |
936 | 0 | static void DoPrintMacros(Preprocessor &PP, raw_ostream *OS) { |
937 | | // Ignore unknown pragmas. |
938 | 0 | PP.IgnorePragmas(); |
939 | | |
940 | | // -dM mode just scans and ignores all tokens in the files, then dumps out |
941 | | // the macro table at the end. |
942 | 0 | PP.EnterMainSourceFile(); |
943 | |
|
944 | 0 | Token Tok; |
945 | 0 | do PP.Lex(Tok); |
946 | 0 | while (Tok.isNot(tok::eof)); |
947 | |
|
948 | 0 | SmallVector<id_macro_pair, 128> MacrosByID; |
949 | 0 | for (Preprocessor::macro_iterator I = PP.macro_begin(), E = PP.macro_end(); |
950 | 0 | I != E; ++I) { |
951 | 0 | auto *MD = I->second.getLatest(); |
952 | 0 | if (MD && MD->isDefined()) |
953 | 0 | MacrosByID.push_back(id_macro_pair(I->first, MD->getMacroInfo())); |
954 | 0 | } |
955 | 0 | llvm::array_pod_sort(MacrosByID.begin(), MacrosByID.end(), MacroIDCompare); |
956 | |
|
957 | 0 | for (unsigned i = 0, e = MacrosByID.size(); i != e; ++i) { |
958 | 0 | MacroInfo &MI = *MacrosByID[i].second; |
959 | | // Ignore computed macros like __LINE__ and friends. |
960 | 0 | if (MI.isBuiltinMacro()) continue; |
961 | | |
962 | 0 | PrintMacroDefinition(*MacrosByID[i].first, MI, PP, OS); |
963 | 0 | *OS << '\n'; |
964 | 0 | } |
965 | 0 | } |
966 | | |
967 | | /// DoPrintPreprocessedInput - This implements -E mode. |
968 | | /// |
969 | | void clang::DoPrintPreprocessedInput(Preprocessor &PP, raw_ostream *OS, |
970 | 0 | const PreprocessorOutputOptions &Opts) { |
971 | | // Show macros with no output is handled specially. |
972 | 0 | if (!Opts.ShowCPP) { |
973 | 0 | assert(Opts.ShowMacros && "Not yet implemented!"); |
974 | 0 | DoPrintMacros(PP, OS); |
975 | 0 | return; |
976 | 0 | } |
977 | | |
978 | | // Inform the preprocessor whether we want it to retain comments or not, due |
979 | | // to -C or -CC. |
980 | 0 | PP.SetCommentRetentionState(Opts.ShowComments, Opts.ShowMacroComments); |
981 | |
|
982 | 0 | PrintPPOutputPPCallbacks *Callbacks = new PrintPPOutputPPCallbacks( |
983 | 0 | PP, OS, !Opts.ShowLineMarkers, Opts.ShowMacros, |
984 | 0 | Opts.ShowIncludeDirectives, Opts.UseLineDirectives, |
985 | 0 | Opts.MinimizeWhitespace, Opts.DirectivesOnly, Opts.KeepSystemIncludes); |
986 | | |
987 | | // Expand macros in pragmas with -fms-extensions. The assumption is that |
988 | | // the majority of pragmas in such a file will be Microsoft pragmas. |
989 | | // Remember the handlers we will add so that we can remove them later. |
990 | 0 | std::unique_ptr<UnknownPragmaHandler> MicrosoftExtHandler( |
991 | 0 | new UnknownPragmaHandler( |
992 | 0 | "#pragma", Callbacks, |
993 | 0 | /*RequireTokenExpansion=*/PP.getLangOpts().MicrosoftExt)); |
994 | |
|
995 | 0 | std::unique_ptr<UnknownPragmaHandler> GCCHandler(new UnknownPragmaHandler( |
996 | 0 | "#pragma GCC", Callbacks, |
997 | 0 | /*RequireTokenExpansion=*/PP.getLangOpts().MicrosoftExt)); |
998 | |
|
999 | 0 | std::unique_ptr<UnknownPragmaHandler> ClangHandler(new UnknownPragmaHandler( |
1000 | 0 | "#pragma clang", Callbacks, |
1001 | 0 | /*RequireTokenExpansion=*/PP.getLangOpts().MicrosoftExt)); |
1002 | |
|
1003 | 0 | PP.AddPragmaHandler(MicrosoftExtHandler.get()); |
1004 | 0 | PP.AddPragmaHandler("GCC", GCCHandler.get()); |
1005 | 0 | PP.AddPragmaHandler("clang", ClangHandler.get()); |
1006 | | |
1007 | | // The tokens after pragma omp need to be expanded. |
1008 | | // |
1009 | | // OpenMP [2.1, Directive format] |
1010 | | // Preprocessing tokens following the #pragma omp are subject to macro |
1011 | | // replacement. |
1012 | 0 | std::unique_ptr<UnknownPragmaHandler> OpenMPHandler( |
1013 | 0 | new UnknownPragmaHandler("#pragma omp", Callbacks, |
1014 | 0 | /*RequireTokenExpansion=*/true)); |
1015 | 0 | PP.AddPragmaHandler("omp", OpenMPHandler.get()); |
1016 | |
|
1017 | 0 | PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks)); |
1018 | | |
1019 | | // After we have configured the preprocessor, enter the main file. |
1020 | 0 | PP.EnterMainSourceFile(); |
1021 | 0 | if (Opts.DirectivesOnly) |
1022 | 0 | PP.SetMacroExpansionOnlyInDirectives(); |
1023 | | |
1024 | | // Consume all of the tokens that come from the predefines buffer. Those |
1025 | | // should not be emitted into the output and are guaranteed to be at the |
1026 | | // start. |
1027 | 0 | const SourceManager &SourceMgr = PP.getSourceManager(); |
1028 | 0 | Token Tok; |
1029 | 0 | do { |
1030 | 0 | PP.Lex(Tok); |
1031 | 0 | if (Tok.is(tok::eof) || !Tok.getLocation().isFileID()) |
1032 | 0 | break; |
1033 | | |
1034 | 0 | PresumedLoc PLoc = SourceMgr.getPresumedLoc(Tok.getLocation()); |
1035 | 0 | if (PLoc.isInvalid()) |
1036 | 0 | break; |
1037 | | |
1038 | 0 | if (strcmp(PLoc.getFilename(), "<built-in>")) |
1039 | 0 | break; |
1040 | 0 | } while (true); |
1041 | | |
1042 | | // Read all the preprocessed tokens, printing them out to the stream. |
1043 | 0 | PrintPreprocessedTokens(PP, Tok, Callbacks); |
1044 | 0 | *OS << '\n'; |
1045 | | |
1046 | | // Remove the handlers we just added to leave the preprocessor in a sane state |
1047 | | // so that it can be reused (for example by a clang::Parser instance). |
1048 | 0 | PP.RemovePragmaHandler(MicrosoftExtHandler.get()); |
1049 | 0 | PP.RemovePragmaHandler("GCC", GCCHandler.get()); |
1050 | 0 | PP.RemovePragmaHandler("clang", ClangHandler.get()); |
1051 | 0 | PP.RemovePragmaHandler("omp", OpenMPHandler.get()); |
1052 | 0 | } |