xref: /llvm-project/clang/unittests/Format/FormatTestCSharp.cpp (revision ec725b307f3fdc5656459047bab6e69669d9534f)
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, CSharpNullCoalescingAssignment) {
362   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
363   Style.SpaceBeforeAssignmentOperators = true;
364 
365   verifyFormat(R"(test ??= ABC;)", Style);
366   verifyFormat(R"(test ??= true;)", Style);
367 
368   Style.SpaceBeforeAssignmentOperators = false;
369 
370   verifyFormat(R"(test??= ABC;)", Style);
371   verifyFormat(R"(test??= true;)", Style);
372 }
373 
374 TEST_F(FormatTestCSharp, CSharpNullForgiving) {
375   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
376 
377   verifyFormat("var test = null!;", Style);
378   verifyFormat("string test = someFunctionCall()! + \"ABC\"!", Style);
379   verifyFormat("int test = (1! + 2 + bar! + foo())!", Style);
380   verifyFormat(R"(test ??= !foo!;)", Style);
381   verifyFormat("test = !bar! ?? !foo!;", Style);
382   verifyFormat("bool test = !(!true && !true! || !null && !null! || !false && "
383                "!false! && !bar()! + (!foo()))!",
384                Style);
385 
386   // Check that line break keeps identifier with the bang.
387   Style.ColumnLimit = 14;
388 
389   verifyFormat("var test =\n"
390                "    foo!;",
391                Style);
392 }
393 
394 TEST_F(FormatTestCSharp, AttributesIndentation) {
395   FormatStyle Style = getMicrosoftStyle(FormatStyle::LK_CSharp);
396   Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None;
397 
398   verifyFormat("[STAThread]\n"
399                "static void Main(string[] args)\n"
400                "{\n"
401                "}",
402                Style);
403 
404   verifyFormat("[STAThread]\n"
405                "void "
406                "veryLooooooooooooooongFunctionName(string[] args)\n"
407                "{\n"
408                "}",
409                Style);
410 
411   verifyFormat("[STAThread]\n"
412                "veryLoooooooooooooooooooongReturnType "
413                "veryLooooooooooooooongFunctionName(string[] args)\n"
414                "{\n"
415                "}",
416                Style);
417 
418   verifyFormat("[SuppressMessage(\"A\", \"B\", Justification = \"C\")]\n"
419                "public override X Y()\n"
420                "{\n"
421                "}\n",
422                Style);
423 
424   verifyFormat("[SuppressMessage]\n"
425                "public X Y()\n"
426                "{\n"
427                "}\n",
428                Style);
429 
430   verifyFormat("[SuppressMessage]\n"
431                "public override X Y()\n"
432                "{\n"
433                "}\n",
434                Style);
435 
436   verifyFormat("public A(B b) : base(b)\n"
437                "{\n"
438                "    [SuppressMessage]\n"
439                "    public override X Y()\n"
440                "    {\n"
441                "    }\n"
442                "}\n",
443                Style);
444 
445   verifyFormat("public A : Base\n"
446                "{\n"
447                "}\n"
448                "[Test]\n"
449                "public Foo()\n"
450                "{\n"
451                "}\n",
452                Style);
453 
454   verifyFormat("namespace\n"
455                "{\n"
456                "public A : Base\n"
457                "{\n"
458                "}\n"
459                "[Test]\n"
460                "public Foo()\n"
461                "{\n"
462                "}\n"
463                "}\n",
464                Style);
465 }
466 
467 TEST_F(FormatTestCSharp, CSharpSpaceBefore) {
468   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
469   Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
470 
471   verifyFormat("List<string> list;", Style);
472   verifyFormat("Dictionary<string, string> dict;", Style);
473 
474   verifyFormat("for (int i = 0; i < size (); i++) {\n"
475                "}",
476                Style);
477   verifyFormat("foreach (var x in y) {\n"
478                "}",
479                Style);
480   verifyFormat("switch (x) {}", Style);
481   verifyFormat("do {\n"
482                "} while (x);",
483                Style);
484 
485   Style.SpaceBeforeParens = FormatStyle::SBPO_Never;
486 
487   verifyFormat("List<string> list;", Style);
488   verifyFormat("Dictionary<string, string> dict;", Style);
489 
490   verifyFormat("for(int i = 0; i < size(); i++) {\n"
491                "}",
492                Style);
493   verifyFormat("foreach(var x in y) {\n"
494                "}",
495                Style);
496   verifyFormat("switch(x) {}", Style);
497   verifyFormat("do {\n"
498                "} while(x);",
499                Style);
500 }
501 
502 TEST_F(FormatTestCSharp, CSharpSpaceAfterCStyleCast) {
503   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
504 
505   verifyFormat("(int)x / y;", Style);
506 
507   Style.SpaceAfterCStyleCast = true;
508   verifyFormat("(int) x / y;", Style);
509 }
510 
511 TEST_F(FormatTestCSharp, CSharpEscapedQuotesInVerbatimStrings) {
512   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
513 
514   verifyFormat(R"(string str = @"""";)", Style);
515   verifyFormat(R"(string str = @"""Hello world""";)", Style);
516   verifyFormat(R"(string str = $@"""Hello {friend}""";)", Style);
517 }
518 
519 TEST_F(FormatTestCSharp, CSharpQuotesInInterpolatedStrings) {
520   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
521 
522   verifyFormat(R"(string str1 = $"{null ?? "null"}";)", Style);
523   verifyFormat(R"(string str2 = $"{{{braceCount} braces";)", Style);
524   verifyFormat(R"(string str3 = $"{braceCount}}} braces";)", Style);
525 }
526 
527 TEST_F(FormatTestCSharp, CSharpNewlinesInVerbatimStrings) {
528   // Use MS style as Google Style inserts a line break before multiline strings.
529 
530   // verifyFormat does not understand multiline C# string-literals
531   // so check the format explicitly.
532 
533   FormatStyle Style = getMicrosoftStyle(FormatStyle::LK_CSharp);
534 
535   std::string Code = R"(string s1 = $@"some code:
536   class {className} {{
537     {className}() {{}}
538   }}";)";
539 
540   EXPECT_EQ(Code, format(Code, Style));
541 
542   // Multiline string in the middle of a function call.
543   Code = R"(
544 var x = foo(className, $@"some code:
545   class {className} {{
546     {className}() {{}}
547   }}",
548             y);)"; // y aligned with `className` arg.
549 
550   EXPECT_EQ(Code, format(Code, Style));
551 
552   // Interpolated string with embedded multiline string.
553   Code = R"(Console.WriteLine($"{string.Join(@",
554 		", values)}");)";
555 
556   EXPECT_EQ(Code, format(Code, Style));
557 }
558 
559 TEST_F(FormatTestCSharp, CSharpLambdas) {
560   FormatStyle GoogleStyle = getGoogleStyle(FormatStyle::LK_CSharp);
561   FormatStyle MicrosoftStyle = getMicrosoftStyle(FormatStyle::LK_CSharp);
562 
563   verifyFormat(R"(//
564 class MyClass {
565   Action<string> greet = name => {
566     string greeting = $"Hello {name}!";
567     Console.WriteLine(greeting);
568   };
569 })",
570                GoogleStyle);
571 
572   // Microsoft Style:
573   // https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/lambda-expressions#statement-lambdas
574   verifyFormat(R"(//
575 class MyClass
576 {
577     Action<string> greet = name =>
578     {
579         string greeting = $"Hello {name}!";
580         Console.WriteLine(greeting);
581     };
582 })",
583                MicrosoftStyle);
584 }
585 
586 TEST_F(FormatTestCSharp, CSharpObjectInitializers) {
587   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
588 
589   // Start code fragments with a comment line so that C++ raw string literals
590   // as seen are identical to expected formatted code.
591 
592   verifyFormat(R"(//
593 Shape[] shapes = new[] {
594   new Circle {
595     Radius = 2.7281,
596     Colour = Colours.Red,
597   },
598   new Square {
599     Side = 101.1,
600     Colour = Colours.Yellow,
601   },
602 };)",
603                Style);
604 
605   // Omitted final `,`s will change the formatting.
606   verifyFormat(R"(//
607 Shape[] shapes = new[] { new Circle { Radius = 2.7281, Colour = Colours.Red },
608                          new Square { Side = 101.1, Colour = Colours.Yellow } };)",
609                Style);
610 
611   // Lambdas can be supplied as initialiser arguments.
612   verifyFormat(R"(//
613 private Transformer _transformer = new X.Y {
614   Filler = (Shape shape) => { return new Transform.Fill(shape, RED); },
615   Scaler = (Shape shape) => { return new Transform.Resize(shape, 0.1); },
616 };)",
617                Style);
618 
619   // Dictionary initialisation.
620   verifyFormat(R"(//
621 var myDict = new Dictionary<string, string> {
622   ["name"] = _donald,
623   ["age"] = Convert.ToString(DateTime.Today.Year - 1934),
624   ["type"] = _duck,
625 };)",
626                Style);
627 }
628 
629 TEST_F(FormatTestCSharp, CSharpArrayInitializers) {
630   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
631 
632   verifyFormat(R"(//
633 private MySet<Node>[] setPoints = {
634   new Point<Node>(),
635   new Point<Node>(),
636 };)",
637                Style);
638 }
639 
640 TEST_F(FormatTestCSharp, CSharpNamedArguments) {
641   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
642 
643   verifyFormat(R"(//
644 PrintOrderDetails(orderNum: 31, productName: "Red Mug", sellerName: "Gift Shop");)",
645                Style);
646 
647   // Ensure that trailing comments do not cause problems.
648   verifyFormat(R"(//
649 PrintOrderDetails(orderNum: 31, productName: "Red Mug",  // comment
650                   sellerName: "Gift Shop");)",
651                Style);
652 
653   verifyFormat(R"(foreach (var tickCount in task.Begin(seed: 0)) {)", Style);
654 }
655 
656 TEST_F(FormatTestCSharp, CSharpPropertyAccessors) {
657   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
658 
659   verifyFormat("int Value { get }", Style);
660   verifyFormat("int Value { get; }", Style);
661   verifyFormat("int Value { internal get; }", Style);
662   verifyFormat("int Value { get; } = 0", Style);
663   verifyFormat("int Value { set }", Style);
664   verifyFormat("int Value { set; }", Style);
665   verifyFormat("int Value { internal set; }", Style);
666   verifyFormat("int Value { set; } = 0", Style);
667   verifyFormat("int Value { get; set }", Style);
668   verifyFormat("int Value { set; get }", Style);
669   verifyFormat("int Value { get; private set; }", Style);
670   verifyFormat("int Value { get; set; }", Style);
671   verifyFormat("int Value { get; set; } = 0", Style);
672   verifyFormat("int Value { internal get; internal set; }", Style);
673 
674   // Do not wrap expression body definitions.
675   verifyFormat(R"(//
676 public string Name {
677   get => _name;
678   set => _name = value;
679 })",
680                Style);
681 
682   // Examples taken from
683   // https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties
684   verifyFormat(R"(
685 // Expression body definitions
686 public class SaleItem {
687   public decimal Price {
688     get => _cost;
689     set => _cost = value;
690   }
691 })",
692                Style);
693 
694   verifyFormat(R"(
695 // Properties with backing fields
696 class TimePeriod {
697   public double Hours {
698     get { return _seconds / 3600; }
699     set {
700       if (value < 0 || value > 24)
701         throw new ArgumentOutOfRangeException($"{nameof(value)} must be between 0 and 24.");
702       _seconds = value * 3600;
703     }
704   }
705 })",
706                Style);
707 
708   verifyFormat(R"(
709 // Auto-implemented properties
710 public class SaleItem {
711   public decimal Price { get; set; }
712 })",
713                Style);
714 
715   // Add column limit to wrap long lines.
716   Style.ColumnLimit = 100;
717 
718   // Examples with assignment to default value.
719   verifyFormat(R"(
720 // Long assignment to default value
721 class MyClass {
722   public override VeryLongNamedTypeIndeed VeryLongNamedValue { get; set } =
723       VeryLongNamedTypeIndeed.Create(DefaultFirstArgument, DefaultSecondArgument,
724                                      DefaultThirdArgument);
725 })",
726                Style);
727 
728   verifyFormat(R"(
729 // Long assignment to default value with expression body
730 class MyClass {
731   public override VeryLongNamedTypeIndeed VeryLongNamedValue {
732     get => veryLongNamedField;
733     set => veryLongNamedField = value;
734   } = VeryLongNamedTypeIndeed.Create(DefaultFirstArgument, DefaultSecondArgument,
735                                      DefaultThirdArgument);
736 })",
737                Style);
738 
739   // Brace wrapping and single-lining of accessor can be controlled by config.
740   Style.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Never;
741   Style.BreakBeforeBraces = FormatStyle::BS_Custom;
742   Style.BraceWrapping.AfterFunction = true;
743 
744   verifyFormat(R"(//
745 class TimePeriod {
746   public double Hours
747   {
748     get {
749       return _seconds / 3600;
750     }
751     set {
752       _seconds = value * 3600;
753     }
754   }
755 })",
756                Style);
757 
758   // Microsoft style trivial property accessors have no line break before the
759   // opening brace.
760   auto MicrosoftStyle = getMicrosoftStyle(FormatStyle::LK_CSharp);
761   verifyFormat(R"(//
762 public class SaleItem
763 {
764     public decimal Price { get; set; }
765 })",
766                MicrosoftStyle);
767 }
768 
769 TEST_F(FormatTestCSharp, CSharpSpaces) {
770   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
771   Style.SpaceBeforeSquareBrackets = false;
772   Style.SpacesInSquareBrackets = false;
773   Style.SpaceBeforeCpp11BracedList = true;
774   Style.Cpp11BracedListStyle = false;
775   Style.SpacesInContainerLiterals = false;
776   Style.SpaceAfterCStyleCast = false;
777 
778   verifyFormat(R"(new Car { "Door", 0.1 })", Style);
779   verifyFormat(R"(new Car { 0.1, "Door" })", Style);
780   verifyFormat(R"(new string[] { "A" })", Style);
781   verifyFormat(R"(new string[] {})", Style);
782   verifyFormat(R"(new Car { someVariableName })", Style);
783   verifyFormat(R"(new Car { someVariableName })", Style);
784   verifyFormat(R"(new Dictionary<string, string> { ["Key"] = "Value" };)",
785                Style);
786   verifyFormat(R"(Apply(x => x.Name, x => () => x.ID);)", Style);
787   verifyFormat(R"(bool[] xs = { true, true };)", Style);
788   verifyFormat(R"(taskContext.Factory.Run(async () => doThing(args);)", Style);
789   verifyFormat(R"(catch (TestException) when (innerFinallyExecuted))", Style);
790   verifyFormat(R"(private float[,] Values;)", Style);
791   verifyFormat(R"(Result this[Index x] => Foo(x);)", Style);
792 
793   verifyFormat(R"(char[,,] rawCharArray = MakeCharacterGrid();)", Style);
794   verifyFormat(R"(var (key, value))", Style);
795 
796   // `&&` is not seen as a reference.
797   verifyFormat(R"(A == typeof(X) && someBool)", Style);
798 
799   // Not seen as a C-style cast.
800   verifyFormat(R"(//
801 foreach ((A a, B b) in someList) {
802 })",
803                Style);
804 
805   // space after lock in `lock (processes)`.
806   verifyFormat("lock (process)", Style);
807 
808   Style.SpacesInSquareBrackets = true;
809   verifyFormat(R"(private float[ , ] Values;)", Style);
810   verifyFormat(R"(string dirPath = args?[ 0 ];)", Style);
811   verifyFormat(R"(char[ ,, ] rawCharArray = MakeCharacterGrid();)", Style);
812 
813   // Method returning tuple
814   verifyFormat(R"(public (string name, int age) methodTuple() {})", Style);
815   verifyFormat(R"(private (string name, int age) methodTuple() {})", Style);
816   verifyFormat(R"(protected (string name, int age) methodTuple() {})", Style);
817   verifyFormat(R"(virtual (string name, int age) methodTuple() {})", Style);
818   verifyFormat(R"(extern (string name, int age) methodTuple() {})", Style);
819   verifyFormat(R"(static (string name, int age) methodTuple() {})", Style);
820   verifyFormat(R"(internal (string name, int age) methodTuple() {})", Style);
821   verifyFormat(R"(abstract (string name, int age) methodTuple() {})", Style);
822   verifyFormat(R"(sealed (string name, int age) methodTuple() {})", Style);
823   verifyFormat(R"(override (string name, int age) methodTuple() {})", Style);
824   verifyFormat(R"(async (string name, int age) methodTuple() {})", Style);
825   verifyFormat(R"(unsafe (string name, int age) methodTuple() {})", Style);
826 }
827 
828 TEST_F(FormatTestCSharp, CSharpNullableTypes) {
829   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
830   Style.SpacesInSquareBrackets = false;
831 
832   verifyFormat(R"(//
833 public class A {
834   void foo() {
835     int? value = some.bar();
836   }
837 })",
838                Style); // int? is nullable not a conditional expression.
839 
840   verifyFormat(R"(void foo(int? x, int? y, int? z) {})",
841                Style); // Nullables in function definitions.
842 
843   verifyFormat(R"(public float? Value;)", Style); // no space before `?`.
844 
845   verifyFormat(R"(int?[] arr = new int?[10];)",
846                Style); // An array of a nullable type.
847 
848   verifyFormat(R"(var x = (int?)y;)", Style); // Cast to a nullable type.
849 
850   verifyFormat(R"(var x = new MyContainer<int?>();)", Style); // Generics.
851 
852   verifyFormat(R"(//
853 public interface I {
854   int? Function();
855 })",
856                Style); // Interface methods.
857 
858   Style.ColumnLimit = 10;
859   verifyFormat(R"(//
860 public VeryLongType? Function(
861     int arg1,
862     int arg2) {
863   //
864 })",
865                Style); // ? sticks with identifier.
866 }
867 
868 TEST_F(FormatTestCSharp, CSharpArraySubscripts) {
869   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
870 
871   // Do not format array subscript operators as attributes.
872   verifyFormat(R"(//
873 if (someThings[index].Contains(myThing)) {
874 })",
875                Style);
876 
877   verifyFormat(R"(//
878 if (someThings[i][j][k].Contains(myThing)) {
879 })",
880                Style);
881 }
882 
883 TEST_F(FormatTestCSharp, CSharpGenericTypeConstraints) {
884   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
885 
886   EXPECT_TRUE(Style.BraceWrapping.SplitEmptyRecord);
887 
888   verifyFormat("class ItemFactory<T>\n"
889                "    where T : new() {\n"
890                "}",
891                Style);
892 
893   verifyFormat("class Dictionary<TKey, TVal>\n"
894                "    where TKey : IComparable<TKey>\n"
895                "    where TVal : IMyInterface {\n"
896                "  public void MyMethod<T>(T t)\n"
897                "      where T : IMyInterface {\n"
898                "    doThing();\n"
899                "  }\n"
900                "}",
901                Style);
902 
903   verifyFormat("class ItemFactory<T>\n"
904                "    where T : new(), IAnInterface<T>, IAnotherInterface<T>, "
905                "IAnotherInterfaceStill<T> {\n"
906                "}",
907                Style);
908 
909   Style.ColumnLimit = 50; // Force lines to be wrapped.
910   verifyFormat(R"(//
911 class ItemFactory<T, U>
912     where T : new(),
913               IAnInterface<T>,
914               IAnotherInterface<T, U>,
915               IAnotherInterfaceStill<T, U> {
916 })",
917                Style);
918 
919   // In other languages `where` can be used as a normal identifier.
920   // This example is in C++!
921   verifyFormat(R"(//
922 class A {
923   int f(int where) {}
924 };)",
925                getGoogleStyle(FormatStyle::LK_Cpp));
926 }
927 
928 } // namespace format
929 } // end namespace clang
930