24 #include "llvm/ADT/SmallString.h" 25 #include "llvm/ADT/SmallVector.h" 26 #include "llvm/ADT/StringRef.h" 27 #include "llvm/Support/FileSystem.h" 28 #include "llvm/Support/raw_ostream.h" 33 #include <system_error> 36 using namespace clang;
63 bool removeLineIfEmpty) {
65 if (Size == 0)
return;
67 unsigned RealOffset = getMappedOffset(OrigOffset,
true);
68 assert(RealOffset+Size <= Buffer.
size() &&
"Invalid location");
71 Buffer.
erase(RealOffset, Size);
74 AddReplaceDelta(OrigOffset, -Size);
76 if (removeLineIfEmpty) {
81 unsigned curLineStartOffs = 0;
83 for (
unsigned i = 0; i != RealOffset; ++i) {
87 curLineStartOffs = i + 1;
92 unsigned lineSize = 0;
98 if (posI !=
end() && *posI ==
'\n') {
99 Buffer.
erase(curLineStartOffs, lineSize + 1);
100 AddReplaceDelta(curLineStartOffs, -(lineSize + 1));
108 if (Str.empty())
return;
110 unsigned RealOffset = getMappedOffset(OrigOffset, InsertAfter);
111 Buffer.
insert(RealOffset, Str.begin(), Str.end());
114 AddInsertDelta(OrigOffset, Str.size());
122 unsigned RealOffset = getMappedOffset(OrigOffset,
true);
123 Buffer.
erase(RealOffset, OrigLength);
124 Buffer.
insert(RealOffset, NewStr.begin(), NewStr.end());
125 if (OrigLength != NewStr.size())
126 AddReplaceDelta(OrigOffset, NewStr.size() - OrigLength);
137 if (!isRewritable(Range.
getBegin()) ||
138 !isRewritable(Range.
getEnd()))
return -1;
140 FileID StartFileID, EndFileID;
141 unsigned StartOff = getLocationOffsetAndFileID(Range.
getBegin(), StartFileID);
142 unsigned EndOff = getLocationOffsetAndFileID(Range.
getEnd(), EndFileID);
144 if (StartFileID != EndFileID)
149 std::map<FileID, RewriteBuffer>::const_iterator I =
150 RewriteBuffers.find(StartFileID);
151 if (I != RewriteBuffers.end()) {
162 return EndOff-StartOff;
175 if (!isRewritable(Range.
getBegin()) ||
176 !isRewritable(Range.
getEnd()))
179 FileID StartFileID, EndFileID;
180 unsigned StartOff, EndOff;
181 StartOff = getLocationOffsetAndFileID(Range.
getBegin(), StartFileID);
182 EndOff = getLocationOffsetAndFileID(Range.
getEnd(), EndFileID);
184 if (StartFileID != EndFileID)
189 std::map<FileID, RewriteBuffer>::const_iterator I =
190 RewriteBuffers.find(StartFileID);
191 if (I == RewriteBuffers.end()) {
193 const char *Ptr = SourceMgr->getCharacterData(Range.
getBegin());
198 return std::string(Ptr, Ptr+EndOff-StartOff);
202 EndOff = RB.getMappedOffset(EndOff,
true);
203 StartOff = RB.getMappedOffset(StartOff);
211 std::advance(Start, StartOff);
213 std::advance(End, EndOff-StartOff);
215 return std::string(Start, End);
220 assert(Loc.
isValid() &&
"Invalid location");
221 std::pair<FileID, unsigned> V = SourceMgr->getDecomposedLoc(Loc);
228 std::map<FileID, RewriteBuffer>::iterator I =
229 RewriteBuffers.lower_bound(FID);
230 if (I != RewriteBuffers.end() && I->first == FID)
232 I = RewriteBuffers.insert(I, std::make_pair(FID,
RewriteBuffer()));
234 StringRef MB = SourceMgr->getBufferData(FID);
243 bool InsertAfter,
bool indentNewLines) {
244 if (!isRewritable(Loc))
return true;
246 unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID);
249 if (indentNewLines && Str.find(
'\n') != StringRef::npos) {
250 StringRef MB = SourceMgr->getBufferData(FID);
252 unsigned lineNo = SourceMgr->getLineNumber(FID, StartOffs) - 1;
254 Content = SourceMgr->getSLocEntry(FID).getFile().getContentCache();
258 StringRef indentSpace;
260 unsigned i = lineOffs;
263 indentSpace = MB.substr(lineOffs, i-lineOffs);
267 Str.split(lines,
"\n");
269 for (
unsigned i = 0, e = lines.size(); i != e; ++i) {
270 indentedStr += lines[i];
273 indentedStr += indentSpace;
276 Str = indentedStr.str();
279 getEditBuffer(FID).InsertText(StartOffs, Str, InsertAfter);
284 if (!isRewritable(Loc))
return true;
286 unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID);
290 getEditBuffer(FID).InsertText(StartOffs, Str,
true);
297 if (!isRewritable(Start))
return true;
299 unsigned StartOffs = getLocationOffsetAndFileID(Start, FID);
309 if (!isRewritable(Start))
return true;
311 unsigned StartOffs = getLocationOffsetAndFileID(Start, StartFileID);
313 getEditBuffer(StartFileID).ReplaceText(StartOffs, OrigLength, NewStr);
318 if (!isRewritable(range.
getBegin()))
return true;
319 if (!isRewritable(range.
getEnd()))
return true;
320 if (replacementRange.
isInvalid())
return true;
325 unsigned newOffs = getLocationOffsetAndFileID(replacementRange.
getBegin(),
327 StringRef MB = SourceMgr->getBufferData(FID);
328 return ReplaceText(start, origLength, MB.substr(newOffs, newLength));
334 if (!isRewritable(range.
getBegin()))
return true;
335 if (!isRewritable(range.
getEnd()))
return true;
336 if (!isRewritable(parentIndent))
return true;
338 FileID StartFileID, EndFileID, parentFileID;
339 unsigned StartOff, EndOff, parentOff;
341 StartOff = getLocationOffsetAndFileID(range.
getBegin(), StartFileID);
342 EndOff = getLocationOffsetAndFileID(range.
getEnd(), EndFileID);
343 parentOff = getLocationOffsetAndFileID(parentIndent, parentFileID);
345 if (StartFileID != EndFileID || StartFileID != parentFileID)
347 if (StartOff > EndOff)
351 StringRef MB = SourceMgr->getBufferData(FID);
353 unsigned parentLineNo = SourceMgr->getLineNumber(FID, parentOff) - 1;
354 unsigned startLineNo = SourceMgr->getLineNumber(FID, StartOff) - 1;
355 unsigned endLineNo = SourceMgr->getLineNumber(FID, EndOff) - 1;
358 Content = SourceMgr->getSLocEntry(FID).getFile().getContentCache();
365 StringRef parentSpace, startSpace;
367 unsigned i = parentLineOffs;
370 parentSpace = MB.substr(parentLineOffs, i-parentLineOffs);
375 startSpace = MB.substr(startLineOffs, i-startLineOffs);
377 if (parentSpace.size() >= startSpace.size())
379 if (!startSpace.startswith(parentSpace))
382 StringRef indent = startSpace.substr(parentSpace.size());
386 for (
unsigned lineNo = startLineNo; lineNo <= endLineNo; ++lineNo) {
391 StringRef origIndent = MB.substr(offs, i-offs);
392 if (origIndent.startswith(startSpace))
407 class AtomicallyMovedFile {
411 : Diagnostics(Diagnostics),
Filename(Filename), AllWritten(AllWritten) {
413 TempFilename +=
"-%%%%%%%%";
415 if (llvm::sys::fs::createUniqueFile(TempFilename, FD, TempFilename)) {
417 Diagnostics.
Report(clang::diag::err_unable_to_make_temp)
420 FileStream.reset(
new llvm::raw_fd_ostream(FD,
true));
424 ~AtomicallyMovedFile() {
429 if (std::error_code ec = llvm::sys::fs::rename(TempFilename, Filename)) {
431 Diagnostics.
Report(clang::diag::err_unable_to_rename_temp)
432 << TempFilename << Filename << ec.message();
435 llvm::sys::fs::remove(TempFilename);
439 bool ok() {
return (
bool)FileStream; }
440 raw_ostream &getStream() {
return *FileStream; }
446 std::unique_ptr<llvm::raw_fd_ostream> FileStream;
453 bool AllWritten =
true;
454 for (
buffer_iterator I = buffer_begin(), E = buffer_end(); I != E; ++I) {
456 getSourceMgr().getFileEntryForID(I->first);
457 AtomicallyMovedFile File(getSourceMgr().getDiagnostics(), Entry->
getName(),
460 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(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.
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...