/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/tools/clang/lib/Rewrite/Rewriter.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===--- Rewriter.cpp - Code rewriting interface --------------------------===// |
2 | | // |
3 | | // The LLVM Compiler Infrastructure |
4 | | // |
5 | | // This file is distributed under the University of Illinois Open Source |
6 | | // License. See LICENSE.TXT for details. |
7 | | // |
8 | | //===----------------------------------------------------------------------===// |
9 | | // |
10 | | // This file defines the Rewriter class, which is used for code |
11 | | // transformations. |
12 | | // |
13 | | //===----------------------------------------------------------------------===// |
14 | | |
15 | | #include "clang/Rewrite/Core/Rewriter.h" |
16 | | #include "clang/Basic/Diagnostic.h" |
17 | | #include "clang/Basic/DiagnosticIDs.h" |
18 | | #include "clang/Basic/SourceManager.h" |
19 | | #include "clang/Lex/Lexer.h" |
20 | | #include "llvm/ADT/SmallString.h" |
21 | | #include "llvm/Support/FileSystem.h" |
22 | | #include "llvm/Support/raw_ostream.h" |
23 | | using namespace clang; |
24 | | |
25 | 9.40k | raw_ostream &RewriteBuffer::write(raw_ostream &os) const { |
26 | 9.40k | // Walk RewriteRope chunks efficiently using MoveToNextPiece() instead of the |
27 | 9.40k | // character iterator. |
28 | 76.7k | for (RopePieceBTreeIterator I = begin(), E = end(); I != E; |
29 | 67.3k | I.MoveToNextPiece()) |
30 | 67.3k | os << I.piece(); |
31 | 9.40k | return os; |
32 | 9.40k | } |
33 | | |
34 | | /// \brief Return true if this character is non-new-line whitespace: |
35 | | /// ' ', '\\t', '\\f', '\\v', '\\r'. |
36 | 1.70k | static inline bool isWhitespaceExceptNL(unsigned char c) { |
37 | 1.70k | switch (c) { |
38 | 1.19k | case ' ': |
39 | 1.19k | case '\t': |
40 | 1.19k | case '\f': |
41 | 1.19k | case '\v': |
42 | 1.19k | case '\r': |
43 | 1.19k | return true; |
44 | 504 | default: |
45 | 504 | return false; |
46 | 0 | } |
47 | 0 | } |
48 | | |
49 | | void RewriteBuffer::RemoveText(unsigned OrigOffset, unsigned Size, |
50 | 403 | bool removeLineIfEmpty) { |
51 | 403 | // Nothing to remove, exit early. |
52 | 403 | if (Size == 0403 ) return0 ; |
53 | 403 | |
54 | 403 | unsigned RealOffset = getMappedOffset(OrigOffset, true); |
55 | 403 | assert(RealOffset+Size <= Buffer.size() && "Invalid location"); |
56 | 403 | |
57 | 403 | // Remove the dead characters. |
58 | 403 | Buffer.erase(RealOffset, Size); |
59 | 403 | |
60 | 403 | // Add a delta so that future changes are offset correctly. |
61 | 403 | AddReplaceDelta(OrigOffset, -Size); |
62 | 403 | |
63 | 403 | if (removeLineIfEmpty403 ) { |
64 | 402 | // Find the line that the remove occurred and if it is completely empty |
65 | 402 | // remove the line as well. |
66 | 402 | |
67 | 402 | iterator curLineStart = begin(); |
68 | 402 | unsigned curLineStartOffs = 0; |
69 | 402 | iterator posI = begin(); |
70 | 349k | for (unsigned i = 0; i != RealOffset349k ; ++i349k ) { |
71 | 349k | if (*posI == '\n'349k ) { |
72 | 16.6k | curLineStart = posI; |
73 | 16.6k | ++curLineStart; |
74 | 16.6k | curLineStartOffs = i + 1; |
75 | 16.6k | } |
76 | 349k | ++posI; |
77 | 349k | } |
78 | 402 | |
79 | 402 | unsigned lineSize = 0; |
80 | 402 | posI = curLineStart; |
81 | 1.31k | while (posI != end() && 1.31k isWhitespaceExceptNL(*posI)1.31k ) { |
82 | 910 | ++posI; |
83 | 910 | ++lineSize; |
84 | 910 | } |
85 | 402 | if (posI != end() && 402 *posI == '\n'402 ) { |
86 | 74 | Buffer.erase(curLineStartOffs, lineSize + 1/* + '\n'*/); |
87 | 74 | AddReplaceDelta(curLineStartOffs, -(lineSize + 1/* + '\n'*/)); |
88 | 74 | } |
89 | 402 | } |
90 | 403 | } |
91 | | |
92 | | void RewriteBuffer::InsertText(unsigned OrigOffset, StringRef Str, |
93 | 150k | bool InsertAfter) { |
94 | 150k | |
95 | 150k | // Nothing to insert, exit early. |
96 | 150k | if (Str.empty()150k ) return0 ; |
97 | 150k | |
98 | 150k | unsigned RealOffset = getMappedOffset(OrigOffset, InsertAfter); |
99 | 150k | Buffer.insert(RealOffset, Str.begin(), Str.end()); |
100 | 150k | |
101 | 150k | // Add a delta so that future changes are offset correctly. |
102 | 150k | AddInsertDelta(OrigOffset, Str.size()); |
103 | 150k | } |
104 | | |
105 | | /// ReplaceText - This method replaces a range of characters in the input |
106 | | /// buffer with a new string. This is effectively a combined "remove+insert" |
107 | | /// operation. |
108 | | void RewriteBuffer::ReplaceText(unsigned OrigOffset, unsigned OrigLength, |
109 | 190k | StringRef NewStr) { |
110 | 190k | unsigned RealOffset = getMappedOffset(OrigOffset, true); |
111 | 190k | Buffer.erase(RealOffset, OrigLength); |
112 | 190k | Buffer.insert(RealOffset, NewStr.begin(), NewStr.end()); |
113 | 190k | if (OrigLength != NewStr.size()) |
114 | 183k | AddReplaceDelta(OrigOffset, NewStr.size() - OrigLength); |
115 | 190k | } |
116 | | |
117 | | |
118 | | //===----------------------------------------------------------------------===// |
119 | | // Rewriter class |
120 | | //===----------------------------------------------------------------------===// |
121 | | |
122 | | /// getRangeSize - Return the size in bytes of the specified range if they |
123 | | /// are in the same file. If not, this returns -1. |
124 | | int Rewriter::getRangeSize(const CharSourceRange &Range, |
125 | 2.60k | RewriteOptions opts) const { |
126 | 2.60k | if (!isRewritable(Range.getBegin()) || |
127 | 2.60k | !isRewritable(Range.getEnd())2.60k ) return -10 ; |
128 | 2.60k | |
129 | 2.60k | FileID StartFileID, EndFileID; |
130 | 2.60k | unsigned StartOff, EndOff; |
131 | 2.60k | |
132 | 2.60k | StartOff = getLocationOffsetAndFileID(Range.getBegin(), StartFileID); |
133 | 2.60k | EndOff = getLocationOffsetAndFileID(Range.getEnd(), EndFileID); |
134 | 2.60k | |
135 | 2.60k | if (StartFileID != EndFileID) |
136 | 0 | return -1; |
137 | 2.60k | |
138 | 2.60k | // If edits have been made to this buffer, the delta between the range may |
139 | 2.60k | // have changed. |
140 | 2.60k | std::map<FileID, RewriteBuffer>::const_iterator I = |
141 | 2.60k | RewriteBuffers.find(StartFileID); |
142 | 2.60k | if (I != RewriteBuffers.end()2.60k ) { |
143 | 2.49k | const RewriteBuffer &RB = I->second; |
144 | 2.49k | EndOff = RB.getMappedOffset(EndOff, opts.IncludeInsertsAtEndOfRange); |
145 | 2.49k | StartOff = RB.getMappedOffset(StartOff, !opts.IncludeInsertsAtBeginOfRange); |
146 | 2.49k | } |
147 | 2.60k | |
148 | 2.60k | |
149 | 2.60k | // Adjust the end offset to the end of the last token, instead of being the |
150 | 2.60k | // start of the last token if this is a token range. |
151 | 2.60k | if (Range.isTokenRange()) |
152 | 674 | EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr, *LangOpts); |
153 | 2.60k | |
154 | 2.60k | return EndOff-StartOff; |
155 | 2.60k | } |
156 | | |
157 | 674 | int Rewriter::getRangeSize(SourceRange Range, RewriteOptions opts) const { |
158 | 674 | return getRangeSize(CharSourceRange::getTokenRange(Range), opts); |
159 | 674 | } |
160 | | |
161 | | |
162 | | /// getRewrittenText - Return the rewritten form of the text in the specified |
163 | | /// range. If the start or end of the range was unrewritable or if they are |
164 | | /// in different buffers, this returns an empty string. |
165 | | /// |
166 | | /// Note that this method is not particularly efficient. |
167 | | /// |
168 | 148 | std::string Rewriter::getRewrittenText(SourceRange Range) const { |
169 | 148 | if (!isRewritable(Range.getBegin()) || |
170 | 148 | !isRewritable(Range.getEnd())) |
171 | 0 | return ""; |
172 | 148 | |
173 | 148 | FileID StartFileID, EndFileID; |
174 | 148 | unsigned StartOff, EndOff; |
175 | 148 | StartOff = getLocationOffsetAndFileID(Range.getBegin(), StartFileID); |
176 | 148 | EndOff = getLocationOffsetAndFileID(Range.getEnd(), EndFileID); |
177 | 148 | |
178 | 148 | if (StartFileID != EndFileID) |
179 | 0 | return ""; // Start and end in different buffers. |
180 | 148 | |
181 | 148 | // If edits have been made to this buffer, the delta between the range may |
182 | 148 | // have changed. |
183 | 148 | std::map<FileID, RewriteBuffer>::const_iterator I = |
184 | 148 | RewriteBuffers.find(StartFileID); |
185 | 148 | if (I == RewriteBuffers.end()148 ) { |
186 | 0 | // If the buffer hasn't been rewritten, just return the text from the input. |
187 | 0 | const char *Ptr = SourceMgr->getCharacterData(Range.getBegin()); |
188 | 0 |
|
189 | 0 | // Adjust the end offset to the end of the last token, instead of being the |
190 | 0 | // start of the last token. |
191 | 0 | EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr, *LangOpts); |
192 | 0 | return std::string(Ptr, Ptr+EndOff-StartOff); |
193 | 0 | } |
194 | 148 | |
195 | 148 | const RewriteBuffer &RB = I->second; |
196 | 148 | EndOff = RB.getMappedOffset(EndOff, true); |
197 | 148 | StartOff = RB.getMappedOffset(StartOff); |
198 | 148 | |
199 | 148 | // Adjust the end offset to the end of the last token, instead of being the |
200 | 148 | // start of the last token. |
201 | 148 | EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr, *LangOpts); |
202 | 148 | |
203 | 148 | // Advance the iterators to the right spot, yay for linear time algorithms. |
204 | 148 | RewriteBuffer::iterator Start = RB.begin(); |
205 | 148 | std::advance(Start, StartOff); |
206 | 148 | RewriteBuffer::iterator End = Start; |
207 | 148 | std::advance(End, EndOff-StartOff); |
208 | 148 | |
209 | 148 | return std::string(Start, End); |
210 | 148 | } |
211 | | |
212 | | unsigned Rewriter::getLocationOffsetAndFileID(SourceLocation Loc, |
213 | 40.6k | FileID &FID) const { |
214 | 40.6k | assert(Loc.isValid() && "Invalid location"); |
215 | 40.6k | std::pair<FileID,unsigned> V = SourceMgr->getDecomposedLoc(Loc); |
216 | 40.6k | FID = V.first; |
217 | 40.6k | return V.second; |
218 | 40.6k | } |
219 | | |
220 | | |
221 | | /// getEditBuffer - Get or create a RewriteBuffer for the specified FileID. |
222 | | /// |
223 | 44.7k | RewriteBuffer &Rewriter::getEditBuffer(FileID FID) { |
224 | 44.7k | std::map<FileID, RewriteBuffer>::iterator I = |
225 | 44.7k | RewriteBuffers.lower_bound(FID); |
226 | 44.7k | if (I != RewriteBuffers.end() && 44.7k I->first == FID35.0k ) |
227 | 35.0k | return I->second; |
228 | 9.69k | I = RewriteBuffers.insert(I, std::make_pair(FID, RewriteBuffer())); |
229 | 9.69k | |
230 | 9.69k | StringRef MB = SourceMgr->getBufferData(FID); |
231 | 9.69k | I->second.Initialize(MB.begin(), MB.end()); |
232 | 9.69k | |
233 | 9.69k | return I->second; |
234 | 9.69k | } |
235 | | |
236 | | /// InsertText - Insert the specified string at the specified location in the |
237 | | /// original buffer. |
238 | | bool Rewriter::InsertText(SourceLocation Loc, StringRef Str, |
239 | 2.53k | bool InsertAfter, bool indentNewLines) { |
240 | 2.53k | if (!isRewritable(Loc)2.53k ) return true0 ; |
241 | 2.53k | FileID FID; |
242 | 2.53k | unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID); |
243 | 2.53k | |
244 | 2.53k | SmallString<128> indentedStr; |
245 | 2.53k | if (indentNewLines && 2.53k Str.find('\n') != StringRef::npos313 ) { |
246 | 12 | StringRef MB = SourceMgr->getBufferData(FID); |
247 | 12 | |
248 | 12 | unsigned lineNo = SourceMgr->getLineNumber(FID, StartOffs) - 1; |
249 | 12 | const SrcMgr::ContentCache * |
250 | 12 | Content = SourceMgr->getSLocEntry(FID).getFile().getContentCache(); |
251 | 12 | unsigned lineOffs = Content->SourceLineCache[lineNo]; |
252 | 12 | |
253 | 12 | // Find the whitespace at the start of the line. |
254 | 12 | StringRef indentSpace; |
255 | 12 | { |
256 | 12 | unsigned i = lineOffs; |
257 | 22 | while (isWhitespaceExceptNL(MB[i])) |
258 | 10 | ++i; |
259 | 12 | indentSpace = MB.substr(lineOffs, i-lineOffs); |
260 | 12 | } |
261 | 12 | |
262 | 12 | SmallVector<StringRef, 4> lines; |
263 | 12 | Str.split(lines, "\n"); |
264 | 12 | |
265 | 54 | for (unsigned i = 0, e = lines.size(); i != e54 ; ++i42 ) { |
266 | 42 | indentedStr += lines[i]; |
267 | 42 | if (i < e-142 ) { |
268 | 30 | indentedStr += '\n'; |
269 | 30 | indentedStr += indentSpace; |
270 | 30 | } |
271 | 42 | } |
272 | 12 | Str = indentedStr.str(); |
273 | 12 | } |
274 | 2.53k | |
275 | 2.53k | getEditBuffer(FID).InsertText(StartOffs, Str, InsertAfter); |
276 | 2.53k | return false; |
277 | 2.53k | } |
278 | | |
279 | 0 | bool Rewriter::InsertTextAfterToken(SourceLocation Loc, StringRef Str) { |
280 | 0 | if (!isRewritable(Loc)0 ) return true0 ; |
281 | 0 | FileID FID; |
282 | 0 | unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID); |
283 | 0 | RewriteOptions rangeOpts; |
284 | 0 | rangeOpts.IncludeInsertsAtBeginOfRange = false; |
285 | 0 | StartOffs += getRangeSize(SourceRange(Loc, Loc), rangeOpts); |
286 | 0 | getEditBuffer(FID).InsertText(StartOffs, Str, /*InsertAfter*/true); |
287 | 0 | return false; |
288 | 0 | } |
289 | | |
290 | | /// RemoveText - Remove the specified text region. |
291 | | bool Rewriter::RemoveText(SourceLocation Start, unsigned Length, |
292 | 402 | RewriteOptions opts) { |
293 | 402 | if (!isRewritable(Start)402 ) return true0 ; |
294 | 402 | FileID FID; |
295 | 402 | unsigned StartOffs = getLocationOffsetAndFileID(Start, FID); |
296 | 402 | getEditBuffer(FID).RemoveText(StartOffs, Length, opts.RemoveLineIfEmpty); |
297 | 402 | return false; |
298 | 402 | } |
299 | | |
300 | | /// ReplaceText - This method replaces a range of characters in the input |
301 | | /// buffer with a new string. This is effectively a combined "remove/insert" |
302 | | /// operation. |
303 | | bool Rewriter::ReplaceText(SourceLocation Start, unsigned OrigLength, |
304 | 32.1k | StringRef NewStr) { |
305 | 32.1k | if (!isRewritable(Start)32.1k ) return true0 ; |
306 | 32.1k | FileID StartFileID; |
307 | 32.1k | unsigned StartOffs = getLocationOffsetAndFileID(Start, StartFileID); |
308 | 32.1k | |
309 | 32.1k | getEditBuffer(StartFileID).ReplaceText(StartOffs, OrigLength, NewStr); |
310 | 32.1k | return false; |
311 | 32.1k | } |
312 | | |
313 | 0 | bool Rewriter::ReplaceText(SourceRange range, SourceRange replacementRange) { |
314 | 0 | if (!isRewritable(range.getBegin())0 ) return true0 ; |
315 | 0 | if (0 !isRewritable(range.getEnd())0 ) return true0 ; |
316 | 0 | if (0 replacementRange.isInvalid()0 ) return true0 ; |
317 | 0 | SourceLocation start = range.getBegin(); |
318 | 0 | unsigned origLength = getRangeSize(range); |
319 | 0 | unsigned newLength = getRangeSize(replacementRange); |
320 | 0 | FileID FID; |
321 | 0 | unsigned newOffs = getLocationOffsetAndFileID(replacementRange.getBegin(), |
322 | 0 | FID); |
323 | 0 | StringRef MB = SourceMgr->getBufferData(FID); |
324 | 0 | return ReplaceText(start, origLength, MB.substr(newOffs, newLength)); |
325 | 0 | } |
326 | | |
327 | | bool Rewriter::IncreaseIndentation(CharSourceRange range, |
328 | 16 | SourceLocation parentIndent) { |
329 | 16 | if (range.isInvalid()16 ) return true0 ; |
330 | 16 | if (16 !isRewritable(range.getBegin())16 ) return true0 ; |
331 | 16 | if (16 !isRewritable(range.getEnd())16 ) return true0 ; |
332 | 16 | if (16 !isRewritable(parentIndent)16 ) return true0 ; |
333 | 16 | |
334 | 16 | FileID StartFileID, EndFileID, parentFileID; |
335 | 16 | unsigned StartOff, EndOff, parentOff; |
336 | 16 | |
337 | 16 | StartOff = getLocationOffsetAndFileID(range.getBegin(), StartFileID); |
338 | 16 | EndOff = getLocationOffsetAndFileID(range.getEnd(), EndFileID); |
339 | 16 | parentOff = getLocationOffsetAndFileID(parentIndent, parentFileID); |
340 | 16 | |
341 | 16 | if (StartFileID != EndFileID || 16 StartFileID != parentFileID16 ) |
342 | 0 | return true; |
343 | 16 | if (16 StartOff > EndOff16 ) |
344 | 0 | return true; |
345 | 16 | |
346 | 16 | FileID FID = StartFileID; |
347 | 16 | StringRef MB = SourceMgr->getBufferData(FID); |
348 | 16 | |
349 | 16 | unsigned parentLineNo = SourceMgr->getLineNumber(FID, parentOff) - 1; |
350 | 16 | unsigned startLineNo = SourceMgr->getLineNumber(FID, StartOff) - 1; |
351 | 16 | unsigned endLineNo = SourceMgr->getLineNumber(FID, EndOff) - 1; |
352 | 16 | |
353 | 16 | const SrcMgr::ContentCache * |
354 | 16 | Content = SourceMgr->getSLocEntry(FID).getFile().getContentCache(); |
355 | 16 | |
356 | 16 | // Find where the lines start. |
357 | 16 | unsigned parentLineOffs = Content->SourceLineCache[parentLineNo]; |
358 | 16 | unsigned startLineOffs = Content->SourceLineCache[startLineNo]; |
359 | 16 | |
360 | 16 | // Find the whitespace at the start of each line. |
361 | 16 | StringRef parentSpace, startSpace; |
362 | 16 | { |
363 | 16 | unsigned i = parentLineOffs; |
364 | 26 | while (isWhitespaceExceptNL(MB[i])) |
365 | 10 | ++i; |
366 | 16 | parentSpace = MB.substr(parentLineOffs, i-parentLineOffs); |
367 | 16 | |
368 | 16 | i = startLineOffs; |
369 | 76 | while (isWhitespaceExceptNL(MB[i])) |
370 | 60 | ++i; |
371 | 16 | startSpace = MB.substr(startLineOffs, i-startLineOffs); |
372 | 16 | } |
373 | 16 | if (parentSpace.size() >= startSpace.size()) |
374 | 0 | return true; |
375 | 16 | if (16 !startSpace.startswith(parentSpace)16 ) |
376 | 0 | return true; |
377 | 16 | |
378 | 16 | StringRef indent = startSpace.substr(parentSpace.size()); |
379 | 16 | |
380 | 16 | // Indent the lines between start/end offsets. |
381 | 16 | RewriteBuffer &RB = getEditBuffer(FID); |
382 | 74 | for (unsigned lineNo = startLineNo; lineNo <= endLineNo74 ; ++lineNo58 ) { |
383 | 58 | unsigned offs = Content->SourceLineCache[lineNo]; |
384 | 58 | unsigned i = offs; |
385 | 264 | while (isWhitespaceExceptNL(MB[i])) |
386 | 206 | ++i; |
387 | 58 | StringRef origIndent = MB.substr(offs, i-offs); |
388 | 58 | if (origIndent.startswith(startSpace)) |
389 | 53 | RB.InsertText(offs, indent, /*InsertAfter=*/false); |
390 | 58 | } |
391 | 16 | |
392 | 16 | return false; |
393 | 16 | } |
394 | | |
395 | | namespace { |
396 | | // A wrapper for a file stream that atomically overwrites the target. |
397 | | // |
398 | | // Creates a file output stream for a temporary file in the constructor, |
399 | | // which is later accessible via getStream() if ok() return true. |
400 | | // Flushes the stream and moves the temporary file to the target location |
401 | | // in the destructor. |
402 | | class AtomicallyMovedFile { |
403 | | public: |
404 | | AtomicallyMovedFile(DiagnosticsEngine &Diagnostics, StringRef Filename, |
405 | | bool &AllWritten) |
406 | 54 | : Diagnostics(Diagnostics), Filename(Filename), AllWritten(AllWritten) { |
407 | 54 | TempFilename = Filename; |
408 | 54 | TempFilename += "-%%%%%%%%"; |
409 | 54 | int FD; |
410 | 54 | if (llvm::sys::fs::createUniqueFile(TempFilename, FD, TempFilename)54 ) { |
411 | 1 | AllWritten = false; |
412 | 1 | Diagnostics.Report(clang::diag::err_unable_to_make_temp) |
413 | 1 | << TempFilename; |
414 | 54 | } else { |
415 | 53 | FileStream.reset(new llvm::raw_fd_ostream(FD, /*shouldClose=*/true)); |
416 | 53 | } |
417 | 54 | } |
418 | | |
419 | 54 | ~AtomicallyMovedFile() { |
420 | 54 | if (!ok()54 ) return1 ; |
421 | 53 | |
422 | 53 | // Close (will also flush) theFileStream. |
423 | 53 | FileStream->close(); |
424 | 53 | if (std::error_code ec53 = llvm::sys::fs::rename(TempFilename, Filename)) { |
425 | 0 | AllWritten = false; |
426 | 0 | Diagnostics.Report(clang::diag::err_unable_to_rename_temp) |
427 | 0 | << TempFilename << Filename << ec.message(); |
428 | 0 | // If the remove fails, there's not a lot we can do - this is already an |
429 | 0 | // error. |
430 | 0 | llvm::sys::fs::remove(TempFilename); |
431 | 0 | } |
432 | 54 | } |
433 | | |
434 | 108 | bool ok() { return (bool)FileStream; } |
435 | 53 | raw_ostream &getStream() { return *FileStream; } |
436 | | |
437 | | private: |
438 | | DiagnosticsEngine &Diagnostics; |
439 | | StringRef Filename; |
440 | | SmallString<128> TempFilename; |
441 | | std::unique_ptr<llvm::raw_fd_ostream> FileStream; |
442 | | bool &AllWritten; |
443 | | }; |
444 | | } // end anonymous namespace |
445 | | |
446 | 60 | bool Rewriter::overwriteChangedFiles() { |
447 | 60 | bool AllWritten = true; |
448 | 114 | for (buffer_iterator I = buffer_begin(), E = buffer_end(); I != E114 ; ++I54 ) { |
449 | 54 | const FileEntry *Entry = |
450 | 54 | getSourceMgr().getFileEntryForID(I->first); |
451 | 54 | AtomicallyMovedFile File(getSourceMgr().getDiagnostics(), Entry->getName(), |
452 | 54 | AllWritten); |
453 | 54 | if (File.ok()54 ) { |
454 | 53 | I->second.write(File.getStream()); |
455 | 53 | } |
456 | 54 | } |
457 | 60 | return !AllWritten; |
458 | 60 | } |