20 #include "llvm/ADT/SmallString.h" 21 #include "llvm/Support/raw_ostream.h" 23 using namespace clang;
37 : Id(Id), FileType(FileType), DirLookup(DirLookup) {}
43 const llvm::MemoryBuffer *PredefinesBuffer;
45 bool UseLineDirectives;
47 std::map<unsigned, IncludedFile> FileIncludes;
49 std::map<unsigned, const Module *> ModuleIncludes;
51 std::map<unsigned, const Module *> ModuleEntryIncludes;
56 InclusionRewriter(
Preprocessor &PP, raw_ostream &OS,
bool ShowLineMarkers,
57 bool UseLineDirectives);
60 void setPredefinesBuffer(
const llvm::MemoryBuffer *Buf) {
61 PredefinesBuffer = Buf;
63 void detectMainFileEOL();
65 assert(Tok.
getKind() == tok::annot_module_begin);
73 void FileSkipped(
const FileEntry &SkippedFile,
const Token &FilenameTok,
76 StringRef FileName,
bool IsAngled,
78 StringRef SearchPath, StringRef RelativePath,
83 StringRef Extra = StringRef());
84 void WriteImplicitModuleImport(
const Module *Mod);
85 void OutputContentUpTo(
const MemoryBuffer &FromFile,
86 unsigned &WriteFrom,
unsigned WriteTo,
87 StringRef EOL,
int &lines,
89 void CommentOutDirective(
Lexer &DirectivesLex,
const Token &StartToken,
90 const MemoryBuffer &FromFile, StringRef EOL,
91 unsigned &NextToWrite,
int &Lines);
95 const IncludedFile *FindIncludeAtLocation(
SourceLocation Loc)
const;
98 StringRef NextIdentifierName(
Lexer &RawLex,
Token &RawToken);
104 InclusionRewriter::InclusionRewriter(
Preprocessor &PP, raw_ostream &OS,
105 bool ShowLineMarkers,
106 bool UseLineDirectives)
107 : PP(PP), SM(PP.getSourceManager()), OS(OS), MainEOL(
"\n"),
108 PredefinesBuffer(nullptr), ShowLineMarkers(ShowLineMarkers),
109 UseLineDirectives(UseLineDirectives),
116 void InclusionRewriter::WriteLineInfo(StringRef
Filename,
int Line,
119 if (!ShowLineMarkers)
121 if (UseLineDirectives) {
122 OS <<
"#line" <<
' ' << Line <<
' ' <<
'"';
123 OS.write_escaped(Filename);
128 OS <<
'#' <<
' ' << Line <<
' ' <<
'"';
129 OS.write_escaped(Filename);
145 void InclusionRewriter::WriteImplicitModuleImport(
const Module *Mod) {
147 <<
" /* clang -frewrite-includes: implicit import */" << MainEOL;
153 FileChangeReason Reason,
156 if (Reason != EnterFile)
162 auto P = FileIncludes.insert(
166 assert(
P.second &&
"Unexpected revisitation of the same include directive");
172 void InclusionRewriter::FileSkipped(
const FileEntry &,
175 assert(LastInclusionLocation.
isValid() &&
176 "A file, that wasn't found via an inclusion directive, was skipped");
187 void InclusionRewriter::InclusionDirective(
SourceLocation HashLoc,
198 auto P = ModuleIncludes.insert(
201 assert(
P.second &&
"Unexpected revisitation of the same include directive");
203 LastInclusionLocation = HashLoc;
208 const InclusionRewriter::IncludedFile *
209 InclusionRewriter::FindIncludeAtLocation(
SourceLocation Loc)
const {
211 if (I != FileIncludes.end())
219 InclusionRewriter::FindModuleAtLocation(
SourceLocation Loc)
const {
221 if (I != ModuleIncludes.end())
231 if (I != ModuleEntryIncludes.end())
238 static StringRef
DetectEOL(
const MemoryBuffer &FromFile) {
242 const char *Pos = strchr(FromFile.getBufferStart(),
'\n');
245 if (Pos - 1 >= FromFile.getBufferStart() && Pos[-1] ==
'\r')
247 if (Pos + 1 < FromFile.getBufferEnd() && Pos[1] ==
'\r')
252 void InclusionRewriter::detectMainFileEOL() {
263 void InclusionRewriter::OutputContentUpTo(
const MemoryBuffer &FromFile,
264 unsigned &WriteFrom,
unsigned WriteTo,
265 StringRef LocalEOL,
int &Line,
266 bool EnsureNewline) {
267 if (WriteTo <= WriteFrom)
269 if (&FromFile == PredefinesBuffer) {
278 if (LocalEOL.size() == 2 &&
279 LocalEOL[0] == (FromFile.getBufferStart() + WriteTo)[-1] &&
280 LocalEOL[1] == (FromFile.getBufferStart() + WriteTo)[0])
283 StringRef TextToWrite(FromFile.getBufferStart() + WriteFrom,
284 WriteTo - WriteFrom);
286 if (MainEOL == LocalEOL) {
289 Line += TextToWrite.count(LocalEOL);
290 if (EnsureNewline && !TextToWrite.endswith(LocalEOL))
294 StringRef Rest = TextToWrite;
295 while (!Rest.empty()) {
297 std::tie(LineText, Rest) = Rest.split(LocalEOL);
303 if (TextToWrite.endswith(LocalEOL) || EnsureNewline)
314 void InclusionRewriter::CommentOutDirective(
Lexer &DirectiveLex,
315 const Token &StartToken,
316 const MemoryBuffer &FromFile,
318 unsigned &NextToWrite,
int &Line) {
319 OutputContentUpTo(FromFile, NextToWrite,
322 Token DirectiveToken;
325 }
while (!DirectiveToken.
is(tok::eod) && DirectiveToken.
isNot(
tok::eof));
326 if (&FromFile == PredefinesBuffer) {
330 OS <<
"#if 0 /* expanded by -frewrite-includes */" << MainEOL;
331 OutputContentUpTo(FromFile, NextToWrite,
334 LocalEOL,
Line,
true);
335 OS <<
"#endif /* expanded by -frewrite-includes */" << MainEOL;
339 StringRef InclusionRewriter::NextIdentifierName(
Lexer &RawLex,
342 if (RawToken.
is(tok::raw_identifier))
344 if (RawToken.
is(tok::identifier))
351 bool InclusionRewriter::HandleHasInclude(
356 if (Tok.
isNot(tok::l_paren))
366 if (Tok.
is(tok::less)) {
369 FilenameBuffer +=
'<';
371 if (Tok.
is(tok::eod))
374 if (Tok.
is(tok::raw_identifier))
379 bool Invalid =
false;
380 StringRef TmpName = PP.
getSpelling(Tok, TmpBuffer, &Invalid);
384 FilenameBuffer += TmpName;
387 }
while (Tok.
isNot(tok::greater));
389 FilenameBuffer +=
'>';
390 Filename = FilenameBuffer;
392 if (Tok.
isNot(tok::string_literal))
395 bool Invalid =
false;
396 Filename = PP.
getSpelling(Tok, FilenameBuffer, &Invalid);
403 if (Tok.
isNot(tok::r_paren))
413 Includers.push_back(std::make_pair(FileEnt, FileEnt->
getDir()));
416 Filename,
SourceLocation(), isAngled, Lookup, CurDir, Includers,
nullptr,
417 nullptr,
nullptr,
nullptr,
nullptr,
nullptr);
419 FileExists = File !=
nullptr;
425 void InclusionRewriter::Process(
FileID FileId,
429 const MemoryBuffer &FromFile = *SM.
getBuffer(FileId, &Invalid);
430 assert(!Invalid &&
"Attempting to process invalid inclusion");
431 StringRef FileName = FromFile.getBufferIdentifier();
435 StringRef LocalEOL =
DetectEOL(FromFile);
439 WriteLineInfo(FileName, 1, FileType,
"");
441 WriteLineInfo(FileName, 1, FileType,
" 1");
460 Token HashToken = RawToken;
462 if (RawToken.
is(tok::raw_identifier))
469 CommentOutDirective(RawLex, HashToken, FromFile, LocalEOL, NextToWrite,
472 WriteLineInfo(FileName, Line - 1, FileType,
"");
473 StringRef LineInfoExtra;
475 if (
const Module *Mod = FindModuleAtLocation(Loc))
476 WriteImplicitModuleImport(Mod);
477 else if (
const IncludedFile *Inc = FindIncludeAtLocation(Loc)) {
478 const Module *Mod = FindEnteredModule(Loc);
480 OS <<
"#pragma clang module begin " 484 Process(Inc->Id, Inc->FileType, Inc->DirLookup);
487 OS <<
"#pragma clang module end /*" 492 LineInfoExtra =
" 2";
496 WriteLineInfo(FileName, Line, FileType, LineInfoExtra);
499 case tok::pp_pragma: {
500 StringRef
Identifier = NextIdentifierName(RawLex, RawToken);
501 if (Identifier ==
"clang" || Identifier ==
"GCC") {
502 if (NextIdentifierName(RawLex, RawToken) ==
"system_header") {
504 CommentOutDirective(RawLex, HashToken, FromFile, LocalEOL,
508 WriteLineInfo(FileName, Line, FileType);
510 }
else if (Identifier ==
"once") {
512 CommentOutDirective(RawLex, HashToken, FromFile, LocalEOL,
514 WriteLineInfo(FileName, Line, FileType);
526 if (RawToken.
is(tok::raw_identifier))
529 if (RawToken.
is(tok::identifier)) {
535 if (!HandleHasInclude(FileId, RawLex,
nullptr, RawToken,
540 "__has_include_next")) {
544 if (!HandleHasInclude(FileId, RawLex, DirLookup, RawToken,
552 OutputContentUpTo(FromFile, NextToWrite, SM.
getFileOffset(Loc),
553 LocalEOL,
Line,
false);
554 OS <<
'(' << (int) HasFile <<
")/*";
555 OutputContentUpTo(FromFile, NextToWrite,
558 LocalEOL,
Line,
false);
561 }
while (RawToken.
isNot(tok::eod));
563 OutputContentUpTo(FromFile, NextToWrite,
566 LocalEOL,
Line,
true);
567 WriteLineInfo(FileName, Line, FileType);
582 OutputContentUpTo(FromFile, NextToWrite,
585 LocalEOL,
Line,
true);
586 WriteLineInfo(FileName, Line, FileType);
598 OutputContentUpTo(FromFile, NextToWrite,
607 InclusionRewriter *Rewrite =
new InclusionRewriter(
609 Rewrite->detectMainFileEOL();
626 if (Tok.
is(tok::annot_module_begin))
627 Rewrite->handleModuleBegin(Tok);
Lexer - This provides a simple interface that turns a text buffer into a stream of tokens...
unsigned getRawEncoding() const
When a SourceLocation itself cannot be used, this returns an (opaque) 32-bit integer encoding for it...
SourceLocation getLocForEndOfFile(FileID FID) const
Return the source location corresponding to the last byte of the specified file.
Specialize PointerLikeTypeTraits to allow LazyGenerationalUpdatePtr to be placed into a PointerUnion...
bool LexFromRawLexer(Token &Result)
LexFromRawLexer - Lex a token from a designated raw lexer (one with no associated preprocessor object...
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)) {...
Defines the SourceManager interface.
void IgnorePragmas()
Install empty handlers for all pragmas (making them ignored).
CharacteristicKind
Indicates whether a file or directory holds normal user code, system code, or system code which is im...
This interface provides a way to observe the actions of the preprocessor as it does its thing...
tok::TokenKind getKind() const
bool isStr(const char(&Str)[StrLen]) const
Return true if this is the identifier for the specified string.
Token - This structure provides full information about a lexed token.
const LangOptions & getLangOpts() 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.
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 ...
HeaderSearch & getHeaderSearchInfo() const
bool GetIncludeFilenameSpelling(SourceLocation Loc, StringRef &Buffer)
Turn the specified lexer token into a fully checked and spelled filename, e.g.
void setParsingPreprocessorDirective(bool f)
Inform the lexer whether or not we are currently lexing a preprocessor directive. ...
unsigned getFileIDSize(FileID FID) const
The size of the SLocEntry that FID represents.
static StringRef DetectEOL(const MemoryBuffer &FromFile)
Detect the likely line ending style of FromFile by examining the first newline found within it...
PreprocessorOutputOptions - Options for controlling the C preprocessor output (e.g., -E).
IdentifierInfo * LookUpIdentifierInfo(Token &Identifier) const
Given a tok::raw_identifier token, look up the identifier information for the token and install it in...
Represents a character-granular source range.
const FileEntry * getFileEntryForID(FileID FID) const
Returns the FileEntry record for the provided FileID.
const AnnotatedLine * Line
void SetMacroExpansionOnlyInDirectives()
Disables macro expansion everywhere except for preprocessor directives.
void EnterMainSourceFile()
Enter the specified FileID as the main source file, which implicitly adds the builtin defines etc...
SourceLocation getSourceLocation(const char *Loc, unsigned TokLen=1) const
getSourceLocation - Return a source location identifier for the specified offset in the current file...
SourceLocation getLocation() const
Return a source location identifier for the specified offset in the current file. ...
Defines the clang::Preprocessor interface.
SrcMgr::CharacteristicKind getFileCharacteristic(SourceLocation Loc) const
Return the file characteristic of the specified source location, indicating whether this is a normal ...
Record the location of an inclusion directive, such as an #include or #import statement.
DirectoryLookup - This class represents one entry in the search list that specifies the search order ...
const DirectoryLookup * GetCurDirLookup()
Get the DirectoryLookup structure used to find the current FileEntry, if CurLexer is non-null and if ...
SourceManager & getSourceManager() const
const DirectoryEntry * getDir() const
Return the directory the file lives in.
unsigned getFileOffset(SourceLocation SpellingLoc) const
Returns the offset from the start of the file that the specified SourceLocation represents.
Encodes a location in the source.
IdentifierInfo * getIdentifierInfo() const
Cached information about one file (either on disk or in the virtual file system). ...
void Lex(Token &Result)
Lex the next token for this preprocessor.
unsigned getLineNumber(FileID FID, unsigned FilePos, bool *Invalid=nullptr) const
Given a SourceLocation, return the spelling line number for the position indicated.
bool isAtStartOfLine() const
isAtStartOfLine - Return true if this token is at the start of a line.
unsigned UseLineDirectives
Use #line instead of GCC-style # N.
StringRef getName() const
Return the actual identifier string.
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
bool isNot(tok::TokenKind K) const
const llvm::MemoryBuffer * getBuffer(FileID FID, SourceLocation Loc, bool *Invalid=nullptr) const
Return the buffer for the specified FileID.
void RewriteIncludesInInput(Preprocessor &PP, raw_ostream *OS, const PreprocessorOutputOptions &Opts)
RewriteIncludesInInput - Implement -frewrite-includes mode.
Dataflow Directional Tag Classes.
bool isValid() const
Return true if this is a valid SourceLocation object.
FileID getMainFileID() const
Returns the FileID of the main source file.
tok::PPKeywordKind getPPKeywordID() const
Return the preprocessor keyword ID for this identifier.
unsigned getLength() const
Indicates that the tracking object is a descendant of a referenced-counted OSObject, used in the Darwin kernel.
FileID getPredefinesFileID() const
Returns the FileID for the preprocessor predefines.
unsigned ShowLineMarkers
Show #line markers.
void SetCommentRetentionState(bool Mode)
SetCommentRetentionMode - Change the comment retention mode of the lexer to the specified mode...
A SourceLocation and its associated SourceManager.
void * getAnnotationValue() const
void SetKeepWhitespaceMode(bool Val)
SetKeepWhitespaceMode - This method lets clients enable or disable whitespace retention mode...
void addPPCallbacks(std::unique_ptr< PPCallbacks > C)
This class handles loading and caching of source files into memory.
Engages in a tight little dance with the lexer to efficiently preprocess tokens.