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