21 #include "llvm/ADT/SmallString.h"
22 #include "llvm/Config/llvm-config.h"
23 #include "llvm/Support/FileSystem.h"
24 #include "llvm/Support/raw_ostream.h"
25 using namespace clang;
52 bool removeLineIfEmpty) {
54 if (Size == 0)
return;
56 unsigned RealOffset = getMappedOffset(OrigOffset,
true);
57 assert(RealOffset+Size <= Buffer.
size() &&
"Invalid location");
60 Buffer.
erase(RealOffset, Size);
63 AddReplaceDelta(OrigOffset, -Size);
65 if (removeLineIfEmpty) {
70 unsigned curLineStartOffs = 0;
72 for (
unsigned i = 0; i != RealOffset; ++i) {
76 curLineStartOffs = i + 1;
81 unsigned lineSize = 0;
87 if (posI !=
end() && *posI ==
'\n') {
88 Buffer.
erase(curLineStartOffs, lineSize + 1);
89 AddReplaceDelta(curLineStartOffs, -(lineSize + 1));
98 if (Str.empty())
return;
100 unsigned RealOffset = getMappedOffset(OrigOffset, InsertAfter);
101 Buffer.
insert(RealOffset, Str.begin(), Str.end());
104 AddInsertDelta(OrigOffset, Str.size());
112 unsigned RealOffset = getMappedOffset(OrigOffset,
true);
113 Buffer.
erase(RealOffset, OrigLength);
114 Buffer.
insert(RealOffset, NewStr.begin(), NewStr.end());
115 if (OrigLength != NewStr.size())
116 AddReplaceDelta(OrigOffset, NewStr.size() - OrigLength);
131 FileID StartFileID, EndFileID;
132 unsigned StartOff, EndOff;
134 StartOff = getLocationOffsetAndFileID(Range.
getBegin(), StartFileID);
135 EndOff = getLocationOffsetAndFileID(Range.
getEnd(), EndFileID);
137 if (StartFileID != EndFileID)
142 std::map<FileID, RewriteBuffer>::const_iterator I =
143 RewriteBuffers.find(StartFileID);
144 if (I != RewriteBuffers.end()) {
156 return EndOff-StartOff;
175 FileID StartFileID, EndFileID;
176 unsigned StartOff, EndOff;
177 StartOff = getLocationOffsetAndFileID(Range.
getBegin(), StartFileID);
178 EndOff = getLocationOffsetAndFileID(Range.
getEnd(), EndFileID);
180 if (StartFileID != EndFileID)
185 std::map<FileID, RewriteBuffer>::const_iterator I =
186 RewriteBuffers.find(StartFileID);
187 if (I == RewriteBuffers.end()) {
194 return std::string(Ptr, Ptr+EndOff-StartOff);
198 EndOff = RB.getMappedOffset(EndOff,
true);
199 StartOff = RB.getMappedOffset(StartOff);
207 std::advance(Start, StartOff);
209 std::advance(End, EndOff-StartOff);
211 return std::string(Start, End);
216 assert(Loc.
isValid() &&
"Invalid location");
226 std::map<FileID, RewriteBuffer>::iterator I =
227 RewriteBuffers.lower_bound(FID);
228 if (I != RewriteBuffers.end() && I->first == FID)
230 I = RewriteBuffers.insert(I, std::make_pair(FID,
RewriteBuffer()));
233 I->second.Initialize(MB.begin(), MB.end());
241 bool InsertAfter,
bool indentNewLines) {
244 unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID);
247 if (indentNewLines && Str.find(
'\n') != StringRef::npos) {
250 unsigned lineNo = SourceMgr->
getLineNumber(FID, StartOffs) - 1;
251 const SrcMgr::ContentCache *
253 unsigned lineOffs = Content->SourceLineCache[lineNo];
256 StringRef indentSpace;
258 unsigned i = lineOffs;
261 indentSpace = MB.substr(lineOffs, i-lineOffs);
265 Str.split(lines,
"\n");
267 for (
unsigned i = 0, e = lines.size(); i != e; ++i) {
268 indentedStr += lines[i];
271 indentedStr += indentSpace;
274 Str = indentedStr.str();
284 unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID);
297 unsigned StartOffs = getLocationOffsetAndFileID(Start, FID);
309 unsigned StartOffs = getLocationOffsetAndFileID(Start, StartFileID);
318 if (replacementRange.
isInvalid())
return true;
323 unsigned newOffs = getLocationOffsetAndFileID(replacementRange.
getBegin(),
326 return ReplaceText(start, origLength, MB.substr(newOffs, newLength));
336 FileID StartFileID, EndFileID, parentFileID;
337 unsigned StartOff, EndOff, parentOff;
339 StartOff = getLocationOffsetAndFileID(range.
getBegin(), StartFileID);
340 EndOff = getLocationOffsetAndFileID(range.
getEnd(), EndFileID);
341 parentOff = getLocationOffsetAndFileID(parentIndent, parentFileID);
343 if (StartFileID != EndFileID || StartFileID != parentFileID)
345 if (StartOff > EndOff)
351 unsigned parentLineNo = SourceMgr->
getLineNumber(FID, parentOff) - 1;
352 unsigned startLineNo = SourceMgr->
getLineNumber(FID, StartOff) - 1;
353 unsigned endLineNo = SourceMgr->
getLineNumber(FID, EndOff) - 1;
355 const SrcMgr::ContentCache *
359 unsigned parentLineOffs = Content->SourceLineCache[parentLineNo];
360 unsigned startLineOffs = Content->SourceLineCache[startLineNo];
363 StringRef parentSpace, startSpace;
365 unsigned i = parentLineOffs;
368 parentSpace = MB.substr(parentLineOffs, i-parentLineOffs);
373 startSpace = MB.substr(startLineOffs, i-startLineOffs);
375 if (parentSpace.size() >= startSpace.size())
377 if (!startSpace.startswith(parentSpace))
380 StringRef indent = startSpace.substr(parentSpace.size());
384 for (
unsigned lineNo = startLineNo; lineNo <= endLineNo; ++lineNo) {
385 unsigned offs = Content->SourceLineCache[lineNo];
389 StringRef origIndent = MB.substr(offs, i-offs);
390 if (origIndent.startswith(startSpace))
404 class AtomicallyMovedFile {
408 : Diagnostics(Diagnostics), Filename(Filename), AllWritten(AllWritten) {
409 TempFilename = Filename;
410 TempFilename +=
"-%%%%%%%%";
412 if (llvm::sys::fs::createUniqueFile(TempFilename.str(), FD, TempFilename)) {
414 Diagnostics.
Report(clang::diag::err_unable_to_make_temp)
417 FileStream.reset(
new llvm::raw_fd_ostream(FD,
true));
421 ~AtomicallyMovedFile() {
429 if (std::error_code ec =
430 llvm::sys::fs::rename(TempFilename.str(), Filename)) {
432 Diagnostics.
Report(clang::diag::err_unable_to_rename_temp)
433 << TempFilename << Filename << ec.message();
436 llvm::sys::fs::remove(TempFilename.str());
440 bool ok() {
return (
bool)FileStream; }
441 raw_ostream &getStream() {
return *FileStream; }
447 std::unique_ptr<llvm::raw_fd_ostream> FileStream;
453 bool AllWritten =
true;
460 I->second.write(File.getStream());
SourceLocation getEnd() const
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. To determine what the indentation ...
SourceLocation getBegin() const
SourceManager & getSourceMgr() const
Defines the clang::FileManager interface and associated types.
static LLVM_READONLY bool isWhitespace(unsigned char c)
Defines the SourceManager interface.
static CharSourceRange getTokenRange(SourceRange R)
const SrcMgr::SLocEntry & getSLocEntry(FileID FID, bool *Invalid=nullptr) const
const char * getCharacterData(SourceLocation SL, bool *Invalid=nullptr) const
Return a pointer to the start of the specified location in the appropriate spelling MemoryBuffer...
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)
StringRef getBufferData(FileID FID, bool *Invalid=nullptr) const
Return a StringRef to the source buffer data for the specified FileID.
bool ReplaceText(SourceLocation Start, unsigned OrigLength, StringRef NewStr)
Concrete class used by the front-end to report problems and issues.
buffer_iterator buffer_end()
const FileEntry * getFileEntryForID(FileID FID) const
Returns the FileEntry record for the provided FileID.
Represents a character-granular source range.
SourceLocation getEnd() const
static unsigned MeasureTokenLength(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts)
void InsertText(unsigned OrigOffset, StringRef Str, bool InsertAfter=true)
bool overwriteChangedFiles()
bool isTokenRange() const
Return true if the end of this range specifies the start of the last token. Return false if the end o...
const char * getName() const
void ReplaceText(unsigned OrigOffset, unsigned OrigLength, StringRef NewStr)
Encodes a location in the source. The SourceManager can decode this to get at the full include stack...
bool isValid() const
Return true if this is a valid SourceLocation object.
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)
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.
const FileInfo & getFile() const
SourceLocation getBegin() const
int getRangeSize(SourceRange Range, RewriteOptions opts=RewriteOptions()) const
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
const ContentCache * getContentCache() const
unsigned getLineNumber(FileID FID, unsigned FilePos, bool *Invalid=nullptr) const
Given a SourceLocation, return the spelling line number for the position indicated.
Defines the Diagnostic-related interfaces.
raw_ostream & write(raw_ostream &Stream) const
Write to Stream the result of applying all changes to the original buffer. Note that it isn't safe to...
std::string getRewrittenText(SourceRange Range) const
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
buffer_iterator buffer_begin()
static bool isRewritable(SourceLocation Loc)
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.
std::pair< FileID, unsigned > getDecomposedLoc(SourceLocation Loc) const
Decompose the specified location into a raw FileID + Offset pair.
bool IncludeInsertsAtEndOfRange
Given a source range, true to include previous inserts at the end of the range as part of the range i...