1730 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "FormatTestBase.h"10 11#define DEBUG_TYPE "format-test"12 13namespace clang {14namespace format {15namespace test {16namespace {17 18class FormatTestCSharp : public test::FormatTestBase {19protected: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::string37 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 49TEST_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 condensed71 // (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 95TEST_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 127TEST_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 138TEST_F(FormatTestCSharp, StringLiteralBreaks) {139 // The line is 75 characters long. The default limit for the Microsoft style140 // 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 189TEST_F(FormatTestCSharp, CSharpVerbatiumStringLiterals) {190 verifyFormat("foo(@\"aaaaaaaa\\abc\\aaaa\");");191 // @"ABC\" + ToString("B") - handle embedded \ in literal string at192 // the end193 //194 /*195 * After removal of Lexer change we are currently not able196 * To handle these cases197 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 204TEST_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 at213 // the end214 verifyFormat("string s = $\"A{abc}BC\" + ToString(\"B\");");215 verifyFormat("$\"{domain}\\\\{user}\"");216 verifyFormat(217 "var verbatimInterpolated = $@\"C:\\Users\\{userName}\\Documents\\\";");218}219 220TEST_F(FormatTestCSharp, CSharpFatArrows) {221 verifyIncompleteFormat("Task serverTask = Task.Run(async() => {");222 verifyFormat("public override string ToString() => \"{Name}\\{Age}\";");223}224 225TEST_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 231TEST_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 255TEST_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 issues303 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 of343 // interfaces. Line wrapping decisions previously caused each interface to be344 // 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"(//387public class A388{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 404TEST_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 451TEST_F(FormatTestCSharp, CSharpRegions) {452 verifyFormat("#region aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaa "453 "aaaaaaaaaaaaaaa long region");454}455 456TEST_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 467TEST_F(FormatTestCSharp, CSharpNullCoalescing) {468 verifyFormat("var test = ABC ?? DEF");469 verifyFormat("string myname = name ?? \"ABC\";");470 verifyFormat("return _name ?? \"DEF\";");471}472 473TEST_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 486TEST_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 506TEST_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 579TEST_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 614TEST_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 623TEST_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 634TEST_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 642TEST_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-literals646 // 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"(659var 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 674TEST_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 692TEST_F(FormatTestCSharp, NewModifier) {693 verifyFormat("public new class NestedC {\n"694 " public int x = 100;\n"695 "}",696 getLLVMStyle(FormatStyle::LK_CSharp));697}698 699TEST_F(FormatTestCSharp, CSharpLambdas) {700 FormatStyle GoogleStyle = getGoogleStyle(FormatStyle::LK_CSharp);701 FormatStyle MicrosoftStyle = getMicrosoftStyle(FormatStyle::LK_CSharp);702 703 verifyFormat(R"(//704class MyClass {705 Action<string> greet = name => {706 string greeting = $"Hello {name}!";707 Console.WriteLine(greeting);708 };709})",710 GoogleStyle);711 712 // Microsoft Style:713 // https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/lambda-expressions#statement-lambdas714 verifyFormat(R"(//715class MyClass716{717 Action<string> greet = name =>718 {719 string greeting = $"Hello {name}!";720 Console.WriteLine(greeting);721 };722})",723 MicrosoftStyle);724 725 verifyFormat("void bar()\n"726 "{\n"727 " Function(Val, (Action)(() =>\n"728 " {\n"729 " lock (mylock)\n"730 " {\n"731 " if (true)\n"732 " {\n"733 " A.Remove(item);\n"734 " }\n"735 " }\n"736 " }));\n"737 "}",738 MicrosoftStyle);739 740 verifyFormat("void baz()\n"741 "{\n"742 " Function(Val, (Action)(() =>\n"743 " {\n"744 " using (var a = new Lock())\n"745 " {\n"746 " if (true)\n"747 " {\n"748 " A.Remove(item);\n"749 " }\n"750 " }\n"751 " }));\n"752 "}",753 MicrosoftStyle);754 755 verifyFormat("void baz()\n"756 "{\n"757 " Function(Val, (Action)(() =>\n"758 " {\n"759 " if (true)\n"760 " {\n"761 " A.Remove(item);\n"762 " }\n"763 " }));\n"764 "}",765 MicrosoftStyle);766 767 verifyFormat("void baz()\n"768 "{\n"769 " Function(Val, (Action)(() =>\n"770 " {\n"771 " do\n"772 " {\n"773 " A.Remove(item);\n"774 " } while (true)\n"775 " }));\n"776 "}",777 MicrosoftStyle);778 779 verifyFormat("void baz()\n"780 "{\n"781 " Function(Val, (Action)(() =>\n"782 " { A.Remove(item); }));\n"783 "}",784 MicrosoftStyle);785 786 verifyFormat("void bar()\n"787 "{\n"788 " Function(Val, (() =>\n"789 " {\n"790 " lock (mylock)\n"791 " {\n"792 " if (true)\n"793 " {\n"794 " A.Remove(item);\n"795 " }\n"796 " }\n"797 " }));\n"798 "}",799 MicrosoftStyle);800 verifyFormat("void bar()\n"801 "{\n"802 " Function((() =>\n"803 " {\n"804 " lock (mylock)\n"805 " {\n"806 " if (true)\n"807 " {\n"808 " A.Remove(item);\n"809 " }\n"810 " }\n"811 " }));\n"812 "}",813 MicrosoftStyle);814 815 MicrosoftStyle.IndentWidth = 2;816 verifyFormat("void bar()\n"817 "{\n"818 " Function((() =>\n"819 " {\n"820 " lock (mylock)\n"821 " {\n"822 " if (true)\n"823 " {\n"824 " A.Remove(item);\n"825 " }\n"826 " }\n"827 " }));\n"828 "}",829 MicrosoftStyle);830 verifyFormat("void bar() {\n"831 " Function((() => {\n"832 " lock (mylock) {\n"833 " if (true) {\n"834 " A.Remove(item);\n"835 " }\n"836 " }\n"837 " }));\n"838 "}",839 GoogleStyle);840}841 842TEST_F(FormatTestCSharp, CSharpLambdasDontBreakFollowingCodeAlignment) {843 FormatStyle GoogleStyle = getGoogleStyle(FormatStyle::LK_CSharp);844 FormatStyle MicrosoftStyle = getMicrosoftStyle(FormatStyle::LK_CSharp);845 846 verifyFormat(R"(//847public class Sample848{849 public void Test()850 {851 while (true)852 {853 preBindEnumerators.RemoveAll(enumerator => !enumerator.MoveNext());854 CodeThatFollowsLambda();855 IsWellAligned();856 }857 }858})",859 MicrosoftStyle);860 861 verifyFormat(R"(//862public class Sample {863 public void Test() {864 while (true) {865 preBindEnumerators.RemoveAll(enumerator => !enumerator.MoveNext());866 CodeThatFollowsLambda();867 IsWellAligned();868 }869 }870})",871 GoogleStyle);872}873 874TEST_F(FormatTestCSharp, CSharpLambdasComplexLambdasDontBreakAlignment) {875 FormatStyle GoogleStyle = getGoogleStyle(FormatStyle::LK_CSharp);876 FormatStyle MicrosoftStyle = getMicrosoftStyle(FormatStyle::LK_CSharp);877 878 verifyFormat(R"(//879public class Test880{881 private static void ComplexLambda(BuildReport protoReport)882 {883 allSelectedScenes =884 veryVeryLongCollectionNameThatPutsTheLineLenghtAboveTheThresholds.Where(scene => scene.enabled)885 .Select(scene => scene.path)886 .ToArray();887 if (allSelectedScenes.Count == 0)888 {889 return;890 }891 Functions();892 AreWell();893 Aligned();894 AfterLambdaBlock();895 }896})",897 MicrosoftStyle);898 899 verifyFormat(R"(//900public class Test {901 private static void ComplexLambda(BuildReport protoReport) {902 allSelectedScenes = veryVeryLongCollectionNameThatPutsTheLineLenghtAboveTheThresholds903 .Where(scene => scene.enabled)904 .Select(scene => scene.path)905 .ToArray();906 if (allSelectedScenes.Count == 0) {907 return;908 }909 Functions();910 AreWell();911 Aligned();912 AfterLambdaBlock();913 }914})",915 GoogleStyle);916}917 918TEST_F(FormatTestCSharp, CSharpLambdasMulipleLambdasDontBreakAlignment) {919 FormatStyle GoogleStyle = getGoogleStyle(FormatStyle::LK_CSharp);920 FormatStyle MicrosoftStyle = getMicrosoftStyle(FormatStyle::LK_CSharp);921 922 verifyFormat(R"(//923public class Test924{925 private static void MultipleLambdas(BuildReport protoReport)926 {927 allSelectedScenes =928 veryVeryLongCollectionNameThatPutsTheLineLenghtAboveTheThresholds.Where(scene => scene.enabled)929 .Select(scene => scene.path)930 .ToArray();931 preBindEnumerators.RemoveAll(enumerator => !enumerator.MoveNext());932 if (allSelectedScenes.Count == 0)933 {934 return;935 }936 Functions();937 AreWell();938 Aligned();939 AfterLambdaBlock();940 }941})",942 MicrosoftStyle);943 944 verifyFormat(R"(//945public class Test {946 private static void MultipleLambdas(BuildReport protoReport) {947 allSelectedScenes = veryVeryLongCollectionNameThatPutsTheLineLenghtAboveTheThresholds948 .Where(scene => scene.enabled)949 .Select(scene => scene.path)950 .ToArray();951 preBindEnumerators.RemoveAll(enumerator => !enumerator.MoveNext());952 if (allSelectedScenes.Count == 0) {953 return;954 }955 Functions();956 AreWell();957 Aligned();958 AfterLambdaBlock();959 }960})",961 GoogleStyle);962}963 964TEST_F(FormatTestCSharp, CSharpObjectInitializers) {965 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);966 967 // Start code fragments with a comment line so that C++ raw string literals968 // as seen are identical to expected formatted code.969 970 verifyFormat(R"(//971Shape[] shapes = new[] {972 new Circle {973 Radius = 2.7281,974 Colour = Colours.Red,975 },976 new Square {977 Side = 101.1,978 Colour = Colours.Yellow,979 },980};)",981 Style);982 983 // Omitted final `,`s will change the formatting.984 verifyFormat(R"(//985Shape[] shapes = new[] { new Circle { Radius = 2.7281, Colour = Colours.Red },986 new Square { Side = 101.1, Colour = Colours.Yellow } };)",987 Style);988 989 // Lambdas can be supplied as initialiser arguments.990 verifyFormat(R"(//991private Transformer _transformer = new X.Y {992 Filler = (Shape shape) => { return new Transform.Fill(shape, RED); },993 Scaler = (Shape shape) => { return new Transform.Resize(shape, 0.1); },994};)",995 Style);996 997 // Dictionary initialisation.998 verifyFormat(R"(//999var myDict = new Dictionary<string, string> {1000 ["name"] = _donald,1001 ["age"] = Convert.ToString(DateTime.Today.Year - 1934),1002 ["type"] = _duck,1003};)",1004 Style);1005}1006 1007TEST_F(FormatTestCSharp, CSharpArrayInitializers) {1008 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);1009 1010 verifyFormat(R"(//1011private MySet<Node>[] setPoints = {1012 new Point<Node>(),1013 new Point<Node>(),1014};)",1015 Style);1016}1017 1018TEST_F(FormatTestCSharp, CSharpNamedArguments) {1019 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);1020 1021 verifyFormat(R"(//1022PrintOrderDetails(orderNum: 31, productName: "Red Mug", sellerName: "Gift Shop");)",1023 Style);1024 1025 // Ensure that trailing comments do not cause problems.1026 verifyFormat(R"(//1027PrintOrderDetails(orderNum: 31, productName: "Red Mug", // comment1028 sellerName: "Gift Shop");)",1029 Style);1030 1031 verifyFormat(R"(foreach (var tickCount in task.Begin(seed: 0)) {)", Style);1032}1033 1034TEST_F(FormatTestCSharp, CSharpPropertyAccessors) {1035 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);1036 1037 verifyFormat("int Value { get }", Style);1038 verifyFormat("int Value { get; }", Style);1039 verifyFormat("int Value { internal get; }", Style);1040 verifyFormat("int Value { get; } = 0", Style);1041 verifyFormat("int Value { set }", Style);1042 verifyFormat("int Value { set; }", Style);1043 verifyFormat("int Value { init; }", Style);1044 verifyFormat("int Value { internal set; }", Style);1045 verifyFormat("int Value { set; } = 0", Style);1046 verifyFormat("int Value { get; set }", Style);1047 verifyFormat("int Value { get; init; }", Style);1048 verifyFormat("int Value { set; get }", Style);1049 verifyFormat("int Value { get; private set; }", Style);1050 verifyFormat("int Value { get; set; }", Style);1051 verifyFormat("int Value { get; set; } = 0", Style);1052 verifyFormat("int Value { internal get; internal set; }", Style);1053 1054 // Do not wrap expression body definitions.1055 verifyFormat(R"(//1056public string Name {1057 get => _name;1058 set => _name = value;1059})",1060 Style);1061 verifyFormat(R"(//1062public string Name {1063 init => _name = value;1064 get => _name;1065})",1066 Style);1067 verifyFormat(R"(//1068public string Name {1069 set => _name = value;1070 get => _name;1071})",1072 Style);1073 1074 // Examples taken from1075 // https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties1076 verifyFormat(R"(1077// Expression body definitions1078public class SaleItem {1079 public decimal Price {1080 get => _cost;1081 set => _cost = value;1082 }1083})",1084 Style);1085 1086 verifyFormat(R"(1087// Properties with backing fields1088class TimePeriod {1089 public double Hours {1090 get { return _seconds / 3600; }1091 set {1092 if (value < 0 || value > 24)1093 throw new ArgumentOutOfRangeException($"{nameof(value)} must be between 0 and 24.");1094 _seconds = value * 3600;1095 }1096 }1097})",1098 Style);1099 1100 verifyFormat(R"(1101// Auto-implemented properties1102public class SaleItem {1103 public decimal Price { get; set; }1104})",1105 Style);1106 1107 // Add column limit to wrap long lines.1108 Style.ColumnLimit = 100;1109 1110 // Examples with assignment to default value.1111 verifyFormat(R"(1112// Long assignment to default value1113class MyClass {1114 public override VeryLongNamedTypeIndeed VeryLongNamedValue { get; set } =1115 VeryLongNamedTypeIndeed.Create(DefaultFirstArgument, DefaultSecondArgument,1116 DefaultThirdArgument);1117})",1118 Style);1119 1120 verifyFormat(R"(1121// Long assignment to default value with expression body1122class MyClass {1123 public override VeryLongNamedTypeIndeed VeryLongNamedValue {1124 get => veryLongNamedField;1125 set => veryLongNamedField = value;1126 } = VeryLongNamedTypeIndeed.Create(DefaultFirstArgument, DefaultSecondArgument,1127 DefaultThirdArgument);1128})",1129 Style);1130 1131 // Brace wrapping and single-lining of accessor can be controlled by config.1132 Style.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Never;1133 Style.BreakBeforeBraces = FormatStyle::BS_Custom;1134 Style.BraceWrapping.AfterFunction = true;1135 1136 verifyFormat(R"(//1137class TimePeriod {1138 public double Hours1139 {1140 get {1141 return _seconds / 3600;1142 }1143 set {1144 _seconds = value * 3600;1145 }1146 }1147})",1148 Style);1149 1150 // Microsoft style trivial property accessors have no line break before the1151 // opening brace.1152 auto MicrosoftStyle = getMicrosoftStyle(FormatStyle::LK_CSharp);1153 verifyFormat(R"(//1154public class SaleItem1155{1156 public decimal Price { get; set; }1157})",1158 MicrosoftStyle);1159 1160 verifyFormat("internal class Program\n"1161 "{\n"1162 " bool AutoAllowKnownApps\n"1163 " {\n"1164 " get;\n"1165 " [Simple]\n"1166 " set;\n"1167 " }\n"1168 "}",1169 MicrosoftStyle);1170}1171 1172TEST_F(FormatTestCSharp, DefaultLiteral) {1173 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);1174 1175 verifyFormat(1176 "T[] InitializeArray<T>(int length, T initialValue = default) {}", Style);1177 verifyFormat("System.Numerics.Complex fillValue = default;", Style);1178 verifyFormat("int Value { get } = default;", Style);1179 verifyFormat("int Value { get } = default!;", Style);1180 verifyFormat(R"(//1181public record Person {1182 public string GetInit { get; init; } = default!;1183};)",1184 Style);1185 verifyFormat(R"(//1186public record Person {1187 public string GetSet { get; set; } = default!;1188};)",1189 Style);1190}1191 1192TEST_F(FormatTestCSharp, CSharpSpaces) {1193 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);1194 Style.SpaceBeforeSquareBrackets = false;1195 Style.SpacesInSquareBrackets = false;1196 Style.SpaceBeforeCpp11BracedList = true;1197 Style.Cpp11BracedListStyle = FormatStyle::BLS_Block;1198 Style.SpacesInContainerLiterals = false;1199 Style.SpaceAfterCStyleCast = false;1200 1201 verifyFormat(R"(new Car { "Door", 0.1 })", Style);1202 verifyFormat(R"(new Car { 0.1, "Door" })", Style);1203 verifyFormat(R"(new string[] { "A" })", Style);1204 verifyFormat(R"(new string[] {})", Style);1205 verifyFormat(R"(new Car { someVariableName })", Style);1206 verifyFormat(R"(new Car { someVariableName })", Style);1207 verifyFormat(R"(new Dictionary<string, string> { ["Key"] = "Value" };)",1208 Style);1209 verifyFormat(R"(Apply(x => x.Name, x => () => x.ID);)", Style);1210 verifyFormat(R"(bool[] xs = { true, true };)", Style);1211 verifyIncompleteFormat(1212 R"(taskContext.Factory.Run(async () => doThing(args);)", Style);1213 verifyFormat(R"(catch (TestException) when (innerFinallyExecuted))", Style);1214 verifyFormat(R"(private float[,] Values;)", Style);1215 verifyFormat(R"(Result this[Index x] => Foo(x);)", Style);1216 1217 verifyFormat(R"(char[,,] rawCharArray = MakeCharacterGrid();)", Style);1218 verifyFormat(R"(var (key, value))", Style);1219 1220 // `&&` is not seen as a reference.1221 verifyFormat(R"(A == typeof(X) && someBool)", Style);1222 1223 // Not seen as a C-style cast.1224 verifyFormat(R"(//1225foreach ((A a, B b) in someList) {1226})",1227 Style);1228 1229 // space after lock in `lock (processes)`.1230 verifyFormat("lock (process)", Style);1231 1232 Style.SpacesInSquareBrackets = true;1233 verifyFormat(R"(private float[ , ] Values;)", Style);1234 verifyFormat(R"(string dirPath = args?[ 0 ];)", Style);1235 verifyFormat(R"(char[ ,, ] rawCharArray = MakeCharacterGrid();)", Style);1236 1237 // Method returning tuple1238 verifyFormat(R"(public (string name, int age) methodTuple() {})", Style);1239 verifyFormat(R"(private (string name, int age) methodTuple() {})", Style);1240 verifyFormat(R"(protected (string name, int age) methodTuple() {})", Style);1241 verifyFormat(R"(virtual (string name, int age) methodTuple() {})", Style);1242 verifyFormat(R"(extern (string name, int age) methodTuple() {})", Style);1243 verifyFormat(R"(static (string name, int age) methodTuple() {})", Style);1244 verifyFormat(R"(internal (string name, int age) methodTuple() {})", Style);1245 verifyFormat(R"(abstract (string name, int age) methodTuple() {})", Style);1246 verifyFormat(R"(sealed (string name, int age) methodTuple() {})", Style);1247 verifyFormat(R"(override (string name, int age) methodTuple() {})", Style);1248 verifyFormat(R"(async (string name, int age) methodTuple() {})", Style);1249 verifyFormat(R"(unsafe (string name, int age) methodTuple() {})", Style);1250 1251 Style.SpacesInSquareBrackets = false;1252 Style.SpaceBeforeSquareBrackets = true;1253 verifyFormat("return a is [1, 2, 3];", Style);1254 verifyFormat("return a is [..];", Style);1255 Style.SpaceBeforeSquareBrackets = false;1256 verifyFormat("return a is [1, 2, 3];", Style);1257 verifyFormat("return a is [..];", Style);1258}1259 1260TEST_F(FormatTestCSharp, CSharpNullableTypes) {1261 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);1262 Style.SpacesInSquareBrackets = false;1263 1264 verifyFormat(R"(//1265public class A {1266 void foo() {1267 int? value = some.bar();1268 }1269})",1270 Style); // int? is nullable not a conditional expression.1271 1272 verifyFormat(R"(void foo(int? x, int? y, int? z) {})",1273 Style); // Nullables in function definitions.1274 1275 verifyFormat(R"(public float? Value;)", Style); // no space before `?`.1276 1277 verifyFormat(R"(int?[] arr = new int?[10];)",1278 Style); // An array of a nullable type.1279 1280 verifyFormat(R"(var x = (int?)y;)", Style); // Cast to a nullable type.1281 1282 verifyFormat(R"(var x = new MyContainer<int?>();)", Style); // Generics.1283 1284 verifyFormat(R"(//1285public interface I {1286 int? Function();1287})",1288 Style); // Interface methods.1289 1290 Style.ColumnLimit = 10;1291 verifyFormat(R"(//1292public VeryLongType? Function(1293 int arg1,1294 int arg2) {1295 //1296})",1297 Style); // ? sticks with identifier.1298}1299 1300TEST_F(FormatTestCSharp, CSharpArraySubscripts) {1301 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);1302 1303 // Do not format array subscript operators as attributes.1304 verifyFormat(R"(//1305if (someThings[index].Contains(myThing)) {1306})",1307 Style);1308 1309 verifyFormat(R"(//1310if (someThings[i][j][k].Contains(myThing)) {1311})",1312 Style);1313}1314 1315TEST_F(FormatTestCSharp, CSharpGenericTypeConstraints) {1316 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);1317 1318 EXPECT_TRUE(Style.BraceWrapping.SplitEmptyRecord);1319 1320 verifyFormat("class ItemFactory<T>\n"1321 " where T : new() {\n"1322 "}",1323 Style);1324 1325 verifyFormat("namespace A {\n"1326 " delegate T MyDelegate<T>()\n"1327 " where T : new();\n"1328 "}",1329 Style);1330 1331 // When the "where" line is not to be formatted, following lines should not1332 // take on its indentation.1333 verifyFormat("class ItemFactory<T>\n"1334 " where T : new() {\n"1335 " int f() {}\n"1336 "}",1337 "class ItemFactory<T>\n"1338 " where T : new() {\n"1339 " int f() {}\n"1340 "}",1341 Style, {tooling::Range(43, 13)});1342 1343 verifyFormat("class Dictionary<TKey, TVal>\n"1344 " where TKey : IComparable<TKey>\n"1345 " where TVal : IMyInterface {\n"1346 " public void MyMethod<T>(T t)\n"1347 " where T : IMyInterface {\n"1348 " doThing();\n"1349 " }\n"1350 "}",1351 Style);1352 1353 verifyFormat("class ItemFactory<T>\n"1354 " where T : new(), IAnInterface<T>, IAnotherInterface<T>, "1355 "IAnotherInterfaceStill<T> {\n"1356 "}",1357 Style);1358 1359 Style.ColumnLimit = 50; // Force lines to be wrapped.1360 verifyFormat(R"(//1361class ItemFactory<T, U>1362 where T : new(),1363 IAnInterface<T>,1364 IAnotherInterface<T, U>,1365 IAnotherInterfaceStill<T, U> {1366})",1367 Style);1368 1369 // In other languages `where` can be used as a normal identifier.1370 // This example is in C++!1371 verifyFormat(R"(//1372class A {1373 int f(int where) {}1374};)",1375 getGoogleStyle(FormatStyle::LK_Cpp));1376}1377 1378TEST_F(FormatTestCSharp, CSharpAfterEnum) {1379 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);1380 Style.BreakBeforeBraces = FormatStyle::BS_Custom;1381 Style.BraceWrapping.AfterEnum = false;1382 Style.AllowShortEnumsOnASingleLine = false;1383 1384 verifyFormat("enum MyEnum {\n"1385 " Foo,\n"1386 " Bar,\n"1387 "}",1388 Style);1389 verifyFormat("internal enum MyEnum {\n"1390 " Foo,\n"1391 " Bar,\n"1392 "}",1393 Style);1394 verifyFormat("public enum MyEnum {\n"1395 " Foo,\n"1396 " Bar,\n"1397 "}",1398 Style);1399 verifyFormat("protected enum MyEnum {\n"1400 " Foo,\n"1401 " Bar,\n"1402 "}",1403 Style);1404 verifyFormat("private enum MyEnum {\n"1405 " Foo,\n"1406 " Bar,\n"1407 "}",1408 Style);1409 1410 Style.BraceWrapping.AfterEnum = true;1411 Style.AllowShortEnumsOnASingleLine = false;1412 1413 verifyFormat("enum MyEnum\n"1414 "{\n"1415 " Foo,\n"1416 " Bar,\n"1417 "}",1418 Style);1419 verifyFormat("internal enum MyEnum\n"1420 "{\n"1421 " Foo,\n"1422 " Bar,\n"1423 "}",1424 Style);1425 verifyFormat("public enum MyEnum\n"1426 "{\n"1427 " Foo,\n"1428 " Bar,\n"1429 "}",1430 Style);1431 verifyFormat("protected enum MyEnum\n"1432 "{\n"1433 " Foo,\n"1434 " Bar,\n"1435 "}",1436 Style);1437 verifyFormat("private enum MyEnum\n"1438 "{\n"1439 " Foo,\n"1440 " Bar,\n"1441 "}",1442 Style);1443 verifyFormat("/* Foo */ private enum MyEnum\n"1444 "{\n"1445 " Foo,\n"1446 " Bar,\n"1447 "}",1448 Style);1449 verifyFormat("/* Foo */ /* Bar */ private enum MyEnum\n"1450 "{\n"1451 " Foo,\n"1452 " Bar,\n"1453 "}",1454 Style);1455}1456 1457TEST_F(FormatTestCSharp, CSharpAfterClass) {1458 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);1459 Style.BreakBeforeBraces = FormatStyle::BS_Custom;1460 Style.BraceWrapping.AfterClass = false;1461 1462 verifyFormat("class MyClass {\n"1463 " int a;\n"1464 " int b;\n"1465 "}",1466 Style);1467 verifyFormat("internal class MyClass {\n"1468 " int a;\n"1469 " int b;\n"1470 "}",1471 Style);1472 verifyFormat("public class MyClass {\n"1473 " int a;\n"1474 " int b;\n"1475 "}",1476 Style);1477 verifyFormat("protected class MyClass {\n"1478 " int a;\n"1479 " int b;\n"1480 "}",1481 Style);1482 verifyFormat("private class MyClass {\n"1483 " int a;\n"1484 " int b;\n"1485 "}",1486 Style);1487 1488 verifyFormat("interface Interface {\n"1489 " int a;\n"1490 " int b;\n"1491 "}",1492 Style);1493 verifyFormat("internal interface Interface {\n"1494 " int a;\n"1495 " int b;\n"1496 "}",1497 Style);1498 verifyFormat("public interface Interface {\n"1499 " int a;\n"1500 " int b;\n"1501 "}",1502 Style);1503 verifyFormat("protected interface Interface {\n"1504 " int a;\n"1505 " int b;\n"1506 "}",1507 Style);1508 verifyFormat("private interface Interface {\n"1509 " int a;\n"1510 " int b;\n"1511 "}",1512 Style);1513 1514 Style.BraceWrapping.AfterClass = true;1515 1516 verifyFormat("class MyClass\n"1517 "{\n"1518 " int a;\n"1519 " int b;\n"1520 "}",1521 Style);1522 verifyFormat("internal class MyClass\n"1523 "{\n"1524 " int a;\n"1525 " int b;\n"1526 "}",1527 Style);1528 verifyFormat("public class MyClass\n"1529 "{\n"1530 " int a;\n"1531 " int b;\n"1532 "}",1533 Style);1534 verifyFormat("protected class MyClass\n"1535 "{\n"1536 " int a;\n"1537 " int b;\n"1538 "}",1539 Style);1540 verifyFormat("private class MyClass\n"1541 "{\n"1542 " int a;\n"1543 " int b;\n"1544 "}",1545 Style);1546 1547 verifyFormat("interface MyInterface\n"1548 "{\n"1549 " int a;\n"1550 " int b;\n"1551 "}",1552 Style);1553 verifyFormat("internal interface MyInterface\n"1554 "{\n"1555 " int a;\n"1556 " int b;\n"1557 "}",1558 Style);1559 verifyFormat("public interface MyInterface\n"1560 "{\n"1561 " int a;\n"1562 " int b;\n"1563 "}",1564 Style);1565 verifyFormat("protected interface MyInterface\n"1566 "{\n"1567 " int a;\n"1568 " int b;\n"1569 "}",1570 Style);1571 verifyFormat("private interface MyInterface\n"1572 "{\n"1573 " int a;\n"1574 " int b;\n"1575 "}",1576 Style);1577 verifyFormat("/* Foo */ private interface MyInterface\n"1578 "{\n"1579 " int a;\n"1580 " int b;\n"1581 "}",1582 Style);1583 verifyFormat("/* Foo */ /* Bar */ private interface MyInterface\n"1584 "{\n"1585 " int a;\n"1586 " int b;\n"1587 "}",1588 Style);1589}1590 1591TEST_F(FormatTestCSharp, NamespaceIndentation) {1592 FormatStyle Style = getMicrosoftStyle(FormatStyle::LK_CSharp);1593 Style.NamespaceIndentation = FormatStyle::NI_None;1594 1595 verifyFormat("namespace A\n"1596 "{\n"1597 "public interface Name1\n"1598 "{\n"1599 "}\n"1600 "}",1601 Style);1602 1603 verifyFormat("namespace A.B\n"1604 "{\n"1605 "public interface Name1\n"1606 "{\n"1607 "}\n"1608 "}",1609 Style);1610 1611 Style.NamespaceIndentation = FormatStyle::NI_Inner;1612 1613 verifyFormat("namespace A\n"1614 "{\n"1615 "namespace B\n"1616 "{\n"1617 " public interface Name1\n"1618 " {\n"1619 " }\n"1620 "}\n"1621 "}",1622 Style);1623 1624 Style.NamespaceIndentation = FormatStyle::NI_All;1625 1626 verifyFormat("namespace A.B\n"1627 "{\n"1628 " public interface Name1\n"1629 " {\n"1630 " }\n"1631 "}",1632 Style);1633 1634 verifyFormat("namespace A\n"1635 "{\n"1636 " namespace B\n"1637 " {\n"1638 " public interface Name1\n"1639 " {\n"1640 " }\n"1641 " }\n"1642 "}",1643 Style);1644}1645 1646TEST_F(FormatTestCSharp, SwitchExpression) {1647 FormatStyle Style = getMicrosoftStyle(FormatStyle::LK_CSharp);1648 verifyFormat("int x = a switch {\n"1649 " 1 => (0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0),\n"1650 " 2 => 1,\n"1651 " _ => 2\n"1652 "};",1653 Style);1654}1655 1656TEST_F(FormatTestCSharp, EmptyShortBlock) {1657 auto Style = getLLVMStyle();1658 Style.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Empty;1659 1660 verifyFormat("try {\n"1661 " doA();\n"1662 "} catch (Exception e) {\n"1663 " e.printStackTrace();\n"1664 "}",1665 Style);1666 1667 verifyFormat("try {\n"1668 " doA();\n"1669 "} catch (Exception e) {}",1670 Style);1671}1672 1673TEST_F(FormatTestCSharp, ShortFunctions) {1674 FormatStyle Style = getLLVMStyle(FormatStyle::LK_CSharp);1675 Style.NamespaceIndentation = FormatStyle::NI_All;1676 Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;1677 verifyFormat("interface Interface {\n"1678 " void f() { return; }\n"1679 "};",1680 Style);1681 verifyFormat("public interface Interface {\n"1682 " void f() { return; }\n"1683 "};",1684 Style);1685 verifyFormat("namespace {\n"1686 " void f() {\n"1687 " return;\n"1688 " }\n"1689 "};",1690 Style);1691 // "union" is not a keyword in C#.1692 verifyFormat("namespace union {\n"1693 " void f() {\n"1694 " return;\n"1695 " }\n"1696 "};",1697 Style);1698}1699 1700TEST_F(FormatTestCSharp, BrokenBrackets) {1701 EXPECT_NE("", format("int where b <")); // reduced from crasher1702}1703 1704TEST_F(FormatTestCSharp, GotoCaseLabel) {1705 verifyFormat("switch (i)\n"1706 "{\n"1707 "case 0:\n"1708 " goto case 1;\n"1709 "case 1:\n"1710 " j = 0;\n"1711 " {\n"1712 " break;\n"1713 " }\n"1714 "}",1715 "switch (i) {\n"1716 "case 0:\n"1717 " goto case 1;\n"1718 "case 1:\n"1719 " j = 0;\n"1720 " {\n"1721 " break;\n"1722 " }\n"1723 "}");1724}1725 1726} // namespace1727} // namespace test1728} // namespace format1729} // namespace clang1730