1 //===- unittest/Format/CleanupTest.cpp - Code cleanup 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 "clang/Format/Format.h" 11 12 #include "../Tooling/ReplacementTest.h" 13 #include "../Tooling/RewriterTestContext.h" 14 #include "clang/Tooling/Core/Replacement.h" 15 16 #include "gtest/gtest.h" 17 18 using clang::tooling::ReplacementTest; 19 using clang::tooling::toReplacements; 20 21 namespace clang { 22 namespace format { 23 namespace { 24 25 class CleanupTest : public ::testing::Test { 26 protected: 27 std::string cleanup(llvm::StringRef Code, 28 const std::vector<tooling::Range> &Ranges, 29 const FormatStyle &Style = getLLVMStyle()) { 30 tooling::Replacements Replaces = format::cleanup(Style, Code, Ranges); 31 32 auto Result = applyAllReplacements(Code, Replaces); 33 EXPECT_TRUE(static_cast<bool>(Result)); 34 return *Result; 35 } 36 37 // Returns code after cleanup around \p Offsets. 38 std::string cleanupAroundOffsets(llvm::ArrayRef<unsigned> Offsets, 39 llvm::StringRef Code) { 40 std::vector<tooling::Range> Ranges; 41 for (auto Offset : Offsets) 42 Ranges.push_back(tooling::Range(Offset, 0)); 43 return cleanup(Code, Ranges); 44 } 45 }; 46 47 TEST_F(CleanupTest, DeleteEmptyNamespaces) { 48 std::string Code = "namespace A {\n" 49 "namespace B {\n" 50 "} // namespace B\n" 51 "} // namespace A\n\n" 52 "namespace C {\n" 53 "namespace D { int i; }\n" 54 "inline namespace E { namespace { } }\n" 55 "}"; 56 std::string Expected = "\n\n\n\n\nnamespace C {\n" 57 "namespace D { int i; }\n \n" 58 "}"; 59 EXPECT_EQ(Expected, cleanupAroundOffsets({28, 91, 132}, Code)); 60 } 61 62 TEST_F(CleanupTest, NamespaceWithSyntaxError) { 63 std::string Code = "namespace A {\n" 64 "namespace B {\n" // missing r_brace 65 "} // namespace A\n\n" 66 "namespace C {\n" 67 "namespace D int i; }\n" 68 "inline namespace E { namespace { } }\n" 69 "}"; 70 std::string Expected = "namespace A {\n" 71 "\n\n\nnamespace C {\n" 72 "namespace D int i; }\n \n" 73 "}"; 74 std::vector<tooling::Range> Ranges(1, tooling::Range(0, Code.size())); 75 EXPECT_EQ(Expected, cleanup(Code, Ranges)); 76 } 77 78 TEST_F(CleanupTest, EmptyNamespaceNotAffected) { 79 std::string Code = "namespace A {\n\n" 80 "namespace {\n\n}}"; 81 // Even though the namespaces are empty, but the inner most empty namespace 82 // block is not affected by the changed ranges. 83 std::string Expected = "namespace A {\n\n" 84 "namespace {\n\n}}"; 85 // Set the changed range to be the second "\n". 86 EXPECT_EQ(Expected, cleanupAroundOffsets({14}, Code)); 87 } 88 89 TEST_F(CleanupTest, EmptyNamespaceWithCommentsNoBreakBeforeBrace) { 90 std::string Code = "namespace A {\n" 91 "namespace B {\n" 92 "// Yo\n" 93 "} // namespace B\n" 94 "} // namespace A\n" 95 "namespace C { // Yo\n" 96 "}"; 97 std::string Expected = "\n\n\n\n\n\n"; 98 std::vector<tooling::Range> Ranges(1, tooling::Range(0, Code.size())); 99 std::string Result = cleanup(Code, Ranges); 100 EXPECT_EQ(Expected, Result); 101 } 102 103 TEST_F(CleanupTest, EmptyNamespaceWithCommentsBreakBeforeBrace) { 104 std::string Code = "namespace A\n" 105 "/* Yo */ {\n" 106 "namespace B\n" 107 "{\n" 108 "// Yo\n" 109 "} // namespace B\n" 110 "} // namespace A\n" 111 "namespace C\n" 112 "{ // Yo\n" 113 "}\n"; 114 std::string Expected = "\n\n\n\n\n\n\n\n\n\n"; 115 std::vector<tooling::Range> Ranges(1, tooling::Range(0, Code.size())); 116 FormatStyle Style = getLLVMStyle(); 117 Style.BraceWrapping.AfterNamespace = true; 118 std::string Result = cleanup(Code, Ranges, Style); 119 EXPECT_EQ(Expected, Result); 120 } 121 122 TEST_F(CleanupTest, CtorInitializationSimpleRedundantComma) { 123 std::string Code = "class A {\nA() : , {} };"; 124 std::string Expected = "class A {\nA() {} };"; 125 EXPECT_EQ(Expected, cleanupAroundOffsets({17, 19}, Code)); 126 127 Code = "class A {\nA() : x(1), {} };"; 128 Expected = "class A {\nA() : x(1) {} };"; 129 EXPECT_EQ(Expected, cleanupAroundOffsets({23}, Code)); 130 131 Code = "class A {\nA() :,,,,{} };"; 132 Expected = "class A {\nA() {} };"; 133 EXPECT_EQ(Expected, cleanupAroundOffsets({15}, Code)); 134 } 135 136 TEST_F(CleanupTest, ListRedundantComma) { 137 std::string Code = "void f() { std::vector<int> v = {1,2,,,3,{4,5}}; }"; 138 std::string Expected = "void f() { std::vector<int> v = {1,2,3,{4,5}}; }"; 139 EXPECT_EQ(Expected, cleanupAroundOffsets({40}, Code)); 140 141 Code = "int main() { f(1,,2,3,,4);}"; 142 Expected = "int main() { f(1,2,3,4);}"; 143 EXPECT_EQ(Expected, cleanupAroundOffsets({17, 22}, Code)); 144 } 145 146 TEST_F(CleanupTest, TrailingCommaInParens) { 147 std::string Code = "int main() { f(,1,,2,3,f(1,2,),4,,);}"; 148 std::string Expected = "int main() { f(1,2,3,f(1,2),4);}"; 149 EXPECT_EQ(Expected, cleanupAroundOffsets({15, 18, 29, 33}, Code)); 150 } 151 152 TEST_F(CleanupTest, TrailingCommaInBraces) { 153 // Trainling comma is allowed in brace list. 154 // If there was trailing comma in the original code, then trailing comma is 155 // preserved. In this example, element between the last two commas is deleted 156 // causing the second-last comma to be redundant. 157 std::string Code = "void f() { std::vector<int> v = {1,2,3,,}; }"; 158 std::string Expected = "void f() { std::vector<int> v = {1,2,3,}; }"; 159 EXPECT_EQ(Expected, cleanupAroundOffsets({39}, Code)); 160 161 // If there was no trailing comma in the original code, then trainling comma 162 // introduced by replacements should be cleaned up. In this example, the 163 // element after the last comma is deleted causing the last comma to be 164 // redundant. 165 Code = "void f() { std::vector<int> v = {1,2,3,}; }"; 166 // FIXME: redundant trailing comma should be removed. 167 Expected = "void f() { std::vector<int> v = {1,2,3,}; }"; 168 EXPECT_EQ(Expected, cleanupAroundOffsets({39}, Code)); 169 170 // Still no trailing comma in the original code, but two elements are deleted, 171 // which makes it seems like there was trailing comma. 172 Code = "void f() { std::vector<int> v = {1, 2, 3, , }; }"; 173 // FIXME: redundant trailing comma should also be removed. 174 Expected = "void f() { std::vector<int> v = {1, 2, 3, }; }"; 175 EXPECT_EQ(Expected, cleanupAroundOffsets({42, 44}, Code)); 176 } 177 178 TEST_F(CleanupTest, CtorInitializationBracesInParens) { 179 std::string Code = "class A {\nA() : x({1}),, {} };"; 180 std::string Expected = "class A {\nA() : x({1}) {} };"; 181 EXPECT_EQ(Expected, cleanupAroundOffsets({24, 26}, Code)); 182 } 183 184 TEST_F(CleanupTest, RedundantCommaNotInAffectedRanges) { 185 std::string Code = 186 "class A {\nA() : x({1}), /* comment */, { int x = 0; } };"; 187 std::string Expected = 188 "class A {\nA() : x({1}), /* comment */, { int x = 0; } };"; 189 // Set the affected range to be "int x = 0", which does not intercept the 190 // constructor initialization list. 191 std::vector<tooling::Range> Ranges(1, tooling::Range(42, 9)); 192 std::string Result = cleanup(Code, Ranges); 193 EXPECT_EQ(Expected, Result); 194 195 Code = "class A {\nA() : x(1), {} };"; 196 Expected = "class A {\nA() : x(1), {} };"; 197 // No range. Fixer should do nothing. 198 Ranges.clear(); 199 Result = cleanup(Code, Ranges); 200 EXPECT_EQ(Expected, Result); 201 } 202 203 TEST_F(CleanupTest, RemoveCommentsAroundDeleteCode) { 204 std::string Code = 205 "class A {\nA() : x({1}), /* comment */, /* comment */ {} };"; 206 std::string Expected = "class A {\nA() : x({1}) {} };"; 207 EXPECT_EQ(Expected, cleanupAroundOffsets({25, 40}, Code)); 208 209 Code = "class A {\nA() : x({1}), // comment\n {} };"; 210 Expected = "class A {\nA() : x({1})\n {} };"; 211 EXPECT_EQ(Expected, cleanupAroundOffsets({25}, Code)); 212 213 Code = "class A {\nA() : x({1}), // comment\n , y(1),{} };"; 214 Expected = "class A {\nA() : x({1}), y(1){} };"; 215 EXPECT_EQ(Expected, cleanupAroundOffsets({38}, Code)); 216 217 Code = "class A {\nA() : x({1}), \n/* comment */, y(1),{} };"; 218 Expected = "class A {\nA() : x({1}), \n y(1){} };"; 219 EXPECT_EQ(Expected, cleanupAroundOffsets({40}, Code)); 220 221 Code = "class A {\nA() : , // comment\n y(1),{} };"; 222 Expected = "class A {\nA() : // comment\n y(1){} };"; 223 EXPECT_EQ(Expected, cleanupAroundOffsets({17}, Code)); 224 } 225 226 TEST_F(CleanupTest, CtorInitializerInNamespace) { 227 std::string Code = "namespace A {\n" 228 "namespace B {\n" // missing r_brace 229 "} // namespace A\n\n" 230 "namespace C {\n" 231 "class A { A() : x(0),, {} };\n" 232 "inline namespace E { namespace { } }\n" 233 "}"; 234 std::string Expected = "namespace A {\n" 235 "\n\n\nnamespace C {\n" 236 "class A { A() : x(0) {} };\n \n" 237 "}"; 238 std::vector<tooling::Range> Ranges(1, tooling::Range(0, Code.size())); 239 std::string Result = cleanup(Code, Ranges); 240 EXPECT_EQ(Expected, Result); 241 } 242 243 class CleanUpReplacementsTest : public ReplacementTest { 244 protected: 245 tooling::Replacement createReplacement(unsigned Offset, unsigned Length, 246 StringRef Text) { 247 return tooling::Replacement(FileName, Offset, Length, Text); 248 } 249 250 tooling::Replacement createInsertion(StringRef IncludeDirective) { 251 return createReplacement(UINT_MAX, 0, IncludeDirective); 252 } 253 254 tooling::Replacement createDeletion(StringRef HeaderName) { 255 return createReplacement(UINT_MAX, 1, HeaderName); 256 } 257 258 inline std::string apply(StringRef Code, 259 const tooling::Replacements Replaces) { 260 auto CleanReplaces = cleanupAroundReplacements(Code, Replaces, Style); 261 EXPECT_TRUE(static_cast<bool>(CleanReplaces)) 262 << llvm::toString(CleanReplaces.takeError()) << "\n"; 263 auto Result = applyAllReplacements(Code, *CleanReplaces); 264 EXPECT_TRUE(static_cast<bool>(Result)); 265 return *Result; 266 } 267 268 inline std::string formatAndApply(StringRef Code, 269 const tooling::Replacements Replaces) { 270 271 auto CleanReplaces = cleanupAroundReplacements(Code, Replaces, Style); 272 EXPECT_TRUE(static_cast<bool>(CleanReplaces)) 273 << llvm::toString(CleanReplaces.takeError()) << "\n"; 274 auto FormattedReplaces = formatReplacements(Code, *CleanReplaces, Style); 275 EXPECT_TRUE(static_cast<bool>(FormattedReplaces)) 276 << llvm::toString(FormattedReplaces.takeError()) << "\n"; 277 auto Result = applyAllReplacements(Code, *FormattedReplaces); 278 EXPECT_TRUE(static_cast<bool>(Result)); 279 return *Result; 280 } 281 282 int getOffset(StringRef Code, int Line, int Column) { 283 RewriterTestContext Context; 284 FileID ID = Context.createInMemoryFile(FileName, Code); 285 auto DecomposedLocation = 286 Context.Sources.getDecomposedLoc(Context.getLocation(ID, Line, Column)); 287 return DecomposedLocation.second; 288 } 289 290 const std::string FileName = "fix.cpp"; 291 FormatStyle Style = getLLVMStyle(); 292 }; 293 294 TEST_F(CleanUpReplacementsTest, FixOnlyAffectedCodeAfterReplacements) { 295 std::string Code = "namespace A {\n" 296 "namespace B {\n" 297 " int x;\n" 298 "} // namespace B\n" 299 "} // namespace A\n" 300 "\n" 301 "namespace C {\n" 302 "namespace D { int i; }\n" 303 "inline namespace E { namespace { int y; } }\n" 304 "int x= 0;" 305 "}"; 306 std::string Expected = "\n\nnamespace C {\n" 307 "namespace D { int i; }\n\n" 308 "int x= 0;" 309 "}"; 310 tooling::Replacements Replaces = 311 toReplacements({createReplacement(getOffset(Code, 3, 3), 6, ""), 312 createReplacement(getOffset(Code, 9, 34), 6, "")}); 313 314 EXPECT_EQ(Expected, formatAndApply(Code, Replaces)); 315 } 316 317 TEST_F(CleanUpReplacementsTest, NoExistingIncludeWithoutDefine) { 318 std::string Code = "int main() {}"; 319 std::string Expected = "#include \"a.h\"\n" 320 "int main() {}"; 321 tooling::Replacements Replaces = 322 toReplacements({createInsertion("#include \"a.h\"")}); 323 EXPECT_EQ(Expected, apply(Code, Replaces)); 324 } 325 326 TEST_F(CleanUpReplacementsTest, NoExistingIncludeWithDefine) { 327 std::string Code = "#ifndef A_H\n" 328 "#define A_H\n" 329 "class A {};\n" 330 "#define MMM 123\n" 331 "#endif"; 332 std::string Expected = "#ifndef A_H\n" 333 "#define A_H\n" 334 "#include \"b.h\"\n" 335 "class A {};\n" 336 "#define MMM 123\n" 337 "#endif"; 338 339 tooling::Replacements Replaces = 340 toReplacements({createInsertion("#include \"b.h\"")}); 341 EXPECT_EQ(Expected, apply(Code, Replaces)); 342 } 343 344 TEST_F(CleanUpReplacementsTest, InsertBeforeCategoryWithLowerPriority) { 345 std::string Code = "#ifndef A_H\n" 346 "#define A_H\n" 347 "\n" 348 "\n" 349 "\n" 350 "#include <vector>\n" 351 "class A {};\n" 352 "#define MMM 123\n" 353 "#endif"; 354 std::string Expected = "#ifndef A_H\n" 355 "#define A_H\n" 356 "\n" 357 "\n" 358 "\n" 359 "#include \"a.h\"\n" 360 "#include <vector>\n" 361 "class A {};\n" 362 "#define MMM 123\n" 363 "#endif"; 364 365 tooling::Replacements Replaces = 366 toReplacements({createInsertion("#include \"a.h\"")}); 367 EXPECT_EQ(Expected, apply(Code, Replaces)); 368 } 369 370 TEST_F(CleanUpReplacementsTest, InsertAfterMainHeader) { 371 std::string Code = "#include \"fix.h\"\n" 372 "\n" 373 "int main() {}"; 374 std::string Expected = "#include \"fix.h\"\n" 375 "#include <a>\n" 376 "\n" 377 "int main() {}"; 378 tooling::Replacements Replaces = 379 toReplacements({createInsertion("#include <a>")}); 380 Style = format::getGoogleStyle(format::FormatStyle::LanguageKind::LK_Cpp); 381 EXPECT_EQ(Expected, apply(Code, Replaces)); 382 } 383 384 TEST_F(CleanUpReplacementsTest, InsertBeforeSystemHeaderLLVM) { 385 std::string Code = "#include <memory>\n" 386 "\n" 387 "int main() {}"; 388 std::string Expected = "#include \"z.h\"\n" 389 "#include <memory>\n" 390 "\n" 391 "int main() {}"; 392 tooling::Replacements Replaces = 393 toReplacements({createInsertion("#include \"z.h\"")}); 394 EXPECT_EQ(Expected, apply(Code, Replaces)); 395 } 396 397 TEST_F(CleanUpReplacementsTest, InsertAfterSystemHeaderGoogle) { 398 std::string Code = "#include <memory>\n" 399 "\n" 400 "int main() {}"; 401 std::string Expected = "#include <memory>\n" 402 "#include \"z.h\"\n" 403 "\n" 404 "int main() {}"; 405 tooling::Replacements Replaces = 406 toReplacements({createInsertion("#include \"z.h\"")}); 407 Style = format::getGoogleStyle(format::FormatStyle::LanguageKind::LK_Cpp); 408 EXPECT_EQ(Expected, apply(Code, Replaces)); 409 } 410 411 TEST_F(CleanUpReplacementsTest, InsertOneIncludeLLVMStyle) { 412 std::string Code = "#include \"x/fix.h\"\n" 413 "#include \"a.h\"\n" 414 "#include \"b.h\"\n" 415 "#include \"clang/Format/Format.h\"\n" 416 "#include <memory>\n"; 417 std::string Expected = "#include \"x/fix.h\"\n" 418 "#include \"a.h\"\n" 419 "#include \"b.h\"\n" 420 "#include \"d.h\"\n" 421 "#include \"clang/Format/Format.h\"\n" 422 "#include \"llvm/x/y.h\"\n" 423 "#include <memory>\n"; 424 tooling::Replacements Replaces = 425 toReplacements({createInsertion("#include \"d.h\""), 426 createInsertion("#include \"llvm/x/y.h\"")}); 427 EXPECT_EQ(Expected, apply(Code, Replaces)); 428 } 429 430 TEST_F(CleanUpReplacementsTest, InsertMultipleIncludesLLVMStyle) { 431 std::string Code = "#include \"x/fix.h\"\n" 432 "#include \"a.h\"\n" 433 "#include \"b.h\"\n" 434 "#include \"clang/Format/Format.h\"\n" 435 "#include <memory>\n"; 436 std::string Expected = "#include \"x/fix.h\"\n" 437 "#include \"a.h\"\n" 438 "#include \"b.h\"\n" 439 "#include \"new/new.h\"\n" 440 "#include \"clang/Format/Format.h\"\n" 441 "#include <memory>\n" 442 "#include <list>\n"; 443 tooling::Replacements Replaces = 444 toReplacements({createInsertion("#include <list>"), 445 createInsertion("#include \"new/new.h\"")}); 446 EXPECT_EQ(Expected, apply(Code, Replaces)); 447 } 448 449 TEST_F(CleanUpReplacementsTest, InsertNewSystemIncludeGoogleStyle) { 450 std::string Code = "#include \"x/fix.h\"\n" 451 "\n" 452 "#include \"y/a.h\"\n" 453 "#include \"z/b.h\"\n"; 454 // FIXME: inserting after the empty line following the main header might be 455 // prefered. 456 std::string Expected = "#include \"x/fix.h\"\n" 457 "#include <vector>\n" 458 "\n" 459 "#include \"y/a.h\"\n" 460 "#include \"z/b.h\"\n"; 461 tooling::Replacements Replaces = 462 toReplacements({createInsertion("#include <vector>")}); 463 Style = format::getGoogleStyle(format::FormatStyle::LanguageKind::LK_Cpp); 464 EXPECT_EQ(Expected, apply(Code, Replaces)); 465 } 466 467 TEST_F(CleanUpReplacementsTest, InsertMultipleIncludesGoogleStyle) { 468 std::string Code = "#include \"x/fix.h\"\n" 469 "\n" 470 "#include <vector>\n" 471 "\n" 472 "#include \"y/a.h\"\n" 473 "#include \"z/b.h\"\n"; 474 std::string Expected = "#include \"x/fix.h\"\n" 475 "\n" 476 "#include <vector>\n" 477 "#include <list>\n" 478 "\n" 479 "#include \"y/a.h\"\n" 480 "#include \"z/b.h\"\n" 481 "#include \"x/x.h\"\n"; 482 tooling::Replacements Replaces = 483 toReplacements({createInsertion("#include <list>"), 484 createInsertion("#include \"x/x.h\"")}); 485 Style = format::getGoogleStyle(format::FormatStyle::LanguageKind::LK_Cpp); 486 EXPECT_EQ(Expected, apply(Code, Replaces)); 487 } 488 489 TEST_F(CleanUpReplacementsTest, InsertMultipleNewHeadersAndSortLLVM) { 490 std::string Code = "\nint x;"; 491 std::string Expected = "\n#include \"fix.h\"\n" 492 "#include \"a.h\"\n" 493 "#include \"b.h\"\n" 494 "#include \"c.h\"\n" 495 "#include <list>\n" 496 "#include <vector>\n" 497 "int x;"; 498 tooling::Replacements Replaces = toReplacements( 499 {createInsertion("#include \"a.h\""), createInsertion("#include \"c.h\""), 500 createInsertion("#include \"b.h\""), 501 createInsertion("#include <vector>"), createInsertion("#include <list>"), 502 createInsertion("#include \"fix.h\"")}); 503 EXPECT_EQ(Expected, formatAndApply(Code, Replaces)); 504 } 505 506 TEST_F(CleanUpReplacementsTest, InsertMultipleNewHeadersAndSortGoogle) { 507 std::string Code = "\nint x;"; 508 std::string Expected = "\n#include \"fix.h\"\n" 509 "#include <list>\n" 510 "#include <vector>\n" 511 "#include \"a.h\"\n" 512 "#include \"b.h\"\n" 513 "#include \"c.h\"\n" 514 "int x;"; 515 tooling::Replacements Replaces = toReplacements( 516 {createInsertion("#include \"a.h\""), createInsertion("#include \"c.h\""), 517 createInsertion("#include \"b.h\""), 518 createInsertion("#include <vector>"), createInsertion("#include <list>"), 519 createInsertion("#include \"fix.h\"")}); 520 Style = format::getGoogleStyle(format::FormatStyle::LanguageKind::LK_Cpp); 521 EXPECT_EQ(Expected, formatAndApply(Code, Replaces)); 522 } 523 524 TEST_F(CleanUpReplacementsTest, FormatCorrectLineWhenHeadersAreInserted) { 525 std::string Code = "\n" 526 "int x;\n" 527 "int a;\n" 528 "int a;\n" 529 "int a;"; 530 531 std::string Expected = "\n#include \"x.h\"\n" 532 "#include \"y.h\"\n" 533 "#include \"clang/x/x.h\"\n" 534 "#include <list>\n" 535 "#include <vector>\n" 536 "int x;\n" 537 "int a;\n" 538 "int b;\n" 539 "int a;"; 540 tooling::Replacements Replaces = toReplacements( 541 {createReplacement(getOffset(Code, 4, 8), 1, "b"), 542 createInsertion("#include <vector>"), createInsertion("#include <list>"), 543 createInsertion("#include \"clang/x/x.h\""), 544 createInsertion("#include \"y.h\""), 545 createInsertion("#include \"x.h\"")}); 546 EXPECT_EQ(Expected, formatAndApply(Code, Replaces)); 547 } 548 549 TEST_F(CleanUpReplacementsTest, NotConfusedByDefine) { 550 std::string Code = "void f() {}\n" 551 "#define A \\\n" 552 " int i;"; 553 std::string Expected = "#include <vector>\n" 554 "void f() {}\n" 555 "#define A \\\n" 556 " int i;"; 557 tooling::Replacements Replaces = 558 toReplacements({createInsertion("#include <vector>")}); 559 EXPECT_EQ(Expected, formatAndApply(Code, Replaces)); 560 } 561 562 TEST_F(CleanUpReplacementsTest, SkippedTopComment) { 563 std::string Code = "// comment\n" 564 "\n" 565 " // comment\n"; 566 std::string Expected = "// comment\n" 567 "\n" 568 " // comment\n" 569 "#include <vector>\n"; 570 tooling::Replacements Replaces = 571 toReplacements({createInsertion("#include <vector>")}); 572 EXPECT_EQ(Expected, apply(Code, Replaces)); 573 } 574 575 TEST_F(CleanUpReplacementsTest, SkippedMixedComments) { 576 std::string Code = "// comment\n" 577 "// comment \\\n" 578 " comment continued\n" 579 "/*\n" 580 "* comment\n" 581 "*/\n"; 582 std::string Expected = "// comment\n" 583 "// comment \\\n" 584 " comment continued\n" 585 "/*\n" 586 "* comment\n" 587 "*/\n" 588 "#include <vector>\n"; 589 tooling::Replacements Replaces = 590 toReplacements({createInsertion("#include <vector>")}); 591 EXPECT_EQ(Expected, apply(Code, Replaces)); 592 } 593 594 TEST_F(CleanUpReplacementsTest, MultipleBlockCommentsInOneLine) { 595 std::string Code = "/*\n" 596 "* comment\n" 597 "*/ /* comment\n" 598 "*/\n" 599 "\n\n" 600 "/* c1 */ /*c2 */\n"; 601 std::string Expected = "/*\n" 602 "* comment\n" 603 "*/ /* comment\n" 604 "*/\n" 605 "\n\n" 606 "/* c1 */ /*c2 */\n" 607 "#include <vector>\n"; 608 tooling::Replacements Replaces = 609 toReplacements({createInsertion("#include <vector>")}); 610 EXPECT_EQ(Expected, apply(Code, Replaces)); 611 } 612 613 TEST_F(CleanUpReplacementsTest, CodeAfterComments) { 614 std::string Code = "/*\n" 615 "* comment\n" 616 "*/ /* comment\n" 617 "*/\n" 618 "\n\n" 619 "/* c1 */ /*c2 */\n" 620 "\n" 621 "int x;\n"; 622 std::string Expected = "/*\n" 623 "* comment\n" 624 "*/ /* comment\n" 625 "*/\n" 626 "\n\n" 627 "/* c1 */ /*c2 */\n" 628 "\n" 629 "#include <vector>\n" 630 "int x;\n"; 631 tooling::Replacements Replaces = 632 toReplacements({createInsertion("#include <vector>")}); 633 EXPECT_EQ(Expected, apply(Code, Replaces)); 634 } 635 636 TEST_F(CleanUpReplacementsTest, FakeHeaderGuardIfDef) { 637 std::string Code = "// comment \n" 638 "#ifdef X\n" 639 "#define X\n"; 640 std::string Expected = "// comment \n" 641 "#include <vector>\n" 642 "#ifdef X\n" 643 "#define X\n"; 644 tooling::Replacements Replaces = 645 toReplacements({createInsertion("#include <vector>")}); 646 EXPECT_EQ(Expected, apply(Code, Replaces)); 647 } 648 649 TEST_F(CleanUpReplacementsTest, RealHeaderGuardAfterComments) { 650 std::string Code = "// comment \n" 651 "#ifndef X\n" 652 "#define X\n" 653 "int x;\n" 654 "#define Y 1\n"; 655 std::string Expected = "// comment \n" 656 "#ifndef X\n" 657 "#define X\n" 658 "#include <vector>\n" 659 "int x;\n" 660 "#define Y 1\n"; 661 tooling::Replacements Replaces = 662 toReplacements({createInsertion("#include <vector>")}); 663 EXPECT_EQ(Expected, apply(Code, Replaces)); 664 } 665 666 TEST_F(CleanUpReplacementsTest, IfNDefWithNoDefine) { 667 std::string Code = "// comment \n" 668 "#ifndef X\n" 669 "int x;\n" 670 "#define Y 1\n"; 671 std::string Expected = "// comment \n" 672 "#include <vector>\n" 673 "#ifndef X\n" 674 "int x;\n" 675 "#define Y 1\n"; 676 tooling::Replacements Replaces = 677 toReplacements({createInsertion("#include <vector>")}); 678 EXPECT_EQ(Expected, apply(Code, Replaces)); 679 } 680 681 TEST_F(CleanUpReplacementsTest, HeaderGuardWithComment) { 682 std::string Code = "// comment \n" 683 "#ifndef X // comment\n" 684 "// comment\n" 685 "/* comment\n" 686 "*/\n" 687 "/* comment */ #define X\n" 688 "int x;\n" 689 "#define Y 1\n"; 690 std::string Expected = "// comment \n" 691 "#ifndef X // comment\n" 692 "// comment\n" 693 "/* comment\n" 694 "*/\n" 695 "/* comment */ #define X\n" 696 "#include <vector>\n" 697 "int x;\n" 698 "#define Y 1\n"; 699 tooling::Replacements Replaces = 700 toReplacements({createInsertion("#include <vector>")}); 701 EXPECT_EQ(Expected, apply(Code, Replaces)); 702 } 703 704 TEST_F(CleanUpReplacementsTest, EmptyCode) { 705 std::string Code = ""; 706 std::string Expected = "#include <vector>\n"; 707 tooling::Replacements Replaces = 708 toReplacements({createInsertion("#include <vector>")}); 709 EXPECT_EQ(Expected, apply(Code, Replaces)); 710 } 711 712 TEST_F(CleanUpReplacementsTest, NoNewLineAtTheEndOfCode) { 713 std::string Code = "#include <map>"; 714 std::string Expected = "#include <map>\n#include <vector>\n"; 715 tooling::Replacements Replaces = 716 toReplacements({createInsertion("#include <vector>")}); 717 EXPECT_EQ(Expected, apply(Code, Replaces)); 718 } 719 720 TEST_F(CleanUpReplacementsTest, NoNewLineAtTheEndOfCodeMultipleInsertions) { 721 std::string Code = "#include <map>"; 722 std::string Expected = 723 "#include <map>\n#include <string>\n#include <vector>\n"; 724 tooling::Replacements Replaces = 725 toReplacements({createInsertion("#include <string>"), 726 createInsertion("#include <vector>")}); 727 EXPECT_EQ(Expected, apply(Code, Replaces)); 728 } 729 730 TEST_F(CleanUpReplacementsTest, SkipExistingHeaders) { 731 std::string Code = "#include \"a.h\"\n" 732 "#include <vector>\n"; 733 std::string Expected = "#include \"a.h\"\n" 734 "#include <vector>\n"; 735 tooling::Replacements Replaces = 736 toReplacements({createInsertion("#include <vector>"), 737 createInsertion("#include \"a.h\"")}); 738 EXPECT_EQ(Expected, apply(Code, Replaces)); 739 } 740 741 TEST_F(CleanUpReplacementsTest, AddIncludesWithDifferentForms) { 742 std::string Code = "#include \"a.h\"\n" 743 "#include <vector>\n"; 744 // FIXME: this might not be the best behavior. 745 std::string Expected = "#include \"a.h\"\n" 746 "#include \"vector\"\n" 747 "#include <vector>\n" 748 "#include <a.h>\n"; 749 tooling::Replacements Replaces = 750 toReplacements({createInsertion("#include \"vector\""), 751 createInsertion("#include <a.h>")}); 752 EXPECT_EQ(Expected, apply(Code, Replaces)); 753 } 754 755 TEST_F(CleanUpReplacementsTest, SimpleDeleteIncludes) { 756 std::string Code = "#include \"abc.h\"\n" 757 "#include \"xyz.h\" // comment\n" 758 "#include \"xyz\"\n" 759 "int x;\n"; 760 std::string Expected = "#include \"xyz\"\n" 761 "int x;\n"; 762 tooling::Replacements Replaces = 763 toReplacements({createDeletion("abc.h"), createDeletion("xyz.h")}); 764 EXPECT_EQ(Expected, apply(Code, Replaces)); 765 } 766 767 TEST_F(CleanUpReplacementsTest, DeleteAllCode) { 768 std::string Code = "#include \"xyz.h\"\n" 769 "#include <xyz.h>"; 770 std::string Expected = ""; 771 tooling::Replacements Replaces = toReplacements({createDeletion("xyz.h")}); 772 EXPECT_EQ(Expected, apply(Code, Replaces)); 773 } 774 775 TEST_F(CleanUpReplacementsTest, DeleteAllIncludesWithSameNameIfNoType) { 776 std::string Code = "#include \"xyz.h\"\n" 777 "#include \"xyz\"\n" 778 "#include <xyz.h>\n"; 779 std::string Expected = "#include \"xyz\"\n"; 780 tooling::Replacements Replaces = toReplacements({createDeletion("xyz.h")}); 781 EXPECT_EQ(Expected, apply(Code, Replaces)); 782 } 783 784 TEST_F(CleanUpReplacementsTest, OnlyDeleteHeaderWithType) { 785 std::string Code = "#include \"xyz.h\"\n" 786 "#include \"xyz\"\n" 787 "#include <xyz.h>"; 788 std::string Expected = "#include \"xyz.h\"\n" 789 "#include \"xyz\"\n"; 790 tooling::Replacements Replaces = toReplacements({createDeletion("<xyz.h>")}); 791 EXPECT_EQ(Expected, apply(Code, Replaces)); 792 } 793 794 TEST_F(CleanUpReplacementsTest, InsertionAndDeleteHeader) { 795 std::string Code = "#include \"a.h\"\n" 796 "\n" 797 "#include <vector>\n"; 798 std::string Expected = "#include \"a.h\"\n" 799 "\n" 800 "#include <map>\n"; 801 tooling::Replacements Replaces = toReplacements( 802 {createDeletion("<vector>"), createInsertion("#include <map>")}); 803 EXPECT_EQ(Expected, apply(Code, Replaces)); 804 } 805 806 } // end namespace 807 } // end namespace format 808 } // end namespace clang 809