18bd12b848bc353a9d34b54144c3dd3407b064292Chris Lattner//===--- Rewriter.cpp - Code rewriting interface --------------------------===//
28bd12b848bc353a9d34b54144c3dd3407b064292Chris Lattner//
38bd12b848bc353a9d34b54144c3dd3407b064292Chris Lattner//                     The LLVM Compiler Infrastructure
48bd12b848bc353a9d34b54144c3dd3407b064292Chris Lattner//
50bc735ffcfb223c0186419547abaa5c84482663eChris Lattner// This file is distributed under the University of Illinois Open Source
60bc735ffcfb223c0186419547abaa5c84482663eChris Lattner// License. See LICENSE.TXT for details.
78bd12b848bc353a9d34b54144c3dd3407b064292Chris Lattner//
88bd12b848bc353a9d34b54144c3dd3407b064292Chris Lattner//===----------------------------------------------------------------------===//
98bd12b848bc353a9d34b54144c3dd3407b064292Chris Lattner//
108bd12b848bc353a9d34b54144c3dd3407b064292Chris Lattner//  This file defines the Rewriter class, which is used for code
118bd12b848bc353a9d34b54144c3dd3407b064292Chris Lattner//  transformations.
128bd12b848bc353a9d34b54144c3dd3407b064292Chris Lattner//
138bd12b848bc353a9d34b54144c3dd3407b064292Chris Lattner//===----------------------------------------------------------------------===//
148bd12b848bc353a9d34b54144c3dd3407b064292Chris Lattner
15305c613af6cfc40e519c75d9d2c84c6fa9a841c0Ted Kremenek#include "clang/Rewrite/Core/Rewriter.h"
16176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines#include "clang/Basic/Diagnostic.h"
17bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek#include "clang/Basic/DiagnosticIDs.h"
18bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek#include "clang/Basic/FileManager.h"
198a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner#include "clang/Basic/SourceManager.h"
20bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek#include "clang/Lex/Lexer.h"
218fe83e1df954d72c0f4ffc15d20a5222ec151c21Benjamin Kramer#include "llvm/ADT/SmallString.h"
22c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines#include "llvm/Config/llvm-config.h"
23bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek#include "llvm/Support/FileSystem.h"
24a93d0f280693b8418bc88cf7a8c93325f7fcf4c6Benjamin Kramer#include "llvm/Support/raw_ostream.h"
258bd12b848bc353a9d34b54144c3dd3407b064292Chris Lattnerusing namespace clang;
268bd12b848bc353a9d34b54144c3dd3407b064292Chris Lattner
275f9e272e632e951b1efe824cd16acb4d96077930Chris Lattnerraw_ostream &RewriteBuffer::write(raw_ostream &os) const {
28651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // Walk RewriteRope chunks efficiently using MoveToNextPiece() instead of the
29651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // character iterator.
30651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  for (RopePieceBTreeIterator I = begin(), E = end(); I != E;
31651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines       I.MoveToNextPiece())
32651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    os << I.piece();
330ade808e0ac411baa2dbc1f76ad352b9b6d6d3f8Nick Lewycky  return os;
340ade808e0ac411baa2dbc1f76ad352b9b6d6d3f8Nick Lewycky}
350ade808e0ac411baa2dbc1f76ad352b9b6d6d3f8Nick Lewycky
36b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis/// \brief Return true if this character is non-new-line whitespace:
378c10f841040b1e2951d06d385c8eefbcbe578fcfJames Dennett/// ' ', '\\t', '\\f', '\\v', '\\r'.
38b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidisstatic inline bool isWhitespace(unsigned char c) {
39b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  switch (c) {
40b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  case ' ':
41b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  case '\t':
42b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  case '\f':
43b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  case '\v':
44b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  case '\r':
45b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis    return true;
46b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  default:
47b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis    return false;
48b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  }
49b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis}
50b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis
51b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidisvoid RewriteBuffer::RemoveText(unsigned OrigOffset, unsigned Size,
52b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis                               bool removeLineIfEmpty) {
537c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner  // Nothing to remove, exit early.
547c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner  if (Size == 0) return;
557c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner
567c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner  unsigned RealOffset = getMappedOffset(OrigOffset, true);
573ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar  assert(RealOffset+Size <= Buffer.size() && "Invalid location");
581eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
597c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner  // Remove the dead characters.
60febe719596ee68605944da5f2e03258e18e6df8cChris Lattner  Buffer.erase(RealOffset, Size);
617c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner
627c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner  // Add a delta so that future changes are offset correctly.
63a0978c24829dfd552d38fc3bae2b86e18bb90d49Eli Friedman  AddReplaceDelta(OrigOffset, -Size);
64b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis
65b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  if (removeLineIfEmpty) {
66b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis    // Find the line that the remove occurred and if it is completely empty
67b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis    // remove the line as well.
68b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis
69b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis    iterator curLineStart = begin();
70b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis    unsigned curLineStartOffs = 0;
71b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis    iterator posI = begin();
72b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis    for (unsigned i = 0; i != RealOffset; ++i) {
73b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis      if (*posI == '\n') {
74b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis        curLineStart = posI;
75b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis        ++curLineStart;
76b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis        curLineStartOffs = i + 1;
77b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis      }
78b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis      ++posI;
79b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis    }
80b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis
81b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis    unsigned lineSize = 0;
82b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis    posI = curLineStart;
83b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis    while (posI != end() && isWhitespace(*posI)) {
84b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis      ++posI;
85b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis      ++lineSize;
86b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis    }
87b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis    if (posI != end() && *posI == '\n') {
88b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis      Buffer.erase(curLineStartOffs, lineSize + 1/* + '\n'*/);
89b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis      AddReplaceDelta(curLineStartOffs, -(lineSize + 1/* + '\n'*/));
90b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis    }
91b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  }
928bd12b848bc353a9d34b54144c3dd3407b064292Chris Lattner}
938bd12b848bc353a9d34b54144c3dd3407b064292Chris Lattner
945f9e272e632e951b1efe824cd16acb4d96077930Chris Lattnervoid RewriteBuffer::InsertText(unsigned OrigOffset, StringRef Str,
95886c8db545170850f7806f47b5f6120864effd09Ted Kremenek                               bool InsertAfter) {
961eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
9703b071043593590b01fdf61df3e29c0ae7c067d3Chris Lattner  // Nothing to insert, exit early.
98d7407dc92c7d19cafce429e7e1cf9819d3fc0b92Daniel Dunbar  if (Str.empty()) return;
99febe719596ee68605944da5f2e03258e18e6df8cChris Lattner
100886c8db545170850f7806f47b5f6120864effd09Ted Kremenek  unsigned RealOffset = getMappedOffset(OrigOffset, InsertAfter);
101d7407dc92c7d19cafce429e7e1cf9819d3fc0b92Daniel Dunbar  Buffer.insert(RealOffset, Str.begin(), Str.end());
1021eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
10303b071043593590b01fdf61df3e29c0ae7c067d3Chris Lattner  // Add a delta so that future changes are offset correctly.
104d7407dc92c7d19cafce429e7e1cf9819d3fc0b92Daniel Dunbar  AddInsertDelta(OrigOffset, Str.size());
1058bd12b848bc353a9d34b54144c3dd3407b064292Chris Lattner}
1068a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner
1077c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner/// ReplaceText - This method replaces a range of characters in the input
108febe719596ee68605944da5f2e03258e18e6df8cChris Lattner/// buffer with a new string.  This is effectively a combined "remove+insert"
1097c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner/// operation.
1107c239606f3a7a685653a0a7e64459c3f43522666Chris Lattnervoid RewriteBuffer::ReplaceText(unsigned OrigOffset, unsigned OrigLength,
1115f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner                                StringRef NewStr) {
112a0978c24829dfd552d38fc3bae2b86e18bb90d49Eli Friedman  unsigned RealOffset = getMappedOffset(OrigOffset, true);
113febe719596ee68605944da5f2e03258e18e6df8cChris Lattner  Buffer.erase(RealOffset, OrigLength);
114d7407dc92c7d19cafce429e7e1cf9819d3fc0b92Daniel Dunbar  Buffer.insert(RealOffset, NewStr.begin(), NewStr.end());
115d7407dc92c7d19cafce429e7e1cf9819d3fc0b92Daniel Dunbar  if (OrigLength != NewStr.size())
116d7407dc92c7d19cafce429e7e1cf9819d3fc0b92Daniel Dunbar    AddReplaceDelta(OrigOffset, NewStr.size() - OrigLength);
1177c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner}
1188a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner
1198a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner
1208a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner//===----------------------------------------------------------------------===//
1218a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner// Rewriter class
1228a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner//===----------------------------------------------------------------------===//
1238a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner
124311ff02fae0392bee6abe7723cdf5a69b2899a47Chris Lattner/// getRangeSize - Return the size in bytes of the specified range if they
125311ff02fae0392bee6abe7723cdf5a69b2899a47Chris Lattner/// are in the same file.  If not, this returns -1.
126b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidisint Rewriter::getRangeSize(const CharSourceRange &Range,
127fd183ba0b16718ff05e161bc479678e447df4999Argyrios Kyrtzidis                           RewriteOptions opts) const {
128311ff02fae0392bee6abe7723cdf5a69b2899a47Chris Lattner  if (!isRewritable(Range.getBegin()) ||
129311ff02fae0392bee6abe7723cdf5a69b2899a47Chris Lattner      !isRewritable(Range.getEnd())) return -1;
1301eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
1312b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner  FileID StartFileID, EndFileID;
1322b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner  unsigned StartOff, EndOff;
1331eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
134311ff02fae0392bee6abe7723cdf5a69b2899a47Chris Lattner  StartOff = getLocationOffsetAndFileID(Range.getBegin(), StartFileID);
135311ff02fae0392bee6abe7723cdf5a69b2899a47Chris Lattner  EndOff   = getLocationOffsetAndFileID(Range.getEnd(), EndFileID);
1361eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
137311ff02fae0392bee6abe7723cdf5a69b2899a47Chris Lattner  if (StartFileID != EndFileID)
138311ff02fae0392bee6abe7723cdf5a69b2899a47Chris Lattner    return -1;
1391eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
140d6690b20b3340f30a225dffa49603951dcd75e4eChris Lattner  // If edits have been made to this buffer, the delta between the range may
141d6690b20b3340f30a225dffa49603951dcd75e4eChris Lattner  // have changed.
1422b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner  std::map<FileID, RewriteBuffer>::const_iterator I =
143075eb6eae0506e041e0086ddcab31ba2e55f0472Chris Lattner    RewriteBuffers.find(StartFileID);
144d6690b20b3340f30a225dffa49603951dcd75e4eChris Lattner  if (I != RewriteBuffers.end()) {
145075eb6eae0506e041e0086ddcab31ba2e55f0472Chris Lattner    const RewriteBuffer &RB = I->second;
146fd183ba0b16718ff05e161bc479678e447df4999Argyrios Kyrtzidis    EndOff = RB.getMappedOffset(EndOff, opts.IncludeInsertsAtEndOfRange);
147fd183ba0b16718ff05e161bc479678e447df4999Argyrios Kyrtzidis    StartOff = RB.getMappedOffset(StartOff, !opts.IncludeInsertsAtBeginOfRange);
148075eb6eae0506e041e0086ddcab31ba2e55f0472Chris Lattner  }
149075eb6eae0506e041e0086ddcab31ba2e55f0472Chris Lattner
1501eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
1519d62a5b31ec3762f416cc9ef89d1b7b433d13ac5Chris Lattner  // Adjust the end offset to the end of the last token, instead of being the
1520a76aae8c03cb7dd7bdbe683485560afaf695959Chris Lattner  // start of the last token if this is a token range.
1530a76aae8c03cb7dd7bdbe683485560afaf695959Chris Lattner  if (Range.isTokenRange())
1540a76aae8c03cb7dd7bdbe683485560afaf695959Chris Lattner    EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr, *LangOpts);
1551eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
156d6690b20b3340f30a225dffa49603951dcd75e4eChris Lattner  return EndOff-StartOff;
157311ff02fae0392bee6abe7723cdf5a69b2899a47Chris Lattner}
158311ff02fae0392bee6abe7723cdf5a69b2899a47Chris Lattner
159fd183ba0b16718ff05e161bc479678e447df4999Argyrios Kyrtzidisint Rewriter::getRangeSize(SourceRange Range, RewriteOptions opts) const {
160fd183ba0b16718ff05e161bc479678e447df4999Argyrios Kyrtzidis  return getRangeSize(CharSourceRange::getTokenRange(Range), opts);
1610a76aae8c03cb7dd7bdbe683485560afaf695959Chris Lattner}
1620a76aae8c03cb7dd7bdbe683485560afaf695959Chris Lattner
1630a76aae8c03cb7dd7bdbe683485560afaf695959Chris Lattner
1646a12a14a529a79524e17889046c7098b80a73c49Ted Kremenek/// getRewrittenText - Return the rewritten form of the text in the specified
165b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner/// range.  If the start or end of the range was unrewritable or if they are
1661eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump/// in different buffers, this returns an empty string.
167b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner///
168b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner/// Note that this method is not particularly efficient.
169b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner///
1706a12a14a529a79524e17889046c7098b80a73c49Ted Kremenekstd::string Rewriter::getRewrittenText(SourceRange Range) const {
171b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner  if (!isRewritable(Range.getBegin()) ||
172b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner      !isRewritable(Range.getEnd()))
173b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner    return "";
1741eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
1752b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner  FileID StartFileID, EndFileID;
1762b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner  unsigned StartOff, EndOff;
177b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner  StartOff = getLocationOffsetAndFileID(Range.getBegin(), StartFileID);
178b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner  EndOff   = getLocationOffsetAndFileID(Range.getEnd(), EndFileID);
1791eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
180b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner  if (StartFileID != EndFileID)
181b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner    return ""; // Start and end in different buffers.
1821eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
183b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner  // If edits have been made to this buffer, the delta between the range may
184b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner  // have changed.
1852b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner  std::map<FileID, RewriteBuffer>::const_iterator I =
186b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner    RewriteBuffers.find(StartFileID);
187b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner  if (I == RewriteBuffers.end()) {
188b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner    // If the buffer hasn't been rewritten, just return the text from the input.
189b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner    const char *Ptr = SourceMgr->getCharacterData(Range.getBegin());
1901eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
191b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner    // Adjust the end offset to the end of the last token, instead of being the
192b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner    // start of the last token.
1932c78b873f4f3823ae859c15674cb3d76c8554113Chris Lattner    EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr, *LangOpts);
194b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner    return std::string(Ptr, Ptr+EndOff-StartOff);
195b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner  }
1961eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
197b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner  const RewriteBuffer &RB = I->second;
198b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner  EndOff = RB.getMappedOffset(EndOff, true);
199b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner  StartOff = RB.getMappedOffset(StartOff);
2001eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
201b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner  // Adjust the end offset to the end of the last token, instead of being the
202b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner  // start of the last token.
2032c78b873f4f3823ae859c15674cb3d76c8554113Chris Lattner  EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr, *LangOpts);
204b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner
205b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner  // Advance the iterators to the right spot, yay for linear time algorithms.
206b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner  RewriteBuffer::iterator Start = RB.begin();
207b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner  std::advance(Start, StartOff);
208b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner  RewriteBuffer::iterator End = Start;
209b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner  std::advance(End, EndOff-StartOff);
2101eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
211b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner  return std::string(Start, End);
212b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner}
213311ff02fae0392bee6abe7723cdf5a69b2899a47Chris Lattner
2147c239606f3a7a685653a0a7e64459c3f43522666Chris Lattnerunsigned Rewriter::getLocationOffsetAndFileID(SourceLocation Loc,
2152b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner                                              FileID &FID) const {
21654bd7cb491cce1fb55ce1baac40cf7002a317166Chris Lattner  assert(Loc.isValid() && "Invalid location");
217de7aeefc5573d669ed476d7bda7a8940d3bcadb7Chris Lattner  std::pair<FileID,unsigned> V = SourceMgr->getDecomposedLoc(Loc);
2182b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner  FID = V.first;
2197c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner  return V.second;
2207c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner}
2217c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner
2227c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner
2238a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner/// getEditBuffer - Get or create a RewriteBuffer for the specified FileID.
2248a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner///
2252b2453a7d8fe732561795431f39ceb2b2a832d84Chris LattnerRewriteBuffer &Rewriter::getEditBuffer(FileID FID) {
2262b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner  std::map<FileID, RewriteBuffer>::iterator I =
2272b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner    RewriteBuffers.lower_bound(FID);
2281eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump  if (I != RewriteBuffers.end() && I->first == FID)
2298a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner    return I->second;
2302b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner  I = RewriteBuffers.insert(I, std::make_pair(FID, RewriteBuffer()));
2311eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2325f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner  StringRef MB = SourceMgr->getBufferData(FID);
233f6ac97b101c8840efa92bf29166077ce4049e293Benjamin Kramer  I->second.Initialize(MB.begin(), MB.end());
2341eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2358a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner  return I->second;
2368a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner}
2378a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner
23854a2f071a37ee63d3ef1d4e7ca2570542ee12115Chris Lattner/// InsertText - Insert the specified string at the specified location in the
239aadaf78d65daef3ac1b45e4ad6136ce859962fe2Chris Lattner/// original buffer.
2405f9e272e632e951b1efe824cd16acb4d96077930Chris Lattnerbool Rewriter::InsertText(SourceLocation Loc, StringRef Str,
241f85e193739c953358c865005855253af4f68a497John McCall                          bool InsertAfter, bool indentNewLines) {
242dcbc5b0b0722282a0fdd829359fe0d7e22adb882Chris Lattner  if (!isRewritable(Loc)) return true;
2432b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner  FileID FID;
2442b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner  unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID);
245f85e193739c953358c865005855253af4f68a497John McCall
246f7ccbad5d9949e7ddd1cbef43d482553b811e026Dylan Noblesmith  SmallString<128> indentedStr;
247f85e193739c953358c865005855253af4f68a497John McCall  if (indentNewLines && Str.find('\n') != StringRef::npos) {
248f85e193739c953358c865005855253af4f68a497John McCall    StringRef MB = SourceMgr->getBufferData(FID);
249f85e193739c953358c865005855253af4f68a497John McCall
250f85e193739c953358c865005855253af4f68a497John McCall    unsigned lineNo = SourceMgr->getLineNumber(FID, StartOffs) - 1;
251f85e193739c953358c865005855253af4f68a497John McCall    const SrcMgr::ContentCache *
252f85e193739c953358c865005855253af4f68a497John McCall        Content = SourceMgr->getSLocEntry(FID).getFile().getContentCache();
253f85e193739c953358c865005855253af4f68a497John McCall    unsigned lineOffs = Content->SourceLineCache[lineNo];
254f85e193739c953358c865005855253af4f68a497John McCall
255f85e193739c953358c865005855253af4f68a497John McCall    // Find the whitespace at the start of the line.
256f85e193739c953358c865005855253af4f68a497John McCall    StringRef indentSpace;
257f85e193739c953358c865005855253af4f68a497John McCall    {
258f85e193739c953358c865005855253af4f68a497John McCall      unsigned i = lineOffs;
259f85e193739c953358c865005855253af4f68a497John McCall      while (isWhitespace(MB[i]))
260f85e193739c953358c865005855253af4f68a497John McCall        ++i;
261f85e193739c953358c865005855253af4f68a497John McCall      indentSpace = MB.substr(lineOffs, i-lineOffs);
262f85e193739c953358c865005855253af4f68a497John McCall    }
263f85e193739c953358c865005855253af4f68a497John McCall
2645f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner    SmallVector<StringRef, 4> lines;
265f85e193739c953358c865005855253af4f68a497John McCall    Str.split(lines, "\n");
266f85e193739c953358c865005855253af4f68a497John McCall
267f85e193739c953358c865005855253af4f68a497John McCall    for (unsigned i = 0, e = lines.size(); i != e; ++i) {
268f85e193739c953358c865005855253af4f68a497John McCall      indentedStr += lines[i];
269f85e193739c953358c865005855253af4f68a497John McCall      if (i < e-1) {
270f85e193739c953358c865005855253af4f68a497John McCall        indentedStr += '\n';
271f85e193739c953358c865005855253af4f68a497John McCall        indentedStr += indentSpace;
272f85e193739c953358c865005855253af4f68a497John McCall      }
273f85e193739c953358c865005855253af4f68a497John McCall    }
274f85e193739c953358c865005855253af4f68a497John McCall    Str = indentedStr.str();
275f85e193739c953358c865005855253af4f68a497John McCall  }
276f85e193739c953358c865005855253af4f68a497John McCall
277d7407dc92c7d19cafce429e7e1cf9819d3fc0b92Daniel Dunbar  getEditBuffer(FID).InsertText(StartOffs, Str, InsertAfter);
278dcbc5b0b0722282a0fdd829359fe0d7e22adb882Chris Lattner  return false;
27954a2f071a37ee63d3ef1d4e7ca2570542ee12115Chris Lattner}
28054a2f071a37ee63d3ef1d4e7ca2570542ee12115Chris Lattner
2815f9e272e632e951b1efe824cd16acb4d96077930Chris Lattnerbool Rewriter::InsertTextAfterToken(SourceLocation Loc, StringRef Str) {
282b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  if (!isRewritable(Loc)) return true;
283b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  FileID FID;
284b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID);
285fd183ba0b16718ff05e161bc479678e447df4999Argyrios Kyrtzidis  RewriteOptions rangeOpts;
286fd183ba0b16718ff05e161bc479678e447df4999Argyrios Kyrtzidis  rangeOpts.IncludeInsertsAtBeginOfRange = false;
287fd183ba0b16718ff05e161bc479678e447df4999Argyrios Kyrtzidis  StartOffs += getRangeSize(SourceRange(Loc, Loc), rangeOpts);
288b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  getEditBuffer(FID).InsertText(StartOffs, Str, /*InsertAfter*/true);
289b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  return false;
290b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis}
291b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis
292aadaf78d65daef3ac1b45e4ad6136ce859962fe2Chris Lattner/// RemoveText - Remove the specified text region.
293b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidisbool Rewriter::RemoveText(SourceLocation Start, unsigned Length,
294fd183ba0b16718ff05e161bc479678e447df4999Argyrios Kyrtzidis                          RewriteOptions opts) {
295aadaf78d65daef3ac1b45e4ad6136ce859962fe2Chris Lattner  if (!isRewritable(Start)) return true;
2962b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner  FileID FID;
2972b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner  unsigned StartOffs = getLocationOffsetAndFileID(Start, FID);
298fd183ba0b16718ff05e161bc479678e447df4999Argyrios Kyrtzidis  getEditBuffer(FID).RemoveText(StartOffs, Length, opts.RemoveLineIfEmpty);
299aadaf78d65daef3ac1b45e4ad6136ce859962fe2Chris Lattner  return false;
300674af9541256dc3ef803e3723027a8b028f1f7a2Chris Lattner}
3018a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner
302674af9541256dc3ef803e3723027a8b028f1f7a2Chris Lattner/// ReplaceText - This method replaces a range of characters in the input
303674af9541256dc3ef803e3723027a8b028f1f7a2Chris Lattner/// buffer with a new string.  This is effectively a combined "remove/insert"
304674af9541256dc3ef803e3723027a8b028f1f7a2Chris Lattner/// operation.
305aadaf78d65daef3ac1b45e4ad6136ce859962fe2Chris Lattnerbool Rewriter::ReplaceText(SourceLocation Start, unsigned OrigLength,
3065f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner                           StringRef NewStr) {
307aadaf78d65daef3ac1b45e4ad6136ce859962fe2Chris Lattner  if (!isRewritable(Start)) return true;
3082b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner  FileID StartFileID;
3097c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner  unsigned StartOffs = getLocationOffsetAndFileID(Start, StartFileID);
3101eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
311d7407dc92c7d19cafce429e7e1cf9819d3fc0b92Daniel Dunbar  getEditBuffer(StartFileID).ReplaceText(StartOffs, OrigLength, NewStr);
312aadaf78d65daef3ac1b45e4ad6136ce859962fe2Chris Lattner  return false;
3138a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner}
31401c5748c29e75b29cab5fc7d8ad1b173b29c7ecfChris Lattner
315b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidisbool Rewriter::ReplaceText(SourceRange range, SourceRange replacementRange) {
316b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  if (!isRewritable(range.getBegin())) return true;
317b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  if (!isRewritable(range.getEnd())) return true;
318b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  if (replacementRange.isInvalid()) return true;
319b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  SourceLocation start = range.getBegin();
320b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  unsigned origLength = getRangeSize(range);
321b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  unsigned newLength = getRangeSize(replacementRange);
322b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  FileID FID;
323b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  unsigned newOffs = getLocationOffsetAndFileID(replacementRange.getBegin(),
324b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis                                                FID);
3255f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner  StringRef MB = SourceMgr->getBufferData(FID);
326b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  return ReplaceText(start, origLength, MB.substr(newOffs, newLength));
327b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis}
328b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis
32910c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidisbool Rewriter::IncreaseIndentation(CharSourceRange range,
33010c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis                                   SourceLocation parentIndent) {
331f85e193739c953358c865005855253af4f68a497John McCall  if (range.isInvalid()) return true;
33210c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  if (!isRewritable(range.getBegin())) return true;
33310c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  if (!isRewritable(range.getEnd())) return true;
33410c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  if (!isRewritable(parentIndent)) return true;
33510c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis
33610c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  FileID StartFileID, EndFileID, parentFileID;
33710c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  unsigned StartOff, EndOff, parentOff;
33810c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis
33910c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  StartOff = getLocationOffsetAndFileID(range.getBegin(), StartFileID);
34010c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  EndOff   = getLocationOffsetAndFileID(range.getEnd(), EndFileID);
34110c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  parentOff = getLocationOffsetAndFileID(parentIndent, parentFileID);
34210c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis
34310c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  if (StartFileID != EndFileID || StartFileID != parentFileID)
34410c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis    return true;
345f85e193739c953358c865005855253af4f68a497John McCall  if (StartOff > EndOff)
34610c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis    return true;
34710c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis
34810c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  FileID FID = StartFileID;
34910c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  StringRef MB = SourceMgr->getBufferData(FID);
35010c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis
35110c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  unsigned parentLineNo = SourceMgr->getLineNumber(FID, parentOff) - 1;
35210c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  unsigned startLineNo = SourceMgr->getLineNumber(FID, StartOff) - 1;
35310c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  unsigned endLineNo = SourceMgr->getLineNumber(FID, EndOff) - 1;
35410c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis
35510c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  const SrcMgr::ContentCache *
35610c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis      Content = SourceMgr->getSLocEntry(FID).getFile().getContentCache();
35710c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis
358f85e193739c953358c865005855253af4f68a497John McCall  // Find where the lines start.
35910c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  unsigned parentLineOffs = Content->SourceLineCache[parentLineNo];
36010c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  unsigned startLineOffs = Content->SourceLineCache[startLineNo];
36110c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis
36210c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  // Find the whitespace at the start of each line.
363f85e193739c953358c865005855253af4f68a497John McCall  StringRef parentSpace, startSpace;
36410c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  {
36510c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis    unsigned i = parentLineOffs;
36610c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis    while (isWhitespace(MB[i]))
36710c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis      ++i;
36810c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis    parentSpace = MB.substr(parentLineOffs, i-parentLineOffs);
36910c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis
37010c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis    i = startLineOffs;
37110c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis    while (isWhitespace(MB[i]))
37210c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis      ++i;
37310c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis    startSpace = MB.substr(startLineOffs, i-startLineOffs);
37410c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  }
37510c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  if (parentSpace.size() >= startSpace.size())
37610c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis    return true;
37710c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  if (!startSpace.startswith(parentSpace))
37810c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis    return true;
37910c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis
3805f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner  StringRef indent = startSpace.substr(parentSpace.size());
38110c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis
38210c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  // Indent the lines between start/end offsets.
38310c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  RewriteBuffer &RB = getEditBuffer(FID);
384f85e193739c953358c865005855253af4f68a497John McCall  for (unsigned lineNo = startLineNo; lineNo <= endLineNo; ++lineNo) {
385f85e193739c953358c865005855253af4f68a497John McCall    unsigned offs = Content->SourceLineCache[lineNo];
386f85e193739c953358c865005855253af4f68a497John McCall    unsigned i = offs;
387f85e193739c953358c865005855253af4f68a497John McCall    while (isWhitespace(MB[i]))
388f85e193739c953358c865005855253af4f68a497John McCall      ++i;
389f85e193739c953358c865005855253af4f68a497John McCall    StringRef origIndent = MB.substr(offs, i-offs);
390f85e193739c953358c865005855253af4f68a497John McCall    if (origIndent.startswith(startSpace))
391f85e193739c953358c865005855253af4f68a497John McCall      RB.InsertText(offs, indent, /*InsertAfter=*/false);
39210c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  }
39310c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis
39410c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  return false;
39510c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis}
396bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek
397c2b914fb6fed213a7e7d9847e543f1e7f94d852dBenjamin Kramernamespace {
398bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek// A wrapper for a file stream that atomically overwrites the target.
399bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek//
400bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek// Creates a file output stream for a temporary file in the constructor,
401bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek// which is later accessible via getStream() if ok() return true.
402bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek// Flushes the stream and moves the temporary file to the target location
403bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek// in the destructor.
404bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimekclass AtomicallyMovedFile {
405bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimekpublic:
406bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  AtomicallyMovedFile(DiagnosticsEngine &Diagnostics, StringRef Filename,
407bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek                      bool &AllWritten)
408bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    : Diagnostics(Diagnostics), Filename(Filename), AllWritten(AllWritten) {
409bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    TempFilename = Filename;
410bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    TempFilename += "-%%%%%%%%";
411bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    int FD;
41270e7aeccbf5856a84f81366c6c1a0c0c01e70063Rafael Espindola    if (llvm::sys::fs::createUniqueFile(TempFilename.str(), FD, TempFilename)) {
413bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek      AllWritten = false;
414bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek      Diagnostics.Report(clang::diag::err_unable_to_make_temp)
415bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek        << TempFilename;
416bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    } else {
417bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek      FileStream.reset(new llvm::raw_fd_ostream(FD, /*shouldClose=*/true));
418bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    }
419bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  }
420bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek
421bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  ~AtomicallyMovedFile() {
422bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    if (!ok()) return;
423bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek
424bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    FileStream->flush();
425651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#ifdef LLVM_ON_WIN32
4262d9c4dfad1f58c42a31721054cd99218d9ac3d52NAKAMURA Takumi    // Win32 does not allow rename/removing opened files.
4272d9c4dfad1f58c42a31721054cd99218d9ac3d52NAKAMURA Takumi    FileStream.reset();
4282d9c4dfad1f58c42a31721054cd99218d9ac3d52NAKAMURA Takumi#endif
429c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    if (std::error_code ec =
430c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines            llvm::sys::fs::rename(TempFilename.str(), Filename)) {
431bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek      AllWritten = false;
432bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek      Diagnostics.Report(clang::diag::err_unable_to_rename_temp)
433bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek        << TempFilename << Filename << ec.message();
434bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek      // If the remove fails, there's not a lot we can do - this is already an
435bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek      // error.
436651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      llvm::sys::fs::remove(TempFilename.str());
437bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    }
438bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  }
439bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek
440651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  bool ok() { return (bool)FileStream; }
441cfa88f893915ceb8ae4ce2f17c46c24a4d67502fDmitri Gribenko  raw_ostream &getStream() { return *FileStream; }
442bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek
443bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimekprivate:
444bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  DiagnosticsEngine &Diagnostics;
445bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  StringRef Filename;
446bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  SmallString<128> TempFilename;
447651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  std::unique_ptr<llvm::raw_fd_ostream> FileStream;
448bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  bool &AllWritten;
449bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek};
450c2b914fb6fed213a7e7d9847e543f1e7f94d852dBenjamin Kramer} // end anonymous namespace
451bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek
452bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimekbool Rewriter::overwriteChangedFiles() {
453bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  bool AllWritten = true;
454bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  for (buffer_iterator I = buffer_begin(), E = buffer_end(); I != E; ++I) {
455bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    const FileEntry *Entry =
456bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek        getSourceMgr().getFileEntryForID(I->first);
457bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    AtomicallyMovedFile File(getSourceMgr().getDiagnostics(), Entry->getName(),
458bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek                             AllWritten);
459bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    if (File.ok()) {
460bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek      I->second.write(File.getStream());
461bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    }
462bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  }
463bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  return !AllWritten;
464bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek}
465