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/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> 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 llvm::Optional<Replacement> ExpectedExisting, 109 llvm::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 OS.flush(); 139 if (ErrorMessage.empty()) return true; 140 llvm::errs() << ErrorMessage; 141 return false; 142 } 143 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)); 150 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)); 156 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)); 162 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)); 168 169 EXPECT_EQ(1u, Replaces.size()); 170 EXPECT_EQ(Deletion, *Replaces.begin()); 171 } 172 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()); 187 } 188 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)); 197 198 EXPECT_EQ(1u, Replaces.size()); 199 EXPECT_EQ(Replacement("x.cc", 0, 5, "34543"), *Replaces.begin()); 200 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()); 206 } 207 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); 218 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); 228 } 229 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)); 236 237 Err = Replaces.add(Replacement("x.cc", 5, 3, "")); 238 EXPECT_TRUE(!Err); 239 llvm::consumeError(std::move(Err)); 240 241 Err = Replaces.add(Replacement("x.cc", 0, 10, "")); 242 EXPECT_TRUE(!Err); 243 llvm::consumeError(std::move(Err)); 244 245 Err = Replaces.add(Replacement("x.cc", 5, 5, "")); 246 EXPECT_TRUE(!Err); 247 llvm::consumeError(std::move(Err)); 248 249 EXPECT_EQ(1u, Replaces.size()); 250 EXPECT_EQ(*Replaces.begin(), ContainingReplacement); 251 } 252 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)); 258 259 Err = Replaces.add(Replacement("x.cc", 5, 5, "")); 260 EXPECT_TRUE(!Err); 261 llvm::consumeError(std::move(Err)); 262 263 Replacement After = Replacement("x.cc", 10, 5, ""); 264 Err = Replaces.add(After); 265 EXPECT_TRUE(!Err); 266 llvm::consumeError(std::move(Err)); 267 268 Replacement ContainingReplacement("x.cc", 0, 10, ""); 269 Err = Replaces.add(ContainingReplacement); 270 EXPECT_TRUE(!Err); 271 llvm::consumeError(std::move(Err)); 272 273 EXPECT_EQ(2u, Replaces.size()); 274 EXPECT_EQ(*Replaces.begin(), ContainingReplacement); 275 EXPECT_EQ(*(++Replaces.begin()), After); 276 } 277 278 TEST_F(ReplacementTest, InsertionBeforeMergedDeletions) { 279 Replacements Replaces; 280 281 Replacement Insertion("x.cc", 0, 0, "123"); 282 auto Err = Replaces.add(Insertion); 283 EXPECT_TRUE(!Err); 284 llvm::consumeError(std::move(Err)); 285 286 Err = Replaces.add(Replacement("x.cc", 5, 5, "")); 287 EXPECT_TRUE(!Err); 288 llvm::consumeError(std::move(Err)); 289 290 Replacement Deletion("x.cc", 0, 10, ""); 291 Err = Replaces.add(Deletion); 292 EXPECT_TRUE(!Err); 293 llvm::consumeError(std::move(Err)); 294 295 EXPECT_EQ(2u, Replaces.size()); 296 EXPECT_EQ(*Replaces.begin(), Insertion); 297 EXPECT_EQ(*(++Replaces.begin()), Deletion); 298 } 299 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)); 305 306 Err = Replaces.add(Replacement("x.cc", 0, 5, "")); 307 EXPECT_TRUE(!Err); 308 llvm::consumeError(std::move(Err)); 309 310 EXPECT_EQ(1u, Replaces.size()); 311 EXPECT_EQ(Replacement("x.cc", 0, 5, ""), *Replaces.begin()); 312 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()); 318 } 319 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)); 326 327 Replacement Second("x.cc", 5, 5, ""); 328 Err = Replaces.add(Second); 329 EXPECT_TRUE(!Err); 330 llvm::consumeError(std::move(Err)); 331 332 Err = Replaces.add(Replacement("x.cc", 1, 10, "")); 333 EXPECT_TRUE(!Err); 334 llvm::consumeError(std::move(Err)); 335 336 EXPECT_EQ(1u, Replaces.size()); 337 EXPECT_EQ(Replacement("x.cc", 0, 11, ""), *Replaces.begin()); 338 } 339 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)); 350 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)); 358 359 Err = Replaces.add(Replacement("x.cc", 10, 0, "")); 360 EXPECT_TRUE(!Err); 361 llvm::consumeError(std::move(Err)); 362 } 363 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); 373 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); 382 } 383 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)); 394 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()); 404 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())); 418 } 419 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)); 431 } 432 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)); 443 } 444 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)); 456 } 457 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)); 466 } 467 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")}); 473 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)); 478 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)); 483 484 EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite)); 485 EXPECT_EQ("line1\nreplaced\nline3\nline4", Context.getRewrittenText(ID)); 486 } 487 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")}); 493 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)); 500 501 EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite)); 502 EXPECT_EQ("line1\nother\nline3\nline4", Context.getRewrittenText(ID)); 503 } 504 505 TEST_F(ReplacementTest, InvalidSourceLocationFailsApplyAll) { 506 Replacements Replaces = 507 toReplacements({Replacement(Context.Sources, SourceLocation(), 5, "2")}); 508 509 EXPECT_FALSE(applyAllReplacements(Replaces, Context.Rewrite)); 510 } 511 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); 529 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)); 547 } 548 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| 562 } 563 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" 570 } 571 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)); 577 } 578 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)); 585 } 586 587 class FlushRewrittenFilesTest : public ::testing::Test { 588 public: 589 FlushRewrittenFilesTest() {} 590 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); 599 } 600 } 601 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; 608 609 llvm::raw_fd_ostream OutStream(FD, true); 610 OutStream << Content; 611 OutStream.close(); 612 auto File = Context.Files.getOptionalFileRef(Path); 613 assert(File); 614 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); 622 } 623 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()); 634 } 635 636 llvm::StringMap<std::string> TemporaryFiles; 637 RewriterTestContext Context; 638 }; 639 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")); 648 } 649 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); 656 } 657 658 protected: 659 clang::SourceManager *SM; 660 clang::ASTContext *Context; 661 662 private: 663 class FindConsumer : public clang::ASTConsumer { 664 public: 665 FindConsumer(TestVisitor *Visitor) : Visitor(Visitor) {} 666 667 void HandleTranslationUnit(clang::ASTContext &Context) override { 668 Visitor->TraverseDecl(Context.getTranslationUnitDecl()); 669 } 670 671 private: 672 TestVisitor *Visitor; 673 }; 674 675 class TestAction : public clang::ASTFrontendAction { 676 public: 677 TestAction(TestVisitor *Visitor) : Visitor(Visitor) {} 678 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); 686 } 687 688 private: 689 TestVisitor *Visitor; 690 }; 691 }; 692 } // end namespace 693 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()); 700 } 701 702 class ClassDeclXVisitor : public TestVisitor<ClassDeclXVisitor> { 703 public: 704 bool VisitCXXRecordDecl(CXXRecordDecl *Record) { 705 if (Record->getName() == "X") { 706 Replace = Replacement(*SM, Record, ""); 707 } 708 return true; 709 } 710 Replacement Replace; 711 }; 712 713 TEST(Replacement, CanBeConstructedFromNode) { 714 ClassDeclXVisitor ClassDeclX; 715 EXPECT_TRUE(ClassDeclX.runOver(" class X;")); 716 expectReplacementAt(ClassDeclX.Replace, "input.cc", 5, 7); 717 } 718 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); 723 } 724 725 class CallToFVisitor : public TestVisitor<CallToFVisitor> { 726 public: 727 bool VisitCallExpr(CallExpr *Call) { 728 if (Call->getDirectCallee()->getName() == "F") { 729 Replace = Replacement(*SM, Call, ""); 730 } 731 return true; 732 } 733 Replacement Replace; 734 }; 735 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); 740 } 741 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); 747 } 748 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()); 757 } 758 } 759 } 760 return TestVisitor<NestedNameSpecifierAVisitor>::TraverseNestedNameSpecifierLoc( 761 NNSLoc); 762 } 763 Replacement Replace; 764 }; 765 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); 770 } 771 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))); 779 } 780 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))); 786 } 787 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")}); 794 795 std::vector<Range> Ranges = Replaces.getAffectedRanges(); 796 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); 802 } 803 804 TEST(Range, CalculateRangesOfInsertionAroundReplacement) { 805 Replacements Replaces = toReplacements( 806 {Replacement("foo", 0, 2, ""), Replacement("foo", 0, 0, "ba")}); 807 808 std::vector<Range> Ranges = Replaces.getAffectedRanges(); 809 810 EXPECT_EQ(1ul, Ranges.size()); 811 EXPECT_EQ(0u, Ranges[0].getOffset()); 812 EXPECT_EQ(2u, Ranges[0].getLength()); 813 } 814 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)); 820 } 821 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)); 827 } 828 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)); 834 } 835 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)); 844 } 845 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)); 854 } 855 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)); 865 } 866 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)); 873 } 874 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)); 882 } 883 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)); 890 } 891 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)); 898 } 899 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)); 908 } 909 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)); 915 } 916 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); 929 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"; 938 } 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"; 952 } 953 }; 954 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"}})); 964 965 mergeAndTestRewrite("aa", "bbabba", "bbabcba", 966 toReplacements({{"", 0, 0, "bb"}, {"", 1, 0, "bb"}}), 967 toReplacements({{"", 4, 0, "c"}})); 968 } 969 970 TEST_F(MergeReplacementsTest, Concatenations) { 971 // Basic concatenations. It is important to merge these into a single 972 // replacement to ensure the correct order. 973 { 974 auto First = toReplacements({{"", 0, 0, "a"}}); 975 auto Second = toReplacements({{"", 1, 0, "b"}}); 976 EXPECT_EQ(toReplacements({{"", 0, 0, "ab"}}), First.merge(Second)); 977 } 978 { 979 auto First = toReplacements({{"", 0, 0, "a"}}); 980 auto Second = toReplacements({{"", 0, 0, "b"}}); 981 EXPECT_EQ(toReplacements({{"", 0, 0, "ba"}}), First.merge(Second)); 982 } 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"}})); 987 } 988 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"}})); 1002 } 1003 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"}})); 1008 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"}})); 1024 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"}})); 1033 } 1034 1035 static constexpr bool usesWindowsPaths() { 1036 return is_style_windows(llvm::sys::path::Style::native); 1037 } 1038 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); 1053 } 1054 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); 1069 } 1070 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()); 1082 } 1083 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."); 1091 } 1092 1093 RewriterTestContext Context; 1094 std::string DefaultCode = std::string(100, 'a'); 1095 unsigned DefaultOffset = 20; 1096 SourceLocation DefaultLoc; 1097 FileID DefaultFileID; 1098 }; 1099 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(); 1111 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()); 1132 } 1133 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); 1160 1161 ExpectedChange.addHeader("a.h"); 1162 ExpectedChange.removeHeader("b.h"); 1163 ExpectedChange.setError("ok"); 1164 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())); 1180 } 1181 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()); 1186 } 1187 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")); 1195 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); 1201 } 1202 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")); 1212 } 1213 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")); 1226 } 1227 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")); 1240 } 1241 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); 1247 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"))); 1256 } 1257 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); 1263 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"))); 1273 } 1274 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); 1279 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"))); 1287 } 1288 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); 1294 } 1295 1296 TEST_F(AtomicChangeTest, NoMetadata) { 1297 AtomicChange Change(Context.Sources, DefaultLoc); 1298 EXPECT_FALSE(Change.getMetadata().has_value()); 1299 } 1300 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(); 1307 } 1308 1309 ~ApplyAtomicChangesTest() override {} 1310 1311 void setInput(llvm::StringRef Input) { 1312 Code = std::string(Input); 1313 FID = Context.createInMemoryFile(FilePath, Code); 1314 } 1315 1316 SourceLocation getLoc(unsigned Offset) const { 1317 return Context.Sources.getLocForStartOfFile(FID).getLocWithOffset(Offset); 1318 } 1319 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; 1328 } 1329 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 ""; 1338 } 1339 return *ChangedCode; 1340 } 1341 1342 RewriterTestContext Context; 1343 FileID FID; 1344 ApplyChangesSpec Spec; 1345 std::string Code; 1346 std::string FilePath; 1347 llvm::SmallVector<AtomicChange, 8> Changes; 1348 }; 1349 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()); 1355 } 1356 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()); 1367 } 1368 1369 TEST_F(ApplyAtomicChangesTest, IgnorePathsInRefactorings) { 1370 setInput("int a;\n" 1371 "int b;"); 1372 Changes.push_back(replacementToAtomicChange("key1", 4, 1, "aa")); 1373 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()); 1383 } 1384 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()); 1390 } 1391 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)); 1397 } 1398 1399 TEST_F(ApplyAtomicChangesTest, BasicReformatting) { 1400 setInput("int a;"); 1401 Changes.push_back(replacementToAtomicChange("key1", 5, 1, "b")); 1402 EXPECT_EQ("int b;", rewrite()); 1403 } 1404 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()); 1418 } 1419 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()); 1430 } 1431 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()); 1442 } 1443 1444 TEST_F(ApplyAtomicChangesTest, Longer) { 1445 setInput("int a;"); 1446 Changes.push_back(replacementToAtomicChange("key1", 5, 1, "bbb")); 1447 EXPECT_EQ("int bbb;", rewrite()); 1448 } 1449 1450 TEST_F(ApplyAtomicChangesTest, Shorter) { 1451 setInput("int aaa;"); 1452 Changes.push_back(replacementToAtomicChange("key1", 5, 3, "b")); 1453 EXPECT_EQ("int b;", rewrite()); 1454 } 1455 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()); 1465 } 1466 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()); 1477 } 1478 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()); 1487 } 1488 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()); 1498 } 1499 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)); 1507 } 1508 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()); 1521 } 1522 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()); 1536 } 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()); 1557 } 1558 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()); 1574 } 1575 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()); 1606 } 1607 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()); 1621 } 1622 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()); 1651 } 1652 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()); 1674 } 1675 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()); 1698 } 1699 1700 TEST_F(ApplyAtomicChangesTest, EverythingDeleted) { 1701 setInput("int a;"); 1702 Changes.push_back(replacementToAtomicChange("key1", 0, 6, "")); 1703 EXPECT_EQ("", rewrite()); 1704 } 1705 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()); 1721 } 1722 1723 } // end namespace tooling 1724 } // end namespace clang 1725