1243791Sdim//===--- Rewriter.cpp - Code rewriting interface --------------------------===//
2243791Sdim//
3243791Sdim//                     The LLVM Compiler Infrastructure
4243791Sdim//
5243791Sdim// This file is distributed under the University of Illinois Open Source
6243791Sdim// License. See LICENSE.TXT for details.
7243791Sdim//
8243791Sdim//===----------------------------------------------------------------------===//
9243791Sdim//
10243791Sdim//  This file defines the Rewriter class, which is used for code
11243791Sdim//  transformations.
12243791Sdim//
13243791Sdim//===----------------------------------------------------------------------===//
14243791Sdim
15243791Sdim#include "clang/Rewrite/Core/Rewriter.h"
16252723Sdim#include "clang/AST/Decl.h"
17252723Sdim#include "clang/AST/PrettyPrinter.h"
18243791Sdim#include "clang/AST/Stmt.h"
19243791Sdim#include "clang/Basic/DiagnosticIDs.h"
20243791Sdim#include "clang/Basic/FileManager.h"
21243791Sdim#include "clang/Basic/SourceManager.h"
22243791Sdim#include "clang/Lex/Lexer.h"
23243791Sdim#include "llvm/ADT/SmallString.h"
24243791Sdim#include "llvm/Support/FileSystem.h"
25252723Sdim#include "llvm/Support/raw_ostream.h"
26243791Sdimusing namespace clang;
27243791Sdim
28243791Sdimraw_ostream &RewriteBuffer::write(raw_ostream &os) const {
29243791Sdim  // FIXME: eliminate the copy by writing out each chunk at a time
30243791Sdim  os << std::string(begin(), end());
31243791Sdim  return os;
32243791Sdim}
33243791Sdim
34243791Sdim/// \brief Return true if this character is non-new-line whitespace:
35243791Sdim/// ' ', '\\t', '\\f', '\\v', '\\r'.
36243791Sdimstatic inline bool isWhitespace(unsigned char c) {
37243791Sdim  switch (c) {
38243791Sdim  case ' ':
39243791Sdim  case '\t':
40243791Sdim  case '\f':
41243791Sdim  case '\v':
42243791Sdim  case '\r':
43243791Sdim    return true;
44243791Sdim  default:
45243791Sdim    return false;
46243791Sdim  }
47243791Sdim}
48243791Sdim
49243791Sdimvoid RewriteBuffer::RemoveText(unsigned OrigOffset, unsigned Size,
50243791Sdim                               bool removeLineIfEmpty) {
51243791Sdim  // Nothing to remove, exit early.
52243791Sdim  if (Size == 0) return;
53243791Sdim
54243791Sdim  unsigned RealOffset = getMappedOffset(OrigOffset, true);
55243791Sdim  assert(RealOffset+Size < Buffer.size() && "Invalid location");
56243791Sdim
57243791Sdim  // Remove the dead characters.
58243791Sdim  Buffer.erase(RealOffset, Size);
59243791Sdim
60243791Sdim  // Add a delta so that future changes are offset correctly.
61243791Sdim  AddReplaceDelta(OrigOffset, -Size);
62243791Sdim
63243791Sdim  if (removeLineIfEmpty) {
64243791Sdim    // Find the line that the remove occurred and if it is completely empty
65243791Sdim    // remove the line as well.
66243791Sdim
67243791Sdim    iterator curLineStart = begin();
68243791Sdim    unsigned curLineStartOffs = 0;
69243791Sdim    iterator posI = begin();
70243791Sdim    for (unsigned i = 0; i != RealOffset; ++i) {
71243791Sdim      if (*posI == '\n') {
72243791Sdim        curLineStart = posI;
73243791Sdim        ++curLineStart;
74243791Sdim        curLineStartOffs = i + 1;
75243791Sdim      }
76243791Sdim      ++posI;
77243791Sdim    }
78243791Sdim
79243791Sdim    unsigned lineSize = 0;
80243791Sdim    posI = curLineStart;
81243791Sdim    while (posI != end() && isWhitespace(*posI)) {
82243791Sdim      ++posI;
83243791Sdim      ++lineSize;
84243791Sdim    }
85243791Sdim    if (posI != end() && *posI == '\n') {
86243791Sdim      Buffer.erase(curLineStartOffs, lineSize + 1/* + '\n'*/);
87243791Sdim      AddReplaceDelta(curLineStartOffs, -(lineSize + 1/* + '\n'*/));
88243791Sdim    }
89243791Sdim  }
90243791Sdim}
91243791Sdim
92243791Sdimvoid RewriteBuffer::InsertText(unsigned OrigOffset, StringRef Str,
93243791Sdim                               bool InsertAfter) {
94243791Sdim
95243791Sdim  // Nothing to insert, exit early.
96243791Sdim  if (Str.empty()) return;
97243791Sdim
98243791Sdim  unsigned RealOffset = getMappedOffset(OrigOffset, InsertAfter);
99243791Sdim  Buffer.insert(RealOffset, Str.begin(), Str.end());
100243791Sdim
101243791Sdim  // Add a delta so that future changes are offset correctly.
102243791Sdim  AddInsertDelta(OrigOffset, Str.size());
103243791Sdim}
104243791Sdim
105243791Sdim/// ReplaceText - This method replaces a range of characters in the input
106243791Sdim/// buffer with a new string.  This is effectively a combined "remove+insert"
107243791Sdim/// operation.
108243791Sdimvoid RewriteBuffer::ReplaceText(unsigned OrigOffset, unsigned OrigLength,
109243791Sdim                                StringRef NewStr) {
110243791Sdim  unsigned RealOffset = getMappedOffset(OrigOffset, true);
111243791Sdim  Buffer.erase(RealOffset, OrigLength);
112243791Sdim  Buffer.insert(RealOffset, NewStr.begin(), NewStr.end());
113243791Sdim  if (OrigLength != NewStr.size())
114243791Sdim    AddReplaceDelta(OrigOffset, NewStr.size() - OrigLength);
115243791Sdim}
116243791Sdim
117243791Sdim
118243791Sdim//===----------------------------------------------------------------------===//
119243791Sdim// Rewriter class
120243791Sdim//===----------------------------------------------------------------------===//
121243791Sdim
122243791Sdim/// getRangeSize - Return the size in bytes of the specified range if they
123243791Sdim/// are in the same file.  If not, this returns -1.
124243791Sdimint Rewriter::getRangeSize(const CharSourceRange &Range,
125243791Sdim                           RewriteOptions opts) const {
126243791Sdim  if (!isRewritable(Range.getBegin()) ||
127243791Sdim      !isRewritable(Range.getEnd())) return -1;
128243791Sdim
129243791Sdim  FileID StartFileID, EndFileID;
130243791Sdim  unsigned StartOff, EndOff;
131243791Sdim
132243791Sdim  StartOff = getLocationOffsetAndFileID(Range.getBegin(), StartFileID);
133243791Sdim  EndOff   = getLocationOffsetAndFileID(Range.getEnd(), EndFileID);
134243791Sdim
135243791Sdim  if (StartFileID != EndFileID)
136243791Sdim    return -1;
137243791Sdim
138243791Sdim  // If edits have been made to this buffer, the delta between the range may
139243791Sdim  // have changed.
140243791Sdim  std::map<FileID, RewriteBuffer>::const_iterator I =
141243791Sdim    RewriteBuffers.find(StartFileID);
142243791Sdim  if (I != RewriteBuffers.end()) {
143243791Sdim    const RewriteBuffer &RB = I->second;
144243791Sdim    EndOff = RB.getMappedOffset(EndOff, opts.IncludeInsertsAtEndOfRange);
145243791Sdim    StartOff = RB.getMappedOffset(StartOff, !opts.IncludeInsertsAtBeginOfRange);
146243791Sdim  }
147243791Sdim
148243791Sdim
149243791Sdim  // Adjust the end offset to the end of the last token, instead of being the
150243791Sdim  // start of the last token if this is a token range.
151243791Sdim  if (Range.isTokenRange())
152243791Sdim    EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr, *LangOpts);
153243791Sdim
154243791Sdim  return EndOff-StartOff;
155243791Sdim}
156243791Sdim
157243791Sdimint Rewriter::getRangeSize(SourceRange Range, RewriteOptions opts) const {
158243791Sdim  return getRangeSize(CharSourceRange::getTokenRange(Range), opts);
159243791Sdim}
160243791Sdim
161243791Sdim
162243791Sdim/// getRewrittenText - Return the rewritten form of the text in the specified
163243791Sdim/// range.  If the start or end of the range was unrewritable or if they are
164243791Sdim/// in different buffers, this returns an empty string.
165243791Sdim///
166243791Sdim/// Note that this method is not particularly efficient.
167243791Sdim///
168243791Sdimstd::string Rewriter::getRewrittenText(SourceRange Range) const {
169243791Sdim  if (!isRewritable(Range.getBegin()) ||
170243791Sdim      !isRewritable(Range.getEnd()))
171243791Sdim    return "";
172243791Sdim
173243791Sdim  FileID StartFileID, EndFileID;
174243791Sdim  unsigned StartOff, EndOff;
175243791Sdim  StartOff = getLocationOffsetAndFileID(Range.getBegin(), StartFileID);
176243791Sdim  EndOff   = getLocationOffsetAndFileID(Range.getEnd(), EndFileID);
177243791Sdim
178243791Sdim  if (StartFileID != EndFileID)
179243791Sdim    return ""; // Start and end in different buffers.
180243791Sdim
181243791Sdim  // If edits have been made to this buffer, the delta between the range may
182243791Sdim  // have changed.
183243791Sdim  std::map<FileID, RewriteBuffer>::const_iterator I =
184243791Sdim    RewriteBuffers.find(StartFileID);
185243791Sdim  if (I == RewriteBuffers.end()) {
186243791Sdim    // If the buffer hasn't been rewritten, just return the text from the input.
187243791Sdim    const char *Ptr = SourceMgr->getCharacterData(Range.getBegin());
188243791Sdim
189243791Sdim    // Adjust the end offset to the end of the last token, instead of being the
190243791Sdim    // start of the last token.
191243791Sdim    EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr, *LangOpts);
192243791Sdim    return std::string(Ptr, Ptr+EndOff-StartOff);
193243791Sdim  }
194243791Sdim
195243791Sdim  const RewriteBuffer &RB = I->second;
196243791Sdim  EndOff = RB.getMappedOffset(EndOff, true);
197243791Sdim  StartOff = RB.getMappedOffset(StartOff);
198243791Sdim
199243791Sdim  // Adjust the end offset to the end of the last token, instead of being the
200243791Sdim  // start of the last token.
201243791Sdim  EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr, *LangOpts);
202243791Sdim
203243791Sdim  // Advance the iterators to the right spot, yay for linear time algorithms.
204243791Sdim  RewriteBuffer::iterator Start = RB.begin();
205243791Sdim  std::advance(Start, StartOff);
206243791Sdim  RewriteBuffer::iterator End = Start;
207243791Sdim  std::advance(End, EndOff-StartOff);
208243791Sdim
209243791Sdim  return std::string(Start, End);
210243791Sdim}
211243791Sdim
212243791Sdimunsigned Rewriter::getLocationOffsetAndFileID(SourceLocation Loc,
213243791Sdim                                              FileID &FID) const {
214243791Sdim  assert(Loc.isValid() && "Invalid location");
215243791Sdim  std::pair<FileID,unsigned> V = SourceMgr->getDecomposedLoc(Loc);
216243791Sdim  FID = V.first;
217243791Sdim  return V.second;
218243791Sdim}
219243791Sdim
220243791Sdim
221243791Sdim/// getEditBuffer - Get or create a RewriteBuffer for the specified FileID.
222243791Sdim///
223243791SdimRewriteBuffer &Rewriter::getEditBuffer(FileID FID) {
224243791Sdim  std::map<FileID, RewriteBuffer>::iterator I =
225243791Sdim    RewriteBuffers.lower_bound(FID);
226243791Sdim  if (I != RewriteBuffers.end() && I->first == FID)
227243791Sdim    return I->second;
228243791Sdim  I = RewriteBuffers.insert(I, std::make_pair(FID, RewriteBuffer()));
229243791Sdim
230243791Sdim  StringRef MB = SourceMgr->getBufferData(FID);
231243791Sdim  I->second.Initialize(MB.begin(), MB.end());
232243791Sdim
233243791Sdim  return I->second;
234243791Sdim}
235243791Sdim
236243791Sdim/// InsertText - Insert the specified string at the specified location in the
237243791Sdim/// original buffer.
238243791Sdimbool Rewriter::InsertText(SourceLocation Loc, StringRef Str,
239243791Sdim                          bool InsertAfter, bool indentNewLines) {
240243791Sdim  if (!isRewritable(Loc)) return true;
241243791Sdim  FileID FID;
242243791Sdim  unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID);
243243791Sdim
244243791Sdim  SmallString<128> indentedStr;
245243791Sdim  if (indentNewLines && Str.find('\n') != StringRef::npos) {
246243791Sdim    StringRef MB = SourceMgr->getBufferData(FID);
247243791Sdim
248243791Sdim    unsigned lineNo = SourceMgr->getLineNumber(FID, StartOffs) - 1;
249243791Sdim    const SrcMgr::ContentCache *
250243791Sdim        Content = SourceMgr->getSLocEntry(FID).getFile().getContentCache();
251243791Sdim    unsigned lineOffs = Content->SourceLineCache[lineNo];
252243791Sdim
253243791Sdim    // Find the whitespace at the start of the line.
254243791Sdim    StringRef indentSpace;
255243791Sdim    {
256243791Sdim      unsigned i = lineOffs;
257243791Sdim      while (isWhitespace(MB[i]))
258243791Sdim        ++i;
259243791Sdim      indentSpace = MB.substr(lineOffs, i-lineOffs);
260243791Sdim    }
261243791Sdim
262243791Sdim    SmallVector<StringRef, 4> lines;
263243791Sdim    Str.split(lines, "\n");
264243791Sdim
265243791Sdim    for (unsigned i = 0, e = lines.size(); i != e; ++i) {
266243791Sdim      indentedStr += lines[i];
267243791Sdim      if (i < e-1) {
268243791Sdim        indentedStr += '\n';
269243791Sdim        indentedStr += indentSpace;
270243791Sdim      }
271243791Sdim    }
272243791Sdim    Str = indentedStr.str();
273243791Sdim  }
274243791Sdim
275243791Sdim  getEditBuffer(FID).InsertText(StartOffs, Str, InsertAfter);
276243791Sdim  return false;
277243791Sdim}
278243791Sdim
279243791Sdimbool Rewriter::InsertTextAfterToken(SourceLocation Loc, StringRef Str) {
280243791Sdim  if (!isRewritable(Loc)) return true;
281243791Sdim  FileID FID;
282243791Sdim  unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID);
283243791Sdim  RewriteOptions rangeOpts;
284243791Sdim  rangeOpts.IncludeInsertsAtBeginOfRange = false;
285243791Sdim  StartOffs += getRangeSize(SourceRange(Loc, Loc), rangeOpts);
286243791Sdim  getEditBuffer(FID).InsertText(StartOffs, Str, /*InsertAfter*/true);
287243791Sdim  return false;
288243791Sdim}
289243791Sdim
290243791Sdim/// RemoveText - Remove the specified text region.
291243791Sdimbool Rewriter::RemoveText(SourceLocation Start, unsigned Length,
292243791Sdim                          RewriteOptions opts) {
293243791Sdim  if (!isRewritable(Start)) return true;
294243791Sdim  FileID FID;
295243791Sdim  unsigned StartOffs = getLocationOffsetAndFileID(Start, FID);
296243791Sdim  getEditBuffer(FID).RemoveText(StartOffs, Length, opts.RemoveLineIfEmpty);
297243791Sdim  return false;
298243791Sdim}
299243791Sdim
300243791Sdim/// ReplaceText - This method replaces a range of characters in the input
301243791Sdim/// buffer with a new string.  This is effectively a combined "remove/insert"
302243791Sdim/// operation.
303243791Sdimbool Rewriter::ReplaceText(SourceLocation Start, unsigned OrigLength,
304243791Sdim                           StringRef NewStr) {
305243791Sdim  if (!isRewritable(Start)) return true;
306243791Sdim  FileID StartFileID;
307243791Sdim  unsigned StartOffs = getLocationOffsetAndFileID(Start, StartFileID);
308243791Sdim
309243791Sdim  getEditBuffer(StartFileID).ReplaceText(StartOffs, OrigLength, NewStr);
310243791Sdim  return false;
311243791Sdim}
312243791Sdim
313243791Sdimbool Rewriter::ReplaceText(SourceRange range, SourceRange replacementRange) {
314243791Sdim  if (!isRewritable(range.getBegin())) return true;
315243791Sdim  if (!isRewritable(range.getEnd())) return true;
316243791Sdim  if (replacementRange.isInvalid()) return true;
317243791Sdim  SourceLocation start = range.getBegin();
318243791Sdim  unsigned origLength = getRangeSize(range);
319243791Sdim  unsigned newLength = getRangeSize(replacementRange);
320243791Sdim  FileID FID;
321243791Sdim  unsigned newOffs = getLocationOffsetAndFileID(replacementRange.getBegin(),
322243791Sdim                                                FID);
323243791Sdim  StringRef MB = SourceMgr->getBufferData(FID);
324243791Sdim  return ReplaceText(start, origLength, MB.substr(newOffs, newLength));
325243791Sdim}
326243791Sdim
327243791Sdim/// ReplaceStmt - This replaces a Stmt/Expr with another, using the pretty
328243791Sdim/// printer to generate the replacement code.  This returns true if the input
329243791Sdim/// could not be rewritten, or false if successful.
330243791Sdimbool Rewriter::ReplaceStmt(Stmt *From, Stmt *To) {
331243791Sdim  // Measaure the old text.
332243791Sdim  int Size = getRangeSize(From->getSourceRange());
333243791Sdim  if (Size == -1)
334243791Sdim    return true;
335243791Sdim
336243791Sdim  // Get the new text.
337243791Sdim  std::string SStr;
338243791Sdim  llvm::raw_string_ostream S(SStr);
339243791Sdim  To->printPretty(S, 0, PrintingPolicy(*LangOpts));
340243791Sdim  const std::string &Str = S.str();
341243791Sdim
342243791Sdim  ReplaceText(From->getLocStart(), Size, Str);
343243791Sdim  return false;
344243791Sdim}
345243791Sdim
346243791Sdimstd::string Rewriter::ConvertToString(Stmt *From) {
347243791Sdim  std::string SStr;
348243791Sdim  llvm::raw_string_ostream S(SStr);
349243791Sdim  From->printPretty(S, 0, PrintingPolicy(*LangOpts));
350243791Sdim  return S.str();
351243791Sdim}
352243791Sdim
353243791Sdimbool Rewriter::IncreaseIndentation(CharSourceRange range,
354243791Sdim                                   SourceLocation parentIndent) {
355243791Sdim  if (range.isInvalid()) return true;
356243791Sdim  if (!isRewritable(range.getBegin())) return true;
357243791Sdim  if (!isRewritable(range.getEnd())) return true;
358243791Sdim  if (!isRewritable(parentIndent)) return true;
359243791Sdim
360243791Sdim  FileID StartFileID, EndFileID, parentFileID;
361243791Sdim  unsigned StartOff, EndOff, parentOff;
362243791Sdim
363243791Sdim  StartOff = getLocationOffsetAndFileID(range.getBegin(), StartFileID);
364243791Sdim  EndOff   = getLocationOffsetAndFileID(range.getEnd(), EndFileID);
365243791Sdim  parentOff = getLocationOffsetAndFileID(parentIndent, parentFileID);
366243791Sdim
367243791Sdim  if (StartFileID != EndFileID || StartFileID != parentFileID)
368243791Sdim    return true;
369243791Sdim  if (StartOff > EndOff)
370243791Sdim    return true;
371243791Sdim
372243791Sdim  FileID FID = StartFileID;
373243791Sdim  StringRef MB = SourceMgr->getBufferData(FID);
374243791Sdim
375243791Sdim  unsigned parentLineNo = SourceMgr->getLineNumber(FID, parentOff) - 1;
376243791Sdim  unsigned startLineNo = SourceMgr->getLineNumber(FID, StartOff) - 1;
377243791Sdim  unsigned endLineNo = SourceMgr->getLineNumber(FID, EndOff) - 1;
378243791Sdim
379243791Sdim  const SrcMgr::ContentCache *
380243791Sdim      Content = SourceMgr->getSLocEntry(FID).getFile().getContentCache();
381243791Sdim
382243791Sdim  // Find where the lines start.
383243791Sdim  unsigned parentLineOffs = Content->SourceLineCache[parentLineNo];
384243791Sdim  unsigned startLineOffs = Content->SourceLineCache[startLineNo];
385243791Sdim
386243791Sdim  // Find the whitespace at the start of each line.
387243791Sdim  StringRef parentSpace, startSpace;
388243791Sdim  {
389243791Sdim    unsigned i = parentLineOffs;
390243791Sdim    while (isWhitespace(MB[i]))
391243791Sdim      ++i;
392243791Sdim    parentSpace = MB.substr(parentLineOffs, i-parentLineOffs);
393243791Sdim
394243791Sdim    i = startLineOffs;
395243791Sdim    while (isWhitespace(MB[i]))
396243791Sdim      ++i;
397243791Sdim    startSpace = MB.substr(startLineOffs, i-startLineOffs);
398243791Sdim  }
399243791Sdim  if (parentSpace.size() >= startSpace.size())
400243791Sdim    return true;
401243791Sdim  if (!startSpace.startswith(parentSpace))
402243791Sdim    return true;
403243791Sdim
404243791Sdim  StringRef indent = startSpace.substr(parentSpace.size());
405243791Sdim
406243791Sdim  // Indent the lines between start/end offsets.
407243791Sdim  RewriteBuffer &RB = getEditBuffer(FID);
408243791Sdim  for (unsigned lineNo = startLineNo; lineNo <= endLineNo; ++lineNo) {
409243791Sdim    unsigned offs = Content->SourceLineCache[lineNo];
410243791Sdim    unsigned i = offs;
411243791Sdim    while (isWhitespace(MB[i]))
412243791Sdim      ++i;
413243791Sdim    StringRef origIndent = MB.substr(offs, i-offs);
414243791Sdim    if (origIndent.startswith(startSpace))
415243791Sdim      RB.InsertText(offs, indent, /*InsertAfter=*/false);
416243791Sdim  }
417243791Sdim
418243791Sdim  return false;
419243791Sdim}
420243791Sdim
421252723Sdimnamespace {
422243791Sdim// A wrapper for a file stream that atomically overwrites the target.
423243791Sdim//
424243791Sdim// Creates a file output stream for a temporary file in the constructor,
425243791Sdim// which is later accessible via getStream() if ok() return true.
426243791Sdim// Flushes the stream and moves the temporary file to the target location
427243791Sdim// in the destructor.
428243791Sdimclass AtomicallyMovedFile {
429243791Sdimpublic:
430243791Sdim  AtomicallyMovedFile(DiagnosticsEngine &Diagnostics, StringRef Filename,
431243791Sdim                      bool &AllWritten)
432243791Sdim    : Diagnostics(Diagnostics), Filename(Filename), AllWritten(AllWritten) {
433243791Sdim    TempFilename = Filename;
434243791Sdim    TempFilename += "-%%%%%%%%";
435243791Sdim    int FD;
436263509Sdim    if (llvm::sys::fs::createUniqueFile(TempFilename.str(), FD, TempFilename)) {
437243791Sdim      AllWritten = false;
438243791Sdim      Diagnostics.Report(clang::diag::err_unable_to_make_temp)
439243791Sdim        << TempFilename;
440243791Sdim    } else {
441243791Sdim      FileStream.reset(new llvm::raw_fd_ostream(FD, /*shouldClose=*/true));
442243791Sdim    }
443243791Sdim  }
444243791Sdim
445243791Sdim  ~AtomicallyMovedFile() {
446243791Sdim    if (!ok()) return;
447243791Sdim
448243791Sdim    FileStream->flush();
449243791Sdim#ifdef _WIN32
450243791Sdim    // Win32 does not allow rename/removing opened files.
451243791Sdim    FileStream.reset();
452243791Sdim#endif
453243791Sdim    if (llvm::error_code ec =
454243791Sdim          llvm::sys::fs::rename(TempFilename.str(), Filename)) {
455243791Sdim      AllWritten = false;
456243791Sdim      Diagnostics.Report(clang::diag::err_unable_to_rename_temp)
457243791Sdim        << TempFilename << Filename << ec.message();
458243791Sdim      bool existed;
459243791Sdim      // If the remove fails, there's not a lot we can do - this is already an
460243791Sdim      // error.
461243791Sdim      llvm::sys::fs::remove(TempFilename.str(), existed);
462243791Sdim    }
463243791Sdim  }
464243791Sdim
465263509Sdim  bool ok() { return FileStream.isValid(); }
466252723Sdim  raw_ostream &getStream() { return *FileStream; }
467243791Sdim
468243791Sdimprivate:
469243791Sdim  DiagnosticsEngine &Diagnostics;
470243791Sdim  StringRef Filename;
471243791Sdim  SmallString<128> TempFilename;
472243791Sdim  OwningPtr<llvm::raw_fd_ostream> FileStream;
473243791Sdim  bool &AllWritten;
474243791Sdim};
475252723Sdim} // end anonymous namespace
476243791Sdim
477243791Sdimbool Rewriter::overwriteChangedFiles() {
478243791Sdim  bool AllWritten = true;
479243791Sdim  for (buffer_iterator I = buffer_begin(), E = buffer_end(); I != E; ++I) {
480243791Sdim    const FileEntry *Entry =
481243791Sdim        getSourceMgr().getFileEntryForID(I->first);
482243791Sdim    AtomicallyMovedFile File(getSourceMgr().getDiagnostics(), Entry->getName(),
483243791Sdim                             AllWritten);
484243791Sdim    if (File.ok()) {
485243791Sdim      I->second.write(File.getStream());
486243791Sdim    }
487243791Sdim  }
488243791Sdim  return !AllWritten;
489243791Sdim}
490