clang: lib/Frontend/PrintPreprocessedOutput.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

24#include "llvm/ADT/STLExtras.h"

25#include "llvm/ADT/StringRef.h"

26#include "llvm/Support/ErrorHandling.h"

27#include "llvm/Support/raw_ostream.h"

28#include

29using namespace clang;

30

31

32

35 *OS << "#define " << II.getName();

36

38 *OS << '(';

41 for (; AI+1 != E; ++AI) {

42 *OS << (*AI)->getName();

43 *OS << ',';

44 }

45

46

47 if ((*AI)->getName() == "__VA_ARGS__")

48 *OS << "...";

49 else

50 *OS << (*AI)->getName();

51 }

52

54 *OS << "...";

55

56 *OS << ')';

57 }

58

59

60

62 *OS << ' ';

63

65 for (const auto &T : MI.tokens()) {

66 if (T.hasLeadingSpace())

67 *OS << ' ';

68

70 }

71}

72

73

74

75

76

77namespace {

78class PrintPPOutputPPCallbacks : public PPCallbacks {

79 Preprocessor &PP;

80 SourceManager &SM;

81 TokenConcatenation ConcatInfo;

82public:

83 raw_ostream *OS;

84private:

85 unsigned CurLine;

86

87 bool EmittedTokensOnThisLine;

88 bool EmittedDirectiveOnThisLine;

90 SmallString<512> CurFilename;

91 bool Initialized;

92 bool DisableLineMarkers;

93 bool DumpDefines;

94 bool DumpIncludeDirectives;

95 bool DumpEmbedDirectives;

96 bool UseLineDirectives;

97 bool IsFirstFileEntered;

98 bool MinimizeWhitespace;

99 bool DirectivesOnly;

100 bool KeepSystemIncludes;

101 raw_ostream *OrigOS;

102 std::unique_ptrllvm::raw\_null\_ostream NullOS;

103 unsigned NumToksToSkip;

104

105 Token PrevTok;

106 Token PrevPrevTok;

107

108public:

109 PrintPPOutputPPCallbacks(Preprocessor &pp, raw_ostream *os, bool lineMarkers,

110 bool defines, bool DumpIncludeDirectives,

111 bool DumpEmbedDirectives, bool UseLineDirectives,

112 bool MinimizeWhitespace, bool DirectivesOnly,

113 bool KeepSystemIncludes)

114 : PP(pp), SM(PP.getSourceManager()), ConcatInfo(PP), OS(os),

115 DisableLineMarkers(lineMarkers), DumpDefines(defines),

116 DumpIncludeDirectives(DumpIncludeDirectives),

117 DumpEmbedDirectives(DumpEmbedDirectives),

118 UseLineDirectives(UseLineDirectives),

119 MinimizeWhitespace(MinimizeWhitespace), DirectivesOnly(DirectivesOnly),

120 KeepSystemIncludes(KeepSystemIncludes), OrigOS(os), NumToksToSkip(0) {

121 CurLine = 0;

122 CurFilename += "";

123 EmittedTokensOnThisLine = false;

124 EmittedDirectiveOnThisLine = false;

126 Initialized = false;

127 IsFirstFileEntered = false;

128 if (KeepSystemIncludes)

129 NullOS = std::make_uniquellvm::raw\_null\_ostream();

130

131 PrevTok.startToken();

132 PrevPrevTok.startToken();

133 }

134

135

136

137 bool expandEmbedContents() const { return !DumpEmbedDirectives; }

138

139 bool isMinimizeWhitespace() const { return MinimizeWhitespace; }

140

141 void setEmittedTokensOnThisLine() { EmittedTokensOnThisLine = true; }

142 bool hasEmittedTokensOnThisLine() const { return EmittedTokensOnThisLine; }

143

144 void setEmittedDirectiveOnThisLine() { EmittedDirectiveOnThisLine = true; }

145 bool hasEmittedDirectiveOnThisLine() const {

146 return EmittedDirectiveOnThisLine;

147 }

148

149

150

151

152

153

154 void startNewLineIfNeeded();

155

156 void FileChanged(SourceLocation Loc, FileChangeReason Reason,

158 FileID PrevFID) override;

159 void EmbedDirective(SourceLocation HashLoc, StringRef FileName, bool IsAngled,

161 const LexEmbedParametersResult &Params) override;

162 void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,

163 StringRef FileName, bool IsAngled,

164 CharSourceRange FilenameRange,

166 StringRef RelativePath, const Module *SuggestedModule,

167 bool ModuleImported,

169 void Ident(SourceLocation Loc, StringRef str) override;

170 void PragmaMessage(SourceLocation Loc, StringRef Namespace,

171 PragmaMessageKind Kind, StringRef Str) override;

172 void PragmaDebug(SourceLocation Loc, StringRef DebugType) override;

173 void PragmaDiagnosticPush(SourceLocation Loc, StringRef Namespace) override;

174 void PragmaDiagnosticPop(SourceLocation Loc, StringRef Namespace) override;

175 void PragmaDiagnostic(SourceLocation Loc, StringRef Namespace,

177 void PragmaWarning(SourceLocation Loc, PragmaWarningSpecifier WarningSpec,

178 ArrayRef Ids) override;

179 void PragmaWarningPush(SourceLocation Loc, int Level) override;

180 void PragmaWarningPop(SourceLocation Loc) override;

181 void PragmaExecCharsetPush(SourceLocation Loc, StringRef Str) override;

182 void PragmaExecCharsetPop(SourceLocation Loc) override;

183 void PragmaAssumeNonNullBegin(SourceLocation Loc) override;

184 void PragmaAssumeNonNullEnd(SourceLocation Loc) override;

185

186

187

188

189

190

191

192

193 void HandleWhitespaceBeforeTok(const Token &Tok, bool RequireSpace,

194 bool RequireSameLine);

195

196

197

198

199

200

201

202

203

204

205

206

207

208 bool MoveToLine(const Token &Tok, bool RequireStartOfLine) {

209 PresumedLoc PLoc = SM.getPresumedLoc(Tok.getLocation());

210 unsigned TargetLine = PLoc.isValid() ? PLoc.getLine() : CurLine;

211 bool IsFirstInFile =

213 return MoveToLine(TargetLine, RequireStartOfLine) || IsFirstInFile;

214 }

215

216

217

218 bool MoveToLine(SourceLocation Loc, bool RequireStartOfLine) {

219 PresumedLoc PLoc = SM.getPresumedLoc(Loc);

220 unsigned TargetLine = PLoc.isValid() ? PLoc.getLine() : CurLine;

221 return MoveToLine(TargetLine, RequireStartOfLine);

222 }

223 bool MoveToLine(unsigned LineNo, bool RequireStartOfLine);

224

225 bool AvoidConcat(const Token &PrevPrevTok, const Token &PrevTok,

226 const Token &Tok) {

227 return ConcatInfo.AvoidConcat(PrevPrevTok, PrevTok, Tok);

228 }

229 void WriteLineInfo(unsigned LineNo, const char *Extra=nullptr,

230 unsigned ExtraLen=0);

231 bool LineMarkersAreDisabled() const { return DisableLineMarkers; }

232 void HandleNewlinesInToken(const char *TokStr, unsigned Len);

233

234

235 void MacroDefined(const Token &MacroNameTok,

236 const MacroDirective *MD) override;

237

238

239 void MacroUndefined(const Token &MacroNameTok,

240 const MacroDefinition &MD,

241 const MacroDirective *Undef) override;

242

243 void BeginModule(const Module *M);

244 void EndModule(const Module *M);

245

246 unsigned GetNumToksToSkip() const { return NumToksToSkip; }

247 void ResetSkipToks() { NumToksToSkip = 0; }

248};

249}

250

251void PrintPPOutputPPCallbacks::WriteLineInfo(unsigned LineNo,

252 const char *Extra,

253 unsigned ExtraLen) {

254 startNewLineIfNeeded();

255

256

257 if (UseLineDirectives) {

258 *OS << "#line" << ' ' << LineNo << ' ' << '"';

259 OS->write_escaped(CurFilename);

260 *OS << '"';

261 } else {

262 *OS << '#' << ' ' << LineNo << ' ' << '"';

263 OS->write_escaped(CurFilename);

264 *OS << '"';

265

266 if (ExtraLen)

267 OS->write(Extra, ExtraLen);

268

270 OS->write(" 3", 2);

272 OS->write(" 3 4", 4);

273 }

274 *OS << '\n';

275}

276

277

278

279

280

281bool PrintPPOutputPPCallbacks::MoveToLine(unsigned LineNo,

282 bool RequireStartOfLine) {

283

284

285

286 bool StartedNewLine = false;

287 if ((RequireStartOfLine && EmittedTokensOnThisLine) ||

288 EmittedDirectiveOnThisLine) {

289 *OS << '\n';

290 StartedNewLine = true;

291 CurLine += 1;

292 EmittedTokensOnThisLine = false;

293 EmittedDirectiveOnThisLine = false;

294 }

295

296

297

298 if (CurLine == LineNo) {

299

300 } else if (MinimizeWhitespace && DisableLineMarkers) {

301

302 } else if (!StartedNewLine && LineNo - CurLine == 1) {

303

304

305

306 *OS << '\n';

307 StartedNewLine = true;

308 } else if (!DisableLineMarkers) {

309 if (LineNo - CurLine <= 8) {

310 const char *NewLines = "\n\n\n\n\n\n\n\n";

311 OS->write(NewLines, LineNo - CurLine);

312 } else {

313

314 WriteLineInfo(LineNo, nullptr, 0);

315 }

316 StartedNewLine = true;

317 } else if (EmittedTokensOnThisLine) {

318

319

320 *OS << '\n';

321 StartedNewLine = true;

322 }

323

324 if (StartedNewLine) {

325 EmittedTokensOnThisLine = false;

326 EmittedDirectiveOnThisLine = false;

327 }

328

329 CurLine = LineNo;

330 return StartedNewLine;

331}

332

333void PrintPPOutputPPCallbacks::startNewLineIfNeeded() {

334 if (EmittedTokensOnThisLine || EmittedDirectiveOnThisLine) {

335 *OS << '\n';

336 EmittedTokensOnThisLine = false;

337 EmittedDirectiveOnThisLine = false;

338 }

339}

340

341

342

343

344void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc,

345 FileChangeReason Reason,

347 FileID PrevFID) {

348

349

350 SourceManager &SourceMgr = SM;

351

354 return;

355

356 unsigned NewLine = UserLoc.getLine();

357

359 SourceLocation IncludeLoc = UserLoc.getIncludeLoc();

360 if (IncludeLoc.isValid())

361 MoveToLine(IncludeLoc, false);

363

364

365

366

367

368 NewLine += 1;

369 }

