xref: /aosp_15_r20/external/clang/lib/ARCMigrate/FileRemapper.cpp (revision 67e74705e28f6214e480b399dd47ea732279e315)
1*67e74705SXin Li //===--- FileRemapper.cpp - File Remapping Helper -------------------------===//
2*67e74705SXin Li //
3*67e74705SXin Li //                     The LLVM Compiler Infrastructure
4*67e74705SXin Li //
5*67e74705SXin Li // This file is distributed under the University of Illinois Open Source
6*67e74705SXin Li // License. See LICENSE.TXT for details.
7*67e74705SXin Li //
8*67e74705SXin Li //===----------------------------------------------------------------------===//
9*67e74705SXin Li 
10*67e74705SXin Li #include "clang/ARCMigrate/FileRemapper.h"
11*67e74705SXin Li #include "clang/Basic/Diagnostic.h"
12*67e74705SXin Li #include "clang/Basic/FileManager.h"
13*67e74705SXin Li #include "clang/Lex/PreprocessorOptions.h"
14*67e74705SXin Li #include "llvm/Support/FileSystem.h"
15*67e74705SXin Li #include "llvm/Support/MemoryBuffer.h"
16*67e74705SXin Li #include "llvm/Support/Path.h"
17*67e74705SXin Li #include "llvm/Support/raw_ostream.h"
18*67e74705SXin Li #include <fstream>
19*67e74705SXin Li 
20*67e74705SXin Li using namespace clang;
21*67e74705SXin Li using namespace arcmt;
22*67e74705SXin Li 
FileRemapper()23*67e74705SXin Li FileRemapper::FileRemapper() {
24*67e74705SXin Li   FileMgr.reset(new FileManager(FileSystemOptions()));
25*67e74705SXin Li }
26*67e74705SXin Li 
~FileRemapper()27*67e74705SXin Li FileRemapper::~FileRemapper() {
28*67e74705SXin Li   clear();
29*67e74705SXin Li }
30*67e74705SXin Li 
clear(StringRef outputDir)31*67e74705SXin Li void FileRemapper::clear(StringRef outputDir) {
32*67e74705SXin Li   for (MappingsTy::iterator
33*67e74705SXin Li          I = FromToMappings.begin(), E = FromToMappings.end(); I != E; ++I)
34*67e74705SXin Li     resetTarget(I->second);
35*67e74705SXin Li   FromToMappings.clear();
36*67e74705SXin Li   assert(ToFromMappings.empty());
37*67e74705SXin Li   if (!outputDir.empty()) {
38*67e74705SXin Li     std::string infoFile = getRemapInfoFile(outputDir);
39*67e74705SXin Li     llvm::sys::fs::remove(infoFile);
40*67e74705SXin Li   }
41*67e74705SXin Li }
42*67e74705SXin Li 
getRemapInfoFile(StringRef outputDir)43*67e74705SXin Li std::string FileRemapper::getRemapInfoFile(StringRef outputDir) {
44*67e74705SXin Li   assert(!outputDir.empty());
45*67e74705SXin Li   SmallString<128> InfoFile = outputDir;
46*67e74705SXin Li   llvm::sys::path::append(InfoFile, "remap");
47*67e74705SXin Li   return InfoFile.str();
48*67e74705SXin Li }
49*67e74705SXin Li 
initFromDisk(StringRef outputDir,DiagnosticsEngine & Diag,bool ignoreIfFilesChanged)50*67e74705SXin Li bool FileRemapper::initFromDisk(StringRef outputDir, DiagnosticsEngine &Diag,
51*67e74705SXin Li                                 bool ignoreIfFilesChanged) {
52*67e74705SXin Li   std::string infoFile = getRemapInfoFile(outputDir);
53*67e74705SXin Li   return initFromFile(infoFile, Diag, ignoreIfFilesChanged);
54*67e74705SXin Li }
55*67e74705SXin Li 
initFromFile(StringRef filePath,DiagnosticsEngine & Diag,bool ignoreIfFilesChanged)56*67e74705SXin Li bool FileRemapper::initFromFile(StringRef filePath, DiagnosticsEngine &Diag,
57*67e74705SXin Li                                 bool ignoreIfFilesChanged) {
58*67e74705SXin Li   assert(FromToMappings.empty() &&
59*67e74705SXin Li          "initFromDisk should be called before any remap calls");
60*67e74705SXin Li   std::string infoFile = filePath;
61*67e74705SXin Li   if (!llvm::sys::fs::exists(infoFile))
62*67e74705SXin Li     return false;
63*67e74705SXin Li 
64*67e74705SXin Li   std::vector<std::pair<const FileEntry *, const FileEntry *> > pairs;
65*67e74705SXin Li 
66*67e74705SXin Li   llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> fileBuf =
67*67e74705SXin Li       llvm::MemoryBuffer::getFile(infoFile.c_str());
68*67e74705SXin Li   if (!fileBuf)
69*67e74705SXin Li     return report("Error opening file: " + infoFile, Diag);
70*67e74705SXin Li 
71*67e74705SXin Li   SmallVector<StringRef, 64> lines;
72*67e74705SXin Li   fileBuf.get()->getBuffer().split(lines, "\n");
73*67e74705SXin Li 
74*67e74705SXin Li   for (unsigned idx = 0; idx+3 <= lines.size(); idx += 3) {
75*67e74705SXin Li     StringRef fromFilename = lines[idx];
76*67e74705SXin Li     unsigned long long timeModified;
77*67e74705SXin Li     if (lines[idx+1].getAsInteger(10, timeModified))
78*67e74705SXin Li       return report("Invalid file data: '" + lines[idx+1] + "' not a number",
79*67e74705SXin Li                     Diag);
80*67e74705SXin Li     StringRef toFilename = lines[idx+2];
81*67e74705SXin Li 
82*67e74705SXin Li     const FileEntry *origFE = FileMgr->getFile(fromFilename);
83*67e74705SXin Li     if (!origFE) {
84*67e74705SXin Li       if (ignoreIfFilesChanged)
85*67e74705SXin Li         continue;
86*67e74705SXin Li       return report("File does not exist: " + fromFilename, Diag);
87*67e74705SXin Li     }
88*67e74705SXin Li     const FileEntry *newFE = FileMgr->getFile(toFilename);
89*67e74705SXin Li     if (!newFE) {
90*67e74705SXin Li       if (ignoreIfFilesChanged)
91*67e74705SXin Li         continue;
92*67e74705SXin Li       return report("File does not exist: " + toFilename, Diag);
93*67e74705SXin Li     }
94*67e74705SXin Li 
95*67e74705SXin Li     if ((uint64_t)origFE->getModificationTime() != timeModified) {
96*67e74705SXin Li       if (ignoreIfFilesChanged)
97*67e74705SXin Li         continue;
98*67e74705SXin Li       return report("File was modified: " + fromFilename, Diag);
99*67e74705SXin Li     }
100*67e74705SXin Li 
101*67e74705SXin Li     pairs.push_back(std::make_pair(origFE, newFE));
102*67e74705SXin Li   }
103*67e74705SXin Li 
104*67e74705SXin Li   for (unsigned i = 0, e = pairs.size(); i != e; ++i)
105*67e74705SXin Li     remap(pairs[i].first, pairs[i].second);
106*67e74705SXin Li 
107*67e74705SXin Li   return false;
108*67e74705SXin Li }
109*67e74705SXin Li 
flushToDisk(StringRef outputDir,DiagnosticsEngine & Diag)110*67e74705SXin Li bool FileRemapper::flushToDisk(StringRef outputDir, DiagnosticsEngine &Diag) {
111*67e74705SXin Li   using namespace llvm::sys;
112*67e74705SXin Li 
113*67e74705SXin Li   if (fs::create_directory(outputDir))
114*67e74705SXin Li     return report("Could not create directory: " + outputDir, Diag);
115*67e74705SXin Li 
116*67e74705SXin Li   std::string infoFile = getRemapInfoFile(outputDir);
117*67e74705SXin Li   return flushToFile(infoFile, Diag);
118*67e74705SXin Li }
119*67e74705SXin Li 
flushToFile(StringRef outputPath,DiagnosticsEngine & Diag)120*67e74705SXin Li bool FileRemapper::flushToFile(StringRef outputPath, DiagnosticsEngine &Diag) {
121*67e74705SXin Li   using namespace llvm::sys;
122*67e74705SXin Li 
123*67e74705SXin Li   std::error_code EC;
124*67e74705SXin Li   std::string infoFile = outputPath;
125*67e74705SXin Li   llvm::raw_fd_ostream infoOut(infoFile, EC, llvm::sys::fs::F_None);
126*67e74705SXin Li   if (EC)
127*67e74705SXin Li     return report(EC.message(), Diag);
128*67e74705SXin Li 
129*67e74705SXin Li   for (MappingsTy::iterator
130*67e74705SXin Li          I = FromToMappings.begin(), E = FromToMappings.end(); I != E; ++I) {
131*67e74705SXin Li 
132*67e74705SXin Li     const FileEntry *origFE = I->first;
133*67e74705SXin Li     SmallString<200> origPath = StringRef(origFE->getName());
134*67e74705SXin Li     fs::make_absolute(origPath);
135*67e74705SXin Li     infoOut << origPath << '\n';
136*67e74705SXin Li     infoOut << (uint64_t)origFE->getModificationTime() << '\n';
137*67e74705SXin Li 
138*67e74705SXin Li     if (const FileEntry *FE = I->second.dyn_cast<const FileEntry *>()) {
139*67e74705SXin Li       SmallString<200> newPath = StringRef(FE->getName());
140*67e74705SXin Li       fs::make_absolute(newPath);
141*67e74705SXin Li       infoOut << newPath << '\n';
142*67e74705SXin Li     } else {
143*67e74705SXin Li 
144*67e74705SXin Li       SmallString<64> tempPath;
145*67e74705SXin Li       int fd;
146*67e74705SXin Li       if (fs::createTemporaryFile(path::filename(origFE->getName()),
147*67e74705SXin Li                                   path::extension(origFE->getName()).drop_front(), fd,
148*67e74705SXin Li                                   tempPath))
149*67e74705SXin Li         return report("Could not create file: " + tempPath.str(), Diag);
150*67e74705SXin Li 
151*67e74705SXin Li       llvm::raw_fd_ostream newOut(fd, /*shouldClose=*/true);
152*67e74705SXin Li       llvm::MemoryBuffer *mem = I->second.get<llvm::MemoryBuffer *>();
153*67e74705SXin Li       newOut.write(mem->getBufferStart(), mem->getBufferSize());
154*67e74705SXin Li       newOut.close();
155*67e74705SXin Li 
156*67e74705SXin Li       const FileEntry *newE = FileMgr->getFile(tempPath);
157*67e74705SXin Li       remap(origFE, newE);
158*67e74705SXin Li       infoOut << newE->getName() << '\n';
159*67e74705SXin Li     }
160*67e74705SXin Li   }
161*67e74705SXin Li 
162*67e74705SXin Li   infoOut.close();
163*67e74705SXin Li   return false;
164*67e74705SXin Li }
165*67e74705SXin Li 
overwriteOriginal(DiagnosticsEngine & Diag,StringRef outputDir)166*67e74705SXin Li bool FileRemapper::overwriteOriginal(DiagnosticsEngine &Diag,
167*67e74705SXin Li                                      StringRef outputDir) {
168*67e74705SXin Li   using namespace llvm::sys;
169*67e74705SXin Li 
170*67e74705SXin Li   for (MappingsTy::iterator
171*67e74705SXin Li          I = FromToMappings.begin(), E = FromToMappings.end(); I != E; ++I) {
172*67e74705SXin Li     const FileEntry *origFE = I->first;
173*67e74705SXin Li     assert(I->second.is<llvm::MemoryBuffer *>());
174*67e74705SXin Li     if (!fs::exists(origFE->getName()))
175*67e74705SXin Li       return report(StringRef("File does not exist: ") + origFE->getName(),
176*67e74705SXin Li                     Diag);
177*67e74705SXin Li 
178*67e74705SXin Li     std::error_code EC;
179*67e74705SXin Li     llvm::raw_fd_ostream Out(origFE->getName(), EC, llvm::sys::fs::F_None);
180*67e74705SXin Li     if (EC)
181*67e74705SXin Li       return report(EC.message(), Diag);
182*67e74705SXin Li 
183*67e74705SXin Li     llvm::MemoryBuffer *mem = I->second.get<llvm::MemoryBuffer *>();
184*67e74705SXin Li     Out.write(mem->getBufferStart(), mem->getBufferSize());
185*67e74705SXin Li     Out.close();
186*67e74705SXin Li   }
187*67e74705SXin Li 
188*67e74705SXin Li   clear(outputDir);
189*67e74705SXin Li   return false;
190*67e74705SXin Li }
191*67e74705SXin Li 
applyMappings(PreprocessorOptions & PPOpts) const192*67e74705SXin Li void FileRemapper::applyMappings(PreprocessorOptions &PPOpts) const {
193*67e74705SXin Li   for (MappingsTy::const_iterator
194*67e74705SXin Li          I = FromToMappings.begin(), E = FromToMappings.end(); I != E; ++I) {
195*67e74705SXin Li     if (const FileEntry *FE = I->second.dyn_cast<const FileEntry *>()) {
196*67e74705SXin Li       PPOpts.addRemappedFile(I->first->getName(), FE->getName());
197*67e74705SXin Li     } else {
198*67e74705SXin Li       llvm::MemoryBuffer *mem = I->second.get<llvm::MemoryBuffer *>();
199*67e74705SXin Li       PPOpts.addRemappedFile(I->first->getName(), mem);
200*67e74705SXin Li     }
201*67e74705SXin Li   }
202*67e74705SXin Li 
203*67e74705SXin Li   PPOpts.RetainRemappedFileBuffers = true;
204*67e74705SXin Li }
205*67e74705SXin Li 
remap(StringRef filePath,std::unique_ptr<llvm::MemoryBuffer> memBuf)206*67e74705SXin Li void FileRemapper::remap(StringRef filePath,
207*67e74705SXin Li                          std::unique_ptr<llvm::MemoryBuffer> memBuf) {
208*67e74705SXin Li   remap(getOriginalFile(filePath), std::move(memBuf));
209*67e74705SXin Li }
210*67e74705SXin Li 
remap(const FileEntry * file,std::unique_ptr<llvm::MemoryBuffer> memBuf)211*67e74705SXin Li void FileRemapper::remap(const FileEntry *file,
212*67e74705SXin Li                          std::unique_ptr<llvm::MemoryBuffer> memBuf) {
213*67e74705SXin Li   assert(file);
214*67e74705SXin Li   Target &targ = FromToMappings[file];
215*67e74705SXin Li   resetTarget(targ);
216*67e74705SXin Li   targ = memBuf.release();
217*67e74705SXin Li }
218*67e74705SXin Li 
remap(const FileEntry * file,const FileEntry * newfile)219*67e74705SXin Li void FileRemapper::remap(const FileEntry *file, const FileEntry *newfile) {
220*67e74705SXin Li   assert(file && newfile);
221*67e74705SXin Li   Target &targ = FromToMappings[file];
222*67e74705SXin Li   resetTarget(targ);
223*67e74705SXin Li   targ = newfile;
224*67e74705SXin Li   ToFromMappings[newfile] = file;
225*67e74705SXin Li }
226*67e74705SXin Li 
getOriginalFile(StringRef filePath)227*67e74705SXin Li const FileEntry *FileRemapper::getOriginalFile(StringRef filePath) {
228*67e74705SXin Li   const FileEntry *file = FileMgr->getFile(filePath);
229*67e74705SXin Li   // If we are updating a file that overriden an original file,
230*67e74705SXin Li   // actually update the original file.
231*67e74705SXin Li   llvm::DenseMap<const FileEntry *, const FileEntry *>::iterator
232*67e74705SXin Li     I = ToFromMappings.find(file);
233*67e74705SXin Li   if (I != ToFromMappings.end()) {
234*67e74705SXin Li     file = I->second;
235*67e74705SXin Li     assert(FromToMappings.find(file) != FromToMappings.end() &&
236*67e74705SXin Li            "Original file not in mappings!");
237*67e74705SXin Li   }
238*67e74705SXin Li   return file;
239*67e74705SXin Li }
240*67e74705SXin Li 
resetTarget(Target & targ)241*67e74705SXin Li void FileRemapper::resetTarget(Target &targ) {
242*67e74705SXin Li   if (!targ)
243*67e74705SXin Li     return;
244*67e74705SXin Li 
245*67e74705SXin Li   if (llvm::MemoryBuffer *oldmem = targ.dyn_cast<llvm::MemoryBuffer *>()) {
246*67e74705SXin Li     delete oldmem;
247*67e74705SXin Li   } else {
248*67e74705SXin Li     const FileEntry *toFE = targ.get<const FileEntry *>();
249*67e74705SXin Li     ToFromMappings.erase(toFE);
250*67e74705SXin Li   }
251*67e74705SXin Li }
252*67e74705SXin Li 
report(const Twine & err,DiagnosticsEngine & Diag)253*67e74705SXin Li bool FileRemapper::report(const Twine &err, DiagnosticsEngine &Diag) {
254*67e74705SXin Li   Diag.Report(Diag.getCustomDiagID(DiagnosticsEngine::Error, "%0"))
255*67e74705SXin Li       << err.str();
256*67e74705SXin Li   return true;
257*67e74705SXin Li }
258