20 #include "llvm/ADT/SmallString.h" 21 #include "llvm/Support/FileSystem.h" 22 #include "llvm/Support/raw_ostream.h" 23 using namespace clang;
50 bool removeLineIfEmpty) {
52 if (Size == 0)
return;
54 unsigned RealOffset = getMappedOffset(OrigOffset,
true);
55 assert(RealOffset+Size <= Buffer.
size() &&
"Invalid location");
58 Buffer.
erase(RealOffset, Size);
61 AddReplaceDelta(OrigOffset, -Size);
63 if (removeLineIfEmpty) {
68 unsigned curLineStartOffs = 0;
70 for (
unsigned i = 0; i != RealOffset; ++i) {
74 curLineStartOffs = i + 1;
79 unsigned lineSize = 0;
85 if (posI !=
end() && *posI ==
'\n') {
86 Buffer.
erase(curLineStartOffs, lineSize + 1);
87 AddReplaceDelta(curLineStartOffs, -(lineSize + 1));
96 if (Str.empty())
return;
98 unsigned RealOffset = getMappedOffset(OrigOffset, InsertAfter);
99 Buffer.
insert(RealOffset, Str.begin(), Str.end());
102 AddInsertDelta(OrigOffset, Str.size());
110 unsigned RealOffset = getMappedOffset(OrigOffset,
true);
111 Buffer.
erase(RealOffset, OrigLength);
112 Buffer.
insert(RealOffset, NewStr.begin(), NewStr.end());
113 if (OrigLength != NewStr.size())
114 AddReplaceDelta(OrigOffset, NewStr.size() - OrigLength);
126 if (!isRewritable(Range.
getBegin()) ||
127 !isRewritable(Range.
getEnd()))
return -1;
129 FileID StartFileID, EndFileID;
130 unsigned StartOff, EndOff;
132 StartOff = getLocationOffsetAndFileID(Range.
getBegin(), StartFileID);
133 EndOff = getLocationOffsetAndFileID(Range.
getEnd(), EndFileID);
135 if (StartFileID != EndFileID)
140 std::map<FileID, RewriteBuffer>::const_iterator I =
141 RewriteBuffers.find(StartFileID);
142 if (I != RewriteBuffers.end()) {
154 return EndOff-StartOff;
169 if (!isRewritable(Range.
getBegin()) ||
170 !isRewritable(Range.
getEnd()))
173 FileID StartFileID, EndFileID;
174 unsigned StartOff, EndOff;
175 StartOff = getLocationOffsetAndFileID(Range.
getBegin(), StartFileID);
176 EndOff = getLocationOffsetAndFileID(Range.
getEnd(), EndFileID);
178 if (StartFileID != EndFileID)
183 std::map<FileID, RewriteBuffer>::const_iterator I =
184 RewriteBuffers.find(StartFileID);
185 if (I == RewriteBuffers.end()) {
187 const char *Ptr = SourceMgr->getCharacterData(Range.
getBegin());
192 return std::string(Ptr, Ptr+EndOff-StartOff);
196 EndOff = RB.getMappedOffset(EndOff,
true);
197 StartOff = RB.getMappedOffset(StartOff);
205 std::advance(Start, StartOff);
207 std::advance(End, EndOff-StartOff);
209 return std::string(Start, End);
214 assert(Loc.
isValid() &&
"Invalid location");
215 std::pair<FileID,unsigned> V = SourceMgr->getDecomposedLoc(Loc);
224 std::map<FileID, RewriteBuffer>::iterator I =
225 RewriteBuffers.lower_bound(FID);
226 if (I != RewriteBuffers.end() && I->first == FID)
228 I = RewriteBuffers.insert(I, std::make_pair(FID,
RewriteBuffer()));
230 StringRef MB = SourceMgr->getBufferData(FID);
231 I->second.Initialize(MB.begin(), MB.end());
239 bool InsertAfter,
bool indentNewLines) {
240 if (!isRewritable(Loc))
return true;
242 unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID);
245 if (indentNewLines && Str.find(
'\n') != StringRef::npos) {
246 StringRef MB = SourceMgr->getBufferData(FID);
248 unsigned lineNo = SourceMgr->getLineNumber(FID, StartOffs) - 1;
250 Content = SourceMgr->getSLocEntry(FID).getFile().getContentCache();
254 StringRef indentSpace;
256 unsigned i = lineOffs;
259 indentSpace = MB.substr(lineOffs, i-lineOffs);
263 Str.split(lines,
"\n");
265 for (
unsigned i = 0, e = lines.size(); i != e; ++i) {
266 indentedStr += lines[i];
269 indentedStr += indentSpace;
272 Str = indentedStr.str();
275 getEditBuffer(FID).InsertText(StartOffs, Str, InsertAfter);
280 if (!isRewritable(Loc))
return true;
282 unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID);
286 getEditBuffer(FID).InsertText(StartOffs, Str,
true);
293 if (!isRewritable(Start))
return true;
295 unsigned StartOffs = getLocationOffsetAndFileID(Start, FID);
305 if (!isRewritable(Start))
return true;
307 unsigned StartOffs = getLocationOffsetAndFileID(Start, StartFileID);
309 getEditBuffer(StartFileID).ReplaceText(StartOffs, OrigLength, NewStr);
314 if (!isRewritable(range.
getBegin()))
return true;
315 if (!isRewritable(range.
getEnd()))
return true;
316 if (replacementRange.
isInvalid())
return true;
321 unsigned newOffs = getLocationOffsetAndFileID(replacementRange.
getBegin(),
323 StringRef MB = SourceMgr->getBufferData(FID);
324 return ReplaceText(start, origLength, MB.substr(newOffs, newLength));
330 if (!isRewritable(range.
getBegin()))
return true;
331 if (!isRewritable(range.
getEnd()))
return true;
332 if (!isRewritable(parentIndent))
return true;
334 FileID StartFileID, EndFileID, parentFileID;
335 unsigned StartOff, EndOff, parentOff;
337 StartOff = getLocationOffsetAndFileID(range.
getBegin(), StartFileID);
338 EndOff = getLocationOffsetAndFileID(range.
getEnd(), EndFileID);
339 parentOff = getLocationOffsetAndFileID(parentIndent, parentFileID);
341 if (StartFileID != EndFileID || StartFileID != parentFileID)
343 if (StartOff > EndOff)
347 StringRef MB = SourceMgr->getBufferData(FID);
349 unsigned parentLineNo = SourceMgr->getLineNumber(FID, parentOff) - 1;
350 unsigned startLineNo = SourceMgr->getLineNumber(FID, StartOff) - 1;
351 unsigned endLineNo = SourceMgr->getLineNumber(FID, EndOff) - 1;
354 Content = SourceMgr->getSLocEntry(FID).getFile().getContentCache();
361 StringRef parentSpace, startSpace;
363 unsigned i = parentLineOffs;
366 parentSpace = MB.substr(parentLineOffs, i-parentLineOffs);
371 startSpace = MB.substr(startLineOffs, i-startLineOffs);
373 if (parentSpace.size() >= startSpace.size())
375 if (!startSpace.startswith(parentSpace))
378 StringRef indent = startSpace.substr(parentSpace.size());
382 for (
unsigned lineNo = startLineNo; lineNo <= endLineNo; ++lineNo) {
387 StringRef origIndent = MB.substr(offs, i-offs);
388 if (origIndent.startswith(startSpace))
402 class AtomicallyMovedFile {
406 : Diagnostics(Diagnostics),
Filename(Filename), AllWritten(AllWritten) {
408 TempFilename +=
"-%%%%%%%%";
410 if (llvm::sys::fs::createUniqueFile(TempFilename, FD, TempFilename)) {
412 Diagnostics.
Report(clang::diag::err_unable_to_make_temp)
415 FileStream.reset(
new llvm::raw_fd_ostream(FD,
true));
419 ~AtomicallyMovedFile() {
424 if (std::error_code ec = llvm::sys::fs::rename(TempFilename, Filename)) {
426 Diagnostics.
Report(clang::diag::err_unable_to_rename_temp)
427 << TempFilename << Filename << ec.message();
430 llvm::sys::fs::remove(TempFilename);
434 bool ok() {
return (
bool)FileStream; }
435 raw_ostream &getStream() {
return *FileStream; }
441 std::unique_ptr<llvm::raw_fd_ostream> FileStream;
447 bool AllWritten =
true;
448 for (
buffer_iterator I = buffer_begin(), E = buffer_end(); I != E; ++I) {
450 getSourceMgr().getFileEntryForID(I->first);
451 AtomicallyMovedFile File(getSourceMgr().getDiagnostics(), Entry->
getName(),
454 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 SourceManager interface.
static CharSourceRange getTokenRange(SourceRange R)
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(SourceRange 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.
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...
bool IncludeInsertsAtBeginOfRange
Given a source range, true to include previous inserts at the beginning of the range as part of the r...
std::map< FileID, RewriteBuffer >::iterator buffer_iterator
SourceLocation getEnd() const
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...