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