23 #include "llvm/ADT/SmallString.h" 24 #include "llvm/ADT/SmallVector.h" 25 #include "llvm/ADT/StringRef.h" 26 #include "llvm/Support/FileSystem.h" 27 #include "llvm/Support/raw_ostream.h" 32 #include <system_error> 35 using namespace clang;
62 bool removeLineIfEmpty) {
64 if (Size == 0)
return;
66 unsigned RealOffset = getMappedOffset(OrigOffset,
true);
67 assert(RealOffset+Size <= Buffer.
size() &&
"Invalid location");
70 Buffer.
erase(RealOffset, Size);
73 AddReplaceDelta(OrigOffset, -Size);
75 if (removeLineIfEmpty) {
80 unsigned curLineStartOffs = 0;
82 for (
unsigned i = 0; i != RealOffset; ++i) {
86 curLineStartOffs = i + 1;
91 unsigned lineSize = 0;
97 if (posI !=
end() && *posI ==
'\n') {
98 Buffer.
erase(curLineStartOffs, lineSize + 1);
110 AddReplaceDelta(curLineStartOffs, -(lineSize + 1));
118 if (Str.empty())
return;
120 unsigned RealOffset = getMappedOffset(OrigOffset, InsertAfter);
121 Buffer.
insert(RealOffset, Str.begin(), Str.end());
124 AddInsertDelta(OrigOffset, Str.size());
132 unsigned RealOffset = getMappedOffset(OrigOffset,
true);
133 Buffer.
erase(RealOffset, OrigLength);
134 Buffer.
insert(RealOffset, NewStr.begin(), NewStr.end());
135 if (OrigLength != NewStr.size())
136 AddReplaceDelta(OrigOffset, NewStr.size() - OrigLength);
147 if (!isRewritable(Range.
getBegin()) ||
148 !isRewritable(Range.
getEnd()))
return -1;
150 FileID StartFileID, EndFileID;
151 unsigned StartOff = getLocationOffsetAndFileID(Range.
getBegin(), StartFileID);
152 unsigned EndOff = getLocationOffsetAndFileID(Range.
getEnd(), EndFileID);
154 if (StartFileID != EndFileID)
159 std::map<FileID, RewriteBuffer>::const_iterator I =
160 RewriteBuffers.find(StartFileID);
161 if (I != RewriteBuffers.end()) {
172 return EndOff-StartOff;
185 if (!isRewritable(Range.
getBegin()) ||
186 !isRewritable(Range.
getEnd()))
189 FileID StartFileID, EndFileID;
190 unsigned StartOff, EndOff;
191 StartOff = getLocationOffsetAndFileID(Range.
getBegin(), StartFileID);
192 EndOff = getLocationOffsetAndFileID(Range.
getEnd(), EndFileID);
194 if (StartFileID != EndFileID)
199 std::map<FileID, RewriteBuffer>::const_iterator I =
200 RewriteBuffers.find(StartFileID);
201 if (I == RewriteBuffers.end()) {
203 const char *Ptr = SourceMgr->getCharacterData(Range.
getBegin());
210 return std::string(Ptr, Ptr+EndOff-StartOff);
214 EndOff = RB.getMappedOffset(EndOff,
true);
215 StartOff = RB.getMappedOffset(StartOff);
224 std::advance(Start, StartOff);
226 std::advance(End, EndOff-StartOff);
228 return std::string(Start, End);
233 assert(Loc.
isValid() &&
"Invalid location");
234 std::pair<FileID, unsigned>
V = SourceMgr->getDecomposedLoc(Loc);
241 std::map<FileID, RewriteBuffer>::iterator I =
242 RewriteBuffers.lower_bound(FID);
243 if (I != RewriteBuffers.end() && I->first == FID)
245 I = RewriteBuffers.insert(I, std::make_pair(FID,
RewriteBuffer()));
247 StringRef MB = SourceMgr->getBufferData(FID);
256 bool InsertAfter,
bool indentNewLines) {
257 if (!isRewritable(Loc))
return true;
259 unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID);
262 if (indentNewLines && Str.find(
'\n') != StringRef::npos) {
263 StringRef MB = SourceMgr->getBufferData(FID);
265 unsigned lineNo = SourceMgr->getLineNumber(FID, StartOffs) - 1;
267 Content = SourceMgr->getSLocEntry(FID).getFile().getContentCache();
271 StringRef indentSpace;
273 unsigned i = lineOffs;
276 indentSpace = MB.substr(lineOffs, i-lineOffs);
280 Str.split(lines,
"\n");
282 for (
unsigned i = 0, e = lines.size(); i != e; ++i) {
283 indentedStr += lines[i];
286 indentedStr += indentSpace;
289 Str = indentedStr.str();
292 getEditBuffer(FID).InsertText(StartOffs, Str, InsertAfter);
297 if (!isRewritable(Loc))
return true;
299 unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID);
303 getEditBuffer(FID).InsertText(StartOffs, Str,
true);
310 if (!isRewritable(Start))
return true;
312 unsigned StartOffs = getLocationOffsetAndFileID(Start, FID);
322 if (!isRewritable(Start))
return true;
324 unsigned StartOffs = getLocationOffsetAndFileID(Start, StartFileID);
326 getEditBuffer(StartFileID).ReplaceText(StartOffs, OrigLength, NewStr);
331 if (!isRewritable(range.
getBegin()))
return true;
332 if (!isRewritable(range.
getEnd()))
return true;
333 if (replacementRange.
isInvalid())
return true;
338 unsigned newOffs = getLocationOffsetAndFileID(replacementRange.
getBegin(),
340 StringRef MB = SourceMgr->getBufferData(FID);
341 return ReplaceText(start, origLength, MB.substr(newOffs, newLength));
347 if (!isRewritable(range.
getBegin()))
return true;
348 if (!isRewritable(range.
getEnd()))
return true;
349 if (!isRewritable(parentIndent))
return true;
351 FileID StartFileID, EndFileID, parentFileID;
352 unsigned StartOff, EndOff, parentOff;
354 StartOff = getLocationOffsetAndFileID(range.
getBegin(), StartFileID);
355 EndOff = getLocationOffsetAndFileID(range.
getEnd(), EndFileID);
356 parentOff = getLocationOffsetAndFileID(parentIndent, parentFileID);
358 if (StartFileID != EndFileID || StartFileID != parentFileID)
360 if (StartOff > EndOff)
364 StringRef MB = SourceMgr->getBufferData(FID);
366 unsigned parentLineNo = SourceMgr->getLineNumber(FID, parentOff) - 1;
367 unsigned startLineNo = SourceMgr->getLineNumber(FID, StartOff) - 1;
368 unsigned endLineNo = SourceMgr->getLineNumber(FID, EndOff) - 1;
371 Content = SourceMgr->getSLocEntry(FID).getFile().getContentCache();
378 StringRef parentSpace, startSpace;
380 unsigned i = parentLineOffs;
383 parentSpace = MB.substr(parentLineOffs, i-parentLineOffs);
388 startSpace = MB.substr(startLineOffs, i-startLineOffs);
390 if (parentSpace.size() >= startSpace.size())
392 if (!startSpace.startswith(parentSpace))
395 StringRef indent = startSpace.substr(parentSpace.size());
399 for (
unsigned lineNo = startLineNo; lineNo <= endLineNo; ++lineNo) {
404 StringRef origIndent = MB.substr(offs, i-offs);
405 if (origIndent.startswith(startSpace))
420 class AtomicallyMovedFile {
424 : Diagnostics(Diagnostics),
Filename(Filename), AllWritten(AllWritten) {
426 TempFilename +=
"-%%%%%%%%";
428 if (llvm::sys::fs::createUniqueFile(TempFilename, FD, TempFilename)) {
430 Diagnostics.
Report(clang::diag::err_unable_to_make_temp)
433 FileStream.reset(
new llvm::raw_fd_ostream(FD,
true));
437 ~AtomicallyMovedFile() {
442 if (std::error_code ec = llvm::sys::fs::rename(TempFilename, Filename)) {
444 Diagnostics.
Report(clang::diag::err_unable_to_rename_temp)
445 << TempFilename << Filename << ec.message();
452 bool ok() {
return (
bool)FileStream; }
453 raw_ostream &getStream() {
return *FileStream; }
459 std::unique_ptr<llvm::raw_fd_ostream> FileStream;
466 bool AllWritten =
true;
467 for (
buffer_iterator I = buffer_begin(), E = buffer_end(); I != E; ++I) {
469 getSourceMgr().getFileEntryForID(I->first);
470 AtomicallyMovedFile File(getSourceMgr().getDiagnostics(), Entry->
getName(),
473 I->second.write(File.getStream());
void insert(unsigned Offset, const char *Start, const char *End)
bool IncreaseIndentation(CharSourceRange range, SourceLocation parentIndent)
Increase indentation for the lines between the given source range.
Defines the clang::FileManager interface and associated types.
Defines the SourceManager interface.
static CharSourceRange getTokenRange(SourceRange R)
void Initialize(const char *BufStart, const char *BufEnd)
Initialize - Start this rewrite buffer out with a copy of the unmodified input buffer.
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
bool RemoveText(SourceLocation Start, unsigned Length, RewriteOptions opts=RewriteOptions())
RemoveText - Remove the specified text region.
void erase(unsigned Offset, unsigned NumBytes)
RewriteBuffer & getEditBuffer(FileID FID)
getEditBuffer - This is like getRewriteBufferFor, but always returns a buffer, and allows you to writ...
RewriteBuffer - As code is rewritten, SourceBuffer's from the original input with modifications get a...
std::string getRewrittenText(CharSourceRange Range) const
getRewrittenText - Return the rewritten form of the text in the specified range.
SourceLocation getBegin() const
One instance of this struct is kept for every file loaded or used.
bool ReplaceText(SourceLocation Start, unsigned OrigLength, StringRef NewStr)
ReplaceText - This method replaces a range of characters in the input buffer with a new string...
Concrete class used by the front-end to report problems and issues.
Defines the Diagnostic-related interfaces.
Represents a character-granular source range.
static unsigned MeasureTokenLength(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts)
MeasureTokenLength - Relex the token at the specified location and return its length in bytes in the ...
SourceLocation getEnd() const
int getRangeSize(SourceRange Range, RewriteOptions opts=RewriteOptions()) const
getRangeSize - Return the size in bytes of the specified range if they are in the same file...
void InsertText(unsigned OrigOffset, StringRef Str, bool InsertAfter=true)
InsertText - Insert some text at the specified point, where the offset in the buffer is specified rel...
bool overwriteChangedFiles()
overwriteChangedFiles - Save all changed files to disk.
void ReplaceText(unsigned OrigOffset, unsigned OrigLength, StringRef NewStr)
ReplaceText - This method replaces a range of characters in the input buffer with a new string...
Encodes a location in the source.
static bool isWhitespaceExceptNL(unsigned char c)
Return true if this character is non-new-line whitespace: ' ', '\t', '\f', '\v', '\r'.
raw_ostream & write(raw_ostream &Stream) const
Write to Stream the result of applying all changes to the original buffer.
StringRef getName() const
Cached information about one file (either on disk or in the virtual file system). ...
bool InsertText(SourceLocation Loc, StringRef Str, bool InsertAfter=true, bool indentNewLines=false)
InsertText - Insert the specified string at the specified location in the original buffer...
bool RemoveLineIfEmpty
If true and removing some text leaves a blank line also remove the empty line (false by default)...
void RemoveText(unsigned OrigOffset, unsigned Size, bool removeLineIfEmpty=false)
RemoveText - Remove the specified text.
unsigned * SourceLineCache
A bump pointer allocated array of offsets for each source line.
std::map< FileID, RewriteBuffer >::iterator buffer_iterator
bool isTokenRange() const
Return true if the end of this range specifies the start of the last token.
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
Dataflow Directional Tag Classes.
bool isValid() const
Return true if this is a valid SourceLocation object.
RopePieceBTreeIterator - This class provides read-only forward iteration over bytes that are in a Rop...
static int getRangeSize(const SourceManager &Sources, const CharSourceRange &Range, const LangOptions &LangOpts)
bool IncludeInsertsAtBeginOfRange
Given a source range, true to include previous inserts at the beginning of the range as part of the r...
SourceLocation getEnd() const
Defines the clang::SourceLocation class and associated facilities.
Defines the Diagnostic IDs-related interfaces.
A trivial tuple used to represent a source range.
bool InsertTextAfterToken(SourceLocation Loc, StringRef Str)
Insert the specified string after the token in the specified location.
SourceLocation getBegin() const
bool IncludeInsertsAtEndOfRange
Given a source range, true to include previous inserts at the end of the range as part of the range i...