370

371 CurLine = NewLine;

372

373

376

377 CurFilename.clear();

380

381 if (DisableLineMarkers) {

382 if (!MinimizeWhitespace)

383 startNewLineIfNeeded();

384 return;

385 }

386

388 WriteLineInfo(CurLine);

390 }

391

392

393

394

395

397 IsFirstFileEntered = true;

398 return;

399 }

400

401 switch (Reason) {

403 WriteLineInfo(CurLine, " 1", 2);

404 break;

406 WriteLineInfo(CurLine, " 2", 2);

407 break;

410 WriteLineInfo(CurLine);

411 break;

412 }

413}

414

415void PrintPPOutputPPCallbacks::EmbedDirective(

416 SourceLocation HashLoc, StringRef FileName, bool IsAngled,

418 if (!DumpEmbedDirectives)

419 return;

420

421

422

423

424

425

426

427

428

429

430

431 MoveToLine(HashLoc, true);

432 *OS << "#embed " << (IsAngled ? '<' : '"') << FileName

433 << (IsAngled ? '>' : '"');

434

435 auto PrintToks = [&](llvm::ArrayRef Toks) {

436 SmallString<128> SpellingBuffer;

437 for (const Token &T : Toks) {

438 if (T.hasLeadingSpace())

439 *OS << " ";

441 }

442 };

443 bool SkipAnnotToks = true;

445 *OS << " if_empty(";

447 *OS << ")";

448

449

450 if (File && File->getSize()) {

452 SkipAnnotToks = false;

453 }

454 }

