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 { none, @string, bool, @enum }"); 349 } 350 351 TEST_F(FormatTestCSharp, CSharpNullCoalescing) { 352 verifyFormat("var test = ABC ?? DEF"); 353 verifyFormat("string myname = name ?? \"ABC\";"); 354 verifyFormat("return _name ?? \"DEF\";"); 355 } 356 357 TEST_F(FormatTestCSharp, AttributesIndentation) { 358 FormatStyle Style = getMicrosoftStyle(FormatStyle::LK_CSharp); 359 Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None; 360 361 verifyFormat("[STAThread]\n" 362 "static void Main(string[] args)\n" 363 "{\n" 364 "}", 365 Style); 366 367 verifyFormat("[STAThread]\n" 368 "void " 369 "veryLooooooooooooooongFunctionName(string[] args)\n" 370 "{\n" 371 "}", 372 Style); 373 374 verifyFormat("[STAThread]\n" 375 "veryLoooooooooooooooooooongReturnType " 376 "veryLooooooooooooooongFunctionName(string[] args)\n" 377 "{\n" 378 "}", 379 Style); 380 381 verifyFormat("[SuppressMessage(\"A\", \"B\", Justification = \"C\")]\n" 382 "public override X Y()\n" 383 "{\n" 384 "}\n", 385 Style); 386 387 verifyFormat("[SuppressMessage]\n" 388 "public X Y()\n" 389 "{\n" 390 "}\n", 391 Style); 392 393 verifyFormat("[SuppressMessage]\n" 394 "public override X Y()\n" 395 "{\n" 396 "}\n", 397 Style); 398 399 verifyFormat("public A(B b) : base(b)\n" 400 "{\n" 401 " [SuppressMessage]\n" 402 " public override X Y()\n" 403 " {\n" 404 " }\n" 405 "}\n", 406 Style); 407 408 verifyFormat("public A : Base\n" 409 "{\n" 410 "}\n" 411 "[Test]\n" 412 "public Foo()\n" 413 "{\n" 414 "}\n", 415 Style); 416 417 verifyFormat("namespace\n" 418 "{\n" 419 "public A : Base\n" 420 "{\n" 421 "}\n" 422 "[Test]\n" 423 "public Foo()\n" 424 "{\n" 425 "}\n" 426 "}\n", 427 Style); 428 } 429 430 TEST_F(FormatTestCSharp, CSharpSpaceBefore) { 431 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 432 Style.SpaceBeforeParens = FormatStyle::SBPO_Always; 433 434 verifyFormat("List<string> list;", Style); 435 verifyFormat("Dictionary<string, string> dict;", Style); 436 437 verifyFormat("for (int i = 0; i < size (); i++) {\n" 438 "}", 439 Style); 440 verifyFormat("foreach (var x in y) {\n" 441 "}", 442 Style); 443 verifyFormat("switch (x) {}", Style); 444 verifyFormat("do {\n" 445 "} while (x);", 446 Style); 447 448 Style.SpaceBeforeParens = FormatStyle::SBPO_Never; 449 450 verifyFormat("List<string> list;", Style); 451 verifyFormat("Dictionary<string, string> dict;", Style); 452 453 verifyFormat("for(int i = 0; i < size(); i++) {\n" 454 "}", 455 Style); 456 verifyFormat("foreach(var x in y) {\n" 457 "}", 458 Style); 459 verifyFormat("switch(x) {}", Style); 460 verifyFormat("do {\n" 461 "} while(x);", 462 Style); 463 } 464 465 TEST_F(FormatTestCSharp, CSharpSpaceAfterCStyleCast) { 466 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 467 468 verifyFormat("(int)x / y;", Style); 469 470 Style.SpaceAfterCStyleCast = true; 471 verifyFormat("(int) x / y;", Style); 472 } 473 474 TEST_F(FormatTestCSharp, CSharpEscapedQuotesInVerbatimStrings) { 475 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 476 477 verifyFormat(R"(string str = @"""";)", Style); 478 verifyFormat(R"(string str = @"""Hello world""";)", Style); 479 verifyFormat(R"(string str = $@"""Hello {friend}""";)", Style); 480 } 481 482 TEST_F(FormatTestCSharp, CSharpQuotesInInterpolatedStrings) { 483 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 484 485 verifyFormat(R"(string str1 = $"{null ?? "null"}";)", Style); 486 verifyFormat(R"(string str2 = $"{{{braceCount} braces";)", Style); 487 verifyFormat(R"(string str3 = $"{braceCount}}} braces";)", Style); 488 } 489 490 TEST_F(FormatTestCSharp, CSharpNewlinesInVerbatimStrings) { 491 // Use MS style as Google Style inserts a line break before multiline strings. 492 493 // verifyFormat does not understand multiline C# string-literals 494 // so check the format explicitly. 495 496 FormatStyle Style = getMicrosoftStyle(FormatStyle::LK_CSharp); 497 498 std::string Code = R"(string s1 = $@"some code: 499 class {className} {{ 500 {className}() {{}} 501 }}";)"; 502 503 EXPECT_EQ(Code, format(Code, Style)); 504 505 // Multiline string in the middle of a function call. 506 Code = R"( 507 var x = foo(className, $@"some code: 508 class {className} {{ 509 {className}() {{}} 510 }}", 511 y);)"; // y aligned with `className` arg. 512 513 EXPECT_EQ(Code, format(Code, Style)); 514 515 // Interpolated string with embedded multiline string. 516 Code = R"(Console.WriteLine($"{string.Join(@", 517 ", values)}");)"; 518 519 EXPECT_EQ(Code, format(Code, Style)); 520 } 521 522 TEST_F(FormatTestCSharp, CSharpObjectInitializers) { 523 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 524 525 // Start code fragments with a comment line so that C++ raw string literals 526 // as seen are identical to expected formatted code. 527 528 verifyFormat(R"(// 529 Shape[] shapes = new[] { 530 new Circle { 531 Radius = 2.7281, 532 Colour = Colours.Red, 533 }, 534 new Square { 535 Side = 101.1, 536 Colour = Colours.Yellow, 537 }, 538 };)", 539 Style); 540 541 // Omitted final `,`s will change the formatting. 542 verifyFormat(R"(// 543 Shape[] shapes = new[] { new Circle { Radius = 2.7281, Colour = Colours.Red }, 544 new Square { Side = 101.1, Colour = Colours.Yellow } };)", 545 Style); 546 547 // Lambdas can be supplied as initialiser arguments. 548 verifyFormat(R"(// 549 private Transformer _transformer = new X.Y { 550 Filler = (Shape shape) => { return new Transform.Fill(shape, RED); }, 551 Scaler = (Shape shape) => { return new Transform.Resize(shape, 0.1); }, 552 };)", 553 Style); 554 555 // Dictionary initialisation. 556 verifyFormat(R"(// 557 var myDict = new Dictionary<string, string> { 558 ["name"] = _donald, 559 ["age"] = Convert.ToString(DateTime.Today.Year - 1934), 560 ["type"] = _duck, 561 };)", 562 Style); 563 } 564 565 TEST_F(FormatTestCSharp, CSharpNamedArguments) { 566 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 567 568 verifyFormat(R"(// 569 PrintOrderDetails(orderNum: 31, productName: "Red Mug", 570 sellerName: "Gift Shop");)", 571 Style); 572 573 // Ensure that trailing comments do not cause problems. 574 verifyFormat(R"(// 575 PrintOrderDetails(orderNum: 31, productName: "Red Mug", // comment 576 sellerName: "Gift Shop");)", 577 Style); 578 579 verifyFormat(R"(foreach (var tickCount in task.Begin(seed: 0)) {)", Style); 580 } 581 582 TEST_F(FormatTestCSharp, CSharpPropertyAccessors) { 583 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 584 585 verifyFormat("int Value { get }", Style); 586 verifyFormat("int Value { get; }", Style); 587 verifyFormat("int Value { internal get; }", Style); 588 verifyFormat("int Value { get; } = 0", Style); 589 verifyFormat("int Value { set }", Style); 590 verifyFormat("int Value { set; }", Style); 591 verifyFormat("int Value { internal set; }", Style); 592 verifyFormat("int Value { set; } = 0", Style); 593 verifyFormat("int Value { get; set }", Style); 594 verifyFormat("int Value { set; get }", Style); 595 verifyFormat("int Value { get; private set; }", Style); 596 verifyFormat("int Value { get; set; }", Style); 597 verifyFormat("int Value { get; set; } = 0", Style); 598 verifyFormat("int Value { internal get; internal set; }", Style); 599 600 // Do not wrap expression body definitions. 601 verifyFormat(R"(// 602 public string Name { 603 get => _name; 604 set => _name = value; 605 })", 606 Style); 607 } 608 609 TEST_F(FormatTestCSharp, CSharpSpaces) { 610 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 611 Style.SpaceBeforeSquareBrackets = false; 612 Style.SpacesInSquareBrackets = false; 613 Style.SpaceBeforeCpp11BracedList = true; 614 Style.Cpp11BracedListStyle = false; 615 Style.SpacesInContainerLiterals = false; 616 617 verifyFormat(R"(new Car { "Door", 0.1 })", Style); 618 verifyFormat(R"(new Car { 0.1, "Door" })", Style); 619 verifyFormat(R"(new string[] { "A" })", Style); 620 verifyFormat(R"(new string[] {})", Style); 621 verifyFormat(R"(new Car { someVariableName })", Style); 622 verifyFormat(R"(new Car { someVariableName })", Style); 623 verifyFormat(R"(new Dictionary<string, string> { ["Key"] = "Value" };)", 624 Style); 625 verifyFormat(R"(Apply(x => x.Name, x => () => x.ID);)", Style); 626 verifyFormat(R"(bool[] xs = { true, true };)", Style); 627 verifyFormat(R"(taskContext.Factory.Run(async () => doThing(args);)", Style); 628 verifyFormat(R"(catch (TestException) when (innerFinallyExecuted))", Style); 629 verifyFormat(R"(private float[,] Values;)", Style); 630 verifyFormat(R"(Result this[Index x] => Foo(x);)", Style); 631 verifyFormat(R"(class ItemFactory<T> where T : new() {})", Style); 632 633 Style.SpacesInSquareBrackets = true; 634 verifyFormat(R"(private float[ , ] Values;)", Style); 635 verifyFormat(R"(string dirPath = args?[ 0 ];)", Style); 636 } 637 638 TEST_F(FormatTestCSharp, CSharpNullableTypes) { 639 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 640 Style.SpacesInSquareBrackets = false; 641 642 verifyFormat(R"(// 643 public class A { 644 void foo() { int? value = some.bar(); } 645 })", 646 Style); // int? is nullable not a conditional expression. 647 648 verifyFormat(R"(void foo(int? x, int? y, int? z) {})", 649 Style); // Nullables in function definitions. 650 651 verifyFormat(R"(public float? Value;)", Style); // no space before `?`. 652 653 verifyFormat(R"(int?[] arr = new int?[10];)", 654 Style); // An array of a nullable type. 655 656 verifyFormat(R"(var x = (int?)y;)", Style); // Cast to a nullable type. 657 658 verifyFormat(R"(var x = new MyContainer<int?>();)", Style); // Generics. 659 } 660 661 TEST_F(FormatTestCSharp, CSharpArraySubscripts) { 662 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 663 664 // Do not format array subscript operators as attributes. 665 verifyFormat(R"(// 666 if (someThings[index].Contains(myThing)) { 667 })", 668 Style); 669 670 verifyFormat(R"(// 671 if (someThings[i][j][k].Contains(myThing)) { 672 })", 673 Style); 674 } 675 676 } // namespace format 677 } // end namespace clang 678