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 "FormatTestUtils.h" 10 #include "clang/Format/Format.h" 11 #include "llvm/Support/Debug.h" 12 #include "gtest/gtest.h" 13 14 #define DEBUG_TYPE "format-test" 15 16 namespace clang { 17 namespace format { 18 19 class FormatTestCSharp : public ::testing::Test { 20 protected: 21 static std::string format(llvm::StringRef Code, unsigned Offset, 22 unsigned Length, const FormatStyle &Style) { 23 LLVM_DEBUG(llvm::errs() << "---\n"); 24 LLVM_DEBUG(llvm::errs() << Code << "\n\n"); 25 std::vector<tooling::Range> Ranges(1, tooling::Range(Offset, Length)); 26 tooling::Replacements Replaces = reformat(Style, Code, Ranges); 27 auto Result = applyAllReplacements(Code, Replaces); 28 EXPECT_TRUE(static_cast<bool>(Result)); 29 LLVM_DEBUG(llvm::errs() << "\n" << *Result << "\n\n"); 30 return *Result; 31 } 32 33 static std::string 34 format(llvm::StringRef Code, 35 const FormatStyle &Style = getMicrosoftStyle(FormatStyle::LK_CSharp)) { 36 return format(Code, 0, Code.size(), Style); 37 } 38 39 static FormatStyle getStyleWithColumns(unsigned ColumnLimit) { 40 FormatStyle Style = getMicrosoftStyle(FormatStyle::LK_CSharp); 41 Style.ColumnLimit = ColumnLimit; 42 return Style; 43 } 44 45 static void verifyFormat( 46 llvm::StringRef Code, 47 const FormatStyle &Style = getMicrosoftStyle(FormatStyle::LK_CSharp)) { 48 EXPECT_EQ(Code.str(), format(Code, Style)) << "Expected code is not stable"; 49 EXPECT_EQ(Code.str(), format(test::messUp(Code), Style)); 50 } 51 }; 52 53 TEST_F(FormatTestCSharp, CSharpClass) { 54 verifyFormat("public class SomeClass\n" 55 "{\n" 56 " void f()\n" 57 " {\n" 58 " }\n" 59 " int g()\n" 60 " {\n" 61 " return 0;\n" 62 " }\n" 63 " void h()\n" 64 " {\n" 65 " while (true)\n" 66 " f();\n" 67 " for (;;)\n" 68 " f();\n" 69 " if (true)\n" 70 " f();\n" 71 " }\n" 72 "}"); 73 74 // Ensure that small and empty classes are handled correctly with condensed 75 // (Google C++-like) brace-breaking style. 76 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 77 Style.BreakBeforeBraces = FormatStyle::BS_Attach; 78 79 verifyFormat("public class SomeEmptyClass {}", Style); 80 81 verifyFormat("public class SomeTinyClass {\n" 82 " int X;\n" 83 "}", 84 Style); 85 verifyFormat("private class SomeTinyClass {\n" 86 " int X;\n" 87 "}", 88 Style); 89 verifyFormat("protected class SomeTinyClass {\n" 90 " int X;\n" 91 "}", 92 Style); 93 verifyFormat("internal class SomeTinyClass {\n" 94 " int X;\n" 95 "}", 96 Style); 97 } 98 99 TEST_F(FormatTestCSharp, AccessModifiers) { 100 verifyFormat("public String toString()\n" 101 "{\n" 102 "}"); 103 verifyFormat("private String toString()\n" 104 "{\n" 105 "}"); 106 verifyFormat("protected String toString()\n" 107 "{\n" 108 "}"); 109 verifyFormat("internal String toString()\n" 110 "{\n" 111 "}"); 112 113 verifyFormat("public override String toString()\n" 114 "{\n" 115 "}"); 116 verifyFormat("private override String toString()\n" 117 "{\n" 118 "}"); 119 verifyFormat("protected override String toString()\n" 120 "{\n" 121 "}"); 122 verifyFormat("internal override String toString()\n" 123 "{\n" 124 "}"); 125 126 verifyFormat("internal static String toString()\n" 127 "{\n" 128 "}"); 129 } 130 131 TEST_F(FormatTestCSharp, NoStringLiteralBreaks) { 132 verifyFormat("foo(" 133 "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 134 "aaaaaa\");"); 135 } 136 137 TEST_F(FormatTestCSharp, CSharpVerbatiumStringLiterals) { 138 verifyFormat("foo(@\"aaaaaaaa\\abc\\aaaa\");"); 139 // @"ABC\" + ToString("B") - handle embedded \ in literal string at 140 // the end 141 // 142 /* 143 * After removal of Lexer change we are currently not able 144 * To handle these cases 145 verifyFormat("string s = @\"ABC\\\" + ToString(\"B\");"); 146 verifyFormat("string s = @\"ABC\"\"DEF\"\"GHI\""); 147 verifyFormat("string s = @\"ABC\"\"DEF\"\"\""); 148 verifyFormat("string s = @\"ABC\"\"DEF\"\"\" + abc"); 149 */ 150 } 151 152 TEST_F(FormatTestCSharp, CSharpInterpolatedStringLiterals) { 153 verifyFormat("foo($\"aaaaaaaa{aaa}aaaa\");"); 154 verifyFormat("foo($\"aaaa{A}\");"); 155 verifyFormat( 156 "foo($\"aaaa{A}" 157 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\");"); 158 verifyFormat("Name = $\"{firstName} {lastName}\";"); 159 160 // $"ABC\" + ToString("B") - handle embedded \ in literal string at 161 // the end 162 verifyFormat("string s = $\"A{abc}BC\" + ToString(\"B\");"); 163 verifyFormat("$\"{domain}\\\\{user}\""); 164 verifyFormat( 165 "var verbatimInterpolated = $@\"C:\\Users\\{userName}\\Documents\\\";"); 166 } 167 168 TEST_F(FormatTestCSharp, CSharpFatArrows) { 169 verifyFormat("Task serverTask = Task.Run(async() => {"); 170 verifyFormat("public override string ToString() => \"{Name}\\{Age}\";"); 171 } 172 173 TEST_F(FormatTestCSharp, CSharpConditionalExpressions) { 174 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 175 // conditional expression is not seen as a NullConditional. 176 verifyFormat("var y = A < B ? -1 : 1;", Style); 177 } 178 179 TEST_F(FormatTestCSharp, CSharpNullConditional) { 180 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 181 Style.SpaceBeforeParens = FormatStyle::SBPO_Always; 182 183 verifyFormat( 184 "public Person(string firstName, string lastName, int? age = null)"); 185 186 verifyFormat("foo () {\n" 187 " switch (args?.Length) {}\n" 188 "}", 189 Style); 190 191 verifyFormat("switch (args?.Length) {}", Style); 192 193 verifyFormat("public static void Main(string[] args)\n" 194 "{\n" 195 " string dirPath = args?[0];\n" 196 "}"); 197 198 Style.SpaceBeforeParens = FormatStyle::SBPO_Never; 199 200 verifyFormat("switch(args?.Length) {}", Style); 201 } 202 203 TEST_F(FormatTestCSharp, Attributes) { 204 verifyFormat("[STAThread]\n" 205 "static void Main(string[] args)\n" 206 "{\n" 207 "}"); 208 209 verifyFormat("[TestMethod]\n" 210 "private class Test\n" 211 "{\n" 212 "}"); 213 214 verifyFormat("[TestMethod]\n" 215 "protected class Test\n" 216 "{\n" 217 "}"); 218 219 verifyFormat("[TestMethod]\n" 220 "internal class Test\n" 221 "{\n" 222 "}"); 223 224 verifyFormat("[TestMethod]\n" 225 "class Test\n" 226 "{\n" 227 "}"); 228 229 verifyFormat("[TestMethod]\n" 230 "[DeploymentItem(\"Test.txt\")]\n" 231 "public class Test\n" 232 "{\n" 233 "}"); 234 235 verifyFormat("[System.AttributeUsage(System.AttributeTargets.Method)]\n" 236 "[System.Runtime.InteropServices.ComVisible(true)]\n" 237 "public sealed class STAThreadAttribute : Attribute\n" 238 "{\n" 239 "}"); 240 241 verifyFormat("[Verb(\"start\", HelpText = \"Starts the server listening on " 242 "provided port\")]\n" 243 "class Test\n" 244 "{\n" 245 "}"); 246 247 verifyFormat("[TestMethod]\n" 248 "public string Host\n" 249 "{ set; get; }"); 250 251 verifyFormat("[TestMethod(\"start\", HelpText = \"Starts the server " 252 "listening on provided host\")]\n" 253 "public string Host\n" 254 "{ set; get; }"); 255 256 verifyFormat( 257 "[DllImport(\"Hello\", EntryPoint = \"hello_world\")]\n" 258 "// The const char* returned by hello_world must not be deleted.\n" 259 "private static extern IntPtr HelloFromCpp();)"); 260 261 // Class attributes go on their own line and do not affect layout of 262 // interfaces. Line wrapping decisions previously caused each interface to be 263 // on its own line. 264 verifyFormat("[SomeAttribute]\n" 265 "[SomeOtherAttribute]\n" 266 "public class A : IShape, IAnimal, IVehicle\n" 267 "{\n" 268 " int X;\n" 269 "}"); 270 271 // Attributes in a method declaration do not cause line wrapping. 272 verifyFormat("void MethodA([In][Out] ref double x)\n" 273 "{\n" 274 "}"); 275 276 // [] in an attribute do not cause premature line wrapping or indenting. 277 verifyFormat(R"(// 278 public class A 279 { 280 [SomeAttribute(new[] { RED, GREEN, BLUE }, -1.0f, 1.0f)] 281 [DoNotSerialize] 282 public Data MemberVariable; 283 })"); 284 285 // Unwrappable lines go on a line of their own. 286 // 'target:' is not treated as a label. 287 // Modify Style to enforce a column limit. 288 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 289 Style.ColumnLimit = 10; 290 verifyFormat(R"([assembly:InternalsVisibleTo( 291 "SomeAssembly, PublicKey=SomePublicKeyThatExceedsTheColumnLimit")])", 292 Style); 293 } 294 295 TEST_F(FormatTestCSharp, CSharpUsing) { 296 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 297 Style.SpaceBeforeParens = FormatStyle::SBPO_Always; 298 verifyFormat("public void foo () {\n" 299 " using (StreamWriter sw = new StreamWriter (filenameA)) {}\n" 300 " using () {}\n" 301 "}", 302 Style); 303 304 // Ensure clang-format affects top-level snippets correctly. 305 verifyFormat("using (StreamWriter sw = new StreamWriter (filenameB)) {}", 306 Style); 307 308 Style.SpaceBeforeParens = FormatStyle::SBPO_Never; 309 verifyFormat("public void foo() {\n" 310 " using(StreamWriter sw = new StreamWriter(filenameB)) {}\n" 311 " using() {}\n" 312 "}", 313 Style); 314 315 // Ensure clang-format affects top-level snippets correctly. 316 verifyFormat("using(StreamWriter sw = new StreamWriter(filenameB)) {}", 317 Style); 318 319 Style.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements; 320 verifyFormat("public void foo() {\n" 321 " using (StreamWriter sw = new StreamWriter(filenameA)) {}\n" 322 " using () {}\n" 323 "}", 324 Style); 325 326 // Ensure clang-format affects top-level snippets correctly. 327 verifyFormat("using (StreamWriter sw = new StreamWriter(filenameB)) {}", 328 Style); 329 330 Style.SpaceBeforeParens = FormatStyle::SBPO_NonEmptyParentheses; 331 verifyFormat("public void foo() {\n" 332 " using (StreamWriter sw = new StreamWriter (filenameA)) {}\n" 333 " using() {}\n" 334 "}", 335 Style); 336 337 // Ensure clang-format affects top-level snippets correctly. 338 verifyFormat("using (StreamWriter sw = new StreamWriter (filenameB)) {}", 339 Style); 340 } 341 342 TEST_F(FormatTestCSharp, CSharpRegions) { 343 verifyFormat("#region aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaa " 344 "aaaaaaaaaaaaaaa long region"); 345 } 346 347 TEST_F(FormatTestCSharp, CSharpKeyWordEscaping) { 348 verifyFormat("public enum var\n" 349 "{\n" 350 " none,\n" 351 " @string,\n" 352 " bool,\n" 353 " @enum\n" 354 "}"); 355 } 356 357 TEST_F(FormatTestCSharp, CSharpNullCoalescing) { 358 verifyFormat("var test = ABC ?? DEF"); 359 verifyFormat("string myname = name ?? \"ABC\";"); 360 verifyFormat("return _name ?? \"DEF\";"); 361 } 362 363 TEST_F(FormatTestCSharp, AttributesIndentation) { 364 FormatStyle Style = getMicrosoftStyle(FormatStyle::LK_CSharp); 365 Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None; 366 367 verifyFormat("[STAThread]\n" 368 "static void Main(string[] args)\n" 369 "{\n" 370 "}", 371 Style); 372 373 verifyFormat("[STAThread]\n" 374 "void " 375 "veryLooooooooooooooongFunctionName(string[] args)\n" 376 "{\n" 377 "}", 378 Style); 379 380 verifyFormat("[STAThread]\n" 381 "veryLoooooooooooooooooooongReturnType " 382 "veryLooooooooooooooongFunctionName(string[] args)\n" 383 "{\n" 384 "}", 385 Style); 386 387 verifyFormat("[SuppressMessage(\"A\", \"B\", Justification = \"C\")]\n" 388 "public override X Y()\n" 389 "{\n" 390 "}\n", 391 Style); 392 393 verifyFormat("[SuppressMessage]\n" 394 "public X Y()\n" 395 "{\n" 396 "}\n", 397 Style); 398 399 verifyFormat("[SuppressMessage]\n" 400 "public override X Y()\n" 401 "{\n" 402 "}\n", 403 Style); 404 405 verifyFormat("public A(B b) : base(b)\n" 406 "{\n" 407 " [SuppressMessage]\n" 408 " public override X Y()\n" 409 " {\n" 410 " }\n" 411 "}\n", 412 Style); 413 414 verifyFormat("public A : Base\n" 415 "{\n" 416 "}\n" 417 "[Test]\n" 418 "public Foo()\n" 419 "{\n" 420 "}\n", 421 Style); 422 423 verifyFormat("namespace\n" 424 "{\n" 425 "public A : Base\n" 426 "{\n" 427 "}\n" 428 "[Test]\n" 429 "public Foo()\n" 430 "{\n" 431 "}\n" 432 "}\n", 433 Style); 434 } 435 436 TEST_F(FormatTestCSharp, CSharpSpaceBefore) { 437 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 438 Style.SpaceBeforeParens = FormatStyle::SBPO_Always; 439 440 verifyFormat("List<string> list;", Style); 441 verifyFormat("Dictionary<string, string> dict;", Style); 442 443 verifyFormat("for (int i = 0; i < size (); i++) {\n" 444 "}", 445 Style); 446 verifyFormat("foreach (var x in y) {\n" 447 "}", 448 Style); 449 verifyFormat("switch (x) {}", Style); 450 verifyFormat("do {\n" 451 "} while (x);", 452 Style); 453 454 Style.SpaceBeforeParens = FormatStyle::SBPO_Never; 455 456 verifyFormat("List<string> list;", Style); 457 verifyFormat("Dictionary<string, string> dict;", Style); 458 459 verifyFormat("for(int i = 0; i < size(); i++) {\n" 460 "}", 461 Style); 462 verifyFormat("foreach(var x in y) {\n" 463 "}", 464 Style); 465 verifyFormat("switch(x) {}", Style); 466 verifyFormat("do {\n" 467 "} while(x);", 468 Style); 469 } 470 471 TEST_F(FormatTestCSharp, CSharpSpaceAfterCStyleCast) { 472 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 473 474 verifyFormat("(int)x / y;", Style); 475 476 Style.SpaceAfterCStyleCast = true; 477 verifyFormat("(int) x / y;", Style); 478 } 479 480 TEST_F(FormatTestCSharp, CSharpEscapedQuotesInVerbatimStrings) { 481 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 482 483 verifyFormat(R"(string str = @"""";)", Style); 484 verifyFormat(R"(string str = @"""Hello world""";)", Style); 485 verifyFormat(R"(string str = $@"""Hello {friend}""";)", Style); 486 } 487 488 TEST_F(FormatTestCSharp, CSharpQuotesInInterpolatedStrings) { 489 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 490 491 verifyFormat(R"(string str1 = $"{null ?? "null"}";)", Style); 492 verifyFormat(R"(string str2 = $"{{{braceCount} braces";)", Style); 493 verifyFormat(R"(string str3 = $"{braceCount}}} braces";)", Style); 494 } 495 496 TEST_F(FormatTestCSharp, CSharpNewlinesInVerbatimStrings) { 497 // Use MS style as Google Style inserts a line break before multiline strings. 498 499 // verifyFormat does not understand multiline C# string-literals 500 // so check the format explicitly. 501 502 FormatStyle Style = getMicrosoftStyle(FormatStyle::LK_CSharp); 503 504 std::string Code = R"(string s1 = $@"some code: 505 class {className} {{ 506 {className}() {{}} 507 }}";)"; 508 509 EXPECT_EQ(Code, format(Code, Style)); 510 511 // Multiline string in the middle of a function call. 512 Code = R"( 513 var x = foo(className, $@"some code: 514 class {className} {{ 515 {className}() {{}} 516 }}", 517 y);)"; // y aligned with `className` arg. 518 519 EXPECT_EQ(Code, format(Code, Style)); 520 521 // Interpolated string with embedded multiline string. 522 Code = R"(Console.WriteLine($"{string.Join(@", 523 ", values)}");)"; 524 525 EXPECT_EQ(Code, format(Code, Style)); 526 } 527 528 TEST_F(FormatTestCSharp, CSharpLambdas) { 529 FormatStyle GoogleStyle = getGoogleStyle(FormatStyle::LK_CSharp); 530 FormatStyle MicrosoftStyle = getMicrosoftStyle(FormatStyle::LK_CSharp); 531 532 verifyFormat(R"(// 533 class MyClass { 534 Action<string> greet = name => { 535 string greeting = $"Hello {name}!"; 536 Console.WriteLine(greeting); 537 }; 538 })", 539 GoogleStyle); 540 541 // Microsoft Style: 542 // https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/lambda-expressions#statement-lambdas 543 verifyFormat(R"(// 544 class MyClass 545 { 546 Action<string> greet = name => 547 { 548 string greeting = $"Hello {name}!"; 549 Console.WriteLine(greeting); 550 }; 551 })", 552 MicrosoftStyle); 553 } 554 555 TEST_F(FormatTestCSharp, CSharpObjectInitializers) { 556 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 557 558 // Start code fragments with a comment line so that C++ raw string literals 559 // as seen are identical to expected formatted code. 560 561 verifyFormat(R"(// 562 Shape[] shapes = new[] { 563 new Circle { 564 Radius = 2.7281, 565 Colour = Colours.Red, 566 }, 567 new Square { 568 Side = 101.1, 569 Colour = Colours.Yellow, 570 }, 571 };)", 572 Style); 573 574 // Omitted final `,`s will change the formatting. 575 verifyFormat(R"(// 576 Shape[] shapes = new[] { new Circle { Radius = 2.7281, Colour = Colours.Red }, 577 new Square { Side = 101.1, Colour = Colours.Yellow } };)", 578 Style); 579 580 // Lambdas can be supplied as initialiser arguments. 581 verifyFormat(R"(// 582 private Transformer _transformer = new X.Y { 583 Filler = (Shape shape) => { return new Transform.Fill(shape, RED); }, 584 Scaler = (Shape shape) => { return new Transform.Resize(shape, 0.1); }, 585 };)", 586 Style); 587 588 // Dictionary initialisation. 589 verifyFormat(R"(// 590 var myDict = new Dictionary<string, string> { 591 ["name"] = _donald, 592 ["age"] = Convert.ToString(DateTime.Today.Year - 1934), 593 ["type"] = _duck, 594 };)", 595 Style); 596 } 597 598 TEST_F(FormatTestCSharp, CSharpArrayInitializers) { 599 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 600 601 verifyFormat(R"(// 602 private MySet<Node>[] setPoints = { 603 new Point<Node>(), 604 new Point<Node>(), 605 };)", 606 Style); 607 } 608 609 TEST_F(FormatTestCSharp, CSharpNamedArguments) { 610 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 611 612 verifyFormat(R"(// 613 PrintOrderDetails(orderNum: 31, productName: "Red Mug", sellerName: "Gift Shop");)", 614 Style); 615 616 // Ensure that trailing comments do not cause problems. 617 verifyFormat(R"(// 618 PrintOrderDetails(orderNum: 31, productName: "Red Mug", // comment 619 sellerName: "Gift Shop");)", 620 Style); 621 622 verifyFormat(R"(foreach (var tickCount in task.Begin(seed: 0)) {)", Style); 623 } 624 625 TEST_F(FormatTestCSharp, CSharpPropertyAccessors) { 626 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 627 628 verifyFormat("int Value { get }", Style); 629 verifyFormat("int Value { get; }", Style); 630 verifyFormat("int Value { internal get; }", Style); 631 verifyFormat("int Value { get; } = 0", Style); 632 verifyFormat("int Value { set }", Style); 633 verifyFormat("int Value { set; }", Style); 634 verifyFormat("int Value { internal set; }", Style); 635 verifyFormat("int Value { set; } = 0", Style); 636 verifyFormat("int Value { get; set }", Style); 637 verifyFormat("int Value { set; get }", Style); 638 verifyFormat("int Value { get; private set; }", Style); 639 verifyFormat("int Value { get; set; }", Style); 640 verifyFormat("int Value { get; set; } = 0", Style); 641 verifyFormat("int Value { internal get; internal set; }", Style); 642 643 // Do not wrap expression body definitions. 644 verifyFormat(R"(// 645 public string Name { 646 get => _name; 647 set => _name = value; 648 })", 649 Style); 650 651 // Examples taken from 652 // https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties 653 verifyFormat(R"( 654 // Expression body definitions 655 public class SaleItem { 656 public decimal Price { 657 get => _cost; 658 set => _cost = value; 659 } 660 })", 661 Style); 662 663 verifyFormat(R"( 664 // Properties with backing fields 665 class TimePeriod { 666 public double Hours { 667 get { return _seconds / 3600; } 668 set { 669 if (value < 0 || value > 24) 670 throw new ArgumentOutOfRangeException($"{nameof(value)} must be between 0 and 24."); 671 _seconds = value * 3600; 672 } 673 } 674 })", 675 Style); 676 677 verifyFormat(R"( 678 // Auto-implemented properties 679 public class SaleItem { 680 public decimal Price { get; set; } 681 })", 682 Style); 683 684 // Add column limit to wrap long lines. 685 Style.ColumnLimit = 100; 686 687 // Examples with assignment to default value. 688 verifyFormat(R"( 689 // Long assignment to default value 690 class MyClass { 691 public override VeryLongNamedTypeIndeed VeryLongNamedValue { get; set } = 692 VeryLongNamedTypeIndeed.Create(DefaultFirstArgument, DefaultSecondArgument, 693 DefaultThirdArgument); 694 })", 695 Style); 696 697 verifyFormat(R"( 698 // Long assignment to default value with expression body 699 class MyClass { 700 public override VeryLongNamedTypeIndeed VeryLongNamedValue { 701 get => veryLongNamedField; 702 set => veryLongNamedField = value; 703 } = VeryLongNamedTypeIndeed.Create(DefaultFirstArgument, DefaultSecondArgument, 704 DefaultThirdArgument); 705 })", 706 Style); 707 708 // Brace wrapping and single-lining of accessor can be controlled by config. 709 Style.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Never; 710 Style.BreakBeforeBraces = FormatStyle::BS_Custom; 711 Style.BraceWrapping.AfterFunction = true; 712 713 verifyFormat(R"(// 714 public class SaleItem { 715 public decimal Price 716 { get; set; } 717 })", 718 Style); 719 720 verifyFormat(R"(// 721 class TimePeriod { 722 public double Hours 723 { 724 get { 725 return _seconds / 3600; 726 } 727 set { 728 _seconds = value * 3600; 729 } 730 } 731 })", 732 Style); 733 } 734 735 TEST_F(FormatTestCSharp, CSharpSpaces) { 736 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 737 Style.SpaceBeforeSquareBrackets = false; 738 Style.SpacesInSquareBrackets = false; 739 Style.SpaceBeforeCpp11BracedList = true; 740 Style.Cpp11BracedListStyle = false; 741 Style.SpacesInContainerLiterals = false; 742 Style.SpaceAfterCStyleCast = false; 743 744 verifyFormat(R"(new Car { "Door", 0.1 })", Style); 745 verifyFormat(R"(new Car { 0.1, "Door" })", Style); 746 verifyFormat(R"(new string[] { "A" })", Style); 747 verifyFormat(R"(new string[] {})", Style); 748 verifyFormat(R"(new Car { someVariableName })", Style); 749 verifyFormat(R"(new Car { someVariableName })", Style); 750 verifyFormat(R"(new Dictionary<string, string> { ["Key"] = "Value" };)", 751 Style); 752 verifyFormat(R"(Apply(x => x.Name, x => () => x.ID);)", Style); 753 verifyFormat(R"(bool[] xs = { true, true };)", Style); 754 verifyFormat(R"(taskContext.Factory.Run(async () => doThing(args);)", Style); 755 verifyFormat(R"(catch (TestException) when (innerFinallyExecuted))", Style); 756 verifyFormat(R"(private float[,] Values;)", Style); 757 verifyFormat(R"(Result this[Index x] => Foo(x);)", Style); 758 759 verifyFormat(R"(char[,,] rawCharArray = MakeCharacterGrid();)", Style); 760 verifyFormat(R"(var (key, value))", Style); 761 762 // `&&` is not seen as a reference. 763 verifyFormat(R"(A == typeof(X) && someBool)", Style); 764 765 // Not seen as a C-style cast. 766 verifyFormat(R"(// 767 foreach ((A a, B b) in someList) { 768 })", 769 Style); 770 771 // space after lock in `lock (processes)`. 772 verifyFormat("lock (process)", Style); 773 774 Style.SpacesInSquareBrackets = true; 775 verifyFormat(R"(private float[ , ] Values;)", Style); 776 verifyFormat(R"(string dirPath = args?[ 0 ];)", Style); 777 verifyFormat(R"(char[ ,, ] rawCharArray = MakeCharacterGrid();)", Style); 778 } 779 780 TEST_F(FormatTestCSharp, CSharpNullableTypes) { 781 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 782 Style.SpacesInSquareBrackets = false; 783 784 verifyFormat(R"(// 785 public class A { 786 void foo() { 787 int? value = some.bar(); 788 } 789 })", 790 Style); // int? is nullable not a conditional expression. 791 792 verifyFormat(R"(void foo(int? x, int? y, int? z) {})", 793 Style); // Nullables in function definitions. 794 795 verifyFormat(R"(public float? Value;)", Style); // no space before `?`. 796 797 verifyFormat(R"(int?[] arr = new int?[10];)", 798 Style); // An array of a nullable type. 799 800 verifyFormat(R"(var x = (int?)y;)", Style); // Cast to a nullable type. 801 802 verifyFormat(R"(var x = new MyContainer<int?>();)", Style); // Generics. 803 } 804 805 TEST_F(FormatTestCSharp, CSharpArraySubscripts) { 806 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 807 808 // Do not format array subscript operators as attributes. 809 verifyFormat(R"(// 810 if (someThings[index].Contains(myThing)) { 811 })", 812 Style); 813 814 verifyFormat(R"(// 815 if (someThings[i][j][k].Contains(myThing)) { 816 })", 817 Style); 818 } 819 820 TEST_F(FormatTestCSharp, CSharpGenericTypeConstraints) { 821 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 822 823 verifyFormat(R"(// 824 class ItemFactory<T> 825 where T : new() {})", 826 Style); 827 828 verifyFormat(R"(// 829 class Dictionary<TKey, TVal> 830 where TKey : IComparable<TKey> 831 where TVal : IMyInterface { 832 public void MyMethod<T>(T t) 833 where T : IMyInterface { 834 doThing(); 835 } 836 })", 837 Style); 838 839 verifyFormat(R"(// 840 class ItemFactory<T> 841 where T : new(), IAnInterface<T>, IAnotherInterface<T>, IAnotherInterfaceStill<T> {})", 842 Style); 843 844 Style.ColumnLimit = 50; // Force lines to be wrapped. 845 verifyFormat(R"(// 846 class ItemFactory<T, U> 847 where T : new(), 848 IAnInterface<T>, 849 IAnotherInterface<T, U>, 850 IAnotherInterfaceStill<T, U> {})", 851 Style); 852 853 // In other languages `where` can be used as a normal identifier. 854 // This example is in C++! 855 verifyFormat(R"(// 856 class A { 857 int f(int where) {} 858 };)", 859 getGoogleStyle(FormatStyle::LK_Cpp)); 860 } 861 862 } // namespace format 863 } // end namespace clang 864