455

458 }

461 }

463 *OS << " prefix(";

465 *OS << ")";

467 }

469 *OS << " suffix(";

471 *OS << ")";

473 }

474

475

476 if (SkipAnnotToks)

477 NumToksToSkip++;

478

479 *OS << " /* clang -E -dE */";

480 setEmittedDirectiveOnThisLine();

481}

482

483void PrintPPOutputPPCallbacks::InclusionDirective(

484 SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,

486 StringRef SearchPath, StringRef RelativePath, const Module *SuggestedModule,

488

489

490 if (DumpIncludeDirectives || (KeepSystemIncludes && isSystem(FileType))) {

491 MoveToLine(HashLoc, true);

495 << (IsAngled ? '<' : '"') << FileName << (IsAngled ? '>' : '"')

496 << " /* clang -E "

497 << (DumpIncludeDirectives ? "-dI" : "-fkeep-system-includes")

498 << " */";

499 setEmittedDirectiveOnThisLine();

500 }

501

502

503 if (ModuleImported) {

505 case tok::pp_include:

506 case tok::pp_import:

507 case tok::pp_include_next:

508 MoveToLine(HashLoc, true);

509 *OS << "#pragma clang module import "

511 << " /* clang -E: implicit import for "

512 << "#" << PP.getSpelling(IncludeTok) << " "

513 << (IsAngled ? '<' : '"') << FileName << (IsAngled ? '>' : '"')

514 << " */";

515 setEmittedDirectiveOnThisLine();

516 break;

517

518 case tok::pp___include_macros:

519

520

521

522

523

524 break;

525

526 default:

527 llvm_unreachable("unknown include directive kind");

528 break;

529 }

530 }

531}

532

533

534void PrintPPOutputPPCallbacks::BeginModule(const Module *M) {

535 startNewLineIfNeeded();

537 setEmittedDirectiveOnThisLine();

538}

539

540

541void PrintPPOutputPPCallbacks::EndModule(const Module *M) {

542 startNewLineIfNeeded();

543 *OS << "#pragma clang module end /*" << M->getFullModuleName(true) << "*/";

544 setEmittedDirectiveOnThisLine();

545}

546

547

548

549void PrintPPOutputPPCallbacks::Ident(SourceLocation Loc, StringRef S) {

550 MoveToLine(Loc, true);

551

552 OS->write("#ident ", strlen("#ident "));

553 OS->write(S.begin(), S.size());

554 setEmittedTokensOnThisLine();

555}

