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