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);
99 AddReplaceDelta(curLineStartOffs, -(lineSize + 1));
107 if (Str.empty())
return;
109 unsigned RealOffset = getMappedOffset(OrigOffset, InsertAfter);
110 Buffer.
insert(RealOffset, Str.begin(), Str.end());
113 AddInsertDelta(OrigOffset, Str.size());
121 unsigned RealOffset = getMappedOffset(OrigOffset,
true);
122 Buffer.
erase(RealOffset, OrigLength);
123 Buffer.
insert(RealOffset, NewStr.begin(), NewStr.end());
124 if (OrigLength != NewStr.size())
125 AddReplaceDelta(OrigOffset, NewStr.size() - OrigLength);
136 if (!isRewritable(Range.
getBegin()) ||
137 !isRewritable(Range.
getEnd()))
return -1;
139 FileID StartFileID, EndFileID;
140 unsigned StartOff = getLocationOffsetAndFileID(Range.
getBegin(), StartFileID);
141 unsigned EndOff = getLocationOffsetAndFileID(Range.
getEnd(), EndFileID);
143 if (StartFileID != EndFileID)
148 std::map<FileID, RewriteBuffer>::const_iterator I =
149 RewriteBuffers.find(StartFileID);
150 if (I != RewriteBuffers.end()) {
161 return EndOff-StartOff;
174 if (!isRewritable(Range.
getBegin()) ||
175 !isRewritable(Range.
getEnd()))
178 FileID StartFileID, EndFileID;
179 unsigned StartOff, EndOff;
180 StartOff = getLocationOffsetAndFileID(Range.
getBegin(), StartFileID);
181 EndOff = getLocationOffsetAndFileID(Range.
getEnd(), EndFileID);
183 if (StartFileID != EndFileID)
188 std::map<FileID, RewriteBuffer>::const_iterator I =
189 RewriteBuffers.find(StartFileID);
190 if (I == RewriteBuffers.end()) {
192 const char *Ptr = SourceMgr->getCharacterData(Range.
getBegin());
199 return std::string(Ptr, Ptr+EndOff-StartOff);
203 EndOff = RB.getMappedOffset(EndOff,
true);
204 StartOff = RB.getMappedOffset(StartOff);
213 std::advance(Start, StartOff);
215 std::advance(End, EndOff-StartOff);
217 return std::string(Start, End);
222 assert(Loc.
isValid() &&
"Invalid location");
223 std::pair<FileID, unsigned>
V = SourceMgr->getDecomposedLoc(Loc);
230 std::map<FileID, RewriteBuffer>::iterator I =
231 RewriteBuffers.lower_bound(FID);
232 if (I != RewriteBuffers.end() && I->first == FID)
234 I = RewriteBuffers.insert(I, std::make_pair(FID,
RewriteBuffer()));
236 StringRef MB = SourceMgr->getBufferData(FID);
245 bool InsertAfter,
bool indentNewLines) {
246 if (!isRewritable(Loc))
return true;
248 unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID);
251 if (indentNewLines && Str.find(
'\n') != StringRef::npos) {
252 StringRef MB = SourceMgr->getBufferData(FID);
254 unsigned lineNo = SourceMgr->getLineNumber(FID, StartOffs) - 1;
256 Content = SourceMgr->getSLocEntry(FID).getFile().getContentCache();
260 StringRef indentSpace;
262 unsigned i = lineOffs;
265 indentSpace = MB.substr(lineOffs, i-lineOffs);
269 Str.split(lines,
"\n");
271 for (
unsigned i = 0, e = lines.size();
i != e; ++
i) {
272 indentedStr += lines[
i];
275 indentedStr += indentSpace;
278 Str = indentedStr.str();
281 getEditBuffer(FID).InsertText(StartOffs, Str, InsertAfter);
286 if (!isRewritable(Loc))
return true;
288 unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID);
292 getEditBuffer(FID).InsertText(StartOffs, Str,
true);
299 if (!isRewritable(Start))
return true;
301 unsigned StartOffs = getLocationOffsetAndFileID(Start, FID);
311 if (!isRewritable(Start))
return true;
313 unsigned StartOffs = getLocationOffsetAndFileID(Start, StartFileID);
315 getEditBuffer(StartFileID).ReplaceText(StartOffs, OrigLength, NewStr);
320 if (!isRewritable(range.
getBegin()))
return true;
321 if (!isRewritable(range.
getEnd()))
return true;
322 if (replacementRange.
isInvalid())
return true;
327 unsigned newOffs = getLocationOffsetAndFileID(replacementRange.
getBegin(),
329 StringRef MB = SourceMgr->getBufferData(FID);
330 return ReplaceText(start, origLength, MB.substr(newOffs, newLength));
336 if (!isRewritable(range.
getBegin()))
return true;
337 if (!isRewritable(range.
getEnd()))
return true;
338 if (!isRewritable(parentIndent))
return true;
340 FileID StartFileID, EndFileID, parentFileID;
341 unsigned StartOff, EndOff, parentOff;
343 StartOff = getLocationOffsetAndFileID(range.
getBegin(), StartFileID);
344 EndOff = getLocationOffsetAndFileID(range.
getEnd(), EndFileID);
345 parentOff = getLocationOffsetAndFileID(parentIndent, parentFileID);
347 if (StartFileID != EndFileID || StartFileID != parentFileID)
349 if (StartOff > EndOff)
353 StringRef MB = SourceMgr->getBufferData(FID);
355 unsigned parentLineNo = SourceMgr->getLineNumber(FID, parentOff) - 1;
356 unsigned startLineNo = SourceMgr->getLineNumber(FID, StartOff) - 1;
357 unsigned endLineNo = SourceMgr->getLineNumber(FID, EndOff) - 1;
360 Content = SourceMgr->getSLocEntry(FID).getFile().getContentCache();
367 StringRef parentSpace, startSpace;
369 unsigned i = parentLineOffs;
372 parentSpace = MB.substr(parentLineOffs, i-parentLineOffs);
377 startSpace = MB.substr(startLineOffs, i-startLineOffs);
379 if (parentSpace.size() >= startSpace.size())
381 if (!startSpace.startswith(parentSpace))
384 StringRef indent = startSpace.substr(parentSpace.size());
388 for (
unsigned lineNo = startLineNo; lineNo <= endLineNo; ++lineNo) {
393 StringRef origIndent = MB.substr(offs, i-offs);
394 if (origIndent.startswith(startSpace))
409 class AtomicallyMovedFile {
413 : Diagnostics(Diagnostics),
Filename(Filename), AllWritten(AllWritten) {
415 TempFilename +=
"-%%%%%%%%";
417 if (llvm::sys::fs::createUniqueFile(TempFilename, FD, TempFilename)) {
419 Diagnostics.
Report(clang::diag::err_unable_to_make_temp)
422 FileStream.reset(
new llvm::raw_fd_ostream(FD,
true));
426 ~AtomicallyMovedFile() {
431 if (std::error_code ec = llvm::sys::fs::rename(TempFilename, Filename)) {
433 Diagnostics.
Report(clang::diag::err_unable_to_rename_temp)
434 << TempFilename << Filename << ec.message();
441 bool ok() {
return (
bool)FileStream; }
442 raw_ostream &getStream() {
return *FileStream; }
448 std::unique_ptr<llvm::raw_fd_ostream> FileStream;
455 bool AllWritten =
true;
456 for (
buffer_iterator I = buffer_begin(), E = buffer_end(); I != E; ++I) {
458 getSourceMgr().getFileEntryForID(I->first);
459 AtomicallyMovedFile File(getSourceMgr().getDiagnostics(), Entry->
getName(),
462 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...