diff options
author | dim <dim@FreeBSD.org> | 2011-05-02 19:39:53 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2011-05-02 19:39:53 +0000 |
commit | 110eaaceddcec790f7e6a5e3bf1261c9aa1e73ab (patch) | |
tree | 64a10f4c4154739d4a8191d7e1b52ce497f4ebd6 /lib/Rewrite/Rewriter.cpp | |
parent | a0fb00f9837bd0d2e5948f16f6a6b82a7a628f51 (diff) | |
download | FreeBSD-src-110eaaceddcec790f7e6a5e3bf1261c9aa1e73ab.zip FreeBSD-src-110eaaceddcec790f7e6a5e3bf1261c9aa1e73ab.tar.gz |
Vendor import of clang trunk r130700:
http://llvm.org/svn/llvm-project/cfe/trunk@130700
Diffstat (limited to 'lib/Rewrite/Rewriter.cpp')
-rw-r--r-- | lib/Rewrite/Rewriter.cpp | 177 |
1 files changed, 169 insertions, 8 deletions
diff --git a/lib/Rewrite/Rewriter.cpp b/lib/Rewrite/Rewriter.cpp index 92e2b03..51fe379 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, + RewriteOptions opts) const { if (!isRewritable(Range.getBegin()) || !isRewritable(Range.getEnd())) return -1; @@ -91,8 +136,8 @@ int Rewriter::getRangeSize(const CharSourceRange &Range) const { RewriteBuffers.find(StartFileID); if (I != RewriteBuffers.end()) { const RewriteBuffer &RB = I->second; - EndOff = RB.getMappedOffset(EndOff, true); - StartOff = RB.getMappedOffset(StartOff); + EndOff = RB.getMappedOffset(EndOff, opts.IncludeInsertsAtEndOfRange); + StartOff = RB.getMappedOffset(StartOff, !opts.IncludeInsertsAtBeginOfRange); } @@ -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, RewriteOptions opts) const { + return getRangeSize(CharSourceRange::getTokenRange(Range), opts); } @@ -194,12 +239,24 @@ 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); + RewriteOptions rangeOpts; + rangeOpts.IncludeInsertsAtBeginOfRange = false; + StartOffs += getRangeSize(SourceRange(Loc, Loc), rangeOpts); + 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, + RewriteOptions opts) { if (!isRewritable(Start)) return true; FileID FID; unsigned StartOffs = getLocationOffsetAndFileID(Start, FID); - getEditBuffer(FID).RemoveText(StartOffs, Length); + getEditBuffer(FID).RemoveText(StartOffs, Length, opts.RemoveLineIfEmpty); return false; } @@ -216,6 +273,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. @@ -234,3 +305,93 @@ bool Rewriter::ReplaceStmt(Stmt *From, Stmt *To) { ReplaceText(From->getLocStart(), Size, Str); return false; } + +std::string Rewriter::ConvertToString(Stmt *From) { + std::string SStr; + llvm::raw_string_ostream S(SStr); + From->printPretty(S, 0, PrintingPolicy(*LangOpts)); + return S.str(); +} + +bool Rewriter::IncreaseIndentation(CharSourceRange range, + SourceLocation parentIndent) { + using llvm::StringRef; + + if (!isRewritable(range.getBegin())) return true; + if (!isRewritable(range.getEnd())) return true; + if (!isRewritable(parentIndent)) return true; + + FileID StartFileID, EndFileID, parentFileID; + unsigned StartOff, EndOff, parentOff; + + StartOff = getLocationOffsetAndFileID(range.getBegin(), StartFileID); + EndOff = getLocationOffsetAndFileID(range.getEnd(), EndFileID); + parentOff = getLocationOffsetAndFileID(parentIndent, parentFileID); + + if (StartFileID != EndFileID || StartFileID != parentFileID) + return true; + if (StartOff >= EndOff || parentOff >= StartOff) + return true; + + FileID FID = StartFileID; + StringRef MB = SourceMgr->getBufferData(FID); + + unsigned parentLineNo = SourceMgr->getLineNumber(FID, parentOff) - 1; + unsigned startLineNo = SourceMgr->getLineNumber(FID, StartOff) - 1; + unsigned endLineNo = SourceMgr->getLineNumber(FID, EndOff) - 1; + + const SrcMgr::ContentCache * + Content = SourceMgr->getSLocEntry(FID).getFile().getContentCache(); + + // Find where the line starts for the three offsets. + unsigned parentLineOffs = Content->SourceLineCache[parentLineNo]; + unsigned startLineOffs = Content->SourceLineCache[startLineNo]; + unsigned endLineOffs = Content->SourceLineCache[endLineNo]; + + if (startLineOffs == endLineOffs || startLineOffs == parentLineOffs) + return true; + + // Find the whitespace at the start of each line. + StringRef parentSpace, startSpace, endSpace; + { + unsigned i = parentLineOffs; + while (isWhitespace(MB[i])) + ++i; + parentSpace = MB.substr(parentLineOffs, i-parentLineOffs); + + i = startLineOffs; + while (isWhitespace(MB[i])) + ++i; + startSpace = MB.substr(startLineOffs, i-startLineOffs); + + i = endLineOffs; + while (isWhitespace(MB[i])) + ++i; + endSpace = MB.substr(endLineOffs, i-endLineOffs); + } + if (parentSpace.size() >= startSpace.size()) + return true; + if (!startSpace.startswith(parentSpace)) + return true; + + llvm::StringRef indent = startSpace.substr(parentSpace.size()); + + // Indent the lines between start/end offsets. + RewriteBuffer &RB = getEditBuffer(FID); + for (unsigned i = startLineOffs; i != endLineOffs; ++i) { + if (MB[i] == '\n') { + unsigned startOfLine = i+1; + if (startOfLine == endLineOffs) + break; + StringRef origIndent; + unsigned ws = startOfLine; + while (isWhitespace(MB[ws])) + ++ws; + origIndent = MB.substr(startOfLine, ws-startOfLine); + if (origIndent.startswith(startSpace)) + RB.InsertText(startOfLine, indent, /*InsertAfter=*/false); + } + } + + return false; +} |