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" 162c3352b5d1f5f4546af2f3051a304d84d57c697eTed Kremenek#include "clang/AST/Decl.h" 17a93d0f280693b8418bc88cf7a8c93325f7fcf4c6Benjamin Kramer#include "clang/AST/PrettyPrinter.h" 18a93d0f280693b8418bc88cf7a8c93325f7fcf4c6Benjamin Kramer#include "clang/AST/Stmt.h" 19bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek#include "clang/Basic/DiagnosticIDs.h" 20bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek#include "clang/Basic/FileManager.h" 218a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner#include "clang/Basic/SourceManager.h" 22bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek#include "clang/Lex/Lexer.h" 238fe83e1df954d72c0f4ffc15d20a5222ec151c21Benjamin Kramer#include "llvm/ADT/SmallString.h" 24bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek#include "llvm/Support/FileSystem.h" 25a93d0f280693b8418bc88cf7a8c93325f7fcf4c6Benjamin Kramer#include "llvm/Support/raw_ostream.h" 268bd12b848bc353a9d34b54144c3dd3407b064292Chris Lattnerusing namespace clang; 278bd12b848bc353a9d34b54144c3dd3407b064292Chris Lattner 285f9e272e632e951b1efe824cd16acb4d96077930Chris Lattnerraw_ostream &RewriteBuffer::write(raw_ostream &os) const { 290ade808e0ac411baa2dbc1f76ad352b9b6d6d3f8Nick Lewycky // FIXME: eliminate the copy by writing out each chunk at a time 300ade808e0ac411baa2dbc1f76ad352b9b6d6d3f8Nick Lewycky os << std::string(begin(), end()); 310ade808e0ac411baa2dbc1f76ad352b9b6d6d3f8Nick Lewycky return os; 320ade808e0ac411baa2dbc1f76ad352b9b6d6d3f8Nick Lewycky} 330ade808e0ac411baa2dbc1f76ad352b9b6d6d3f8Nick Lewycky 34b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis/// \brief Return true if this character is non-new-line whitespace: 358c10f841040b1e2951d06d385c8eefbcbe578fcfJames Dennett/// ' ', '\\t', '\\f', '\\v', '\\r'. 36b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidisstatic inline bool isWhitespace(unsigned char c) { 37b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis switch (c) { 38b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis case ' ': 39b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis case '\t': 40b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis case '\f': 41b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis case '\v': 42b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis case '\r': 43b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis return true; 44b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis default: 45b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis return false; 46b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis } 47b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis} 48b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis 49b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidisvoid RewriteBuffer::RemoveText(unsigned OrigOffset, unsigned Size, 50b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis bool removeLineIfEmpty) { 517c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner // Nothing to remove, exit early. 527c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner if (Size == 0) return; 537c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner 547c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner unsigned RealOffset = getMappedOffset(OrigOffset, true); 557c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner assert(RealOffset+Size < Buffer.size() && "Invalid location"); 561eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 577c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner // Remove the dead characters. 58febe719596ee68605944da5f2e03258e18e6df8cChris Lattner Buffer.erase(RealOffset, Size); 597c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner 607c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner // Add a delta so that future changes are offset correctly. 61a0978c24829dfd552d38fc3bae2b86e18bb90d49Eli Friedman AddReplaceDelta(OrigOffset, -Size); 62b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis 63b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis if (removeLineIfEmpty) { 64b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis // Find the line that the remove occurred and if it is completely empty 65b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis // remove the line as well. 66b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis 67b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis iterator curLineStart = begin(); 68b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis unsigned curLineStartOffs = 0; 69b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis iterator posI = begin(); 70b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis for (unsigned i = 0; i != RealOffset; ++i) { 71b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis if (*posI == '\n') { 72b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis curLineStart = posI; 73b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis ++curLineStart; 74b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis curLineStartOffs = i + 1; 75b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis } 76b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis ++posI; 77b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis } 78b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis 79b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis unsigned lineSize = 0; 80b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis posI = curLineStart; 81b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis while (posI != end() && isWhitespace(*posI)) { 82b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis ++posI; 83b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis ++lineSize; 84b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis } 85b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis if (posI != end() && *posI == '\n') { 86b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis Buffer.erase(curLineStartOffs, lineSize + 1/* + '\n'*/); 87b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis AddReplaceDelta(curLineStartOffs, -(lineSize + 1/* + '\n'*/)); 88b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis } 89b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis } 908bd12b848bc353a9d34b54144c3dd3407b064292Chris Lattner} 918bd12b848bc353a9d34b54144c3dd3407b064292Chris Lattner 925f9e272e632e951b1efe824cd16acb4d96077930Chris Lattnervoid RewriteBuffer::InsertText(unsigned OrigOffset, StringRef Str, 93886c8db545170850f7806f47b5f6120864effd09Ted Kremenek bool InsertAfter) { 941eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 9503b071043593590b01fdf61df3e29c0ae7c067d3Chris Lattner // Nothing to insert, exit early. 96d7407dc92c7d19cafce429e7e1cf9819d3fc0b92Daniel Dunbar if (Str.empty()) return; 97febe719596ee68605944da5f2e03258e18e6df8cChris Lattner 98886c8db545170850f7806f47b5f6120864effd09Ted Kremenek unsigned RealOffset = getMappedOffset(OrigOffset, InsertAfter); 99d7407dc92c7d19cafce429e7e1cf9819d3fc0b92Daniel Dunbar Buffer.insert(RealOffset, Str.begin(), Str.end()); 1001eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 10103b071043593590b01fdf61df3e29c0ae7c067d3Chris Lattner // Add a delta so that future changes are offset correctly. 102d7407dc92c7d19cafce429e7e1cf9819d3fc0b92Daniel Dunbar AddInsertDelta(OrigOffset, Str.size()); 1038bd12b848bc353a9d34b54144c3dd3407b064292Chris Lattner} 1048a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner 1057c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner/// ReplaceText - This method replaces a range of characters in the input 106febe719596ee68605944da5f2e03258e18e6df8cChris Lattner/// buffer with a new string. This is effectively a combined "remove+insert" 1077c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner/// operation. 1087c239606f3a7a685653a0a7e64459c3f43522666Chris Lattnervoid RewriteBuffer::ReplaceText(unsigned OrigOffset, unsigned OrigLength, 1095f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner StringRef NewStr) { 110a0978c24829dfd552d38fc3bae2b86e18bb90d49Eli Friedman unsigned RealOffset = getMappedOffset(OrigOffset, true); 111febe719596ee68605944da5f2e03258e18e6df8cChris Lattner Buffer.erase(RealOffset, OrigLength); 112d7407dc92c7d19cafce429e7e1cf9819d3fc0b92Daniel Dunbar Buffer.insert(RealOffset, NewStr.begin(), NewStr.end()); 113d7407dc92c7d19cafce429e7e1cf9819d3fc0b92Daniel Dunbar if (OrigLength != NewStr.size()) 114d7407dc92c7d19cafce429e7e1cf9819d3fc0b92Daniel Dunbar AddReplaceDelta(OrigOffset, NewStr.size() - OrigLength); 1157c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner} 1168a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner 1178a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner 1188a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner//===----------------------------------------------------------------------===// 1198a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner// Rewriter class 1208a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner//===----------------------------------------------------------------------===// 1218a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner 122311ff02fae0392bee6abe7723cdf5a69b2899a47Chris Lattner/// getRangeSize - Return the size in bytes of the specified range if they 123311ff02fae0392bee6abe7723cdf5a69b2899a47Chris Lattner/// are in the same file. If not, this returns -1. 124b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidisint Rewriter::getRangeSize(const CharSourceRange &Range, 125fd183ba0b16718ff05e161bc479678e447df4999Argyrios Kyrtzidis RewriteOptions opts) const { 126311ff02fae0392bee6abe7723cdf5a69b2899a47Chris Lattner if (!isRewritable(Range.getBegin()) || 127311ff02fae0392bee6abe7723cdf5a69b2899a47Chris Lattner !isRewritable(Range.getEnd())) return -1; 1281eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1292b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner FileID StartFileID, EndFileID; 1302b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner unsigned StartOff, EndOff; 1311eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 132311ff02fae0392bee6abe7723cdf5a69b2899a47Chris Lattner StartOff = getLocationOffsetAndFileID(Range.getBegin(), StartFileID); 133311ff02fae0392bee6abe7723cdf5a69b2899a47Chris Lattner EndOff = getLocationOffsetAndFileID(Range.getEnd(), EndFileID); 1341eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 135311ff02fae0392bee6abe7723cdf5a69b2899a47Chris Lattner if (StartFileID != EndFileID) 136311ff02fae0392bee6abe7723cdf5a69b2899a47Chris Lattner return -1; 1371eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 138d6690b20b3340f30a225dffa49603951dcd75e4eChris Lattner // If edits have been made to this buffer, the delta between the range may 139d6690b20b3340f30a225dffa49603951dcd75e4eChris Lattner // have changed. 1402b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner std::map<FileID, RewriteBuffer>::const_iterator I = 141075eb6eae0506e041e0086ddcab31ba2e55f0472Chris Lattner RewriteBuffers.find(StartFileID); 142d6690b20b3340f30a225dffa49603951dcd75e4eChris Lattner if (I != RewriteBuffers.end()) { 143075eb6eae0506e041e0086ddcab31ba2e55f0472Chris Lattner const RewriteBuffer &RB = I->second; 144fd183ba0b16718ff05e161bc479678e447df4999Argyrios Kyrtzidis EndOff = RB.getMappedOffset(EndOff, opts.IncludeInsertsAtEndOfRange); 145fd183ba0b16718ff05e161bc479678e447df4999Argyrios Kyrtzidis StartOff = RB.getMappedOffset(StartOff, !opts.IncludeInsertsAtBeginOfRange); 146075eb6eae0506e041e0086ddcab31ba2e55f0472Chris Lattner } 147075eb6eae0506e041e0086ddcab31ba2e55f0472Chris Lattner 1481eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1499d62a5b31ec3762f416cc9ef89d1b7b433d13ac5Chris Lattner // Adjust the end offset to the end of the last token, instead of being the 1500a76aae8c03cb7dd7bdbe683485560afaf695959Chris Lattner // start of the last token if this is a token range. 1510a76aae8c03cb7dd7bdbe683485560afaf695959Chris Lattner if (Range.isTokenRange()) 1520a76aae8c03cb7dd7bdbe683485560afaf695959Chris Lattner EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr, *LangOpts); 1531eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 154d6690b20b3340f30a225dffa49603951dcd75e4eChris Lattner return EndOff-StartOff; 155311ff02fae0392bee6abe7723cdf5a69b2899a47Chris Lattner} 156311ff02fae0392bee6abe7723cdf5a69b2899a47Chris Lattner 157fd183ba0b16718ff05e161bc479678e447df4999Argyrios Kyrtzidisint Rewriter::getRangeSize(SourceRange Range, RewriteOptions opts) const { 158fd183ba0b16718ff05e161bc479678e447df4999Argyrios Kyrtzidis return getRangeSize(CharSourceRange::getTokenRange(Range), opts); 1590a76aae8c03cb7dd7bdbe683485560afaf695959Chris Lattner} 1600a76aae8c03cb7dd7bdbe683485560afaf695959Chris Lattner 1610a76aae8c03cb7dd7bdbe683485560afaf695959Chris Lattner 1626a12a14a529a79524e17889046c7098b80a73c49Ted Kremenek/// getRewrittenText - Return the rewritten form of the text in the specified 163b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner/// range. If the start or end of the range was unrewritable or if they are 1641eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump/// in different buffers, this returns an empty string. 165b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner/// 166b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner/// Note that this method is not particularly efficient. 167b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner/// 1686a12a14a529a79524e17889046c7098b80a73c49Ted Kremenekstd::string Rewriter::getRewrittenText(SourceRange Range) const { 169b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner if (!isRewritable(Range.getBegin()) || 170b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner !isRewritable(Range.getEnd())) 171b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner return ""; 1721eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1732b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner FileID StartFileID, EndFileID; 1742b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner unsigned StartOff, EndOff; 175b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner StartOff = getLocationOffsetAndFileID(Range.getBegin(), StartFileID); 176b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner EndOff = getLocationOffsetAndFileID(Range.getEnd(), EndFileID); 1771eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 178b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner if (StartFileID != EndFileID) 179b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner return ""; // Start and end in different buffers. 1801eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 181b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner // If edits have been made to this buffer, the delta between the range may 182b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner // have changed. 1832b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner std::map<FileID, RewriteBuffer>::const_iterator I = 184b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner RewriteBuffers.find(StartFileID); 185b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner if (I == RewriteBuffers.end()) { 186b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner // If the buffer hasn't been rewritten, just return the text from the input. 187b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner const char *Ptr = SourceMgr->getCharacterData(Range.getBegin()); 1881eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 189b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner // Adjust the end offset to the end of the last token, instead of being the 190b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner // start of the last token. 1912c78b873f4f3823ae859c15674cb3d76c8554113Chris Lattner EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr, *LangOpts); 192b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner return std::string(Ptr, Ptr+EndOff-StartOff); 193b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner } 1941eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 195b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner const RewriteBuffer &RB = I->second; 196b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner EndOff = RB.getMappedOffset(EndOff, true); 197b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner StartOff = RB.getMappedOffset(StartOff); 1981eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 199b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner // Adjust the end offset to the end of the last token, instead of being the 200b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner // start of the last token. 2012c78b873f4f3823ae859c15674cb3d76c8554113Chris Lattner EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr, *LangOpts); 202b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner 203b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner // Advance the iterators to the right spot, yay for linear time algorithms. 204b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner RewriteBuffer::iterator Start = RB.begin(); 205b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner std::advance(Start, StartOff); 206b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner RewriteBuffer::iterator End = Start; 207b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner std::advance(End, EndOff-StartOff); 2081eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 209b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner return std::string(Start, End); 210b5cd09a2bf1509167a2e7a46bdd0316812a93335Chris Lattner} 211311ff02fae0392bee6abe7723cdf5a69b2899a47Chris Lattner 2127c239606f3a7a685653a0a7e64459c3f43522666Chris Lattnerunsigned Rewriter::getLocationOffsetAndFileID(SourceLocation Loc, 2132b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner FileID &FID) const { 21454bd7cb491cce1fb55ce1baac40cf7002a317166Chris Lattner assert(Loc.isValid() && "Invalid location"); 215de7aeefc5573d669ed476d7bda7a8940d3bcadb7Chris Lattner std::pair<FileID,unsigned> V = SourceMgr->getDecomposedLoc(Loc); 2162b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner FID = V.first; 2177c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner return V.second; 2187c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner} 2197c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner 2207c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner 2218a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner/// getEditBuffer - Get or create a RewriteBuffer for the specified FileID. 2228a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner/// 2232b2453a7d8fe732561795431f39ceb2b2a832d84Chris LattnerRewriteBuffer &Rewriter::getEditBuffer(FileID FID) { 2242b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner std::map<FileID, RewriteBuffer>::iterator I = 2252b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner RewriteBuffers.lower_bound(FID); 2261eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump if (I != RewriteBuffers.end() && I->first == FID) 2278a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner return I->second; 2282b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner I = RewriteBuffers.insert(I, std::make_pair(FID, RewriteBuffer())); 2291eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2305f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner StringRef MB = SourceMgr->getBufferData(FID); 231f6ac97b101c8840efa92bf29166077ce4049e293Benjamin Kramer I->second.Initialize(MB.begin(), MB.end()); 2321eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2338a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner return I->second; 2348a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner} 2358a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner 23654a2f071a37ee63d3ef1d4e7ca2570542ee12115Chris Lattner/// InsertText - Insert the specified string at the specified location in the 237aadaf78d65daef3ac1b45e4ad6136ce859962fe2Chris Lattner/// original buffer. 2385f9e272e632e951b1efe824cd16acb4d96077930Chris Lattnerbool Rewriter::InsertText(SourceLocation Loc, StringRef Str, 239f85e193739c953358c865005855253af4f68a497John McCall bool InsertAfter, bool indentNewLines) { 240dcbc5b0b0722282a0fdd829359fe0d7e22adb882Chris Lattner if (!isRewritable(Loc)) return true; 2412b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner FileID FID; 2422b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID); 243f85e193739c953358c865005855253af4f68a497John McCall 244f7ccbad5d9949e7ddd1cbef43d482553b811e026Dylan Noblesmith SmallString<128> indentedStr; 245f85e193739c953358c865005855253af4f68a497John McCall if (indentNewLines && Str.find('\n') != StringRef::npos) { 246f85e193739c953358c865005855253af4f68a497John McCall StringRef MB = SourceMgr->getBufferData(FID); 247f85e193739c953358c865005855253af4f68a497John McCall 248f85e193739c953358c865005855253af4f68a497John McCall unsigned lineNo = SourceMgr->getLineNumber(FID, StartOffs) - 1; 249f85e193739c953358c865005855253af4f68a497John McCall const SrcMgr::ContentCache * 250f85e193739c953358c865005855253af4f68a497John McCall Content = SourceMgr->getSLocEntry(FID).getFile().getContentCache(); 251f85e193739c953358c865005855253af4f68a497John McCall unsigned lineOffs = Content->SourceLineCache[lineNo]; 252f85e193739c953358c865005855253af4f68a497John McCall 253f85e193739c953358c865005855253af4f68a497John McCall // Find the whitespace at the start of the line. 254f85e193739c953358c865005855253af4f68a497John McCall StringRef indentSpace; 255f85e193739c953358c865005855253af4f68a497John McCall { 256f85e193739c953358c865005855253af4f68a497John McCall unsigned i = lineOffs; 257f85e193739c953358c865005855253af4f68a497John McCall while (isWhitespace(MB[i])) 258f85e193739c953358c865005855253af4f68a497John McCall ++i; 259f85e193739c953358c865005855253af4f68a497John McCall indentSpace = MB.substr(lineOffs, i-lineOffs); 260f85e193739c953358c865005855253af4f68a497John McCall } 261f85e193739c953358c865005855253af4f68a497John McCall 2625f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner SmallVector<StringRef, 4> lines; 263f85e193739c953358c865005855253af4f68a497John McCall Str.split(lines, "\n"); 264f85e193739c953358c865005855253af4f68a497John McCall 265f85e193739c953358c865005855253af4f68a497John McCall for (unsigned i = 0, e = lines.size(); i != e; ++i) { 266f85e193739c953358c865005855253af4f68a497John McCall indentedStr += lines[i]; 267f85e193739c953358c865005855253af4f68a497John McCall if (i < e-1) { 268f85e193739c953358c865005855253af4f68a497John McCall indentedStr += '\n'; 269f85e193739c953358c865005855253af4f68a497John McCall indentedStr += indentSpace; 270f85e193739c953358c865005855253af4f68a497John McCall } 271f85e193739c953358c865005855253af4f68a497John McCall } 272f85e193739c953358c865005855253af4f68a497John McCall Str = indentedStr.str(); 273f85e193739c953358c865005855253af4f68a497John McCall } 274f85e193739c953358c865005855253af4f68a497John McCall 275d7407dc92c7d19cafce429e7e1cf9819d3fc0b92Daniel Dunbar getEditBuffer(FID).InsertText(StartOffs, Str, InsertAfter); 276dcbc5b0b0722282a0fdd829359fe0d7e22adb882Chris Lattner return false; 27754a2f071a37ee63d3ef1d4e7ca2570542ee12115Chris Lattner} 27854a2f071a37ee63d3ef1d4e7ca2570542ee12115Chris Lattner 2795f9e272e632e951b1efe824cd16acb4d96077930Chris Lattnerbool Rewriter::InsertTextAfterToken(SourceLocation Loc, StringRef Str) { 280b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis if (!isRewritable(Loc)) return true; 281b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis FileID FID; 282b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID); 283fd183ba0b16718ff05e161bc479678e447df4999Argyrios Kyrtzidis RewriteOptions rangeOpts; 284fd183ba0b16718ff05e161bc479678e447df4999Argyrios Kyrtzidis rangeOpts.IncludeInsertsAtBeginOfRange = false; 285fd183ba0b16718ff05e161bc479678e447df4999Argyrios Kyrtzidis StartOffs += getRangeSize(SourceRange(Loc, Loc), rangeOpts); 286b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis getEditBuffer(FID).InsertText(StartOffs, Str, /*InsertAfter*/true); 287b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis return false; 288b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis} 289b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis 290aadaf78d65daef3ac1b45e4ad6136ce859962fe2Chris Lattner/// RemoveText - Remove the specified text region. 291b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidisbool Rewriter::RemoveText(SourceLocation Start, unsigned Length, 292fd183ba0b16718ff05e161bc479678e447df4999Argyrios Kyrtzidis RewriteOptions opts) { 293aadaf78d65daef3ac1b45e4ad6136ce859962fe2Chris Lattner if (!isRewritable(Start)) return true; 2942b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner FileID FID; 2952b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner unsigned StartOffs = getLocationOffsetAndFileID(Start, FID); 296fd183ba0b16718ff05e161bc479678e447df4999Argyrios Kyrtzidis getEditBuffer(FID).RemoveText(StartOffs, Length, opts.RemoveLineIfEmpty); 297aadaf78d65daef3ac1b45e4ad6136ce859962fe2Chris Lattner return false; 298674af9541256dc3ef803e3723027a8b028f1f7a2Chris Lattner} 2998a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner 300674af9541256dc3ef803e3723027a8b028f1f7a2Chris Lattner/// ReplaceText - This method replaces a range of characters in the input 301674af9541256dc3ef803e3723027a8b028f1f7a2Chris Lattner/// buffer with a new string. This is effectively a combined "remove/insert" 302674af9541256dc3ef803e3723027a8b028f1f7a2Chris Lattner/// operation. 303aadaf78d65daef3ac1b45e4ad6136ce859962fe2Chris Lattnerbool Rewriter::ReplaceText(SourceLocation Start, unsigned OrigLength, 3045f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner StringRef NewStr) { 305aadaf78d65daef3ac1b45e4ad6136ce859962fe2Chris Lattner if (!isRewritable(Start)) return true; 3062b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner FileID StartFileID; 3077c239606f3a7a685653a0a7e64459c3f43522666Chris Lattner unsigned StartOffs = getLocationOffsetAndFileID(Start, StartFileID); 3081eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 309d7407dc92c7d19cafce429e7e1cf9819d3fc0b92Daniel Dunbar getEditBuffer(StartFileID).ReplaceText(StartOffs, OrigLength, NewStr); 310aadaf78d65daef3ac1b45e4ad6136ce859962fe2Chris Lattner return false; 3118a12c2777cccdf629b89745b6ecc89a8c1641e4eChris Lattner} 31201c5748c29e75b29cab5fc7d8ad1b173b29c7ecfChris Lattner 313b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidisbool Rewriter::ReplaceText(SourceRange range, SourceRange replacementRange) { 314b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis if (!isRewritable(range.getBegin())) return true; 315b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis if (!isRewritable(range.getEnd())) return true; 316b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis if (replacementRange.isInvalid()) return true; 317b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis SourceLocation start = range.getBegin(); 318b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis unsigned origLength = getRangeSize(range); 319b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis unsigned newLength = getRangeSize(replacementRange); 320b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis FileID FID; 321b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis unsigned newOffs = getLocationOffsetAndFileID(replacementRange.getBegin(), 322b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis FID); 3235f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner StringRef MB = SourceMgr->getBufferData(FID); 324b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis return ReplaceText(start, origLength, MB.substr(newOffs, newLength)); 325b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis} 326b65ed34ebf0380c001756eea7a1c1d01e110b557Argyrios Kyrtzidis 32701c5748c29e75b29cab5fc7d8ad1b173b29c7ecfChris Lattner/// ReplaceStmt - This replaces a Stmt/Expr with another, using the pretty 32801c5748c29e75b29cab5fc7d8ad1b173b29c7ecfChris Lattner/// printer to generate the replacement code. This returns true if the input 32901c5748c29e75b29cab5fc7d8ad1b173b29c7ecfChris Lattner/// could not be rewritten, or false if successful. 33088906cddbb1d5b3a868eeeec6cb170befc829c2fFariborz Jahanianbool Rewriter::ReplaceStmt(Stmt *From, Stmt *To) { 33101c5748c29e75b29cab5fc7d8ad1b173b29c7ecfChris Lattner // Measaure the old text. 33288906cddbb1d5b3a868eeeec6cb170befc829c2fFariborz Jahanian int Size = getRangeSize(From->getSourceRange()); 33301c5748c29e75b29cab5fc7d8ad1b173b29c7ecfChris Lattner if (Size == -1) 33401c5748c29e75b29cab5fc7d8ad1b173b29c7ecfChris Lattner return true; 3351eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 33601c5748c29e75b29cab5fc7d8ad1b173b29c7ecfChris Lattner // Get the new text. 337a95d3750441ac8ad03e36af8e6e74039c9a3109dTed Kremenek std::string SStr; 338a95d3750441ac8ad03e36af8e6e74039c9a3109dTed Kremenek llvm::raw_string_ostream S(SStr); 339e4f2142d00fa5fdb580c4e2413da91882d955381Chris Lattner To->printPretty(S, 0, PrintingPolicy(*LangOpts)); 34001c5748c29e75b29cab5fc7d8ad1b173b29c7ecfChris Lattner const std::string &Str = S.str(); 34101c5748c29e75b29cab5fc7d8ad1b173b29c7ecfChris Lattner 342d7407dc92c7d19cafce429e7e1cf9819d3fc0b92Daniel Dunbar ReplaceText(From->getLocStart(), Size, Str); 34301c5748c29e75b29cab5fc7d8ad1b173b29c7ecfChris Lattner return false; 34401c5748c29e75b29cab5fc7d8ad1b173b29c7ecfChris Lattner} 3451d015313b27f6002b1c4a74e478ede1622141b4eFariborz Jahanian 3461d015313b27f6002b1c4a74e478ede1622141b4eFariborz Jahanianstd::string Rewriter::ConvertToString(Stmt *From) { 3471d015313b27f6002b1c4a74e478ede1622141b4eFariborz Jahanian std::string SStr; 3481d015313b27f6002b1c4a74e478ede1622141b4eFariborz Jahanian llvm::raw_string_ostream S(SStr); 3491d015313b27f6002b1c4a74e478ede1622141b4eFariborz Jahanian From->printPretty(S, 0, PrintingPolicy(*LangOpts)); 35085b1c7ce94904873b1c0b7d08a6bce885d8eb245Fariborz Jahanian return S.str(); 3511d015313b27f6002b1c4a74e478ede1622141b4eFariborz Jahanian} 35210c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis 35310c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidisbool Rewriter::IncreaseIndentation(CharSourceRange range, 35410c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis SourceLocation parentIndent) { 355f85e193739c953358c865005855253af4f68a497John McCall if (range.isInvalid()) return true; 35610c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis if (!isRewritable(range.getBegin())) return true; 35710c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis if (!isRewritable(range.getEnd())) return true; 35810c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis if (!isRewritable(parentIndent)) return true; 35910c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis 36010c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis FileID StartFileID, EndFileID, parentFileID; 36110c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis unsigned StartOff, EndOff, parentOff; 36210c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis 36310c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis StartOff = getLocationOffsetAndFileID(range.getBegin(), StartFileID); 36410c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis EndOff = getLocationOffsetAndFileID(range.getEnd(), EndFileID); 36510c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis parentOff = getLocationOffsetAndFileID(parentIndent, parentFileID); 36610c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis 36710c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis if (StartFileID != EndFileID || StartFileID != parentFileID) 36810c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis return true; 369f85e193739c953358c865005855253af4f68a497John McCall if (StartOff > EndOff) 37010c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis return true; 37110c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis 37210c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis FileID FID = StartFileID; 37310c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis StringRef MB = SourceMgr->getBufferData(FID); 37410c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis 37510c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis unsigned parentLineNo = SourceMgr->getLineNumber(FID, parentOff) - 1; 37610c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis unsigned startLineNo = SourceMgr->getLineNumber(FID, StartOff) - 1; 37710c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis unsigned endLineNo = SourceMgr->getLineNumber(FID, EndOff) - 1; 37810c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis 37910c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis const SrcMgr::ContentCache * 38010c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis Content = SourceMgr->getSLocEntry(FID).getFile().getContentCache(); 38110c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis 382f85e193739c953358c865005855253af4f68a497John McCall // Find where the lines start. 38310c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis unsigned parentLineOffs = Content->SourceLineCache[parentLineNo]; 38410c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis unsigned startLineOffs = Content->SourceLineCache[startLineNo]; 38510c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis 38610c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis // Find the whitespace at the start of each line. 387f85e193739c953358c865005855253af4f68a497John McCall StringRef parentSpace, startSpace; 38810c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis { 38910c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis unsigned i = parentLineOffs; 39010c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis while (isWhitespace(MB[i])) 39110c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis ++i; 39210c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis parentSpace = MB.substr(parentLineOffs, i-parentLineOffs); 39310c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis 39410c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis i = startLineOffs; 39510c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis while (isWhitespace(MB[i])) 39610c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis ++i; 39710c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis startSpace = MB.substr(startLineOffs, i-startLineOffs); 39810c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis } 39910c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis if (parentSpace.size() >= startSpace.size()) 40010c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis return true; 40110c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis if (!startSpace.startswith(parentSpace)) 40210c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis return true; 40310c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis 4045f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner StringRef indent = startSpace.substr(parentSpace.size()); 40510c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis 40610c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis // Indent the lines between start/end offsets. 40710c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis RewriteBuffer &RB = getEditBuffer(FID); 408f85e193739c953358c865005855253af4f68a497John McCall for (unsigned lineNo = startLineNo; lineNo <= endLineNo; ++lineNo) { 409f85e193739c953358c865005855253af4f68a497John McCall unsigned offs = Content->SourceLineCache[lineNo]; 410f85e193739c953358c865005855253af4f68a497John McCall unsigned i = offs; 411f85e193739c953358c865005855253af4f68a497John McCall while (isWhitespace(MB[i])) 412f85e193739c953358c865005855253af4f68a497John McCall ++i; 413f85e193739c953358c865005855253af4f68a497John McCall StringRef origIndent = MB.substr(offs, i-offs); 414f85e193739c953358c865005855253af4f68a497John McCall if (origIndent.startswith(startSpace)) 415f85e193739c953358c865005855253af4f68a497John McCall RB.InsertText(offs, indent, /*InsertAfter=*/false); 41610c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis } 41710c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis 41810c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis return false; 41910c8d9e63bcc96d55f788e7c08b72ce626c8aeecArgyrios Kyrtzidis} 420bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek 421c2b914fb6fed213a7e7d9847e543f1e7f94d852dBenjamin Kramernamespace { 422bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek// A wrapper for a file stream that atomically overwrites the target. 423bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek// 424bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek// Creates a file output stream for a temporary file in the constructor, 425bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek// which is later accessible via getStream() if ok() return true. 426bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek// Flushes the stream and moves the temporary file to the target location 427bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek// in the destructor. 428bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimekclass AtomicallyMovedFile { 429bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimekpublic: 430bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek AtomicallyMovedFile(DiagnosticsEngine &Diagnostics, StringRef Filename, 431bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek bool &AllWritten) 432bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek : Diagnostics(Diagnostics), Filename(Filename), AllWritten(AllWritten) { 433bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek TempFilename = Filename; 434bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek TempFilename += "-%%%%%%%%"; 435bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek int FD; 43670e7aeccbf5856a84f81366c6c1a0c0c01e70063Rafael Espindola if (llvm::sys::fs::createUniqueFile(TempFilename.str(), FD, TempFilename)) { 437bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek AllWritten = false; 438bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek Diagnostics.Report(clang::diag::err_unable_to_make_temp) 439bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek << TempFilename; 440bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek } else { 441bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek FileStream.reset(new llvm::raw_fd_ostream(FD, /*shouldClose=*/true)); 442bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek } 443bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek } 444bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek 445bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek ~AtomicallyMovedFile() { 446bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek if (!ok()) return; 447bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek 448bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek FileStream->flush(); 4492d9c4dfad1f58c42a31721054cd99218d9ac3d52NAKAMURA Takumi#ifdef _WIN32 4502d9c4dfad1f58c42a31721054cd99218d9ac3d52NAKAMURA Takumi // Win32 does not allow rename/removing opened files. 4512d9c4dfad1f58c42a31721054cd99218d9ac3d52NAKAMURA Takumi FileStream.reset(); 4522d9c4dfad1f58c42a31721054cd99218d9ac3d52NAKAMURA Takumi#endif 453bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek if (llvm::error_code ec = 454bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek llvm::sys::fs::rename(TempFilename.str(), Filename)) { 455bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek AllWritten = false; 456bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek Diagnostics.Report(clang::diag::err_unable_to_rename_temp) 457bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek << TempFilename << Filename << ec.message(); 458bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek bool existed; 459bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek // If the remove fails, there's not a lot we can do - this is already an 460bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek // error. 461bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek llvm::sys::fs::remove(TempFilename.str(), existed); 462bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek } 463bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek } 464bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek 4657247c88d1e41514a41085f83ebf03dd5220e054aDavid Blaikie bool ok() { return FileStream.isValid(); } 466cfa88f893915ceb8ae4ce2f17c46c24a4d67502fDmitri Gribenko raw_ostream &getStream() { return *FileStream; } 467bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek 468bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimekprivate: 469bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek DiagnosticsEngine &Diagnostics; 470bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek StringRef Filename; 471bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek SmallString<128> TempFilename; 472bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek OwningPtr<llvm::raw_fd_ostream> FileStream; 473bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek bool &AllWritten; 474bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek}; 475c2b914fb6fed213a7e7d9847e543f1e7f94d852dBenjamin Kramer} // end anonymous namespace 476bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek 477bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimekbool Rewriter::overwriteChangedFiles() { 478bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek bool AllWritten = true; 479bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek for (buffer_iterator I = buffer_begin(), E = buffer_end(); I != E; ++I) { 480bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek const FileEntry *Entry = 481bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek getSourceMgr().getFileEntryForID(I->first); 482bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek AtomicallyMovedFile File(getSourceMgr().getDiagnostics(), Entry->getName(), 483bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek AllWritten); 484bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek if (File.ok()) { 485bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek I->second.write(File.getStream()); 486bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek } 487bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek } 488bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek return !AllWritten; 489bfbfee51ec8f20f3f1b9f8329705d816b67438e7Manuel Klimek} 490