19#include "llvm/ADT/SmallString.h"
20#include "llvm/Support/raw_ostream.h"
35 : Id(Id), FileType(FileType) {}
41 llvm::MemoryBufferRef PredefinesBuffer;
43 bool UseLineDirectives;
45 std::map<SourceLocation, IncludedFile> FileIncludes;
47 std::map<SourceLocation, const Module *> ModuleIncludes;
49 std::map<SourceLocation, const Module *> ModuleEntryIncludes;
51 std::map<SourceLocation, bool> IfConditions;
54 SourceLocation LastInclusionLocation;
56 InclusionRewriter(Preprocessor &PP, raw_ostream &OS,
bool ShowLineMarkers,
57 bool UseLineDirectives);
59 void setPredefinesBuffer(
const llvm::MemoryBufferRef &Buf) {
60 PredefinesBuffer = Buf;
62 void detectMainFileEOL();
63 void handleModuleBegin(Token &
Tok) {
64 assert(
Tok.
getKind() == tok::annot_module_begin);
65 ModuleEntryIncludes.insert(
69 void FileChanged(SourceLocation Loc, FileChangeReason Reason,
71 FileID PrevFID)
override;
72 void FileSkipped(
const FileEntryRef &SkippedFile,
const Token &FilenameTok,
74 void InclusionDirective(SourceLocation HashLoc,
const Token &IncludeTok,
76 CharSourceRange FilenameRange,
78 StringRef RelativePath,
const Module *SuggestedModule,
81 void If(SourceLocation Loc, SourceRange ConditionRange,
82 ConditionValueKind ConditionValue)
override;
83 void Elif(SourceLocation Loc, SourceRange ConditionRange,
84 ConditionValueKind ConditionValue, SourceLocation IfLoc)
override;
85 void WriteLineInfo(StringRef Filename,
int Line,
87 StringRef
Extra = StringRef());
88 void WriteImplicitModuleImport(
const Module *Mod);
89 void OutputContentUpTo(
const MemoryBufferRef &FromFile,
unsigned &WriteFrom,
90 unsigned WriteTo, StringRef EOL,
int &lines,
92 void CommentOutDirective(Lexer &DirectivesLex,
const Token &StartToken,
93 const MemoryBufferRef &FromFile, StringRef EOL,
94 unsigned &NextToWrite,
int &Lines,
95 const IncludedFile *Inc =
nullptr);
96 const IncludedFile *FindIncludeAtLocation(SourceLocation Loc)
const;
97 StringRef getIncludedFileName(
const IncludedFile *Inc)
const;
98 const Module *FindModuleAtLocation(SourceLocation Loc)
const;
99 const Module *FindEnteredModule(SourceLocation Loc)
const;
100 bool IsIfAtLocationTrue(SourceLocation Loc)
const;
101 StringRef NextIdentifierName(Lexer &RawLex, Token &RawToken);
107InclusionRewriter::InclusionRewriter(
Preprocessor &PP, raw_ostream &OS,
108 bool ShowLineMarkers,
109 bool UseLineDirectives)
110 : PP(PP),
SM(PP.getSourceManager()),
OS(
OS), MainEOL(
"\n"),
111 ShowLineMarkers(ShowLineMarkers), UseLineDirectives(UseLineDirectives),
118void InclusionRewriter::WriteLineInfo(StringRef Filename,
int Line,
121 if (!ShowLineMarkers)
123 if (UseLineDirectives) {
124 OS <<
"#line" <<
' ' <<
Line <<
' ' <<
'"';
125 OS.write_escaped(Filename);
130 OS <<
'#' <<
' ' <<
Line <<
' ' <<
'"';
131 OS.write_escaped(Filename);
147void InclusionRewriter::WriteImplicitModuleImport(
const Module *Mod) {
149 <<
" /* clang -frewrite-includes: implicit import */" << MainEOL;
154void InclusionRewriter::FileChanged(SourceLocation Loc,
155 FileChangeReason Reason,
158 if (Reason != EnterFile)
163 FileID Id = FullSourceLoc(Loc,
SM).getFileID();
164 auto P = FileIncludes.insert(
165 std::make_pair(LastInclusionLocation, IncludedFile(Id, NewFileType)));
167 assert(P.second &&
"Unexpected revisitation of the same include directive");
168 LastInclusionLocation = SourceLocation();
173void InclusionRewriter::FileSkipped(
const FileEntryRef & ,
176 assert(LastInclusionLocation.
isValid() &&
177 "A file, that wasn't found via an inclusion directive, was skipped");
178 LastInclusionLocation = SourceLocation();
188void InclusionRewriter::InclusionDirective(
189 SourceLocation HashLoc,
const Token & ,
192 StringRef , StringRef ,
193 const Module *SuggestedModule,
bool ModuleImported,
195 if (ModuleImported) {
196 auto P = ModuleIncludes.insert(std::make_pair(HashLoc, SuggestedModule));
198 assert(P.second &&
"Unexpected revisitation of the same include directive");
200 LastInclusionLocation = HashLoc;
203void InclusionRewriter::If(SourceLocation Loc, SourceRange ConditionRange,
204 ConditionValueKind ConditionValue) {
205 auto P = IfConditions.insert(std::make_pair(Loc, ConditionValue == CVK_True));
207 assert(P.second &&
"Unexpected revisitation of the same if directive");
210void InclusionRewriter::Elif(SourceLocation Loc, SourceRange ConditionRange,
211 ConditionValueKind ConditionValue,
212 SourceLocation IfLoc) {
213 auto P = IfConditions.insert(std::make_pair(Loc, ConditionValue == CVK_True));
215 assert(P.second &&
"Unexpected revisitation of the same elif directive");
220const InclusionRewriter::IncludedFile *
221InclusionRewriter::FindIncludeAtLocation(SourceLocation Loc)
const {
222 const auto I = FileIncludes.find(Loc);
223 if (I != FileIncludes.end())
231InclusionRewriter::FindModuleAtLocation(SourceLocation Loc)
const {
232 const auto I = ModuleIncludes.find(Loc);
233 if (I != ModuleIncludes.end())
241InclusionRewriter::FindEnteredModule(SourceLocation Loc)
const {
242 const auto I = ModuleEntryIncludes.find(Loc);
243 if (I != ModuleEntryIncludes.end())
248bool InclusionRewriter::IsIfAtLocationTrue(SourceLocation Loc)
const {
249 const auto I = IfConditions.find(Loc);
250 if (I != IfConditions.end())
255void InclusionRewriter::detectMainFileEOL() {
256 std::optional<MemoryBufferRef> FromFile =
257 *
SM.getBufferOrNone(
SM.getMainFileID());
261 MainEOL = FromFile->getBuffer().detectEOL();
266void InclusionRewriter::OutputContentUpTo(
const MemoryBufferRef &FromFile,
267 unsigned &WriteFrom,
unsigned WriteTo,
268 StringRef LocalEOL,
int &
Line,
269 bool EnsureNewline) {
270 if (WriteTo <= WriteFrom)
272 if (FromFile == PredefinesBuffer) {
281 if (LocalEOL.size() == 2 &&
282 LocalEOL[0] == (FromFile.getBufferStart() + WriteTo)[-1] &&
283 LocalEOL[1] == (FromFile.getBufferStart() + WriteTo)[0])
286 StringRef TextToWrite(FromFile.getBufferStart() + WriteFrom,
287 WriteTo - WriteFrom);
289 Line += TextToWrite.count(LocalEOL);
291 if (MainEOL == LocalEOL) {
295 StringRef Rest = TextToWrite;
296 while (!Rest.empty()) {
298 size_t Idx = Rest.find(LocalEOL);
299 StringRef LineText = Rest.substr(0, Idx);
301 if (Idx != StringRef::npos) {
305 Idx += LocalEOL.size();
309 Rest = Rest.substr(Idx);
312 if (EnsureNewline && !TextToWrite.ends_with(LocalEOL))
319InclusionRewriter::getIncludedFileName(
const IncludedFile *Inc)
const {
321 auto B =
SM.getBufferOrNone(
Inc->Id);
322 assert(B &&
"Attempting to process invalid inclusion");
324 return llvm::sys::path::filename(B->getBufferIdentifier());
334void InclusionRewriter::CommentOutDirective(Lexer &DirectiveLex,
335 const Token &StartToken,
336 const MemoryBufferRef &FromFile,
338 unsigned &NextToWrite,
int &
Line,
339 const IncludedFile *Inc) {
340 OutputContentUpTo(FromFile, NextToWrite,
343 Token DirectiveToken;
346 }
while (!DirectiveToken.
is(tok::eod) && DirectiveToken.
isNot(tok::eof));
347 if (FromFile == PredefinesBuffer) {
352 OS <<
"#if defined(__CLANG_REWRITTEN_INCLUDES) ";
354 OS <<
"|| defined(__CLANG_REWRITTEN_SYSTEM_INCLUDES) ";
355 OS <<
"/* " << getIncludedFileName(Inc);
359 OS <<
" expanded by -frewrite-includes */" << MainEOL;
360 OutputContentUpTo(FromFile, NextToWrite,
363 LocalEOL,
Line,
true);
364 OS << (
Inc ?
"#else /* " :
"#endif /*") << getIncludedFileName(Inc)
365 <<
" expanded by -frewrite-includes */" << MainEOL;
369StringRef InclusionRewriter::NextIdentifierName(Lexer &RawLex,
372 if (RawToken.
is(tok::raw_identifier))
374 if (RawToken.
is(tok::identifier))
381void InclusionRewriter::Process(FileID FileId,
383 MemoryBufferRef FromFile;
385 auto B =
SM.getBufferOrNone(FileId);
386 assert(B &&
"Attempting to process invalid inclusion");
390 StringRef
FileName = FromFile.getBufferIdentifier();
394 StringRef LocalEOL = FromFile.getBuffer().detectEOL();
402 if (
SM.getFileIDSize(FileId) == 0)
408 assert(
SM.getLineNumber(FileId, NextToWrite) == 1);
416 while (RawToken.
isNot(tok::eof)) {
419 Token HashToken = RawToken;
421 if (RawToken.
is(tok::raw_identifier))
425 case tok::pp_include:
426 case tok::pp_include_next:
427 case tok::pp_import: {
429 const IncludedFile *
Inc = FindIncludeAtLocation(Loc);
430 CommentOutDirective(RawLex, HashToken, FromFile, LocalEOL,
431 NextToWrite,
Line, Inc);
434 StringRef LineInfoExtra;
435 if (
const Module *Mod = FindModuleAtLocation(Loc))
436 WriteImplicitModuleImport(Mod);
438 const Module *Mod = FindEnteredModule(Loc);
440 OS <<
"#pragma clang module begin "
444 Process(
Inc->Id,
Inc->FileType);
447 OS <<
"#pragma clang module end /*"
450 if (FromFile != PredefinesBuffer) {
451 OS <<
"#endif /* " << getIncludedFileName(Inc)
452 <<
" expanded by -frewrite-includes */" << LocalEOL;
457 LineInfoExtra =
" 2";
464 case tok::pp_pragma: {
465 StringRef Identifier = NextIdentifierName(RawLex, RawToken);
466 if (Identifier ==
"clang" || Identifier ==
"GCC") {
467 if (NextIdentifierName(RawLex, RawToken) ==
"system_header") {
469 CommentOutDirective(RawLex, HashToken, FromFile, LocalEOL,
475 }
else if (Identifier ==
"once") {
477 CommentOutDirective(RawLex, HashToken, FromFile, LocalEOL,
487 bool isTrue = IsIfAtLocationTrue(RawToken.
getLocation());
488 OutputContentUpTo(FromFile, NextToWrite,
490 LocalEOL,
Line,
true);
493 }
while (!RawToken.
is(tok::eod) && RawToken.
isNot(tok::eof));
500 OS <<
"#if 0 /* disabled by -frewrite-includes */" << MainEOL;
502 OS <<
"#if 0" << MainEOL;
504 OutputContentUpTo(FromFile, NextToWrite,
507 LocalEOL,
Line,
true);
509 OS <<
"#endif" << MainEOL;
510 OS <<
"#endif /* disabled by -frewrite-includes */" << MainEOL;
511 OS << (elif ?
"#elif " :
"#if ") << (isTrue ?
"1" :
"0")
512 <<
" /* evaluated by -frewrite-includes */" << MainEOL;
526 }
while (RawToken.
isNot(tok::eod) && RawToken.
isNot(tok::eof));
527 OutputContentUpTo(FromFile, NextToWrite,
530 LocalEOL,
Line,
true);
543 OutputContentUpTo(FromFile, NextToWrite,
544 SM.getFileOffset(
SM.getLocForEndOfFile(FileId)), LocalEOL,
552 InclusionRewriter *
Rewrite =
new InclusionRewriter(
571 if (
Tok.is(tok::annot_module_begin))
573 }
while (
Tok.isNot(tok::eof));
llvm::MachO::FileType FileType
Defines the clang::Preprocessor interface.
Defines the SourceManager interface.
tok::PPKeywordKind getPPKeywordID() const
Return the preprocessor keyword ID for this identifier.
StringRef getName() const
Return the actual identifier string.
void SetKeepWhitespaceMode(bool Val)
SetKeepWhitespaceMode - This method lets clients enable or disable whitespace retention mode.
bool LexFromRawLexer(Token &Result)
LexFromRawLexer - Lex a token from a designated raw lexer (one with no associated preprocessor object...
void SetCommentRetentionState(bool Mode)
SetCommentRetentionMode - Change the comment retention mode of the lexer to the specified mode.
SourceLocation getSourceLocation(const char *Loc, unsigned TokLen=1) const
getSourceLocation - Return a source location identifier for the specified offset in the current file.
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.
void setParsingPreprocessorDirective(bool f)
Inform the lexer whether or not we are currently lexing a preprocessor directive.
PreprocessorOutputOptions - Options for controlling the C preprocessor output (e.g....
unsigned UseLineDirectives
Use #line instead of GCC-style # N.
unsigned ShowLineMarkers
Show #line markers.
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
void IgnorePragmas()
Install empty handlers for all pragmas (making them ignored).
IdentifierInfo * LookUpIdentifierInfo(Token &Identifier) const
Given a tok::raw_identifier token, look up the identifier information for the token and install it in...
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.
SourceManager & getSourceManager() const
void SetMacroExpansionOnlyInDirectives()
Disables macro expansion everywhere except for preprocessor directives.
FileID getPredefinesFileID() const
Returns the FileID for the preprocessor predefines.
const LangOptions & getLangOpts() const
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
This class handles loading and caching of source files into memory.
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.
unsigned getLength() const
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)) {....
void * getAnnotationValue() const
tok::TokenKind getKind() const
bool isAtStartOfLine() const
isAtStartOfLine - Return true if this token is at the start of a line.
bool isNot(tok::TokenKind K) const
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.
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
bool Inc(InterpState &S, CodePtr OpPC, bool CanOverflow)
1) Pops a pointer from the stack 2) Load the value from the pointer 3) Writes the value increased by ...
The JSON file list parser is used to communicate input to InstallAPI.
CustomizableOptional< FileEntryRef > OptionalFileEntryRef
@ Rewrite
We are substituting template parameters for (typically) other template parameters in order to rewrite...
@ If
'if' clause, allowed on all the Compute Constructs, Data Constructs, Executable Constructs,...
@ Module
Module linkage, which indicates that the entity can be referred to from other translation units withi...
void RewriteIncludesInInput(Preprocessor &PP, raw_ostream *OS, const PreprocessorOutputOptions &Opts)
RewriteIncludesInInput - Implement -frewrite-includes mode.
Diagnostic wrappers for TextAPI types for error reporting.