comparison clang/lib/Frontend/Rewrite/InclusionRewriter.cpp @ 221:79ff65ed7e25

LLVM12 Original
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Tue, 15 Jun 2021 19:15:29 +0900
parents 1d019706d866
children c4bab56944e8
comparison
equal deleted inserted replaced
220:42394fc6a535 221:79ff65ed7e25
38 }; 38 };
39 Preprocessor &PP; ///< Used to find inclusion directives. 39 Preprocessor &PP; ///< Used to find inclusion directives.
40 SourceManager &SM; ///< Used to read and manage source files. 40 SourceManager &SM; ///< Used to read and manage source files.
41 raw_ostream &OS; ///< The destination stream for rewritten contents. 41 raw_ostream &OS; ///< The destination stream for rewritten contents.
42 StringRef MainEOL; ///< The line ending marker to use. 42 StringRef MainEOL; ///< The line ending marker to use.
43 const llvm::MemoryBuffer *PredefinesBuffer; ///< The preprocessor predefines. 43 llvm::MemoryBufferRef PredefinesBuffer; ///< The preprocessor predefines.
44 bool ShowLineMarkers; ///< Show #line markers. 44 bool ShowLineMarkers; ///< Show #line markers.
45 bool UseLineDirectives; ///< Use of line directives or line markers. 45 bool UseLineDirectives; ///< Use of line directives or line markers.
46 /// Tracks where inclusions that change the file are found. 46 /// Tracks where inclusions that change the file are found.
47 std::map<unsigned, IncludedFile> FileIncludes; 47 std::map<SourceLocation, IncludedFile> FileIncludes;
48 /// Tracks where inclusions that import modules are found. 48 /// Tracks where inclusions that import modules are found.
49 std::map<unsigned, const Module *> ModuleIncludes; 49 std::map<SourceLocation, const Module *> ModuleIncludes;
50 /// Tracks where inclusions that enter modules (in a module build) are found. 50 /// Tracks where inclusions that enter modules (in a module build) are found.
51 std::map<unsigned, const Module *> ModuleEntryIncludes; 51 std::map<SourceLocation, const Module *> ModuleEntryIncludes;
52 /// Tracks where #if and #elif directives get evaluated and whether to true. 52 /// Tracks where #if and #elif directives get evaluated and whether to true.
53 std::map<unsigned, bool> IfConditions; 53 std::map<SourceLocation, bool> IfConditions;
54 /// Used transitively for building up the FileIncludes mapping over the 54 /// Used transitively for building up the FileIncludes mapping over the
55 /// various \c PPCallbacks callbacks. 55 /// various \c PPCallbacks callbacks.
56 SourceLocation LastInclusionLocation; 56 SourceLocation LastInclusionLocation;
57 public: 57 public:
58 InclusionRewriter(Preprocessor &PP, raw_ostream &OS, bool ShowLineMarkers, 58 InclusionRewriter(Preprocessor &PP, raw_ostream &OS, bool ShowLineMarkers,
59 bool UseLineDirectives); 59 bool UseLineDirectives);
60 void Process(FileID FileId, SrcMgr::CharacteristicKind FileType, 60 void Process(FileID FileId, SrcMgr::CharacteristicKind FileType,
61 const DirectoryLookup *DirLookup); 61 const DirectoryLookup *DirLookup);
62 void setPredefinesBuffer(const llvm::MemoryBuffer *Buf) { 62 void setPredefinesBuffer(const llvm::MemoryBufferRef &Buf) {
63 PredefinesBuffer = Buf; 63 PredefinesBuffer = Buf;
64 } 64 }
65 void detectMainFileEOL(); 65 void detectMainFileEOL();
66 void handleModuleBegin(Token &Tok) { 66 void handleModuleBegin(Token &Tok) {
67 assert(Tok.getKind() == tok::annot_module_begin); 67 assert(Tok.getKind() == tok::annot_module_begin);
68 ModuleEntryIncludes.insert({Tok.getLocation().getRawEncoding(), 68 ModuleEntryIncludes.insert(
69 (Module *)Tok.getAnnotationValue()}); 69 {Tok.getLocation(), (Module *)Tok.getAnnotationValue()});
70 } 70 }
71 private: 71 private:
72 void FileChanged(SourceLocation Loc, FileChangeReason Reason, 72 void FileChanged(SourceLocation Loc, FileChangeReason Reason,
73 SrcMgr::CharacteristicKind FileType, 73 SrcMgr::CharacteristicKind FileType,
74 FileID PrevFID) override; 74 FileID PrevFID) override;
86 ConditionValueKind ConditionValue, SourceLocation IfLoc) override; 86 ConditionValueKind ConditionValue, SourceLocation IfLoc) override;
87 void WriteLineInfo(StringRef Filename, int Line, 87 void WriteLineInfo(StringRef Filename, int Line,
88 SrcMgr::CharacteristicKind FileType, 88 SrcMgr::CharacteristicKind FileType,
89 StringRef Extra = StringRef()); 89 StringRef Extra = StringRef());
90 void WriteImplicitModuleImport(const Module *Mod); 90 void WriteImplicitModuleImport(const Module *Mod);
91 void OutputContentUpTo(const MemoryBuffer &FromFile, 91 void OutputContentUpTo(const MemoryBufferRef &FromFile, unsigned &WriteFrom,
92 unsigned &WriteFrom, unsigned WriteTo, 92 unsigned WriteTo, StringRef EOL, int &lines,
93 StringRef EOL, int &lines,
94 bool EnsureNewline); 93 bool EnsureNewline);
95 void CommentOutDirective(Lexer &DirectivesLex, const Token &StartToken, 94 void CommentOutDirective(Lexer &DirectivesLex, const Token &StartToken,
96 const MemoryBuffer &FromFile, StringRef EOL, 95 const MemoryBufferRef &FromFile, StringRef EOL,
97 unsigned &NextToWrite, int &Lines); 96 unsigned &NextToWrite, int &Lines);
98 const IncludedFile *FindIncludeAtLocation(SourceLocation Loc) const; 97 const IncludedFile *FindIncludeAtLocation(SourceLocation Loc) const;
99 const Module *FindModuleAtLocation(SourceLocation Loc) const; 98 const Module *FindModuleAtLocation(SourceLocation Loc) const;
100 const Module *FindEnteredModule(SourceLocation Loc) const; 99 const Module *FindEnteredModule(SourceLocation Loc) const;
101 bool IsIfAtLocationTrue(SourceLocation Loc) const; 100 bool IsIfAtLocationTrue(SourceLocation Loc) const;
107 /// Initializes an InclusionRewriter with a \p PP source and \p OS destination. 106 /// Initializes an InclusionRewriter with a \p PP source and \p OS destination.
108 InclusionRewriter::InclusionRewriter(Preprocessor &PP, raw_ostream &OS, 107 InclusionRewriter::InclusionRewriter(Preprocessor &PP, raw_ostream &OS,
109 bool ShowLineMarkers, 108 bool ShowLineMarkers,
110 bool UseLineDirectives) 109 bool UseLineDirectives)
111 : PP(PP), SM(PP.getSourceManager()), OS(OS), MainEOL("\n"), 110 : PP(PP), SM(PP.getSourceManager()), OS(OS), MainEOL("\n"),
112 PredefinesBuffer(nullptr), ShowLineMarkers(ShowLineMarkers), 111 ShowLineMarkers(ShowLineMarkers), UseLineDirectives(UseLineDirectives),
113 UseLineDirectives(UseLineDirectives),
114 LastInclusionLocation(SourceLocation()) {} 112 LastInclusionLocation(SourceLocation()) {}
115 113
116 /// Write appropriate line information as either #line directives or GNU line 114 /// Write appropriate line information as either #line directives or GNU line
117 /// markers depending on what mode we're in, including the \p Filename and 115 /// markers depending on what mode we're in, including the \p Filename and
118 /// \p Line we are located at, using the specified \p EOL line separator, and 116 /// \p Line we are located at, using the specified \p EOL line separator, and
162 if (LastInclusionLocation.isInvalid()) 160 if (LastInclusionLocation.isInvalid())
163 // we didn't reach this file (eg: the main file) via an inclusion directive 161 // we didn't reach this file (eg: the main file) via an inclusion directive
164 return; 162 return;
165 FileID Id = FullSourceLoc(Loc, SM).getFileID(); 163 FileID Id = FullSourceLoc(Loc, SM).getFileID();
166 auto P = FileIncludes.insert( 164 auto P = FileIncludes.insert(
167 std::make_pair(LastInclusionLocation.getRawEncoding(), 165 std::make_pair(LastInclusionLocation,
168 IncludedFile(Id, NewFileType, PP.GetCurDirLookup()))); 166 IncludedFile(Id, NewFileType, PP.GetCurDirLookup())));
169 (void)P; 167 (void)P;
170 assert(P.second && "Unexpected revisitation of the same include directive"); 168 assert(P.second && "Unexpected revisitation of the same include directive");
171 LastInclusionLocation = SourceLocation(); 169 LastInclusionLocation = SourceLocation();
172 } 170 }
197 StringRef /*SearchPath*/, 195 StringRef /*SearchPath*/,
198 StringRef /*RelativePath*/, 196 StringRef /*RelativePath*/,
199 const Module *Imported, 197 const Module *Imported,
200 SrcMgr::CharacteristicKind FileType){ 198 SrcMgr::CharacteristicKind FileType){
201 if (Imported) { 199 if (Imported) {
202 auto P = ModuleIncludes.insert( 200 auto P = ModuleIncludes.insert(std::make_pair(HashLoc, Imported));
203 std::make_pair(HashLoc.getRawEncoding(), Imported));
204 (void)P; 201 (void)P;
205 assert(P.second && "Unexpected revisitation of the same include directive"); 202 assert(P.second && "Unexpected revisitation of the same include directive");
206 } else 203 } else
207 LastInclusionLocation = HashLoc; 204 LastInclusionLocation = HashLoc;
208 } 205 }
209 206
210 void InclusionRewriter::If(SourceLocation Loc, SourceRange ConditionRange, 207 void InclusionRewriter::If(SourceLocation Loc, SourceRange ConditionRange,
211 ConditionValueKind ConditionValue) { 208 ConditionValueKind ConditionValue) {
212 auto P = IfConditions.insert( 209 auto P = IfConditions.insert(std::make_pair(Loc, ConditionValue == CVK_True));
213 std::make_pair(Loc.getRawEncoding(), ConditionValue == CVK_True));
214 (void)P; 210 (void)P;
215 assert(P.second && "Unexpected revisitation of the same if directive"); 211 assert(P.second && "Unexpected revisitation of the same if directive");
216 } 212 }
217 213
218 void InclusionRewriter::Elif(SourceLocation Loc, SourceRange ConditionRange, 214 void InclusionRewriter::Elif(SourceLocation Loc, SourceRange ConditionRange,
219 ConditionValueKind ConditionValue, 215 ConditionValueKind ConditionValue,
220 SourceLocation IfLoc) { 216 SourceLocation IfLoc) {
221 auto P = IfConditions.insert( 217 auto P = IfConditions.insert(std::make_pair(Loc, ConditionValue == CVK_True));
222 std::make_pair(Loc.getRawEncoding(), ConditionValue == CVK_True));
223 (void)P; 218 (void)P;
224 assert(P.second && "Unexpected revisitation of the same elif directive"); 219 assert(P.second && "Unexpected revisitation of the same elif directive");
225 } 220 }
226 221
227 /// Simple lookup for a SourceLocation (specifically one denoting the hash in 222 /// Simple lookup for a SourceLocation (specifically one denoting the hash in
228 /// an inclusion directive) in the map of inclusion information, FileChanges. 223 /// an inclusion directive) in the map of inclusion information, FileChanges.
229 const InclusionRewriter::IncludedFile * 224 const InclusionRewriter::IncludedFile *
230 InclusionRewriter::FindIncludeAtLocation(SourceLocation Loc) const { 225 InclusionRewriter::FindIncludeAtLocation(SourceLocation Loc) const {
231 const auto I = FileIncludes.find(Loc.getRawEncoding()); 226 const auto I = FileIncludes.find(Loc);
232 if (I != FileIncludes.end()) 227 if (I != FileIncludes.end())
233 return &I->second; 228 return &I->second;
234 return nullptr; 229 return nullptr;
235 } 230 }
236 231
237 /// Simple lookup for a SourceLocation (specifically one denoting the hash in 232 /// Simple lookup for a SourceLocation (specifically one denoting the hash in
238 /// an inclusion directive) in the map of module inclusion information. 233 /// an inclusion directive) in the map of module inclusion information.
239 const Module * 234 const Module *
240 InclusionRewriter::FindModuleAtLocation(SourceLocation Loc) const { 235 InclusionRewriter::FindModuleAtLocation(SourceLocation Loc) const {
241 const auto I = ModuleIncludes.find(Loc.getRawEncoding()); 236 const auto I = ModuleIncludes.find(Loc);
242 if (I != ModuleIncludes.end()) 237 if (I != ModuleIncludes.end())
243 return I->second; 238 return I->second;
244 return nullptr; 239 return nullptr;
245 } 240 }
246 241
247 /// Simple lookup for a SourceLocation (specifically one denoting the hash in 242 /// Simple lookup for a SourceLocation (specifically one denoting the hash in
248 /// an inclusion directive) in the map of module entry information. 243 /// an inclusion directive) in the map of module entry information.
249 const Module * 244 const Module *
250 InclusionRewriter::FindEnteredModule(SourceLocation Loc) const { 245 InclusionRewriter::FindEnteredModule(SourceLocation Loc) const {
251 const auto I = ModuleEntryIncludes.find(Loc.getRawEncoding()); 246 const auto I = ModuleEntryIncludes.find(Loc);
252 if (I != ModuleEntryIncludes.end()) 247 if (I != ModuleEntryIncludes.end())
253 return I->second; 248 return I->second;
254 return nullptr; 249 return nullptr;
255 } 250 }
256 251
257 bool InclusionRewriter::IsIfAtLocationTrue(SourceLocation Loc) const { 252 bool InclusionRewriter::IsIfAtLocationTrue(SourceLocation Loc) const {
258 const auto I = IfConditions.find(Loc.getRawEncoding()); 253 const auto I = IfConditions.find(Loc);
259 if (I != IfConditions.end()) 254 if (I != IfConditions.end())
260 return I->second; 255 return I->second;
261 return false; 256 return false;
262 } 257 }
263 258
264 /// Detect the likely line ending style of \p FromFile by examining the first 259 /// Detect the likely line ending style of \p FromFile by examining the first
265 /// newline found within it. 260 /// newline found within it.
266 static StringRef DetectEOL(const MemoryBuffer &FromFile) { 261 static StringRef DetectEOL(const MemoryBufferRef &FromFile) {
267 // Detect what line endings the file uses, so that added content does not mix 262 // Detect what line endings the file uses, so that added content does not mix
268 // the style. We need to check for "\r\n" first because "\n\r" will match 263 // the style. We need to check for "\r\n" first because "\n\r" will match
269 // "\r\n\r\n". 264 // "\r\n\r\n".
270 const char *Pos = strchr(FromFile.getBufferStart(), '\n'); 265 const char *Pos = strchr(FromFile.getBufferStart(), '\n');
271 if (!Pos) 266 if (!Pos)
276 return "\n\r"; 271 return "\n\r";
277 return "\n"; 272 return "\n";
278 } 273 }
279 274
280 void InclusionRewriter::detectMainFileEOL() { 275 void InclusionRewriter::detectMainFileEOL() {
281 bool Invalid; 276 Optional<MemoryBufferRef> FromFile = *SM.getBufferOrNone(SM.getMainFileID());
282 const MemoryBuffer &FromFile = *SM.getBuffer(SM.getMainFileID(), &Invalid); 277 assert(FromFile);
283 assert(!Invalid); 278 if (!FromFile)
284 if (Invalid)
285 return; // Should never happen, but whatever. 279 return; // Should never happen, but whatever.
286 MainEOL = DetectEOL(FromFile); 280 MainEOL = DetectEOL(*FromFile);
287 } 281 }
288 282
289 /// Writes out bytes from \p FromFile, starting at \p NextToWrite and ending at 283 /// Writes out bytes from \p FromFile, starting at \p NextToWrite and ending at
290 /// \p WriteTo - 1. 284 /// \p WriteTo - 1.
291 void InclusionRewriter::OutputContentUpTo(const MemoryBuffer &FromFile, 285 void InclusionRewriter::OutputContentUpTo(const MemoryBufferRef &FromFile,
292 unsigned &WriteFrom, unsigned WriteTo, 286 unsigned &WriteFrom, unsigned WriteTo,
293 StringRef LocalEOL, int &Line, 287 StringRef LocalEOL, int &Line,
294 bool EnsureNewline) { 288 bool EnsureNewline) {
295 if (WriteTo <= WriteFrom) 289 if (WriteTo <= WriteFrom)
296 return; 290 return;
297 if (&FromFile == PredefinesBuffer) { 291 if (FromFile == PredefinesBuffer) {
298 // Ignore the #defines of the predefines buffer. 292 // Ignore the #defines of the predefines buffer.
299 WriteFrom = WriteTo; 293 WriteFrom = WriteTo;
300 return; 294 return;
301 } 295 }
302 296
339 /// inclusion directive disabled by a #if directive, updating \p NextToWrite 333 /// inclusion directive disabled by a #if directive, updating \p NextToWrite
340 /// and \p Line to track the number of source lines visited and the progress 334 /// and \p Line to track the number of source lines visited and the progress
341 /// through the \p FromFile buffer. 335 /// through the \p FromFile buffer.
342 void InclusionRewriter::CommentOutDirective(Lexer &DirectiveLex, 336 void InclusionRewriter::CommentOutDirective(Lexer &DirectiveLex,
343 const Token &StartToken, 337 const Token &StartToken,
344 const MemoryBuffer &FromFile, 338 const MemoryBufferRef &FromFile,
345 StringRef LocalEOL, 339 StringRef LocalEOL,
346 unsigned &NextToWrite, int &Line) { 340 unsigned &NextToWrite, int &Line) {
347 OutputContentUpTo(FromFile, NextToWrite, 341 OutputContentUpTo(FromFile, NextToWrite,
348 SM.getFileOffset(StartToken.getLocation()), LocalEOL, Line, 342 SM.getFileOffset(StartToken.getLocation()), LocalEOL, Line,
349 false); 343 false);
350 Token DirectiveToken; 344 Token DirectiveToken;
351 do { 345 do {
352 DirectiveLex.LexFromRawLexer(DirectiveToken); 346 DirectiveLex.LexFromRawLexer(DirectiveToken);
353 } while (!DirectiveToken.is(tok::eod) && DirectiveToken.isNot(tok::eof)); 347 } while (!DirectiveToken.is(tok::eod) && DirectiveToken.isNot(tok::eof));
354 if (&FromFile == PredefinesBuffer) { 348 if (FromFile == PredefinesBuffer) {
355 // OutputContentUpTo() would not output anything anyway. 349 // OutputContentUpTo() would not output anything anyway.
356 return; 350 return;
357 } 351 }
358 OS << "#if 0 /* expanded by -frewrite-includes */" << MainEOL; 352 OS << "#if 0 /* expanded by -frewrite-includes */" << MainEOL;
359 OutputContentUpTo(FromFile, NextToWrite, 353 OutputContentUpTo(FromFile, NextToWrite,
377 /// Use a raw lexer to analyze \p FileId, incrementally copying parts of it 371 /// Use a raw lexer to analyze \p FileId, incrementally copying parts of it
378 /// and including content of included files recursively. 372 /// and including content of included files recursively.
379 void InclusionRewriter::Process(FileID FileId, 373 void InclusionRewriter::Process(FileID FileId,
380 SrcMgr::CharacteristicKind FileType, 374 SrcMgr::CharacteristicKind FileType,
381 const DirectoryLookup *DirLookup) { 375 const DirectoryLookup *DirLookup) {
382 bool Invalid; 376 MemoryBufferRef FromFile;
383 const MemoryBuffer &FromFile = *SM.getBuffer(FileId, &Invalid); 377 {
384 assert(!Invalid && "Attempting to process invalid inclusion"); 378 auto B = SM.getBufferOrNone(FileId);
379 assert(B && "Attempting to process invalid inclusion");
380 if (B)
381 FromFile = *B;
382 }
385 StringRef FileName = FromFile.getBufferIdentifier(); 383 StringRef FileName = FromFile.getBufferIdentifier();
386 Lexer RawLex(FileId, &FromFile, PP.getSourceManager(), PP.getLangOpts()); 384 Lexer RawLex(FileId, FromFile, PP.getSourceManager(), PP.getLangOpts());
387 RawLex.SetCommentRetentionState(false); 385 RawLex.SetCommentRetentionState(false);
388 386
389 StringRef LocalEOL = DetectEOL(FromFile); 387 StringRef LocalEOL = DetectEOL(FromFile);
390 388
391 // Per the GNU docs: "1" indicates entering a new file. 389 // Per the GNU docs: "1" indicates entering a new file.
558 do { 556 do {
559 PP.Lex(Tok); 557 PP.Lex(Tok);
560 if (Tok.is(tok::annot_module_begin)) 558 if (Tok.is(tok::annot_module_begin))
561 Rewrite->handleModuleBegin(Tok); 559 Rewrite->handleModuleBegin(Tok);
562 } while (Tok.isNot(tok::eof)); 560 } while (Tok.isNot(tok::eof));
563 Rewrite->setPredefinesBuffer(SM.getBuffer(PP.getPredefinesFileID())); 561 Rewrite->setPredefinesBuffer(SM.getBufferOrFake(PP.getPredefinesFileID()));
564 Rewrite->Process(PP.getPredefinesFileID(), SrcMgr::C_User, nullptr); 562 Rewrite->Process(PP.getPredefinesFileID(), SrcMgr::C_User, nullptr);
565 Rewrite->Process(SM.getMainFileID(), SrcMgr::C_User, nullptr); 563 Rewrite->Process(SM.getMainFileID(), SrcMgr::C_User, nullptr);
566 OS->flush(); 564 OS->flush();
567 } 565 }