From: Argyrios Kyrtzidis Date: Thu, 7 Apr 2011 18:10:12 +0000 (+0000) Subject: Enhance the Rewriter. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b65ed34ebf0380c001756eea7a1c1d01e110b557;p=clang Enhance the Rewriter. -Allow removing a line completely if it ends up empty -Provide more control on what should be removed. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@129085 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Rewrite/Rewriter.h b/include/clang/Rewrite/Rewriter.h index b3d4035628..252f0baf89 100644 --- a/include/clang/Rewrite/Rewriter.h +++ b/include/clang/Rewrite/Rewriter.h @@ -58,7 +58,8 @@ public: llvm::raw_ostream &write(llvm::raw_ostream &) const; /// RemoveText - Remove the specified text. - void RemoveText(unsigned OrigOffset, unsigned Size); + void RemoveText(unsigned OrigOffset, unsigned Size, + bool removeLineIfEmpty = false); /// InsertText - Insert some text at the specified point, where the offset in /// the buffer is specified relative to the original SourceBuffer. The @@ -150,8 +151,11 @@ public: /// getRangeSize - Return the size in bytes of the specified range if they /// are in the same file. If not, this returns -1. - int getRangeSize(SourceRange Range) const; - int getRangeSize(const CharSourceRange &Range) const; + /// If AfterInserts is true and if the beginning of range indicates a position + /// where text is inserted, the beginning of range will be after any inserted + /// text at the position. + int getRangeSize(SourceRange Range, bool AfterInserts = false) const; + int getRangeSize(const CharSourceRange &Range, bool AfterInserts=false) const; /// getRewrittenText - Return the rewritten form of the text in the specified /// range. If the start or end of the range was unrewritable or if they are @@ -176,6 +180,10 @@ public: return InsertText(Loc, Str); } + /// \brief Insert the specified string after the token in the + /// specified location. + bool InsertTextAfterToken(SourceLocation Loc, llvm::StringRef Str); + /// InsertText - Insert the specified string at the specified location in the /// original buffer. This method returns true (and does nothing) if the input /// location was not rewritable, false otherwise. Text is @@ -186,7 +194,34 @@ public: } /// RemoveText - Remove the specified text region. - bool RemoveText(SourceLocation Start, unsigned Length); + bool RemoveText(SourceLocation Start, unsigned Length, + bool removeLineIfEmpty = false); + + /// \brief Remove the specified text region. + /// + /// \param afterInserts if true the beginning of removal will be after any + /// inserted text at the position. + /// + /// \param removeLineIfEmpty if true and removing the text leaves a blank line + /// also remove the empty line. + bool RemoveText(CharSourceRange range, bool afterInserts = false, + bool removeLineIfEmpty = false) { + return RemoveText(range.getBegin(), getRangeSize(range, afterInserts), + removeLineIfEmpty); + } + + /// \brief Remove the specified text region. + /// + /// \param afterInserts if true the beginning of removal will be after any + /// inserted text at the position. + /// + /// \param removeLineIfEmpty if true and removing the text leaves a blank line + /// also remove the empty line. + bool RemoveText(SourceRange range, bool afterInserts = false, + bool removeLineIfEmpty = false) { + return RemoveText(range.getBegin(), getRangeSize(range, afterInserts), + removeLineIfEmpty); + } /// ReplaceText - This method replaces a range of characters in the input /// buffer with a new string. This is effectively a combined "remove/insert" @@ -194,6 +229,18 @@ public: bool ReplaceText(SourceLocation Start, unsigned OrigLength, llvm::StringRef NewStr); + /// ReplaceText - This method replaces a range of characters in the input + /// buffer with a new string. This is effectively a combined "remove/insert" + /// operation. + bool ReplaceText(SourceRange range, llvm::StringRef NewStr) { + return ReplaceText(range.getBegin(), getRangeSize(range), NewStr); + } + + /// ReplaceText - This method replaces a range of characters in the input + /// buffer with a new string. This is effectively a combined "remove/insert" + /// operation. + bool ReplaceText(SourceRange range, SourceRange replacementRange); + /// ReplaceStmt - This replaces a Stmt/Expr with another, using the pretty /// printer to generate the replacement code. This returns true if the input /// could not be rewritten, or false if successful. diff --git a/lib/Rewrite/Rewriter.cpp b/lib/Rewrite/Rewriter.cpp index 92e2b03f76..c4b6757bac 100644 --- a/lib/Rewrite/Rewriter.cpp +++ b/lib/Rewrite/Rewriter.cpp @@ -26,7 +26,23 @@ llvm::raw_ostream &RewriteBuffer::write(llvm::raw_ostream &os) const { return os; } -void RewriteBuffer::RemoveText(unsigned OrigOffset, unsigned Size) { +/// \brief Return true if this character is non-new-line whitespace: +/// ' ', '\t', '\f', '\v', '\r'. +static inline bool isWhitespace(unsigned char c) { + switch (c) { + case ' ': + case '\t': + case '\f': + case '\v': + case '\r': + return true; + default: + return false; + } +} + +void RewriteBuffer::RemoveText(unsigned OrigOffset, unsigned Size, + bool removeLineIfEmpty) { // Nothing to remove, exit early. if (Size == 0) return; @@ -38,6 +54,34 @@ void RewriteBuffer::RemoveText(unsigned OrigOffset, unsigned Size) { // Add a delta so that future changes are offset correctly. AddReplaceDelta(OrigOffset, -Size); + + if (removeLineIfEmpty) { + // Find the line that the remove occurred and if it is completely empty + // remove the line as well. + + iterator curLineStart = begin(); + unsigned curLineStartOffs = 0; + iterator posI = begin(); + for (unsigned i = 0; i != RealOffset; ++i) { + if (*posI == '\n') { + curLineStart = posI; + ++curLineStart; + curLineStartOffs = i + 1; + } + ++posI; + } + + unsigned lineSize = 0; + posI = curLineStart; + while (posI != end() && isWhitespace(*posI)) { + ++posI; + ++lineSize; + } + if (posI != end() && *posI == '\n') { + Buffer.erase(curLineStartOffs, lineSize + 1/* + '\n'*/); + AddReplaceDelta(curLineStartOffs, -(lineSize + 1/* + '\n'*/)); + } + } } void RewriteBuffer::InsertText(unsigned OrigOffset, llvm::StringRef Str, @@ -72,7 +116,8 @@ void RewriteBuffer::ReplaceText(unsigned OrigOffset, unsigned OrigLength, /// getRangeSize - Return the size in bytes of the specified range if they /// are in the same file. If not, this returns -1. -int Rewriter::getRangeSize(const CharSourceRange &Range) const { +int Rewriter::getRangeSize(const CharSourceRange &Range, + bool AfterInserts) const { if (!isRewritable(Range.getBegin()) || !isRewritable(Range.getEnd())) return -1; @@ -92,7 +137,7 @@ int Rewriter::getRangeSize(const CharSourceRange &Range) const { if (I != RewriteBuffers.end()) { const RewriteBuffer &RB = I->second; EndOff = RB.getMappedOffset(EndOff, true); - StartOff = RB.getMappedOffset(StartOff); + StartOff = RB.getMappedOffset(StartOff, AfterInserts); } @@ -104,8 +149,8 @@ int Rewriter::getRangeSize(const CharSourceRange &Range) const { return EndOff-StartOff; } -int Rewriter::getRangeSize(SourceRange Range) const { - return getRangeSize(CharSourceRange::getTokenRange(Range)); +int Rewriter::getRangeSize(SourceRange Range, bool AfterInserts) const { + return getRangeSize(CharSourceRange::getTokenRange(Range), AfterInserts); } @@ -194,12 +239,22 @@ bool Rewriter::InsertText(SourceLocation Loc, llvm::StringRef Str, return false; } +bool Rewriter::InsertTextAfterToken(SourceLocation Loc, llvm::StringRef Str) { + if (!isRewritable(Loc)) return true; + FileID FID; + unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID); + StartOffs += getRangeSize(SourceRange(Loc, Loc), /*AfterInserts*/true); + getEditBuffer(FID).InsertText(StartOffs, Str, /*InsertAfter*/true); + return false; +} + /// RemoveText - Remove the specified text region. -bool Rewriter::RemoveText(SourceLocation Start, unsigned Length) { +bool Rewriter::RemoveText(SourceLocation Start, unsigned Length, + bool removeLineIfEmpty) { if (!isRewritable(Start)) return true; FileID FID; unsigned StartOffs = getLocationOffsetAndFileID(Start, FID); - getEditBuffer(FID).RemoveText(StartOffs, Length); + getEditBuffer(FID).RemoveText(StartOffs, Length, removeLineIfEmpty); return false; } @@ -216,6 +271,20 @@ bool Rewriter::ReplaceText(SourceLocation Start, unsigned OrigLength, return false; } +bool Rewriter::ReplaceText(SourceRange range, SourceRange replacementRange) { + if (!isRewritable(range.getBegin())) return true; + if (!isRewritable(range.getEnd())) return true; + if (replacementRange.isInvalid()) return true; + SourceLocation start = range.getBegin(); + unsigned origLength = getRangeSize(range); + unsigned newLength = getRangeSize(replacementRange); + FileID FID; + unsigned newOffs = getLocationOffsetAndFileID(replacementRange.getBegin(), + FID); + llvm::StringRef MB = SourceMgr->getBufferData(FID); + return ReplaceText(start, origLength, MB.substr(newOffs, newLength)); +} + /// ReplaceStmt - This replaces a Stmt/Expr with another, using the pretty /// printer to generate the replacement code. This returns true if the input /// could not be rewritten, or false if successful.