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 { set; get; }"); 249 250 verifyFormat("[TestMethod(\"start\", HelpText = \"Starts the server " 251 "listening on provided host\")]\n" 252 "public string Host { set; get; }"); 253 254 verifyFormat( 255 "[DllImport(\"Hello\", EntryPoint = \"hello_world\")]\n" 256 "// The const char* returned by hello_world must not be deleted.\n" 257 "private static extern IntPtr HelloFromCpp();)"); 258 259 // Class attributes go on their own line and do not affect layout of 260 // interfaces. Line wrapping decisions previously caused each interface to be 261 // on its own line. 262 verifyFormat("[SomeAttribute]\n" 263 "[SomeOtherAttribute]\n" 264 "public class A : IShape, IAnimal, IVehicle\n" 265 "{\n" 266 " int X;\n" 267 "}"); 268 269 // Attributes in a method declaration do not cause line wrapping. 270 verifyFormat("void MethodA([In][Out] ref double x)\n" 271 "{\n" 272 "}"); 273 274 // [] in an attribute do not cause premature line wrapping or indenting. 275 verifyFormat(R"(// 276 public class A 277 { 278 [SomeAttribute(new[] { RED, GREEN, BLUE }, -1.0f, 1.0f)] 279 [DoNotSerialize] 280 public Data MemberVariable; 281 })"); 282 283 // Unwrappable lines go on a line of their own. 284 // 'target:' is not treated as a label. 285 // Modify Style to enforce a column limit. 286 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 287 Style.ColumnLimit = 10; 288 verifyFormat(R"([assembly:InternalsVisibleTo( 289 "SomeAssembly, PublicKey=SomePublicKeyThatExceedsTheColumnLimit")])", 290 Style); 291 } 292 293 TEST_F(FormatTestCSharp, CSharpUsing) { 294 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 295 Style.SpaceBeforeParens = FormatStyle::SBPO_Always; 296 verifyFormat("public void foo () {\n" 297 " using (StreamWriter sw = new StreamWriter (filenameA)) {}\n" 298 " using () {}\n" 299 "}", 300 Style); 301 302 // Ensure clang-format affects top-level snippets correctly. 303 verifyFormat("using (StreamWriter sw = new StreamWriter (filenameB)) {}", 304 Style); 305 306 Style.SpaceBeforeParens = FormatStyle::SBPO_Never; 307 verifyFormat("public void foo() {\n" 308 " using(StreamWriter sw = new StreamWriter(filenameB)) {}\n" 309 " using() {}\n" 310 "}", 311 Style); 312 313 // Ensure clang-format affects top-level snippets correctly. 314 verifyFormat("using(StreamWriter sw = new StreamWriter(filenameB)) {}", 315 Style); 316 317 Style.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements; 318 verifyFormat("public void foo() {\n" 319 " using (StreamWriter sw = new StreamWriter(filenameA)) {}\n" 320 " using () {}\n" 321 "}", 322 Style); 323 324 // Ensure clang-format affects top-level snippets correctly. 325 verifyFormat("using (StreamWriter sw = new StreamWriter(filenameB)) {}", 326 Style); 327 328 Style.SpaceBeforeParens = FormatStyle::SBPO_NonEmptyParentheses; 329 verifyFormat("public void foo() {\n" 330 " using (StreamWriter sw = new StreamWriter (filenameA)) {}\n" 331 " using() {}\n" 332 "}", 333 Style); 334 335 // Ensure clang-format affects top-level snippets correctly. 336 verifyFormat("using (StreamWriter sw = new StreamWriter (filenameB)) {}", 337 Style); 338 } 339 340 TEST_F(FormatTestCSharp, CSharpRegions) { 341 verifyFormat("#region aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaa " 342 "aaaaaaaaaaaaaaa long region"); 343 } 344 345 TEST_F(FormatTestCSharp, CSharpKeyWordEscaping) { 346 verifyFormat("public enum var\n" 347 "{\n" 348 " none,\n" 349 " @string,\n" 350 " bool,\n" 351 " @enum\n" 352 "}"); 353 } 354 355 TEST_F(FormatTestCSharp, CSharpNullCoalescing) { 356 verifyFormat("var test = ABC ?? DEF"); 357 verifyFormat("string myname = name ?? \"ABC\";"); 358 verifyFormat("return _name ?? \"DEF\";"); 359 } 360 361 TEST_F(FormatTestCSharp, AttributesIndentation) { 362 FormatStyle Style = getMicrosoftStyle(FormatStyle::LK_CSharp); 363 Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None; 364 365 verifyFormat("[STAThread]\n" 366 "static void Main(string[] args)\n" 367 "{\n" 368 "}", 369 Style); 370 371 verifyFormat("[STAThread]\n" 372 "void " 373 "veryLooooooooooooooongFunctionName(string[] args)\n" 374 "{\n" 375 "}", 376 Style); 377 378 verifyFormat("[STAThread]\n" 379 "veryLoooooooooooooooooooongReturnType " 380 "veryLooooooooooooooongFunctionName(string[] args)\n" 381 "{\n" 382 "}", 383 Style); 384 385 verifyFormat("[SuppressMessage(\"A\", \"B\", Justification = \"C\")]\n" 386 "public override X Y()\n" 387 "{\n" 388 "}\n", 389 Style); 390 391 verifyFormat("[SuppressMessage]\n" 392 "public X Y()\n" 393 "{\n" 394 "}\n", 395 Style); 396 397 verifyFormat("[SuppressMessage]\n" 398 "public override X Y()\n" 399 "{\n" 400 "}\n", 401 Style); 402 403 verifyFormat("public A(B b) : base(b)\n" 404 "{\n" 405 " [SuppressMessage]\n" 406 " public override X Y()\n" 407 " {\n" 408 " }\n" 409 "}\n", 410 Style); 411 412 verifyFormat("public A : Base\n" 413 "{\n" 414 "}\n" 415 "[Test]\n" 416 "public Foo()\n" 417 "{\n" 418 "}\n", 419 Style); 420 421 verifyFormat("namespace\n" 422 "{\n" 423 "public A : Base\n" 424 "{\n" 425 "}\n" 426 "[Test]\n" 427 "public Foo()\n" 428 "{\n" 429 "}\n" 430 "}\n", 431 Style); 432 } 433 434 TEST_F(FormatTestCSharp, CSharpSpaceBefore) { 435 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 436 Style.SpaceBeforeParens = FormatStyle::SBPO_Always; 437 438 verifyFormat("List<string> list;", Style); 439 verifyFormat("Dictionary<string, string> dict;", Style); 440 441 verifyFormat("for (int i = 0; i < size (); i++) {\n" 442 "}", 443 Style); 444 verifyFormat("foreach (var x in y) {\n" 445 "}", 446 Style); 447 verifyFormat("switch (x) {}", Style); 448 verifyFormat("do {\n" 449 "} while (x);", 450 Style); 451 452 Style.SpaceBeforeParens = FormatStyle::SBPO_Never; 453 454 verifyFormat("List<string> list;", Style); 455 verifyFormat("Dictionary<string, string> dict;", Style); 456 457 verifyFormat("for(int i = 0; i < size(); i++) {\n" 458 "}", 459 Style); 460 verifyFormat("foreach(var x in y) {\n" 461 "}", 462 Style); 463 verifyFormat("switch(x) {}", Style); 464 verifyFormat("do {\n" 465 "} while(x);", 466 Style); 467 } 468 469 TEST_F(FormatTestCSharp, CSharpSpaceAfterCStyleCast) { 470 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 471 472 verifyFormat("(int)x / y;", Style); 473 474 Style.SpaceAfterCStyleCast = true; 475 verifyFormat("(int) x / y;", Style); 476 } 477 478 TEST_F(FormatTestCSharp, CSharpEscapedQuotesInVerbatimStrings) { 479 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 480 481 verifyFormat(R"(string str = @"""";)", Style); 482 verifyFormat(R"(string str = @"""Hello world""";)", Style); 483 verifyFormat(R"(string str = $@"""Hello {friend}""";)", Style); 484 } 485 486 TEST_F(FormatTestCSharp, CSharpQuotesInInterpolatedStrings) { 487 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 488 489 verifyFormat(R"(string str1 = $"{null ?? "null"}";)", Style); 490 verifyFormat(R"(string str2 = $"{{{braceCount} braces";)", Style); 491 verifyFormat(R"(string str3 = $"{braceCount}}} braces";)", Style); 492 } 493 494 TEST_F(FormatTestCSharp, CSharpNewlinesInVerbatimStrings) { 495 // Use MS style as Google Style inserts a line break before multiline strings. 496 497 // verifyFormat does not understand multiline C# string-literals 498 // so check the format explicitly. 499 500 FormatStyle Style = getMicrosoftStyle(FormatStyle::LK_CSharp); 501 502 std::string Code = R"(string s1 = $@"some code: 503 class {className} {{ 504 {className}() {{}} 505 }}";)"; 506 507 EXPECT_EQ(Code, format(Code, Style)); 508 509 // Multiline string in the middle of a function call. 510 Code = R"( 511 var x = foo(className, $@"some code: 512 class {className} {{ 513 {className}() {{}} 514 }}", 515 y);)"; // y aligned with `className` arg. 516 517 EXPECT_EQ(Code, format(Code, Style)); 518 519 // Interpolated string with embedded multiline string. 520 Code = R"(Console.WriteLine($"{string.Join(@", 521 ", values)}");)"; 522 523 EXPECT_EQ(Code, format(Code, Style)); 524 } 525 526 TEST_F(FormatTestCSharp, CSharpObjectInitializers) { 527 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 528 529 // Start code fragments with a comment line so that C++ raw string literals 530 // as seen are identical to expected formatted code. 531 532 verifyFormat(R"(// 533 Shape[] shapes = new[] { 534 new Circle { 535 Radius = 2.7281, 536 Colour = Colours.Red, 537 }, 538 new Square { 539 Side = 101.1, 540 Colour = Colours.Yellow, 541 }, 542 };)", 543 Style); 544 545 // Omitted final `,`s will change the formatting. 546 verifyFormat(R"(// 547 Shape[] shapes = new[] { new Circle { Radius = 2.7281, Colour = Colours.Red }, 548 new Square { Side = 101.1, Colour = Colours.Yellow } };)", 549 Style); 550 551 // Lambdas can be supplied as initialiser arguments. 552 verifyFormat(R"(// 553 private Transformer _transformer = new X.Y { 554 Filler = (Shape shape) => { return new Transform.Fill(shape, RED); }, 555 Scaler = (Shape shape) => { return new Transform.Resize(shape, 0.1); }, 556 };)", 557 Style); 558 559 // Dictionary initialisation. 560 verifyFormat(R"(// 561 var myDict = new Dictionary<string, string> { 562 ["name"] = _donald, 563 ["age"] = Convert.ToString(DateTime.Today.Year - 1934), 564 ["type"] = _duck, 565 };)", 566 Style); 567 } 568 569 TEST_F(FormatTestCSharp, CSharpArrayInitializers) { 570 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 571 572 verifyFormat(R"(// 573 private MySet<Node>[] setPoints = { 574 new Point<Node>(), 575 new Point<Node>(), 576 };)", 577 Style); 578 } 579 580 TEST_F(FormatTestCSharp, CSharpNamedArguments) { 581 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 582 583 verifyFormat(R"(// 584 PrintOrderDetails(orderNum: 31, productName: "Red Mug", 585 sellerName: "Gift Shop");)", 586 Style); 587 588 // Ensure that trailing comments do not cause problems. 589 verifyFormat(R"(// 590 PrintOrderDetails(orderNum: 31, productName: "Red Mug", // comment 591 sellerName: "Gift Shop");)", 592 Style); 593 594 verifyFormat(R"(foreach (var tickCount in task.Begin(seed: 0)) {)", Style); 595 } 596 597 TEST_F(FormatTestCSharp, CSharpPropertyAccessors) { 598 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 599 600 verifyFormat("int Value { get }", Style); 601 verifyFormat("int Value { get; }", Style); 602 verifyFormat("int Value { internal get; }", Style); 603 verifyFormat("int Value { get; } = 0", Style); 604 verifyFormat("int Value { set }", Style); 605 verifyFormat("int Value { set; }", Style); 606 verifyFormat("int Value { internal set; }", Style); 607 verifyFormat("int Value { set; } = 0", Style); 608 verifyFormat("int Value { get; set }", Style); 609 verifyFormat("int Value { set; get }", Style); 610 verifyFormat("int Value { get; private set; }", Style); 611 verifyFormat("int Value { get; set; }", Style); 612 verifyFormat("int Value { get; set; } = 0", Style); 613 verifyFormat("int Value { internal get; internal set; }", Style); 614 615 // Do not wrap expression body definitions. 616 verifyFormat(R"(// 617 public string Name { 618 get => _name; 619 set => _name = value; 620 })", 621 Style); 622 623 // Examples taken from 624 // https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties 625 verifyFormat(R"( 626 // Expression body definitions 627 public class SaleItem { 628 public decimal Price { 629 get => _cost; 630 set => _cost = value; 631 } 632 })", 633 Style); 634 635 verifyFormat(R"( 636 // Properties with backing fields 637 class TimePeriod { 638 public double Hours { 639 get { return _seconds / 3600; } 640 set { 641 if (value < 0 || value > 24) 642 throw new ArgumentOutOfRangeException( 643 $"{nameof(value)} must be between 0 and 24."); 644 _seconds = value * 3600; 645 } 646 } 647 })", 648 Style); 649 650 verifyFormat(R"( 651 // Auto-implemented properties 652 public class SaleItem { 653 public decimal Price { get; set; } 654 })", 655 Style); 656 657 // Add column limit to wrap long lines. 658 Style.ColumnLimit = 100; 659 660 // Examples with assignment to default value. 661 verifyFormat(R"( 662 // Long assignment to default value 663 class MyClass { 664 public override VeryLongNamedTypeIndeed VeryLongNamedValue { get; set } = 665 VeryLongNamedTypeIndeed.Create(DefaultFirstArgument, DefaultSecondArgument, 666 DefaultThirdArgument); 667 })", 668 Style); 669 670 verifyFormat(R"( 671 // Long assignment to default value with expression body 672 class MyClass { 673 public override VeryLongNamedTypeIndeed VeryLongNamedValue { 674 get => veryLongNamedField; 675 set => veryLongNamedField = value; 676 } = VeryLongNamedTypeIndeed.Create(DefaultFirstArgument, DefaultSecondArgument, 677 DefaultThirdArgument); 678 })", 679 Style); 680 } 681 682 TEST_F(FormatTestCSharp, CSharpSpaces) { 683 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 684 Style.SpaceBeforeSquareBrackets = false; 685 Style.SpacesInSquareBrackets = false; 686 Style.SpaceBeforeCpp11BracedList = true; 687 Style.Cpp11BracedListStyle = false; 688 Style.SpacesInContainerLiterals = false; 689 Style.SpaceAfterCStyleCast = false; 690 691 verifyFormat(R"(new Car { "Door", 0.1 })", Style); 692 verifyFormat(R"(new Car { 0.1, "Door" })", Style); 693 verifyFormat(R"(new string[] { "A" })", Style); 694 verifyFormat(R"(new string[] {})", Style); 695 verifyFormat(R"(new Car { someVariableName })", Style); 696 verifyFormat(R"(new Car { someVariableName })", Style); 697 verifyFormat(R"(new Dictionary<string, string> { ["Key"] = "Value" };)", 698 Style); 699 verifyFormat(R"(Apply(x => x.Name, x => () => x.ID);)", Style); 700 verifyFormat(R"(bool[] xs = { true, true };)", Style); 701 verifyFormat(R"(taskContext.Factory.Run(async () => doThing(args);)", Style); 702 verifyFormat(R"(catch (TestException) when (innerFinallyExecuted))", Style); 703 verifyFormat(R"(private float[,] Values;)", Style); 704 verifyFormat(R"(Result this[Index x] => Foo(x);)", Style); 705 706 verifyFormat(R"(char[,,] rawCharArray = MakeCharacterGrid();)", Style); 707 verifyFormat(R"(var (key, value))", Style); 708 709 // Not seen as a C-style cast. 710 verifyFormat(R"(// 711 foreach ((A a, B b) in someList) { 712 })", 713 Style); 714 715 Style.SpacesInSquareBrackets = true; 716 verifyFormat(R"(private float[ , ] Values;)", Style); 717 verifyFormat(R"(string dirPath = args?[ 0 ];)", Style); 718 verifyFormat(R"(char[ ,, ] rawCharArray = MakeCharacterGrid();)", Style); 719 } 720 721 TEST_F(FormatTestCSharp, CSharpNullableTypes) { 722 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 723 Style.SpacesInSquareBrackets = false; 724 725 verifyFormat(R"(// 726 public class A { 727 void foo() { int? value = some.bar(); } 728 })", 729 Style); // int? is nullable not a conditional expression. 730 731 verifyFormat(R"(void foo(int? x, int? y, int? z) {})", 732 Style); // Nullables in function definitions. 733 734 verifyFormat(R"(public float? Value;)", Style); // no space before `?`. 735 736 verifyFormat(R"(int?[] arr = new int?[10];)", 737 Style); // An array of a nullable type. 738 739 verifyFormat(R"(var x = (int?)y;)", Style); // Cast to a nullable type. 740 741 verifyFormat(R"(var x = new MyContainer<int?>();)", Style); // Generics. 742 } 743 744 TEST_F(FormatTestCSharp, CSharpArraySubscripts) { 745 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 746 747 // Do not format array subscript operators as attributes. 748 verifyFormat(R"(// 749 if (someThings[index].Contains(myThing)) { 750 })", 751 Style); 752 753 verifyFormat(R"(// 754 if (someThings[i][j][k].Contains(myThing)) { 755 })", 756 Style); 757 } 758 759 TEST_F(FormatTestCSharp, CSharpGenericTypeConstraints) { 760 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 761 762 verifyFormat(R"(// 763 class ItemFactory<T> 764 where T : new() {})", 765 Style); 766 767 verifyFormat(R"(// 768 class Dictionary<TKey, TVal> 769 where TKey : IComparable<TKey> 770 where TVal : IMyInterface { 771 public void MyMethod<T>(T t) 772 where T : IMyInterface { doThing(); } 773 })", 774 Style); 775 776 verifyFormat(R"(// 777 class ItemFactory<T> 778 where T : new(), 779 IAnInterface<T>, 780 IAnotherInterface<T>, 781 IAnotherInterfaceStill<T> {})", 782 Style); 783 784 Style.ColumnLimit = 50; // Force lines to be wrapped. 785 verifyFormat(R"(// 786 class ItemFactory<T, U> 787 where T : new(), 788 IAnInterface<T>, 789 IAnotherInterface<T, U>, 790 IAnotherInterfaceStill<T, U> {})", 791 Style); 792 793 // In other languages `where` can be used as a normal identifier. 794 // This example is in C++! 795 verifyFormat(R"(// 796 class A { 797 int f(int where) {} 798 };)", 799 getGoogleStyle(FormatStyle::LK_Cpp)); 800 } 801 802 } // namespace format 803 } // end namespace clang 804