21 #include "llvm/ADT/SmallString.h" 22 #include "llvm/Support/raw_ostream.h" 24 using namespace clang;
36 : Id(Id), FileType(FileType) {}
42 const llvm::MemoryBuffer *PredefinesBuffer;
44 bool UseLineDirectives;
46 std::map<unsigned, IncludedFile> FileIncludes;
48 std::map<unsigned, const Module *> ModuleIncludes;
50 std::map<unsigned, const Module *> ModuleEntryIncludes;
55 InclusionRewriter(
Preprocessor &PP, raw_ostream &OS,
bool ShowLineMarkers,
56 bool UseLineDirectives);
58 void setPredefinesBuffer(
const llvm::MemoryBuffer *Buf) {
59 PredefinesBuffer = Buf;
61 void detectMainFileEOL();
63 assert(Tok.
getKind() == tok::annot_module_begin);
71 void FileSkipped(
const FileEntry &SkippedFile,
const Token &FilenameTok,
74 StringRef FileName,
bool IsAngled,
76 StringRef SearchPath, StringRef RelativePath,
77 const Module *Imported)
override;
80 StringRef Extra = StringRef());
81 void WriteImplicitModuleImport(
const Module *Mod);
82 void OutputContentUpTo(
const MemoryBuffer &FromFile,
83 unsigned &WriteFrom,
unsigned WriteTo,
84 StringRef EOL,
int &lines,
86 void CommentOutDirective(
Lexer &DirectivesLex,
const Token &StartToken,
87 const MemoryBuffer &FromFile, StringRef EOL,
88 unsigned &NextToWrite,
int &Lines);
92 const IncludedFile *FindIncludeAtLocation(
SourceLocation Loc)
const;
95 StringRef NextIdentifierName(
Lexer &RawLex,
Token &RawToken);
101 InclusionRewriter::InclusionRewriter(
Preprocessor &PP, raw_ostream &OS,
102 bool ShowLineMarkers,
103 bool UseLineDirectives)
104 : PP(PP), SM(PP.getSourceManager()), OS(OS), MainEOL(
"\n"),
105 PredefinesBuffer(nullptr), ShowLineMarkers(ShowLineMarkers),
106 UseLineDirectives(UseLineDirectives),
113 void InclusionRewriter::WriteLineInfo(StringRef
Filename,
int Line,
116 if (!ShowLineMarkers)
118 if (UseLineDirectives) {
119 OS <<
"#line" <<
' ' << Line <<
' ' <<
'"';
120 OS.write_escaped(Filename);
125 OS <<
'#' <<
' ' << Line <<
' ' <<
'"';
126 OS.write_escaped(Filename);
142 void InclusionRewriter::WriteImplicitModuleImport(
const Module *Mod) {
144 <<
" /* clang -frewrite-includes: implicit import */" << MainEOL;
150 FileChangeReason Reason,
153 if (Reason != EnterFile)
159 auto P = FileIncludes.insert(std::make_pair(
160 LastInclusionLocation.
getRawEncoding(), IncludedFile(Id, NewFileType)));
162 assert(
P.second &&
"Unexpected revisitation of the same include directive");
168 void InclusionRewriter::FileSkipped(
const FileEntry &,
171 assert(LastInclusionLocation.
isValid() &&
172 "A file, that wasn't found via an inclusion directive, was skipped");
183 void InclusionRewriter::InclusionDirective(
SourceLocation HashLoc,
193 auto P = ModuleIncludes.insert(
196 assert(
P.second &&
"Unexpected revisitation of the same include directive");
198 LastInclusionLocation = HashLoc;
203 const InclusionRewriter::IncludedFile *
204 InclusionRewriter::FindIncludeAtLocation(
SourceLocation Loc)
const {
206 if (I != FileIncludes.end())
214 InclusionRewriter::FindModuleAtLocation(
SourceLocation Loc)
const {
216 if (I != ModuleIncludes.end())
226 if (I != ModuleEntryIncludes.end())
233 static StringRef
DetectEOL(
const MemoryBuffer &FromFile) {
237 const char *Pos = strchr(FromFile.getBufferStart(),
'\n');
240 if (Pos - 1 >= FromFile.getBufferStart() && Pos[-1] ==
'\r')
242 if (Pos + 1 < FromFile.getBufferEnd() && Pos[1] ==
'\r')
247 void InclusionRewriter::detectMainFileEOL() {
258 void InclusionRewriter::OutputContentUpTo(
const MemoryBuffer &FromFile,
259 unsigned &WriteFrom,
unsigned WriteTo,
260 StringRef LocalEOL,
int &Line,
261 bool EnsureNewline) {
262 if (WriteTo <= WriteFrom)
264 if (&FromFile == PredefinesBuffer) {
273 if (LocalEOL.size() == 2 &&
274 LocalEOL[0] == (FromFile.getBufferStart() + WriteTo)[-1] &&
275 LocalEOL[1] == (FromFile.getBufferStart() + WriteTo)[0])
278 StringRef TextToWrite(FromFile.getBufferStart() + WriteFrom,
279 WriteTo - WriteFrom);
281 if (MainEOL == LocalEOL) {
284 Line += TextToWrite.count(LocalEOL);
285 if (EnsureNewline && !TextToWrite.endswith(LocalEOL))
289 StringRef Rest = TextToWrite;
290 while (!Rest.empty()) {
292 std::tie(LineText, Rest) = Rest.split(LocalEOL);
298 if (TextToWrite.endswith(LocalEOL) || EnsureNewline)
309 void InclusionRewriter::CommentOutDirective(
Lexer &DirectiveLex,
310 const Token &StartToken,
311 const MemoryBuffer &FromFile,
313 unsigned &NextToWrite,
int &Line) {
314 OutputContentUpTo(FromFile, NextToWrite,
317 Token DirectiveToken;
320 }
while (!DirectiveToken.
is(tok::eod) && DirectiveToken.
isNot(
tok::eof));
321 if (&FromFile == PredefinesBuffer) {
325 OS <<
"#if 0 /* expanded by -frewrite-includes */" << MainEOL;
326 OutputContentUpTo(FromFile, NextToWrite,
329 LocalEOL,
Line,
true);
330 OS <<
"#endif /* expanded by -frewrite-includes */" << MainEOL;
334 StringRef InclusionRewriter::NextIdentifierName(
Lexer &RawLex,
337 if (RawToken.
is(tok::raw_identifier))
339 if (RawToken.
is(tok::identifier))
346 bool InclusionRewriter::HandleHasInclude(
351 if (Tok.
isNot(tok::l_paren))
361 if (Tok.
is(tok::less)) {
364 FilenameBuffer +=
'<';
366 if (Tok.
is(tok::eod))
369 if (Tok.
is(tok::raw_identifier))
374 bool Invalid =
false;
375 StringRef TmpName = PP.
getSpelling(Tok, TmpBuffer, &Invalid);
379 FilenameBuffer += TmpName;
382 }
while (Tok.
isNot(tok::greater));
384 FilenameBuffer +=
'>';
385 Filename = FilenameBuffer;
387 if (Tok.
isNot(tok::string_literal))
390 bool Invalid =
false;
391 Filename = PP.
getSpelling(Tok, FilenameBuffer, &Invalid);
398 if (Tok.
isNot(tok::r_paren))
408 Includers.push_back(std::make_pair(FileEnt, FileEnt->
getDir()));
411 Filename,
SourceLocation(), isAngled,
nullptr, CurDir, Includers,
nullptr,
412 nullptr,
nullptr,
nullptr,
nullptr);
414 FileExists = File !=
nullptr;
420 void InclusionRewriter::Process(
FileID FileId,
423 const MemoryBuffer &FromFile = *SM.
getBuffer(FileId, &Invalid);
424 assert(!Invalid &&
"Attempting to process invalid inclusion");
425 StringRef FileName = FromFile.getBufferIdentifier();
429 StringRef LocalEOL =
DetectEOL(FromFile);
433 WriteLineInfo(FileName, 1, FileType,
"");
435 WriteLineInfo(FileName, 1, FileType,
" 1");
454 Token HashToken = RawToken;
456 if (RawToken.
is(tok::raw_identifier))
460 case tok::pp_include:
461 case tok::pp_include_next:
462 case tok::pp_import: {
463 CommentOutDirective(RawLex, HashToken, FromFile, LocalEOL, NextToWrite,
466 WriteLineInfo(FileName, Line - 1, FileType,
"");
467 StringRef LineInfoExtra;
469 if (
const Module *Mod = FindModuleAtLocation(Loc))
470 WriteImplicitModuleImport(Mod);
471 else if (
const IncludedFile *Inc = FindIncludeAtLocation(Loc)) {
472 const Module *Mod = FindEnteredModule(Loc);
474 OS <<
"#pragma clang module begin " 478 Process(Inc->Id, Inc->FileType);
481 OS <<
"#pragma clang module end /*" 486 LineInfoExtra =
" 2";
490 WriteLineInfo(FileName, Line, FileType, LineInfoExtra);
493 case tok::pp_pragma: {
494 StringRef Identifier = NextIdentifierName(RawLex, RawToken);
495 if (Identifier ==
"clang" || Identifier ==
"GCC") {
496 if (NextIdentifierName(RawLex, RawToken) ==
"system_header") {
498 CommentOutDirective(RawLex, HashToken, FromFile, LocalEOL,
502 WriteLineInfo(FileName, Line, FileType);
504 }
else if (Identifier ==
"once") {
506 CommentOutDirective(RawLex, HashToken, FromFile, LocalEOL,
508 WriteLineInfo(FileName, Line, FileType);
520 if (RawToken.
is(tok::raw_identifier))
523 if (RawToken.
is(tok::identifier)) {
529 if (!HandleHasInclude(FileId, RawLex,
nullptr, RawToken,
534 "__has_include_next")) {
539 if (!HandleHasInclude(FileId, RawLex, Lookup, RawToken,
547 OutputContentUpTo(FromFile, NextToWrite, SM.
getFileOffset(Loc),
548 LocalEOL,
Line,
false);
549 OS <<
'(' << (int) HasFile <<
")/*";
550 OutputContentUpTo(FromFile, NextToWrite,
553 LocalEOL,
Line,
false);
556 }
while (RawToken.
isNot(tok::eod));
558 OutputContentUpTo(FromFile, NextToWrite,
561 LocalEOL,
Line,
true);
562 WriteLineInfo(FileName, Line, FileType);
577 OutputContentUpTo(FromFile, NextToWrite,
580 LocalEOL,
Line,
true);
581 WriteLineInfo(FileName, Line, FileType);
592 OutputContentUpTo(FromFile, NextToWrite,
601 InclusionRewriter *Rewrite =
new InclusionRewriter(
603 Rewrite->detectMainFileEOL();
620 if (Tok.
is(tok::annot_module_begin))
621 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.