556

557

558void PrintPPOutputPPCallbacks::MacroDefined(const Token &MacroNameTok,

559 const MacroDirective *MD) {

561

562

563 if ((!DumpDefines && !DirectivesOnly) ||

564

566 return;

567

569 if (DirectivesOnly && !MI->isUsed()) {

571 if (SM.isInPredefinedFile(DefLoc))

572 return;

573 }

574 MoveToLine(DefLoc, true);

576 setEmittedDirectiveOnThisLine();

577}

578

579void PrintPPOutputPPCallbacks::MacroUndefined(const Token &MacroNameTok,

580 const MacroDefinition &MD,

581 const MacroDirective *Undef) {

582

583

584 if (!DumpDefines && !DirectivesOnly)

585 return;

586

587 MoveToLine(MacroNameTok.getLocation(), true);

589 setEmittedDirectiveOnThisLine();

590}

591

593 for (unsigned char Char : Str) {

594 if (isPrintable(Char) && Char != '\\' && Char != '"')

595 *OS << (char)Char;

596 else

597 *OS << '\\'

598 << (char)('0' + ((Char >> 6) & 7))

599 << (char)('0' + ((Char >> 3) & 7))

600 << (char)('0' + ((Char >> 0) & 7));

601 }

602}

603

604void PrintPPOutputPPCallbacks::PragmaMessage(SourceLocation Loc,

605 StringRef Namespace,

606 PragmaMessageKind Kind,

607 StringRef Str) {

608 MoveToLine(Loc, true);

609 *OS << "#pragma ";

612 switch (Kind) {

613 case PMK_Message:

614 *OS << "message(\"";

615 break;

616 case PMK_Warning:

617 *OS << "warning \"";

618 break;

619 case PMK_Error:

620 *OS << "error \"";

621 break;

622 }

623

625 *OS << '"';

626 if (Kind == PMK_Message)

627 *OS << ')';

628 setEmittedDirectiveOnThisLine();

629}

630

631void PrintPPOutputPPCallbacks::PragmaDebug(SourceLocation Loc,

632 StringRef DebugType) {

633 MoveToLine(Loc, true);

634

635 *OS << "#pragma clang __debug ";

636 *OS << DebugType;

637

638 setEmittedDirectiveOnThisLine();

639}

640

641void PrintPPOutputPPCallbacks::

642PragmaDiagnosticPush(SourceLocation Loc, StringRef Namespace) {

643 MoveToLine(Loc, true);

644 *OS << "#pragma " << Namespace << " diagnostic push";

645 setEmittedDirectiveOnThisLine();

646}

647

648void PrintPPOutputPPCallbacks::

649PragmaDiagnosticPop(SourceLocation Loc, StringRef Namespace) {

650 MoveToLine(Loc, true);

651 *OS << "#pragma " << Namespace << " diagnostic pop";

652 setEmittedDirectiveOnThisLine();

653}

654

655void PrintPPOutputPPCallbacks::PragmaDiagnostic(SourceLocation Loc,

656 StringRef Namespace,

658 StringRef Str) {

659 MoveToLine(Loc, true);

660 *OS << "#pragma " << Namespace << " diagnostic ";

661 switch (Map) {

662 case diag::Severity::Remark:

663 *OS << "remark";

664 break;

665 case diag::Severity::Warning:

666 *OS << "warning";

667 break;

668 case diag::Severity::Error:

669 *OS << "error";

670 break;

671 case diag::Severity::Ignored:

672 *OS << "ignored";

673 break;

674 case diag::Severity::Fatal:

675 *OS << "fatal";

676 break;

677 }

678 *OS << " \"" << Str << '"';

679 setEmittedDirectiveOnThisLine();

680}

681

682void PrintPPOutputPPCallbacks::PragmaWarning(SourceLocation Loc,

683 PragmaWarningSpecifier WarningSpec,

684 ArrayRef Ids) {

685 MoveToLine(Loc, true);

686

687 *OS << "#pragma warning(";

688 switch(WarningSpec) {

689 case PWS_Default: *OS << "default"; break;

690 case PWS_Disable: *OS << "disable"; break;

691 case PWS_Error: *OS << "error"; break;

692 case PWS_Once: *OS << "once"; break;

693 case PWS_Suppress: *OS << "suppress"; break;

694 case PWS_Level1: *OS << '1'; break;

695 case PWS_Level2: *OS << '2'; break;

696 case PWS_Level3: *OS << '3'; break;

697 case PWS_Level4: *OS << '4'; break;

698 }

699 *OS << ':';

700

701 for (ArrayRef::iterator I = Ids.begin(), E = Ids.end(); I != E; ++I)

702 *OS << ' ' << *I;

703 *OS << ')';

704 setEmittedDirectiveOnThisLine();

705}

706

