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"
1601c5748c29e75b29cab5fc7d8ad1b173b29c7ecfChris Lattner#include "clang/AST/Stmt.h"
172c3352b5d1f5f4546af2f3051a304d84d57c697eTed Kremenek#include "clang/AST/Decl.h"
18bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek#include "clang/Basic/DiagnosticIDs.h"
19bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek#include "clang/Basic/FileManager.h"
208a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner#include "clang/Basic/SourceManager.h"
21bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek#include "clang/Lex/Lexer.h"
228fe83e1df954d72c0f4ffc15d20a5222ec151c21Benjamin Kramer#include "llvm/ADT/SmallString.h"
23bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek#include "llvm/Support/FileSystem.h"
248bd12b848bc353a9d34b54144c3dd3407b064292Chris Lattnerusing namespace clang;
258bd12b848bc353a9d34b54144c3dd3407b064292Chris Lattner
265f9e272e632e951b1efe824cd16acb4d96077930Chris Lattnerraw_ostream &RewriteBuffer::write(raw_ostream &os) const {
270ade808e0ac411baa2dbc1f76ad352b9b6d6d3f8Nick Lewycky  // FIXME: eliminate the copy by writing out each chunk at a time
280ade808e0ac411baa2dbc1f76ad352b9b6d6d3f8Nick Lewycky  os << std::string(begin(), end());
290ade808e0ac411baa2dbc1f76ad352b9b6d6d3f8Nick Lewycky  return os;
300ade808e0ac411baa2dbc1f76ad352b9b6d6d3f8Nick Lewycky}
310ade808e0ac411baa2dbc1f76ad352b9b6d6d3f8Nick Lewycky
32b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis/// \brief Return true if this character is non-new-line whitespace:
338c10f841040b1e2951d06d385c8eefbcbe578fcfJames Dennett/// ' ', '\\t', '\\f', '\\v', '\\r'.
34b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidisstatic inline bool isWhitespace(unsigned char c) {
35b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  switch (c) {
36b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  case ' ':
37b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  case '\t':
38b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  case '\f':
39b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  case '\v':
40b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  case '\r':
41b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis    return true;
42b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  default:
43b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis    return false;
44b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  }
45b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis}
46b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis
47b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidisvoid RewriteBuffer::RemoveText(unsigned OrigOffset, unsigned Size,
48b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis                               bool removeLineIfEmpty) {
497c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner  // Nothing to remove, exit early.
507c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner  if (Size == 0) return;
517c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner
527c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner  unsigned RealOffset = getMappedOffset(OrigOffset, true);
537c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner  assert(RealOffset+Size < Buffer.size() && "Invalid location");
541eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
557c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner  // Remove the dead characters.
56febe719596ee68605944da5f2e03258e18e6df8cChris Lattner  Buffer.erase(RealOffset, Size);
577c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner
587c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner  // Add a delta so that future changes are offset correctly.
59a0978c24829dfd552d38fc3bae2b86e18bb90d49Eli Friedman  AddReplaceDelta(OrigOffset, -Size);
60b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis
61b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  if (removeLineIfEmpty) {
62b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis    // Find the line that the remove occurred and if it is completely empty
63b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis    // remove the line as well.
64b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis
65b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis    iterator curLineStart = begin();
66b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis    unsigned curLineStartOffs = 0;
67b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis    iterator posI = begin();
68b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis    for (unsigned i = 0; i != RealOffset; ++i) {
69b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis      if (*posI == '\n') {
70b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis        curLineStart = posI;
71b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis        ++curLineStart;
72b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis        curLineStartOffs = i + 1;
73b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis      }
74b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis      ++posI;
75b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis    }
76b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis
77b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis    unsigned lineSize = 0;
78b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis    posI = curLineStart;
79b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis    while (posI != end() && isWhitespace(*posI)) {
80b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis      ++posI;
81b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis      ++lineSize;
82b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis    }
83b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis    if (posI != end() && *posI == '\n') {
84b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis      Buffer.erase(curLineStartOffs, lineSize + 1/* + '\n'*/);
85b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis      AddReplaceDelta(curLineStartOffs, -(lineSize + 1/* + '\n'*/));
86b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis    }
87b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  }
888bd12b848bc353a9d34b54144c3dd3407b064292Chris Lattner}
898bd12b848bc353a9d34b54144c3dd3407b064292Chris Lattner
905f9e272e632e951b1efe824cd16acb4d96077930Chris Lattnervoid RewriteBuffer::InsertText(unsigned OrigOffset, StringRef Str,
91886c8db545170850f7806f47b5f6120864effd09Ted Kremenek                               bool InsertAfter) {
921eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
9303b071043593590b01fdf61df3e29c0ae7c067d3Chris Lattner  // Nothing to insert, exit early.
94d7407dc92c7d19cafce429e7e1cf9819d3fc0b92Daniel Dunbar  if (Str.empty()) return;
95febe719596ee68605944da5f2e03258e18e6df8cChris Lattner
96886c8db545170850f7806f47b5f6120864effd09Ted Kremenek  unsigned RealOffset = getMappedOffset(OrigOffset, InsertAfter);
97d7407dc92c7d19cafce429e7e1cf9819d3fc0b92Daniel Dunbar  Buffer.insert(RealOffset, Str.begin(), Str.end());
981eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
9903b071043593590b01fdf61df3e29c0ae7c067d3Chris Lattner  // Add a delta so that future changes are offset correctly.
100d7407dc92c7d19cafce429e7e1cf9819d3fc0b92Daniel Dunbar  AddInsertDelta(OrigOffset, Str.size());
1018bd12b848bc353a9d34b54144c3dd3407b064292Chris Lattner}
1028a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner
1037c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner/// ReplaceText - This method replaces a range of characters in the input
104febe719596ee68605944da5f2e03258e18e6df8cChris Lattner/// buffer with a new string.  This is effectively a combined "remove+insert"
1057c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner/// operation.
1067c239606f3a7a685653a0a7e64459c3f43522666Chris Lattnervoid RewriteBuffer::ReplaceText(unsigned OrigOffset, unsigned OrigLength,
1075f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner                                StringRef NewStr) {
108a0978c24829dfd552d38fc3bae2b86e18bb90d49Eli Friedman  unsigned RealOffset = getMappedOffset(OrigOffset, true);
109febe719596ee68605944da5f2e03258e18e6df8cChris Lattner  Buffer.erase(RealOffset, OrigLength);
110d7407dc92c7d19cafce429e7e1cf9819d3fc0b92Daniel Dunbar  Buffer.insert(RealOffset, NewStr.begin(), NewStr.end());
111d7407dc92c7d19cafce429e7e1cf9819d3fc0b92Daniel Dunbar  if (OrigLength != NewStr.size())
112d7407dc92c7d19cafce429e7e1cf9819d3fc0b92Daniel Dunbar    AddReplaceDelta(OrigOffset, NewStr.size() - OrigLength);
1137c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner}
1148a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner
1158a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner
1168a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner//===----------------------------------------------------------------------===//
1178a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner// Rewriter class
1188a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner//===----------------------------------------------------------------------===//
1198a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner
120311ff02fae0392bee6abe7723cdf5a69b2899a47Chris Lattner/// getRangeSize - Return the size in bytes of the specified range if they
121311ff02fae0392bee6abe7723cdf5a69b2899a47Chris Lattner/// are in the same file.  If not, this returns -1.
122b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidisint Rewriter::getRangeSize(const CharSourceRange &Range,
123fd183ba0b16718ff05e161bc479678e447df4999Argyrios Kyrtzidis                           RewriteOptions opts) const {
124311ff02fae0392bee6abe7723cdf5a69b2899a47Chris Lattner  if (!isRewritable(Range.getBegin()) ||
125311ff02fae0392bee6abe7723cdf5a69b2899a47Chris Lattner      !isRewritable(Range.getEnd())) return -1;
1261eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
1272b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner  FileID StartFileID, EndFileID;
1282b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner  unsigned StartOff, EndOff;
1291eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
130311ff02fae0392bee6abe7723cdf5a69b2899a47Chris Lattner  StartOff = getLocationOffsetAndFileID(Range.getBegin(), StartFileID);
131311ff02fae0392bee6abe7723cdf5a69b2899a47Chris Lattner  EndOff   = getLocationOffsetAndFileID(Range.getEnd(), EndFileID);
1321eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
133311ff02fae0392bee6abe7723cdf5a69b2899a47Chris Lattner  if (StartFileID != EndFileID)
134311ff02fae0392bee6abe7723cdf5a69b2899a47Chris Lattner    return -1;
1351eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
136d6690b20b3340f30a225dffa49603951dcd75e4eChris Lattner  // If edits have been made to this buffer, the delta between the range may
137d6690b20b3340f30a225dffa49603951dcd75e4eChris Lattner  // have changed.
1382b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner  std::map<FileID, RewriteBuffer>::const_iterator I =
139075eb6eae0506e041e0086ddcab31ba2e55f0472Chris Lattner    RewriteBuffers.find(StartFileID);
140d6690b20b3340f30a225dffa49603951dcd75e4eChris Lattner  if (I != RewriteBuffers.end()) {
141075eb6eae0506e041e0086ddcab31ba2e55f0472Chris Lattner    const RewriteBuffer &RB = I->second;
142fd183ba0b16718ff05e161bc479678e447df4999Argyrios Kyrtzidis    EndOff = RB.getMappedOffset(EndOff, opts.IncludeInsertsAtEndOfRange);
143fd183ba0b16718ff05e161bc479678e447df4999Argyrios Kyrtzidis    StartOff = RB.getMappedOffset(StartOff, !opts.IncludeInsertsAtBeginOfRange);
144075eb6eae0506e041e0086ddcab31ba2e55f0472Chris Lattner  }
145075eb6eae0506e041e0086ddcab31ba2e55f0472Chris Lattner
1461eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
1479d62a5b31ec3762f416cc9ef89d1b7b433d13ac5Chris Lattner  // Adjust the end offset to the end of the last token, instead of being the
1480a76aae8c03cb7dd7bdbe683485560afaf695959Chris Lattner  // start of the last token if this is a token range.
1490a76aae8c03cb7dd7bdbe683485560afaf695959Chris Lattner  if (Range.isTokenRange())
1500a76aae8c03cb7dd7bdbe683485560afaf695959Chris Lattner    EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr, *LangOpts);
1511eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
152d6690b20b3340f30a225dffa49603951dcd75e4eChris Lattner  return EndOff-StartOff;
153311ff02fae0392bee6abe7723cdf5a69b2899a47Chris Lattner}
154311ff02fae0392bee6abe7723cdf5a69b2899a47Chris Lattner
155fd183ba0b16718ff05e161bc479678e447df4999Argyrios Kyrtzidisint Rewriter::getRangeSize(SourceRange Range, RewriteOptions opts) const {
156fd183ba0b16718ff05e161bc479678e447df4999Argyrios Kyrtzidis  return getRangeSize(CharSourceRange::getTokenRange(Range), opts);
1570a76aae8c03cb7dd7bdbe683485560afaf695959Chris Lattner}
1580a76aae8c03cb7dd7bdbe683485560afaf695959Chris Lattner
1590a76aae8c03cb7dd7bdbe683485560afaf695959Chris Lattner
1606a12a14a529a79524e17889046c7098b80a73c49Ted Kremenek/// getRewrittenText - Return the rewritten form of the text in the specified
161b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner/// range.  If the start or end of the range was unrewritable or if they are
1621eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump/// in different buffers, this returns an empty string.
163b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner///
164b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner/// Note that this method is not particularly efficient.
165b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner///
1666a12a14a529a79524e17889046c7098b80a73c49Ted Kremenekstd::string Rewriter::getRewrittenText(SourceRange Range) const {
167b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner  if (!isRewritable(Range.getBegin()) ||
168b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner      !isRewritable(Range.getEnd()))
169b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner    return "";
1701eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
1712b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner  FileID StartFileID, EndFileID;
1722b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner  unsigned StartOff, EndOff;
173b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner  StartOff = getLocationOffsetAndFileID(Range.getBegin(), StartFileID);
174b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner  EndOff   = getLocationOffsetAndFileID(Range.getEnd(), EndFileID);
1751eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
176b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner  if (StartFileID != EndFileID)
177b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner    return ""; // Start and end in different buffers.
1781eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
179b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner  // If edits have been made to this buffer, the delta between the range may
180b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner  // have changed.
1812b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner  std::map<FileID, RewriteBuffer>::const_iterator I =
182b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner    RewriteBuffers.find(StartFileID);
183b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner  if (I == RewriteBuffers.end()) {
184b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner    // If the buffer hasn't been rewritten, just return the text from the input.
185b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner    const char *Ptr = SourceMgr->getCharacterData(Range.getBegin());
1861eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
187b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner    // Adjust the end offset to the end of the last token, instead of being the
188b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner    // start of the last token.
1892c78b873f4f3823ae859c15674cb3d76c8554113Chris Lattner    EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr, *LangOpts);
190b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner    return std::string(Ptr, Ptr+EndOff-StartOff);
191b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner  }
1921eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
193b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner  const RewriteBuffer &RB = I->second;
194b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner  EndOff = RB.getMappedOffset(EndOff, true);
195b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner  StartOff = RB.getMappedOffset(StartOff);
1961eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
197b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner  // Adjust the end offset to the end of the last token, instead of being the
198b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner  // start of the last token.
1992c78b873f4f3823ae859c15674cb3d76c8554113Chris Lattner  EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr, *LangOpts);
200b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner
201b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner  // Advance the iterators to the right spot, yay for linear time algorithms.
202b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner  RewriteBuffer::iterator Start = RB.begin();
203b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner  std::advance(Start, StartOff);
204b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner  RewriteBuffer::iterator End = Start;
205b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner  std::advance(End, EndOff-StartOff);
2061eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
207b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner  return std::string(Start, End);
208b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner}
209311ff02fae0392bee6abe7723cdf5a69b2899a47Chris Lattner
2107c239606f3a7a685653a0a7e64459c3f43522666Chris Lattnerunsigned Rewriter::getLocationOffsetAndFileID(SourceLocation Loc,
2112b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner                                              FileID &FID) const {
21254bd7cb491cce1fb55ce1baac40cf7002a317166Chris Lattner  assert(Loc.isValid() && "Invalid location");
213de7aeefc5573d669ed476d7bda7a8940d3bcadb7Chris Lattner  std::pair<FileID,unsigned> V = SourceMgr->getDecomposedLoc(Loc);
2142b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner  FID = V.first;
2157c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner  return V.second;
2167c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner}
2177c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner
2187c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner
2198a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner/// getEditBuffer - Get or create a RewriteBuffer for the specified FileID.
2208a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner///
2212b2453a7d8fe732561795431f39ceb2b2a832d84Chris LattnerRewriteBuffer &Rewriter::getEditBuffer(FileID FID) {
2222b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner  std::map<FileID, RewriteBuffer>::iterator I =
2232b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner    RewriteBuffers.lower_bound(FID);
2241eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump  if (I != RewriteBuffers.end() && I->first == FID)
2258a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner    return I->second;
2262b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner  I = RewriteBuffers.insert(I, std::make_pair(FID, RewriteBuffer()));
2271eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2285f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner  StringRef MB = SourceMgr->getBufferData(FID);
229f6ac97b101c8840efa92bf29166077ce4049e293Benjamin Kramer  I->second.Initialize(MB.begin(), MB.end());
2301eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2318a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner  return I->second;
2328a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner}
2338a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner
23454a2f071a37ee63d3ef1d4e7ca2570542ee12115Chris Lattner/// InsertText - Insert the specified string at the specified location in the
235aadaf78d65daef3ac1b45e4ad6136ce859962fe2Chris Lattner/// original buffer.
2365f9e272e632e951b1efe824cd16acb4d96077930Chris Lattnerbool Rewriter::InsertText(SourceLocation Loc, StringRef Str,
237f85e193739c953358c865005855253af4f68a497John McCall                          bool InsertAfter, bool indentNewLines) {
238dcbc5b0b0722282a0fdd829359fe0d7e22adb882Chris Lattner  if (!isRewritable(Loc)) return true;
2392b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner  FileID FID;
2402b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner  unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID);
241f85e193739c953358c865005855253af4f68a497John McCall
242f7ccbad5d9949e7ddd1cbef43d482553b811e026Dylan Noblesmith  SmallString<128> indentedStr;
243f85e193739c953358c865005855253af4f68a497John McCall  if (indentNewLines && Str.find('\n') != StringRef::npos) {
244f85e193739c953358c865005855253af4f68a497John McCall    StringRef MB = SourceMgr->getBufferData(FID);
245f85e193739c953358c865005855253af4f68a497John McCall
246f85e193739c953358c865005855253af4f68a497John McCall    unsigned lineNo = SourceMgr->getLineNumber(FID, StartOffs) - 1;
247f85e193739c953358c865005855253af4f68a497John McCall    const SrcMgr::ContentCache *
248f85e193739c953358c865005855253af4f68a497John McCall        Content = SourceMgr->getSLocEntry(FID).getFile().getContentCache();
249f85e193739c953358c865005855253af4f68a497John McCall    unsigned lineOffs = Content->SourceLineCache[lineNo];
250f85e193739c953358c865005855253af4f68a497John McCall
251f85e193739c953358c865005855253af4f68a497John McCall    // Find the whitespace at the start of the line.
252f85e193739c953358c865005855253af4f68a497John McCall    StringRef indentSpace;
253f85e193739c953358c865005855253af4f68a497John McCall    {
254f85e193739c953358c865005855253af4f68a497John McCall      unsigned i = lineOffs;
255f85e193739c953358c865005855253af4f68a497John McCall      while (isWhitespace(MB[i]))
256f85e193739c953358c865005855253af4f68a497John McCall        ++i;
257f85e193739c953358c865005855253af4f68a497John McCall      indentSpace = MB.substr(lineOffs, i-lineOffs);
258f85e193739c953358c865005855253af4f68a497John McCall    }
259f85e193739c953358c865005855253af4f68a497John McCall
2605f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner    SmallVector<StringRef, 4> lines;
261f85e193739c953358c865005855253af4f68a497John McCall    Str.split(lines, "\n");
262f85e193739c953358c865005855253af4f68a497John McCall
263f85e193739c953358c865005855253af4f68a497John McCall    for (unsigned i = 0, e = lines.size(); i != e; ++i) {
264f85e193739c953358c865005855253af4f68a497John McCall      indentedStr += lines[i];
265f85e193739c953358c865005855253af4f68a497John McCall      if (i < e-1) {
266f85e193739c953358c865005855253af4f68a497John McCall        indentedStr += '\n';
267f85e193739c953358c865005855253af4f68a497John McCall        indentedStr += indentSpace;
268f85e193739c953358c865005855253af4f68a497John McCall      }
269f85e193739c953358c865005855253af4f68a497John McCall    }
270f85e193739c953358c865005855253af4f68a497John McCall    Str = indentedStr.str();
271f85e193739c953358c865005855253af4f68a497John McCall  }
272f85e193739c953358c865005855253af4f68a497John McCall
273d7407dc92c7d19cafce429e7e1cf9819d3fc0b92Daniel Dunbar  getEditBuffer(FID).InsertText(StartOffs, Str, InsertAfter);
274dcbc5b0b0722282a0fdd829359fe0d7e22adb882Chris Lattner  return false;
27554a2f071a37ee63d3ef1d4e7ca2570542ee12115Chris Lattner}
27654a2f071a37ee63d3ef1d4e7ca2570542ee12115Chris Lattner
2775f9e272e632e951b1efe824cd16acb4d96077930Chris Lattnerbool Rewriter::InsertTextAfterToken(SourceLocation Loc, StringRef Str) {
278b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  if (!isRewritable(Loc)) return true;
279b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  FileID FID;
280b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID);
281fd183ba0b16718ff05e161bc479678e447df4999Argyrios Kyrtzidis  RewriteOptions rangeOpts;
282fd183ba0b16718ff05e161bc479678e447df4999Argyrios Kyrtzidis  rangeOpts.IncludeInsertsAtBeginOfRange = false;
283fd183ba0b16718ff05e161bc479678e447df4999Argyrios Kyrtzidis  StartOffs += getRangeSize(SourceRange(Loc, Loc), rangeOpts);
284b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  getEditBuffer(FID).InsertText(StartOffs, Str, /*InsertAfter*/true);
285b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  return false;
286b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis}
287b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis
288aadaf78d65daef3ac1b45e4ad6136ce859962fe2Chris Lattner/// RemoveText - Remove the specified text region.
289b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidisbool Rewriter::RemoveText(SourceLocation Start, unsigned Length,
290fd183ba0b16718ff05e161bc479678e447df4999Argyrios Kyrtzidis                          RewriteOptions opts) {
291aadaf78d65daef3ac1b45e4ad6136ce859962fe2Chris Lattner  if (!isRewritable(Start)) return true;
2922b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner  FileID FID;
2932b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner  unsigned StartOffs = getLocationOffsetAndFileID(Start, FID);
294fd183ba0b16718ff05e161bc479678e447df4999Argyrios Kyrtzidis  getEditBuffer(FID).RemoveText(StartOffs, Length, opts.RemoveLineIfEmpty);
295aadaf78d65daef3ac1b45e4ad6136ce859962fe2Chris Lattner  return false;
296674af9541256dc3ef803e3723027a8b028f1f7a2Chris Lattner}
2978a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner
298674af9541256dc3ef803e3723027a8b028f1f7a2Chris Lattner/// ReplaceText - This method replaces a range of characters in the input
299674af9541256dc3ef803e3723027a8b028f1f7a2Chris Lattner/// buffer with a new string.  This is effectively a combined "remove/insert"
300674af9541256dc3ef803e3723027a8b028f1f7a2Chris Lattner/// operation.
301aadaf78d65daef3ac1b45e4ad6136ce859962fe2Chris Lattnerbool Rewriter::ReplaceText(SourceLocation Start, unsigned OrigLength,
3025f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner                           StringRef NewStr) {
303aadaf78d65daef3ac1b45e4ad6136ce859962fe2Chris Lattner  if (!isRewritable(Start)) return true;
3042b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner  FileID StartFileID;
3057c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner  unsigned StartOffs = getLocationOffsetAndFileID(Start, StartFileID);
3061eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
307d7407dc92c7d19cafce429e7e1cf9819d3fc0b92Daniel Dunbar  getEditBuffer(StartFileID).ReplaceText(StartOffs, OrigLength, NewStr);
308aadaf78d65daef3ac1b45e4ad6136ce859962fe2Chris Lattner  return false;
3098a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner}
31001c5748c29e75b29cab5fc7d8ad1b173b29c7ecfChris Lattner
311b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidisbool Rewriter::ReplaceText(SourceRange range, SourceRange replacementRange) {
312b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  if (!isRewritable(range.getBegin())) return true;
313b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  if (!isRewritable(range.getEnd())) return true;
314b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  if (replacementRange.isInvalid()) return true;
315b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  SourceLocation start = range.getBegin();
316b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  unsigned origLength = getRangeSize(range);
317b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  unsigned newLength = getRangeSize(replacementRange);
318b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  FileID FID;
319b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  unsigned newOffs = getLocationOffsetAndFileID(replacementRange.getBegin(),
320b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis                                                FID);
3215f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner  StringRef MB = SourceMgr->getBufferData(FID);
322b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis  return ReplaceText(start, origLength, MB.substr(newOffs, newLength));
323b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis}
324b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis
32501c5748c29e75b29cab5fc7d8ad1b173b29c7ecfChris Lattner/// ReplaceStmt - This replaces a Stmt/Expr with another, using the pretty
32601c5748c29e75b29cab5fc7d8ad1b173b29c7ecfChris Lattner/// printer to generate the replacement code.  This returns true if the input
32701c5748c29e75b29cab5fc7d8ad1b173b29c7ecfChris Lattner/// could not be rewritten, or false if successful.
32888906cddbb1d5b3a868eeeec6cb170befc829c2fFariborz Jahanianbool Rewriter::ReplaceStmt(Stmt *From, Stmt *To) {
32901c5748c29e75b29cab5fc7d8ad1b173b29c7ecfChris Lattner  // Measaure the old text.
33088906cddbb1d5b3a868eeeec6cb170befc829c2fFariborz Jahanian  int Size = getRangeSize(From->getSourceRange());
33101c5748c29e75b29cab5fc7d8ad1b173b29c7ecfChris Lattner  if (Size == -1)
33201c5748c29e75b29cab5fc7d8ad1b173b29c7ecfChris Lattner    return true;
3331eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
33401c5748c29e75b29cab5fc7d8ad1b173b29c7ecfChris Lattner  // Get the new text.
335a95d3750441ac8ad03e36af8e6e74039c9a3109dTed Kremenek  std::string SStr;
336a95d3750441ac8ad03e36af8e6e74039c9a3109dTed Kremenek  llvm::raw_string_ostream S(SStr);
337e4f2142d00fa5fdb580c4e2413da91882d955381Chris Lattner  To->printPretty(S, 0, PrintingPolicy(*LangOpts));
33801c5748c29e75b29cab5fc7d8ad1b173b29c7ecfChris Lattner  const std::string &Str = S.str();
33901c5748c29e75b29cab5fc7d8ad1b173b29c7ecfChris Lattner
340d7407dc92c7d19cafce429e7e1cf9819d3fc0b92Daniel Dunbar  ReplaceText(From->getLocStart(), Size, Str);
34101c5748c29e75b29cab5fc7d8ad1b173b29c7ecfChris Lattner  return false;
34201c5748c29e75b29cab5fc7d8ad1b173b29c7ecfChris Lattner}
3431d015313b27f6002b1c4a74e478ede1622141b4eFariborz Jahanian
3441d015313b27f6002b1c4a74e478ede1622141b4eFariborz Jahanianstd::string Rewriter::ConvertToString(Stmt *From) {
3451d015313b27f6002b1c4a74e478ede1622141b4eFariborz Jahanian  std::string SStr;
3461d015313b27f6002b1c4a74e478ede1622141b4eFariborz Jahanian  llvm::raw_string_ostream S(SStr);
3471d015313b27f6002b1c4a74e478ede1622141b4eFariborz Jahanian  From->printPretty(S, 0, PrintingPolicy(*LangOpts));
34885b1c7ce94904873b1c0b7d08a6bce885d8eb245Fariborz Jahanian  return S.str();
3491d015313b27f6002b1c4a74e478ede1622141b4eFariborz Jahanian}
35010c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis
35110c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidisbool Rewriter::IncreaseIndentation(CharSourceRange range,
35210c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis                                   SourceLocation parentIndent) {
353f85e193739c953358c865005855253af4f68a497John McCall  if (range.isInvalid()) return true;
35410c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  if (!isRewritable(range.getBegin())) return true;
35510c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  if (!isRewritable(range.getEnd())) return true;
35610c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  if (!isRewritable(parentIndent)) return true;
35710c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis
35810c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  FileID StartFileID, EndFileID, parentFileID;
35910c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  unsigned StartOff, EndOff, parentOff;
36010c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis
36110c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  StartOff = getLocationOffsetAndFileID(range.getBegin(), StartFileID);
36210c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  EndOff   = getLocationOffsetAndFileID(range.getEnd(), EndFileID);
36310c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  parentOff = getLocationOffsetAndFileID(parentIndent, parentFileID);
36410c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis
36510c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  if (StartFileID != EndFileID || StartFileID != parentFileID)
36610c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis    return true;
367f85e193739c953358c865005855253af4f68a497John McCall  if (StartOff > EndOff)
36810c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis    return true;
36910c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis
37010c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  FileID FID = StartFileID;
37110c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  StringRef MB = SourceMgr->getBufferData(FID);
37210c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis
37310c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  unsigned parentLineNo = SourceMgr->getLineNumber(FID, parentOff) - 1;
37410c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  unsigned startLineNo = SourceMgr->getLineNumber(FID, StartOff) - 1;
37510c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  unsigned endLineNo = SourceMgr->getLineNumber(FID, EndOff) - 1;
37610c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis
37710c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  const SrcMgr::ContentCache *
37810c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis      Content = SourceMgr->getSLocEntry(FID).getFile().getContentCache();
37910c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis
380f85e193739c953358c865005855253af4f68a497John McCall  // Find where the lines start.
38110c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  unsigned parentLineOffs = Content->SourceLineCache[parentLineNo];
38210c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  unsigned startLineOffs = Content->SourceLineCache[startLineNo];
38310c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis
38410c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  // Find the whitespace at the start of each line.
385f85e193739c953358c865005855253af4f68a497John McCall  StringRef parentSpace, startSpace;
38610c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  {
38710c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis    unsigned i = parentLineOffs;
38810c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis    while (isWhitespace(MB[i]))
38910c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis      ++i;
39010c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis    parentSpace = MB.substr(parentLineOffs, i-parentLineOffs);
39110c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis
39210c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis    i = startLineOffs;
39310c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis    while (isWhitespace(MB[i]))
39410c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis      ++i;
39510c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis    startSpace = MB.substr(startLineOffs, i-startLineOffs);
39610c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  }
39710c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  if (parentSpace.size() >= startSpace.size())
39810c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis    return true;
39910c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  if (!startSpace.startswith(parentSpace))
40010c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis    return true;
40110c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis
4025f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner  StringRef indent = startSpace.substr(parentSpace.size());
40310c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis
40410c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  // Indent the lines between start/end offsets.
40510c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  RewriteBuffer &RB = getEditBuffer(FID);
406f85e193739c953358c865005855253af4f68a497John McCall  for (unsigned lineNo = startLineNo; lineNo <= endLineNo; ++lineNo) {
407f85e193739c953358c865005855253af4f68a497John McCall    unsigned offs = Content->SourceLineCache[lineNo];
408f85e193739c953358c865005855253af4f68a497John McCall    unsigned i = offs;
409f85e193739c953358c865005855253af4f68a497John McCall    while (isWhitespace(MB[i]))
410f85e193739c953358c865005855253af4f68a497John McCall      ++i;
411f85e193739c953358c865005855253af4f68a497John McCall    StringRef origIndent = MB.substr(offs, i-offs);
412f85e193739c953358c865005855253af4f68a497John McCall    if (origIndent.startswith(startSpace))
413f85e193739c953358c865005855253af4f68a497John McCall      RB.InsertText(offs, indent, /*InsertAfter=*/false);
41410c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  }
41510c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis
41610c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis  return false;
41710c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis}
418bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek
419bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek// A wrapper for a file stream that atomically overwrites the target.
420bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek//
421bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek// Creates a file output stream for a temporary file in the constructor,
422bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek// which is later accessible via getStream() if ok() return true.
423bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek// Flushes the stream and moves the temporary file to the target location
424bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek// in the destructor.
425bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimekclass AtomicallyMovedFile {
426bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimekpublic:
427bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  AtomicallyMovedFile(DiagnosticsEngine &Diagnostics, StringRef Filename,
428bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek                      bool &AllWritten)
429bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    : Diagnostics(Diagnostics), Filename(Filename), AllWritten(AllWritten) {
430bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    TempFilename = Filename;
431bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    TempFilename += "-%%%%%%%%";
432bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    int FD;
433bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    if (llvm::sys::fs::unique_file(TempFilename.str(), FD, TempFilename,
434bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek                                    /*makeAbsolute=*/true, 0664)) {
435bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek      AllWritten = false;
436bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek      Diagnostics.Report(clang::diag::err_unable_to_make_temp)
437bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek        << TempFilename;
438bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    } else {
439bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek      FileStream.reset(new llvm::raw_fd_ostream(FD, /*shouldClose=*/true));
440bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    }
441bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  }
442bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek
443bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  ~AtomicallyMovedFile() {
444bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    if (!ok()) return;
445bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek
446bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    FileStream->flush();
4472d9c4dfad1f58c42a31721054cd99218d9ac3d52NAKAMURA Takumi#ifdef _WIN32
4482d9c4dfad1f58c42a31721054cd99218d9ac3d52NAKAMURA Takumi    // Win32 does not allow rename/removing opened files.
4492d9c4dfad1f58c42a31721054cd99218d9ac3d52NAKAMURA Takumi    FileStream.reset();
4502d9c4dfad1f58c42a31721054cd99218d9ac3d52NAKAMURA Takumi#endif
451bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    if (llvm::error_code ec =
452bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek          llvm::sys::fs::rename(TempFilename.str(), Filename)) {
453bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek      AllWritten = false;
454bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek      Diagnostics.Report(clang::diag::err_unable_to_rename_temp)
455bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek        << TempFilename << Filename << ec.message();
456bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek      bool existed;
457bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek      // If the remove fails, there's not a lot we can do - this is already an
458bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek      // error.
459bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek      llvm::sys::fs::remove(TempFilename.str(), existed);
460bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    }
461bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  }
462bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek
463bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  bool ok() { return FileStream; }
464bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  llvm::raw_ostream &getStream() { return *FileStream; }
465bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek
466bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimekprivate:
467bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  DiagnosticsEngine &Diagnostics;
468bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  StringRef Filename;
469bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  SmallString<128> TempFilename;
470bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  OwningPtr<llvm::raw_fd_ostream> FileStream;
471bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  bool &AllWritten;
472bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek};
473bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek
474bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimekbool Rewriter::overwriteChangedFiles() {
475bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  bool AllWritten = true;
476bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  for (buffer_iterator I = buffer_begin(), E = buffer_end(); I != E; ++I) {
477bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    const FileEntry *Entry =
478bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek        getSourceMgr().getFileEntryForID(I->first);
479bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    AtomicallyMovedFile File(getSourceMgr().getDiagnostics(), Entry->getName(),
480bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek                             AllWritten);
481bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    if (File.ok()) {
482bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek      I->second.write(File.getStream());
483bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek    }
484bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  }
485bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek  return !AllWritten;
486bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek}
487