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