707void PrintPPOutputPPCallbacks::PragmaWarningPush(SourceLocation Loc,

708 int Level) {

709 MoveToLine(Loc, true);

710 *OS << "#pragma warning(push";

711 if (Level >= 0)

713 *OS << ')';

714 setEmittedDirectiveOnThisLine();

715}

716

717void PrintPPOutputPPCallbacks::PragmaWarningPop(SourceLocation Loc) {

718 MoveToLine(Loc, true);

719 *OS << "#pragma warning(pop)";

720 setEmittedDirectiveOnThisLine();

721}

722

723void PrintPPOutputPPCallbacks::PragmaExecCharsetPush(SourceLocation Loc,

724 StringRef Str) {

725 MoveToLine(Loc, true);

726 *OS << "#pragma character_execution_set(push";

727 if (!Str.empty())

728 *OS << ", " << Str;

729 *OS << ')';

730 setEmittedDirectiveOnThisLine();

731}

732

733void PrintPPOutputPPCallbacks::PragmaExecCharsetPop(SourceLocation Loc) {

734 MoveToLine(Loc, true);

735 *OS << "#pragma character_execution_set(pop)";

736 setEmittedDirectiveOnThisLine();

737}

738

739void PrintPPOutputPPCallbacks::

740PragmaAssumeNonNullBegin(SourceLocation Loc) {

741 MoveToLine(Loc, true);

742 *OS << "#pragma clang assume_nonnull begin";

743 setEmittedDirectiveOnThisLine();

744}

745

746void PrintPPOutputPPCallbacks::

747PragmaAssumeNonNullEnd(SourceLocation Loc) {

748 MoveToLine(Loc, true);

749 *OS << "#pragma clang assume_nonnull end";

750 setEmittedDirectiveOnThisLine();

751}

752

753void PrintPPOutputPPCallbacks::HandleWhitespaceBeforeTok(const Token &Tok,

754 bool RequireSpace,

755 bool RequireSameLine) {

756

757

758 if (Tok.is(tok::eof) ||

760 Tok.is(tok::annot_module_begin) && Tok.is(tok::annot_module_end) &&

761 Tok.is(tok::annot_repl_input_end) && Tok.is(tok::annot_embed)))

762 return;

763

764

765 if ((!RequireSameLine || EmittedDirectiveOnThisLine) &&

766 MoveToLine(Tok, EmittedDirectiveOnThisLine)) {

767 if (MinimizeWhitespace) {

768

769 if (Tok.is(tok::hash))

770 *OS << ' ';

771 } else {

772

773

774 unsigned ColNo = SM.getExpansionColumnNumber(Tok.getLocation());

775

776

777

778

779

781 ColNo = 2;

782

783

784

785

786

787

788

789 if (ColNo <= 1 && Tok.is(tok::hash))

790 *OS << ' ';

791

792

793 for (; ColNo > 1; --ColNo)

794 *OS << ' ';

795 }

796 } else {

797

798

799

800

801

802

803 if (RequireSpace || (!MinimizeWhitespace && Tok.hasLeadingSpace()) ||

804 ((EmittedTokensOnThisLine || EmittedDirectiveOnThisLine) &&

805 AvoidConcat(PrevPrevTok, PrevTok, Tok)))

806 *OS << ' ';

807 }

808

809 PrevPrevTok = PrevTok;

810 PrevTok = Tok;

811}

812

813void PrintPPOutputPPCallbacks::HandleNewlinesInToken(const char *TokStr,

814 unsigned Len) {

815 unsigned NumNewlines = 0;

816 for (; Len; --Len, ++TokStr) {

817 if (*TokStr != '\n' &&

818 *TokStr != '\r')

819 continue;

820

821 ++NumNewlines;

822

823

824 if (Len != 1 &&

825 (TokStr[1] == '\n' || TokStr[1] == '\r') &&

826 TokStr[0] != TokStr[1]) {

827 ++TokStr;

828 --Len;

829 }

830 }

831

832 if (NumNewlines == 0) return;

833

834 CurLine += NumNewlines;

835}

836

837

838namespace {

839struct UnknownPragmaHandler : public PragmaHandler {

840 const char *Prefix;

841 PrintPPOutputPPCallbacks *Callbacks;

842

843

844 bool ShouldExpandTokens;

845

846 UnknownPragmaHandler(const char *prefix, PrintPPOutputPPCallbacks *callbacks,

847 bool RequireTokenExpansion)

848 : Prefix(prefix), Callbacks(callbacks),

849 ShouldExpandTokens(RequireTokenExpansion) {}

850 void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,

851 Token &PragmaTok) override {

852

853

854 Callbacks->MoveToLine(PragmaTok.getLocation(), true);

855 Callbacks->OS->write(Prefix, strlen(Prefix));

856 Callbacks->setEmittedTokensOnThisLine();

857

858 if (ShouldExpandTokens) {

859

860

861 auto Toks = std::make_unique<Token[]>(1);

862 Toks[0] = PragmaTok;

863 PP.EnterTokenStream(std::move(Toks), 1,

864 false,

865 false);

866 PP.Lex(PragmaTok);

867 }

868

869

871 while (PragmaTok.isNot(tok::eod)) {

872 Callbacks->HandleWhitespaceBeforeTok(PragmaTok, IsFirst,

873 true);

875 std::string TokSpell = PP.getSpelling(PragmaTok);

876 Callbacks->OS->write(&TokSpell[0], TokSpell.size());

877 Callbacks->setEmittedTokensOnThisLine();

878

879 if (ShouldExpandTokens)

880 PP.Lex(PragmaTok);

881 else

883 }

884 Callbacks->setEmittedDirectiveOnThisLine();

885 }

886};

