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;
53 std::map<unsigned, bool> IfConditions;
58 InclusionRewriter(
Preprocessor &PP, raw_ostream &OS,
bool ShowLineMarkers,
59 bool UseLineDirectives);
62 void setPredefinesBuffer(
const llvm::MemoryBuffer *Buf) {
63 PredefinesBuffer = Buf;
65 void detectMainFileEOL();
67 assert(Tok.
getKind() == tok::annot_module_begin);
78 StringRef FileName,
bool IsAngled,
80 StringRef SearchPath, StringRef RelativePath,
84 ConditionValueKind ConditionValue)
override;
89 StringRef Extra = StringRef());
90 void WriteImplicitModuleImport(
const Module *Mod);
91 void OutputContentUpTo(
const MemoryBuffer &FromFile,
92 unsigned &WriteFrom,
unsigned WriteTo,
93 StringRef EOL,
int &lines,
95 void CommentOutDirective(
Lexer &DirectivesLex,
const Token &StartToken,
96 const MemoryBuffer &FromFile, StringRef EOL,
97 unsigned &NextToWrite,
int &Lines);
98 const IncludedFile *FindIncludeAtLocation(
SourceLocation Loc)
const;
102 StringRef NextIdentifierName(
Lexer &RawLex,
Token &RawToken);
108 InclusionRewriter::InclusionRewriter(
Preprocessor &PP, raw_ostream &OS,
109 bool ShowLineMarkers,
110 bool UseLineDirectives)
111 : PP(PP), SM(PP.getSourceManager()), OS(OS), MainEOL(
"\n"),
112 PredefinesBuffer(nullptr), ShowLineMarkers(ShowLineMarkers),
113 UseLineDirectives(UseLineDirectives),
120 void InclusionRewriter::WriteLineInfo(StringRef
Filename,
int Line,
123 if (!ShowLineMarkers)
125 if (UseLineDirectives) {
126 OS <<
"#line" <<
' ' << Line <<
' ' <<
'"';
127 OS.write_escaped(Filename);
132 OS <<
'#' <<
' ' << Line <<
' ' <<
'"';
133 OS.write_escaped(Filename);
149 void InclusionRewriter::WriteImplicitModuleImport(
const Module *Mod) {
151 <<
" /* clang -frewrite-includes: implicit import */" << MainEOL;
157 FileChangeReason Reason,
160 if (Reason != EnterFile)
166 auto P = FileIncludes.insert(
170 assert(
P.second &&
"Unexpected revisitation of the same include directive");
176 void InclusionRewriter::FileSkipped(
const FileEntryRef & ,
179 assert(LastInclusionLocation.
isValid() &&
180 "A file, that wasn't found via an inclusion directive, was skipped");
191 void InclusionRewriter::InclusionDirective(
SourceLocation HashLoc,
202 auto P = ModuleIncludes.insert(
205 assert(
P.second &&
"Unexpected revisitation of the same include directive");
207 LastInclusionLocation = HashLoc;
211 ConditionValueKind ConditionValue) {
212 auto P = IfConditions.insert(
213 std::make_pair(Loc.
getRawEncoding(), ConditionValue == CVK_True));
215 assert(
P.second &&
"Unexpected revisitation of the same if directive");
219 ConditionValueKind ConditionValue,
221 auto P = IfConditions.insert(
222 std::make_pair(Loc.
getRawEncoding(), ConditionValue == CVK_True));
224 assert(
P.second &&
"Unexpected revisitation of the same elif directive");
229 const InclusionRewriter::IncludedFile *
230 InclusionRewriter::FindIncludeAtLocation(
SourceLocation Loc)
const {
232 if (I != FileIncludes.end())
240 InclusionRewriter::FindModuleAtLocation(
SourceLocation Loc)
const {
242 if (I != ModuleIncludes.end())
252 if (I != ModuleEntryIncludes.end())
257 bool InclusionRewriter::IsIfAtLocationTrue(
SourceLocation Loc)
const {
259 if (I != IfConditions.end())
266 static StringRef
DetectEOL(
const MemoryBuffer &FromFile) {
270 const char *Pos = strchr(FromFile.getBufferStart(),
'\n');
273 if (Pos - 1 >= FromFile.getBufferStart() && Pos[-1] ==
'\r')
275 if (Pos + 1 < FromFile.getBufferEnd() && Pos[1] ==
'\r')
280 void InclusionRewriter::detectMainFileEOL() {
291 void InclusionRewriter::OutputContentUpTo(
const MemoryBuffer &FromFile,
292 unsigned &WriteFrom,
unsigned WriteTo,
293 StringRef LocalEOL,
int &Line,
294 bool EnsureNewline) {
295 if (WriteTo <= WriteFrom)
297 if (&FromFile == PredefinesBuffer) {
306 if (LocalEOL.size() == 2 &&
307 LocalEOL[0] == (FromFile.getBufferStart() + WriteTo)[-1] &&
308 LocalEOL[1] == (FromFile.getBufferStart() + WriteTo)[0])
311 StringRef TextToWrite(FromFile.getBufferStart() + WriteFrom,
312 WriteTo - WriteFrom);
314 if (MainEOL == LocalEOL) {
317 Line += TextToWrite.count(LocalEOL);
318 if (EnsureNewline && !TextToWrite.endswith(LocalEOL))
322 StringRef Rest = TextToWrite;
323 while (!Rest.empty()) {
325 std::tie(LineText, Rest) = Rest.split(LocalEOL);
331 if (TextToWrite.endswith(LocalEOL) || EnsureNewline)
342 void InclusionRewriter::CommentOutDirective(
Lexer &DirectiveLex,
343 const Token &StartToken,
344 const MemoryBuffer &FromFile,
346 unsigned &NextToWrite,
int &Line) {
347 OutputContentUpTo(FromFile, NextToWrite,
350 Token DirectiveToken;
353 }
while (!DirectiveToken.
is(tok::eod) && DirectiveToken.
isNot(
tok::eof));
354 if (&FromFile == PredefinesBuffer) {
358 OS <<
"#if 0 /* expanded by -frewrite-includes */" << MainEOL;
359 OutputContentUpTo(FromFile, NextToWrite,
362 LocalEOL,
Line,
true);
363 OS <<
"#endif /* expanded by -frewrite-includes */" << MainEOL;
367 StringRef InclusionRewriter::NextIdentifierName(
Lexer &RawLex,
370 if (RawToken.
is(tok::raw_identifier))
372 if (RawToken.
is(tok::identifier))
379 void InclusionRewriter::Process(
FileID FileId,
383 const MemoryBuffer &FromFile = *SM.
getBuffer(FileId, &Invalid);
384 assert(!Invalid &&
"Attempting to process invalid inclusion");
385 StringRef FileName = FromFile.getBufferIdentifier();
389 StringRef LocalEOL =
DetectEOL(FromFile);
393 WriteLineInfo(FileName, 1, FileType,
"");
395 WriteLineInfo(FileName, 1, FileType,
" 1");
414 Token HashToken = RawToken;
416 if (RawToken.
is(tok::raw_identifier))
423 CommentOutDirective(RawLex, HashToken, FromFile, LocalEOL, NextToWrite,
426 WriteLineInfo(FileName, Line - 1, FileType,
"");
427 StringRef LineInfoExtra;
429 if (
const Module *Mod = FindModuleAtLocation(Loc))
430 WriteImplicitModuleImport(Mod);
431 else if (
const IncludedFile *Inc = FindIncludeAtLocation(Loc)) {
432 const Module *Mod = FindEnteredModule(Loc);
434 OS <<
"#pragma clang module begin " 438 Process(Inc->Id, Inc->FileType, Inc->DirLookup);
441 OS <<
"#pragma clang module end /*" 446 LineInfoExtra =
" 2";
450 WriteLineInfo(FileName, Line, FileType, LineInfoExtra);
453 case tok::pp_pragma: {
454 StringRef
Identifier = NextIdentifierName(RawLex, RawToken);
455 if (Identifier ==
"clang" || Identifier ==
"GCC") {
456 if (NextIdentifierName(RawLex, RawToken) ==
"system_header") {
458 CommentOutDirective(RawLex, HashToken, FromFile, LocalEOL,
462 WriteLineInfo(FileName, Line, FileType);
464 }
else if (Identifier ==
"once") {
466 CommentOutDirective(RawLex, HashToken, FromFile, LocalEOL,
468 WriteLineInfo(FileName, Line, FileType);
476 bool isTrue = IsIfAtLocationTrue(RawToken.
getLocation());
477 OutputContentUpTo(FromFile, NextToWrite,
479 LocalEOL, Line,
true);
489 OS <<
"#if 0 /* disabled by -frewrite-includes */" << MainEOL;
491 OS <<
"#if 0" << MainEOL;
493 OutputContentUpTo(FromFile, NextToWrite,
496 LocalEOL,
Line,
true);
498 OS <<
"#endif" << MainEOL;
499 OS <<
"#endif /* disabled by -frewrite-includes */" << MainEOL;
500 OS << (elif ?
"#elif " :
"#if ") << (isTrue ?
"1" :
"0")
501 <<
" /* evaluated by -frewrite-includes */" << MainEOL;
502 WriteLineInfo(FileName, Line, FileType);
516 OutputContentUpTo(FromFile, NextToWrite,
519 LocalEOL,
Line,
true);
520 WriteLineInfo(FileName, Line, FileType);
532 OutputContentUpTo(FromFile, NextToWrite,
541 InclusionRewriter *Rewrite =
new InclusionRewriter(
543 Rewrite->detectMainFileEOL();
560 if (Tok.
is(tok::annot_module_begin))
561 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.
A reference to a FileEntry that includes the name of the file as it was accessed by the FileManager's...
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
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.
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 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
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.
A trivial tuple used to represent a source range.
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.