Argyrios Kyrtzidis | 69e6f1f | 2015-03-08 04:00:33 +0000 | [diff] [blame] | 1 | //===- unittests/Rewrite/RewriteBufferTest.cpp - RewriteBuffer tests ------===// |
| 2 | // |
Chandler Carruth | 2946cd7 | 2019-01-19 08:50:56 +0000 | [diff] [blame] | 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 |
Argyrios Kyrtzidis | 69e6f1f | 2015-03-08 04:00:33 +0000 | [diff] [blame] | 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #include "clang/Rewrite/Core/RewriteBuffer.h" |
| 10 | #include "gtest/gtest.h" |
| 11 | |
| 12 | using namespace llvm; |
| 13 | using namespace clang; |
| 14 | |
| 15 | namespace { |
| 16 | |
Joel E. Denny | 9be6d7e | 2019-08-15 21:17:48 +0000 | [diff] [blame] | 17 | #define EXPECT_OUTPUT(Buf, Output) EXPECT_EQ(Output, writeOutput(Buf)) |
| 18 | |
| 19 | static std::string writeOutput(const RewriteBuffer &Buf) { |
| 20 | std::string Result; |
| 21 | raw_string_ostream OS(Result); |
| 22 | Buf.write(OS); |
| 23 | OS.flush(); |
| 24 | return Result; |
| 25 | } |
| 26 | |
Argyrios Kyrtzidis | 69e6f1f | 2015-03-08 04:00:33 +0000 | [diff] [blame] | 27 | static void tagRange(unsigned Offset, unsigned Len, StringRef tagName, |
| 28 | RewriteBuffer &Buf) { |
| 29 | std::string BeginTag; |
| 30 | raw_string_ostream(BeginTag) << '<' << tagName << '>'; |
| 31 | std::string EndTag; |
| 32 | raw_string_ostream(EndTag) << "</" << tagName << '>'; |
| 33 | |
| 34 | Buf.InsertTextAfter(Offset, BeginTag); |
| 35 | Buf.InsertTextBefore(Offset+Len, EndTag); |
| 36 | } |
| 37 | |
| 38 | TEST(RewriteBuffer, TagRanges) { |
| 39 | StringRef Input = "hello world"; |
| 40 | const char *Output = "<outer><inner>hello</inner></outer> "; |
| 41 | |
| 42 | RewriteBuffer Buf; |
| 43 | Buf.Initialize(Input); |
| 44 | StringRef RemoveStr = "world"; |
| 45 | size_t Pos = Input.find(RemoveStr); |
| 46 | Buf.RemoveText(Pos, RemoveStr.size()); |
| 47 | |
| 48 | StringRef TagStr = "hello"; |
| 49 | Pos = Input.find(TagStr); |
| 50 | tagRange(Pos, TagStr.size(), "outer", Buf); |
| 51 | tagRange(Pos, TagStr.size(), "inner", Buf); |
| 52 | |
Joel E. Denny | 9be6d7e | 2019-08-15 21:17:48 +0000 | [diff] [blame] | 53 | EXPECT_OUTPUT(Buf, Output); |
| 54 | } |
| 55 | |
| 56 | TEST(RewriteBuffer, DISABLED_RemoveLineIfEmpty_XFAIL) { |
| 57 | StringRef Input = "def\n" |
| 58 | "ghi\n" |
| 59 | "jkl\n"; |
| 60 | RewriteBuffer Buf; |
| 61 | Buf.Initialize(Input); |
| 62 | |
| 63 | // Insert "abc\n" at the start. |
| 64 | Buf.InsertText(0, "abc\n"); |
| 65 | EXPECT_OUTPUT(Buf, "abc\n" |
| 66 | "def\n" |
| 67 | "ghi\n" |
| 68 | "jkl\n"); |
| 69 | |
| 70 | // Remove "def\n". |
| 71 | // |
| 72 | // After the removal of "def", we have: |
| 73 | // |
| 74 | // "abc\n" |
| 75 | // "\n" |
| 76 | // "ghi\n" |
| 77 | // "jkl\n" |
| 78 | // |
| 79 | // Because removeLineIfEmpty=true, RemoveText has to remove the "\n" left on |
| 80 | // the line. This happens correctly for the rewrite buffer itself, so the |
| 81 | // next check below passes. |
| 82 | // |
| 83 | // However, RemoveText's implementation incorrectly records the delta for |
| 84 | // removing the "\n" using the rewrite buffer offset, 4, where it was |
| 85 | // supposed to use the original input offset, 3. Interpreted as an original |
| 86 | // input offset, 4 points to "g" not to "\n". Thus, any future modifications |
| 87 | // at the original input's "g" will incorrectly see "g" as having become an |
| 88 | // empty string and so will map to the next character, "h", in the rewrite |
| 89 | // buffer. |
| 90 | StringRef RemoveStr0 = "def"; |
| 91 | Buf.RemoveText(Input.find(RemoveStr0), RemoveStr0.size(), |
| 92 | /*removeLineIfEmpty*/ true); |
| 93 | EXPECT_OUTPUT(Buf, "abc\n" |
| 94 | "ghi\n" |
| 95 | "jkl\n"); |
| 96 | |
| 97 | // Try to remove "ghi\n". |
| 98 | // |
| 99 | // As discussed above, the original input offset for "ghi\n" incorrectly |
| 100 | // maps to the rewrite buffer offset for "hi\nj", so we end up with: |
| 101 | // |
| 102 | // "abc\n" |
| 103 | // "gkl\n" |
| 104 | // |
| 105 | // To show that removeLineIfEmpty=true is the culprit, change true to false |
| 106 | // and append a newline to RemoveStr0 above. The test then passes. |
| 107 | StringRef RemoveStr1 = "ghi\n"; |
| 108 | Buf.RemoveText(Input.find(RemoveStr1), RemoveStr1.size()); |
| 109 | EXPECT_OUTPUT(Buf, "abc\n" |
| 110 | "jkl\n"); |
Argyrios Kyrtzidis | 69e6f1f | 2015-03-08 04:00:33 +0000 | [diff] [blame] | 111 | } |
| 112 | |
| 113 | } // anonymous namespace |