1 //===- unittest/Format/SortIncludesTest.cpp - Include sort 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 "FormatTestUtils.h" 10 #include "clang/Format/Format.h" 11 #include "llvm/Support/Debug.h" 12 #include "gtest/gtest.h" 13 14 #define DEBUG_TYPE "format-test" 15 16 namespace clang { 17 namespace format { 18 namespace { 19 20 class SortIncludesTest : public ::testing::Test { 21 protected: 22 std::vector<tooling::Range> GetCodeRange(StringRef Code) { 23 return std::vector<tooling::Range>(1, tooling::Range(0, Code.size())); 24 } 25 26 std::string sort(StringRef Code, std::vector<tooling::Range> Ranges, 27 StringRef FileName = "input.cc") { 28 auto Replaces = sortIncludes(FmtStyle, Code, Ranges, FileName); 29 Ranges = tooling::calculateRangesAfterReplacements(Replaces, Ranges); 30 auto Sorted = applyAllReplacements(Code, Replaces); 31 EXPECT_TRUE(static_cast<bool>(Sorted)); 32 auto Result = applyAllReplacements( 33 *Sorted, reformat(FmtStyle, *Sorted, Ranges, FileName)); 34 EXPECT_TRUE(static_cast<bool>(Result)); 35 return *Result; 36 } 37 38 std::string sort(StringRef Code, StringRef FileName = "input.cpp") { 39 return sort(Code, GetCodeRange(Code), FileName); 40 } 41 42 unsigned newCursor(llvm::StringRef Code, unsigned Cursor) { 43 sortIncludes(FmtStyle, Code, GetCodeRange(Code), "input.cpp", &Cursor); 44 return Cursor; 45 } 46 47 FormatStyle FmtStyle = getLLVMStyle(); 48 tooling::IncludeStyle &Style = FmtStyle.IncludeStyle; 49 }; 50 51 TEST_F(SortIncludesTest, BasicSorting) { 52 EXPECT_EQ("#include \"a.h\"\n" 53 "#include \"b.h\"\n" 54 "#include \"c.h\"\n", 55 sort("#include \"a.h\"\n" 56 "#include \"c.h\"\n" 57 "#include \"b.h\"\n")); 58 59 EXPECT_EQ("// comment\n" 60 "#include <a>\n" 61 "#include <b>\n", 62 sort("// comment\n" 63 "#include <b>\n" 64 "#include <a>\n", 65 {tooling::Range(25, 1)})); 66 } 67 68 TEST_F(SortIncludesTest, NoReplacementsForValidIncludes) { 69 // Identical #includes have led to a failure with an unstable sort. 70 std::string Code = "#include <a>\n" 71 "#include <b>\n" 72 "#include <c>\n" 73 "#include <d>\n" 74 "#include <e>\n" 75 "#include <f>\n"; 76 EXPECT_TRUE(sortIncludes(FmtStyle, Code, GetCodeRange(Code), "a.cc").empty()); 77 } 78 79 TEST_F(SortIncludesTest, SortedIncludesInMultipleBlocksAreMerged) { 80 Style.IncludeBlocks = tooling::IncludeStyle::IBS_Merge; 81 EXPECT_EQ("#include \"a.h\"\n" 82 "#include \"b.h\"\n" 83 "#include \"c.h\"\n", 84 sort("#include \"a.h\"\n" 85 "#include \"c.h\"\n" 86 "\n" 87 "\n" 88 "#include \"b.h\"\n")); 89 90 Style.IncludeBlocks = tooling::IncludeStyle::IBS_Regroup; 91 EXPECT_EQ("#include \"a.h\"\n" 92 "#include \"b.h\"\n" 93 "#include \"c.h\"\n", 94 sort("#include \"a.h\"\n" 95 "#include \"c.h\"\n" 96 "\n" 97 "\n" 98 "#include \"b.h\"\n")); 99 } 100 101 TEST_F(SortIncludesTest, SupportClangFormatOff) { 102 EXPECT_EQ("#include <a>\n" 103 "#include <b>\n" 104 "#include <c>\n" 105 "// clang-format off\n" 106 "#include <b>\n" 107 "#include <a>\n" 108 "#include <c>\n" 109 "// clang-format on\n", 110 sort("#include <b>\n" 111 "#include <a>\n" 112 "#include <c>\n" 113 "// clang-format off\n" 114 "#include <b>\n" 115 "#include <a>\n" 116 "#include <c>\n" 117 "// clang-format on\n")); 118 } 119 120 TEST_F(SortIncludesTest, SupportClangFormatOffCStyle) { 121 EXPECT_EQ("#include <a>\n" 122 "#include <b>\n" 123 "#include <c>\n" 124 "/* clang-format off */\n" 125 "#include <b>\n" 126 "#include <a>\n" 127 "#include <c>\n" 128 "/* clang-format on */\n", 129 sort("#include <b>\n" 130 "#include <a>\n" 131 "#include <c>\n" 132 "/* clang-format off */\n" 133 "#include <b>\n" 134 "#include <a>\n" 135 "#include <c>\n" 136 "/* clang-format on */\n")); 137 138 // Not really turning it off 139 EXPECT_EQ("#include <a>\n" 140 "#include <b>\n" 141 "#include <c>\n" 142 "/* clang-format offically */\n" 143 "#include <a>\n" 144 "#include <b>\n" 145 "#include <c>\n" 146 "/* clang-format onwards */\n", 147 sort("#include <b>\n" 148 "#include <a>\n" 149 "#include <c>\n" 150 "/* clang-format offically */\n" 151 "#include <b>\n" 152 "#include <a>\n" 153 "#include <c>\n" 154 "/* clang-format onwards */\n")); 155 } 156 157 TEST_F(SortIncludesTest, IncludeSortingCanBeDisabled) { 158 FmtStyle.SortIncludes = false; 159 EXPECT_EQ("#include \"a.h\"\n" 160 "#include \"c.h\"\n" 161 "#include \"b.h\"\n", 162 sort("#include \"a.h\"\n" 163 "#include \"c.h\"\n" 164 "#include \"b.h\"\n")); 165 } 166 167 TEST_F(SortIncludesTest, MixIncludeAndImport) { 168 EXPECT_EQ("#include \"a.h\"\n" 169 "#import \"b.h\"\n" 170 "#include \"c.h\"\n", 171 sort("#include \"a.h\"\n" 172 "#include \"c.h\"\n" 173 "#import \"b.h\"\n")); 174 } 175 176 TEST_F(SortIncludesTest, FixTrailingComments) { 177 EXPECT_EQ("#include \"a.h\" // comment\n" 178 "#include \"bb.h\" // comment\n" 179 "#include \"ccc.h\"\n", 180 sort("#include \"a.h\" // comment\n" 181 "#include \"ccc.h\"\n" 182 "#include \"bb.h\" // comment\n")); 183 } 184 185 TEST_F(SortIncludesTest, LeadingWhitespace) { 186 EXPECT_EQ("#include \"a.h\"\n" 187 "#include \"b.h\"\n" 188 "#include \"c.h\"\n", 189 sort(" #include \"a.h\"\n" 190 " #include \"c.h\"\n" 191 " #include \"b.h\"\n")); 192 EXPECT_EQ("#include \"a.h\"\n" 193 "#include \"b.h\"\n" 194 "#include \"c.h\"\n", 195 sort("# include \"a.h\"\n" 196 "# include \"c.h\"\n" 197 "# include \"b.h\"\n")); 198 } 199 200 TEST_F(SortIncludesTest, GreaterInComment) { 201 EXPECT_EQ("#include \"a.h\"\n" 202 "#include \"b.h\" // >\n" 203 "#include \"c.h\"\n", 204 sort("#include \"a.h\"\n" 205 "#include \"c.h\"\n" 206 "#include \"b.h\" // >\n")); 207 } 208 209 TEST_F(SortIncludesTest, SortsLocallyInEachBlock) { 210 EXPECT_EQ("#include \"a.h\"\n" 211 "#include \"c.h\"\n" 212 "\n" 213 "#include \"b.h\"\n", 214 sort("#include \"a.h\"\n" 215 "#include \"c.h\"\n" 216 "\n" 217 "#include \"b.h\"\n")); 218 } 219 220 TEST_F(SortIncludesTest, SortsAllBlocksWhenMerging) { 221 Style.IncludeBlocks = tooling::IncludeStyle::IBS_Merge; 222 EXPECT_EQ("#include \"a.h\"\n" 223 "#include \"b.h\"\n" 224 "#include \"c.h\"\n", 225 sort("#include \"a.h\"\n" 226 "#include \"c.h\"\n" 227 "\n" 228 "#include \"b.h\"\n")); 229 } 230 231 TEST_F(SortIncludesTest, CommentsAlwaysSeparateGroups) { 232 EXPECT_EQ("#include \"a.h\"\n" 233 "#include \"c.h\"\n" 234 "// comment\n" 235 "#include \"b.h\"\n", 236 sort("#include \"c.h\"\n" 237 "#include \"a.h\"\n" 238 "// comment\n" 239 "#include \"b.h\"\n")); 240 241 Style.IncludeBlocks = tooling::IncludeStyle::IBS_Merge; 242 EXPECT_EQ("#include \"a.h\"\n" 243 "#include \"c.h\"\n" 244 "// comment\n" 245 "#include \"b.h\"\n", 246 sort("#include \"c.h\"\n" 247 "#include \"a.h\"\n" 248 "// comment\n" 249 "#include \"b.h\"\n")); 250 251 Style.IncludeBlocks = tooling::IncludeStyle::IBS_Regroup; 252 EXPECT_EQ("#include \"a.h\"\n" 253 "#include \"c.h\"\n" 254 "// comment\n" 255 "#include \"b.h\"\n", 256 sort("#include \"c.h\"\n" 257 "#include \"a.h\"\n" 258 "// comment\n" 259 "#include \"b.h\"\n")); 260 } 261 262 TEST_F(SortIncludesTest, HandlesAngledIncludesAsSeparateBlocks) { 263 EXPECT_EQ("#include \"a.h\"\n" 264 "#include \"c.h\"\n" 265 "#include <b.h>\n" 266 "#include <d.h>\n", 267 sort("#include <d.h>\n" 268 "#include <b.h>\n" 269 "#include \"c.h\"\n" 270 "#include \"a.h\"\n")); 271 272 FmtStyle = getGoogleStyle(FormatStyle::LK_Cpp); 273 EXPECT_EQ("#include <b.h>\n" 274 "#include <d.h>\n" 275 "#include \"a.h\"\n" 276 "#include \"c.h\"\n", 277 sort("#include <d.h>\n" 278 "#include <b.h>\n" 279 "#include \"c.h\"\n" 280 "#include \"a.h\"\n")); 281 } 282 283 TEST_F(SortIncludesTest, RegroupsAngledIncludesInSeparateBlocks) { 284 Style.IncludeBlocks = tooling::IncludeStyle::IBS_Regroup; 285 EXPECT_EQ("#include \"a.h\"\n" 286 "#include \"c.h\"\n" 287 "\n" 288 "#include <b.h>\n" 289 "#include <d.h>\n", 290 sort("#include <d.h>\n" 291 "#include <b.h>\n" 292 "#include \"c.h\"\n" 293 "#include \"a.h\"\n")); 294 } 295 296 TEST_F(SortIncludesTest, HandlesMultilineIncludes) { 297 EXPECT_EQ("#include \"a.h\"\n" 298 "#include \"b.h\"\n" 299 "#include \"c.h\"\n", 300 sort("#include \"a.h\"\n" 301 "#include \\\n" 302 "\"c.h\"\n" 303 "#include \"b.h\"\n")); 304 } 305 306 TEST_F(SortIncludesTest, LeavesMainHeaderFirst) { 307 Style.IncludeIsMainRegex = "([-_](test|unittest))?$"; 308 EXPECT_EQ("#include \"llvm/a.h\"\n" 309 "#include \"b.h\"\n" 310 "#include \"c.h\"\n", 311 sort("#include \"llvm/a.h\"\n" 312 "#include \"c.h\"\n" 313 "#include \"b.h\"\n", 314 "a.cc")); 315 EXPECT_EQ("#include \"llvm/a.h\"\n" 316 "#include \"b.h\"\n" 317 "#include \"c.h\"\n", 318 sort("#include \"llvm/a.h\"\n" 319 "#include \"c.h\"\n" 320 "#include \"b.h\"\n", 321 "a_test.cc")); 322 EXPECT_EQ("#include \"llvm/input.h\"\n" 323 "#include \"b.h\"\n" 324 "#include \"c.h\"\n", 325 sort("#include \"llvm/input.h\"\n" 326 "#include \"c.h\"\n" 327 "#include \"b.h\"\n", 328 "input.mm")); 329 330 // Don't allow prefixes. 331 EXPECT_EQ("#include \"b.h\"\n" 332 "#include \"c.h\"\n" 333 "#include \"llvm/not_a.h\"\n", 334 sort("#include \"llvm/not_a.h\"\n" 335 "#include \"c.h\"\n" 336 "#include \"b.h\"\n", 337 "a.cc")); 338 339 // Don't do this for _main and other suffixes. 340 EXPECT_EQ("#include \"b.h\"\n" 341 "#include \"c.h\"\n" 342 "#include \"llvm/a.h\"\n", 343 sort("#include \"llvm/a.h\"\n" 344 "#include \"c.h\"\n" 345 "#include \"b.h\"\n", 346 "a_main.cc")); 347 348 // Don't do this in headers. 349 EXPECT_EQ("#include \"b.h\"\n" 350 "#include \"c.h\"\n" 351 "#include \"llvm/a.h\"\n", 352 sort("#include \"llvm/a.h\"\n" 353 "#include \"c.h\"\n" 354 "#include \"b.h\"\n", 355 "a.h")); 356 357 // Only do this in the first #include block. 358 EXPECT_EQ("#include <a>\n" 359 "\n" 360 "#include \"b.h\"\n" 361 "#include \"c.h\"\n" 362 "#include \"llvm/a.h\"\n", 363 sort("#include <a>\n" 364 "\n" 365 "#include \"llvm/a.h\"\n" 366 "#include \"c.h\"\n" 367 "#include \"b.h\"\n", 368 "a.cc")); 369 370 // Only recognize the first #include with a matching basename as main include. 371 EXPECT_EQ("#include \"a.h\"\n" 372 "#include \"b.h\"\n" 373 "#include \"c.h\"\n" 374 "#include \"llvm/a.h\"\n", 375 sort("#include \"b.h\"\n" 376 "#include \"a.h\"\n" 377 "#include \"c.h\"\n" 378 "#include \"llvm/a.h\"\n", 379 "a.cc")); 380 } 381 382 TEST_F(SortIncludesTest, RecognizeMainHeaderInAllGroups) { 383 Style.IncludeIsMainRegex = "([-_](test|unittest))?$"; 384 Style.IncludeBlocks = tooling::IncludeStyle::IBS_Merge; 385 386 EXPECT_EQ("#include \"c.h\"\n" 387 "#include \"a.h\"\n" 388 "#include \"b.h\"\n", 389 sort("#include \"b.h\"\n" 390 "\n" 391 "#include \"a.h\"\n" 392 "#include \"c.h\"\n", 393 "c.cc")); 394 } 395 396 TEST_F(SortIncludesTest, MainHeaderIsSeparatedWhenRegroupping) { 397 Style.IncludeIsMainRegex = "([-_](test|unittest))?$"; 398 Style.IncludeBlocks = tooling::IncludeStyle::IBS_Regroup; 399 400 EXPECT_EQ("#include \"a.h\"\n" 401 "\n" 402 "#include \"b.h\"\n" 403 "#include \"c.h\"\n", 404 sort("#include \"b.h\"\n" 405 "\n" 406 "#include \"a.h\"\n" 407 "#include \"c.h\"\n", 408 "a.cc")); 409 } 410 411 TEST_F(SortIncludesTest, SupportCaseInsensitiveMatching) { 412 // Setup an regex for main includes so we can cover those as well. 413 Style.IncludeIsMainRegex = "([-_](test|unittest))?$"; 414 415 // Ensure both main header detection and grouping work in a case insensitive 416 // manner. 417 EXPECT_EQ("#include \"llvm/A.h\"\n" 418 "#include \"b.h\"\n" 419 "#include \"c.h\"\n" 420 "#include \"LLVM/z.h\"\n" 421 "#include \"llvm/X.h\"\n" 422 "#include \"GTest/GTest.h\"\n" 423 "#include \"gmock/gmock.h\"\n", 424 sort("#include \"c.h\"\n" 425 "#include \"b.h\"\n" 426 "#include \"GTest/GTest.h\"\n" 427 "#include \"llvm/A.h\"\n" 428 "#include \"gmock/gmock.h\"\n" 429 "#include \"llvm/X.h\"\n" 430 "#include \"LLVM/z.h\"\n", 431 "a_TEST.cc")); 432 } 433 434 TEST_F(SortIncludesTest, NegativePriorities) { 435 Style.IncludeCategories = {{".*important_os_header.*", -1}, {".*", 1}}; 436 EXPECT_EQ("#include \"important_os_header.h\"\n" 437 "#include \"c_main.h\"\n" 438 "#include \"a_other.h\"\n", 439 sort("#include \"c_main.h\"\n" 440 "#include \"a_other.h\"\n" 441 "#include \"important_os_header.h\"\n", 442 "c_main.cc")); 443 444 // check stable when re-run 445 EXPECT_EQ("#include \"important_os_header.h\"\n" 446 "#include \"c_main.h\"\n" 447 "#include \"a_other.h\"\n", 448 sort("#include \"important_os_header.h\"\n" 449 "#include \"c_main.h\"\n" 450 "#include \"a_other.h\"\n", 451 "c_main.cc")); 452 } 453 454 TEST_F(SortIncludesTest, PriorityGroupsAreSeparatedWhenRegroupping) { 455 Style.IncludeCategories = {{".*important_os_header.*", -1}, {".*", 1}}; 456 Style.IncludeBlocks = tooling::IncludeStyle::IBS_Regroup; 457 458 EXPECT_EQ("#include \"important_os_header.h\"\n" 459 "\n" 460 "#include \"c_main.h\"\n" 461 "\n" 462 "#include \"a_other.h\"\n", 463 sort("#include \"c_main.h\"\n" 464 "#include \"a_other.h\"\n" 465 "#include \"important_os_header.h\"\n", 466 "c_main.cc")); 467 468 // check stable when re-run 469 EXPECT_EQ("#include \"important_os_header.h\"\n" 470 "\n" 471 "#include \"c_main.h\"\n" 472 "\n" 473 "#include \"a_other.h\"\n", 474 sort("#include \"important_os_header.h\"\n" 475 "\n" 476 "#include \"c_main.h\"\n" 477 "\n" 478 "#include \"a_other.h\"\n", 479 "c_main.cc")); 480 } 481 482 TEST_F(SortIncludesTest, CalculatesCorrectCursorPosition) { 483 std::string Code = "#include <ccc>\n" // Start of line: 0 484 "#include <bbbbbb>\n" // Start of line: 15 485 "#include <a>\n"; // Start of line: 33 486 EXPECT_EQ(31u, newCursor(Code, 0)); 487 EXPECT_EQ(13u, newCursor(Code, 15)); 488 EXPECT_EQ(0u, newCursor(Code, 33)); 489 490 EXPECT_EQ(41u, newCursor(Code, 10)); 491 EXPECT_EQ(23u, newCursor(Code, 25)); 492 EXPECT_EQ(10u, newCursor(Code, 43)); 493 } 494 495 TEST_F(SortIncludesTest, DeduplicateIncludes) { 496 EXPECT_EQ("#include <a>\n" 497 "#include <b>\n" 498 "#include <c>\n", 499 sort("#include <a>\n" 500 "#include <b>\n" 501 "#include <b>\n" 502 "#include <b>\n" 503 "#include <b>\n" 504 "#include <c>\n")); 505 506 Style.IncludeBlocks = tooling::IncludeStyle::IBS_Merge; 507 EXPECT_EQ("#include <a>\n" 508 "#include <b>\n" 509 "#include <c>\n", 510 sort("#include <a>\n" 511 "#include <b>\n" 512 "\n" 513 "#include <b>\n" 514 "\n" 515 "#include <b>\n" 516 "#include <c>\n")); 517 518 Style.IncludeBlocks = tooling::IncludeStyle::IBS_Regroup; 519 EXPECT_EQ("#include <a>\n" 520 "#include <b>\n" 521 "#include <c>\n", 522 sort("#include <a>\n" 523 "#include <b>\n" 524 "\n" 525 "#include <b>\n" 526 "\n" 527 "#include <b>\n" 528 "#include <c>\n")); 529 } 530 531 TEST_F(SortIncludesTest, SortAndDeduplicateIncludes) { 532 EXPECT_EQ("#include <a>\n" 533 "#include <b>\n" 534 "#include <c>\n", 535 sort("#include <b>\n" 536 "#include <a>\n" 537 "#include <b>\n" 538 "#include <b>\n" 539 "#include <c>\n" 540 "#include <b>\n")); 541 542 Style.IncludeBlocks = tooling::IncludeStyle::IBS_Merge; 543 EXPECT_EQ("#include <a>\n" 544 "#include <b>\n" 545 "#include <c>\n", 546 sort("#include <b>\n" 547 "#include <a>\n" 548 "\n" 549 "#include <b>\n" 550 "\n" 551 "#include <c>\n" 552 "#include <b>\n")); 553 554 Style.IncludeBlocks = tooling::IncludeStyle::IBS_Regroup; 555 EXPECT_EQ("#include <a>\n" 556 "#include <b>\n" 557 "#include <c>\n", 558 sort("#include <b>\n" 559 "#include <a>\n" 560 "\n" 561 "#include <b>\n" 562 "\n" 563 "#include <c>\n" 564 "#include <b>\n")); 565 } 566 567 TEST_F(SortIncludesTest, CalculatesCorrectCursorPositionAfterDeduplicate) { 568 std::string Code = "#include <b>\n" // Start of line: 0 569 "#include <a>\n" // Start of line: 13 570 "#include <b>\n" // Start of line: 26 571 "#include <b>\n" // Start of line: 39 572 "#include <c>\n" // Start of line: 52 573 "#include <b>\n"; // Start of line: 65 574 std::string Expected = "#include <a>\n" // Start of line: 0 575 "#include <b>\n" // Start of line: 13 576 "#include <c>\n"; // Start of line: 26 577 EXPECT_EQ(Expected, sort(Code)); 578 // Cursor on 'i' in "#include <a>". 579 EXPECT_EQ(1u, newCursor(Code, 14)); 580 // Cursor on 'b' in "#include <b>". 581 EXPECT_EQ(23u, newCursor(Code, 10)); 582 EXPECT_EQ(23u, newCursor(Code, 36)); 583 EXPECT_EQ(23u, newCursor(Code, 49)); 584 EXPECT_EQ(23u, newCursor(Code, 36)); 585 EXPECT_EQ(23u, newCursor(Code, 75)); 586 // Cursor on '#' in "#include <c>". 587 EXPECT_EQ(26u, newCursor(Code, 52)); 588 } 589 590 TEST_F(SortIncludesTest, DeduplicateLocallyInEachBlock) { 591 EXPECT_EQ("#include <a>\n" 592 "#include <b>\n" 593 "\n" 594 "#include <b>\n" 595 "#include <c>\n", 596 sort("#include <a>\n" 597 "#include <b>\n" 598 "\n" 599 "#include <c>\n" 600 "#include <b>\n" 601 "#include <b>\n")); 602 } 603 604 TEST_F(SortIncludesTest, ValidAffactedRangesAfterDeduplicatingIncludes) { 605 std::string Code = "#include <a>\n" 606 "#include <b>\n" 607 "#include <a>\n" 608 "#include <a>\n" 609 "\n" 610 " int x ;"; 611 std::vector<tooling::Range> Ranges = {tooling::Range(0, 52)}; 612 auto Replaces = sortIncludes(FmtStyle, Code, Ranges, "input.cpp"); 613 Ranges = tooling::calculateRangesAfterReplacements(Replaces, Ranges); 614 EXPECT_EQ(1u, Ranges.size()); 615 EXPECT_EQ(0u, Ranges[0].getOffset()); 616 EXPECT_EQ(26u, Ranges[0].getLength()); 617 } 618 619 TEST_F(SortIncludesTest, DoNotSortLikelyXml) { 620 EXPECT_EQ("<!--;\n" 621 "#include <b>\n" 622 "#include <a>\n" 623 "-->", 624 sort("<!--;\n" 625 "#include <b>\n" 626 "#include <a>\n" 627 "-->")); 628 } 629 630 } // end namespace 631 } // end namespace format 632 } // end namespace clang 633