887}

888

889

891 PrintPPOutputPPCallbacks *Callbacks) {

892 bool DropComments = PP.getLangOpts().TraditionalCPP &&

894

895 bool IsStartOfLine = false;

896 char Buffer[256];

897 while (true) {

898

899

900

901

902

903

904

905 IsStartOfLine = IsStartOfLine || Tok.isAtStartOfLine();

906

907 Callbacks->HandleWhitespaceBeforeTok(Tok, false,

908 !IsStartOfLine);

909

910 if (DropComments && Tok.is(tok::comment)) {

911

912

913

915 continue;

916 } else if (Tok.is(tok::annot_repl_input_end)) {

917

918 } else if (Tok.is(tok::eod)) {

919

920

921

923

924

925 IsStartOfLine = true;

926 continue;

927 } else if (Tok.is(tok::annot_module_include)) {

928

929

931 IsStartOfLine = true;

932 continue;

933 } else if (Tok.is(tok::annot_module_begin)) {

934

935

936

937

938

939

940 Callbacks->BeginModule(

941 reinterpret_cast<Module *>(Tok.getAnnotationValue()));

943 IsStartOfLine = true;

944 continue;

945 } else if (Tok.is(tok::annot_module_end)) {

946 Callbacks->EndModule(

947 reinterpret_cast<Module *>(Tok.getAnnotationValue()));

949 IsStartOfLine = true;

950 continue;

951 } else if (Tok.is(tok::annot_header_unit)) {

952

953

954

955

956

957 Module *M = reinterpret_cast<Module *>(Tok.getAnnotationValue());

959 *Callbacks->OS << '"';

960 Callbacks->OS->write_escaped(Name);

961 *Callbacks->OS << '"';

962 } else if (Tok.is(tok::annot_embed)) {

963

964

965

966

967 assert(Callbacks->expandEmbedContents() &&

968 "did not expect an embed annotation");

971

972

973

974 bool PrintComma = false;

975 for (unsigned char Byte : Data->BinaryData.bytes()) {

976 if (PrintComma)

977 *Callbacks->OS << ", ";

978 *Callbacks->OS << static_cast<int>(Byte);

979 PrintComma = true;

980 }

981 } else if (Tok.isAnnotation()) {

982

983

985 continue;

987 *Callbacks->OS << II->getName();

988 } else if (Tok.isLiteral() && Tok.needsCleaning() &&

989 Tok.getLiteralData()) {

990 Callbacks->OS->write(Tok.getLiteralData(), Tok.getLength());

991 } else if (Tok.getLength() < std::size(Buffer)) {

992 const char *TokPtr = Buffer;

994 Callbacks->OS->write(TokPtr, Len);

995

996

997

998

999

1000

1001 if (Tok.getKind() == tok::comment || Tok.getKind() == tok::unknown)

1002 Callbacks->HandleNewlinesInToken(TokPtr, Len);

1003 if (Tok.is(tok::comment) && Len >= 2 && TokPtr[0] == '/' &&

1004 TokPtr[1] == '/') {

1005

1006

1007 Callbacks->setEmittedDirectiveOnThisLine();

1008 }

1009 } else {

1011 Callbacks->OS->write(S.data(), S.size());

1012

1013

1014

1015 if (Tok.getKind() == tok::comment || Tok.getKind() == tok::unknown)

1016 Callbacks->HandleNewlinesInToken(S.data(), S.size());

1017 if (Tok.is(tok::comment) && S.size() >= 2 && S[0] == '/' && S[1] == '/') {

1018

1019

1020 Callbacks->setEmittedDirectiveOnThisLine();

1021 }

1022 }

1023 Callbacks->setEmittedTokensOnThisLine();

1024 IsStartOfLine = false;

1025

1026 if (Tok.is(tok::eof) || Tok.is(tok::annot_repl_input_end))

1027 break;

1028

1030

1031 for (unsigned I = 0, Skip = Callbacks->GetNumToksToSkip(); I < Skip; ++I)

1033 Callbacks->ResetSkipToks();

1034 }

1035}

1036

1037typedef std::pair<const IdentifierInfo *, MacroInfo *> id_macro_pair;

