19#include "llvm/ADT/SmallString.h"
20#include "llvm/Support/Path.h"
21#include "llvm/Support/raw_ostream.h"
36 : Id(Id), FileType(FileType) {}
42 llvm::MemoryBufferRef PredefinesBuffer;
44 bool UseLineDirectives;
46 std::map<SourceLocation, IncludedFile> FileIncludes;
48 std::map<SourceLocation, const Module *> ModuleIncludes;
50 std::map<SourceLocation, const Module *> ModuleEntryIncludes;
52 std::map<SourceLocation, bool> IfConditions;
55 SourceLocation LastInclusionLocation;
57 InclusionRewriter(Preprocessor &PP, raw_ostream &OS,
bool ShowLineMarkers,
58 bool UseLineDirectives);
60 void setPredefinesBuffer(
const llvm::MemoryBufferRef &Buf) {
61 PredefinesBuffer = Buf;
63 void detectMainFileEOL();
64 void handleModuleBegin(Token &
Tok) {
65 assert(
Tok.
getKind() == tok::annot_module_begin);
66 ModuleEntryIncludes.insert(
70 void FileChanged(SourceLocation Loc, FileChangeReason Reason,
72 FileID PrevFID)
override;
73 void FileSkipped(
const FileEntryRef &SkippedFile,
const Token &FilenameTok,
75 void InclusionDirective(SourceLocation HashLoc,
const Token &IncludeTok,
77 CharSourceRange FilenameRange,
79 StringRef RelativePath,
const Module *SuggestedModule,
82 void If(SourceLocation Loc, SourceRange ConditionRange,
83 ConditionValueKind ConditionValue)
override;
84 void Elif(SourceLocation Loc, SourceRange ConditionRange,
85 ConditionValueKind ConditionValue, SourceLocation IfLoc)
override;
86 void WriteLineInfo(StringRef Filename,
int Line,
88 StringRef
Extra = StringRef());
89 void WriteImplicitModuleImport(
const Module *Mod);
90 void OutputContentUpTo(
const MemoryBufferRef &FromFile,
unsigned &WriteFrom,
91 unsigned WriteTo, StringRef EOL,
int &lines,
93 void CommentOutDirective(Lexer &DirectivesLex,
const Token &StartToken,
94 const MemoryBufferRef &FromFile, StringRef EOL,
95 unsigned &NextToWrite,
int &Lines,
96 const IncludedFile *Inc =
nullptr);
97 const IncludedFile *FindIncludeAtLocation(SourceLocation Loc)
const;
98 StringRef getIncludedFileName(
const IncludedFile *Inc)
const;
99 const Module *FindModuleAtLocation(SourceLocation Loc)
const;
100 const Module *FindEnteredModule(SourceLocation Loc)
const;
101 bool IsIfAtLocationTrue(SourceLocation Loc)
const;
102 StringRef NextIdentifierName(Lexer &RawLex, Token &RawToken);
108InclusionRewriter::InclusionRewriter(
Preprocessor &PP, raw_ostream &OS,
109 bool ShowLineMarkers,
110 bool UseLineDirectives)
111 : PP(PP), SM(PP.getSourceManager()),
OS(
OS), MainEOL(
"\n"),
112 ShowLineMarkers(ShowLineMarkers), UseLineDirectives(UseLineDirectives),
119void InclusionRewriter::WriteLineInfo(StringRef Filename,
int Line,
122 if (!ShowLineMarkers)
124 if (UseLineDirectives) {
125 OS <<
"#line" <<
' ' <<
Line <<
' ' <<
'"';
131 OS <<
'#' <<
' ' <<
Line <<
' ' <<
'"';
148void InclusionRewriter::WriteImplicitModuleImport(
const Module *Mod) {
150 <<
" /* clang -frewrite-includes: implicit import */" << MainEOL;
155void InclusionRewriter::FileChanged(SourceLocation Loc,
156 FileChangeReason Reason,
159 if (Reason != EnterFile)
164 FileID Id = FullSourceLoc(Loc, SM).getFileID();
165 auto P = FileIncludes.insert(
166 std::make_pair(LastInclusionLocation, IncludedFile(Id, NewFileType)));
168 assert(P.second &&
"Unexpected revisitation of the same include directive");
169 LastInclusionLocation = SourceLocation();
174void InclusionRewriter::FileSkipped(
const FileEntryRef & ,
177 assert(LastInclusionLocation.
isValid() &&
178 "A file, that wasn't found via an inclusion directive, was skipped");
179 LastInclusionLocation = SourceLocation();
189void InclusionRewriter::InclusionDirective(
190 SourceLocation HashLoc,
const Token & ,
193 StringRef , StringRef ,
194 const Module *SuggestedModule,
bool ModuleImported,
196 if (ModuleImported) {
197 auto P = ModuleIncludes.insert(std::make_pair(HashLoc, SuggestedModule));
199 assert(P.second &&
"Unexpected revisitation of the same include directive");
201 LastInclusionLocation = HashLoc;
204void InclusionRewriter::If(SourceLocation Loc, SourceRange ConditionRange,
205 ConditionValueKind ConditionValue) {
206 auto P = IfConditions.insert(std::make_pair(Loc, ConditionValue == CVK_True));
208 assert(P.second &&
"Unexpected revisitation of the same if directive");
211void InclusionRewriter::Elif(SourceLocation Loc, SourceRange ConditionRange,
212 ConditionValueKind ConditionValue,
213 SourceLocation IfLoc) {
214 auto P = IfConditions.insert(std::make_pair(Loc, ConditionValue == CVK_True));
216 assert(P.second &&
"Unexpected revisitation of the same elif directive");
221const InclusionRewriter::IncludedFile *
222InclusionRewriter::FindIncludeAtLocation(SourceLocation Loc)
const {
223 const auto I = FileIncludes.find(Loc);
224 if (I != FileIncludes.end())
232InclusionRewriter::FindModuleAtLocation(SourceLocation Loc)
const {
233 const auto I = ModuleIncludes.find(Loc);
234 if (I != ModuleIncludes.end())
242InclusionRewriter::FindEnteredModule(SourceLocation Loc)
const {
243 const auto I = ModuleEntryIncludes.find(Loc);
244 if (I != ModuleEntryIncludes.end())
249bool InclusionRewriter::IsIfAtLocationTrue(SourceLocation Loc)
const {
250 const auto I = IfConditions.find(Loc);
251 if (I != IfConditions.end())
256void InclusionRewriter::detectMainFileEOL() {
257 std::optional<MemoryBufferRef> FromFile =
262 MainEOL = FromFile->getBuffer().detectEOL();
267void InclusionRewriter::OutputContentUpTo(
const MemoryBufferRef &FromFile,
268 unsigned &WriteFrom,
unsigned WriteTo,
269 StringRef LocalEOL,
int &
Line,
270 bool EnsureNewline) {
271 if (WriteTo <= WriteFrom)
273 if (FromFile == PredefinesBuffer) {
282 if (LocalEOL.size() == 2 &&
283 LocalEOL[0] == (FromFile.getBufferStart() + WriteTo)[-1] &&
284 LocalEOL[1] == (FromFile.getBufferStart() + WriteTo)[0])
287 StringRef TextToWrite(FromFile.getBufferStart() + WriteFrom,
288 WriteTo - WriteFrom);
290 Line += TextToWrite.count(LocalEOL);
292 if (MainEOL == LocalEOL) {
296 StringRef Rest = TextToWrite;
297 while (!Rest.empty()) {
299 size_t Idx = Rest.find(LocalEOL);
300 StringRef LineText = Rest.substr(0, Idx);
302 if (Idx != StringRef::npos) {
306 Idx += LocalEOL.size();
310 Rest = Rest.substr(Idx);
313 if (EnsureNewline && !TextToWrite.ends_with(LocalEOL))
320InclusionRewriter::getIncludedFileName(
const IncludedFile *Inc)
const {
323 assert(B &&
"Attempting to process invalid inclusion");
325 return llvm::sys::path::filename(B->getBufferIdentifier());
335void InclusionRewriter::CommentOutDirective(Lexer &DirectiveLex,
336 const Token &StartToken,
337 const MemoryBufferRef &FromFile,
339 unsigned &NextToWrite,
int &
Line,
340 const IncludedFile *Inc) {
341 OutputContentUpTo(FromFile, NextToWrite,
344 Token DirectiveToken;
347 }
while (!DirectiveToken.
is(tok::eod) && DirectiveToken.
isNot(tok::eof));
348 if (FromFile == PredefinesBuffer) {
353 OS <<
"#if defined(__CLANG_REWRITTEN_INCLUDES) ";
355 OS <<
"|| defined(__CLANG_REWRITTEN_SYSTEM_INCLUDES) ";
356 OS <<
"/* " << getIncludedFileName(Inc);
360 OS <<
" expanded by -frewrite-includes */" << MainEOL;
361 OutputContentUpTo(FromFile, NextToWrite,
364 LocalEOL,
Line,
true);
365 OS << (
Inc ?
"#else /* " :
"#endif /*") << getIncludedFileName(Inc)
366 <<
" expanded by -frewrite-includes */" << MainEOL;
370StringRef InclusionRewriter::NextIdentifierName(Lexer &RawLex,
373 if (RawToken.
is(tok::raw_identifier))
375 if (RawToken.
is(tok::identifier))
382void InclusionRewriter::Process(FileID FileId,
384 MemoryBufferRef FromFile;
387 assert(B &&
"Attempting to process invalid inclusion");
391 StringRef
FileName = FromFile.getBufferIdentifier();
395 StringRef LocalEOL = FromFile.getBuffer().detectEOL();
417 while (RawToken.
isNot(tok::eof)) {
420 Token HashToken = RawToken;
422 if (RawToken.
is(tok::raw_identifier))
426 case tok::pp_include:
427 case tok::pp_include_next:
428 case tok::pp_import: {
430 const IncludedFile *
Inc = FindIncludeAtLocation(Loc);
431 CommentOutDirective(RawLex, HashToken, FromFile, LocalEOL,
432 NextToWrite,
Line, Inc);
435 StringRef LineInfoExtra;
436 if (
const Module *Mod = FindModuleAtLocation(Loc))
437 WriteImplicitModuleImport(Mod);
439 const Module *Mod = FindEnteredModule(Loc);
441 OS <<
"#pragma clang module begin "
445 Process(
Inc->Id,
Inc->FileType);
448 OS <<
"#pragma clang module end /*"
451 if (FromFile != PredefinesBuffer) {
452 OS <<
"#endif /* " << getIncludedFileName(Inc)
453 <<
" expanded by -frewrite-includes */" << LocalEOL;
458 LineInfoExtra =
" 2";
465 case tok::pp_pragma: {
466 StringRef Identifier = NextIdentifierName(RawLex, RawToken);
467 if (Identifier ==
"clang" || Identifier ==
"GCC") {
468 if (NextIdentifierName(RawLex, RawToken) ==
"system_header") {
470 CommentOutDirective(RawLex, HashToken, FromFile, LocalEOL,
476 }
else if (Identifier ==
"once") {
478 CommentOutDirective(RawLex, HashToken, FromFile, LocalEOL,
488 bool isTrue = IsIfAtLocationTrue(RawToken.
getLocation());
489 OutputContentUpTo(FromFile, NextToWrite,
491 LocalEOL,
Line,
true);
494 }
while (!RawToken.
is(tok::eod) && RawToken.
isNot(tok::eof));
501 OS <<
"#if 0 /* disabled by -frewrite-includes */" << MainEOL;
503 OS <<
"#if 0" << MainEOL;
505 OutputContentUpTo(FromFile, NextToWrite,
508 LocalEOL,
Line,
true);
510 OS <<
"#endif" << MainEOL;
511 OS <<
"#endif /* disabled by -frewrite-includes */" << MainEOL;
512 OS << (elif ?
"#elif " :
"#if ") << (isTrue ?
"1" :
"0")
513 <<
" /* evaluated by -frewrite-includes */" << MainEOL;
527 }
while (RawToken.
isNot(tok::eod) && RawToken.
isNot(tok::eof));
528 OutputContentUpTo(FromFile, NextToWrite,
531 LocalEOL,
Line,
true);
544 OutputContentUpTo(FromFile, NextToWrite,
553 InclusionRewriter *
Rewrite =
new InclusionRewriter(
572 if (
Tok.is(tok::annot_module_begin))
574 }
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.
unsigned getFileOffset(SourceLocation SpellingLoc) const
Returns the offset from the start of the file that the specified SourceLocation represents.
SourceLocation getLocForEndOfFile(FileID FID) const
Return the source location corresponding to the last byte of the specified file.
FileID getMainFileID() const
Returns the FileID of the main source file.
llvm::MemoryBufferRef getBufferOrFake(FileID FID, SourceLocation Loc=SourceLocation()) const
Return the buffer for the specified FileID.
unsigned getFileIDSize(FileID FID) const
The size of the SLocEntry that FID represents.
unsigned getLineNumber(FileID FID, unsigned FilePos, bool *Invalid=nullptr) const
Given a SourceLocation, return the spelling line number for the position indicated.
SrcMgr::CharacteristicKind getFileCharacteristic(SourceLocation Loc) const
Return the file characteristic of the specified source location, indicating whether this is a normal ...
std::optional< llvm::MemoryBufferRef > getBufferOrNone(FileID FID, SourceLocation Loc=SourceLocation()) const
Return the buffer for the specified FileID.
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 ...
Top level wrappers for InstallAPI frontend operations.
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.