1 //===- unittest/Tooling/RefactoringTest.cpp - Refactoring unit tests ------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 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/Basic/VirtualFileSystem.h" 23 #include "clang/Format/Format.h" 24 #include "clang/Frontend/CompilerInstance.h" 25 #include "clang/Frontend/FrontendAction.h" 26 #include "clang/Frontend/TextDiagnosticPrinter.h" 27 #include "clang/Rewrite/Core/Rewriter.h" 28 #include "clang/Tooling/Refactoring.h" 29 #include "clang/Tooling/Tooling.h" 30 #include "llvm/ADT/SmallString.h" 31 #include "gtest/gtest.h" 32 33 namespace clang { 34 namespace tooling { 35 36 TEST_F(ReplacementTest, CanDeleteAllText) { 37 FileID ID = Context.createInMemoryFile("input.cpp", "text"); 38 SourceLocation Location = Context.getLocation(ID, 1, 1); 39 Replacement Replace(createReplacement(Location, 4, "")); 40 EXPECT_TRUE(Replace.apply(Context.Rewrite)); 41 EXPECT_EQ("", Context.getRewrittenText(ID)); 42 } 43 44 TEST_F(ReplacementTest, CanDeleteAllTextInTextWithNewlines) { 45 FileID ID = Context.createInMemoryFile("input.cpp", "line1\nline2\nline3"); 46 SourceLocation Location = Context.getLocation(ID, 1, 1); 47 Replacement Replace(createReplacement(Location, 17, "")); 48 EXPECT_TRUE(Replace.apply(Context.Rewrite)); 49 EXPECT_EQ("", Context.getRewrittenText(ID)); 50 } 51 52 TEST_F(ReplacementTest, CanAddText) { 53 FileID ID = Context.createInMemoryFile("input.cpp", ""); 54 SourceLocation Location = Context.getLocation(ID, 1, 1); 55 Replacement Replace(createReplacement(Location, 0, "result")); 56 EXPECT_TRUE(Replace.apply(Context.Rewrite)); 57 EXPECT_EQ("result", Context.getRewrittenText(ID)); 58 } 59 60 TEST_F(ReplacementTest, CanReplaceTextAtPosition) { 61 FileID ID = Context.createInMemoryFile("input.cpp", 62 "line1\nline2\nline3\nline4"); 63 SourceLocation Location = Context.getLocation(ID, 2, 3); 64 Replacement Replace(createReplacement(Location, 12, "x")); 65 EXPECT_TRUE(Replace.apply(Context.Rewrite)); 66 EXPECT_EQ("line1\nlixne4", Context.getRewrittenText(ID)); 67 } 68 69 TEST_F(ReplacementTest, CanReplaceTextAtPositionMultipleTimes) { 70 FileID ID = Context.createInMemoryFile("input.cpp", 71 "line1\nline2\nline3\nline4"); 72 SourceLocation Location1 = Context.getLocation(ID, 2, 3); 73 Replacement Replace1(createReplacement(Location1, 12, "x\ny\n")); 74 EXPECT_TRUE(Replace1.apply(Context.Rewrite)); 75 EXPECT_EQ("line1\nlix\ny\nne4", Context.getRewrittenText(ID)); 76 77 // Since the original source has not been modified, the (4, 4) points to the 78 // 'e' in the original content. 79 SourceLocation Location2 = Context.getLocation(ID, 4, 4); 80 Replacement Replace2(createReplacement(Location2, 1, "f")); 81 EXPECT_TRUE(Replace2.apply(Context.Rewrite)); 82 EXPECT_EQ("line1\nlix\ny\nnf4", Context.getRewrittenText(ID)); 83 } 84 85 TEST_F(ReplacementTest, ApplyFailsForNonExistentLocation) { 86 Replacement Replace("nonexistent-file.cpp", 0, 1, ""); 87 EXPECT_FALSE(Replace.apply(Context.Rewrite)); 88 } 89 90 TEST_F(ReplacementTest, CanRetrivePath) { 91 Replacement Replace("/path/to/file.cpp", 0, 1, ""); 92 EXPECT_EQ("/path/to/file.cpp", Replace.getFilePath()); 93 } 94 95 TEST_F(ReplacementTest, ReturnsInvalidPath) { 96 Replacement Replace1(Context.Sources, SourceLocation(), 0, ""); 97 EXPECT_TRUE(Replace1.getFilePath().empty()); 98 99 Replacement Replace2; 100 EXPECT_TRUE(Replace2.getFilePath().empty()); 101 } 102 103 // Checks that an llvm::Error instance contains a ReplacementError with expected 104 // error code, expected new replacement, and expected existing replacement. 105 static bool checkReplacementError( 106 llvm::Error&& Error, replacement_error ExpectedErr, 107 llvm::Optional<Replacement> ExpectedExisting, 108 llvm::Optional<Replacement> ExpectedNew) { 109 if (!Error) { 110 llvm::errs() << "Error is a success."; 111 return false; 112 } 113 std::string ErrorMessage; 114 llvm::raw_string_ostream OS(ErrorMessage); 115 llvm::handleAllErrors(std::move(Error), [&](const ReplacementError &RE) { 116 llvm::errs() << "Handling error...\n"; 117 if (ExpectedErr != RE.get()) 118 OS << "Unexpected error code: " << int(RE.get()) << "\n"; 119 if (ExpectedExisting != RE.getExistingReplacement()) { 120 OS << "Expected Existing != Actual Existing.\n"; 121 if (ExpectedExisting.hasValue()) 122 OS << "Expected existing replacement: " << ExpectedExisting->toString() 123 << "\n"; 124 if (RE.getExistingReplacement().hasValue()) 125 OS << "Actual existing replacement: " 126 << RE.getExistingReplacement()->toString() << "\n"; 127 } 128 if (ExpectedNew != RE.getNewReplacement()) { 129 OS << "Expected New != Actual New.\n"; 130 if (ExpectedNew.hasValue()) 131 OS << "Expected new replacement: " << ExpectedNew->toString() << "\n"; 132 if (RE.getNewReplacement().hasValue()) 133 OS << "Actual new replacement: " << RE.getNewReplacement()->toString() 134 << "\n"; 135 } 136 }); 137 OS.flush(); 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[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[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 const FileEntry *File = Context.Files.getFile(Path); 612 assert(File != nullptr); 613 614 StringRef Found = 615 TemporaryFiles.insert(std::make_pair(Name, Path.str())).first->second; 616 assert(Found == Path); 617 (void)Found; 618 return Context.Sources.createFileID(File, SourceLocation(), SrcMgr::C_User); 619 } 620 621 std::string getFileContentFromDisk(llvm::StringRef Name) { 622 std::string Path = TemporaryFiles.lookup(Name); 623 assert(!Path.empty()); 624 // We need to read directly from the FileManager without relaying through 625 // a FileEntry, as otherwise we'd read through an already opened file 626 // descriptor, which might not see the changes made. 627 // FIXME: Figure out whether there is a way to get the SourceManger to 628 // reopen the file. 629 auto FileBuffer = Context.Files.getBufferForFile(Path); 630 return (*FileBuffer)->getBuffer(); 631 } 632 633 llvm::StringMap<std::string> TemporaryFiles; 634 RewriterTestContext Context; 635 }; 636 637 TEST_F(FlushRewrittenFilesTest, StoresChangesOnDisk) { 638 FileID ID = createFile("input.cpp", "line1\nline2\nline3\nline4"); 639 Replacements Replaces = toReplacements({Replacement( 640 Context.Sources, Context.getLocation(ID, 2, 1), 5, "replaced")}); 641 EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite)); 642 EXPECT_FALSE(Context.Rewrite.overwriteChangedFiles()); 643 EXPECT_EQ("line1\nreplaced\nline3\nline4", 644 getFileContentFromDisk("input.cpp")); 645 } 646 647 namespace { 648 template <typename T> 649 class TestVisitor : public clang::RecursiveASTVisitor<T> { 650 public: 651 bool runOver(StringRef Code) { 652 return runToolOnCode(new TestAction(this), Code); 653 } 654 655 protected: 656 clang::SourceManager *SM; 657 clang::ASTContext *Context; 658 659 private: 660 class FindConsumer : public clang::ASTConsumer { 661 public: 662 FindConsumer(TestVisitor *Visitor) : Visitor(Visitor) {} 663 664 void HandleTranslationUnit(clang::ASTContext &Context) override { 665 Visitor->TraverseDecl(Context.getTranslationUnitDecl()); 666 } 667 668 private: 669 TestVisitor *Visitor; 670 }; 671 672 class TestAction : public clang::ASTFrontendAction { 673 public: 674 TestAction(TestVisitor *Visitor) : Visitor(Visitor) {} 675 676 std::unique_ptr<clang::ASTConsumer> 677 CreateASTConsumer(clang::CompilerInstance &compiler, 678 llvm::StringRef dummy) override { 679 Visitor->SM = &compiler.getSourceManager(); 680 Visitor->Context = &compiler.getASTContext(); 681 /// TestConsumer will be deleted by the framework calling us. 682 return llvm::make_unique<FindConsumer>(Visitor); 683 } 684 685 private: 686 TestVisitor *Visitor; 687 }; 688 }; 689 } // end namespace 690 691 void expectReplacementAt(const Replacement &Replace, 692 StringRef File, unsigned Offset, unsigned Length) { 693 ASSERT_TRUE(Replace.isApplicable()); 694 EXPECT_EQ(File, Replace.getFilePath()); 695 EXPECT_EQ(Offset, Replace.getOffset()); 696 EXPECT_EQ(Length, Replace.getLength()); 697 } 698 699 class ClassDeclXVisitor : public TestVisitor<ClassDeclXVisitor> { 700 public: 701 bool VisitCXXRecordDecl(CXXRecordDecl *Record) { 702 if (Record->getName() == "X") { 703 Replace = Replacement(*SM, Record, ""); 704 } 705 return true; 706 } 707 Replacement Replace; 708 }; 709 710 TEST(Replacement, CanBeConstructedFromNode) { 711 ClassDeclXVisitor ClassDeclX; 712 EXPECT_TRUE(ClassDeclX.runOver(" class X;")); 713 expectReplacementAt(ClassDeclX.Replace, "input.cc", 5, 7); 714 } 715 716 TEST(Replacement, ReplacesAtSpellingLocation) { 717 ClassDeclXVisitor ClassDeclX; 718 EXPECT_TRUE(ClassDeclX.runOver("#define A(Y) Y\nA(class X);")); 719 expectReplacementAt(ClassDeclX.Replace, "input.cc", 17, 7); 720 } 721 722 class CallToFVisitor : public TestVisitor<CallToFVisitor> { 723 public: 724 bool VisitCallExpr(CallExpr *Call) { 725 if (Call->getDirectCallee()->getName() == "F") { 726 Replace = Replacement(*SM, Call, ""); 727 } 728 return true; 729 } 730 Replacement Replace; 731 }; 732 733 TEST(Replacement, FunctionCall) { 734 CallToFVisitor CallToF; 735 EXPECT_TRUE(CallToF.runOver("void F(); void G() { F(); }")); 736 expectReplacementAt(CallToF.Replace, "input.cc", 21, 3); 737 } 738 739 TEST(Replacement, TemplatedFunctionCall) { 740 CallToFVisitor CallToF; 741 EXPECT_TRUE(CallToF.runOver( 742 "template <typename T> void F(); void G() { F<int>(); }")); 743 expectReplacementAt(CallToF.Replace, "input.cc", 43, 8); 744 } 745 746 class NestedNameSpecifierAVisitor 747 : public TestVisitor<NestedNameSpecifierAVisitor> { 748 public: 749 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNSLoc) { 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<NestedNameSpecifierAVisitor>::TraverseNestedNameSpecifierLoc( 758 NNSLoc); 759 } 760 Replacement Replace; 761 }; 762 763 TEST(Replacement, ColonColon) { 764 NestedNameSpecifierAVisitor VisitNNSA; 765 EXPECT_TRUE(VisitNNSA.runOver("namespace a { void f() { ::a::f(); } }")); 766 expectReplacementAt(VisitNNSA.Replace, "input.cc", 25, 5); 767 } 768 769 TEST(Range, overlaps) { 770 EXPECT_TRUE(Range(10, 10).overlapsWith(Range(0, 11))); 771 EXPECT_TRUE(Range(0, 11).overlapsWith(Range(10, 10))); 772 EXPECT_FALSE(Range(10, 10).overlapsWith(Range(0, 10))); 773 EXPECT_FALSE(Range(0, 10).overlapsWith(Range(10, 10))); 774 EXPECT_TRUE(Range(0, 10).overlapsWith(Range(2, 6))); 775 EXPECT_TRUE(Range(2, 6).overlapsWith(Range(0, 10))); 776 } 777 778 TEST(Range, contains) { 779 EXPECT_TRUE(Range(0, 10).contains(Range(0, 10))); 780 EXPECT_TRUE(Range(0, 10).contains(Range(2, 6))); 781 EXPECT_FALSE(Range(2, 6).contains(Range(0, 10))); 782 EXPECT_FALSE(Range(0, 10).contains(Range(0, 11))); 783 } 784 785 TEST(Range, CalculateRangesOfReplacements) { 786 // Before: aaaabbbbbbz 787 // After : bbbbbbzzzzzzoooooooooooooooo 788 Replacements Replaces = toReplacements( 789 {Replacement("foo", 0, 4, ""), Replacement("foo", 10, 1, "zzzzzz"), 790 Replacement("foo", 11, 0, "oooooooooooooooo")}); 791 792 std::vector<Range> Ranges = Replaces.getAffectedRanges(); 793 794 EXPECT_EQ(2ul, Ranges.size()); 795 EXPECT_TRUE(Ranges[0].getOffset() == 0); 796 EXPECT_TRUE(Ranges[0].getLength() == 0); 797 EXPECT_TRUE(Ranges[1].getOffset() == 6); 798 EXPECT_TRUE(Ranges[1].getLength() == 22); 799 } 800 801 TEST(Range, CalculateRangesOfInsertionAroundReplacement) { 802 Replacements Replaces = toReplacements( 803 {Replacement("foo", 0, 2, ""), Replacement("foo", 0, 0, "ba")}); 804 805 std::vector<Range> Ranges = Replaces.getAffectedRanges(); 806 807 EXPECT_EQ(1ul, Ranges.size()); 808 EXPECT_EQ(0u, Ranges[0].getOffset()); 809 EXPECT_EQ(2u, Ranges[0].getLength()); 810 } 811 812 TEST(Range, RangesAfterEmptyReplacements) { 813 std::vector<Range> Ranges = {Range(5, 6), Range(10, 5)}; 814 Replacements Replaces; 815 std::vector<Range> Expected = {Range(5, 10)}; 816 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges)); 817 } 818 819 TEST(Range, RangesAfterReplacements) { 820 std::vector<Range> Ranges = {Range(5, 2), Range(10, 5)}; 821 Replacements Replaces = toReplacements({Replacement("foo", 0, 2, "1234")}); 822 std::vector<Range> Expected = {Range(0, 4), Range(7, 2), Range(12, 5)}; 823 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges)); 824 } 825 826 TEST(Range, RangesBeforeReplacements) { 827 std::vector<Range> Ranges = {Range(5, 2), Range(10, 5)}; 828 Replacements Replaces = toReplacements({Replacement("foo", 20, 2, "1234")}); 829 std::vector<Range> Expected = {Range(5, 2), Range(10, 5), Range(20, 4)}; 830 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges)); 831 } 832 833 TEST(Range, NotAffectedByReplacements) { 834 std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(10, 5)}; 835 Replacements Replaces = toReplacements({Replacement("foo", 3, 2, "12"), 836 Replacement("foo", 12, 2, "12"), 837 Replacement("foo", 20, 5, "")}); 838 std::vector<Range> Expected = {Range(0, 2), Range(3, 4), Range(10, 5), 839 Range(20, 0)}; 840 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges)); 841 } 842 843 TEST(Range, RangesWithNonOverlappingReplacements) { 844 std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(10, 5)}; 845 Replacements Replaces = toReplacements({Replacement("foo", 3, 1, ""), 846 Replacement("foo", 6, 1, "123"), 847 Replacement("foo", 20, 2, "12345")}); 848 std::vector<Range> Expected = {Range(0, 2), Range(3, 0), Range(4, 4), 849 Range(11, 5), Range(21, 5)}; 850 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges)); 851 } 852 853 TEST(Range, RangesWithOverlappingReplacements) { 854 std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(15, 5), 855 Range(30, 5)}; 856 Replacements Replaces = toReplacements( 857 {Replacement("foo", 1, 3, ""), Replacement("foo", 6, 1, "123"), 858 Replacement("foo", 13, 3, "1"), Replacement("foo", 25, 15, "")}); 859 std::vector<Range> Expected = {Range(0, 1), Range(2, 4), Range(12, 5), 860 Range(22, 0)}; 861 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges)); 862 } 863 864 TEST(Range, MergeIntoOneRange) { 865 std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(15, 5)}; 866 Replacements Replaces = 867 toReplacements({Replacement("foo", 1, 15, "1234567890")}); 868 std::vector<Range> Expected = {Range(0, 15)}; 869 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges)); 870 } 871 872 TEST(Range, ReplacementsStartingAtRangeOffsets) { 873 std::vector<Range> Ranges = {Range(0, 2), Range(5, 5), Range(15, 5)}; 874 Replacements Replaces = toReplacements( 875 {Replacement("foo", 0, 2, "12"), Replacement("foo", 5, 1, "123"), 876 Replacement("foo", 7, 4, "12345"), Replacement("foo", 15, 10, "12")}); 877 std::vector<Range> Expected = {Range(0, 2), Range(5, 9), Range(18, 2)}; 878 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges)); 879 } 880 881 TEST(Range, ReplacementsEndingAtRangeEnds) { 882 std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(15, 5)}; 883 Replacements Replaces = toReplacements( 884 {Replacement("foo", 6, 1, "123"), Replacement("foo", 17, 3, "12")}); 885 std::vector<Range> Expected = {Range(0, 2), Range(5, 4), Range(17, 4)}; 886 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges)); 887 } 888 889 TEST(Range, AjacentReplacements) { 890 std::vector<Range> Ranges = {Range(0, 0), Range(15, 5)}; 891 Replacements Replaces = toReplacements( 892 {Replacement("foo", 1, 2, "123"), Replacement("foo", 12, 3, "1234")}); 893 std::vector<Range> Expected = {Range(0, 0), Range(1, 3), Range(13, 9)}; 894 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges)); 895 } 896 897 TEST(Range, MergeRangesAfterReplacements) { 898 std::vector<Range> Ranges = {Range(8, 0), Range(5, 2), Range(9, 0), Range(0, 1)}; 899 Replacements Replaces = toReplacements({Replacement("foo", 1, 3, ""), 900 Replacement("foo", 7, 0, "12"), 901 Replacement("foo", 9, 2, "")}); 902 std::vector<Range> Expected = {Range(0, 1), Range(2, 4), Range(7, 0), 903 Range(8, 0)}; 904 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges)); 905 } 906 907 TEST(Range, ConflictingRangesBeforeReplacements) { 908 std::vector<Range> Ranges = {Range(8, 3), Range(5, 4), Range(9, 1)}; 909 Replacements Replaces = toReplacements({Replacement("foo", 1, 3, "")}); 910 std::vector<Range> Expected = {Range(1, 0), Range(2, 6)}; 911 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges)); 912 } 913 914 class MergeReplacementsTest : public ::testing::Test { 915 protected: 916 void mergeAndTestRewrite(StringRef Code, StringRef Intermediate, 917 StringRef Result, const Replacements &First, 918 const Replacements &Second) { 919 // These are mainly to verify the test itself and make it easier to read. 920 auto AfterFirst = applyAllReplacements(Code, First); 921 EXPECT_TRUE(static_cast<bool>(AfterFirst)); 922 auto InSequenceRewrite = applyAllReplacements(*AfterFirst, Second); 923 EXPECT_TRUE(static_cast<bool>(InSequenceRewrite)); 924 EXPECT_EQ(Intermediate, *AfterFirst); 925 EXPECT_EQ(Result, *InSequenceRewrite); 926 927 tooling::Replacements Merged = First.merge(Second); 928 auto MergedRewrite = applyAllReplacements(Code, Merged); 929 EXPECT_TRUE(static_cast<bool>(MergedRewrite)); 930 EXPECT_EQ(*InSequenceRewrite, *MergedRewrite); 931 if (*InSequenceRewrite != *MergedRewrite) 932 for (tooling::Replacement M : Merged) 933 llvm::errs() << M.getOffset() << " " << M.getLength() << " " 934 << M.getReplacementText() << "\n"; 935 } 936 void mergeAndTestRewrite(StringRef Code, const Replacements &First, 937 const Replacements &Second) { 938 auto AfterFirst = applyAllReplacements(Code, First); 939 EXPECT_TRUE(static_cast<bool>(AfterFirst)); 940 auto InSequenceRewrite = applyAllReplacements(*AfterFirst, Second); 941 tooling::Replacements Merged = First.merge(Second); 942 auto MergedRewrite = applyAllReplacements(Code, Merged); 943 EXPECT_TRUE(static_cast<bool>(MergedRewrite)); 944 EXPECT_EQ(*InSequenceRewrite, *MergedRewrite); 945 if (*InSequenceRewrite != *MergedRewrite) 946 for (tooling::Replacement M : Merged) 947 llvm::errs() << M.getOffset() << " " << M.getLength() << " " 948 << M.getReplacementText() << "\n"; 949 } 950 }; 951 952 TEST_F(MergeReplacementsTest, Offsets) { 953 mergeAndTestRewrite("aaa", "aabab", "cacabab", 954 toReplacements({{"", 2, 0, "b"}, {"", 3, 0, "b"}}), 955 toReplacements({{"", 0, 0, "c"}, {"", 1, 0, "c"}})); 956 mergeAndTestRewrite("aaa", "babaa", "babacac", 957 toReplacements({{"", 0, 0, "b"}, {"", 1, 0, "b"}}), 958 toReplacements({{"", 4, 0, "c"}, {"", 5, 0, "c"}})); 959 mergeAndTestRewrite("aaaa", "aaa", "aac", toReplacements({{"", 1, 1, ""}}), 960 toReplacements({{"", 2, 1, "c"}})); 961 962 mergeAndTestRewrite("aa", "bbabba", "bbabcba", 963 toReplacements({{"", 0, 0, "bb"}, {"", 1, 0, "bb"}}), 964 toReplacements({{"", 4, 0, "c"}})); 965 } 966 967 TEST_F(MergeReplacementsTest, Concatenations) { 968 // Basic concatenations. It is important to merge these into a single 969 // replacement to ensure the correct order. 970 { 971 auto First = toReplacements({{"", 0, 0, "a"}}); 972 auto Second = toReplacements({{"", 1, 0, "b"}}); 973 EXPECT_EQ(toReplacements({{"", 0, 0, "ab"}}), First.merge(Second)); 974 } 975 { 976 auto First = toReplacements({{"", 0, 0, "a"}}); 977 auto Second = toReplacements({{"", 0, 0, "b"}}); 978 EXPECT_EQ(toReplacements({{"", 0, 0, "ba"}}), First.merge(Second)); 979 } 980 mergeAndTestRewrite("", "a", "ab", toReplacements({{"", 0, 0, "a"}}), 981 toReplacements({{"", 1, 0, "b"}})); 982 mergeAndTestRewrite("", "a", "ba", toReplacements({{"", 0, 0, "a"}}), 983 toReplacements({{"", 0, 0, "b"}})); 984 } 985 986 TEST_F(MergeReplacementsTest, NotChangingLengths) { 987 mergeAndTestRewrite("aaaa", "abba", "acca", 988 toReplacements({{"", 1, 2, "bb"}}), 989 toReplacements({{"", 1, 2, "cc"}})); 990 mergeAndTestRewrite("aaaa", "abba", "abcc", 991 toReplacements({{"", 1, 2, "bb"}}), 992 toReplacements({{"", 2, 2, "cc"}})); 993 mergeAndTestRewrite("aaaa", "abba", "ccba", 994 toReplacements({{"", 1, 2, "bb"}}), 995 toReplacements({{"", 0, 2, "cc"}})); 996 mergeAndTestRewrite("aaaaaa", "abbdda", "abccda", 997 toReplacements({{"", 1, 2, "bb"}, {"", 3, 2, "dd"}}), 998 toReplacements({{"", 2, 2, "cc"}})); 999 } 1000 1001 TEST_F(MergeReplacementsTest, OverlappingRanges) { 1002 mergeAndTestRewrite("aaa", "bbd", "bcbcd", 1003 toReplacements({{"", 0, 1, "bb"}, {"", 1, 2, "d"}}), 1004 toReplacements({{"", 1, 0, "c"}, {"", 2, 0, "c"}})); 1005 1006 mergeAndTestRewrite("aaaa", "aabbaa", "acccca", 1007 toReplacements({{"", 2, 0, "bb"}}), 1008 toReplacements({{"", 1, 4, "cccc"}})); 1009 mergeAndTestRewrite("aaaa", "aababa", "acccca", 1010 toReplacements({{"", 2, 0, "b"}, {"", 3, 0, "b"}}), 1011 toReplacements({{"", 1, 4, "cccc"}})); 1012 mergeAndTestRewrite("aaaaaa", "abbbba", "abba", 1013 toReplacements({{"", 1, 4, "bbbb"}}), 1014 toReplacements({{"", 2, 2, ""}})); 1015 mergeAndTestRewrite("aaaa", "aa", "cc", 1016 toReplacements({{"", 1, 1, ""}, {"", 2, 1, ""}}), 1017 toReplacements({{"", 0, 2, "cc"}})); 1018 mergeAndTestRewrite("aa", "abbba", "abcbcba", 1019 toReplacements({{"", 1, 0, "bbb"}}), 1020 toReplacements({{"", 2, 0, "c"}, {"", 3, 0, "c"}})); 1021 1022 mergeAndTestRewrite( 1023 "aaa", "abbab", "ccdd", 1024 toReplacements({{"", 0, 1, ""}, {"", 2, 0, "bb"}, {"", 3, 0, "b"}}), 1025 toReplacements({{"", 0, 2, "cc"}, {"", 2, 3, "dd"}})); 1026 mergeAndTestRewrite( 1027 "aa", "babbab", "ccdd", 1028 toReplacements({{"", 0, 0, "b"}, {"", 1, 0, "bb"}, {"", 2, 0, "b"}}), 1029 toReplacements({{"", 0, 3, "cc"}, {"", 3, 3, "dd"}})); 1030 } 1031 1032 TEST(DeduplicateByFileTest, PathsWithDots) { 1033 std::map<std::string, Replacements> FileToReplaces; 1034 llvm::IntrusiveRefCntPtr<vfs::InMemoryFileSystem> VFS( 1035 new vfs::InMemoryFileSystem()); 1036 FileManager FileMgr(FileSystemOptions(), VFS); 1037 #if !defined(LLVM_ON_WIN32) 1038 StringRef Path1 = "a/b/.././c.h"; 1039 StringRef Path2 = "a/c.h"; 1040 #else 1041 StringRef Path1 = "a\\b\\..\\.\\c.h"; 1042 StringRef Path2 = "a\\c.h"; 1043 #endif 1044 EXPECT_TRUE(VFS->addFile(Path1, 0, llvm::MemoryBuffer::getMemBuffer(""))); 1045 EXPECT_TRUE(VFS->addFile(Path2, 0, llvm::MemoryBuffer::getMemBuffer(""))); 1046 FileToReplaces[Path1] = Replacements(); 1047 FileToReplaces[Path2] = Replacements(); 1048 FileToReplaces = groupReplacementsByFile(FileMgr, FileToReplaces); 1049 EXPECT_EQ(1u, FileToReplaces.size()); 1050 EXPECT_EQ(Path1, FileToReplaces.begin()->first); 1051 } 1052 1053 TEST(DeduplicateByFileTest, PathWithDotSlash) { 1054 std::map<std::string, Replacements> FileToReplaces; 1055 llvm::IntrusiveRefCntPtr<vfs::InMemoryFileSystem> VFS( 1056 new vfs::InMemoryFileSystem()); 1057 FileManager FileMgr(FileSystemOptions(), VFS); 1058 #if !defined(LLVM_ON_WIN32) 1059 StringRef Path1 = "./a/b/c.h"; 1060 StringRef Path2 = "a/b/c.h"; 1061 #else 1062 StringRef Path1 = ".\\a\\b\\c.h"; 1063 StringRef Path2 = "a\\b\\c.h"; 1064 #endif 1065 EXPECT_TRUE(VFS->addFile(Path1, 0, llvm::MemoryBuffer::getMemBuffer(""))); 1066 EXPECT_TRUE(VFS->addFile(Path2, 0, llvm::MemoryBuffer::getMemBuffer(""))); 1067 FileToReplaces[Path1] = Replacements(); 1068 FileToReplaces[Path2] = Replacements(); 1069 FileToReplaces = groupReplacementsByFile(FileMgr, FileToReplaces); 1070 EXPECT_EQ(1u, FileToReplaces.size()); 1071 EXPECT_EQ(Path1, FileToReplaces.begin()->first); 1072 } 1073 1074 TEST(DeduplicateByFileTest, NonExistingFilePath) { 1075 std::map<std::string, Replacements> FileToReplaces; 1076 llvm::IntrusiveRefCntPtr<vfs::InMemoryFileSystem> VFS( 1077 new vfs::InMemoryFileSystem()); 1078 FileManager FileMgr(FileSystemOptions(), VFS); 1079 #if !defined(LLVM_ON_WIN32) 1080 StringRef Path1 = "./a/b/c.h"; 1081 StringRef Path2 = "a/b/c.h"; 1082 #else 1083 StringRef Path1 = ".\\a\\b\\c.h"; 1084 StringRef Path2 = "a\\b\\c.h"; 1085 #endif 1086 FileToReplaces[Path1] = Replacements(); 1087 FileToReplaces[Path2] = Replacements(); 1088 FileToReplaces = groupReplacementsByFile(FileMgr, FileToReplaces); 1089 EXPECT_TRUE(FileToReplaces.empty()); 1090 } 1091 1092 } // end namespace tooling 1093 } // end namespace clang 1094