1 //===- unittest/Format/FormatTestCSharp.cpp - Formatting tests for CSharp -===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "FormatTestBase.h" 10 11 #define DEBUG_TYPE "format-test" 12 13 namespace clang { 14 namespace format { 15 namespace test { 16 namespace { 17 18 class FormatTestCSharp : public test::FormatTestBase { 19 protected: 20 FormatStyle getDefaultStyle() const override { 21 return getMicrosoftStyle(FormatStyle::LK_CSharp); 22 } 23 24 static std::string format(StringRef Code, unsigned Offset, unsigned Length, 25 const FormatStyle &Style) { 26 LLVM_DEBUG(llvm::errs() << "---\n"); 27 LLVM_DEBUG(llvm::errs() << Code << "\n\n"); 28 std::vector<tooling::Range> Ranges(1, tooling::Range(Offset, Length)); 29 tooling::Replacements Replaces = reformat(Style, Code, Ranges); 30 auto Result = applyAllReplacements(Code, Replaces); 31 EXPECT_TRUE(static_cast<bool>(Result)); 32 LLVM_DEBUG(llvm::errs() << "\n" << *Result << "\n\n"); 33 return *Result; 34 } 35 36 static std::string 37 format(StringRef Code, 38 const FormatStyle &Style = getMicrosoftStyle(FormatStyle::LK_CSharp)) { 39 return format(Code, 0, Code.size(), Style); 40 } 41 42 static FormatStyle getStyleWithColumns(unsigned ColumnLimit) { 43 FormatStyle Style = getMicrosoftStyle(FormatStyle::LK_CSharp); 44 Style.ColumnLimit = ColumnLimit; 45 return Style; 46 } 47 }; 48 49 TEST_F(FormatTestCSharp, CSharpClass) { 50 verifyFormat("public class SomeClass\n" 51 "{\n" 52 " void f()\n" 53 " {\n" 54 " }\n" 55 " int g()\n" 56 " {\n" 57 " return 0;\n" 58 " }\n" 59 " void h()\n" 60 " {\n" 61 " while (true)\n" 62 " f();\n" 63 " for (;;)\n" 64 " f();\n" 65 " if (true)\n" 66 " f();\n" 67 " }\n" 68 "}"); 69 70 // Ensure that small and empty classes are handled correctly with condensed 71 // (Google C++-like) brace-breaking style. 72 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 73 Style.BreakBeforeBraces = FormatStyle::BS_Attach; 74 75 verifyFormat("public class SomeEmptyClass {}", Style); 76 77 verifyFormat("public class SomeTinyClass {\n" 78 " int X;\n" 79 "}", 80 Style); 81 verifyFormat("private class SomeTinyClass {\n" 82 " int X;\n" 83 "}", 84 Style); 85 verifyFormat("protected class SomeTinyClass {\n" 86 " int X;\n" 87 "}", 88 Style); 89 verifyFormat("internal class SomeTinyClass {\n" 90 " int X;\n" 91 "}", 92 Style); 93 } 94 95 TEST_F(FormatTestCSharp, AccessModifiers) { 96 verifyFormat("public String toString()\n" 97 "{\n" 98 "}"); 99 verifyFormat("private String toString()\n" 100 "{\n" 101 "}"); 102 verifyFormat("protected String toString()\n" 103 "{\n" 104 "}"); 105 verifyFormat("internal String toString()\n" 106 "{\n" 107 "}"); 108 109 verifyFormat("public override String toString()\n" 110 "{\n" 111 "}"); 112 verifyFormat("private override String toString()\n" 113 "{\n" 114 "}"); 115 verifyFormat("protected override String toString()\n" 116 "{\n" 117 "}"); 118 verifyFormat("internal override String toString()\n" 119 "{\n" 120 "}"); 121 122 verifyFormat("internal static String toString()\n" 123 "{\n" 124 "}"); 125 } 126 127 TEST_F(FormatTestCSharp, NoStringLiteralBreaks) { 128 // Breaking of interpolated strings is not implemented. 129 auto Style = getDefaultStyle(); 130 Style.ColumnLimit = 40; 131 Style.BreakStringLiterals = true; 132 verifyFormat("foo(" 133 "$\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 134 "aaaaaaa\");", 135 Style); 136 } 137 138 TEST_F(FormatTestCSharp, StringLiteralBreaks) { 139 // The line is 75 characters long. The default limit for the Microsoft style 140 // is 120. 141 auto Style = getDefaultStyle(); 142 Style.BreakStringLiterals = true; 143 verifyFormat("foo(" 144 "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 145 "aaaaaa\");", 146 Style); 147 // When the column limit is smaller, the string should get broken. 148 Style.ColumnLimit = 40; 149 verifyFormat(R"(foo("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + 150 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + 151 "aaa");)", 152 "foo(" 153 "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 154 "aaaaaa\");", 155 Style); 156 // The new quotes should be the same as the original. 157 verifyFormat(R"(foo(@"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + 158 @"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + 159 @"aaaaa");)", 160 "foo(" 161 "@\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 162 "aaaaaaa\");", 163 Style); 164 // The operators can be on either line. 165 Style.BreakBeforeBinaryOperators = FormatStyle::BOS_NonAssignment; 166 verifyFormat(R"(foo("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 167 + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 168 + "a");)", 169 "foo(" 170 "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 171 "aaaaaa\");", 172 Style); 173 Style.AlignOperands = FormatStyle::OAS_AlignAfterOperator; 174 verifyFormat(R"(foo("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 175 + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 176 + "a");)", 177 "foo(" 178 "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 179 "aaaaaa\");", 180 Style); 181 verifyFormat(R"(x = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 182 + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";)", 183 "x = " 184 "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 185 "aaaaaa\";", 186 Style); 187 } 188 189 TEST_F(FormatTestCSharp, CSharpVerbatiumStringLiterals) { 190 verifyFormat("foo(@\"aaaaaaaa\\abc\\aaaa\");"); 191 // @"ABC\" + ToString("B") - handle embedded \ in literal string at 192 // the end 193 // 194 /* 195 * After removal of Lexer change we are currently not able 196 * To handle these cases 197 verifyFormat("string s = @\"ABC\\\" + ToString(\"B\");"); 198 verifyFormat("string s = @\"ABC\"\"DEF\"\"GHI\""); 199 verifyFormat("string s = @\"ABC\"\"DEF\"\"\""); 200 verifyFormat("string s = @\"ABC\"\"DEF\"\"\" + abc"); 201 */ 202 } 203 204 TEST_F(FormatTestCSharp, CSharpInterpolatedStringLiterals) { 205 verifyFormat("foo($\"aaaaaaaa{aaa}aaaa\");"); 206 verifyFormat("foo($\"aaaa{A}\");"); 207 verifyFormat( 208 "foo($\"aaaa{A}" 209 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\");"); 210 verifyFormat("Name = $\"{firstName} {lastName}\";"); 211 212 // $"ABC\" + ToString("B") - handle embedded \ in literal string at 213 // the end 214 verifyFormat("string s = $\"A{abc}BC\" + ToString(\"B\");"); 215 verifyFormat("$\"{domain}\\\\{user}\""); 216 verifyFormat( 217 "var verbatimInterpolated = $@\"C:\\Users\\{userName}\\Documents\\\";"); 218 } 219 220 TEST_F(FormatTestCSharp, CSharpFatArrows) { 221 verifyIncompleteFormat("Task serverTask = Task.Run(async() => {"); 222 verifyFormat("public override string ToString() => \"{Name}\\{Age}\";"); 223 } 224 225 TEST_F(FormatTestCSharp, CSharpConditionalExpressions) { 226 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 227 // conditional expression is not seen as a NullConditional. 228 verifyFormat("var y = A < B ? -1 : 1;", Style); 229 } 230 231 TEST_F(FormatTestCSharp, CSharpNullConditional) { 232 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 233 Style.SpaceBeforeParens = FormatStyle::SBPO_Always; 234 235 verifyFormat( 236 "public Person(string firstName, string lastName, int? age = null)"); 237 238 verifyFormat("foo () {\n" 239 " switch (args?.Length) {}\n" 240 "}", 241 Style); 242 243 verifyFormat("switch (args?.Length) {}", Style); 244 245 verifyFormat("public static void Main(string[] args)\n" 246 "{\n" 247 " string dirPath = args?[0];\n" 248 "}"); 249 250 Style.SpaceBeforeParens = FormatStyle::SBPO_Never; 251 252 verifyFormat("switch(args?.Length) {}", Style); 253 } 254 255 TEST_F(FormatTestCSharp, Attributes) { 256 verifyFormat("[STAThread]\n" 257 "static void Main(string[] args)\n" 258 "{\n" 259 "}"); 260 261 verifyFormat("[TestMethod]\n" 262 "private class Test\n" 263 "{\n" 264 "}"); 265 266 verifyFormat("[TestMethod]\n" 267 "protected class Test\n" 268 "{\n" 269 "}"); 270 271 verifyFormat("[TestMethod]\n" 272 "internal class Test\n" 273 "{\n" 274 "}"); 275 276 verifyFormat("[TestMethod]\n" 277 "class Test\n" 278 "{\n" 279 "}"); 280 281 verifyFormat("[TestMethod]\n" 282 "[DeploymentItem(\"Test.txt\")]\n" 283 "public class Test\n" 284 "{\n" 285 "}"); 286 287 verifyFormat("[System.AttributeUsage(System.AttributeTargets.Method)]\n" 288 "[System.Runtime.InteropServices.ComVisible(true)]\n" 289 "public sealed class STAThreadAttribute : Attribute\n" 290 "{\n" 291 "}"); 292 293 verifyFormat("[Verb(\"start\", HelpText = \"Starts the server listening on " 294 "provided port\")]\n" 295 "class Test\n" 296 "{\n" 297 "}"); 298 299 verifyFormat("[TestMethod]\n" 300 "public string Host { set; get; }"); 301 302 // Adjacent properties should not cause line wrapping issues 303 verifyFormat("[JsonProperty(\"foo\")]\n" 304 "public string Foo { set; get; }\n" 305 "[JsonProperty(\"bar\")]\n" 306 "public string Bar { set; get; }\n" 307 "[JsonProperty(\"bar\")]\n" 308 "protected string Bar { set; get; }\n" 309 "[JsonProperty(\"bar\")]\n" 310 "internal string Bar { set; get; }"); 311 312 // Multiple attributes should always be split (not just the first ones) 313 verifyFormat("[XmlIgnore]\n" 314 "[JsonProperty(\"foo\")]\n" 315 "public string Foo { set; get; }"); 316 317 verifyFormat("[XmlIgnore]\n" 318 "[JsonProperty(\"foo\")]\n" 319 "public string Foo { set; get; }\n" 320 "[XmlIgnore]\n" 321 "[JsonProperty(\"bar\")]\n" 322 "public string Bar { set; get; }"); 323 324 verifyFormat("[XmlIgnore]\n" 325 "[ScriptIgnore]\n" 326 "[JsonProperty(\"foo\")]\n" 327 "public string Foo { set; get; }\n" 328 "[XmlIgnore]\n" 329 "[ScriptIgnore]\n" 330 "[JsonProperty(\"bar\")]\n" 331 "public string Bar { set; get; }"); 332 333 verifyFormat("[TestMethod(\"start\", HelpText = \"Starts the server " 334 "listening on provided host\")]\n" 335 "public string Host { set; get; }"); 336 337 verifyIncompleteFormat( 338 "[DllImport(\"Hello\", EntryPoint = \"hello_world\")]\n" 339 "// The const char* returned by hello_world must not be deleted.\n" 340 "private static extern IntPtr HelloFromCpp();)"); 341 342 // Class attributes go on their own line and do not affect layout of 343 // interfaces. Line wrapping decisions previously caused each interface to be 344 // on its own line. 345 verifyFormat("[SomeAttribute]\n" 346 "[SomeOtherAttribute]\n" 347 "public class A : IShape, IAnimal, IVehicle\n" 348 "{\n" 349 " int X;\n" 350 "}"); 351 352 // Attributes in a method declaration do not cause line wrapping. 353 verifyFormat("void MethodA([In][Out] ref double x)\n" 354 "{\n" 355 "}"); 356 357 verifyFormat("void MethodA([In, Out] ref double x)\n" 358 "{\n" 359 "}"); 360 361 verifyFormat("void MethodA([In, Out] double[] x)\n" 362 "{\n" 363 "}"); 364 365 verifyFormat("void MethodA([In] double[] x)\n" 366 "{\n" 367 "}"); 368 369 verifyFormat("void MethodA(int[] x)\n" 370 "{\n" 371 "}"); 372 verifyFormat("void MethodA(int[][] x)\n" 373 "{\n" 374 "}"); 375 verifyFormat("void MethodA([] x)\n" 376 "{\n" 377 "}"); 378 379 verifyFormat("public void Log([CallerLineNumber] int line = -1, " 380 "[CallerFilePath] string path = null,\n" 381 " [CallerMemberName] string name = null)\n" 382 "{\n" 383 "}"); 384 385 // [] in an attribute do not cause premature line wrapping or indenting. 386 verifyFormat(R"(// 387 public class A 388 { 389 [SomeAttribute(new[] { RED, GREEN, BLUE }, -1.0f, 1.0f)] 390 [DoNotSerialize] 391 public Data MemberVariable; 392 })"); 393 394 // Unwrappable lines go on a line of their own. 395 // 'target:' is not treated as a label. 396 // Modify Style to enforce a column limit. 397 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 398 Style.ColumnLimit = 10; 399 verifyFormat(R"([assembly:InternalsVisibleTo( 400 "SomeAssembly, PublicKey=SomePublicKeyThatExceedsTheColumnLimit")])", 401 Style); 402 } 403 404 TEST_F(FormatTestCSharp, CSharpUsing) { 405 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 406 Style.SpaceBeforeParens = FormatStyle::SBPO_Always; 407 verifyFormat("public void foo () {\n" 408 " using (StreamWriter sw = new StreamWriter (filenameA)) {}\n" 409 " using () {}\n" 410 "}", 411 Style); 412 413 // Ensure clang-format affects top-level snippets correctly. 414 verifyFormat("using (StreamWriter sw = new StreamWriter (filenameB)) {}", 415 Style); 416 417 Style.SpaceBeforeParens = FormatStyle::SBPO_Never; 418 verifyFormat("public void foo() {\n" 419 " using(StreamWriter sw = new StreamWriter(filenameB)) {}\n" 420 " using() {}\n" 421 "}", 422 Style); 423 424 // Ensure clang-format affects top-level snippets correctly. 425 verifyFormat("using(StreamWriter sw = new StreamWriter(filenameB)) {}", 426 Style); 427 428 Style.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements; 429 verifyFormat("public void foo() {\n" 430 " using (StreamWriter sw = new StreamWriter(filenameA)) {}\n" 431 " using () {}\n" 432 "}", 433 Style); 434 435 // Ensure clang-format affects top-level snippets correctly. 436 verifyFormat("using (StreamWriter sw = new StreamWriter(filenameB)) {}", 437 Style); 438 439 Style.SpaceBeforeParens = FormatStyle::SBPO_NonEmptyParentheses; 440 verifyFormat("public void foo() {\n" 441 " using (StreamWriter sw = new StreamWriter (filenameA)) {}\n" 442 " using() {}\n" 443 "}", 444 Style); 445 446 // Ensure clang-format affects top-level snippets correctly. 447 verifyFormat("using (StreamWriter sw = new StreamWriter (filenameB)) {}", 448 Style); 449 } 450 451 TEST_F(FormatTestCSharp, CSharpRegions) { 452 verifyFormat("#region aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaa " 453 "aaaaaaaaaaaaaaa long region"); 454 } 455 456 TEST_F(FormatTestCSharp, CSharpKeyWordEscaping) { 457 // AfterEnum is true by default. 458 verifyFormat("public enum var\n" 459 "{\n" 460 " none,\n" 461 " @string,\n" 462 " bool,\n" 463 " @enum\n" 464 "}"); 465 } 466 467 TEST_F(FormatTestCSharp, CSharpNullCoalescing) { 468 verifyFormat("var test = ABC ?? DEF"); 469 verifyFormat("string myname = name ?? \"ABC\";"); 470 verifyFormat("return _name ?? \"DEF\";"); 471 } 472 473 TEST_F(FormatTestCSharp, CSharpNullCoalescingAssignment) { 474 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 475 Style.SpaceBeforeAssignmentOperators = true; 476 477 verifyFormat(R"(test ??= ABC;)", Style); 478 verifyFormat(R"(test ??= true;)", Style); 479 480 Style.SpaceBeforeAssignmentOperators = false; 481 482 verifyFormat(R"(test??= ABC;)", Style); 483 verifyFormat(R"(test??= true;)", Style); 484 } 485 486 TEST_F(FormatTestCSharp, CSharpNullForgiving) { 487 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 488 489 verifyFormat("var test = null!;", Style); 490 verifyFormat("string test = someFunctionCall()! + \"ABC\"!", Style); 491 verifyFormat("int test = (1! + 2 + bar! + foo())!", Style); 492 verifyFormat(R"(test ??= !foo!;)", Style); 493 verifyFormat("test = !bar! ?? !foo!;", Style); 494 verifyFormat("bool test = !(!true && !true! || !null && !null! || !false && " 495 "!false! && !bar()! + (!foo()))!", 496 Style); 497 498 // Check that line break keeps identifier with the bang. 499 Style.ColumnLimit = 14; 500 501 verifyFormat("var test =\n" 502 " foo!;", 503 Style); 504 } 505 506 TEST_F(FormatTestCSharp, AttributesIndentation) { 507 FormatStyle Style = getMicrosoftStyle(FormatStyle::LK_CSharp); 508 Style.BreakAfterReturnType = FormatStyle::RTBS_None; 509 510 verifyFormat("[STAThread]\n" 511 "static void Main(string[] args)\n" 512 "{\n" 513 "}", 514 Style); 515 516 verifyFormat("[STAThread]\n" 517 "void " 518 "veryLooooooooooooooongFunctionName(string[] args)\n" 519 "{\n" 520 "}", 521 Style); 522 523 verifyFormat("[STAThread]\n" 524 "veryLoooooooooooooooooooongReturnType " 525 "veryLooooooooooooooongFunctionName(string[] args)\n" 526 "{\n" 527 "}", 528 Style); 529 530 verifyFormat("[SuppressMessage(\"A\", \"B\", Justification = \"C\")]\n" 531 "public override X Y()\n" 532 "{\n" 533 "}", 534 Style); 535 536 verifyFormat("[SuppressMessage]\n" 537 "public X Y()\n" 538 "{\n" 539 "}", 540 Style); 541 542 verifyFormat("[SuppressMessage]\n" 543 "public override X Y()\n" 544 "{\n" 545 "}", 546 Style); 547 548 verifyFormat("public A(B b) : base(b)\n" 549 "{\n" 550 " [SuppressMessage]\n" 551 " public override X Y()\n" 552 " {\n" 553 " }\n" 554 "}", 555 Style); 556 557 verifyFormat("public A : Base\n" 558 "{\n" 559 "}\n" 560 "[Test]\n" 561 "public Foo()\n" 562 "{\n" 563 "}", 564 Style); 565 566 verifyFormat("namespace\n" 567 "{\n" 568 "public A : Base\n" 569 "{\n" 570 "}\n" 571 "[Test]\n" 572 "public Foo()\n" 573 "{\n" 574 "}\n" 575 "}", 576 Style); 577 } 578 579 TEST_F(FormatTestCSharp, CSharpSpaceBefore) { 580 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 581 Style.SpaceBeforeParens = FormatStyle::SBPO_Always; 582 583 verifyFormat("List<string> list;", Style); 584 verifyFormat("Dictionary<string, string> dict;", Style); 585 586 verifyFormat("for (int i = 0; i < size (); i++) {\n" 587 "}", 588 Style); 589 verifyFormat("foreach (var x in y) {\n" 590 "}", 591 Style); 592 verifyFormat("switch (x) {}", Style); 593 verifyFormat("do {\n" 594 "} while (x);", 595 Style); 596 597 Style.SpaceBeforeParens = FormatStyle::SBPO_Never; 598 599 verifyFormat("List<string> list;", Style); 600 verifyFormat("Dictionary<string, string> dict;", Style); 601 602 verifyFormat("for(int i = 0; i < size(); i++) {\n" 603 "}", 604 Style); 605 verifyFormat("foreach(var x in y) {\n" 606 "}", 607 Style); 608 verifyFormat("switch(x) {}", Style); 609 verifyFormat("do {\n" 610 "} while(x);", 611 Style); 612 } 613 614 TEST_F(FormatTestCSharp, CSharpSpaceAfterCStyleCast) { 615 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 616 617 verifyFormat("(int)x / y;", Style); 618 619 Style.SpaceAfterCStyleCast = true; 620 verifyFormat("(int) x / y;", Style); 621 } 622 623 TEST_F(FormatTestCSharp, CSharpEscapedQuotesInVerbatimStrings) { 624 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 625 626 verifyFormat(R"(string str = @"""";)", Style); 627 verifyFormat(R"(string str = @"""Hello world""";)", Style); 628 verifyFormat(R"(string str = $@"""Hello {friend}""";)", Style); 629 verifyFormat(R"(return $@"Foo ""/foo?f={Request.Query["f"]}""";)", Style); 630 verifyFormat(R"(return @$"Foo ""/foo?f={Request.Query["f"]}""";)", Style); 631 verifyFormat(R"(return @$"path\to\{specifiedFile}")", Style); 632 } 633 634 TEST_F(FormatTestCSharp, CSharpQuotesInInterpolatedStrings) { 635 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 636 637 verifyFormat(R"(string str1 = $"{null ?? "null"}";)", Style); 638 verifyFormat(R"(string str2 = $"{{{braceCount} braces";)", Style); 639 verifyFormat(R"(string str3 = $"{braceCount}}} braces";)", Style); 640 } 641 642 TEST_F(FormatTestCSharp, CSharpNewlinesInVerbatimStrings) { 643 // Use MS style as Google Style inserts a line break before multiline strings. 644 645 // verifyFormat does not understand multiline C# string-literals 646 // so check the format explicitly. 647 648 FormatStyle Style = getMicrosoftStyle(FormatStyle::LK_CSharp); 649 650 std::string Code = R"(string s1 = $@"some code: 651 class {className} {{ 652 {className}() {{}} 653 }}";)"; 654 655 EXPECT_EQ(Code, format(Code, Style)); 656 657 // Multiline string in the middle of a function call. 658 Code = R"( 659 var x = foo(className, $@"some code: 660 class {className} {{ 661 {className}() {{}} 662 }}", 663 y);)"; // y aligned with `className` arg. 664 665 EXPECT_EQ(Code, format(Code, Style)); 666 667 // Interpolated string with embedded multiline string. 668 Code = R"(Console.WriteLine($"{string.Join(@", 669 ", values)}");)"; 670 671 EXPECT_EQ(Code, format(Code, Style)); 672 } 673 674 TEST_F(FormatTestCSharp, CSharpNewOperator) { 675 FormatStyle Style = getLLVMStyle(FormatStyle::LK_CSharp); 676 677 verifyFormat("public void F() {\n" 678 " var v = new C(() => { var t = 5; });\n" 679 "}", 680 Style); 681 verifyFormat("public void F() {\n" 682 " var v = new C(() => {\n" 683 " try {\n" 684 " } catch {\n" 685 " var t = 5;\n" 686 " }\n" 687 " });\n" 688 "}", 689 Style); 690 } 691 692 TEST_F(FormatTestCSharp, CSharpLambdas) { 693 FormatStyle GoogleStyle = getGoogleStyle(FormatStyle::LK_CSharp); 694 FormatStyle MicrosoftStyle = getMicrosoftStyle(FormatStyle::LK_CSharp); 695 696 verifyFormat(R"(// 697 class MyClass { 698 Action<string> greet = name => { 699 string greeting = $"Hello {name}!"; 700 Console.WriteLine(greeting); 701 }; 702 })", 703 GoogleStyle); 704 705 // Microsoft Style: 706 // https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/lambda-expressions#statement-lambdas 707 verifyFormat(R"(// 708 class MyClass 709 { 710 Action<string> greet = name => 711 { 712 string greeting = $"Hello {name}!"; 713 Console.WriteLine(greeting); 714 }; 715 })", 716 MicrosoftStyle); 717 718 verifyFormat("void bar()\n" 719 "{\n" 720 " Function(Val, (Action)(() =>\n" 721 " {\n" 722 " lock (mylock)\n" 723 " {\n" 724 " if (true)\n" 725 " {\n" 726 " A.Remove(item);\n" 727 " }\n" 728 " }\n" 729 " }));\n" 730 "}", 731 MicrosoftStyle); 732 733 verifyFormat("void baz()\n" 734 "{\n" 735 " Function(Val, (Action)(() =>\n" 736 " {\n" 737 " using (var a = new Lock())\n" 738 " {\n" 739 " if (true)\n" 740 " {\n" 741 " A.Remove(item);\n" 742 " }\n" 743 " }\n" 744 " }));\n" 745 "}", 746 MicrosoftStyle); 747 748 verifyFormat("void baz()\n" 749 "{\n" 750 " Function(Val, (Action)(() =>\n" 751 " {\n" 752 " if (true)\n" 753 " {\n" 754 " A.Remove(item);\n" 755 " }\n" 756 " }));\n" 757 "}", 758 MicrosoftStyle); 759 760 verifyFormat("void baz()\n" 761 "{\n" 762 " Function(Val, (Action)(() =>\n" 763 " {\n" 764 " do\n" 765 " {\n" 766 " A.Remove(item);\n" 767 " } while (true)\n" 768 " }));\n" 769 "}", 770 MicrosoftStyle); 771 772 verifyFormat("void baz()\n" 773 "{\n" 774 " Function(Val, (Action)(() =>\n" 775 " { A.Remove(item); }));\n" 776 "}", 777 MicrosoftStyle); 778 779 verifyFormat("void bar()\n" 780 "{\n" 781 " Function(Val, (() =>\n" 782 " {\n" 783 " lock (mylock)\n" 784 " {\n" 785 " if (true)\n" 786 " {\n" 787 " A.Remove(item);\n" 788 " }\n" 789 " }\n" 790 " }));\n" 791 "}", 792 MicrosoftStyle); 793 verifyFormat("void bar()\n" 794 "{\n" 795 " Function((() =>\n" 796 " {\n" 797 " lock (mylock)\n" 798 " {\n" 799 " if (true)\n" 800 " {\n" 801 " A.Remove(item);\n" 802 " }\n" 803 " }\n" 804 " }));\n" 805 "}", 806 MicrosoftStyle); 807 808 MicrosoftStyle.IndentWidth = 2; 809 verifyFormat("void bar()\n" 810 "{\n" 811 " Function((() =>\n" 812 " {\n" 813 " lock (mylock)\n" 814 " {\n" 815 " if (true)\n" 816 " {\n" 817 " A.Remove(item);\n" 818 " }\n" 819 " }\n" 820 " }));\n" 821 "}", 822 MicrosoftStyle); 823 verifyFormat("void bar() {\n" 824 " Function((() => {\n" 825 " lock (mylock) {\n" 826 " if (true) {\n" 827 " A.Remove(item);\n" 828 " }\n" 829 " }\n" 830 " }));\n" 831 "}", 832 GoogleStyle); 833 } 834 835 TEST_F(FormatTestCSharp, CSharpLambdasDontBreakFollowingCodeAlignment) { 836 FormatStyle GoogleStyle = getGoogleStyle(FormatStyle::LK_CSharp); 837 FormatStyle MicrosoftStyle = getMicrosoftStyle(FormatStyle::LK_CSharp); 838 839 verifyFormat(R"(// 840 public class Sample 841 { 842 public void Test() 843 { 844 while (true) 845 { 846 preBindEnumerators.RemoveAll(enumerator => !enumerator.MoveNext()); 847 CodeThatFollowsLambda(); 848 IsWellAligned(); 849 } 850 } 851 })", 852 MicrosoftStyle); 853 854 verifyFormat(R"(// 855 public class Sample { 856 public void Test() { 857 while (true) { 858 preBindEnumerators.RemoveAll(enumerator => !enumerator.MoveNext()); 859 CodeThatFollowsLambda(); 860 IsWellAligned(); 861 } 862 } 863 })", 864 GoogleStyle); 865 } 866 867 TEST_F(FormatTestCSharp, CSharpLambdasComplexLambdasDontBreakAlignment) { 868 FormatStyle GoogleStyle = getGoogleStyle(FormatStyle::LK_CSharp); 869 FormatStyle MicrosoftStyle = getMicrosoftStyle(FormatStyle::LK_CSharp); 870 871 verifyFormat(R"(// 872 public class Test 873 { 874 private static void ComplexLambda(BuildReport protoReport) 875 { 876 allSelectedScenes = 877 veryVeryLongCollectionNameThatPutsTheLineLenghtAboveTheThresholds.Where(scene => scene.enabled) 878 .Select(scene => scene.path) 879 .ToArray(); 880 if (allSelectedScenes.Count == 0) 881 { 882 return; 883 } 884 Functions(); 885 AreWell(); 886 Aligned(); 887 AfterLambdaBlock(); 888 } 889 })", 890 MicrosoftStyle); 891 892 verifyFormat(R"(// 893 public class Test { 894 private static void ComplexLambda(BuildReport protoReport) { 895 allSelectedScenes = veryVeryLongCollectionNameThatPutsTheLineLenghtAboveTheThresholds 896 .Where(scene => scene.enabled) 897 .Select(scene => scene.path) 898 .ToArray(); 899 if (allSelectedScenes.Count == 0) { 900 return; 901 } 902 Functions(); 903 AreWell(); 904 Aligned(); 905 AfterLambdaBlock(); 906 } 907 })", 908 GoogleStyle); 909 } 910 911 TEST_F(FormatTestCSharp, CSharpLambdasMulipleLambdasDontBreakAlignment) { 912 FormatStyle GoogleStyle = getGoogleStyle(FormatStyle::LK_CSharp); 913 FormatStyle MicrosoftStyle = getMicrosoftStyle(FormatStyle::LK_CSharp); 914 915 verifyFormat(R"(// 916 public class Test 917 { 918 private static void MultipleLambdas(BuildReport protoReport) 919 { 920 allSelectedScenes = 921 veryVeryLongCollectionNameThatPutsTheLineLenghtAboveTheThresholds.Where(scene => scene.enabled) 922 .Select(scene => scene.path) 923 .ToArray(); 924 preBindEnumerators.RemoveAll(enumerator => !enumerator.MoveNext()); 925 if (allSelectedScenes.Count == 0) 926 { 927 return; 928 } 929 Functions(); 930 AreWell(); 931 Aligned(); 932 AfterLambdaBlock(); 933 } 934 })", 935 MicrosoftStyle); 936 937 verifyFormat(R"(// 938 public class Test { 939 private static void MultipleLambdas(BuildReport protoReport) { 940 allSelectedScenes = veryVeryLongCollectionNameThatPutsTheLineLenghtAboveTheThresholds 941 .Where(scene => scene.enabled) 942 .Select(scene => scene.path) 943 .ToArray(); 944 preBindEnumerators.RemoveAll(enumerator => !enumerator.MoveNext()); 945 if (allSelectedScenes.Count == 0) { 946 return; 947 } 948 Functions(); 949 AreWell(); 950 Aligned(); 951 AfterLambdaBlock(); 952 } 953 })", 954 GoogleStyle); 955 } 956 957 TEST_F(FormatTestCSharp, CSharpObjectInitializers) { 958 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 959 960 // Start code fragments with a comment line so that C++ raw string literals 961 // as seen are identical to expected formatted code. 962 963 verifyFormat(R"(// 964 Shape[] shapes = new[] { 965 new Circle { 966 Radius = 2.7281, 967 Colour = Colours.Red, 968 }, 969 new Square { 970 Side = 101.1, 971 Colour = Colours.Yellow, 972 }, 973 };)", 974 Style); 975 976 // Omitted final `,`s will change the formatting. 977 verifyFormat(R"(// 978 Shape[] shapes = new[] { new Circle { Radius = 2.7281, Colour = Colours.Red }, 979 new Square { Side = 101.1, Colour = Colours.Yellow } };)", 980 Style); 981 982 // Lambdas can be supplied as initialiser arguments. 983 verifyFormat(R"(// 984 private Transformer _transformer = new X.Y { 985 Filler = (Shape shape) => { return new Transform.Fill(shape, RED); }, 986 Scaler = (Shape shape) => { return new Transform.Resize(shape, 0.1); }, 987 };)", 988 Style); 989 990 // Dictionary initialisation. 991 verifyFormat(R"(// 992 var myDict = new Dictionary<string, string> { 993 ["name"] = _donald, 994 ["age"] = Convert.ToString(DateTime.Today.Year - 1934), 995 ["type"] = _duck, 996 };)", 997 Style); 998 } 999 1000 TEST_F(FormatTestCSharp, CSharpArrayInitializers) { 1001 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 1002 1003 verifyFormat(R"(// 1004 private MySet<Node>[] setPoints = { 1005 new Point<Node>(), 1006 new Point<Node>(), 1007 };)", 1008 Style); 1009 } 1010 1011 TEST_F(FormatTestCSharp, CSharpNamedArguments) { 1012 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 1013 1014 verifyFormat(R"(// 1015 PrintOrderDetails(orderNum: 31, productName: "Red Mug", sellerName: "Gift Shop");)", 1016 Style); 1017 1018 // Ensure that trailing comments do not cause problems. 1019 verifyFormat(R"(// 1020 PrintOrderDetails(orderNum: 31, productName: "Red Mug", // comment 1021 sellerName: "Gift Shop");)", 1022 Style); 1023 1024 verifyFormat(R"(foreach (var tickCount in task.Begin(seed: 0)) {)", Style); 1025 } 1026 1027 TEST_F(FormatTestCSharp, CSharpPropertyAccessors) { 1028 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 1029 1030 verifyFormat("int Value { get }", Style); 1031 verifyFormat("int Value { get; }", Style); 1032 verifyFormat("int Value { internal get; }", Style); 1033 verifyFormat("int Value { get; } = 0", Style); 1034 verifyFormat("int Value { set }", Style); 1035 verifyFormat("int Value { set; }", Style); 1036 verifyFormat("int Value { init; }", Style); 1037 verifyFormat("int Value { internal set; }", Style); 1038 verifyFormat("int Value { set; } = 0", Style); 1039 verifyFormat("int Value { get; set }", Style); 1040 verifyFormat("int Value { get; init; }", Style); 1041 verifyFormat("int Value { set; get }", Style); 1042 verifyFormat("int Value { get; private set; }", Style); 1043 verifyFormat("int Value { get; set; }", Style); 1044 verifyFormat("int Value { get; set; } = 0", Style); 1045 verifyFormat("int Value { internal get; internal set; }", Style); 1046 1047 // Do not wrap expression body definitions. 1048 verifyFormat(R"(// 1049 public string Name { 1050 get => _name; 1051 set => _name = value; 1052 })", 1053 Style); 1054 verifyFormat(R"(// 1055 public string Name { 1056 init => _name = value; 1057 get => _name; 1058 })", 1059 Style); 1060 verifyFormat(R"(// 1061 public string Name { 1062 set => _name = value; 1063 get => _name; 1064 })", 1065 Style); 1066 1067 // Examples taken from 1068 // https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties 1069 verifyFormat(R"( 1070 // Expression body definitions 1071 public class SaleItem { 1072 public decimal Price { 1073 get => _cost; 1074 set => _cost = value; 1075 } 1076 })", 1077 Style); 1078 1079 verifyFormat(R"( 1080 // Properties with backing fields 1081 class TimePeriod { 1082 public double Hours { 1083 get { return _seconds / 3600; } 1084 set { 1085 if (value < 0 || value > 24) 1086 throw new ArgumentOutOfRangeException($"{nameof(value)} must be between 0 and 24."); 1087 _seconds = value * 3600; 1088 } 1089 } 1090 })", 1091 Style); 1092 1093 verifyFormat(R"( 1094 // Auto-implemented properties 1095 public class SaleItem { 1096 public decimal Price { get; set; } 1097 })", 1098 Style); 1099 1100 // Add column limit to wrap long lines. 1101 Style.ColumnLimit = 100; 1102 1103 // Examples with assignment to default value. 1104 verifyFormat(R"( 1105 // Long assignment to default value 1106 class MyClass { 1107 public override VeryLongNamedTypeIndeed VeryLongNamedValue { get; set } = 1108 VeryLongNamedTypeIndeed.Create(DefaultFirstArgument, DefaultSecondArgument, 1109 DefaultThirdArgument); 1110 })", 1111 Style); 1112 1113 verifyFormat(R"( 1114 // Long assignment to default value with expression body 1115 class MyClass { 1116 public override VeryLongNamedTypeIndeed VeryLongNamedValue { 1117 get => veryLongNamedField; 1118 set => veryLongNamedField = value; 1119 } = VeryLongNamedTypeIndeed.Create(DefaultFirstArgument, DefaultSecondArgument, 1120 DefaultThirdArgument); 1121 })", 1122 Style); 1123 1124 // Brace wrapping and single-lining of accessor can be controlled by config. 1125 Style.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Never; 1126 Style.BreakBeforeBraces = FormatStyle::BS_Custom; 1127 Style.BraceWrapping.AfterFunction = true; 1128 1129 verifyFormat(R"(// 1130 class TimePeriod { 1131 public double Hours 1132 { 1133 get { 1134 return _seconds / 3600; 1135 } 1136 set { 1137 _seconds = value * 3600; 1138 } 1139 } 1140 })", 1141 Style); 1142 1143 // Microsoft style trivial property accessors have no line break before the 1144 // opening brace. 1145 auto MicrosoftStyle = getMicrosoftStyle(FormatStyle::LK_CSharp); 1146 verifyFormat(R"(// 1147 public class SaleItem 1148 { 1149 public decimal Price { get; set; } 1150 })", 1151 MicrosoftStyle); 1152 1153 verifyFormat("internal class Program\n" 1154 "{\n" 1155 " bool AutoAllowKnownApps\n" 1156 " {\n" 1157 " get;\n" 1158 " [Simple]\n" 1159 " set;\n" 1160 " }\n" 1161 "}", 1162 MicrosoftStyle); 1163 } 1164 1165 TEST_F(FormatTestCSharp, DefaultLiteral) { 1166 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 1167 1168 verifyFormat( 1169 "T[] InitializeArray<T>(int length, T initialValue = default) {}", Style); 1170 verifyFormat("System.Numerics.Complex fillValue = default;", Style); 1171 verifyFormat("int Value { get } = default;", Style); 1172 verifyFormat("int Value { get } = default!;", Style); 1173 verifyFormat(R"(// 1174 public record Person { 1175 public string GetInit { get; init; } = default!; 1176 };)", 1177 Style); 1178 verifyFormat(R"(// 1179 public record Person { 1180 public string GetSet { get; set; } = default!; 1181 };)", 1182 Style); 1183 } 1184 1185 TEST_F(FormatTestCSharp, CSharpSpaces) { 1186 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 1187 Style.SpaceBeforeSquareBrackets = false; 1188 Style.SpacesInSquareBrackets = false; 1189 Style.SpaceBeforeCpp11BracedList = true; 1190 Style.Cpp11BracedListStyle = false; 1191 Style.SpacesInContainerLiterals = false; 1192 Style.SpaceAfterCStyleCast = false; 1193 1194 verifyFormat(R"(new Car { "Door", 0.1 })", Style); 1195 verifyFormat(R"(new Car { 0.1, "Door" })", Style); 1196 verifyFormat(R"(new string[] { "A" })", Style); 1197 verifyFormat(R"(new string[] {})", Style); 1198 verifyFormat(R"(new Car { someVariableName })", Style); 1199 verifyFormat(R"(new Car { someVariableName })", Style); 1200 verifyFormat(R"(new Dictionary<string, string> { ["Key"] = "Value" };)", 1201 Style); 1202 verifyFormat(R"(Apply(x => x.Name, x => () => x.ID);)", Style); 1203 verifyFormat(R"(bool[] xs = { true, true };)", Style); 1204 verifyIncompleteFormat( 1205 R"(taskContext.Factory.Run(async () => doThing(args);)", Style); 1206 verifyFormat(R"(catch (TestException) when (innerFinallyExecuted))", Style); 1207 verifyFormat(R"(private float[,] Values;)", Style); 1208 verifyFormat(R"(Result this[Index x] => Foo(x);)", Style); 1209 1210 verifyFormat(R"(char[,,] rawCharArray = MakeCharacterGrid();)", Style); 1211 verifyFormat(R"(var (key, value))", Style); 1212 1213 // `&&` is not seen as a reference. 1214 verifyFormat(R"(A == typeof(X) && someBool)", Style); 1215 1216 // Not seen as a C-style cast. 1217 verifyFormat(R"(// 1218 foreach ((A a, B b) in someList) { 1219 })", 1220 Style); 1221 1222 // space after lock in `lock (processes)`. 1223 verifyFormat("lock (process)", Style); 1224 1225 Style.SpacesInSquareBrackets = true; 1226 verifyFormat(R"(private float[ , ] Values;)", Style); 1227 verifyFormat(R"(string dirPath = args?[ 0 ];)", Style); 1228 verifyFormat(R"(char[ ,, ] rawCharArray = MakeCharacterGrid();)", Style); 1229 1230 // Method returning tuple 1231 verifyFormat(R"(public (string name, int age) methodTuple() {})", Style); 1232 verifyFormat(R"(private (string name, int age) methodTuple() {})", Style); 1233 verifyFormat(R"(protected (string name, int age) methodTuple() {})", Style); 1234 verifyFormat(R"(virtual (string name, int age) methodTuple() {})", Style); 1235 verifyFormat(R"(extern (string name, int age) methodTuple() {})", Style); 1236 verifyFormat(R"(static (string name, int age) methodTuple() {})", Style); 1237 verifyFormat(R"(internal (string name, int age) methodTuple() {})", Style); 1238 verifyFormat(R"(abstract (string name, int age) methodTuple() {})", Style); 1239 verifyFormat(R"(sealed (string name, int age) methodTuple() {})", Style); 1240 verifyFormat(R"(override (string name, int age) methodTuple() {})", Style); 1241 verifyFormat(R"(async (string name, int age) methodTuple() {})", Style); 1242 verifyFormat(R"(unsafe (string name, int age) methodTuple() {})", Style); 1243 1244 Style.SpacesInSquareBrackets = false; 1245 Style.SpaceBeforeSquareBrackets = true; 1246 verifyFormat("return a is [1, 2, 3];", Style); 1247 verifyFormat("return a is [..];", Style); 1248 Style.SpaceBeforeSquareBrackets = false; 1249 verifyFormat("return a is [1, 2, 3];", Style); 1250 verifyFormat("return a is [..];", Style); 1251 } 1252 1253 TEST_F(FormatTestCSharp, CSharpNullableTypes) { 1254 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 1255 Style.SpacesInSquareBrackets = false; 1256 1257 verifyFormat(R"(// 1258 public class A { 1259 void foo() { 1260 int? value = some.bar(); 1261 } 1262 })", 1263 Style); // int? is nullable not a conditional expression. 1264 1265 verifyFormat(R"(void foo(int? x, int? y, int? z) {})", 1266 Style); // Nullables in function definitions. 1267 1268 verifyFormat(R"(public float? Value;)", Style); // no space before `?`. 1269 1270 verifyFormat(R"(int?[] arr = new int?[10];)", 1271 Style); // An array of a nullable type. 1272 1273 verifyFormat(R"(var x = (int?)y;)", Style); // Cast to a nullable type. 1274 1275 verifyFormat(R"(var x = new MyContainer<int?>();)", Style); // Generics. 1276 1277 verifyFormat(R"(// 1278 public interface I { 1279 int? Function(); 1280 })", 1281 Style); // Interface methods. 1282 1283 Style.ColumnLimit = 10; 1284 verifyFormat(R"(// 1285 public VeryLongType? Function( 1286 int arg1, 1287 int arg2) { 1288 // 1289 })", 1290 Style); // ? sticks with identifier. 1291 } 1292 1293 TEST_F(FormatTestCSharp, CSharpArraySubscripts) { 1294 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 1295 1296 // Do not format array subscript operators as attributes. 1297 verifyFormat(R"(// 1298 if (someThings[index].Contains(myThing)) { 1299 })", 1300 Style); 1301 1302 verifyFormat(R"(// 1303 if (someThings[i][j][k].Contains(myThing)) { 1304 })", 1305 Style); 1306 } 1307 1308 TEST_F(FormatTestCSharp, CSharpGenericTypeConstraints) { 1309 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 1310 1311 EXPECT_TRUE(Style.BraceWrapping.SplitEmptyRecord); 1312 1313 verifyFormat("class ItemFactory<T>\n" 1314 " where T : new() {\n" 1315 "}", 1316 Style); 1317 1318 // When the "where" line is not to be formatted, following lines should not 1319 // take on its indentation. 1320 verifyFormat("class ItemFactory<T>\n" 1321 " where T : new() {\n" 1322 " int f() {}\n" 1323 "}", 1324 "class ItemFactory<T>\n" 1325 " where T : new() {\n" 1326 " int f() {}\n" 1327 "}", 1328 Style, {tooling::Range(43, 13)}); 1329 1330 verifyFormat("class Dictionary<TKey, TVal>\n" 1331 " where TKey : IComparable<TKey>\n" 1332 " where TVal : IMyInterface {\n" 1333 " public void MyMethod<T>(T t)\n" 1334 " where T : IMyInterface {\n" 1335 " doThing();\n" 1336 " }\n" 1337 "}", 1338 Style); 1339 1340 verifyFormat("class ItemFactory<T>\n" 1341 " where T : new(), IAnInterface<T>, IAnotherInterface<T>, " 1342 "IAnotherInterfaceStill<T> {\n" 1343 "}", 1344 Style); 1345 1346 Style.ColumnLimit = 50; // Force lines to be wrapped. 1347 verifyFormat(R"(// 1348 class ItemFactory<T, U> 1349 where T : new(), 1350 IAnInterface<T>, 1351 IAnotherInterface<T, U>, 1352 IAnotherInterfaceStill<T, U> { 1353 })", 1354 Style); 1355 1356 // In other languages `where` can be used as a normal identifier. 1357 // This example is in C++! 1358 verifyFormat(R"(// 1359 class A { 1360 int f(int where) {} 1361 };)", 1362 getGoogleStyle(FormatStyle::LK_Cpp)); 1363 } 1364 1365 TEST_F(FormatTestCSharp, CSharpAfterEnum) { 1366 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 1367 Style.BreakBeforeBraces = FormatStyle::BS_Custom; 1368 Style.BraceWrapping.AfterEnum = false; 1369 Style.AllowShortEnumsOnASingleLine = false; 1370 1371 verifyFormat("enum MyEnum {\n" 1372 " Foo,\n" 1373 " Bar,\n" 1374 "}", 1375 Style); 1376 verifyFormat("internal enum MyEnum {\n" 1377 " Foo,\n" 1378 " Bar,\n" 1379 "}", 1380 Style); 1381 verifyFormat("public enum MyEnum {\n" 1382 " Foo,\n" 1383 " Bar,\n" 1384 "}", 1385 Style); 1386 verifyFormat("protected enum MyEnum {\n" 1387 " Foo,\n" 1388 " Bar,\n" 1389 "}", 1390 Style); 1391 verifyFormat("private enum MyEnum {\n" 1392 " Foo,\n" 1393 " Bar,\n" 1394 "}", 1395 Style); 1396 1397 Style.BraceWrapping.AfterEnum = true; 1398 Style.AllowShortEnumsOnASingleLine = false; 1399 1400 verifyFormat("enum MyEnum\n" 1401 "{\n" 1402 " Foo,\n" 1403 " Bar,\n" 1404 "}", 1405 Style); 1406 verifyFormat("internal enum MyEnum\n" 1407 "{\n" 1408 " Foo,\n" 1409 " Bar,\n" 1410 "}", 1411 Style); 1412 verifyFormat("public enum MyEnum\n" 1413 "{\n" 1414 " Foo,\n" 1415 " Bar,\n" 1416 "}", 1417 Style); 1418 verifyFormat("protected enum MyEnum\n" 1419 "{\n" 1420 " Foo,\n" 1421 " Bar,\n" 1422 "}", 1423 Style); 1424 verifyFormat("private enum MyEnum\n" 1425 "{\n" 1426 " Foo,\n" 1427 " Bar,\n" 1428 "}", 1429 Style); 1430 verifyFormat("/* Foo */ private enum MyEnum\n" 1431 "{\n" 1432 " Foo,\n" 1433 " Bar,\n" 1434 "}", 1435 Style); 1436 verifyFormat("/* Foo */ /* Bar */ private enum MyEnum\n" 1437 "{\n" 1438 " Foo,\n" 1439 " Bar,\n" 1440 "}", 1441 Style); 1442 } 1443 1444 TEST_F(FormatTestCSharp, CSharpAfterClass) { 1445 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 1446 Style.BreakBeforeBraces = FormatStyle::BS_Custom; 1447 Style.BraceWrapping.AfterClass = false; 1448 1449 verifyFormat("class MyClass {\n" 1450 " int a;\n" 1451 " int b;\n" 1452 "}", 1453 Style); 1454 verifyFormat("internal class MyClass {\n" 1455 " int a;\n" 1456 " int b;\n" 1457 "}", 1458 Style); 1459 verifyFormat("public class MyClass {\n" 1460 " int a;\n" 1461 " int b;\n" 1462 "}", 1463 Style); 1464 verifyFormat("protected class MyClass {\n" 1465 " int a;\n" 1466 " int b;\n" 1467 "}", 1468 Style); 1469 verifyFormat("private class MyClass {\n" 1470 " int a;\n" 1471 " int b;\n" 1472 "}", 1473 Style); 1474 1475 verifyFormat("interface Interface {\n" 1476 " int a;\n" 1477 " int b;\n" 1478 "}", 1479 Style); 1480 verifyFormat("internal interface Interface {\n" 1481 " int a;\n" 1482 " int b;\n" 1483 "}", 1484 Style); 1485 verifyFormat("public interface Interface {\n" 1486 " int a;\n" 1487 " int b;\n" 1488 "}", 1489 Style); 1490 verifyFormat("protected interface Interface {\n" 1491 " int a;\n" 1492 " int b;\n" 1493 "}", 1494 Style); 1495 verifyFormat("private interface Interface {\n" 1496 " int a;\n" 1497 " int b;\n" 1498 "}", 1499 Style); 1500 1501 Style.BraceWrapping.AfterClass = true; 1502 1503 verifyFormat("class MyClass\n" 1504 "{\n" 1505 " int a;\n" 1506 " int b;\n" 1507 "}", 1508 Style); 1509 verifyFormat("internal class MyClass\n" 1510 "{\n" 1511 " int a;\n" 1512 " int b;\n" 1513 "}", 1514 Style); 1515 verifyFormat("public class MyClass\n" 1516 "{\n" 1517 " int a;\n" 1518 " int b;\n" 1519 "}", 1520 Style); 1521 verifyFormat("protected class MyClass\n" 1522 "{\n" 1523 " int a;\n" 1524 " int b;\n" 1525 "}", 1526 Style); 1527 verifyFormat("private class MyClass\n" 1528 "{\n" 1529 " int a;\n" 1530 " int b;\n" 1531 "}", 1532 Style); 1533 1534 verifyFormat("interface MyInterface\n" 1535 "{\n" 1536 " int a;\n" 1537 " int b;\n" 1538 "}", 1539 Style); 1540 verifyFormat("internal interface MyInterface\n" 1541 "{\n" 1542 " int a;\n" 1543 " int b;\n" 1544 "}", 1545 Style); 1546 verifyFormat("public interface MyInterface\n" 1547 "{\n" 1548 " int a;\n" 1549 " int b;\n" 1550 "}", 1551 Style); 1552 verifyFormat("protected interface MyInterface\n" 1553 "{\n" 1554 " int a;\n" 1555 " int b;\n" 1556 "}", 1557 Style); 1558 verifyFormat("private interface MyInterface\n" 1559 "{\n" 1560 " int a;\n" 1561 " int b;\n" 1562 "}", 1563 Style); 1564 verifyFormat("/* Foo */ private interface MyInterface\n" 1565 "{\n" 1566 " int a;\n" 1567 " int b;\n" 1568 "}", 1569 Style); 1570 verifyFormat("/* Foo */ /* Bar */ private interface MyInterface\n" 1571 "{\n" 1572 " int a;\n" 1573 " int b;\n" 1574 "}", 1575 Style); 1576 } 1577 1578 TEST_F(FormatTestCSharp, NamespaceIndentation) { 1579 FormatStyle Style = getMicrosoftStyle(FormatStyle::LK_CSharp); 1580 Style.NamespaceIndentation = FormatStyle::NI_None; 1581 1582 verifyFormat("namespace A\n" 1583 "{\n" 1584 "public interface Name1\n" 1585 "{\n" 1586 "}\n" 1587 "}", 1588 Style); 1589 1590 verifyFormat("namespace A.B\n" 1591 "{\n" 1592 "public interface Name1\n" 1593 "{\n" 1594 "}\n" 1595 "}", 1596 Style); 1597 1598 Style.NamespaceIndentation = FormatStyle::NI_Inner; 1599 1600 verifyFormat("namespace A\n" 1601 "{\n" 1602 "namespace B\n" 1603 "{\n" 1604 " public interface Name1\n" 1605 " {\n" 1606 " }\n" 1607 "}\n" 1608 "}", 1609 Style); 1610 1611 Style.NamespaceIndentation = FormatStyle::NI_All; 1612 1613 verifyFormat("namespace A.B\n" 1614 "{\n" 1615 " public interface Name1\n" 1616 " {\n" 1617 " }\n" 1618 "}", 1619 Style); 1620 1621 verifyFormat("namespace A\n" 1622 "{\n" 1623 " namespace B\n" 1624 " {\n" 1625 " public interface Name1\n" 1626 " {\n" 1627 " }\n" 1628 " }\n" 1629 "}", 1630 Style); 1631 } 1632 1633 TEST_F(FormatTestCSharp, SwitchExpression) { 1634 FormatStyle Style = getMicrosoftStyle(FormatStyle::LK_CSharp); 1635 verifyFormat("int x = a switch {\n" 1636 " 1 => (0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0),\n" 1637 " 2 => 1,\n" 1638 " _ => 2\n" 1639 "};", 1640 Style); 1641 } 1642 1643 TEST_F(FormatTestCSharp, EmptyShortBlock) { 1644 auto Style = getLLVMStyle(); 1645 Style.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Empty; 1646 1647 verifyFormat("try {\n" 1648 " doA();\n" 1649 "} catch (Exception e) {\n" 1650 " e.printStackTrace();\n" 1651 "}", 1652 Style); 1653 1654 verifyFormat("try {\n" 1655 " doA();\n" 1656 "} catch (Exception e) {}", 1657 Style); 1658 } 1659 1660 TEST_F(FormatTestCSharp, ShortFunctions) { 1661 FormatStyle Style = getLLVMStyle(FormatStyle::LK_CSharp); 1662 Style.NamespaceIndentation = FormatStyle::NI_All; 1663 Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline; 1664 verifyFormat("interface Interface {\n" 1665 " void f() { return; }\n" 1666 "};", 1667 Style); 1668 verifyFormat("public interface Interface {\n" 1669 " void f() { return; }\n" 1670 "};", 1671 Style); 1672 verifyFormat("namespace {\n" 1673 " void f() {\n" 1674 " return;\n" 1675 " }\n" 1676 "};", 1677 Style); 1678 // "union" is not a keyword in C#. 1679 verifyFormat("namespace union {\n" 1680 " void f() {\n" 1681 " return;\n" 1682 " }\n" 1683 "};", 1684 Style); 1685 } 1686 1687 TEST_F(FormatTestCSharp, BrokenBrackets) { 1688 EXPECT_NE("", format("int where b <")); // reduced from crasher 1689 } 1690 1691 TEST_F(FormatTestCSharp, GotoCaseLabel) { 1692 verifyFormat("switch (i)\n" 1693 "{\n" 1694 "case 0:\n" 1695 " goto case 1;\n" 1696 "case 1:\n" 1697 " j = 0;\n" 1698 " {\n" 1699 " break;\n" 1700 " }\n" 1701 "}", 1702 "switch (i) {\n" 1703 "case 0:\n" 1704 " goto case 1;\n" 1705 "case 1:\n" 1706 " j = 0;\n" 1707 " {\n" 1708 " break;\n" 1709 " }\n" 1710 "}"); 1711 } 1712 1713 } // namespace 1714 } // namespace test 1715 } // namespace format 1716 } // namespace clang 1717