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