1*0b57cec5SDimitry Andric //===--- InclusionRewriter.cpp - Rewrite includes into their expansions ---===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric // This code rewrites include invocations into their expansions. This gives you 10*0b57cec5SDimitry Andric // a file with all included files merged into it. 11*0b57cec5SDimitry Andric // 12*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 13*0b57cec5SDimitry Andric 14*0b57cec5SDimitry Andric #include "clang/Rewrite/Frontend/Rewriters.h" 15*0b57cec5SDimitry Andric #include "clang/Basic/SourceManager.h" 16*0b57cec5SDimitry Andric #include "clang/Frontend/PreprocessorOutputOptions.h" 17*0b57cec5SDimitry Andric #include "clang/Lex/HeaderSearch.h" 18*0b57cec5SDimitry Andric #include "clang/Lex/Pragma.h" 19*0b57cec5SDimitry Andric #include "clang/Lex/Preprocessor.h" 20*0b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h" 21*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 22*0b57cec5SDimitry Andric 23*0b57cec5SDimitry Andric using namespace clang; 24*0b57cec5SDimitry Andric using namespace llvm; 25*0b57cec5SDimitry Andric 26*0b57cec5SDimitry Andric namespace { 27*0b57cec5SDimitry Andric 28*0b57cec5SDimitry Andric class InclusionRewriter : public PPCallbacks { 29*0b57cec5SDimitry Andric /// Information about which #includes were actually performed, 30*0b57cec5SDimitry Andric /// created by preprocessor callbacks. 31*0b57cec5SDimitry Andric struct IncludedFile { 32*0b57cec5SDimitry Andric FileID Id; 33*0b57cec5SDimitry Andric SrcMgr::CharacteristicKind FileType; 34*0b57cec5SDimitry Andric const DirectoryLookup *DirLookup; 35*0b57cec5SDimitry Andric IncludedFile(FileID Id, SrcMgr::CharacteristicKind FileType, 36*0b57cec5SDimitry Andric const DirectoryLookup *DirLookup) 37*0b57cec5SDimitry Andric : Id(Id), FileType(FileType), DirLookup(DirLookup) {} 38*0b57cec5SDimitry Andric }; 39*0b57cec5SDimitry Andric Preprocessor &PP; ///< Used to find inclusion directives. 40*0b57cec5SDimitry Andric SourceManager &SM; ///< Used to read and manage source files. 41*0b57cec5SDimitry Andric raw_ostream &OS; ///< The destination stream for rewritten contents. 42*0b57cec5SDimitry Andric StringRef MainEOL; ///< The line ending marker to use. 43*0b57cec5SDimitry Andric const llvm::MemoryBuffer *PredefinesBuffer; ///< The preprocessor predefines. 44*0b57cec5SDimitry Andric bool ShowLineMarkers; ///< Show #line markers. 45*0b57cec5SDimitry Andric bool UseLineDirectives; ///< Use of line directives or line markers. 46*0b57cec5SDimitry Andric /// Tracks where inclusions that change the file are found. 47*0b57cec5SDimitry Andric std::map<unsigned, IncludedFile> FileIncludes; 48*0b57cec5SDimitry Andric /// Tracks where inclusions that import modules are found. 49*0b57cec5SDimitry Andric std::map<unsigned, const Module *> ModuleIncludes; 50*0b57cec5SDimitry Andric /// Tracks where inclusions that enter modules (in a module build) are found. 51*0b57cec5SDimitry Andric std::map<unsigned, const Module *> ModuleEntryIncludes; 52*0b57cec5SDimitry Andric /// Used transitively for building up the FileIncludes mapping over the 53*0b57cec5SDimitry Andric /// various \c PPCallbacks callbacks. 54*0b57cec5SDimitry Andric SourceLocation LastInclusionLocation; 55*0b57cec5SDimitry Andric public: 56*0b57cec5SDimitry Andric InclusionRewriter(Preprocessor &PP, raw_ostream &OS, bool ShowLineMarkers, 57*0b57cec5SDimitry Andric bool UseLineDirectives); 58*0b57cec5SDimitry Andric void Process(FileID FileId, SrcMgr::CharacteristicKind FileType, 59*0b57cec5SDimitry Andric const DirectoryLookup *DirLookup); 60*0b57cec5SDimitry Andric void setPredefinesBuffer(const llvm::MemoryBuffer *Buf) { 61*0b57cec5SDimitry Andric PredefinesBuffer = Buf; 62*0b57cec5SDimitry Andric } 63*0b57cec5SDimitry Andric void detectMainFileEOL(); 64*0b57cec5SDimitry Andric void handleModuleBegin(Token &Tok) { 65*0b57cec5SDimitry Andric assert(Tok.getKind() == tok::annot_module_begin); 66*0b57cec5SDimitry Andric ModuleEntryIncludes.insert({Tok.getLocation().getRawEncoding(), 67*0b57cec5SDimitry Andric (Module *)Tok.getAnnotationValue()}); 68*0b57cec5SDimitry Andric } 69*0b57cec5SDimitry Andric private: 70*0b57cec5SDimitry Andric void FileChanged(SourceLocation Loc, FileChangeReason Reason, 71*0b57cec5SDimitry Andric SrcMgr::CharacteristicKind FileType, 72*0b57cec5SDimitry Andric FileID PrevFID) override; 73*0b57cec5SDimitry Andric void FileSkipped(const FileEntry &SkippedFile, const Token &FilenameTok, 74*0b57cec5SDimitry Andric SrcMgr::CharacteristicKind FileType) override; 75*0b57cec5SDimitry Andric void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, 76*0b57cec5SDimitry Andric StringRef FileName, bool IsAngled, 77*0b57cec5SDimitry Andric CharSourceRange FilenameRange, const FileEntry *File, 78*0b57cec5SDimitry Andric StringRef SearchPath, StringRef RelativePath, 79*0b57cec5SDimitry Andric const Module *Imported, 80*0b57cec5SDimitry Andric SrcMgr::CharacteristicKind FileType) override; 81*0b57cec5SDimitry Andric void WriteLineInfo(StringRef Filename, int Line, 82*0b57cec5SDimitry Andric SrcMgr::CharacteristicKind FileType, 83*0b57cec5SDimitry Andric StringRef Extra = StringRef()); 84*0b57cec5SDimitry Andric void WriteImplicitModuleImport(const Module *Mod); 85*0b57cec5SDimitry Andric void OutputContentUpTo(const MemoryBuffer &FromFile, 86*0b57cec5SDimitry Andric unsigned &WriteFrom, unsigned WriteTo, 87*0b57cec5SDimitry Andric StringRef EOL, int &lines, 88*0b57cec5SDimitry Andric bool EnsureNewline); 89*0b57cec5SDimitry Andric void CommentOutDirective(Lexer &DirectivesLex, const Token &StartToken, 90*0b57cec5SDimitry Andric const MemoryBuffer &FromFile, StringRef EOL, 91*0b57cec5SDimitry Andric unsigned &NextToWrite, int &Lines); 92*0b57cec5SDimitry Andric bool HandleHasInclude(FileID FileId, Lexer &RawLex, 93*0b57cec5SDimitry Andric const DirectoryLookup *Lookup, Token &Tok, 94*0b57cec5SDimitry Andric bool &FileExists); 95*0b57cec5SDimitry Andric const IncludedFile *FindIncludeAtLocation(SourceLocation Loc) const; 96*0b57cec5SDimitry Andric const Module *FindModuleAtLocation(SourceLocation Loc) const; 97*0b57cec5SDimitry Andric const Module *FindEnteredModule(SourceLocation Loc) const; 98*0b57cec5SDimitry Andric StringRef NextIdentifierName(Lexer &RawLex, Token &RawToken); 99*0b57cec5SDimitry Andric }; 100*0b57cec5SDimitry Andric 101*0b57cec5SDimitry Andric } // end anonymous namespace 102*0b57cec5SDimitry Andric 103*0b57cec5SDimitry Andric /// Initializes an InclusionRewriter with a \p PP source and \p OS destination. 104*0b57cec5SDimitry Andric InclusionRewriter::InclusionRewriter(Preprocessor &PP, raw_ostream &OS, 105*0b57cec5SDimitry Andric bool ShowLineMarkers, 106*0b57cec5SDimitry Andric bool UseLineDirectives) 107*0b57cec5SDimitry Andric : PP(PP), SM(PP.getSourceManager()), OS(OS), MainEOL("\n"), 108*0b57cec5SDimitry Andric PredefinesBuffer(nullptr), ShowLineMarkers(ShowLineMarkers), 109*0b57cec5SDimitry Andric UseLineDirectives(UseLineDirectives), 110*0b57cec5SDimitry Andric LastInclusionLocation(SourceLocation()) {} 111*0b57cec5SDimitry Andric 112*0b57cec5SDimitry Andric /// Write appropriate line information as either #line directives or GNU line 113*0b57cec5SDimitry Andric /// markers depending on what mode we're in, including the \p Filename and 114*0b57cec5SDimitry Andric /// \p Line we are located at, using the specified \p EOL line separator, and 115*0b57cec5SDimitry Andric /// any \p Extra context specifiers in GNU line directives. 116*0b57cec5SDimitry Andric void InclusionRewriter::WriteLineInfo(StringRef Filename, int Line, 117*0b57cec5SDimitry Andric SrcMgr::CharacteristicKind FileType, 118*0b57cec5SDimitry Andric StringRef Extra) { 119*0b57cec5SDimitry Andric if (!ShowLineMarkers) 120*0b57cec5SDimitry Andric return; 121*0b57cec5SDimitry Andric if (UseLineDirectives) { 122*0b57cec5SDimitry Andric OS << "#line" << ' ' << Line << ' ' << '"'; 123*0b57cec5SDimitry Andric OS.write_escaped(Filename); 124*0b57cec5SDimitry Andric OS << '"'; 125*0b57cec5SDimitry Andric } else { 126*0b57cec5SDimitry Andric // Use GNU linemarkers as described here: 127*0b57cec5SDimitry Andric // http://gcc.gnu.org/onlinedocs/cpp/Preprocessor-Output.html 128*0b57cec5SDimitry Andric OS << '#' << ' ' << Line << ' ' << '"'; 129*0b57cec5SDimitry Andric OS.write_escaped(Filename); 130*0b57cec5SDimitry Andric OS << '"'; 131*0b57cec5SDimitry Andric if (!Extra.empty()) 132*0b57cec5SDimitry Andric OS << Extra; 133*0b57cec5SDimitry Andric if (FileType == SrcMgr::C_System) 134*0b57cec5SDimitry Andric // "`3' This indicates that the following text comes from a system header 135*0b57cec5SDimitry Andric // file, so certain warnings should be suppressed." 136*0b57cec5SDimitry Andric OS << " 3"; 137*0b57cec5SDimitry Andric else if (FileType == SrcMgr::C_ExternCSystem) 138*0b57cec5SDimitry Andric // as above for `3', plus "`4' This indicates that the following text 139*0b57cec5SDimitry Andric // should be treated as being wrapped in an implicit extern "C" block." 140*0b57cec5SDimitry Andric OS << " 3 4"; 141*0b57cec5SDimitry Andric } 142*0b57cec5SDimitry Andric OS << MainEOL; 143*0b57cec5SDimitry Andric } 144*0b57cec5SDimitry Andric 145*0b57cec5SDimitry Andric void InclusionRewriter::WriteImplicitModuleImport(const Module *Mod) { 146*0b57cec5SDimitry Andric OS << "#pragma clang module import " << Mod->getFullModuleName(true) 147*0b57cec5SDimitry Andric << " /* clang -frewrite-includes: implicit import */" << MainEOL; 148*0b57cec5SDimitry Andric } 149*0b57cec5SDimitry Andric 150*0b57cec5SDimitry Andric /// FileChanged - Whenever the preprocessor enters or exits a #include file 151*0b57cec5SDimitry Andric /// it invokes this handler. 152*0b57cec5SDimitry Andric void InclusionRewriter::FileChanged(SourceLocation Loc, 153*0b57cec5SDimitry Andric FileChangeReason Reason, 154*0b57cec5SDimitry Andric SrcMgr::CharacteristicKind NewFileType, 155*0b57cec5SDimitry Andric FileID) { 156*0b57cec5SDimitry Andric if (Reason != EnterFile) 157*0b57cec5SDimitry Andric return; 158*0b57cec5SDimitry Andric if (LastInclusionLocation.isInvalid()) 159*0b57cec5SDimitry Andric // we didn't reach this file (eg: the main file) via an inclusion directive 160*0b57cec5SDimitry Andric return; 161*0b57cec5SDimitry Andric FileID Id = FullSourceLoc(Loc, SM).getFileID(); 162*0b57cec5SDimitry Andric auto P = FileIncludes.insert( 163*0b57cec5SDimitry Andric std::make_pair(LastInclusionLocation.getRawEncoding(), 164*0b57cec5SDimitry Andric IncludedFile(Id, NewFileType, PP.GetCurDirLookup()))); 165*0b57cec5SDimitry Andric (void)P; 166*0b57cec5SDimitry Andric assert(P.second && "Unexpected revisitation of the same include directive"); 167*0b57cec5SDimitry Andric LastInclusionLocation = SourceLocation(); 168*0b57cec5SDimitry Andric } 169*0b57cec5SDimitry Andric 170*0b57cec5SDimitry Andric /// Called whenever an inclusion is skipped due to canonical header protection 171*0b57cec5SDimitry Andric /// macros. 172*0b57cec5SDimitry Andric void InclusionRewriter::FileSkipped(const FileEntry &/*SkippedFile*/, 173*0b57cec5SDimitry Andric const Token &/*FilenameTok*/, 174*0b57cec5SDimitry Andric SrcMgr::CharacteristicKind /*FileType*/) { 175*0b57cec5SDimitry Andric assert(LastInclusionLocation.isValid() && 176*0b57cec5SDimitry Andric "A file, that wasn't found via an inclusion directive, was skipped"); 177*0b57cec5SDimitry Andric LastInclusionLocation = SourceLocation(); 178*0b57cec5SDimitry Andric } 179*0b57cec5SDimitry Andric 180*0b57cec5SDimitry Andric /// This should be called whenever the preprocessor encounters include 181*0b57cec5SDimitry Andric /// directives. It does not say whether the file has been included, but it 182*0b57cec5SDimitry Andric /// provides more information about the directive (hash location instead 183*0b57cec5SDimitry Andric /// of location inside the included file). It is assumed that the matching 184*0b57cec5SDimitry Andric /// FileChanged() or FileSkipped() is called after this (or neither is 185*0b57cec5SDimitry Andric /// called if this #include results in an error or does not textually include 186*0b57cec5SDimitry Andric /// anything). 187*0b57cec5SDimitry Andric void InclusionRewriter::InclusionDirective(SourceLocation HashLoc, 188*0b57cec5SDimitry Andric const Token &/*IncludeTok*/, 189*0b57cec5SDimitry Andric StringRef /*FileName*/, 190*0b57cec5SDimitry Andric bool /*IsAngled*/, 191*0b57cec5SDimitry Andric CharSourceRange /*FilenameRange*/, 192*0b57cec5SDimitry Andric const FileEntry * /*File*/, 193*0b57cec5SDimitry Andric StringRef /*SearchPath*/, 194*0b57cec5SDimitry Andric StringRef /*RelativePath*/, 195*0b57cec5SDimitry Andric const Module *Imported, 196*0b57cec5SDimitry Andric SrcMgr::CharacteristicKind FileType){ 197*0b57cec5SDimitry Andric if (Imported) { 198*0b57cec5SDimitry Andric auto P = ModuleIncludes.insert( 199*0b57cec5SDimitry Andric std::make_pair(HashLoc.getRawEncoding(), Imported)); 200*0b57cec5SDimitry Andric (void)P; 201*0b57cec5SDimitry Andric assert(P.second && "Unexpected revisitation of the same include directive"); 202*0b57cec5SDimitry Andric } else 203*0b57cec5SDimitry Andric LastInclusionLocation = HashLoc; 204*0b57cec5SDimitry Andric } 205*0b57cec5SDimitry Andric 206*0b57cec5SDimitry Andric /// Simple lookup for a SourceLocation (specifically one denoting the hash in 207*0b57cec5SDimitry Andric /// an inclusion directive) in the map of inclusion information, FileChanges. 208*0b57cec5SDimitry Andric const InclusionRewriter::IncludedFile * 209*0b57cec5SDimitry Andric InclusionRewriter::FindIncludeAtLocation(SourceLocation Loc) const { 210*0b57cec5SDimitry Andric const auto I = FileIncludes.find(Loc.getRawEncoding()); 211*0b57cec5SDimitry Andric if (I != FileIncludes.end()) 212*0b57cec5SDimitry Andric return &I->second; 213*0b57cec5SDimitry Andric return nullptr; 214*0b57cec5SDimitry Andric } 215*0b57cec5SDimitry Andric 216*0b57cec5SDimitry Andric /// Simple lookup for a SourceLocation (specifically one denoting the hash in 217*0b57cec5SDimitry Andric /// an inclusion directive) in the map of module inclusion information. 218*0b57cec5SDimitry Andric const Module * 219*0b57cec5SDimitry Andric InclusionRewriter::FindModuleAtLocation(SourceLocation Loc) const { 220*0b57cec5SDimitry Andric const auto I = ModuleIncludes.find(Loc.getRawEncoding()); 221*0b57cec5SDimitry Andric if (I != ModuleIncludes.end()) 222*0b57cec5SDimitry Andric return I->second; 223*0b57cec5SDimitry Andric return nullptr; 224*0b57cec5SDimitry Andric } 225*0b57cec5SDimitry Andric 226*0b57cec5SDimitry Andric /// Simple lookup for a SourceLocation (specifically one denoting the hash in 227*0b57cec5SDimitry Andric /// an inclusion directive) in the map of module entry information. 228*0b57cec5SDimitry Andric const Module * 229*0b57cec5SDimitry Andric InclusionRewriter::FindEnteredModule(SourceLocation Loc) const { 230*0b57cec5SDimitry Andric const auto I = ModuleEntryIncludes.find(Loc.getRawEncoding()); 231*0b57cec5SDimitry Andric if (I != ModuleEntryIncludes.end()) 232*0b57cec5SDimitry Andric return I->second; 233*0b57cec5SDimitry Andric return nullptr; 234*0b57cec5SDimitry Andric } 235*0b57cec5SDimitry Andric 236*0b57cec5SDimitry Andric /// Detect the likely line ending style of \p FromFile by examining the first 237*0b57cec5SDimitry Andric /// newline found within it. 238*0b57cec5SDimitry Andric static StringRef DetectEOL(const MemoryBuffer &FromFile) { 239*0b57cec5SDimitry Andric // Detect what line endings the file uses, so that added content does not mix 240*0b57cec5SDimitry Andric // the style. We need to check for "\r\n" first because "\n\r" will match 241*0b57cec5SDimitry Andric // "\r\n\r\n". 242*0b57cec5SDimitry Andric const char *Pos = strchr(FromFile.getBufferStart(), '\n'); 243*0b57cec5SDimitry Andric if (!Pos) 244*0b57cec5SDimitry Andric return "\n"; 245*0b57cec5SDimitry Andric if (Pos - 1 >= FromFile.getBufferStart() && Pos[-1] == '\r') 246*0b57cec5SDimitry Andric return "\r\n"; 247*0b57cec5SDimitry Andric if (Pos + 1 < FromFile.getBufferEnd() && Pos[1] == '\r') 248*0b57cec5SDimitry Andric return "\n\r"; 249*0b57cec5SDimitry Andric return "\n"; 250*0b57cec5SDimitry Andric } 251*0b57cec5SDimitry Andric 252*0b57cec5SDimitry Andric void InclusionRewriter::detectMainFileEOL() { 253*0b57cec5SDimitry Andric bool Invalid; 254*0b57cec5SDimitry Andric const MemoryBuffer &FromFile = *SM.getBuffer(SM.getMainFileID(), &Invalid); 255*0b57cec5SDimitry Andric assert(!Invalid); 256*0b57cec5SDimitry Andric if (Invalid) 257*0b57cec5SDimitry Andric return; // Should never happen, but whatever. 258*0b57cec5SDimitry Andric MainEOL = DetectEOL(FromFile); 259*0b57cec5SDimitry Andric } 260*0b57cec5SDimitry Andric 261*0b57cec5SDimitry Andric /// Writes out bytes from \p FromFile, starting at \p NextToWrite and ending at 262*0b57cec5SDimitry Andric /// \p WriteTo - 1. 263*0b57cec5SDimitry Andric void InclusionRewriter::OutputContentUpTo(const MemoryBuffer &FromFile, 264*0b57cec5SDimitry Andric unsigned &WriteFrom, unsigned WriteTo, 265*0b57cec5SDimitry Andric StringRef LocalEOL, int &Line, 266*0b57cec5SDimitry Andric bool EnsureNewline) { 267*0b57cec5SDimitry Andric if (WriteTo <= WriteFrom) 268*0b57cec5SDimitry Andric return; 269*0b57cec5SDimitry Andric if (&FromFile == PredefinesBuffer) { 270*0b57cec5SDimitry Andric // Ignore the #defines of the predefines buffer. 271*0b57cec5SDimitry Andric WriteFrom = WriteTo; 272*0b57cec5SDimitry Andric return; 273*0b57cec5SDimitry Andric } 274*0b57cec5SDimitry Andric 275*0b57cec5SDimitry Andric // If we would output half of a line ending, advance one character to output 276*0b57cec5SDimitry Andric // the whole line ending. All buffers are null terminated, so looking ahead 277*0b57cec5SDimitry Andric // one byte is safe. 278*0b57cec5SDimitry Andric if (LocalEOL.size() == 2 && 279*0b57cec5SDimitry Andric LocalEOL[0] == (FromFile.getBufferStart() + WriteTo)[-1] && 280*0b57cec5SDimitry Andric LocalEOL[1] == (FromFile.getBufferStart() + WriteTo)[0]) 281*0b57cec5SDimitry Andric WriteTo++; 282*0b57cec5SDimitry Andric 283*0b57cec5SDimitry Andric StringRef TextToWrite(FromFile.getBufferStart() + WriteFrom, 284*0b57cec5SDimitry Andric WriteTo - WriteFrom); 285*0b57cec5SDimitry Andric 286*0b57cec5SDimitry Andric if (MainEOL == LocalEOL) { 287*0b57cec5SDimitry Andric OS << TextToWrite; 288*0b57cec5SDimitry Andric // count lines manually, it's faster than getPresumedLoc() 289*0b57cec5SDimitry Andric Line += TextToWrite.count(LocalEOL); 290*0b57cec5SDimitry Andric if (EnsureNewline && !TextToWrite.endswith(LocalEOL)) 291*0b57cec5SDimitry Andric OS << MainEOL; 292*0b57cec5SDimitry Andric } else { 293*0b57cec5SDimitry Andric // Output the file one line at a time, rewriting the line endings as we go. 294*0b57cec5SDimitry Andric StringRef Rest = TextToWrite; 295*0b57cec5SDimitry Andric while (!Rest.empty()) { 296*0b57cec5SDimitry Andric StringRef LineText; 297*0b57cec5SDimitry Andric std::tie(LineText, Rest) = Rest.split(LocalEOL); 298*0b57cec5SDimitry Andric OS << LineText; 299*0b57cec5SDimitry Andric Line++; 300*0b57cec5SDimitry Andric if (!Rest.empty()) 301*0b57cec5SDimitry Andric OS << MainEOL; 302*0b57cec5SDimitry Andric } 303*0b57cec5SDimitry Andric if (TextToWrite.endswith(LocalEOL) || EnsureNewline) 304*0b57cec5SDimitry Andric OS << MainEOL; 305*0b57cec5SDimitry Andric } 306*0b57cec5SDimitry Andric WriteFrom = WriteTo; 307*0b57cec5SDimitry Andric } 308*0b57cec5SDimitry Andric 309*0b57cec5SDimitry Andric /// Print characters from \p FromFile starting at \p NextToWrite up until the 310*0b57cec5SDimitry Andric /// inclusion directive at \p StartToken, then print out the inclusion 311*0b57cec5SDimitry Andric /// inclusion directive disabled by a #if directive, updating \p NextToWrite 312*0b57cec5SDimitry Andric /// and \p Line to track the number of source lines visited and the progress 313*0b57cec5SDimitry Andric /// through the \p FromFile buffer. 314*0b57cec5SDimitry Andric void InclusionRewriter::CommentOutDirective(Lexer &DirectiveLex, 315*0b57cec5SDimitry Andric const Token &StartToken, 316*0b57cec5SDimitry Andric const MemoryBuffer &FromFile, 317*0b57cec5SDimitry Andric StringRef LocalEOL, 318*0b57cec5SDimitry Andric unsigned &NextToWrite, int &Line) { 319*0b57cec5SDimitry Andric OutputContentUpTo(FromFile, NextToWrite, 320*0b57cec5SDimitry Andric SM.getFileOffset(StartToken.getLocation()), LocalEOL, Line, 321*0b57cec5SDimitry Andric false); 322*0b57cec5SDimitry Andric Token DirectiveToken; 323*0b57cec5SDimitry Andric do { 324*0b57cec5SDimitry Andric DirectiveLex.LexFromRawLexer(DirectiveToken); 325*0b57cec5SDimitry Andric } while (!DirectiveToken.is(tok::eod) && DirectiveToken.isNot(tok::eof)); 326*0b57cec5SDimitry Andric if (&FromFile == PredefinesBuffer) { 327*0b57cec5SDimitry Andric // OutputContentUpTo() would not output anything anyway. 328*0b57cec5SDimitry Andric return; 329*0b57cec5SDimitry Andric } 330*0b57cec5SDimitry Andric OS << "#if 0 /* expanded by -frewrite-includes */" << MainEOL; 331*0b57cec5SDimitry Andric OutputContentUpTo(FromFile, NextToWrite, 332*0b57cec5SDimitry Andric SM.getFileOffset(DirectiveToken.getLocation()) + 333*0b57cec5SDimitry Andric DirectiveToken.getLength(), 334*0b57cec5SDimitry Andric LocalEOL, Line, true); 335*0b57cec5SDimitry Andric OS << "#endif /* expanded by -frewrite-includes */" << MainEOL; 336*0b57cec5SDimitry Andric } 337*0b57cec5SDimitry Andric 338*0b57cec5SDimitry Andric /// Find the next identifier in the pragma directive specified by \p RawToken. 339*0b57cec5SDimitry Andric StringRef InclusionRewriter::NextIdentifierName(Lexer &RawLex, 340*0b57cec5SDimitry Andric Token &RawToken) { 341*0b57cec5SDimitry Andric RawLex.LexFromRawLexer(RawToken); 342*0b57cec5SDimitry Andric if (RawToken.is(tok::raw_identifier)) 343*0b57cec5SDimitry Andric PP.LookUpIdentifierInfo(RawToken); 344*0b57cec5SDimitry Andric if (RawToken.is(tok::identifier)) 345*0b57cec5SDimitry Andric return RawToken.getIdentifierInfo()->getName(); 346*0b57cec5SDimitry Andric return StringRef(); 347*0b57cec5SDimitry Andric } 348*0b57cec5SDimitry Andric 349*0b57cec5SDimitry Andric // Expand __has_include and __has_include_next if possible. If there's no 350*0b57cec5SDimitry Andric // definitive answer return false. 351*0b57cec5SDimitry Andric bool InclusionRewriter::HandleHasInclude( 352*0b57cec5SDimitry Andric FileID FileId, Lexer &RawLex, const DirectoryLookup *Lookup, Token &Tok, 353*0b57cec5SDimitry Andric bool &FileExists) { 354*0b57cec5SDimitry Andric // Lex the opening paren. 355*0b57cec5SDimitry Andric RawLex.LexFromRawLexer(Tok); 356*0b57cec5SDimitry Andric if (Tok.isNot(tok::l_paren)) 357*0b57cec5SDimitry Andric return false; 358*0b57cec5SDimitry Andric 359*0b57cec5SDimitry Andric RawLex.LexFromRawLexer(Tok); 360*0b57cec5SDimitry Andric 361*0b57cec5SDimitry Andric SmallString<128> FilenameBuffer; 362*0b57cec5SDimitry Andric StringRef Filename; 363*0b57cec5SDimitry Andric // Since the raw lexer doesn't give us angle_literals we have to parse them 364*0b57cec5SDimitry Andric // ourselves. 365*0b57cec5SDimitry Andric // FIXME: What to do if the file name is a macro? 366*0b57cec5SDimitry Andric if (Tok.is(tok::less)) { 367*0b57cec5SDimitry Andric RawLex.LexFromRawLexer(Tok); 368*0b57cec5SDimitry Andric 369*0b57cec5SDimitry Andric FilenameBuffer += '<'; 370*0b57cec5SDimitry Andric do { 371*0b57cec5SDimitry Andric if (Tok.is(tok::eod)) // Sanity check. 372*0b57cec5SDimitry Andric return false; 373*0b57cec5SDimitry Andric 374*0b57cec5SDimitry Andric if (Tok.is(tok::raw_identifier)) 375*0b57cec5SDimitry Andric PP.LookUpIdentifierInfo(Tok); 376*0b57cec5SDimitry Andric 377*0b57cec5SDimitry Andric // Get the string piece. 378*0b57cec5SDimitry Andric SmallVector<char, 128> TmpBuffer; 379*0b57cec5SDimitry Andric bool Invalid = false; 380*0b57cec5SDimitry Andric StringRef TmpName = PP.getSpelling(Tok, TmpBuffer, &Invalid); 381*0b57cec5SDimitry Andric if (Invalid) 382*0b57cec5SDimitry Andric return false; 383*0b57cec5SDimitry Andric 384*0b57cec5SDimitry Andric FilenameBuffer += TmpName; 385*0b57cec5SDimitry Andric 386*0b57cec5SDimitry Andric RawLex.LexFromRawLexer(Tok); 387*0b57cec5SDimitry Andric } while (Tok.isNot(tok::greater)); 388*0b57cec5SDimitry Andric 389*0b57cec5SDimitry Andric FilenameBuffer += '>'; 390*0b57cec5SDimitry Andric Filename = FilenameBuffer; 391*0b57cec5SDimitry Andric } else { 392*0b57cec5SDimitry Andric if (Tok.isNot(tok::string_literal)) 393*0b57cec5SDimitry Andric return false; 394*0b57cec5SDimitry Andric 395*0b57cec5SDimitry Andric bool Invalid = false; 396*0b57cec5SDimitry Andric Filename = PP.getSpelling(Tok, FilenameBuffer, &Invalid); 397*0b57cec5SDimitry Andric if (Invalid) 398*0b57cec5SDimitry Andric return false; 399*0b57cec5SDimitry Andric } 400*0b57cec5SDimitry Andric 401*0b57cec5SDimitry Andric // Lex the closing paren. 402*0b57cec5SDimitry Andric RawLex.LexFromRawLexer(Tok); 403*0b57cec5SDimitry Andric if (Tok.isNot(tok::r_paren)) 404*0b57cec5SDimitry Andric return false; 405*0b57cec5SDimitry Andric 406*0b57cec5SDimitry Andric // Now ask HeaderInfo if it knows about the header. 407*0b57cec5SDimitry Andric // FIXME: Subframeworks aren't handled here. Do we care? 408*0b57cec5SDimitry Andric bool isAngled = PP.GetIncludeFilenameSpelling(Tok.getLocation(), Filename); 409*0b57cec5SDimitry Andric const DirectoryLookup *CurDir; 410*0b57cec5SDimitry Andric const FileEntry *FileEnt = PP.getSourceManager().getFileEntryForID(FileId); 411*0b57cec5SDimitry Andric SmallVector<std::pair<const FileEntry *, const DirectoryEntry *>, 1> 412*0b57cec5SDimitry Andric Includers; 413*0b57cec5SDimitry Andric Includers.push_back(std::make_pair(FileEnt, FileEnt->getDir())); 414*0b57cec5SDimitry Andric // FIXME: Why don't we call PP.LookupFile here? 415*0b57cec5SDimitry Andric const FileEntry *File = PP.getHeaderSearchInfo().LookupFile( 416*0b57cec5SDimitry Andric Filename, SourceLocation(), isAngled, Lookup, CurDir, Includers, nullptr, 417*0b57cec5SDimitry Andric nullptr, nullptr, nullptr, nullptr, nullptr); 418*0b57cec5SDimitry Andric 419*0b57cec5SDimitry Andric FileExists = File != nullptr; 420*0b57cec5SDimitry Andric return true; 421*0b57cec5SDimitry Andric } 422*0b57cec5SDimitry Andric 423*0b57cec5SDimitry Andric /// Use a raw lexer to analyze \p FileId, incrementally copying parts of it 424*0b57cec5SDimitry Andric /// and including content of included files recursively. 425*0b57cec5SDimitry Andric void InclusionRewriter::Process(FileID FileId, 426*0b57cec5SDimitry Andric SrcMgr::CharacteristicKind FileType, 427*0b57cec5SDimitry Andric const DirectoryLookup *DirLookup) { 428*0b57cec5SDimitry Andric bool Invalid; 429*0b57cec5SDimitry Andric const MemoryBuffer &FromFile = *SM.getBuffer(FileId, &Invalid); 430*0b57cec5SDimitry Andric assert(!Invalid && "Attempting to process invalid inclusion"); 431*0b57cec5SDimitry Andric StringRef FileName = FromFile.getBufferIdentifier(); 432*0b57cec5SDimitry Andric Lexer RawLex(FileId, &FromFile, PP.getSourceManager(), PP.getLangOpts()); 433*0b57cec5SDimitry Andric RawLex.SetCommentRetentionState(false); 434*0b57cec5SDimitry Andric 435*0b57cec5SDimitry Andric StringRef LocalEOL = DetectEOL(FromFile); 436*0b57cec5SDimitry Andric 437*0b57cec5SDimitry Andric // Per the GNU docs: "1" indicates entering a new file. 438*0b57cec5SDimitry Andric if (FileId == SM.getMainFileID() || FileId == PP.getPredefinesFileID()) 439*0b57cec5SDimitry Andric WriteLineInfo(FileName, 1, FileType, ""); 440*0b57cec5SDimitry Andric else 441*0b57cec5SDimitry Andric WriteLineInfo(FileName, 1, FileType, " 1"); 442*0b57cec5SDimitry Andric 443*0b57cec5SDimitry Andric if (SM.getFileIDSize(FileId) == 0) 444*0b57cec5SDimitry Andric return; 445*0b57cec5SDimitry Andric 446*0b57cec5SDimitry Andric // The next byte to be copied from the source file, which may be non-zero if 447*0b57cec5SDimitry Andric // the lexer handled a BOM. 448*0b57cec5SDimitry Andric unsigned NextToWrite = SM.getFileOffset(RawLex.getSourceLocation()); 449*0b57cec5SDimitry Andric assert(SM.getLineNumber(FileId, NextToWrite) == 1); 450*0b57cec5SDimitry Andric int Line = 1; // The current input file line number. 451*0b57cec5SDimitry Andric 452*0b57cec5SDimitry Andric Token RawToken; 453*0b57cec5SDimitry Andric RawLex.LexFromRawLexer(RawToken); 454*0b57cec5SDimitry Andric 455*0b57cec5SDimitry Andric // TODO: Consider adding a switch that strips possibly unimportant content, 456*0b57cec5SDimitry Andric // such as comments, to reduce the size of repro files. 457*0b57cec5SDimitry Andric while (RawToken.isNot(tok::eof)) { 458*0b57cec5SDimitry Andric if (RawToken.is(tok::hash) && RawToken.isAtStartOfLine()) { 459*0b57cec5SDimitry Andric RawLex.setParsingPreprocessorDirective(true); 460*0b57cec5SDimitry Andric Token HashToken = RawToken; 461*0b57cec5SDimitry Andric RawLex.LexFromRawLexer(RawToken); 462*0b57cec5SDimitry Andric if (RawToken.is(tok::raw_identifier)) 463*0b57cec5SDimitry Andric PP.LookUpIdentifierInfo(RawToken); 464*0b57cec5SDimitry Andric if (RawToken.getIdentifierInfo() != nullptr) { 465*0b57cec5SDimitry Andric switch (RawToken.getIdentifierInfo()->getPPKeywordID()) { 466*0b57cec5SDimitry Andric case tok::pp_include: 467*0b57cec5SDimitry Andric case tok::pp_include_next: 468*0b57cec5SDimitry Andric case tok::pp_import: { 469*0b57cec5SDimitry Andric CommentOutDirective(RawLex, HashToken, FromFile, LocalEOL, NextToWrite, 470*0b57cec5SDimitry Andric Line); 471*0b57cec5SDimitry Andric if (FileId != PP.getPredefinesFileID()) 472*0b57cec5SDimitry Andric WriteLineInfo(FileName, Line - 1, FileType, ""); 473*0b57cec5SDimitry Andric StringRef LineInfoExtra; 474*0b57cec5SDimitry Andric SourceLocation Loc = HashToken.getLocation(); 475*0b57cec5SDimitry Andric if (const Module *Mod = FindModuleAtLocation(Loc)) 476*0b57cec5SDimitry Andric WriteImplicitModuleImport(Mod); 477*0b57cec5SDimitry Andric else if (const IncludedFile *Inc = FindIncludeAtLocation(Loc)) { 478*0b57cec5SDimitry Andric const Module *Mod = FindEnteredModule(Loc); 479*0b57cec5SDimitry Andric if (Mod) 480*0b57cec5SDimitry Andric OS << "#pragma clang module begin " 481*0b57cec5SDimitry Andric << Mod->getFullModuleName(true) << "\n"; 482*0b57cec5SDimitry Andric 483*0b57cec5SDimitry Andric // Include and recursively process the file. 484*0b57cec5SDimitry Andric Process(Inc->Id, Inc->FileType, Inc->DirLookup); 485*0b57cec5SDimitry Andric 486*0b57cec5SDimitry Andric if (Mod) 487*0b57cec5SDimitry Andric OS << "#pragma clang module end /*" 488*0b57cec5SDimitry Andric << Mod->getFullModuleName(true) << "*/\n"; 489*0b57cec5SDimitry Andric 490*0b57cec5SDimitry Andric // Add line marker to indicate we're returning from an included 491*0b57cec5SDimitry Andric // file. 492*0b57cec5SDimitry Andric LineInfoExtra = " 2"; 493*0b57cec5SDimitry Andric } 494*0b57cec5SDimitry Andric // fix up lineinfo (since commented out directive changed line 495*0b57cec5SDimitry Andric // numbers) for inclusions that were skipped due to header guards 496*0b57cec5SDimitry Andric WriteLineInfo(FileName, Line, FileType, LineInfoExtra); 497*0b57cec5SDimitry Andric break; 498*0b57cec5SDimitry Andric } 499*0b57cec5SDimitry Andric case tok::pp_pragma: { 500*0b57cec5SDimitry Andric StringRef Identifier = NextIdentifierName(RawLex, RawToken); 501*0b57cec5SDimitry Andric if (Identifier == "clang" || Identifier == "GCC") { 502*0b57cec5SDimitry Andric if (NextIdentifierName(RawLex, RawToken) == "system_header") { 503*0b57cec5SDimitry Andric // keep the directive in, commented out 504*0b57cec5SDimitry Andric CommentOutDirective(RawLex, HashToken, FromFile, LocalEOL, 505*0b57cec5SDimitry Andric NextToWrite, Line); 506*0b57cec5SDimitry Andric // update our own type 507*0b57cec5SDimitry Andric FileType = SM.getFileCharacteristic(RawToken.getLocation()); 508*0b57cec5SDimitry Andric WriteLineInfo(FileName, Line, FileType); 509*0b57cec5SDimitry Andric } 510*0b57cec5SDimitry Andric } else if (Identifier == "once") { 511*0b57cec5SDimitry Andric // keep the directive in, commented out 512*0b57cec5SDimitry Andric CommentOutDirective(RawLex, HashToken, FromFile, LocalEOL, 513*0b57cec5SDimitry Andric NextToWrite, Line); 514*0b57cec5SDimitry Andric WriteLineInfo(FileName, Line, FileType); 515*0b57cec5SDimitry Andric } 516*0b57cec5SDimitry Andric break; 517*0b57cec5SDimitry Andric } 518*0b57cec5SDimitry Andric case tok::pp_if: 519*0b57cec5SDimitry Andric case tok::pp_elif: { 520*0b57cec5SDimitry Andric bool elif = (RawToken.getIdentifierInfo()->getPPKeywordID() == 521*0b57cec5SDimitry Andric tok::pp_elif); 522*0b57cec5SDimitry Andric // Rewrite special builtin macros to avoid pulling in host details. 523*0b57cec5SDimitry Andric do { 524*0b57cec5SDimitry Andric // Walk over the directive. 525*0b57cec5SDimitry Andric RawLex.LexFromRawLexer(RawToken); 526*0b57cec5SDimitry Andric if (RawToken.is(tok::raw_identifier)) 527*0b57cec5SDimitry Andric PP.LookUpIdentifierInfo(RawToken); 528*0b57cec5SDimitry Andric 529*0b57cec5SDimitry Andric if (RawToken.is(tok::identifier)) { 530*0b57cec5SDimitry Andric bool HasFile; 531*0b57cec5SDimitry Andric SourceLocation Loc = RawToken.getLocation(); 532*0b57cec5SDimitry Andric 533*0b57cec5SDimitry Andric // Rewrite __has_include(x) 534*0b57cec5SDimitry Andric if (RawToken.getIdentifierInfo()->isStr("__has_include")) { 535*0b57cec5SDimitry Andric if (!HandleHasInclude(FileId, RawLex, nullptr, RawToken, 536*0b57cec5SDimitry Andric HasFile)) 537*0b57cec5SDimitry Andric continue; 538*0b57cec5SDimitry Andric // Rewrite __has_include_next(x) 539*0b57cec5SDimitry Andric } else if (RawToken.getIdentifierInfo()->isStr( 540*0b57cec5SDimitry Andric "__has_include_next")) { 541*0b57cec5SDimitry Andric if (DirLookup) 542*0b57cec5SDimitry Andric ++DirLookup; 543*0b57cec5SDimitry Andric 544*0b57cec5SDimitry Andric if (!HandleHasInclude(FileId, RawLex, DirLookup, RawToken, 545*0b57cec5SDimitry Andric HasFile)) 546*0b57cec5SDimitry Andric continue; 547*0b57cec5SDimitry Andric } else { 548*0b57cec5SDimitry Andric continue; 549*0b57cec5SDimitry Andric } 550*0b57cec5SDimitry Andric // Replace the macro with (0) or (1), followed by the commented 551*0b57cec5SDimitry Andric // out macro for reference. 552*0b57cec5SDimitry Andric OutputContentUpTo(FromFile, NextToWrite, SM.getFileOffset(Loc), 553*0b57cec5SDimitry Andric LocalEOL, Line, false); 554*0b57cec5SDimitry Andric OS << '(' << (int) HasFile << ")/*"; 555*0b57cec5SDimitry Andric OutputContentUpTo(FromFile, NextToWrite, 556*0b57cec5SDimitry Andric SM.getFileOffset(RawToken.getLocation()) + 557*0b57cec5SDimitry Andric RawToken.getLength(), 558*0b57cec5SDimitry Andric LocalEOL, Line, false); 559*0b57cec5SDimitry Andric OS << "*/"; 560*0b57cec5SDimitry Andric } 561*0b57cec5SDimitry Andric } while (RawToken.isNot(tok::eod)); 562*0b57cec5SDimitry Andric if (elif) { 563*0b57cec5SDimitry Andric OutputContentUpTo(FromFile, NextToWrite, 564*0b57cec5SDimitry Andric SM.getFileOffset(RawToken.getLocation()) + 565*0b57cec5SDimitry Andric RawToken.getLength(), 566*0b57cec5SDimitry Andric LocalEOL, Line, /*EnsureNewline=*/ true); 567*0b57cec5SDimitry Andric WriteLineInfo(FileName, Line, FileType); 568*0b57cec5SDimitry Andric } 569*0b57cec5SDimitry Andric break; 570*0b57cec5SDimitry Andric } 571*0b57cec5SDimitry Andric case tok::pp_endif: 572*0b57cec5SDimitry Andric case tok::pp_else: { 573*0b57cec5SDimitry Andric // We surround every #include by #if 0 to comment it out, but that 574*0b57cec5SDimitry Andric // changes line numbers. These are fixed up right after that, but 575*0b57cec5SDimitry Andric // the whole #include could be inside a preprocessor conditional 576*0b57cec5SDimitry Andric // that is not processed. So it is necessary to fix the line 577*0b57cec5SDimitry Andric // numbers one the next line after each #else/#endif as well. 578*0b57cec5SDimitry Andric RawLex.SetKeepWhitespaceMode(true); 579*0b57cec5SDimitry Andric do { 580*0b57cec5SDimitry Andric RawLex.LexFromRawLexer(RawToken); 581*0b57cec5SDimitry Andric } while (RawToken.isNot(tok::eod) && RawToken.isNot(tok::eof)); 582*0b57cec5SDimitry Andric OutputContentUpTo(FromFile, NextToWrite, 583*0b57cec5SDimitry Andric SM.getFileOffset(RawToken.getLocation()) + 584*0b57cec5SDimitry Andric RawToken.getLength(), 585*0b57cec5SDimitry Andric LocalEOL, Line, /*EnsureNewline=*/ true); 586*0b57cec5SDimitry Andric WriteLineInfo(FileName, Line, FileType); 587*0b57cec5SDimitry Andric RawLex.SetKeepWhitespaceMode(false); 588*0b57cec5SDimitry Andric break; 589*0b57cec5SDimitry Andric } 590*0b57cec5SDimitry Andric default: 591*0b57cec5SDimitry Andric break; 592*0b57cec5SDimitry Andric } 593*0b57cec5SDimitry Andric } 594*0b57cec5SDimitry Andric RawLex.setParsingPreprocessorDirective(false); 595*0b57cec5SDimitry Andric } 596*0b57cec5SDimitry Andric RawLex.LexFromRawLexer(RawToken); 597*0b57cec5SDimitry Andric } 598*0b57cec5SDimitry Andric OutputContentUpTo(FromFile, NextToWrite, 599*0b57cec5SDimitry Andric SM.getFileOffset(SM.getLocForEndOfFile(FileId)), LocalEOL, 600*0b57cec5SDimitry Andric Line, /*EnsureNewline=*/true); 601*0b57cec5SDimitry Andric } 602*0b57cec5SDimitry Andric 603*0b57cec5SDimitry Andric /// InclusionRewriterInInput - Implement -frewrite-includes mode. 604*0b57cec5SDimitry Andric void clang::RewriteIncludesInInput(Preprocessor &PP, raw_ostream *OS, 605*0b57cec5SDimitry Andric const PreprocessorOutputOptions &Opts) { 606*0b57cec5SDimitry Andric SourceManager &SM = PP.getSourceManager(); 607*0b57cec5SDimitry Andric InclusionRewriter *Rewrite = new InclusionRewriter( 608*0b57cec5SDimitry Andric PP, *OS, Opts.ShowLineMarkers, Opts.UseLineDirectives); 609*0b57cec5SDimitry Andric Rewrite->detectMainFileEOL(); 610*0b57cec5SDimitry Andric 611*0b57cec5SDimitry Andric PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Rewrite)); 612*0b57cec5SDimitry Andric PP.IgnorePragmas(); 613*0b57cec5SDimitry Andric 614*0b57cec5SDimitry Andric // First let the preprocessor process the entire file and call callbacks. 615*0b57cec5SDimitry Andric // Callbacks will record which #include's were actually performed. 616*0b57cec5SDimitry Andric PP.EnterMainSourceFile(); 617*0b57cec5SDimitry Andric Token Tok; 618*0b57cec5SDimitry Andric // Only preprocessor directives matter here, so disable macro expansion 619*0b57cec5SDimitry Andric // everywhere else as an optimization. 620*0b57cec5SDimitry Andric // TODO: It would be even faster if the preprocessor could be switched 621*0b57cec5SDimitry Andric // to a mode where it would parse only preprocessor directives and comments, 622*0b57cec5SDimitry Andric // nothing else matters for parsing or processing. 623*0b57cec5SDimitry Andric PP.SetMacroExpansionOnlyInDirectives(); 624*0b57cec5SDimitry Andric do { 625*0b57cec5SDimitry Andric PP.Lex(Tok); 626*0b57cec5SDimitry Andric if (Tok.is(tok::annot_module_begin)) 627*0b57cec5SDimitry Andric Rewrite->handleModuleBegin(Tok); 628*0b57cec5SDimitry Andric } while (Tok.isNot(tok::eof)); 629*0b57cec5SDimitry Andric Rewrite->setPredefinesBuffer(SM.getBuffer(PP.getPredefinesFileID())); 630*0b57cec5SDimitry Andric Rewrite->Process(PP.getPredefinesFileID(), SrcMgr::C_User, nullptr); 631*0b57cec5SDimitry Andric Rewrite->Process(SM.getMainFileID(), SrcMgr::C_User, nullptr); 632*0b57cec5SDimitry Andric OS->flush(); 633*0b57cec5SDimitry Andric } 634