1039 return LHS->first->getName().compare(RHS->first->getName());

1040}

1041

1043

1045

1046

1047

1049

1051

1054 I != E; ++I) {

1055 auto *MD = I->second.getLatest();

1056 if (MD && MD->isDefined())

1058 }

1059 llvm::array_pod_sort(MacrosByID.begin(), MacrosByID.end(), MacroIDCompare);

1060

1061 for (unsigned i = 0, e = MacrosByID.size(); i != e; ++i) {

1062 MacroInfo &MI = *MacrosByID[i].second;

1063

1065

1067 *OS << '\n';

1068 }

1069}

1070

1071

1072

1075

1077 assert(Opts.ShowMacros && "Not yet implemented!");

1079 return;

1080 }

1081

1082

1083

1085

1086 PrintPPOutputPPCallbacks *Callbacks = new PrintPPOutputPPCallbacks(

1091

1092

1093

1094

1095 std::unique_ptr MicrosoftExtHandler(

1096 new UnknownPragmaHandler(

1097 "#pragma", Callbacks,

1098 PP.getLangOpts().MicrosoftExt));

1099

1100 std::unique_ptr GCCHandler(new UnknownPragmaHandler(

1101 "#pragma GCC", Callbacks,

1102 PP.getLangOpts().MicrosoftExt));

1103

1104 std::unique_ptr ClangHandler(new UnknownPragmaHandler(

1105 "#pragma clang", Callbacks,

1106 PP.getLangOpts().MicrosoftExt));

1107

1111

1112

1113

1114

1115

1116

1117 std::unique_ptr OpenMPHandler(

1118 new UnknownPragmaHandler("#pragma omp", Callbacks,

1119 true));

1121

1122 PP.addPPCallbacks(std::unique_ptr(Callbacks));

1123

1124

1128

1129

1130

1131

1134 do {

1136 if (Tok.is(tok::eof) || Tok.getLocation().isFileID())

1137 break;

1138

1139 PresumedLoc PLoc = SourceMgr.getPresumedLoc(Tok.getLocation());

1141 break;

1142

1143 if (strcmp(PLoc.getFilename(), ""))

1144 break;

1145 } while (true);

1146

1147

1149 *OS << '\n';

1150

1151

1152

1157}

Defines the Diagnostic-related interfaces.

StringRef TokenText

The raw text of the token.

unsigned IsFirst

Indicates that this is the first token of the file.

llvm::MachO::FileType FileType

Defines the clang::MacroInfo and clang::MacroDirective classes.

Defines the PPCallbacks interface.

Defines the clang::Preprocessor interface.

std::pair< const IdentifierInfo *, MacroInfo * > id_macro_pair

Definition PrintPreprocessedOutput.cpp:1037

static void DoPrintMacros(Preprocessor &PP, raw_ostream *OS)

Definition PrintPreprocessedOutput.cpp:1042

static void PrintMacroDefinition(const IdentifierInfo &II, const MacroInfo &MI, Preprocessor &PP, raw_ostream *OS)

PrintMacroDefinition - Print a macro definition in a form that will be properly accepted back as a de...

Definition PrintPreprocessedOutput.cpp:33

static int MacroIDCompare(const id_macro_pair *LHS, const id_macro_pair *RHS)

Definition PrintPreprocessedOutput.cpp:1038

static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok, PrintPPOutputPPCallbacks *Callbacks)

Definition PrintPreprocessedOutput.cpp:890

static void outputPrintable(raw_ostream *OS, StringRef Str)

Definition PrintPreprocessedOutput.cpp:592

Defines the SourceManager interface.

One of these records is kept for each identifier that is lexed.

tok::PPKeywordKind getPPKeywordID() const

Return the preprocessor keyword ID for this identifier.

StringRef getName() const

Return the actual identifier string.

MacroInfo * getMacroInfo() const

Get the MacroInfo that should be used for this definition.

const MacroInfo * getMacroInfo() const

