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