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