21 #include "llvm/ADT/SmallString.h" 22 #include "llvm/Support/raw_ostream.h" 24 using namespace clang;
38 : Id(Id), FileType(FileType), DirLookup(DirLookup) {}
44 const llvm::MemoryBuffer *PredefinesBuffer;
46 bool UseLineDirectives;
48 std::map<unsigned, IncludedFile> FileIncludes;
50 std::map<unsigned, const Module *> ModuleIncludes;
52 std::map<unsigned, const Module *> ModuleEntryIncludes;
57 InclusionRewriter(
Preprocessor &PP, raw_ostream &OS,
bool ShowLineMarkers,
58 bool UseLineDirectives);
61 void setPredefinesBuffer(
const llvm::MemoryBuffer *Buf) {
62 PredefinesBuffer = Buf;
64 void detectMainFileEOL();
66 assert(Tok.
getKind() == tok::annot_module_begin);
74 void FileSkipped(
const FileEntry &SkippedFile,
const Token &FilenameTok,
77 StringRef FileName,
bool IsAngled,
79 StringRef SearchPath, StringRef RelativePath,
84 StringRef Extra = StringRef());
85 void WriteImplicitModuleImport(
const Module *Mod);
86 void OutputContentUpTo(
const MemoryBuffer &FromFile,
87 unsigned &WriteFrom,
unsigned WriteTo,
88 StringRef EOL,
int &lines,
90 void CommentOutDirective(
Lexer &DirectivesLex,
const Token &StartToken,
91 const MemoryBuffer &FromFile, StringRef EOL,
92 unsigned &NextToWrite,
int &Lines);
96 const IncludedFile *FindIncludeAtLocation(
SourceLocation Loc)
const;
99 StringRef NextIdentifierName(
Lexer &RawLex,
Token &RawToken);
105 InclusionRewriter::InclusionRewriter(
Preprocessor &PP, raw_ostream &OS,
106 bool ShowLineMarkers,
107 bool UseLineDirectives)
108 : PP(PP), SM(PP.getSourceManager()), OS(OS), MainEOL(
"\n"),
109 PredefinesBuffer(nullptr), ShowLineMarkers(ShowLineMarkers),
110 UseLineDirectives(UseLineDirectives),
117 void InclusionRewriter::WriteLineInfo(StringRef
Filename,
int Line,
120 if (!ShowLineMarkers)
122 if (UseLineDirectives) {
123 OS <<
"#line" <<
' ' << Line <<
' ' <<
'"';
124 OS.write_escaped(Filename);
129 OS <<
'#' <<
' ' << Line <<
' ' <<
'"';
130 OS.write_escaped(Filename);
146 void InclusionRewriter::WriteImplicitModuleImport(
const Module *Mod) {
148 <<
" /* clang -frewrite-includes: implicit import */" << MainEOL;
154 FileChangeReason Reason,
157 if (Reason != EnterFile)
163 auto P = FileIncludes.insert(
167 assert(
P.second &&
"Unexpected revisitation of the same include directive");
173 void InclusionRewriter::FileSkipped(
const FileEntry &,
176 assert(LastInclusionLocation.
isValid() &&
177 "A file, that wasn't found via an inclusion directive, was skipped");
188 void InclusionRewriter::InclusionDirective(
SourceLocation HashLoc,
199 auto P = ModuleIncludes.insert(
202 assert(
P.second &&
"Unexpected revisitation of the same include directive");
204 LastInclusionLocation = HashLoc;
209 const InclusionRewriter::IncludedFile *
210 InclusionRewriter::FindIncludeAtLocation(
SourceLocation Loc)
const {
212 if (I != FileIncludes.end())
220 InclusionRewriter::FindModuleAtLocation(
SourceLocation Loc)
const {
222 if (I != ModuleIncludes.end())
232 if (I != ModuleEntryIncludes.end())
239 static StringRef
DetectEOL(
const MemoryBuffer &FromFile) {
243 const char *Pos = strchr(FromFile.getBufferStart(),
'\n');
246 if (Pos - 1 >= FromFile.getBufferStart() && Pos[-1] ==
'\r')
248 if (Pos + 1 < FromFile.getBufferEnd() && Pos[1] ==
'\r')
253 void InclusionRewriter::detectMainFileEOL() {
264 void InclusionRewriter::OutputContentUpTo(
const MemoryBuffer &FromFile,
265 unsigned &WriteFrom,
unsigned WriteTo,
266 StringRef LocalEOL,
int &Line,
267 bool EnsureNewline) {
268 if (WriteTo <= WriteFrom)
270 if (&FromFile == PredefinesBuffer) {
279 if (LocalEOL.size() == 2 &&
280 LocalEOL[0] == (FromFile.getBufferStart() + WriteTo)[-1] &&
281 LocalEOL[1] == (FromFile.getBufferStart() + WriteTo)[0])
284 StringRef TextToWrite(FromFile.getBufferStart() + WriteFrom,
285 WriteTo - WriteFrom);
287 if (MainEOL == LocalEOL) {
290 Line += TextToWrite.count(LocalEOL);
291 if (EnsureNewline && !TextToWrite.endswith(LocalEOL))
295 StringRef Rest = TextToWrite;
296 while (!Rest.empty()) {
298 std::tie(LineText, Rest) = Rest.split(LocalEOL);
304 if (TextToWrite.endswith(LocalEOL) || EnsureNewline)
315 void InclusionRewriter::CommentOutDirective(
Lexer &DirectiveLex,
316 const Token &StartToken,
317 const MemoryBuffer &FromFile,
319 unsigned &NextToWrite,
int &Line) {
320 OutputContentUpTo(FromFile, NextToWrite,
323 Token DirectiveToken;
326 }
while (!DirectiveToken.
is(tok::eod) && DirectiveToken.
isNot(
tok::eof));
327 if (&FromFile == PredefinesBuffer) {
331 OS <<
"#if 0 /* expanded by -frewrite-includes */" << MainEOL;
332 OutputContentUpTo(FromFile, NextToWrite,
335 LocalEOL,
Line,
true);
336 OS <<
"#endif /* expanded by -frewrite-includes */" << MainEOL;
340 StringRef InclusionRewriter::NextIdentifierName(
Lexer &RawLex,
343 if (RawToken.
is(tok::raw_identifier))
345 if (RawToken.
is(tok::identifier))
352 bool InclusionRewriter::HandleHasInclude(
357 if (Tok.
isNot(tok::l_paren))
367 if (Tok.
is(tok::less)) {
370 FilenameBuffer +=
'<';
372 if (Tok.
is(tok::eod))
375 if (Tok.
is(tok::raw_identifier))
380 bool Invalid =
false;
381 StringRef TmpName = PP.
getSpelling(Tok, TmpBuffer, &Invalid);
385 FilenameBuffer += TmpName;
388 }
while (Tok.
isNot(tok::greater));
390 FilenameBuffer +=
'>';
391 Filename = FilenameBuffer;
393 if (Tok.
isNot(tok::string_literal))
396 bool Invalid =
false;
397 Filename = PP.
getSpelling(Tok, FilenameBuffer, &Invalid);
404 if (Tok.
isNot(tok::r_paren))
414 Includers.push_back(std::make_pair(FileEnt, FileEnt->
getDir()));
417 Filename,
SourceLocation(), isAngled, Lookup, CurDir, Includers,
nullptr,
418 nullptr,
nullptr,
nullptr,
nullptr);
420 FileExists = File !=
nullptr;
426 void InclusionRewriter::Process(
FileID FileId,
430 const MemoryBuffer &FromFile = *SM.
getBuffer(FileId, &Invalid);
431 assert(!Invalid &&
"Attempting to process invalid inclusion");
432 StringRef FileName = FromFile.getBufferIdentifier();
436 StringRef LocalEOL =
DetectEOL(FromFile);
440 WriteLineInfo(FileName, 1, FileType,
"");
442 WriteLineInfo(FileName, 1, FileType,
" 1");
461 Token HashToken = RawToken;
463 if (RawToken.
is(tok::raw_identifier))
467 case tok::pp_include:
468 case tok::pp_include_next:
469 case tok::pp_import: {
470 CommentOutDirective(RawLex, HashToken, FromFile, LocalEOL, NextToWrite,
473 WriteLineInfo(FileName, Line - 1, FileType,
"");
474 StringRef LineInfoExtra;
476 if (
const Module *Mod = FindModuleAtLocation(Loc))
477 WriteImplicitModuleImport(Mod);
478 else if (
const IncludedFile *Inc = FindIncludeAtLocation(Loc)) {
479 const Module *Mod = FindEnteredModule(Loc);
481 OS <<
"#pragma clang module begin " 485 Process(Inc->Id, Inc->FileType, Inc->DirLookup);
488 OS <<
"#pragma clang module end /*" 493 LineInfoExtra =
" 2";
497 WriteLineInfo(FileName, Line, FileType, LineInfoExtra);
500 case tok::pp_pragma: {
501 StringRef Identifier = NextIdentifierName(RawLex, RawToken);
502 if (Identifier ==
"clang" || Identifier ==
"GCC") {
503 if (NextIdentifierName(RawLex, RawToken) ==
"system_header") {
505 CommentOutDirective(RawLex, HashToken, FromFile, LocalEOL,
509 WriteLineInfo(FileName, Line, FileType);
511 }
else if (Identifier ==
"once") {
513 CommentOutDirective(RawLex, HashToken, FromFile, LocalEOL,
515 WriteLineInfo(FileName, Line, FileType);
527 if (RawToken.
is(tok::raw_identifier))
530 if (RawToken.
is(tok::identifier)) {
536 if (!HandleHasInclude(FileId, RawLex,
nullptr, RawToken,
541 "__has_include_next")) {
545 if (!HandleHasInclude(FileId, RawLex, DirLookup, RawToken,
553 OutputContentUpTo(FromFile, NextToWrite, SM.
getFileOffset(Loc),
554 LocalEOL,
Line,
false);
555 OS <<
'(' << (int) HasFile <<
")/*";
556 OutputContentUpTo(FromFile, NextToWrite,
559 LocalEOL,
Line,
false);
562 }
while (RawToken.
isNot(tok::eod));
564 OutputContentUpTo(FromFile, NextToWrite,
567 LocalEOL,
Line,
true);
568 WriteLineInfo(FileName, Line, FileType);
583 OutputContentUpTo(FromFile, NextToWrite,
586 LocalEOL,
Line,
true);
587 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.
DominatorTree GraphTraits specialization so the DominatorTree can be iterable by generic graph iterat...
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
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.
llvm::MemoryBuffer * getBuffer(FileID FID, SourceLocation Loc, bool *Invalid=nullptr) const
Return the buffer for the specified FileID.
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
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
bool GetIncludeFilenameSpelling(SourceLocation Loc, StringRef &Filename)
Turn the specified lexer token into a fully checked and spelled filename, e.g.
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.