Encapsulates the data about a macro definition (e.g.

bool isUsed() const

Return false if this macro is defined in the main file and has not yet been used.

bool isFunctionLike() const

const_tokens_iterator tokens_begin() const

param_iterator param_begin() const

bool isBuiltinMacro() const

Return true if this macro requires processing before expansion.

IdentifierInfo *const * param_iterator

Parameters - The list of parameters for a function-like macro.

SourceLocation getDefinitionLoc() const

Return the location that the macro was defined at.

bool tokens_empty() const

param_iterator param_end() const

ArrayRef< Token > tokens() const

bool isGNUVarargs() const

Describes a module or submodule.

std::string getFullModuleName(bool AllowStringLiterals=false) const

Retrieve the full name of this module, including the path from its top-level module.

This interface provides a way to observe the actions of the preprocessor as it does its thing.

PreprocessorOutputOptions - Options for controlling the C preprocessor output (e.g....

unsigned UseLineDirectives

Use #line instead of GCC-style # N.

unsigned ShowMacros

Print macro definitions.

unsigned ShowIncludeDirectives

Print includes, imports etc. within preprocessed output.

unsigned ShowMacroComments

Show comments, even in macros.

unsigned ShowCPP

Print normal preprocessed output.

unsigned MinimizeWhitespace

Ignore whitespace from input.

unsigned KeepSystemIncludes

Do not expand system headers.

unsigned ShowComments

Show comments.

unsigned ShowEmbedDirectives

Print embeds, etc. within preprocessed.

unsigned ShowLineMarkers

Show #line markers.

unsigned DirectivesOnly

Process directives but do not expand macros.

Engages in a tight little dance with the lexer to efficiently preprocess tokens.

void IgnorePragmas()

Install empty handlers for all pragmas (making them ignored).

macro_iterator macro_begin(bool IncludeExternalMacros=true) const

void Lex(Token &Result)

Lex the next token for this preprocessor.

void addPPCallbacks(std::unique_ptr< PPCallbacks > C)

void EnterMainSourceFile()

Enter the specified FileID as the main source file, which implicitly adds the builtin defines etc.

macro_iterator macro_end(bool IncludeExternalMacros=true) const

SourceManager & getSourceManager() const

bool getCommentRetentionState() const

void SetMacroExpansionOnlyInDirectives()

Disables macro expansion everywhere except for preprocessor directives.

MacroMap::const_iterator macro_iterator

void LexUnexpandedToken(Token &Result)

Just like Lex, but disables macro expansion of identifier tokens.

void AddPragmaHandler(StringRef Namespace, PragmaHandler *Handler)

Add the specified pragma handler to this preprocessor.

StringRef getSpelling(SourceLocation loc, SmallVectorImpl< char > &buffer, bool *invalid=nullptr) const

Return the 'spelling' of the token at the given location; does not go up to the spelling location or ...

const LangOptions & getLangOpts() const

void LexTokensUntilEOF(std::vector< Token > *Tokens=nullptr)

Lex all tokens for this preprocessor until (and excluding) end of file.

void SetCommentRetentionState(bool KeepComments, bool KeepMacroComments)

Control whether the preprocessor retains comments in output.

void RemovePragmaHandler(StringRef Namespace, PragmaHandler *Handler)

Remove the specific pragma handler from this preprocessor.

Represents an unpacked "presumed" location which can be presented to the user.

const char * getFilename() const

Return the presumed filename of this location.

unsigned getLine() const

Return the presumed line number of this location.

bool isInvalid() const

Return true if this object is invalid or uninitialized.

SourceLocation getIncludeLoc() const

Return the presumed include location of this location.

bool isValid() const

Return true if this is a valid SourceLocation object.

This class handles loading and caching of source files into memory.

PresumedLoc getPresumedLoc(SourceLocation Loc, bool UseLineDirectives=true) const

Returns the "presumed" location of a SourceLocation specifies.

Token - This structure provides full information about a lexed token.

IdentifierInfo * getIdentifierInfo() const

SourceLocation getLocation() const

Return a source location identifier for the specified offset in the current file.

bool is(tok::TokenKind K) const

is/isNot - Predicates to check if this token is a specific kind, as in "if (Tok.is(tok::l_brace)) {....

bool isAtStartOfLine() const

isAtStartOfLine - Return true if this token is at the start of a line.

bool hasLeadingSpace() const

Return true if this token has whitespace before it.

bool isNot(tok::TokenKind K) const

bool isAnnotation() const

Return true if this is any of tok::annot_* kind tokens.

CharacteristicKind

Indicates whether a file or directory holds normal user code, system code, or system code which is im...

bool isSystem(CharacteristicKind CK)

Determine whether a file / directory characteristic is for system code.

Severity

Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs to either Ignore (nothing),...

@ OS

Indicates that the tracking object is a descendant of a referenced-counted OSObject,...

The JSON file list parser is used to communicate input to InstallAPI.

CustomizableOptional< FileEntryRef > OptionalFileEntryRef

LLVM_READONLY bool isPrintable(unsigned char c)

Return true if this character is an ASCII printable character; that is, a character that should take ...

@ Module

Module linkage, which indicates that the entity can be referred to from other translation units withi...

const FunctionProtoType * T

void DoPrintPreprocessedInput(Preprocessor &PP, raw_ostream *OS, const PreprocessorOutputOptions &Opts)

DoPrintPreprocessedInput - Implement -E mode.

Definition PrintPreprocessedOutput.cpp:1073

Helper class to shuttle information about embed directives from the preprocessor to the parser throug...

std::optional< PPEmbedParameterIfEmpty > MaybeIfEmptyParam

std::optional< PPEmbedParameterOffset > MaybeOffsetParam

std::optional< PPEmbedParameterLimit > MaybeLimitParam

std::optional< PPEmbedParameterSuffix > MaybeSuffixParam

std::optional< PPEmbedParameterPrefix > MaybePrefixParam