1 //===- RewriteBuffer.h - Buffer rewriting interface -----------------------===//
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-exception
7 //===----------------------------------------------------------------------===//
9 #include "llvm/ADT/RewriteBuffer.h"
10 #include "llvm/Support/raw_ostream.h"
14 raw_ostream
&RewriteBuffer::write(raw_ostream
&Stream
) const {
15 // Walk RewriteRope chunks efficiently using MoveToNextPiece() instead of the
16 // character iterator.
17 for (RopePieceBTreeIterator I
= begin(), E
= end(); I
!= E
;
23 /// Return true if this character is non-new-line whitespace:
24 /// ' ', '\\t', '\\f', '\\v', '\\r'.
25 static inline bool isWhitespaceExceptNL(unsigned char c
) {
26 return c
== ' ' || c
== '\t' || c
== '\f' || c
== '\v' || c
== '\r';
29 void RewriteBuffer::RemoveText(unsigned OrigOffset
, unsigned Size
,
30 bool removeLineIfEmpty
) {
31 // Nothing to remove, exit early.
35 unsigned RealOffset
= getMappedOffset(OrigOffset
, true);
36 assert(RealOffset
+ Size
<= Buffer
.size() && "Invalid location");
38 // Remove the dead characters.
39 Buffer
.erase(RealOffset
, Size
);
41 // Add a delta so that future changes are offset correctly.
42 AddReplaceDelta(OrigOffset
, -Size
);
44 if (removeLineIfEmpty
) {
45 // Find the line that the remove occurred and if it is completely empty
46 // remove the line as well.
48 iterator curLineStart
= begin();
49 unsigned curLineStartOffs
= 0;
50 iterator posI
= begin();
51 for (unsigned i
= 0; i
!= RealOffset
; ++i
) {
55 curLineStartOffs
= i
+ 1;
60 unsigned lineSize
= 0;
62 while (posI
!= end() && isWhitespaceExceptNL(*posI
)) {
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 be
69 // expressed in terms of the original input not the "real" rewrite
70 // buffer. How do we compute that reliably? It might be tempting to use
71 // curLineStartOffs + OrigOffset - RealOffset, but that assumes the
72 // difference between the original and real offset is the same at the
73 // removed text and at the start of the line, but that's not true if
74 // edits were previously made earlier on the line. This bug is also
75 // documented by a FIXME on the definition of
76 // clang::Rewriter::RewriteOptions::RemoveLineIfEmpty. A reproducer for
77 // the implementation below is the test RemoveLineIfEmpty in
78 // clang/unittests/Rewrite/RewriteBufferTest.cpp.
79 AddReplaceDelta(curLineStartOffs
, -(lineSize
+ 1 /* + '\n'*/));
84 void RewriteBuffer::InsertText(unsigned OrigOffset
, StringRef Str
,
86 // Nothing to insert, exit early.
90 unsigned RealOffset
= getMappedOffset(OrigOffset
, InsertAfter
);
91 Buffer
.insert(RealOffset
, Str
.begin(), Str
.end());
93 // Add a delta so that future changes are offset correctly.
94 AddInsertDelta(OrigOffset
, Str
.size());
97 /// ReplaceText - This method replaces a range of characters in the input
98 /// buffer with a new string. This is effectively a combined "remove+insert"
100 void RewriteBuffer::ReplaceText(unsigned OrigOffset
, unsigned OrigLength
,
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
);