108 lines · cpp
1//===- RewriteBuffer.h - Buffer rewriting interface -----------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/ADT/RewriteBuffer.h"10#include "llvm/Support/raw_ostream.h"11 12using namespace llvm;13 14raw_ostream &RewriteBuffer::write(raw_ostream &Stream) const {15 // Walk RewriteRope chunks efficiently using MoveToNextPiece() instead of the16 // character iterator.17 for (RopePieceBTreeIterator I = begin(), E = end(); I != E;18 I.MoveToNextPiece())19 Stream << I.piece();20 return Stream;21}22 23/// Return true if this character is non-new-line whitespace:24/// ' ', '\\t', '\\f', '\\v', '\\r'.25static inline bool isWhitespaceExceptNL(unsigned char c) {26 return c == ' ' || c == '\t' || c == '\f' || c == '\v' || c == '\r';27}28 29void RewriteBuffer::RemoveText(unsigned OrigOffset, unsigned Size,30 bool removeLineIfEmpty) {31 // Nothing to remove, exit early.32 if (Size == 0)33 return;34 35 unsigned RealOffset = getMappedOffset(OrigOffset, true);36 assert(RealOffset + Size <= Buffer.size() && "Invalid location");37 38 // Remove the dead characters.39 Buffer.erase(RealOffset, Size);40 41 // Add a delta so that future changes are offset correctly.42 AddReplaceDelta(OrigOffset, -Size);43 44 if (removeLineIfEmpty) {45 // Find the line that the remove occurred and if it is completely empty46 // remove the line as well.47 48 iterator curLineStart = begin();49 unsigned curLineStartOffs = 0;50 iterator posI = begin();51 for (unsigned i = 0; i != RealOffset; ++i) {52 if (*posI == '\n') {53 curLineStart = posI;54 ++curLineStart;55 curLineStartOffs = i + 1;56 }57 ++posI;58 }59 60 unsigned lineSize = 0;61 posI = curLineStart;62 while (posI != end() && isWhitespaceExceptNL(*posI)) {63 ++posI;64 ++lineSize;65 }66 if (posI != end() && *posI == '\n') {67 Buffer.erase(curLineStartOffs, lineSize + 1 /* + '\n'*/);68 // FIXME: Here, the offset of the start of the line is supposed to be69 // expressed in terms of the original input not the "real" rewrite70 // buffer. How do we compute that reliably? It might be tempting to use71 // curLineStartOffs + OrigOffset - RealOffset, but that assumes the72 // difference between the original and real offset is the same at the73 // removed text and at the start of the line, but that's not true if74 // edits were previously made earlier on the line. This bug is also75 // documented by a FIXME on the definition of76 // clang::Rewriter::RewriteOptions::RemoveLineIfEmpty. A reproducer for77 // the implementation below is the test RemoveLineIfEmpty in78 // clang/unittests/Rewrite/RewriteBufferTest.cpp.79 AddReplaceDelta(curLineStartOffs, -(lineSize + 1 /* + '\n'*/));80 }81 }82}83 84void RewriteBuffer::InsertText(unsigned OrigOffset, StringRef Str,85 bool InsertAfter) {86 // Nothing to insert, exit early.87 if (Str.empty())88 return;89 90 unsigned RealOffset = getMappedOffset(OrigOffset, InsertAfter);91 Buffer.insert(RealOffset, Str.begin(), Str.end());92 93 // Add a delta so that future changes are offset correctly.94 AddInsertDelta(OrigOffset, Str.size());95}96 97/// ReplaceText - This method replaces a range of characters in the input98/// buffer with a new string. This is effectively a combined "remove+insert"99/// operation.100void RewriteBuffer::ReplaceText(unsigned OrigOffset, unsigned OrigLength,101 StringRef NewStr) {102 unsigned RealOffset = getMappedOffset(OrigOffset, true);103 Buffer.erase(RealOffset, OrigLength);104 Buffer.insert(RealOffset, NewStr.begin(), NewStr.end());105 if (OrigLength != NewStr.size())106 AddReplaceDelta(OrigOffset, NewStr.size() - OrigLength);107}108