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/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.h" 28 #include "clang/Tooling/Tooling.h" 29 #include "llvm/ADT/SmallString.h" 30 #include "gtest/gtest.h" 31 32 namespace clang { 33 namespace tooling { 34 35 TEST_F(ReplacementTest, CanDeleteAllText) { 36 FileID ID = Context.createInMemoryFile("input.cpp", "text"); 37 SourceLocation Location = Context.getLocation(ID, 1, 1); 38 Replacement Replace(createReplacement(Location, 4, "")); 39 EXPECT_TRUE(Replace.apply(Context.Rewrite)); 40 EXPECT_EQ("", Context.getRewrittenText(ID)); 41 } 42 43 TEST_F(ReplacementTest, CanDeleteAllTextInTextWithNewlines) { 44 FileID ID = Context.createInMemoryFile("input.cpp", "line1\nline2\nline3"); 45 SourceLocation Location = Context.getLocation(ID, 1, 1); 46 Replacement Replace(createReplacement(Location, 17, "")); 47 EXPECT_TRUE(Replace.apply(Context.Rewrite)); 48 EXPECT_EQ("", Context.getRewrittenText(ID)); 49 } 50 51 TEST_F(ReplacementTest, CanAddText) { 52 FileID ID = Context.createInMemoryFile("input.cpp", ""); 53 SourceLocation Location = Context.getLocation(ID, 1, 1); 54 Replacement Replace(createReplacement(Location, 0, "result")); 55 EXPECT_TRUE(Replace.apply(Context.Rewrite)); 56 EXPECT_EQ("result", Context.getRewrittenText(ID)); 57 } 58 59 TEST_F(ReplacementTest, CanReplaceTextAtPosition) { 60 FileID ID = Context.createInMemoryFile("input.cpp", 61 "line1\nline2\nline3\nline4"); 62 SourceLocation Location = Context.getLocation(ID, 2, 3); 63 Replacement Replace(createReplacement(Location, 12, "x")); 64 EXPECT_TRUE(Replace.apply(Context.Rewrite)); 65 EXPECT_EQ("line1\nlixne4", Context.getRewrittenText(ID)); 66 } 67 68 TEST_F(ReplacementTest, CanReplaceTextAtPositionMultipleTimes) { 69 FileID ID = Context.createInMemoryFile("input.cpp", 70 "line1\nline2\nline3\nline4"); 71 SourceLocation Location1 = Context.getLocation(ID, 2, 3); 72 Replacement Replace1(createReplacement(Location1, 12, "x\ny\n")); 73 EXPECT_TRUE(Replace1.apply(Context.Rewrite)); 74 EXPECT_EQ("line1\nlix\ny\nne4", Context.getRewrittenText(ID)); 75 76 // Since the original source has not been modified, the (4, 4) points to the 77 // 'e' in the original content. 78 SourceLocation Location2 = Context.getLocation(ID, 4, 4); 79 Replacement Replace2(createReplacement(Location2, 1, "f")); 80 EXPECT_TRUE(Replace2.apply(Context.Rewrite)); 81 EXPECT_EQ("line1\nlix\ny\nnf4", Context.getRewrittenText(ID)); 82 } 83 84 TEST_F(ReplacementTest, ApplyFailsForNonExistentLocation) { 85 Replacement Replace("nonexistent-file.cpp", 0, 1, ""); 86 EXPECT_FALSE(Replace.apply(Context.Rewrite)); 87 } 88 89 TEST_F(ReplacementTest, CanRetrivePath) { 90 Replacement Replace("/path/to/file.cpp", 0, 1, ""); 91 EXPECT_EQ("/path/to/file.cpp", Replace.getFilePath()); 92 } 93 94 TEST_F(ReplacementTest, ReturnsInvalidPath) { 95 Replacement Replace1(Context.Sources, SourceLocation(), 0, ""); 96 EXPECT_TRUE(Replace1.getFilePath().empty()); 97 98 Replacement Replace2; 99 EXPECT_TRUE(Replace2.getFilePath().empty()); 100 } 101 102 TEST_F(ReplacementTest, FailAddReplacements) { 103 Replacements Replaces; 104 Replacement Deletion("x.cc", 0, 10, "3"); 105 auto Err = Replaces.add(Deletion); 106 EXPECT_TRUE(!Err); 107 llvm::consumeError(std::move(Err)); 108 Err = Replaces.add(Replacement("x.cc", 0, 2, "a")); 109 EXPECT_TRUE((bool)Err); 110 llvm::consumeError(std::move(Err)); 111 Err = Replaces.add(Replacement("x.cc", 2, 2, "a")); 112 EXPECT_TRUE((bool)Err); 113 llvm::consumeError(std::move(Err)); 114 Err = Replaces.add(Replacement("y.cc", 20, 2, "")); 115 EXPECT_TRUE((bool)Err); 116 llvm::consumeError(std::move(Err)); 117 EXPECT_EQ(1u, Replaces.size()); 118 EXPECT_EQ(Deletion, *Replaces.begin()); 119 } 120 121 TEST_F(ReplacementTest, DeletionInReplacements) { 122 Replacements Replaces; 123 Replacement R("x.cc", 0, 10, "3"); 124 auto Err = Replaces.add(R); 125 EXPECT_TRUE(!Err); 126 llvm::consumeError(std::move(Err)); 127 Err = Replaces.add(Replacement("x.cc", 0, 2, "")); 128 EXPECT_TRUE(!Err); 129 llvm::consumeError(std::move(Err)); 130 Err = Replaces.add(Replacement("x.cc", 2, 2, "")); 131 EXPECT_TRUE(!Err); 132 llvm::consumeError(std::move(Err)); 133 EXPECT_EQ(1u, Replaces.size()); 134 EXPECT_EQ(R, *Replaces.begin()); 135 } 136 137 TEST_F(ReplacementTest, OverlappingReplacements) { 138 Replacements Replaces; 139 auto Err = Replaces.add(Replacement("x.cc", 0, 3, "345")); 140 EXPECT_TRUE(!Err); 141 llvm::consumeError(std::move(Err)); 142 Err = Replaces.add(Replacement("x.cc", 2, 3, "543")); 143 EXPECT_TRUE(!Err); 144 llvm::consumeError(std::move(Err)); 145 146 EXPECT_EQ(1u, Replaces.size()); 147 EXPECT_EQ(Replacement("x.cc", 0, 5, "34543"), *Replaces.begin()); 148 149 Err = Replaces.add(Replacement("x.cc", 2, 1, "5")); 150 EXPECT_TRUE(!Err); 151 llvm::consumeError(std::move(Err)); 152 EXPECT_EQ(1u, Replaces.size()); 153 EXPECT_EQ(Replacement("x.cc", 0, 5, "34543"), *Replaces.begin()); 154 } 155 156 TEST_F(ReplacementTest, AddAdjacentInsertionAndReplacement) { 157 Replacements Replaces; 158 // Test adding an insertion at the offset of an existing replacement. 159 auto Err = Replaces.add(Replacement("x.cc", 10, 3, "replace")); 160 EXPECT_TRUE(!Err); 161 llvm::consumeError(std::move(Err)); 162 Err = Replaces.add(Replacement("x.cc", 10, 0, "insert")); 163 EXPECT_TRUE(!Err); 164 llvm::consumeError(std::move(Err)); 165 EXPECT_EQ(Replaces.size(), 2u); 166 167 Replaces.clear(); 168 // Test overlap with an existing insertion. 169 Err = Replaces.add(Replacement("x.cc", 10, 0, "insert")); 170 EXPECT_TRUE(!Err); 171 llvm::consumeError(std::move(Err)); 172 Err = Replaces.add(Replacement("x.cc", 10, 3, "replace")); 173 EXPECT_TRUE(!Err); 174 llvm::consumeError(std::move(Err)); 175 EXPECT_EQ(Replaces.size(), 2u); 176 } 177 178 TEST_F(ReplacementTest, MergeNewDeletions) { 179 Replacements Replaces; 180 Replacement ContainingReplacement("x.cc", 0, 10, ""); 181 auto Err = Replaces.add(ContainingReplacement); 182 EXPECT_TRUE(!Err); 183 llvm::consumeError(std::move(Err)); 184 185 Err = Replaces.add(Replacement("x.cc", 5, 3, "")); 186 EXPECT_TRUE(!Err); 187 llvm::consumeError(std::move(Err)); 188 189 Err = Replaces.add(Replacement("x.cc", 0, 10, "")); 190 EXPECT_TRUE(!Err); 191 llvm::consumeError(std::move(Err)); 192 193 Err = Replaces.add(Replacement("x.cc", 5, 5, "")); 194 EXPECT_TRUE(!Err); 195 llvm::consumeError(std::move(Err)); 196 197 EXPECT_EQ(1u, Replaces.size()); 198 EXPECT_EQ(*Replaces.begin(), ContainingReplacement); 199 } 200 201 TEST_F(ReplacementTest, MergeOverlappingButNotAdjacentReplacement) { 202 Replacements Replaces; 203 auto Err = Replaces.add(Replacement("x.cc", 0, 2, "")); 204 EXPECT_TRUE(!Err); 205 llvm::consumeError(std::move(Err)); 206 207 Err = Replaces.add(Replacement("x.cc", 5, 5, "")); 208 EXPECT_TRUE(!Err); 209 llvm::consumeError(std::move(Err)); 210 211 Replacement After = Replacement("x.cc", 10, 5, ""); 212 Err = Replaces.add(After); 213 EXPECT_TRUE(!Err); 214 llvm::consumeError(std::move(Err)); 215 216 Replacement ContainingReplacement("x.cc", 0, 10, ""); 217 Err = Replaces.add(ContainingReplacement); 218 EXPECT_TRUE(!Err); 219 llvm::consumeError(std::move(Err)); 220 221 EXPECT_EQ(2u, Replaces.size()); 222 EXPECT_EQ(*Replaces.begin(), ContainingReplacement); 223 EXPECT_EQ(*(++Replaces.begin()), After); 224 } 225 226 TEST_F(ReplacementTest, InsertionBeforeMergedDeletions) { 227 Replacements Replaces; 228 229 Replacement Insertion("x.cc", 0, 0, "123"); 230 auto Err = Replaces.add(Insertion); 231 EXPECT_TRUE(!Err); 232 llvm::consumeError(std::move(Err)); 233 234 Err = Replaces.add(Replacement("x.cc", 5, 5, "")); 235 EXPECT_TRUE(!Err); 236 llvm::consumeError(std::move(Err)); 237 238 Replacement Deletion("x.cc", 0, 10, ""); 239 Err = Replaces.add(Deletion); 240 EXPECT_TRUE(!Err); 241 llvm::consumeError(std::move(Err)); 242 243 EXPECT_EQ(2u, Replaces.size()); 244 EXPECT_EQ(*Replaces.begin(), Insertion); 245 EXPECT_EQ(*(++Replaces.begin()), Deletion); 246 } 247 248 TEST_F(ReplacementTest, MergeOverlappingDeletions) { 249 Replacements Replaces; 250 auto Err = Replaces.add(Replacement("x.cc", 0, 2, "")); 251 EXPECT_TRUE(!Err); 252 llvm::consumeError(std::move(Err)); 253 254 Err = Replaces.add(Replacement("x.cc", 0, 5, "")); 255 EXPECT_TRUE(!Err); 256 llvm::consumeError(std::move(Err)); 257 258 EXPECT_EQ(1u, Replaces.size()); 259 EXPECT_EQ(Replacement("x.cc", 0, 5, ""), *Replaces.begin()); 260 261 Err = Replaces.add(Replacement("x.cc", 1, 5, "")); 262 EXPECT_TRUE(!Err); 263 llvm::consumeError(std::move(Err)); 264 EXPECT_EQ(1u, Replaces.size()); 265 EXPECT_EQ(Replacement("x.cc", 0, 6, ""), *Replaces.begin()); 266 } 267 268 TEST_F(ReplacementTest, FailedMergeExistingDeletions) { 269 Replacements Replaces; 270 Replacement First("x.cc", 0, 2, ""); 271 auto Err = Replaces.add(First); 272 EXPECT_TRUE(!Err); 273 llvm::consumeError(std::move(Err)); 274 275 Replacement Second("x.cc", 5, 5, ""); 276 Err = Replaces.add(Second); 277 EXPECT_TRUE(!Err); 278 llvm::consumeError(std::move(Err)); 279 280 Err = Replaces.add(Replacement("x.cc", 1, 10, "")); 281 EXPECT_TRUE(!Err); 282 llvm::consumeError(std::move(Err)); 283 284 EXPECT_EQ(1u, Replaces.size()); 285 EXPECT_EQ(Replacement("x.cc", 0, 11, ""), *Replaces.begin()); 286 } 287 288 TEST_F(ReplacementTest, FailAddRegression) { 289 Replacements Replaces; 290 // Create two replacements, where the second one is an insertion of the empty 291 // string exactly at the end of the first one. 292 auto Err = Replaces.add(Replacement("x.cc", 0, 10, "1")); 293 EXPECT_TRUE(!Err); 294 llvm::consumeError(std::move(Err)); 295 Err = Replaces.add(Replacement("x.cc", 10, 0, "")); 296 EXPECT_TRUE(!Err); 297 llvm::consumeError(std::move(Err)); 298 299 // Make sure we find the overlap with the first entry when inserting a 300 // replacement that ends exactly at the seam of the existing replacements. 301 Err = Replaces.add(Replacement("x.cc", 5, 5, "fail")); 302 EXPECT_TRUE((bool)Err); 303 llvm::consumeError(std::move(Err)); 304 305 Err = Replaces.add(Replacement("x.cc", 10, 0, "")); 306 EXPECT_TRUE(!Err); 307 llvm::consumeError(std::move(Err)); 308 } 309 310 TEST_F(ReplacementTest, InsertAtOffsetOfReplacement) { 311 Replacements Replaces; 312 auto Err = Replaces.add(Replacement("x.cc", 10, 2, "")); 313 EXPECT_TRUE(!Err); 314 llvm::consumeError(std::move(Err)); 315 Err = Replaces.add(Replacement("x.cc", 10, 0, "")); 316 EXPECT_TRUE(!Err); 317 llvm::consumeError(std::move(Err)); 318 EXPECT_EQ(Replaces.size(), 2u); 319 320 Replaces.clear(); 321 Err = Replaces.add(Replacement("x.cc", 10, 0, "")); 322 EXPECT_TRUE(!Err); 323 llvm::consumeError(std::move(Err)); 324 Err = Replaces.add(Replacement("x.cc", 10, 2, "")); 325 EXPECT_TRUE(!Err); 326 llvm::consumeError(std::move(Err)); 327 EXPECT_EQ(Replaces.size(), 2u); 328 } 329 330 TEST_F(ReplacementTest, AddInsertAtOtherInsertWhenOderIndependent) { 331 Replacements Replaces; 332 auto Err = Replaces.add(Replacement("x.cc", 10, 0, "a")); 333 EXPECT_TRUE(!Err); 334 llvm::consumeError(std::move(Err)); 335 Err = Replaces.add(Replacement("x.cc", 10, 0, "b")); 336 EXPECT_TRUE((bool)Err); 337 llvm::consumeError(std::move(Err)); 338 339 Replaces.clear(); 340 Err = Replaces.add(Replacement("x.cc", 10, 0, "a")); 341 EXPECT_TRUE(!Err); 342 llvm::consumeError(std::move(Err)); 343 Err = Replaces.add(Replacement("x.cc", 10, 0, "aa")); 344 EXPECT_TRUE(!Err); 345 llvm::consumeError(std::move(Err)); 346 EXPECT_EQ(1u, Replaces.size()); 347 EXPECT_EQ(Replacement("x.cc", 10, 0, "aaa"), *Replaces.begin()); 348 349 Replaces.clear(); 350 Err = Replaces.add(Replacement("x.cc", 10, 0, "")); 351 EXPECT_TRUE(!Err); 352 llvm::consumeError(std::move(Err)); 353 Err = Replaces.add(Replacement("x.cc", 10, 3, "")); 354 EXPECT_TRUE(!Err); 355 llvm::consumeError(std::move(Err)); 356 Err = Replaces.add(Replacement("x.cc", 10, 0, "")); 357 EXPECT_TRUE(!Err); 358 llvm::consumeError(std::move(Err)); 359 EXPECT_EQ(2u, Replaces.size()); 360 EXPECT_EQ(Replacement("x.cc", 10, 0, ""), *Replaces.begin()); 361 EXPECT_EQ(Replacement("x.cc", 10, 3, ""), *std::next(Replaces.begin())); 362 } 363 364 TEST_F(ReplacementTest, InsertBetweenAdjacentReplacements) { 365 Replacements Replaces; 366 auto Err = Replaces.add(Replacement("x.cc", 10, 5, "a")); 367 EXPECT_TRUE(!Err); 368 llvm::consumeError(std::move(Err)); 369 Err = Replaces.add(Replacement("x.cc", 8, 2, "a")); 370 EXPECT_TRUE(!Err); 371 llvm::consumeError(std::move(Err)); 372 Err = Replaces.add(Replacement("x.cc", 10, 0, "b")); 373 EXPECT_TRUE(!Err); 374 llvm::consumeError(std::move(Err)); 375 } 376 377 TEST_F(ReplacementTest, CanApplyReplacements) { 378 FileID ID = Context.createInMemoryFile("input.cpp", 379 "line1\nline2\nline3\nline4"); 380 Replacements Replaces = 381 toReplacements({Replacement(Context.Sources, 382 Context.getLocation(ID, 2, 1), 5, "replaced"), 383 Replacement(Context.Sources, 384 Context.getLocation(ID, 3, 1), 5, "other")}); 385 EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite)); 386 EXPECT_EQ("line1\nreplaced\nother\nline4", Context.getRewrittenText(ID)); 387 } 388 389 // Verifies that replacement/deletion is applied before insertion at the same 390 // offset. 391 TEST_F(ReplacementTest, InsertAndDelete) { 392 FileID ID = Context.createInMemoryFile("input.cpp", 393 "line1\nline2\nline3\nline4"); 394 Replacements Replaces = toReplacements( 395 {Replacement(Context.Sources, Context.getLocation(ID, 2, 1), 6, ""), 396 Replacement(Context.Sources, Context.getLocation(ID, 2, 1), 0, 397 "other\n")}); 398 EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite)); 399 EXPECT_EQ("line1\nother\nline3\nline4", Context.getRewrittenText(ID)); 400 } 401 402 TEST_F(ReplacementTest, AdjacentReplacements) { 403 FileID ID = Context.createInMemoryFile("input.cpp", 404 "ab"); 405 Replacements Replaces = toReplacements( 406 {Replacement(Context.Sources, Context.getLocation(ID, 1, 1), 1, "x"), 407 Replacement(Context.Sources, Context.getLocation(ID, 1, 2), 1, "y")}); 408 EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite)); 409 EXPECT_EQ("xy", Context.getRewrittenText(ID)); 410 } 411 412 TEST_F(ReplacementTest, AddDuplicateReplacements) { 413 FileID ID = Context.createInMemoryFile("input.cpp", 414 "line1\nline2\nline3\nline4"); 415 auto Replaces = toReplacements({Replacement( 416 Context.Sources, Context.getLocation(ID, 2, 1), 5, "replaced")}); 417 418 auto Err = Replaces.add(Replacement( 419 Context.Sources, Context.getLocation(ID, 2, 1), 5, "replaced")); 420 EXPECT_TRUE(!Err); 421 llvm::consumeError(std::move(Err)); 422 423 Err = Replaces.add(Replacement(Context.Sources, Context.getLocation(ID, 2, 1), 424 5, "replaced")); 425 EXPECT_TRUE(!Err); 426 llvm::consumeError(std::move(Err)); 427 428 EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite)); 429 EXPECT_EQ("line1\nreplaced\nline3\nline4", Context.getRewrittenText(ID)); 430 } 431 432 TEST_F(ReplacementTest, FailOrderDependentReplacements) { 433 FileID ID = Context.createInMemoryFile("input.cpp", 434 "line1\nline2\nline3\nline4"); 435 auto Replaces = toReplacements({Replacement( 436 Context.Sources, Context.getLocation(ID, 2, 1), 5, "other")}); 437 438 auto Err = Replaces.add(Replacement( 439 Context.Sources, Context.getLocation(ID, 2, 1), 5, "rehto")); 440 EXPECT_TRUE((bool)Err); 441 llvm::consumeError(std::move(Err)); 442 443 EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite)); 444 EXPECT_EQ("line1\nother\nline3\nline4", Context.getRewrittenText(ID)); 445 } 446 447 TEST_F(ReplacementTest, InvalidSourceLocationFailsApplyAll) { 448 Replacements Replaces = 449 toReplacements({Replacement(Context.Sources, SourceLocation(), 5, "2")}); 450 451 EXPECT_FALSE(applyAllReplacements(Replaces, Context.Rewrite)); 452 } 453 454 TEST_F(ReplacementTest, MultipleFilesReplaceAndFormat) { 455 // Column limit is 20. 456 std::string Code1 = "Long *a =\n" 457 " new Long();\n" 458 "long x = 1;"; 459 std::string Expected1 = "auto a = new Long();\n" 460 "long x =\n" 461 " 12345678901;"; 462 std::string Code2 = "int x = 123;\n" 463 "int y = 0;"; 464 std::string Expected2 = "int x =\n" 465 " 1234567890123;\n" 466 "int y = 10;"; 467 StringRef File1 = "format_1.cpp"; 468 StringRef File2 = "format_2.cpp"; 469 FileID ID1 = Context.createInMemoryFile(File1, Code1); 470 FileID ID2 = Context.createInMemoryFile(File2, Code2); 471 472 // Scrambled the order of replacements. 473 std::map<std::string, Replacements> FileToReplaces; 474 FileToReplaces[File1] = toReplacements( 475 {tooling::Replacement(Context.Sources, Context.getLocation(ID1, 1, 1), 6, 476 "auto "), 477 tooling::Replacement(Context.Sources, Context.getLocation(ID1, 3, 10), 1, 478 "12345678901")}); 479 FileToReplaces[File2] = toReplacements( 480 {tooling::Replacement(Context.Sources, Context.getLocation(ID2, 1, 12), 0, 481 "4567890123"), 482 tooling::Replacement(Context.Sources, Context.getLocation(ID2, 2, 9), 1, 483 "10")}); 484 EXPECT_TRUE( 485 formatAndApplyAllReplacements(FileToReplaces, Context.Rewrite, 486 "{BasedOnStyle: LLVM, ColumnLimit: 20}")); 487 EXPECT_EQ(Expected1, Context.getRewrittenText(ID1)); 488 EXPECT_EQ(Expected2, Context.getRewrittenText(ID2)); 489 } 490 491 TEST(ShiftedCodePositionTest, FindsNewCodePosition) { 492 Replacements Replaces = 493 toReplacements({Replacement("", 0, 1, ""), Replacement("", 4, 3, " ")}); 494 // Assume ' int i;' is turned into 'int i;' and cursor is located at '|'. 495 EXPECT_EQ(0u, Replaces.getShiftedCodePosition(0)); // |int i; 496 EXPECT_EQ(0u, Replaces.getShiftedCodePosition(1)); // |nt i; 497 EXPECT_EQ(1u, Replaces.getShiftedCodePosition(2)); // i|t i; 498 EXPECT_EQ(2u, Replaces.getShiftedCodePosition(3)); // in| i; 499 EXPECT_EQ(3u, Replaces.getShiftedCodePosition(4)); // int| i; 500 EXPECT_EQ(3u, Replaces.getShiftedCodePosition(5)); // int | i; 501 EXPECT_EQ(3u, Replaces.getShiftedCodePosition(6)); // int |i; 502 EXPECT_EQ(4u, Replaces.getShiftedCodePosition(7)); // int |; 503 EXPECT_EQ(5u, Replaces.getShiftedCodePosition(8)); // int i| 504 } 505 506 TEST(ShiftedCodePositionTest, FindsNewCodePositionWithInserts) { 507 Replacements Replaces = toReplacements({Replacement("", 4, 0, "\"\n\"")}); 508 // Assume '"12345678"' is turned into '"1234"\n"5678"'. 509 EXPECT_EQ(3u, Replaces.getShiftedCodePosition(3)); // "123|5678" 510 EXPECT_EQ(7u, Replaces.getShiftedCodePosition(4)); // "1234|678" 511 EXPECT_EQ(8u, Replaces.getShiftedCodePosition(5)); // "12345|78" 512 } 513 514 TEST(ShiftedCodePositionTest, FindsNewCodePositionInReplacedText) { 515 // Replace the first four characters with "abcd". 516 auto Replaces = toReplacements({Replacement("", 0, 4, "abcd")}); 517 for (unsigned i = 0; i < 3; ++i) 518 EXPECT_EQ(i, Replaces.getShiftedCodePosition(i)); 519 } 520 521 TEST(ShiftedCodePositionTest, NoReplacementText) { 522 Replacements Replaces = toReplacements({Replacement("", 0, 42, "")}); 523 EXPECT_EQ(0u, Replaces.getShiftedCodePosition(0)); 524 EXPECT_EQ(0u, Replaces.getShiftedCodePosition(39)); 525 EXPECT_EQ(3u, Replaces.getShiftedCodePosition(45)); 526 EXPECT_EQ(0u, Replaces.getShiftedCodePosition(42)); 527 } 528 529 class FlushRewrittenFilesTest : public ::testing::Test { 530 public: 531 FlushRewrittenFilesTest() {} 532 533 ~FlushRewrittenFilesTest() override { 534 for (llvm::StringMap<std::string>::iterator I = TemporaryFiles.begin(), 535 E = TemporaryFiles.end(); 536 I != E; ++I) { 537 llvm::StringRef Name = I->second; 538 std::error_code EC = llvm::sys::fs::remove(Name); 539 (void)EC; 540 assert(!EC); 541 } 542 } 543 544 FileID createFile(llvm::StringRef Name, llvm::StringRef Content) { 545 SmallString<1024> Path; 546 int FD; 547 std::error_code EC = llvm::sys::fs::createTemporaryFile(Name, "", FD, Path); 548 assert(!EC); 549 (void)EC; 550 551 llvm::raw_fd_ostream OutStream(FD, true); 552 OutStream << Content; 553 OutStream.close(); 554 const FileEntry *File = Context.Files.getFile(Path); 555 assert(File != nullptr); 556 557 StringRef Found = 558 TemporaryFiles.insert(std::make_pair(Name, Path.str())).first->second; 559 assert(Found == Path); 560 (void)Found; 561 return Context.Sources.createFileID(File, SourceLocation(), SrcMgr::C_User); 562 } 563 564 std::string getFileContentFromDisk(llvm::StringRef Name) { 565 std::string Path = TemporaryFiles.lookup(Name); 566 assert(!Path.empty()); 567 // We need to read directly from the FileManager without relaying through 568 // a FileEntry, as otherwise we'd read through an already opened file 569 // descriptor, which might not see the changes made. 570 // FIXME: Figure out whether there is a way to get the SourceManger to 571 // reopen the file. 572 auto FileBuffer = Context.Files.getBufferForFile(Path); 573 return (*FileBuffer)->getBuffer(); 574 } 575 576 llvm::StringMap<std::string> TemporaryFiles; 577 RewriterTestContext Context; 578 }; 579 580 TEST_F(FlushRewrittenFilesTest, StoresChangesOnDisk) { 581 FileID ID = createFile("input.cpp", "line1\nline2\nline3\nline4"); 582 Replacements Replaces = toReplacements({Replacement( 583 Context.Sources, Context.getLocation(ID, 2, 1), 5, "replaced")}); 584 EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite)); 585 EXPECT_FALSE(Context.Rewrite.overwriteChangedFiles()); 586 EXPECT_EQ("line1\nreplaced\nline3\nline4", 587 getFileContentFromDisk("input.cpp")); 588 } 589 590 namespace { 591 template <typename T> 592 class TestVisitor : public clang::RecursiveASTVisitor<T> { 593 public: 594 bool runOver(StringRef Code) { 595 return runToolOnCode(new TestAction(this), Code); 596 } 597 598 protected: 599 clang::SourceManager *SM; 600 clang::ASTContext *Context; 601 602 private: 603 class FindConsumer : public clang::ASTConsumer { 604 public: 605 FindConsumer(TestVisitor *Visitor) : Visitor(Visitor) {} 606 607 void HandleTranslationUnit(clang::ASTContext &Context) override { 608 Visitor->TraverseDecl(Context.getTranslationUnitDecl()); 609 } 610 611 private: 612 TestVisitor *Visitor; 613 }; 614 615 class TestAction : public clang::ASTFrontendAction { 616 public: 617 TestAction(TestVisitor *Visitor) : Visitor(Visitor) {} 618 619 std::unique_ptr<clang::ASTConsumer> 620 CreateASTConsumer(clang::CompilerInstance &compiler, 621 llvm::StringRef dummy) override { 622 Visitor->SM = &compiler.getSourceManager(); 623 Visitor->Context = &compiler.getASTContext(); 624 /// TestConsumer will be deleted by the framework calling us. 625 return llvm::make_unique<FindConsumer>(Visitor); 626 } 627 628 private: 629 TestVisitor *Visitor; 630 }; 631 }; 632 } // end namespace 633 634 void expectReplacementAt(const Replacement &Replace, 635 StringRef File, unsigned Offset, unsigned Length) { 636 ASSERT_TRUE(Replace.isApplicable()); 637 EXPECT_EQ(File, Replace.getFilePath()); 638 EXPECT_EQ(Offset, Replace.getOffset()); 639 EXPECT_EQ(Length, Replace.getLength()); 640 } 641 642 class ClassDeclXVisitor : public TestVisitor<ClassDeclXVisitor> { 643 public: 644 bool VisitCXXRecordDecl(CXXRecordDecl *Record) { 645 if (Record->getName() == "X") { 646 Replace = Replacement(*SM, Record, ""); 647 } 648 return true; 649 } 650 Replacement Replace; 651 }; 652 653 TEST(Replacement, CanBeConstructedFromNode) { 654 ClassDeclXVisitor ClassDeclX; 655 EXPECT_TRUE(ClassDeclX.runOver(" class X;")); 656 expectReplacementAt(ClassDeclX.Replace, "input.cc", 5, 7); 657 } 658 659 TEST(Replacement, ReplacesAtSpellingLocation) { 660 ClassDeclXVisitor ClassDeclX; 661 EXPECT_TRUE(ClassDeclX.runOver("#define A(Y) Y\nA(class X);")); 662 expectReplacementAt(ClassDeclX.Replace, "input.cc", 17, 7); 663 } 664 665 class CallToFVisitor : public TestVisitor<CallToFVisitor> { 666 public: 667 bool VisitCallExpr(CallExpr *Call) { 668 if (Call->getDirectCallee()->getName() == "F") { 669 Replace = Replacement(*SM, Call, ""); 670 } 671 return true; 672 } 673 Replacement Replace; 674 }; 675 676 TEST(Replacement, FunctionCall) { 677 CallToFVisitor CallToF; 678 EXPECT_TRUE(CallToF.runOver("void F(); void G() { F(); }")); 679 expectReplacementAt(CallToF.Replace, "input.cc", 21, 3); 680 } 681 682 TEST(Replacement, TemplatedFunctionCall) { 683 CallToFVisitor CallToF; 684 EXPECT_TRUE(CallToF.runOver( 685 "template <typename T> void F(); void G() { F<int>(); }")); 686 expectReplacementAt(CallToF.Replace, "input.cc", 43, 8); 687 } 688 689 class NestedNameSpecifierAVisitor 690 : public TestVisitor<NestedNameSpecifierAVisitor> { 691 public: 692 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNSLoc) { 693 if (NNSLoc.getNestedNameSpecifier()) { 694 if (const NamespaceDecl* NS = NNSLoc.getNestedNameSpecifier()->getAsNamespace()) { 695 if (NS->getName() == "a") { 696 Replace = Replacement(*SM, &NNSLoc, "", Context->getLangOpts()); 697 } 698 } 699 } 700 return TestVisitor<NestedNameSpecifierAVisitor>::TraverseNestedNameSpecifierLoc( 701 NNSLoc); 702 } 703 Replacement Replace; 704 }; 705 706 TEST(Replacement, ColonColon) { 707 NestedNameSpecifierAVisitor VisitNNSA; 708 EXPECT_TRUE(VisitNNSA.runOver("namespace a { void f() { ::a::f(); } }")); 709 expectReplacementAt(VisitNNSA.Replace, "input.cc", 25, 5); 710 } 711 712 TEST(Range, overlaps) { 713 EXPECT_TRUE(Range(10, 10).overlapsWith(Range(0, 11))); 714 EXPECT_TRUE(Range(0, 11).overlapsWith(Range(10, 10))); 715 EXPECT_FALSE(Range(10, 10).overlapsWith(Range(0, 10))); 716 EXPECT_FALSE(Range(0, 10).overlapsWith(Range(10, 10))); 717 EXPECT_TRUE(Range(0, 10).overlapsWith(Range(2, 6))); 718 EXPECT_TRUE(Range(2, 6).overlapsWith(Range(0, 10))); 719 } 720 721 TEST(Range, contains) { 722 EXPECT_TRUE(Range(0, 10).contains(Range(0, 10))); 723 EXPECT_TRUE(Range(0, 10).contains(Range(2, 6))); 724 EXPECT_FALSE(Range(2, 6).contains(Range(0, 10))); 725 EXPECT_FALSE(Range(0, 10).contains(Range(0, 11))); 726 } 727 728 TEST(Range, CalculateRangesOfReplacements) { 729 // Before: aaaabbbbbbz 730 // After : bbbbbbzzzzzzoooooooooooooooo 731 Replacements Replaces = toReplacements( 732 {Replacement("foo", 0, 4, ""), Replacement("foo", 10, 1, "zzzzzz"), 733 Replacement("foo", 11, 0, "oooooooooooooooo")}); 734 735 std::vector<Range> Ranges = Replaces.getAffectedRanges(); 736 737 EXPECT_EQ(2ul, Ranges.size()); 738 EXPECT_TRUE(Ranges[0].getOffset() == 0); 739 EXPECT_TRUE(Ranges[0].getLength() == 0); 740 EXPECT_TRUE(Ranges[1].getOffset() == 6); 741 EXPECT_TRUE(Ranges[1].getLength() == 22); 742 } 743 744 TEST(Range, CalculateRangesOfInsertionAroundReplacement) { 745 Replacements Replaces = toReplacements( 746 {Replacement("foo", 0, 2, ""), Replacement("foo", 0, 0, "ba")}); 747 748 std::vector<Range> Ranges = Replaces.getAffectedRanges(); 749 750 EXPECT_EQ(1ul, Ranges.size()); 751 EXPECT_EQ(0u, Ranges[0].getOffset()); 752 EXPECT_EQ(2u, Ranges[0].getLength()); 753 } 754 755 TEST(Range, RangesAfterEmptyReplacements) { 756 std::vector<Range> Ranges = {Range(5, 6), Range(10, 5)}; 757 Replacements Replaces; 758 std::vector<Range> Expected = {Range(5, 10)}; 759 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges)); 760 } 761 762 TEST(Range, RangesAfterReplacements) { 763 std::vector<Range> Ranges = {Range(5, 2), Range(10, 5)}; 764 Replacements Replaces = toReplacements({Replacement("foo", 0, 2, "1234")}); 765 std::vector<Range> Expected = {Range(0, 4), Range(7, 2), Range(12, 5)}; 766 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges)); 767 } 768 769 TEST(Range, RangesBeforeReplacements) { 770 std::vector<Range> Ranges = {Range(5, 2), Range(10, 5)}; 771 Replacements Replaces = toReplacements({Replacement("foo", 20, 2, "1234")}); 772 std::vector<Range> Expected = {Range(5, 2), Range(10, 5), Range(20, 4)}; 773 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges)); 774 } 775 776 TEST(Range, NotAffectedByReplacements) { 777 std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(10, 5)}; 778 Replacements Replaces = toReplacements({Replacement("foo", 3, 2, "12"), 779 Replacement("foo", 12, 2, "12"), 780 Replacement("foo", 20, 5, "")}); 781 std::vector<Range> Expected = {Range(0, 2), Range(3, 4), Range(10, 5), 782 Range(20, 0)}; 783 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges)); 784 } 785 786 TEST(Range, RangesWithNonOverlappingReplacements) { 787 std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(10, 5)}; 788 Replacements Replaces = toReplacements({Replacement("foo", 3, 1, ""), 789 Replacement("foo", 6, 1, "123"), 790 Replacement("foo", 20, 2, "12345")}); 791 std::vector<Range> Expected = {Range(0, 2), Range(3, 0), Range(4, 4), 792 Range(11, 5), Range(21, 5)}; 793 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges)); 794 } 795 796 TEST(Range, RangesWithOverlappingReplacements) { 797 std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(15, 5), 798 Range(30, 5)}; 799 Replacements Replaces = toReplacements( 800 {Replacement("foo", 1, 3, ""), Replacement("foo", 6, 1, "123"), 801 Replacement("foo", 13, 3, "1"), Replacement("foo", 25, 15, "")}); 802 std::vector<Range> Expected = {Range(0, 1), Range(2, 4), Range(12, 5), 803 Range(22, 0)}; 804 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges)); 805 } 806 807 TEST(Range, MergeIntoOneRange) { 808 std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(15, 5)}; 809 Replacements Replaces = 810 toReplacements({Replacement("foo", 1, 15, "1234567890")}); 811 std::vector<Range> Expected = {Range(0, 15)}; 812 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges)); 813 } 814 815 TEST(Range, ReplacementsStartingAtRangeOffsets) { 816 std::vector<Range> Ranges = {Range(0, 2), Range(5, 5), Range(15, 5)}; 817 Replacements Replaces = toReplacements( 818 {Replacement("foo", 0, 2, "12"), Replacement("foo", 5, 1, "123"), 819 Replacement("foo", 7, 4, "12345"), Replacement("foo", 15, 10, "12")}); 820 std::vector<Range> Expected = {Range(0, 2), Range(5, 9), Range(18, 2)}; 821 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges)); 822 } 823 824 TEST(Range, ReplacementsEndingAtRangeEnds) { 825 std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(15, 5)}; 826 Replacements Replaces = toReplacements( 827 {Replacement("foo", 6, 1, "123"), Replacement("foo", 17, 3, "12")}); 828 std::vector<Range> Expected = {Range(0, 2), Range(5, 4), Range(17, 4)}; 829 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges)); 830 } 831 832 TEST(Range, AjacentReplacements) { 833 std::vector<Range> Ranges = {Range(0, 0), Range(15, 5)}; 834 Replacements Replaces = toReplacements( 835 {Replacement("foo", 1, 2, "123"), Replacement("foo", 12, 3, "1234")}); 836 std::vector<Range> Expected = {Range(0, 0), Range(1, 3), Range(13, 9)}; 837 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges)); 838 } 839 840 TEST(Range, MergeRangesAfterReplacements) { 841 std::vector<Range> Ranges = {Range(8, 0), Range(5, 2), Range(9, 0), Range(0, 1)}; 842 Replacements Replaces = toReplacements({Replacement("foo", 1, 3, ""), 843 Replacement("foo", 7, 0, "12"), 844 Replacement("foo", 9, 2, "")}); 845 std::vector<Range> Expected = {Range(0, 1), Range(2, 4), Range(7, 0), 846 Range(8, 0)}; 847 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges)); 848 } 849 850 TEST(Range, ConflictingRangesBeforeReplacements) { 851 std::vector<Range> Ranges = {Range(8, 3), Range(5, 4), Range(9, 1)}; 852 Replacements Replaces = toReplacements({Replacement("foo", 1, 3, "")}); 853 std::vector<Range> Expected = {Range(1, 0), Range(2, 6)}; 854 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges)); 855 } 856 857 class MergeReplacementsTest : public ::testing::Test { 858 protected: 859 void mergeAndTestRewrite(StringRef Code, StringRef Intermediate, 860 StringRef Result, const Replacements &First, 861 const Replacements &Second) { 862 // These are mainly to verify the test itself and make it easier to read. 863 auto AfterFirst = applyAllReplacements(Code, First); 864 EXPECT_TRUE(static_cast<bool>(AfterFirst)); 865 auto InSequenceRewrite = applyAllReplacements(*AfterFirst, Second); 866 EXPECT_TRUE(static_cast<bool>(InSequenceRewrite)); 867 EXPECT_EQ(Intermediate, *AfterFirst); 868 EXPECT_EQ(Result, *InSequenceRewrite); 869 870 tooling::Replacements Merged = First.merge(Second); 871 auto MergedRewrite = applyAllReplacements(Code, Merged); 872 EXPECT_TRUE(static_cast<bool>(MergedRewrite)); 873 EXPECT_EQ(*InSequenceRewrite, *MergedRewrite); 874 if (*InSequenceRewrite != *MergedRewrite) 875 for (tooling::Replacement M : Merged) 876 llvm::errs() << M.getOffset() << " " << M.getLength() << " " 877 << M.getReplacementText() << "\n"; 878 } 879 void mergeAndTestRewrite(StringRef Code, const Replacements &First, 880 const Replacements &Second) { 881 auto AfterFirst = applyAllReplacements(Code, First); 882 EXPECT_TRUE(static_cast<bool>(AfterFirst)); 883 auto InSequenceRewrite = applyAllReplacements(*AfterFirst, Second); 884 tooling::Replacements Merged = First.merge(Second); 885 auto MergedRewrite = applyAllReplacements(Code, Merged); 886 EXPECT_TRUE(static_cast<bool>(MergedRewrite)); 887 EXPECT_EQ(*InSequenceRewrite, *MergedRewrite); 888 if (*InSequenceRewrite != *MergedRewrite) 889 for (tooling::Replacement M : Merged) 890 llvm::errs() << M.getOffset() << " " << M.getLength() << " " 891 << M.getReplacementText() << "\n"; 892 } 893 }; 894 895 TEST_F(MergeReplacementsTest, Offsets) { 896 mergeAndTestRewrite("aaa", "aabab", "cacabab", 897 toReplacements({{"", 2, 0, "b"}, {"", 3, 0, "b"}}), 898 toReplacements({{"", 0, 0, "c"}, {"", 1, 0, "c"}})); 899 mergeAndTestRewrite("aaa", "babaa", "babacac", 900 toReplacements({{"", 0, 0, "b"}, {"", 1, 0, "b"}}), 901 toReplacements({{"", 4, 0, "c"}, {"", 5, 0, "c"}})); 902 mergeAndTestRewrite("aaaa", "aaa", "aac", toReplacements({{"", 1, 1, ""}}), 903 toReplacements({{"", 2, 1, "c"}})); 904 905 mergeAndTestRewrite("aa", "bbabba", "bbabcba", 906 toReplacements({{"", 0, 0, "bb"}, {"", 1, 0, "bb"}}), 907 toReplacements({{"", 4, 0, "c"}})); 908 } 909 910 TEST_F(MergeReplacementsTest, Concatenations) { 911 // Basic concatenations. It is important to merge these into a single 912 // replacement to ensure the correct order. 913 { 914 auto First = toReplacements({{"", 0, 0, "a"}}); 915 auto Second = toReplacements({{"", 1, 0, "b"}}); 916 EXPECT_EQ(toReplacements({{"", 0, 0, "ab"}}), First.merge(Second)); 917 } 918 { 919 auto First = toReplacements({{"", 0, 0, "a"}}); 920 auto Second = toReplacements({{"", 0, 0, "b"}}); 921 EXPECT_EQ(toReplacements({{"", 0, 0, "ba"}}), First.merge(Second)); 922 } 923 mergeAndTestRewrite("", "a", "ab", toReplacements({{"", 0, 0, "a"}}), 924 toReplacements({{"", 1, 0, "b"}})); 925 mergeAndTestRewrite("", "a", "ba", toReplacements({{"", 0, 0, "a"}}), 926 toReplacements({{"", 0, 0, "b"}})); 927 } 928 929 TEST_F(MergeReplacementsTest, NotChangingLengths) { 930 mergeAndTestRewrite("aaaa", "abba", "acca", 931 toReplacements({{"", 1, 2, "bb"}}), 932 toReplacements({{"", 1, 2, "cc"}})); 933 mergeAndTestRewrite("aaaa", "abba", "abcc", 934 toReplacements({{"", 1, 2, "bb"}}), 935 toReplacements({{"", 2, 2, "cc"}})); 936 mergeAndTestRewrite("aaaa", "abba", "ccba", 937 toReplacements({{"", 1, 2, "bb"}}), 938 toReplacements({{"", 0, 2, "cc"}})); 939 mergeAndTestRewrite("aaaaaa", "abbdda", "abccda", 940 toReplacements({{"", 1, 2, "bb"}, {"", 3, 2, "dd"}}), 941 toReplacements({{"", 2, 2, "cc"}})); 942 } 943 944 TEST_F(MergeReplacementsTest, OverlappingRanges) { 945 mergeAndTestRewrite("aaa", "bbd", "bcbcd", 946 toReplacements({{"", 0, 1, "bb"}, {"", 1, 2, "d"}}), 947 toReplacements({{"", 1, 0, "c"}, {"", 2, 0, "c"}})); 948 949 mergeAndTestRewrite("aaaa", "aabbaa", "acccca", 950 toReplacements({{"", 2, 0, "bb"}}), 951 toReplacements({{"", 1, 4, "cccc"}})); 952 mergeAndTestRewrite("aaaa", "aababa", "acccca", 953 toReplacements({{"", 2, 0, "b"}, {"", 3, 0, "b"}}), 954 toReplacements({{"", 1, 4, "cccc"}})); 955 mergeAndTestRewrite("aaaaaa", "abbbba", "abba", 956 toReplacements({{"", 1, 4, "bbbb"}}), 957 toReplacements({{"", 2, 2, ""}})); 958 mergeAndTestRewrite("aaaa", "aa", "cc", 959 toReplacements({{"", 1, 1, ""}, {"", 2, 1, ""}}), 960 toReplacements({{"", 0, 2, "cc"}})); 961 mergeAndTestRewrite("aa", "abbba", "abcbcba", 962 toReplacements({{"", 1, 0, "bbb"}}), 963 toReplacements({{"", 2, 0, "c"}, {"", 3, 0, "c"}})); 964 965 mergeAndTestRewrite( 966 "aaa", "abbab", "ccdd", 967 toReplacements({{"", 0, 1, ""}, {"", 2, 0, "bb"}, {"", 3, 0, "b"}}), 968 toReplacements({{"", 0, 2, "cc"}, {"", 2, 3, "dd"}})); 969 mergeAndTestRewrite( 970 "aa", "babbab", "ccdd", 971 toReplacements({{"", 0, 0, "b"}, {"", 1, 0, "bb"}, {"", 2, 0, "b"}}), 972 toReplacements({{"", 0, 3, "cc"}, {"", 3, 3, "dd"}})); 973 } 974 975 TEST(DeduplicateByFileTest, LeaveLeadingDotDot) { 976 std::map<std::string, Replacements> FileToReplaces; 977 #if !defined(LLVM_ON_WIN32) 978 FileToReplaces["../../a/b/.././c.h"] = Replacements(); 979 FileToReplaces["../../a/c.h"] = Replacements(); 980 #else 981 FileToReplaces["..\\..\\a\\b\\..\\.\\c.h"] = Replacements(); 982 FileToReplaces["..\\..\\a\\c.h"] = Replacements(); 983 #endif 984 FileToReplaces = groupReplacementsByFile(FileToReplaces); 985 EXPECT_EQ(1u, FileToReplaces.size()); 986 #if !defined(LLVM_ON_WIN32) 987 EXPECT_EQ("../../a/c.h", FileToReplaces.begin()->first); 988 #else 989 EXPECT_EQ("..\\..\\a\\c.h", FileToReplaces.begin()->first); 990 #endif 991 } 992 993 TEST(DeduplicateByFileTest, RemoveDotSlash) { 994 std::map<std::string, Replacements> FileToReplaces; 995 #if !defined(LLVM_ON_WIN32) 996 FileToReplaces["./a/b/.././c.h"] = Replacements(); 997 FileToReplaces["a/c.h"] = Replacements(); 998 #else 999 FileToReplaces[".\\a\\b\\..\\.\\c.h"] = Replacements(); 1000 FileToReplaces["a\\c.h"] = Replacements(); 1001 #endif 1002 FileToReplaces = groupReplacementsByFile(FileToReplaces); 1003 EXPECT_EQ(1u, FileToReplaces.size()); 1004 #if !defined(LLVM_ON_WIN32) 1005 EXPECT_EQ("a/c.h", FileToReplaces.begin()->first); 1006 #else 1007 EXPECT_EQ("a\\c.h", FileToReplaces.begin()->first); 1008 #endif 1009 } 1010 1011 } // end namespace tooling 1012 } // end namespace clang 1013