Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / clang / unittests / Tooling / RefactoringTest.cpp
blob77d410f5d3b6042bd3b430997cbde3be00d6f88a
1 //===- unittest/Tooling/RefactoringTest.cpp - Refactoring unit tests ------===//
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-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include "clang/Tooling/Refactoring.h"
10 #include "ReplacementTest.h"
11 #include "RewriterTestContext.h"
12 #include "clang/AST/ASTConsumer.h"
13 #include "clang/AST/ASTContext.h"
14 #include "clang/AST/DeclCXX.h"
15 #include "clang/AST/DeclGroup.h"
16 #include "clang/AST/RecursiveASTVisitor.h"
17 #include "clang/Basic/Diagnostic.h"
18 #include "clang/Basic/DiagnosticOptions.h"
19 #include "clang/Basic/FileManager.h"
20 #include "clang/Basic/LangOptions.h"
21 #include "clang/Basic/SourceManager.h"
22 #include "clang/Format/Format.h"
23 #include "clang/Frontend/CompilerInstance.h"
24 #include "clang/Frontend/FrontendAction.h"
25 #include "clang/Frontend/TextDiagnosticPrinter.h"
26 #include "clang/Rewrite/Core/Rewriter.h"
27 #include "clang/Tooling/Refactoring/AtomicChange.h"
28 #include "clang/Tooling/Tooling.h"
29 #include "llvm/ADT/SmallString.h"
30 #include "llvm/Support/VirtualFileSystem.h"
31 #include "gtest/gtest.h"
32 #include <optional>
34 namespace clang {
35 namespace tooling {
37 TEST_F(ReplacementTest, CanDeleteAllText) {
38 FileID ID = Context.createInMemoryFile("input.cpp", "text");
39 SourceLocation Location = Context.getLocation(ID, 1, 1);
40 Replacement Replace(createReplacement(Location, 4, ""));
41 EXPECT_TRUE(Replace.apply(Context.Rewrite));
42 EXPECT_EQ("", Context.getRewrittenText(ID));
45 TEST_F(ReplacementTest, CanDeleteAllTextInTextWithNewlines) {
46 FileID ID = Context.createInMemoryFile("input.cpp", "line1\nline2\nline3");
47 SourceLocation Location = Context.getLocation(ID, 1, 1);
48 Replacement Replace(createReplacement(Location, 17, ""));
49 EXPECT_TRUE(Replace.apply(Context.Rewrite));
50 EXPECT_EQ("", Context.getRewrittenText(ID));
53 TEST_F(ReplacementTest, CanAddText) {
54 FileID ID = Context.createInMemoryFile("input.cpp", "");
55 SourceLocation Location = Context.getLocation(ID, 1, 1);
56 Replacement Replace(createReplacement(Location, 0, "result"));
57 EXPECT_TRUE(Replace.apply(Context.Rewrite));
58 EXPECT_EQ("result", Context.getRewrittenText(ID));
61 TEST_F(ReplacementTest, CanReplaceTextAtPosition) {
62 FileID ID = Context.createInMemoryFile("input.cpp",
63 "line1\nline2\nline3\nline4");
64 SourceLocation Location = Context.getLocation(ID, 2, 3);
65 Replacement Replace(createReplacement(Location, 12, "x"));
66 EXPECT_TRUE(Replace.apply(Context.Rewrite));
67 EXPECT_EQ("line1\nlixne4", Context.getRewrittenText(ID));
70 TEST_F(ReplacementTest, CanReplaceTextAtPositionMultipleTimes) {
71 FileID ID = Context.createInMemoryFile("input.cpp",
72 "line1\nline2\nline3\nline4");
73 SourceLocation Location1 = Context.getLocation(ID, 2, 3);
74 Replacement Replace1(createReplacement(Location1, 12, "x\ny\n"));
75 EXPECT_TRUE(Replace1.apply(Context.Rewrite));
76 EXPECT_EQ("line1\nlix\ny\nne4", Context.getRewrittenText(ID));
78 // Since the original source has not been modified, the (4, 4) points to the
79 // 'e' in the original content.
80 SourceLocation Location2 = Context.getLocation(ID, 4, 4);
81 Replacement Replace2(createReplacement(Location2, 1, "f"));
82 EXPECT_TRUE(Replace2.apply(Context.Rewrite));
83 EXPECT_EQ("line1\nlix\ny\nnf4", Context.getRewrittenText(ID));
86 TEST_F(ReplacementTest, ApplyFailsForNonExistentLocation) {
87 Replacement Replace("nonexistent-file.cpp", 0, 1, "");
88 EXPECT_FALSE(Replace.apply(Context.Rewrite));
91 TEST_F(ReplacementTest, CanRetrivePath) {
92 Replacement Replace("/path/to/file.cpp", 0, 1, "");
93 EXPECT_EQ("/path/to/file.cpp", Replace.getFilePath());
96 TEST_F(ReplacementTest, ReturnsInvalidPath) {
97 Replacement Replace1(Context.Sources, SourceLocation(), 0, "");
98 EXPECT_TRUE(Replace1.getFilePath().empty());
100 Replacement Replace2;
101 EXPECT_TRUE(Replace2.getFilePath().empty());
104 // Checks that an llvm::Error instance contains a ReplacementError with expected
105 // error code, expected new replacement, and expected existing replacement.
106 static bool checkReplacementError(llvm::Error &&Error,
107 replacement_error ExpectedErr,
108 std::optional<Replacement> ExpectedExisting,
109 std::optional<Replacement> ExpectedNew) {
110 if (!Error) {
111 llvm::errs() << "Error is a success.";
112 return false;
114 std::string ErrorMessage;
115 llvm::raw_string_ostream OS(ErrorMessage);
116 llvm::handleAllErrors(std::move(Error), [&](const ReplacementError &RE) {
117 llvm::errs() << "Handling error...\n";
118 if (ExpectedErr != RE.get())
119 OS << "Unexpected error code: " << int(RE.get()) << "\n";
120 if (ExpectedExisting != RE.getExistingReplacement()) {
121 OS << "Expected Existing != Actual Existing.\n";
122 if (ExpectedExisting)
123 OS << "Expected existing replacement: " << ExpectedExisting->toString()
124 << "\n";
125 if (RE.getExistingReplacement())
126 OS << "Actual existing replacement: "
127 << RE.getExistingReplacement()->toString() << "\n";
129 if (ExpectedNew != RE.getNewReplacement()) {
130 OS << "Expected New != Actual New.\n";
131 if (ExpectedNew)
132 OS << "Expected new replacement: " << ExpectedNew->toString() << "\n";
133 if (RE.getNewReplacement())
134 OS << "Actual new replacement: " << RE.getNewReplacement()->toString()
135 << "\n";
138 OS.flush();
139 if (ErrorMessage.empty()) return true;
140 llvm::errs() << ErrorMessage;
141 return false;
144 TEST_F(ReplacementTest, FailAddReplacements) {
145 Replacements Replaces;
146 Replacement Deletion("x.cc", 0, 10, "3");
147 auto Err = Replaces.add(Deletion);
148 EXPECT_TRUE(!Err);
149 llvm::consumeError(std::move(Err));
151 Replacement OverlappingReplacement("x.cc", 0, 2, "a");
152 Err = Replaces.add(OverlappingReplacement);
153 EXPECT_TRUE(checkReplacementError(std::move(Err),
154 replacement_error::overlap_conflict,
155 Deletion, OverlappingReplacement));
157 Replacement ContainedReplacement("x.cc", 2, 2, "a");
158 Err = Replaces.add(Replacement(ContainedReplacement));
159 EXPECT_TRUE(checkReplacementError(std::move(Err),
160 replacement_error::overlap_conflict,
161 Deletion, ContainedReplacement));
163 Replacement WrongPathReplacement("y.cc", 20, 2, "");
164 Err = Replaces.add(WrongPathReplacement);
165 EXPECT_TRUE(checkReplacementError(std::move(Err),
166 replacement_error::wrong_file_path,
167 Deletion, WrongPathReplacement));
169 EXPECT_EQ(1u, Replaces.size());
170 EXPECT_EQ(Deletion, *Replaces.begin());
173 TEST_F(ReplacementTest, DeletionInReplacements) {
174 Replacements Replaces;
175 Replacement R("x.cc", 0, 10, "3");
176 auto Err = Replaces.add(R);
177 EXPECT_TRUE(!Err);
178 llvm::consumeError(std::move(Err));
179 Err = Replaces.add(Replacement("x.cc", 0, 2, ""));
180 EXPECT_TRUE(!Err);
181 llvm::consumeError(std::move(Err));
182 Err = Replaces.add(Replacement("x.cc", 2, 2, ""));
183 EXPECT_TRUE(!Err);
184 llvm::consumeError(std::move(Err));
185 EXPECT_EQ(1u, Replaces.size());
186 EXPECT_EQ(R, *Replaces.begin());
189 TEST_F(ReplacementTest, OverlappingReplacements) {
190 Replacements Replaces;
191 auto Err = Replaces.add(Replacement("x.cc", 0, 3, "345"));
192 EXPECT_TRUE(!Err);
193 llvm::consumeError(std::move(Err));
194 Err = Replaces.add(Replacement("x.cc", 2, 3, "543"));
195 EXPECT_TRUE(!Err);
196 llvm::consumeError(std::move(Err));
198 EXPECT_EQ(1u, Replaces.size());
199 EXPECT_EQ(Replacement("x.cc", 0, 5, "34543"), *Replaces.begin());
201 Err = Replaces.add(Replacement("x.cc", 2, 1, "5"));
202 EXPECT_TRUE(!Err);
203 llvm::consumeError(std::move(Err));
204 EXPECT_EQ(1u, Replaces.size());
205 EXPECT_EQ(Replacement("x.cc", 0, 5, "34543"), *Replaces.begin());
208 TEST_F(ReplacementTest, AddAdjacentInsertionAndReplacement) {
209 Replacements Replaces;
210 // Test adding an insertion at the offset of an existing replacement.
211 auto Err = Replaces.add(Replacement("x.cc", 10, 3, "replace"));
212 EXPECT_TRUE(!Err);
213 llvm::consumeError(std::move(Err));
214 Err = Replaces.add(Replacement("x.cc", 10, 0, "insert"));
215 EXPECT_TRUE(!Err);
216 llvm::consumeError(std::move(Err));
217 EXPECT_EQ(Replaces.size(), 2u);
219 Replaces.clear();
220 // Test overlap with an existing insertion.
221 Err = Replaces.add(Replacement("x.cc", 10, 0, "insert"));
222 EXPECT_TRUE(!Err);
223 llvm::consumeError(std::move(Err));
224 Err = Replaces.add(Replacement("x.cc", 10, 3, "replace"));
225 EXPECT_TRUE(!Err);
226 llvm::consumeError(std::move(Err));
227 EXPECT_EQ(Replaces.size(), 2u);
230 TEST_F(ReplacementTest, MergeNewDeletions) {
231 Replacements Replaces;
232 Replacement ContainingReplacement("x.cc", 0, 10, "");
233 auto Err = Replaces.add(ContainingReplacement);
234 EXPECT_TRUE(!Err);
235 llvm::consumeError(std::move(Err));
237 Err = Replaces.add(Replacement("x.cc", 5, 3, ""));
238 EXPECT_TRUE(!Err);
239 llvm::consumeError(std::move(Err));
241 Err = Replaces.add(Replacement("x.cc", 0, 10, ""));
242 EXPECT_TRUE(!Err);
243 llvm::consumeError(std::move(Err));
245 Err = Replaces.add(Replacement("x.cc", 5, 5, ""));
246 EXPECT_TRUE(!Err);
247 llvm::consumeError(std::move(Err));
249 EXPECT_EQ(1u, Replaces.size());
250 EXPECT_EQ(*Replaces.begin(), ContainingReplacement);
253 TEST_F(ReplacementTest, MergeOverlappingButNotAdjacentReplacement) {
254 Replacements Replaces;
255 auto Err = Replaces.add(Replacement("x.cc", 0, 2, ""));
256 EXPECT_TRUE(!Err);
257 llvm::consumeError(std::move(Err));
259 Err = Replaces.add(Replacement("x.cc", 5, 5, ""));
260 EXPECT_TRUE(!Err);
261 llvm::consumeError(std::move(Err));
263 Replacement After = Replacement("x.cc", 10, 5, "");
264 Err = Replaces.add(After);
265 EXPECT_TRUE(!Err);
266 llvm::consumeError(std::move(Err));
268 Replacement ContainingReplacement("x.cc", 0, 10, "");
269 Err = Replaces.add(ContainingReplacement);
270 EXPECT_TRUE(!Err);
271 llvm::consumeError(std::move(Err));
273 EXPECT_EQ(2u, Replaces.size());
274 EXPECT_EQ(*Replaces.begin(), ContainingReplacement);
275 EXPECT_EQ(*(++Replaces.begin()), After);
278 TEST_F(ReplacementTest, InsertionBeforeMergedDeletions) {
279 Replacements Replaces;
281 Replacement Insertion("x.cc", 0, 0, "123");
282 auto Err = Replaces.add(Insertion);
283 EXPECT_TRUE(!Err);
284 llvm::consumeError(std::move(Err));
286 Err = Replaces.add(Replacement("x.cc", 5, 5, ""));
287 EXPECT_TRUE(!Err);
288 llvm::consumeError(std::move(Err));
290 Replacement Deletion("x.cc", 0, 10, "");
291 Err = Replaces.add(Deletion);
292 EXPECT_TRUE(!Err);
293 llvm::consumeError(std::move(Err));
295 EXPECT_EQ(2u, Replaces.size());
296 EXPECT_EQ(*Replaces.begin(), Insertion);
297 EXPECT_EQ(*(++Replaces.begin()), Deletion);
300 TEST_F(ReplacementTest, MergeOverlappingDeletions) {
301 Replacements Replaces;
302 auto Err = Replaces.add(Replacement("x.cc", 0, 2, ""));
303 EXPECT_TRUE(!Err);
304 llvm::consumeError(std::move(Err));
306 Err = Replaces.add(Replacement("x.cc", 0, 5, ""));
307 EXPECT_TRUE(!Err);
308 llvm::consumeError(std::move(Err));
310 EXPECT_EQ(1u, Replaces.size());
311 EXPECT_EQ(Replacement("x.cc", 0, 5, ""), *Replaces.begin());
313 Err = Replaces.add(Replacement("x.cc", 1, 5, ""));
314 EXPECT_TRUE(!Err);
315 llvm::consumeError(std::move(Err));
316 EXPECT_EQ(1u, Replaces.size());
317 EXPECT_EQ(Replacement("x.cc", 0, 6, ""), *Replaces.begin());
320 TEST_F(ReplacementTest, FailedMergeExistingDeletions) {
321 Replacements Replaces;
322 Replacement First("x.cc", 0, 2, "");
323 auto Err = Replaces.add(First);
324 EXPECT_TRUE(!Err);
325 llvm::consumeError(std::move(Err));
327 Replacement Second("x.cc", 5, 5, "");
328 Err = Replaces.add(Second);
329 EXPECT_TRUE(!Err);
330 llvm::consumeError(std::move(Err));
332 Err = Replaces.add(Replacement("x.cc", 1, 10, ""));
333 EXPECT_TRUE(!Err);
334 llvm::consumeError(std::move(Err));
336 EXPECT_EQ(1u, Replaces.size());
337 EXPECT_EQ(Replacement("x.cc", 0, 11, ""), *Replaces.begin());
340 TEST_F(ReplacementTest, FailAddRegression) {
341 Replacements Replaces;
342 // Create two replacements, where the second one is an insertion of the empty
343 // string exactly at the end of the first one.
344 auto Err = Replaces.add(Replacement("x.cc", 0, 10, "1"));
345 EXPECT_TRUE(!Err);
346 llvm::consumeError(std::move(Err));
347 Err = Replaces.add(Replacement("x.cc", 10, 0, ""));
348 EXPECT_TRUE(!Err);
349 llvm::consumeError(std::move(Err));
351 // Make sure we find the overlap with the first entry when inserting a
352 // replacement that ends exactly at the seam of the existing replacements.
353 Replacement OverlappingReplacement("x.cc", 5, 5, "fail");
354 Err = Replaces.add(OverlappingReplacement);
355 EXPECT_TRUE(checkReplacementError(std::move(Err),
356 replacement_error::overlap_conflict,
357 *Replaces.begin(), OverlappingReplacement));
359 Err = Replaces.add(Replacement("x.cc", 10, 0, ""));
360 EXPECT_TRUE(!Err);
361 llvm::consumeError(std::move(Err));
364 TEST_F(ReplacementTest, InsertAtOffsetOfReplacement) {
365 Replacements Replaces;
366 auto Err = Replaces.add(Replacement("x.cc", 10, 2, ""));
367 EXPECT_TRUE(!Err);
368 llvm::consumeError(std::move(Err));
369 Err = Replaces.add(Replacement("x.cc", 10, 0, ""));
370 EXPECT_TRUE(!Err);
371 llvm::consumeError(std::move(Err));
372 EXPECT_EQ(Replaces.size(), 2u);
374 Replaces.clear();
375 Err = Replaces.add(Replacement("x.cc", 10, 0, ""));
376 EXPECT_TRUE(!Err);
377 llvm::consumeError(std::move(Err));
378 Err = Replaces.add(Replacement("x.cc", 10, 2, ""));
379 EXPECT_TRUE(!Err);
380 llvm::consumeError(std::move(Err));
381 EXPECT_EQ(Replaces.size(), 2u);
384 TEST_F(ReplacementTest, AddInsertAtOtherInsertWhenOderIndependent) {
385 Replacements Replaces;
386 auto Err = Replaces.add(Replacement("x.cc", 10, 0, "a"));
387 EXPECT_TRUE(!Err);
388 llvm::consumeError(std::move(Err));
389 Replacement ConflictInsertion("x.cc", 10, 0, "b");
390 Err = Replaces.add(ConflictInsertion);
391 EXPECT_TRUE(checkReplacementError(std::move(Err),
392 replacement_error::insert_conflict,
393 *Replaces.begin(), ConflictInsertion));
395 Replaces.clear();
396 Err = Replaces.add(Replacement("x.cc", 10, 0, "a"));
397 EXPECT_TRUE(!Err);
398 llvm::consumeError(std::move(Err));
399 Err = Replaces.add(Replacement("x.cc", 10, 0, "aa"));
400 EXPECT_TRUE(!Err);
401 llvm::consumeError(std::move(Err));
402 EXPECT_EQ(1u, Replaces.size());
403 EXPECT_EQ(Replacement("x.cc", 10, 0, "aaa"), *Replaces.begin());
405 Replaces.clear();
406 Err = Replaces.add(Replacement("x.cc", 10, 0, ""));
407 EXPECT_TRUE(!Err);
408 llvm::consumeError(std::move(Err));
409 Err = Replaces.add(Replacement("x.cc", 10, 3, ""));
410 EXPECT_TRUE(!Err);
411 llvm::consumeError(std::move(Err));
412 Err = Replaces.add(Replacement("x.cc", 10, 0, ""));
413 EXPECT_TRUE(!Err);
414 llvm::consumeError(std::move(Err));
415 EXPECT_EQ(2u, Replaces.size());
416 EXPECT_EQ(Replacement("x.cc", 10, 0, ""), *Replaces.begin());
417 EXPECT_EQ(Replacement("x.cc", 10, 3, ""), *std::next(Replaces.begin()));
420 TEST_F(ReplacementTest, InsertBetweenAdjacentReplacements) {
421 Replacements Replaces;
422 auto Err = Replaces.add(Replacement("x.cc", 10, 5, "a"));
423 EXPECT_TRUE(!Err);
424 llvm::consumeError(std::move(Err));
425 Err = Replaces.add(Replacement("x.cc", 8, 2, "a"));
426 EXPECT_TRUE(!Err);
427 llvm::consumeError(std::move(Err));
428 Err = Replaces.add(Replacement("x.cc", 10, 0, "b"));
429 EXPECT_TRUE(!Err);
430 llvm::consumeError(std::move(Err));
433 TEST_F(ReplacementTest, CanApplyReplacements) {
434 FileID ID = Context.createInMemoryFile("input.cpp",
435 "line1\nline2\nline3\nline4");
436 Replacements Replaces =
437 toReplacements({Replacement(Context.Sources,
438 Context.getLocation(ID, 2, 1), 5, "replaced"),
439 Replacement(Context.Sources,
440 Context.getLocation(ID, 3, 1), 5, "other")});
441 EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
442 EXPECT_EQ("line1\nreplaced\nother\nline4", Context.getRewrittenText(ID));
445 // Verifies that replacement/deletion is applied before insertion at the same
446 // offset.
447 TEST_F(ReplacementTest, InsertAndDelete) {
448 FileID ID = Context.createInMemoryFile("input.cpp",
449 "line1\nline2\nline3\nline4");
450 Replacements Replaces = toReplacements(
451 {Replacement(Context.Sources, Context.getLocation(ID, 2, 1), 6, ""),
452 Replacement(Context.Sources, Context.getLocation(ID, 2, 1), 0,
453 "other\n")});
454 EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
455 EXPECT_EQ("line1\nother\nline3\nline4", Context.getRewrittenText(ID));
458 TEST_F(ReplacementTest, AdjacentReplacements) {
459 FileID ID = Context.createInMemoryFile("input.cpp",
460 "ab");
461 Replacements Replaces = toReplacements(
462 {Replacement(Context.Sources, Context.getLocation(ID, 1, 1), 1, "x"),
463 Replacement(Context.Sources, Context.getLocation(ID, 1, 2), 1, "y")});
464 EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
465 EXPECT_EQ("xy", Context.getRewrittenText(ID));
468 TEST_F(ReplacementTest, AddDuplicateReplacements) {
469 FileID ID = Context.createInMemoryFile("input.cpp",
470 "line1\nline2\nline3\nline4");
471 auto Replaces = toReplacements({Replacement(
472 Context.Sources, Context.getLocation(ID, 2, 1), 5, "replaced")});
474 auto Err = Replaces.add(Replacement(
475 Context.Sources, Context.getLocation(ID, 2, 1), 5, "replaced"));
476 EXPECT_TRUE(!Err);
477 llvm::consumeError(std::move(Err));
479 Err = Replaces.add(Replacement(Context.Sources, Context.getLocation(ID, 2, 1),
480 5, "replaced"));
481 EXPECT_TRUE(!Err);
482 llvm::consumeError(std::move(Err));
484 EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
485 EXPECT_EQ("line1\nreplaced\nline3\nline4", Context.getRewrittenText(ID));
488 TEST_F(ReplacementTest, FailOrderDependentReplacements) {
489 FileID ID = Context.createInMemoryFile("input.cpp",
490 "line1\nline2\nline3\nline4");
491 auto Replaces = toReplacements({Replacement(
492 Context.Sources, Context.getLocation(ID, 2, 1), 5, "other")});
494 Replacement ConflictReplacement(Context.Sources,
495 Context.getLocation(ID, 2, 1), 5, "rehto");
496 auto Err = Replaces.add(ConflictReplacement);
497 EXPECT_TRUE(checkReplacementError(std::move(Err),
498 replacement_error::overlap_conflict,
499 *Replaces.begin(), ConflictReplacement));
501 EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
502 EXPECT_EQ("line1\nother\nline3\nline4", Context.getRewrittenText(ID));
505 TEST_F(ReplacementTest, InvalidSourceLocationFailsApplyAll) {
506 Replacements Replaces =
507 toReplacements({Replacement(Context.Sources, SourceLocation(), 5, "2")});
509 EXPECT_FALSE(applyAllReplacements(Replaces, Context.Rewrite));
512 TEST_F(ReplacementTest, MultipleFilesReplaceAndFormat) {
513 // Column limit is 20.
514 std::string Code1 = "Long *a =\n"
515 " new Long();\n"
516 "long x = 1;";
517 std::string Expected1 = "auto a = new Long();\n"
518 "long x =\n"
519 " 12345678901;";
520 std::string Code2 = "int x = 123;\n"
521 "int y = 0;";
522 std::string Expected2 = "int x =\n"
523 " 1234567890123;\n"
524 "int y = 10;";
525 StringRef File1 = "format_1.cpp";
526 StringRef File2 = "format_2.cpp";
527 FileID ID1 = Context.createInMemoryFile(File1, Code1);
528 FileID ID2 = Context.createInMemoryFile(File2, Code2);
530 // Scrambled the order of replacements.
531 std::map<std::string, Replacements> FileToReplaces;
532 FileToReplaces[std::string(File1)] = toReplacements(
533 {tooling::Replacement(Context.Sources, Context.getLocation(ID1, 1, 1), 6,
534 "auto "),
535 tooling::Replacement(Context.Sources, Context.getLocation(ID1, 3, 10), 1,
536 "12345678901")});
537 FileToReplaces[std::string(File2)] = toReplacements(
538 {tooling::Replacement(Context.Sources, Context.getLocation(ID2, 1, 12), 0,
539 "4567890123"),
540 tooling::Replacement(Context.Sources, Context.getLocation(ID2, 2, 9), 1,
541 "10")});
542 EXPECT_TRUE(
543 formatAndApplyAllReplacements(FileToReplaces, Context.Rewrite,
544 "{BasedOnStyle: LLVM, ColumnLimit: 20}"));
545 EXPECT_EQ(Expected1, Context.getRewrittenText(ID1));
546 EXPECT_EQ(Expected2, Context.getRewrittenText(ID2));
549 TEST(ShiftedCodePositionTest, FindsNewCodePosition) {
550 Replacements Replaces =
551 toReplacements({Replacement("", 0, 1, ""), Replacement("", 4, 3, " ")});
552 // Assume ' int i;' is turned into 'int i;' and cursor is located at '|'.
553 EXPECT_EQ(0u, Replaces.getShiftedCodePosition(0)); // |int i;
554 EXPECT_EQ(0u, Replaces.getShiftedCodePosition(1)); // |nt i;
555 EXPECT_EQ(1u, Replaces.getShiftedCodePosition(2)); // i|t i;
556 EXPECT_EQ(2u, Replaces.getShiftedCodePosition(3)); // in| i;
557 EXPECT_EQ(3u, Replaces.getShiftedCodePosition(4)); // int| i;
558 EXPECT_EQ(3u, Replaces.getShiftedCodePosition(5)); // int | i;
559 EXPECT_EQ(3u, Replaces.getShiftedCodePosition(6)); // int |i;
560 EXPECT_EQ(4u, Replaces.getShiftedCodePosition(7)); // int |;
561 EXPECT_EQ(5u, Replaces.getShiftedCodePosition(8)); // int i|
564 TEST(ShiftedCodePositionTest, FindsNewCodePositionWithInserts) {
565 Replacements Replaces = toReplacements({Replacement("", 4, 0, "\"\n\"")});
566 // Assume '"12345678"' is turned into '"1234"\n"5678"'.
567 EXPECT_EQ(3u, Replaces.getShiftedCodePosition(3)); // "123|5678"
568 EXPECT_EQ(7u, Replaces.getShiftedCodePosition(4)); // "1234|678"
569 EXPECT_EQ(8u, Replaces.getShiftedCodePosition(5)); // "12345|78"
572 TEST(ShiftedCodePositionTest, FindsNewCodePositionInReplacedText) {
573 // Replace the first four characters with "abcd".
574 auto Replaces = toReplacements({Replacement("", 0, 4, "abcd")});
575 for (unsigned i = 0; i < 3; ++i)
576 EXPECT_EQ(i, Replaces.getShiftedCodePosition(i));
579 TEST(ShiftedCodePositionTest, NoReplacementText) {
580 Replacements Replaces = toReplacements({Replacement("", 0, 42, "")});
581 EXPECT_EQ(0u, Replaces.getShiftedCodePosition(0));
582 EXPECT_EQ(0u, Replaces.getShiftedCodePosition(39));
583 EXPECT_EQ(3u, Replaces.getShiftedCodePosition(45));
584 EXPECT_EQ(0u, Replaces.getShiftedCodePosition(42));
587 class FlushRewrittenFilesTest : public ::testing::Test {
588 public:
589 FlushRewrittenFilesTest() {}
591 ~FlushRewrittenFilesTest() override {
592 for (llvm::StringMap<std::string>::iterator I = TemporaryFiles.begin(),
593 E = TemporaryFiles.end();
594 I != E; ++I) {
595 llvm::StringRef Name = I->second;
596 std::error_code EC = llvm::sys::fs::remove(Name);
597 (void)EC;
598 assert(!EC);
602 FileID createFile(llvm::StringRef Name, llvm::StringRef Content) {
603 SmallString<1024> Path;
604 int FD;
605 std::error_code EC = llvm::sys::fs::createTemporaryFile(Name, "", FD, Path);
606 assert(!EC);
607 (void)EC;
609 llvm::raw_fd_ostream OutStream(FD, true);
610 OutStream << Content;
611 OutStream.close();
612 auto File = Context.Files.getOptionalFileRef(Path);
613 assert(File);
615 StringRef Found =
616 TemporaryFiles.insert(std::make_pair(Name, std::string(Path.str())))
617 .first->second;
618 assert(Found == Path);
619 (void)Found;
620 return Context.Sources.createFileID(*File, SourceLocation(),
621 SrcMgr::C_User);
624 std::string getFileContentFromDisk(llvm::StringRef Name) {
625 std::string Path = TemporaryFiles.lookup(Name);
626 assert(!Path.empty());
627 // We need to read directly from the FileManager without relaying through
628 // a FileEntry, as otherwise we'd read through an already opened file
629 // descriptor, which might not see the changes made.
630 // FIXME: Figure out whether there is a way to get the SourceManger to
631 // reopen the file.
632 auto FileBuffer = Context.Files.getBufferForFile(Path);
633 return std::string((*FileBuffer)->getBuffer());
636 llvm::StringMap<std::string> TemporaryFiles;
637 RewriterTestContext Context;
640 TEST_F(FlushRewrittenFilesTest, StoresChangesOnDisk) {
641 FileID ID = createFile("input.cpp", "line1\nline2\nline3\nline4");
642 Replacements Replaces = toReplacements({Replacement(
643 Context.Sources, Context.getLocation(ID, 2, 1), 5, "replaced")});
644 EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
645 EXPECT_FALSE(Context.Rewrite.overwriteChangedFiles());
646 EXPECT_EQ("line1\nreplaced\nline3\nline4",
647 getFileContentFromDisk("input.cpp"));
650 namespace {
651 template <typename T>
652 class TestVisitor : public clang::RecursiveASTVisitor<T> {
653 public:
654 bool runOver(StringRef Code) {
655 return runToolOnCode(std::make_unique<TestAction>(this), Code);
658 protected:
659 clang::SourceManager *SM;
660 clang::ASTContext *Context;
662 private:
663 class FindConsumer : public clang::ASTConsumer {
664 public:
665 FindConsumer(TestVisitor *Visitor) : Visitor(Visitor) {}
667 void HandleTranslationUnit(clang::ASTContext &Context) override {
668 Visitor->TraverseDecl(Context.getTranslationUnitDecl());
671 private:
672 TestVisitor *Visitor;
675 class TestAction : public clang::ASTFrontendAction {
676 public:
677 TestAction(TestVisitor *Visitor) : Visitor(Visitor) {}
679 std::unique_ptr<clang::ASTConsumer>
680 CreateASTConsumer(clang::CompilerInstance &compiler,
681 llvm::StringRef dummy) override {
682 Visitor->SM = &compiler.getSourceManager();
683 Visitor->Context = &compiler.getASTContext();
684 /// TestConsumer will be deleted by the framework calling us.
685 return std::make_unique<FindConsumer>(Visitor);
688 private:
689 TestVisitor *Visitor;
692 } // end namespace
694 void expectReplacementAt(const Replacement &Replace,
695 StringRef File, unsigned Offset, unsigned Length) {
696 ASSERT_TRUE(Replace.isApplicable());
697 EXPECT_EQ(File, Replace.getFilePath());
698 EXPECT_EQ(Offset, Replace.getOffset());
699 EXPECT_EQ(Length, Replace.getLength());
702 class ClassDeclXVisitor : public TestVisitor<ClassDeclXVisitor> {
703 public:
704 bool VisitCXXRecordDecl(CXXRecordDecl *Record) {
705 if (Record->getName() == "X") {
706 Replace = Replacement(*SM, Record, "");
708 return true;
710 Replacement Replace;
713 TEST(Replacement, CanBeConstructedFromNode) {
714 ClassDeclXVisitor ClassDeclX;
715 EXPECT_TRUE(ClassDeclX.runOver(" class X;"));
716 expectReplacementAt(ClassDeclX.Replace, "input.cc", 5, 7);
719 TEST(Replacement, ReplacesAtSpellingLocation) {
720 ClassDeclXVisitor ClassDeclX;
721 EXPECT_TRUE(ClassDeclX.runOver("#define A(Y) Y\nA(class X);"));
722 expectReplacementAt(ClassDeclX.Replace, "input.cc", 17, 7);
725 class CallToFVisitor : public TestVisitor<CallToFVisitor> {
726 public:
727 bool VisitCallExpr(CallExpr *Call) {
728 if (Call->getDirectCallee()->getName() == "F") {
729 Replace = Replacement(*SM, Call, "");
731 return true;
733 Replacement Replace;
736 TEST(Replacement, FunctionCall) {
737 CallToFVisitor CallToF;
738 EXPECT_TRUE(CallToF.runOver("void F(); void G() { F(); }"));
739 expectReplacementAt(CallToF.Replace, "input.cc", 21, 3);
742 TEST(Replacement, TemplatedFunctionCall) {
743 CallToFVisitor CallToF;
744 EXPECT_TRUE(CallToF.runOver(
745 "template <typename T> void F(); void G() { F<int>(); }"));
746 expectReplacementAt(CallToF.Replace, "input.cc", 43, 8);
749 class NestedNameSpecifierAVisitor
750 : public TestVisitor<NestedNameSpecifierAVisitor> {
751 public:
752 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNSLoc) {
753 if (NNSLoc.getNestedNameSpecifier()) {
754 if (const NamespaceDecl* NS = NNSLoc.getNestedNameSpecifier()->getAsNamespace()) {
755 if (NS->getName() == "a") {
756 Replace = Replacement(*SM, &NNSLoc, "", Context->getLangOpts());
760 return TestVisitor<NestedNameSpecifierAVisitor>::TraverseNestedNameSpecifierLoc(
761 NNSLoc);
763 Replacement Replace;
766 TEST(Replacement, ColonColon) {
767 NestedNameSpecifierAVisitor VisitNNSA;
768 EXPECT_TRUE(VisitNNSA.runOver("namespace a { void f() { ::a::f(); } }"));
769 expectReplacementAt(VisitNNSA.Replace, "input.cc", 25, 5);
772 TEST(Range, overlaps) {
773 EXPECT_TRUE(Range(10, 10).overlapsWith(Range(0, 11)));
774 EXPECT_TRUE(Range(0, 11).overlapsWith(Range(10, 10)));
775 EXPECT_FALSE(Range(10, 10).overlapsWith(Range(0, 10)));
776 EXPECT_FALSE(Range(0, 10).overlapsWith(Range(10, 10)));
777 EXPECT_TRUE(Range(0, 10).overlapsWith(Range(2, 6)));
778 EXPECT_TRUE(Range(2, 6).overlapsWith(Range(0, 10)));
781 TEST(Range, contains) {
782 EXPECT_TRUE(Range(0, 10).contains(Range(0, 10)));
783 EXPECT_TRUE(Range(0, 10).contains(Range(2, 6)));
784 EXPECT_FALSE(Range(2, 6).contains(Range(0, 10)));
785 EXPECT_FALSE(Range(0, 10).contains(Range(0, 11)));
788 TEST(Range, CalculateRangesOfReplacements) {
789 // Before: aaaabbbbbbz
790 // After : bbbbbbzzzzzzoooooooooooooooo
791 Replacements Replaces = toReplacements(
792 {Replacement("foo", 0, 4, ""), Replacement("foo", 10, 1, "zzzzzz"),
793 Replacement("foo", 11, 0, "oooooooooooooooo")});
795 std::vector<Range> Ranges = Replaces.getAffectedRanges();
797 EXPECT_EQ(2ul, Ranges.size());
798 EXPECT_TRUE(Ranges[0].getOffset() == 0);
799 EXPECT_TRUE(Ranges[0].getLength() == 0);
800 EXPECT_TRUE(Ranges[1].getOffset() == 6);
801 EXPECT_TRUE(Ranges[1].getLength() == 22);
804 TEST(Range, CalculateRangesOfInsertionAroundReplacement) {
805 Replacements Replaces = toReplacements(
806 {Replacement("foo", 0, 2, ""), Replacement("foo", 0, 0, "ba")});
808 std::vector<Range> Ranges = Replaces.getAffectedRanges();
810 EXPECT_EQ(1ul, Ranges.size());
811 EXPECT_EQ(0u, Ranges[0].getOffset());
812 EXPECT_EQ(2u, Ranges[0].getLength());
815 TEST(Range, RangesAfterEmptyReplacements) {
816 std::vector<Range> Ranges = {Range(5, 6), Range(10, 5)};
817 Replacements Replaces;
818 std::vector<Range> Expected = {Range(5, 10)};
819 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
822 TEST(Range, RangesAfterReplacements) {
823 std::vector<Range> Ranges = {Range(5, 2), Range(10, 5)};
824 Replacements Replaces = toReplacements({Replacement("foo", 0, 2, "1234")});
825 std::vector<Range> Expected = {Range(0, 4), Range(7, 2), Range(12, 5)};
826 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
829 TEST(Range, RangesBeforeReplacements) {
830 std::vector<Range> Ranges = {Range(5, 2), Range(10, 5)};
831 Replacements Replaces = toReplacements({Replacement("foo", 20, 2, "1234")});
832 std::vector<Range> Expected = {Range(5, 2), Range(10, 5), Range(20, 4)};
833 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
836 TEST(Range, NotAffectedByReplacements) {
837 std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(10, 5)};
838 Replacements Replaces = toReplacements({Replacement("foo", 3, 2, "12"),
839 Replacement("foo", 12, 2, "12"),
840 Replacement("foo", 20, 5, "")});
841 std::vector<Range> Expected = {Range(0, 2), Range(3, 4), Range(10, 5),
842 Range(20, 0)};
843 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
846 TEST(Range, RangesWithNonOverlappingReplacements) {
847 std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(10, 5)};
848 Replacements Replaces = toReplacements({Replacement("foo", 3, 1, ""),
849 Replacement("foo", 6, 1, "123"),
850 Replacement("foo", 20, 2, "12345")});
851 std::vector<Range> Expected = {Range(0, 2), Range(3, 0), Range(4, 4),
852 Range(11, 5), Range(21, 5)};
853 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
856 TEST(Range, RangesWithOverlappingReplacements) {
857 std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(15, 5),
858 Range(30, 5)};
859 Replacements Replaces = toReplacements(
860 {Replacement("foo", 1, 3, ""), Replacement("foo", 6, 1, "123"),
861 Replacement("foo", 13, 3, "1"), Replacement("foo", 25, 15, "")});
862 std::vector<Range> Expected = {Range(0, 1), Range(2, 4), Range(12, 5),
863 Range(22, 0)};
864 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
867 TEST(Range, MergeIntoOneRange) {
868 std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(15, 5)};
869 Replacements Replaces =
870 toReplacements({Replacement("foo", 1, 15, "1234567890")});
871 std::vector<Range> Expected = {Range(0, 15)};
872 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
875 TEST(Range, ReplacementsStartingAtRangeOffsets) {
876 std::vector<Range> Ranges = {Range(0, 2), Range(5, 5), Range(15, 5)};
877 Replacements Replaces = toReplacements(
878 {Replacement("foo", 0, 2, "12"), Replacement("foo", 5, 1, "123"),
879 Replacement("foo", 7, 4, "12345"), Replacement("foo", 15, 10, "12")});
880 std::vector<Range> Expected = {Range(0, 2), Range(5, 9), Range(18, 2)};
881 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
884 TEST(Range, ReplacementsEndingAtRangeEnds) {
885 std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(15, 5)};
886 Replacements Replaces = toReplacements(
887 {Replacement("foo", 6, 1, "123"), Replacement("foo", 17, 3, "12")});
888 std::vector<Range> Expected = {Range(0, 2), Range(5, 4), Range(17, 4)};
889 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
892 TEST(Range, AjacentReplacements) {
893 std::vector<Range> Ranges = {Range(0, 0), Range(15, 5)};
894 Replacements Replaces = toReplacements(
895 {Replacement("foo", 1, 2, "123"), Replacement("foo", 12, 3, "1234")});
896 std::vector<Range> Expected = {Range(0, 0), Range(1, 3), Range(13, 9)};
897 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
900 TEST(Range, MergeRangesAfterReplacements) {
901 std::vector<Range> Ranges = {Range(8, 0), Range(5, 2), Range(9, 0), Range(0, 1)};
902 Replacements Replaces = toReplacements({Replacement("foo", 1, 3, ""),
903 Replacement("foo", 7, 0, "12"),
904 Replacement("foo", 9, 2, "")});
905 std::vector<Range> Expected = {Range(0, 1), Range(2, 4), Range(7, 0),
906 Range(8, 0)};
907 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
910 TEST(Range, ConflictingRangesBeforeReplacements) {
911 std::vector<Range> Ranges = {Range(8, 3), Range(5, 4), Range(9, 1)};
912 Replacements Replaces = toReplacements({Replacement("foo", 1, 3, "")});
913 std::vector<Range> Expected = {Range(1, 0), Range(2, 6)};
914 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
917 class MergeReplacementsTest : public ::testing::Test {
918 protected:
919 void mergeAndTestRewrite(StringRef Code, StringRef Intermediate,
920 StringRef Result, const Replacements &First,
921 const Replacements &Second) {
922 // These are mainly to verify the test itself and make it easier to read.
923 auto AfterFirst = applyAllReplacements(Code, First);
924 EXPECT_TRUE(static_cast<bool>(AfterFirst));
925 auto InSequenceRewrite = applyAllReplacements(*AfterFirst, Second);
926 EXPECT_TRUE(static_cast<bool>(InSequenceRewrite));
927 EXPECT_EQ(Intermediate, *AfterFirst);
928 EXPECT_EQ(Result, *InSequenceRewrite);
930 tooling::Replacements Merged = First.merge(Second);
931 auto MergedRewrite = applyAllReplacements(Code, Merged);
932 EXPECT_TRUE(static_cast<bool>(MergedRewrite));
933 EXPECT_EQ(*InSequenceRewrite, *MergedRewrite);
934 if (*InSequenceRewrite != *MergedRewrite)
935 for (tooling::Replacement M : Merged)
936 llvm::errs() << M.getOffset() << " " << M.getLength() << " "
937 << M.getReplacementText() << "\n";
939 void mergeAndTestRewrite(StringRef Code, const Replacements &First,
940 const Replacements &Second) {
941 auto AfterFirst = applyAllReplacements(Code, First);
942 EXPECT_TRUE(static_cast<bool>(AfterFirst));
943 auto InSequenceRewrite = applyAllReplacements(*AfterFirst, Second);
944 tooling::Replacements Merged = First.merge(Second);
945 auto MergedRewrite = applyAllReplacements(Code, Merged);
946 EXPECT_TRUE(static_cast<bool>(MergedRewrite));
947 EXPECT_EQ(*InSequenceRewrite, *MergedRewrite);
948 if (*InSequenceRewrite != *MergedRewrite)
949 for (tooling::Replacement M : Merged)
950 llvm::errs() << M.getOffset() << " " << M.getLength() << " "
951 << M.getReplacementText() << "\n";
955 TEST_F(MergeReplacementsTest, Offsets) {
956 mergeAndTestRewrite("aaa", "aabab", "cacabab",
957 toReplacements({{"", 2, 0, "b"}, {"", 3, 0, "b"}}),
958 toReplacements({{"", 0, 0, "c"}, {"", 1, 0, "c"}}));
959 mergeAndTestRewrite("aaa", "babaa", "babacac",
960 toReplacements({{"", 0, 0, "b"}, {"", 1, 0, "b"}}),
961 toReplacements({{"", 4, 0, "c"}, {"", 5, 0, "c"}}));
962 mergeAndTestRewrite("aaaa", "aaa", "aac", toReplacements({{"", 1, 1, ""}}),
963 toReplacements({{"", 2, 1, "c"}}));
965 mergeAndTestRewrite("aa", "bbabba", "bbabcba",
966 toReplacements({{"", 0, 0, "bb"}, {"", 1, 0, "bb"}}),
967 toReplacements({{"", 4, 0, "c"}}));
970 TEST_F(MergeReplacementsTest, Concatenations) {
971 // Basic concatenations. It is important to merge these into a single
972 // replacement to ensure the correct order.
974 auto First = toReplacements({{"", 0, 0, "a"}});
975 auto Second = toReplacements({{"", 1, 0, "b"}});
976 EXPECT_EQ(toReplacements({{"", 0, 0, "ab"}}), First.merge(Second));
979 auto First = toReplacements({{"", 0, 0, "a"}});
980 auto Second = toReplacements({{"", 0, 0, "b"}});
981 EXPECT_EQ(toReplacements({{"", 0, 0, "ba"}}), First.merge(Second));
983 mergeAndTestRewrite("", "a", "ab", toReplacements({{"", 0, 0, "a"}}),
984 toReplacements({{"", 1, 0, "b"}}));
985 mergeAndTestRewrite("", "a", "ba", toReplacements({{"", 0, 0, "a"}}),
986 toReplacements({{"", 0, 0, "b"}}));
989 TEST_F(MergeReplacementsTest, NotChangingLengths) {
990 mergeAndTestRewrite("aaaa", "abba", "acca",
991 toReplacements({{"", 1, 2, "bb"}}),
992 toReplacements({{"", 1, 2, "cc"}}));
993 mergeAndTestRewrite("aaaa", "abba", "abcc",
994 toReplacements({{"", 1, 2, "bb"}}),
995 toReplacements({{"", 2, 2, "cc"}}));
996 mergeAndTestRewrite("aaaa", "abba", "ccba",
997 toReplacements({{"", 1, 2, "bb"}}),
998 toReplacements({{"", 0, 2, "cc"}}));
999 mergeAndTestRewrite("aaaaaa", "abbdda", "abccda",
1000 toReplacements({{"", 1, 2, "bb"}, {"", 3, 2, "dd"}}),
1001 toReplacements({{"", 2, 2, "cc"}}));
1004 TEST_F(MergeReplacementsTest, OverlappingRanges) {
1005 mergeAndTestRewrite("aaa", "bbd", "bcbcd",
1006 toReplacements({{"", 0, 1, "bb"}, {"", 1, 2, "d"}}),
1007 toReplacements({{"", 1, 0, "c"}, {"", 2, 0, "c"}}));
1009 mergeAndTestRewrite("aaaa", "aabbaa", "acccca",
1010 toReplacements({{"", 2, 0, "bb"}}),
1011 toReplacements({{"", 1, 4, "cccc"}}));
1012 mergeAndTestRewrite("aaaa", "aababa", "acccca",
1013 toReplacements({{"", 2, 0, "b"}, {"", 3, 0, "b"}}),
1014 toReplacements({{"", 1, 4, "cccc"}}));
1015 mergeAndTestRewrite("aaaaaa", "abbbba", "abba",
1016 toReplacements({{"", 1, 4, "bbbb"}}),
1017 toReplacements({{"", 2, 2, ""}}));
1018 mergeAndTestRewrite("aaaa", "aa", "cc",
1019 toReplacements({{"", 1, 1, ""}, {"", 2, 1, ""}}),
1020 toReplacements({{"", 0, 2, "cc"}}));
1021 mergeAndTestRewrite("aa", "abbba", "abcbcba",
1022 toReplacements({{"", 1, 0, "bbb"}}),
1023 toReplacements({{"", 2, 0, "c"}, {"", 3, 0, "c"}}));
1025 mergeAndTestRewrite(
1026 "aaa", "abbab", "ccdd",
1027 toReplacements({{"", 0, 1, ""}, {"", 2, 0, "bb"}, {"", 3, 0, "b"}}),
1028 toReplacements({{"", 0, 2, "cc"}, {"", 2, 3, "dd"}}));
1029 mergeAndTestRewrite(
1030 "aa", "babbab", "ccdd",
1031 toReplacements({{"", 0, 0, "b"}, {"", 1, 0, "bb"}, {"", 2, 0, "b"}}),
1032 toReplacements({{"", 0, 3, "cc"}, {"", 3, 3, "dd"}}));
1035 static constexpr bool usesWindowsPaths() {
1036 return is_style_windows(llvm::sys::path::Style::native);
1039 TEST(DeduplicateByFileTest, PathsWithDots) {
1040 std::map<std::string, Replacements> FileToReplaces;
1041 llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> VFS(
1042 new llvm::vfs::InMemoryFileSystem());
1043 FileManager FileMgr(FileSystemOptions(), VFS);
1044 StringRef Path1 = usesWindowsPaths() ? "a\\b\\..\\.\\c.h" : "a/b/.././c.h";
1045 StringRef Path2 = usesWindowsPaths() ? "a\\c.h" : "a/c.h";
1046 EXPECT_TRUE(VFS->addFile(Path1, 0, llvm::MemoryBuffer::getMemBuffer("")));
1047 EXPECT_TRUE(VFS->addFile(Path2, 0, llvm::MemoryBuffer::getMemBuffer("")));
1048 FileToReplaces[std::string(Path1)] = Replacements();
1049 FileToReplaces[std::string(Path2)] = Replacements();
1050 FileToReplaces = groupReplacementsByFile(FileMgr, FileToReplaces);
1051 EXPECT_EQ(1u, FileToReplaces.size());
1052 EXPECT_EQ(Path1, FileToReplaces.begin()->first);
1055 TEST(DeduplicateByFileTest, PathWithDotSlash) {
1056 std::map<std::string, Replacements> FileToReplaces;
1057 llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> VFS(
1058 new llvm::vfs::InMemoryFileSystem());
1059 FileManager FileMgr(FileSystemOptions(), VFS);
1060 StringRef Path1 = usesWindowsPaths() ? ".\\a\\b\\c.h" : "./a/b/c.h";
1061 StringRef Path2 = usesWindowsPaths() ? "a\\b\\c.h" : "a/b/c.h";
1062 EXPECT_TRUE(VFS->addFile(Path1, 0, llvm::MemoryBuffer::getMemBuffer("")));
1063 EXPECT_TRUE(VFS->addFile(Path2, 0, llvm::MemoryBuffer::getMemBuffer("")));
1064 FileToReplaces[std::string(Path1)] = Replacements();
1065 FileToReplaces[std::string(Path2)] = Replacements();
1066 FileToReplaces = groupReplacementsByFile(FileMgr, FileToReplaces);
1067 EXPECT_EQ(1u, FileToReplaces.size());
1068 EXPECT_EQ(Path1, FileToReplaces.begin()->first);
1071 TEST(DeduplicateByFileTest, NonExistingFilePath) {
1072 std::map<std::string, Replacements> FileToReplaces;
1073 llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> VFS(
1074 new llvm::vfs::InMemoryFileSystem());
1075 FileManager FileMgr(FileSystemOptions(), VFS);
1076 StringRef Path1 = usesWindowsPaths() ? ".\\a\\b\\c.h" : "./a/b/c.h";
1077 StringRef Path2 = usesWindowsPaths() ? "a\\b\\c.h" : "a/b/c.h";
1078 FileToReplaces[std::string(Path1)] = Replacements();
1079 FileToReplaces[std::string(Path2)] = Replacements();
1080 FileToReplaces = groupReplacementsByFile(FileMgr, FileToReplaces);
1081 EXPECT_TRUE(FileToReplaces.empty());
1084 class AtomicChangeTest : public ::testing::Test {
1085 protected:
1086 void SetUp() override {
1087 DefaultFileID = Context.createInMemoryFile("input.cpp", DefaultCode);
1088 DefaultLoc = Context.Sources.getLocForStartOfFile(DefaultFileID)
1089 .getLocWithOffset(20);
1090 assert(DefaultLoc.isValid() && "Default location must be valid.");
1093 RewriterTestContext Context;
1094 std::string DefaultCode = std::string(100, 'a');
1095 unsigned DefaultOffset = 20;
1096 SourceLocation DefaultLoc;
1097 FileID DefaultFileID;
1100 TEST_F(AtomicChangeTest, AtomicChangeToYAML) {
1101 AtomicChange Change(Context.Sources, DefaultLoc);
1102 llvm::Error Err =
1103 Change.insert(Context.Sources, DefaultLoc, "aa", /*InsertAfter=*/false);
1104 ASSERT_TRUE(!Err);
1105 Err = Change.insert(Context.Sources, DefaultLoc.getLocWithOffset(10), "bb",
1106 /*InsertAfter=*/false);
1107 ASSERT_TRUE(!Err);
1108 Change.addHeader("a.h");
1109 Change.removeHeader("b.h");
1110 std::string YAMLString = Change.toYAMLString();
1112 // NOTE: If this test starts to fail for no obvious reason, check whitespace.
1113 ASSERT_STREQ("---\n"
1114 "Key: 'input.cpp:20'\n"
1115 "FilePath: input.cpp\n"
1116 "Error: ''\n"
1117 "InsertedHeaders:\n"
1118 " - a.h\n"
1119 "RemovedHeaders:\n"
1120 " - b.h\n"
1121 "Replacements:\n"
1122 " - FilePath: input.cpp\n"
1123 " Offset: 20\n"
1124 " Length: 0\n"
1125 " ReplacementText: aa\n"
1126 " - FilePath: input.cpp\n"
1127 " Offset: 30\n"
1128 " Length: 0\n"
1129 " ReplacementText: bb\n"
1130 "...\n",
1131 YAMLString.c_str());
1134 TEST_F(AtomicChangeTest, YAMLToAtomicChange) {
1135 std::string YamlContent = "---\n"
1136 "Key: 'input.cpp:20'\n"
1137 "FilePath: input.cpp\n"
1138 "Error: 'ok'\n"
1139 "InsertedHeaders:\n"
1140 " - a.h\n"
1141 "RemovedHeaders:\n"
1142 " - b.h\n"
1143 "Replacements:\n"
1144 " - FilePath: input.cpp\n"
1145 " Offset: 20\n"
1146 " Length: 0\n"
1147 " ReplacementText: aa\n"
1148 " - FilePath: input.cpp\n"
1149 " Offset: 30\n"
1150 " Length: 0\n"
1151 " ReplacementText: bb\n"
1152 "...\n";
1153 AtomicChange ExpectedChange(Context.Sources, DefaultLoc);
1154 llvm::Error Err = ExpectedChange.insert(Context.Sources, DefaultLoc, "aa",
1155 /*InsertAfter=*/false);
1156 ASSERT_TRUE(!Err);
1157 Err = ExpectedChange.insert(Context.Sources, DefaultLoc.getLocWithOffset(10),
1158 "bb", /*InsertAfter=*/false);
1159 ASSERT_TRUE(!Err);
1161 ExpectedChange.addHeader("a.h");
1162 ExpectedChange.removeHeader("b.h");
1163 ExpectedChange.setError("ok");
1165 AtomicChange ActualChange = AtomicChange::convertFromYAML(YamlContent);
1166 EXPECT_EQ(ExpectedChange.getKey(), ActualChange.getKey());
1167 EXPECT_EQ(ExpectedChange.getFilePath(), ActualChange.getFilePath());
1168 EXPECT_EQ(ExpectedChange.getError(), ActualChange.getError());
1169 EXPECT_EQ(ExpectedChange.getInsertedHeaders(),
1170 ActualChange.getInsertedHeaders());
1171 EXPECT_EQ(ExpectedChange.getRemovedHeaders(),
1172 ActualChange.getRemovedHeaders());
1173 EXPECT_EQ(ExpectedChange.getReplacements().size(),
1174 ActualChange.getReplacements().size());
1175 EXPECT_EQ(2u, ActualChange.getReplacements().size());
1176 EXPECT_EQ(*ExpectedChange.getReplacements().begin(),
1177 *ActualChange.getReplacements().begin());
1178 EXPECT_EQ(*(++ExpectedChange.getReplacements().begin()),
1179 *(++ActualChange.getReplacements().begin()));
1182 TEST_F(AtomicChangeTest, CheckKeyAndKeyFile) {
1183 AtomicChange Change(Context.Sources, DefaultLoc);
1184 EXPECT_EQ("input.cpp:20", Change.getKey());
1185 EXPECT_EQ("input.cpp", Change.getFilePath());
1188 TEST_F(AtomicChangeTest, Replace) {
1189 AtomicChange Change(Context.Sources, DefaultLoc);
1190 llvm::Error Err = Change.replace(Context.Sources, DefaultLoc, 2, "aa");
1191 ASSERT_TRUE(!Err);
1192 EXPECT_EQ(Change.getReplacements().size(), 1u);
1193 EXPECT_EQ(*Change.getReplacements().begin(),
1194 Replacement(Context.Sources, DefaultLoc, 2, "aa"));
1196 // Add a new replacement that conflicts with the existing one.
1197 Err = Change.replace(Context.Sources, DefaultLoc, 3, "ab");
1198 EXPECT_TRUE((bool)Err);
1199 llvm::consumeError(std::move(Err));
1200 EXPECT_EQ(Change.getReplacements().size(), 1u);
1203 TEST_F(AtomicChangeTest, ReplaceWithRange) {
1204 AtomicChange Change(Context.Sources, DefaultLoc);
1205 SourceLocation End = DefaultLoc.getLocWithOffset(20);
1206 llvm::Error Err = Change.replace(
1207 Context.Sources, CharSourceRange::getCharRange(DefaultLoc, End), "aa");
1208 ASSERT_TRUE(!Err);
1209 EXPECT_EQ(Change.getReplacements().size(), 1u);
1210 EXPECT_EQ(*Change.getReplacements().begin(),
1211 Replacement(Context.Sources, DefaultLoc, 20, "aa"));
1214 TEST_F(AtomicChangeTest, InsertBefore) {
1215 AtomicChange Change(Context.Sources, DefaultLoc);
1216 llvm::Error Err = Change.insert(Context.Sources, DefaultLoc, "aa");
1217 ASSERT_TRUE(!Err);
1218 EXPECT_EQ(Change.getReplacements().size(), 1u);
1219 EXPECT_EQ(*Change.getReplacements().begin(),
1220 Replacement(Context.Sources, DefaultLoc, 0, "aa"));
1221 Err = Change.insert(Context.Sources, DefaultLoc, "b", /*InsertAfter=*/false);
1222 ASSERT_TRUE(!Err);
1223 EXPECT_EQ(Change.getReplacements().size(), 1u);
1224 EXPECT_EQ(*Change.getReplacements().begin(),
1225 Replacement(Context.Sources, DefaultLoc, 0, "baa"));
1228 TEST_F(AtomicChangeTest, InsertAfter) {
1229 AtomicChange Change(Context.Sources, DefaultLoc);
1230 llvm::Error Err = Change.insert(Context.Sources, DefaultLoc, "aa");
1231 ASSERT_TRUE(!Err);
1232 EXPECT_EQ(Change.getReplacements().size(), 1u);
1233 EXPECT_EQ(*Change.getReplacements().begin(),
1234 Replacement(Context.Sources, DefaultLoc, 0, "aa"));
1235 Err = Change.insert(Context.Sources, DefaultLoc, "b");
1236 ASSERT_TRUE(!Err);
1237 EXPECT_EQ(Change.getReplacements().size(), 1u);
1238 EXPECT_EQ(*Change.getReplacements().begin(),
1239 Replacement(Context.Sources, DefaultLoc, 0, "aab"));
1242 TEST_F(AtomicChangeTest, InsertBeforeWithInvalidLocation) {
1243 AtomicChange Change(Context.Sources, DefaultLoc);
1244 llvm::Error Err =
1245 Change.insert(Context.Sources, DefaultLoc, "a", /*InsertAfter=*/false);
1246 ASSERT_TRUE(!Err);
1248 // Invalid location.
1249 Err = Change.insert(Context.Sources, SourceLocation(), "a",
1250 /*InsertAfter=*/false);
1251 ASSERT_TRUE((bool)Err);
1252 EXPECT_TRUE(checkReplacementError(
1253 std::move(Err), replacement_error::wrong_file_path,
1254 Replacement(Context.Sources, DefaultLoc, 0, "a"),
1255 Replacement(Context.Sources, SourceLocation(), 0, "a")));
1258 TEST_F(AtomicChangeTest, InsertBeforeToWrongFile) {
1259 AtomicChange Change(Context.Sources, DefaultLoc);
1260 llvm::Error Err =
1261 Change.insert(Context.Sources, DefaultLoc, "a", /*InsertAfter=*/false);
1262 ASSERT_TRUE(!Err);
1264 // Inserting at a different file.
1265 FileID NewID = Context.createInMemoryFile("extra.cpp", DefaultCode);
1266 SourceLocation NewLoc = Context.Sources.getLocForStartOfFile(NewID);
1267 Err = Change.insert(Context.Sources, NewLoc, "b", /*InsertAfter=*/false);
1268 ASSERT_TRUE((bool)Err);
1269 EXPECT_TRUE(
1270 checkReplacementError(std::move(Err), replacement_error::wrong_file_path,
1271 Replacement(Context.Sources, DefaultLoc, 0, "a"),
1272 Replacement(Context.Sources, NewLoc, 0, "b")));
1275 TEST_F(AtomicChangeTest, InsertAfterWithInvalidLocation) {
1276 AtomicChange Change(Context.Sources, DefaultLoc);
1277 llvm::Error Err = Change.insert(Context.Sources, DefaultLoc, "a");
1278 ASSERT_TRUE(!Err);
1280 // Invalid location.
1281 Err = Change.insert(Context.Sources, SourceLocation(), "b");
1282 ASSERT_TRUE((bool)Err);
1283 EXPECT_TRUE(checkReplacementError(
1284 std::move(Err), replacement_error::wrong_file_path,
1285 Replacement(Context.Sources, DefaultLoc, 0, "a"),
1286 Replacement(Context.Sources, SourceLocation(), 0, "b")));
1289 TEST_F(AtomicChangeTest, Metadata) {
1290 AtomicChange Change(Context.Sources, DefaultLoc, 17);
1291 const llvm::Any &Metadata = Change.getMetadata();
1292 ASSERT_TRUE(llvm::any_cast<int>(&Metadata));
1293 EXPECT_EQ(llvm::any_cast<int>(Metadata), 17);
1296 TEST_F(AtomicChangeTest, NoMetadata) {
1297 AtomicChange Change(Context.Sources, DefaultLoc);
1298 EXPECT_FALSE(Change.getMetadata().has_value());
1301 class ApplyAtomicChangesTest : public ::testing::Test {
1302 protected:
1303 ApplyAtomicChangesTest() : FilePath("file.cc") {
1304 Spec.Cleanup = true;
1305 Spec.Format = ApplyChangesSpec::kAll;
1306 Spec.Style = format::getLLVMStyle();
1309 ~ApplyAtomicChangesTest() override {}
1311 void setInput(llvm::StringRef Input) {
1312 Code = std::string(Input);
1313 FID = Context.createInMemoryFile(FilePath, Code);
1316 SourceLocation getLoc(unsigned Offset) const {
1317 return Context.Sources.getLocForStartOfFile(FID).getLocWithOffset(Offset);
1320 AtomicChange replacementToAtomicChange(llvm::StringRef Key, unsigned Offset,
1321 unsigned Length,
1322 llvm::StringRef Text) {
1323 AtomicChange Change(FilePath, Key);
1324 llvm::Error Err =
1325 Change.replace(Context.Sources, getLoc(Offset), Length, Text);
1326 EXPECT_FALSE(Err);
1327 return Change;
1330 std::string rewrite(bool FailureExpected = false) {
1331 llvm::Expected<std::string> ChangedCode =
1332 applyAtomicChanges(FilePath, Code, Changes, Spec);
1333 EXPECT_EQ(FailureExpected, !ChangedCode);
1334 if (!ChangedCode) {
1335 llvm::errs() << "Failed to apply changes: "
1336 << llvm::toString(ChangedCode.takeError()) << "\n";
1337 return "";
1339 return *ChangedCode;
1342 RewriterTestContext Context;
1343 FileID FID;
1344 ApplyChangesSpec Spec;
1345 std::string Code;
1346 std::string FilePath;
1347 llvm::SmallVector<AtomicChange, 8> Changes;
1350 TEST_F(ApplyAtomicChangesTest, BasicRefactoring) {
1351 setInput("int a;");
1352 AtomicChange Change(FilePath, "key1");
1353 Changes.push_back(replacementToAtomicChange("key1", 4, 1, "b"));
1354 EXPECT_EQ("int b;", rewrite());
1357 TEST_F(ApplyAtomicChangesTest, SeveralRefactorings) {
1358 setInput("int a;\n"
1359 "int b;");
1360 Changes.push_back(replacementToAtomicChange("key1", 0, 3, "float"));
1361 Changes.push_back(replacementToAtomicChange("key2", 4, 1, "f"));
1362 Changes.push_back(replacementToAtomicChange("key3", 11, 1, "g"));
1363 Changes.push_back(replacementToAtomicChange("key4", 7, 3, "float"));
1364 EXPECT_EQ("float f;\n"
1365 "float g;",
1366 rewrite());
1369 TEST_F(ApplyAtomicChangesTest, IgnorePathsInRefactorings) {
1370 setInput("int a;\n"
1371 "int b;");
1372 Changes.push_back(replacementToAtomicChange("key1", 4, 1, "aa"));
1374 FileID ID = Context.createInMemoryFile("AnotherFile", "12345678912345");
1375 Changes.emplace_back("AnotherFile", "key2");
1376 auto Err = Changes.back().replace(
1377 Context.Sources,
1378 Context.Sources.getLocForStartOfFile(ID).getLocWithOffset(11), 1, "bb");
1379 ASSERT_TRUE(!Err);
1380 EXPECT_EQ("int aa;\n"
1381 "int bb;",
1382 rewrite());
1385 TEST_F(ApplyAtomicChangesTest, AppliesDuplicateInsertions) {
1386 setInput("int a;");
1387 Changes.push_back(replacementToAtomicChange("key1", 5, 0, "b"));
1388 Changes.push_back(replacementToAtomicChange("key2", 5, 0, "b"));
1389 EXPECT_EQ("int abb;", rewrite());
1392 TEST_F(ApplyAtomicChangesTest, BailsOnOverlappingRefactorings) {
1393 setInput("int a;");
1394 Changes.push_back(replacementToAtomicChange("key1", 0, 5, "float f"));
1395 Changes.push_back(replacementToAtomicChange("key2", 4, 1, "b"));
1396 EXPECT_EQ("", rewrite(/*FailureExpected=*/true));
1399 TEST_F(ApplyAtomicChangesTest, BasicReformatting) {
1400 setInput("int a;");
1401 Changes.push_back(replacementToAtomicChange("key1", 5, 1, "b"));
1402 EXPECT_EQ("int b;", rewrite());
1405 TEST_F(ApplyAtomicChangesTest, OnlyFormatWhenViolateColumnLimits) {
1406 Spec.Format = ApplyChangesSpec::kViolations;
1407 Spec.Style.ColumnLimit = 8;
1408 setInput("int a;\n"
1409 "int a;\n"
1410 "int aaaaaaaa;\n");
1411 Changes.push_back(replacementToAtomicChange("key1", 5, 1, "x"));
1412 Changes.push_back(replacementToAtomicChange("key2", 15, 1, "x"));
1413 Changes.push_back(replacementToAtomicChange("key3", 23, 8, "xx"));
1414 EXPECT_EQ("int x;\n"
1415 "int x;\n"
1416 "int xx;\n",
1417 rewrite());
1420 TEST_F(ApplyAtomicChangesTest, LastLineViolateColumnLimits) {
1421 Spec.Format = ApplyChangesSpec::kViolations;
1422 Spec.Style.ColumnLimit = 8;
1423 setInput("int a;\n"
1424 "int a;");
1425 Changes.push_back(replacementToAtomicChange("key1", 0, 1, "i"));
1426 Changes.push_back(replacementToAtomicChange("key2", 15, 2, "y;"));
1427 EXPECT_EQ("int a;\n"
1428 "int y;",
1429 rewrite());
1432 TEST_F(ApplyAtomicChangesTest, LastLineWithNewlineViolateColumnLimits) {
1433 Spec.Format = ApplyChangesSpec::kViolations;
1434 Spec.Style.ColumnLimit = 8;
1435 setInput("int a;\n"
1436 "int a;\n");
1437 Changes.push_back(replacementToAtomicChange("key1", 0, 1, "i"));
1438 Changes.push_back(replacementToAtomicChange("key2", 14, 3, "y;\n"));
1439 EXPECT_EQ("int a;\n"
1440 "int y;\n",
1441 rewrite());
1444 TEST_F(ApplyAtomicChangesTest, Longer) {
1445 setInput("int a;");
1446 Changes.push_back(replacementToAtomicChange("key1", 5, 1, "bbb"));
1447 EXPECT_EQ("int bbb;", rewrite());
1450 TEST_F(ApplyAtomicChangesTest, Shorter) {
1451 setInput("int aaa;");
1452 Changes.push_back(replacementToAtomicChange("key1", 5, 3, "b"));
1453 EXPECT_EQ("int b;", rewrite());
1456 TEST_F(ApplyAtomicChangesTest, OnlyFormatChangedLines) {
1457 setInput("int aaa;\n"
1458 "int a = b;\n"
1459 "int bbb;");
1460 Changes.push_back(replacementToAtomicChange("key1", 14, 1, "b"));
1461 EXPECT_EQ("int aaa;\n"
1462 "int b = b;\n"
1463 "int bbb;",
1464 rewrite());
1467 TEST_F(ApplyAtomicChangesTest, DisableFormatting) {
1468 Spec.Format = ApplyChangesSpec::kNone;
1469 setInput("int aaa;\n"
1470 "int a = b;\n"
1471 "int bbb;");
1472 Changes.push_back(replacementToAtomicChange("key1", 14, 1, "b"));
1473 EXPECT_EQ("int aaa;\n"
1474 "int b = b;\n"
1475 "int bbb;",
1476 rewrite());
1479 TEST_F(ApplyAtomicChangesTest, AdaptsToLocalPointerStyle) {
1480 setInput("int *aaa;\n"
1481 "int *bbb;");
1482 Changes.push_back(replacementToAtomicChange("key1", 0, 0, "int* ccc;\n"));
1483 EXPECT_EQ("int *ccc;\n"
1484 "int *aaa;\n"
1485 "int *bbb;",
1486 rewrite());
1489 TEST_F(ApplyAtomicChangesTest, AcceptsSurroundingFormatting) {
1490 setInput(" int aaa;\n"
1491 " int a = b;\n"
1492 " int bbb;");
1493 Changes.push_back(replacementToAtomicChange("key1", 20, 1, "b"));
1494 EXPECT_EQ(" int aaa;\n"
1495 " int b = b;\n"
1496 " int bbb;",
1497 rewrite());
1500 TEST_F(ApplyAtomicChangesTest, BailsOutOnConflictingChanges) {
1501 setInput("int c;\n"
1502 "int f;");
1503 // Insertions at the same offset are only allowed in the same AtomicChange.
1504 Changes.push_back(replacementToAtomicChange("key1", 0, 0, "int a;\n"));
1505 Changes.push_back(replacementToAtomicChange("key2", 0, 0, "int b;\n"));
1506 EXPECT_EQ("", rewrite(/*FailureExpected=*/true));
1509 TEST_F(ApplyAtomicChangesTest, InsertsNewIncludesInRightOrder) {
1510 setInput("int a;");
1511 Changes.emplace_back(FilePath, "key1");
1512 Changes.back().addHeader("b");
1513 Changes.back().addHeader("c");
1514 Changes.emplace_back(FilePath, "key2");
1515 Changes.back().addHeader("a");
1516 EXPECT_EQ("#include \"a\"\n"
1517 "#include \"b\"\n"
1518 "#include \"c\"\n"
1519 "int a;",
1520 rewrite());
1523 TEST_F(ApplyAtomicChangesTest, RemoveAndSortIncludes) {
1524 setInput("#include \"a\"\n"
1525 "#include \"b\"\n"
1526 "#include \"c\"\n"
1527 "\n"
1528 "int a;");
1529 Changes.emplace_back(FilePath, "key1");
1530 Changes.back().removeHeader("b");
1531 EXPECT_EQ("#include \"a\"\n"
1532 "#include \"c\"\n"
1533 "\n"
1534 "int a;",
1535 rewrite());
1537 TEST_F(ApplyAtomicChangesTest, InsertsSystemIncludes) {
1538 setInput("#include <asys>\n"
1539 "#include <csys>\n"
1540 "\n"
1541 "#include \"a\"\n"
1542 "#include \"c\"\n");
1543 Changes.emplace_back(FilePath, "key1");
1544 Changes.back().addHeader("<asys>"); // Already exists.
1545 Changes.back().addHeader("<b>");
1546 Changes.back().addHeader("<d>");
1547 Changes.back().addHeader("\"b-already-escaped\"");
1548 EXPECT_EQ("#include <asys>\n"
1549 "#include <b>\n"
1550 "#include <csys>\n"
1551 "#include <d>\n"
1552 "\n"
1553 "#include \"a\"\n"
1554 "#include \"b-already-escaped\"\n"
1555 "#include \"c\"\n",
1556 rewrite());
1559 TEST_F(ApplyAtomicChangesTest, RemoveSystemIncludes) {
1560 setInput("#include <a>\n"
1561 "#include <b>\n"
1562 "\n"
1563 "#include \"c\""
1564 "\n"
1565 "int a;");
1566 Changes.emplace_back(FilePath, "key1");
1567 Changes.back().removeHeader("<a>");
1568 EXPECT_EQ("#include <b>\n"
1569 "\n"
1570 "#include \"c\""
1571 "\n"
1572 "int a;",
1573 rewrite());
1576 TEST_F(ApplyAtomicChangesTest,
1577 DoNotFormatFollowingLinesIfSeparatedWithNewline) {
1578 setInput("#ifndef __H__\n"
1579 "#define __H__\n"
1580 "#include \"b\"\n"
1581 "\n"
1582 "int a;\n"
1583 "int a;\n"
1584 "int a;\n"
1585 "#endif // __H__\n");
1586 Changes.push_back(replacementToAtomicChange("key1",
1587 llvm::StringRef("#ifndef __H__\n"
1588 "#define __H__\n"
1589 "\n"
1590 "#include \"b\"\n"
1591 "int a;\n"
1592 "int ")
1593 .size(),
1594 1, "b"));
1595 Changes.back().addHeader("a");
1596 EXPECT_EQ("#ifndef __H__\n"
1597 "#define __H__\n"
1598 "#include \"a\"\n"
1599 "#include \"b\"\n"
1600 "\n"
1601 "int a;\n"
1602 "int b;\n"
1603 "int a;\n"
1604 "#endif // __H__\n",
1605 rewrite());
1608 TEST_F(ApplyAtomicChangesTest, FormatsCorrectLineWhenHeaderIsRemoved) {
1609 setInput("#include \"a\"\n"
1610 "\n"
1611 "int a;\n"
1612 "int a;\n"
1613 "int a;");
1614 Changes.push_back(replacementToAtomicChange("key1", 27, 1, "b"));
1615 Changes.back().removeHeader("a");
1616 EXPECT_EQ("\n"
1617 "int a;\n"
1618 "int b;\n"
1619 "int a;",
1620 rewrite());
1623 TEST_F(ApplyAtomicChangesTest, CleansUpCtorInitializers) {
1624 setInput("A::A() : a(), b() {}\n"
1625 "A::A() : a(), b() {}\n"
1626 "A::A() : a(), b() {}\n"
1627 "A::A() : a()/**/, b() {}\n"
1628 "A::A() : a() ,// \n"
1629 " /**/ b() {}");
1630 Changes.emplace_back(FilePath, "key1");
1631 auto Err = Changes.back().replace(Context.Sources, getLoc(9), 3, "");
1632 ASSERT_TRUE(!Err);
1633 Err = Changes.back().replace(Context.Sources, getLoc(35), 3, "");
1634 ASSERT_TRUE(!Err);
1635 Err = Changes.back().replace(Context.Sources, getLoc(51), 3, "");
1636 ASSERT_TRUE(!Err);
1637 Err = Changes.back().replace(Context.Sources, getLoc(56), 3, "");
1638 ASSERT_TRUE(!Err);
1639 Err = Changes.back().replace(Context.Sources, getLoc(72), 3, "");
1640 ASSERT_TRUE(!Err);
1641 Err = Changes.back().replace(Context.Sources, getLoc(97), 3, "");
1642 ASSERT_TRUE(!Err);
1643 Err = Changes.back().replace(Context.Sources, getLoc(118), 3, "");
1644 ASSERT_TRUE(!Err);
1645 EXPECT_EQ("A::A() : b() {}\n"
1646 "A::A() : a() {}\n"
1647 "A::A() {}\n"
1648 "A::A() : b() {}\n"
1649 "A::A() {}",
1650 rewrite());
1653 TEST_F(ApplyAtomicChangesTest, CleansUpParameterLists) {
1654 setInput("void f(int i, float f, string s);\n"
1655 "f(1, 2.0f, \"a\");\n"
1656 "g(1, 1);");
1657 Changes.emplace_back(FilePath, "key1");
1658 auto Err = Changes.back().replace(Context.Sources, getLoc(7), 5, "");
1659 ASSERT_TRUE(!Err);
1660 Err = Changes.back().replace(Context.Sources, getLoc(23), 8, "");
1661 ASSERT_TRUE(!Err);
1662 Err = Changes.back().replace(Context.Sources, getLoc(36), 1, "");
1663 ASSERT_TRUE(!Err);
1664 Err = Changes.back().replace(Context.Sources, getLoc(45), 3, "");
1665 ASSERT_TRUE(!Err);
1666 Err = Changes.back().replace(Context.Sources, getLoc(53), 1, "");
1667 ASSERT_TRUE(!Err);
1668 Err = Changes.back().replace(Context.Sources, getLoc(56), 1, "");
1669 ASSERT_TRUE(!Err);
1670 EXPECT_EQ("void f(float f);\n"
1671 "f(2.0f);\n"
1672 "g();",
1673 rewrite());
1676 TEST_F(ApplyAtomicChangesTest, DisableCleanup) {
1677 Spec.Cleanup = false;
1678 setInput("void f(int i, float f, string s);\n"
1679 "f(1, 2.0f, \"a\");\n"
1680 "g(1, 1);");
1681 Changes.emplace_back(FilePath, "key1");
1682 auto Err = Changes.back().replace(Context.Sources, getLoc(7), 5, "");
1683 ASSERT_TRUE(!Err);
1684 Err = Changes.back().replace(Context.Sources, getLoc(23), 8, "");
1685 ASSERT_TRUE(!Err);
1686 Err = Changes.back().replace(Context.Sources, getLoc(36), 1, "");
1687 ASSERT_TRUE(!Err);
1688 Err = Changes.back().replace(Context.Sources, getLoc(45), 3, "");
1689 ASSERT_TRUE(!Err);
1690 Err = Changes.back().replace(Context.Sources, getLoc(53), 1, "");
1691 ASSERT_TRUE(!Err);
1692 Err = Changes.back().replace(Context.Sources, getLoc(56), 1, "");
1693 ASSERT_TRUE(!Err);
1694 EXPECT_EQ("void f(, float f, );\n"
1695 "f(, 2.0f, );\n"
1696 "g(, );",
1697 rewrite());
1700 TEST_F(ApplyAtomicChangesTest, EverythingDeleted) {
1701 setInput("int a;");
1702 Changes.push_back(replacementToAtomicChange("key1", 0, 6, ""));
1703 EXPECT_EQ("", rewrite());
1706 TEST_F(ApplyAtomicChangesTest, DoesNotDeleteInserts) {
1707 setInput("int a;\n"
1708 "int b;");
1709 Changes.emplace_back(FilePath, "key1");
1710 auto Err = Changes.back().replace(Context.Sources, getLoc(4), 1, "");
1711 ASSERT_TRUE(!Err);
1712 Err = Changes.back().replace(Context.Sources, getLoc(4), 0, "b");
1713 ASSERT_TRUE(!Err);
1714 Err = Changes.back().replace(Context.Sources, getLoc(11), 0, "a");
1715 ASSERT_TRUE(!Err);
1716 Err = Changes.back().replace(Context.Sources, getLoc(11), 1, "");
1717 ASSERT_TRUE(!Err);
1718 EXPECT_EQ("int b;\n"
1719 "int a;",
1720 rewrite());
1723 } // end namespace tooling
1724 } // end namespace clang