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