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