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:
format(llvm::StringRef Code,unsigned Offset,unsigned Length,const FormatStyle & Style)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
format(llvm::StringRef Code,const FormatStyle & Style=getMicrosoftStyle (FormatStyle::LK_CSharp))34 format(llvm::StringRef Code,
35 const FormatStyle &Style = getMicrosoftStyle(FormatStyle::LK_CSharp)) {
36 return format(Code, 0, Code.size(), Style);
37 }
38
getStyleWithColumns(unsigned ColumnLimit)39 static FormatStyle getStyleWithColumns(unsigned ColumnLimit) {
40 FormatStyle Style = getMicrosoftStyle(FormatStyle::LK_CSharp);
41 Style.ColumnLimit = ColumnLimit;
42 return Style;
43 }
44
verifyFormat(llvm::StringRef Code,const FormatStyle & Style=getMicrosoftStyle (FormatStyle::LK_CSharp))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
TEST_F(FormatTestCSharp,CSharpClass)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
TEST_F(FormatTestCSharp,AccessModifiers)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
TEST_F(FormatTestCSharp,NoStringLiteralBreaks)131 TEST_F(FormatTestCSharp, NoStringLiteralBreaks) {
132 verifyFormat("foo("
133 "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
134 "aaaaaa\");");
135 }
136
TEST_F(FormatTestCSharp,CSharpVerbatiumStringLiterals)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
TEST_F(FormatTestCSharp,CSharpInterpolatedStringLiterals)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
TEST_F(FormatTestCSharp,CSharpFatArrows)168 TEST_F(FormatTestCSharp, CSharpFatArrows) {
169 verifyFormat("Task serverTask = Task.Run(async() => {");
170 verifyFormat("public override string ToString() => \"{Name}\\{Age}\";");
171 }
172
TEST_F(FormatTestCSharp,CSharpConditionalExpressions)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
TEST_F(FormatTestCSharp,CSharpNullConditional)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
TEST_F(FormatTestCSharp,Attributes)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 // Adjacent properties should not cause line wrapping issues
251 verifyFormat("[JsonProperty(\"foo\")]\n"
252 "public string Foo { set; get; }\n"
253 "[JsonProperty(\"bar\")]\n"
254 "public string Bar { set; get; }\n"
255 "[JsonProperty(\"bar\")]\n"
256 "protected string Bar { set; get; }\n"
257 "[JsonProperty(\"bar\")]\n"
258 "internal string Bar { set; get; }");
259
260 // Multiple attributes should always be split (not just the first ones)
261 verifyFormat("[XmlIgnore]\n"
262 "[JsonProperty(\"foo\")]\n"
263 "public string Foo { set; get; }");
264
265 verifyFormat("[XmlIgnore]\n"
266 "[JsonProperty(\"foo\")]\n"
267 "public string Foo { set; get; }\n"
268 "[XmlIgnore]\n"
269 "[JsonProperty(\"bar\")]\n"
270 "public string Bar { set; get; }");
271
272 verifyFormat("[XmlIgnore]\n"
273 "[ScriptIgnore]\n"
274 "[JsonProperty(\"foo\")]\n"
275 "public string Foo { set; get; }\n"
276 "[XmlIgnore]\n"
277 "[ScriptIgnore]\n"
278 "[JsonProperty(\"bar\")]\n"
279 "public string Bar { set; get; }");
280
281 verifyFormat("[TestMethod(\"start\", HelpText = \"Starts the server "
282 "listening on provided host\")]\n"
283 "public string Host { set; get; }");
284
285 verifyFormat(
286 "[DllImport(\"Hello\", EntryPoint = \"hello_world\")]\n"
287 "// The const char* returned by hello_world must not be deleted.\n"
288 "private static extern IntPtr HelloFromCpp();)");
289
290 // Class attributes go on their own line and do not affect layout of
291 // interfaces. Line wrapping decisions previously caused each interface to be
292 // on its own line.
293 verifyFormat("[SomeAttribute]\n"
294 "[SomeOtherAttribute]\n"
295 "public class A : IShape, IAnimal, IVehicle\n"
296 "{\n"
297 " int X;\n"
298 "}");
299
300 // Attributes in a method declaration do not cause line wrapping.
301 verifyFormat("void MethodA([In][Out] ref double x)\n"
302 "{\n"
303 "}");
304
305 verifyFormat("void MethodA([In, Out] ref double x)\n"
306 "{\n"
307 "}");
308
309 verifyFormat("void MethodA([In, Out] double[] x)\n"
310 "{\n"
311 "}");
312
313 verifyFormat("void MethodA([In] double[] x)\n"
314 "{\n"
315 "}");
316
317 verifyFormat("void MethodA(int[] x)\n"
318 "{\n"
319 "}");
320 verifyFormat("void MethodA(int[][] x)\n"
321 "{\n"
322 "}");
323 verifyFormat("void MethodA([] x)\n"
324 "{\n"
325 "}");
326
327 verifyFormat("public void Log([CallerLineNumber] int line = -1, "
328 "[CallerFilePath] string path = null,\n"
329 " [CallerMemberName] string name = null)\n"
330 "{\n"
331 "}");
332
333 // [] in an attribute do not cause premature line wrapping or indenting.
334 verifyFormat(R"(//
335 public class A
336 {
337 [SomeAttribute(new[] { RED, GREEN, BLUE }, -1.0f, 1.0f)]
338 [DoNotSerialize]
339 public Data MemberVariable;
340 })");
341
342 // Unwrappable lines go on a line of their own.
343 // 'target:' is not treated as a label.
344 // Modify Style to enforce a column limit.
345 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
346 Style.ColumnLimit = 10;
347 verifyFormat(R"([assembly:InternalsVisibleTo(
348 "SomeAssembly, PublicKey=SomePublicKeyThatExceedsTheColumnLimit")])",
349 Style);
350 }
351
TEST_F(FormatTestCSharp,CSharpUsing)352 TEST_F(FormatTestCSharp, CSharpUsing) {
353 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
354 Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
355 verifyFormat("public void foo () {\n"
356 " using (StreamWriter sw = new StreamWriter (filenameA)) {}\n"
357 " using () {}\n"
358 "}",
359 Style);
360
361 // Ensure clang-format affects top-level snippets correctly.
362 verifyFormat("using (StreamWriter sw = new StreamWriter (filenameB)) {}",
363 Style);
364
365 Style.SpaceBeforeParens = FormatStyle::SBPO_Never;
366 verifyFormat("public void foo() {\n"
367 " using(StreamWriter sw = new StreamWriter(filenameB)) {}\n"
368 " using() {}\n"
369 "}",
370 Style);
371
372 // Ensure clang-format affects top-level snippets correctly.
373 verifyFormat("using(StreamWriter sw = new StreamWriter(filenameB)) {}",
374 Style);
375
376 Style.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements;
377 verifyFormat("public void foo() {\n"
378 " using (StreamWriter sw = new StreamWriter(filenameA)) {}\n"
379 " using () {}\n"
380 "}",
381 Style);
382
383 // Ensure clang-format affects top-level snippets correctly.
384 verifyFormat("using (StreamWriter sw = new StreamWriter(filenameB)) {}",
385 Style);
386
387 Style.SpaceBeforeParens = FormatStyle::SBPO_NonEmptyParentheses;
388 verifyFormat("public void foo() {\n"
389 " using (StreamWriter sw = new StreamWriter (filenameA)) {}\n"
390 " using() {}\n"
391 "}",
392 Style);
393
394 // Ensure clang-format affects top-level snippets correctly.
395 verifyFormat("using (StreamWriter sw = new StreamWriter (filenameB)) {}",
396 Style);
397 }
398
TEST_F(FormatTestCSharp,CSharpRegions)399 TEST_F(FormatTestCSharp, CSharpRegions) {
400 verifyFormat("#region aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaa "
401 "aaaaaaaaaaaaaaa long region");
402 }
403
TEST_F(FormatTestCSharp,CSharpKeyWordEscaping)404 TEST_F(FormatTestCSharp, CSharpKeyWordEscaping) {
405 // AfterEnum is true by default.
406 verifyFormat("public enum var\n"
407 "{\n"
408 " none,\n"
409 " @string,\n"
410 " bool,\n"
411 " @enum\n"
412 "}");
413 }
414
TEST_F(FormatTestCSharp,CSharpNullCoalescing)415 TEST_F(FormatTestCSharp, CSharpNullCoalescing) {
416 verifyFormat("var test = ABC ?? DEF");
417 verifyFormat("string myname = name ?? \"ABC\";");
418 verifyFormat("return _name ?? \"DEF\";");
419 }
420
TEST_F(FormatTestCSharp,CSharpNullCoalescingAssignment)421 TEST_F(FormatTestCSharp, CSharpNullCoalescingAssignment) {
422 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
423 Style.SpaceBeforeAssignmentOperators = true;
424
425 verifyFormat(R"(test ??= ABC;)", Style);
426 verifyFormat(R"(test ??= true;)", Style);
427
428 Style.SpaceBeforeAssignmentOperators = false;
429
430 verifyFormat(R"(test??= ABC;)", Style);
431 verifyFormat(R"(test??= true;)", Style);
432 }
433
TEST_F(FormatTestCSharp,CSharpNullForgiving)434 TEST_F(FormatTestCSharp, CSharpNullForgiving) {
435 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
436
437 verifyFormat("var test = null!;", Style);
438 verifyFormat("string test = someFunctionCall()! + \"ABC\"!", Style);
439 verifyFormat("int test = (1! + 2 + bar! + foo())!", Style);
440 verifyFormat(R"(test ??= !foo!;)", Style);
441 verifyFormat("test = !bar! ?? !foo!;", Style);
442 verifyFormat("bool test = !(!true && !true! || !null && !null! || !false && "
443 "!false! && !bar()! + (!foo()))!",
444 Style);
445
446 // Check that line break keeps identifier with the bang.
447 Style.ColumnLimit = 14;
448
449 verifyFormat("var test =\n"
450 " foo!;",
451 Style);
452 }
453
TEST_F(FormatTestCSharp,AttributesIndentation)454 TEST_F(FormatTestCSharp, AttributesIndentation) {
455 FormatStyle Style = getMicrosoftStyle(FormatStyle::LK_CSharp);
456 Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None;
457
458 verifyFormat("[STAThread]\n"
459 "static void Main(string[] args)\n"
460 "{\n"
461 "}",
462 Style);
463
464 verifyFormat("[STAThread]\n"
465 "void "
466 "veryLooooooooooooooongFunctionName(string[] args)\n"
467 "{\n"
468 "}",
469 Style);
470
471 verifyFormat("[STAThread]\n"
472 "veryLoooooooooooooooooooongReturnType "
473 "veryLooooooooooooooongFunctionName(string[] args)\n"
474 "{\n"
475 "}",
476 Style);
477
478 verifyFormat("[SuppressMessage(\"A\", \"B\", Justification = \"C\")]\n"
479 "public override X Y()\n"
480 "{\n"
481 "}\n",
482 Style);
483
484 verifyFormat("[SuppressMessage]\n"
485 "public X Y()\n"
486 "{\n"
487 "}\n",
488 Style);
489
490 verifyFormat("[SuppressMessage]\n"
491 "public override X Y()\n"
492 "{\n"
493 "}\n",
494 Style);
495
496 verifyFormat("public A(B b) : base(b)\n"
497 "{\n"
498 " [SuppressMessage]\n"
499 " public override X Y()\n"
500 " {\n"
501 " }\n"
502 "}\n",
503 Style);
504
505 verifyFormat("public A : Base\n"
506 "{\n"
507 "}\n"
508 "[Test]\n"
509 "public Foo()\n"
510 "{\n"
511 "}\n",
512 Style);
513
514 verifyFormat("namespace\n"
515 "{\n"
516 "public A : Base\n"
517 "{\n"
518 "}\n"
519 "[Test]\n"
520 "public Foo()\n"
521 "{\n"
522 "}\n"
523 "}\n",
524 Style);
525 }
526
TEST_F(FormatTestCSharp,CSharpSpaceBefore)527 TEST_F(FormatTestCSharp, CSharpSpaceBefore) {
528 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
529 Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
530
531 verifyFormat("List<string> list;", Style);
532 verifyFormat("Dictionary<string, string> dict;", Style);
533
534 verifyFormat("for (int i = 0; i < size (); i++) {\n"
535 "}",
536 Style);
537 verifyFormat("foreach (var x in y) {\n"
538 "}",
539 Style);
540 verifyFormat("switch (x) {}", Style);
541 verifyFormat("do {\n"
542 "} while (x);",
543 Style);
544
545 Style.SpaceBeforeParens = FormatStyle::SBPO_Never;
546
547 verifyFormat("List<string> list;", Style);
548 verifyFormat("Dictionary<string, string> dict;", Style);
549
550 verifyFormat("for(int i = 0; i < size(); i++) {\n"
551 "}",
552 Style);
553 verifyFormat("foreach(var x in y) {\n"
554 "}",
555 Style);
556 verifyFormat("switch(x) {}", Style);
557 verifyFormat("do {\n"
558 "} while(x);",
559 Style);
560 }
561
TEST_F(FormatTestCSharp,CSharpSpaceAfterCStyleCast)562 TEST_F(FormatTestCSharp, CSharpSpaceAfterCStyleCast) {
563 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
564
565 verifyFormat("(int)x / y;", Style);
566
567 Style.SpaceAfterCStyleCast = true;
568 verifyFormat("(int) x / y;", Style);
569 }
570
TEST_F(FormatTestCSharp,CSharpEscapedQuotesInVerbatimStrings)571 TEST_F(FormatTestCSharp, CSharpEscapedQuotesInVerbatimStrings) {
572 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
573
574 verifyFormat(R"(string str = @"""";)", Style);
575 verifyFormat(R"(string str = @"""Hello world""";)", Style);
576 verifyFormat(R"(string str = $@"""Hello {friend}""";)", Style);
577 verifyFormat(R"(return $@"Foo ""/foo?f={Request.Query["f"]}""";)", Style);
578 }
579
TEST_F(FormatTestCSharp,CSharpQuotesInInterpolatedStrings)580 TEST_F(FormatTestCSharp, CSharpQuotesInInterpolatedStrings) {
581 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
582
583 verifyFormat(R"(string str1 = $"{null ?? "null"}";)", Style);
584 verifyFormat(R"(string str2 = $"{{{braceCount} braces";)", Style);
585 verifyFormat(R"(string str3 = $"{braceCount}}} braces";)", Style);
586 }
587
TEST_F(FormatTestCSharp,CSharpNewlinesInVerbatimStrings)588 TEST_F(FormatTestCSharp, CSharpNewlinesInVerbatimStrings) {
589 // Use MS style as Google Style inserts a line break before multiline strings.
590
591 // verifyFormat does not understand multiline C# string-literals
592 // so check the format explicitly.
593
594 FormatStyle Style = getMicrosoftStyle(FormatStyle::LK_CSharp);
595
596 std::string Code = R"(string s1 = $@"some code:
597 class {className} {{
598 {className}() {{}}
599 }}";)";
600
601 EXPECT_EQ(Code, format(Code, Style));
602
603 // Multiline string in the middle of a function call.
604 Code = R"(
605 var x = foo(className, $@"some code:
606 class {className} {{
607 {className}() {{}}
608 }}",
609 y);)"; // y aligned with `className` arg.
610
611 EXPECT_EQ(Code, format(Code, Style));
612
613 // Interpolated string with embedded multiline string.
614 Code = R"(Console.WriteLine($"{string.Join(@",
615 ", values)}");)";
616
617 EXPECT_EQ(Code, format(Code, Style));
618 }
619
TEST_F(FormatTestCSharp,CSharpLambdas)620 TEST_F(FormatTestCSharp, CSharpLambdas) {
621 FormatStyle GoogleStyle = getGoogleStyle(FormatStyle::LK_CSharp);
622 FormatStyle MicrosoftStyle = getMicrosoftStyle(FormatStyle::LK_CSharp);
623
624 verifyFormat(R"(//
625 class MyClass {
626 Action<string> greet = name => {
627 string greeting = $"Hello {name}!";
628 Console.WriteLine(greeting);
629 };
630 })",
631 GoogleStyle);
632
633 // Microsoft Style:
634 // https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/lambda-expressions#statement-lambdas
635 verifyFormat(R"(//
636 class MyClass
637 {
638 Action<string> greet = name =>
639 {
640 string greeting = $"Hello {name}!";
641 Console.WriteLine(greeting);
642 };
643 })",
644 MicrosoftStyle);
645
646 verifyFormat("void bar()\n"
647 "{\n"
648 " Function(Val, (Action)(() =>\n"
649 " {\n"
650 " lock (mylock)\n"
651 " {\n"
652 " if (true)\n"
653 " {\n"
654 " A.Remove(item);\n"
655 " }\n"
656 " }\n"
657 " }));\n"
658 "}",
659 MicrosoftStyle);
660
661 verifyFormat("void baz()\n"
662 "{\n"
663 " Function(Val, (Action)(() =>\n"
664 " {\n"
665 " using (var a = new Lock())\n"
666 " {\n"
667 " if (true)\n"
668 " {\n"
669 " A.Remove(item);\n"
670 " }\n"
671 " }\n"
672 " }));\n"
673 "}",
674 MicrosoftStyle);
675
676 verifyFormat("void baz()\n"
677 "{\n"
678 " Function(Val, (Action)(() =>\n"
679 " {\n"
680 " if (true)\n"
681 " {\n"
682 " A.Remove(item);\n"
683 " }\n"
684 " }));\n"
685 "}",
686 MicrosoftStyle);
687
688 verifyFormat("void baz()\n"
689 "{\n"
690 " Function(Val, (Action)(() =>\n"
691 " {\n"
692 " do\n"
693 " {\n"
694 " A.Remove(item);\n"
695 " } while (true)\n"
696 " }));\n"
697 "}",
698 MicrosoftStyle);
699
700 verifyFormat("void baz()\n"
701 "{\n"
702 " Function(Val, (Action)(() =>\n"
703 " { A.Remove(item); }));\n"
704 "}",
705 MicrosoftStyle);
706
707 verifyFormat("void bar()\n"
708 "{\n"
709 " Function(Val, (() =>\n"
710 " {\n"
711 " lock (mylock)\n"
712 " {\n"
713 " if (true)\n"
714 " {\n"
715 " A.Remove(item);\n"
716 " }\n"
717 " }\n"
718 " }));\n"
719 "}",
720 MicrosoftStyle);
721 verifyFormat("void bar()\n"
722 "{\n"
723 " Function((() =>\n"
724 " {\n"
725 " lock (mylock)\n"
726 " {\n"
727 " if (true)\n"
728 " {\n"
729 " A.Remove(item);\n"
730 " }\n"
731 " }\n"
732 " }));\n"
733 "}",
734 MicrosoftStyle);
735
736 MicrosoftStyle.IndentWidth = 2;
737 verifyFormat("void bar()\n"
738 "{\n"
739 " Function((() =>\n"
740 " {\n"
741 " lock (mylock)\n"
742 " {\n"
743 " if (true)\n"
744 " {\n"
745 " A.Remove(item);\n"
746 " }\n"
747 " }\n"
748 " }));\n"
749 "}",
750 MicrosoftStyle);
751 verifyFormat("void bar() {\n"
752 " Function((() => {\n"
753 " lock (mylock) {\n"
754 " if (true) {\n"
755 " A.Remove(item);\n"
756 " }\n"
757 " }\n"
758 " }));\n"
759 "}",
760 GoogleStyle);
761 }
762
TEST_F(FormatTestCSharp,CSharpLambdasDontBreakFollowingCodeAlignment)763 TEST_F(FormatTestCSharp, CSharpLambdasDontBreakFollowingCodeAlignment) {
764 FormatStyle GoogleStyle = getGoogleStyle(FormatStyle::LK_CSharp);
765 FormatStyle MicrosoftStyle = getMicrosoftStyle(FormatStyle::LK_CSharp);
766
767 verifyFormat(R"(//
768 public class Sample
769 {
770 public void Test()
771 {
772 while (true)
773 {
774 preBindEnumerators.RemoveAll(enumerator => !enumerator.MoveNext());
775 CodeThatFollowsLambda();
776 IsWellAligned();
777 }
778 }
779 })",
780 MicrosoftStyle);
781
782 verifyFormat(R"(//
783 public class Sample {
784 public void Test() {
785 while (true) {
786 preBindEnumerators.RemoveAll(enumerator => !enumerator.MoveNext());
787 CodeThatFollowsLambda();
788 IsWellAligned();
789 }
790 }
791 })",
792 GoogleStyle);
793 }
794
TEST_F(FormatTestCSharp,CSharpLambdasComplexLambdasDontBreakAlignment)795 TEST_F(FormatTestCSharp, CSharpLambdasComplexLambdasDontBreakAlignment) {
796 FormatStyle GoogleStyle = getGoogleStyle(FormatStyle::LK_CSharp);
797 FormatStyle MicrosoftStyle = getMicrosoftStyle(FormatStyle::LK_CSharp);
798
799 verifyFormat(R"(//
800 public class Test
801 {
802 private static void ComplexLambda(BuildReport protoReport)
803 {
804 allSelectedScenes =
805 veryVeryLongCollectionNameThatPutsTheLineLenghtAboveTheThresholds.Where(scene => scene.enabled)
806 .Select(scene => scene.path)
807 .ToArray();
808 if (allSelectedScenes.Count == 0)
809 {
810 return;
811 }
812 Functions();
813 AreWell();
814 Aligned();
815 AfterLambdaBlock();
816 }
817 })",
818 MicrosoftStyle);
819
820 verifyFormat(R"(//
821 public class Test {
822 private static void ComplexLambda(BuildReport protoReport) {
823 allSelectedScenes = veryVeryLongCollectionNameThatPutsTheLineLenghtAboveTheThresholds
824 .Where(scene => scene.enabled)
825 .Select(scene => scene.path)
826 .ToArray();
827 if (allSelectedScenes.Count == 0) {
828 return;
829 }
830 Functions();
831 AreWell();
832 Aligned();
833 AfterLambdaBlock();
834 }
835 })",
836 GoogleStyle);
837 }
838
TEST_F(FormatTestCSharp,CSharpLambdasMulipleLambdasDontBreakAlignment)839 TEST_F(FormatTestCSharp, CSharpLambdasMulipleLambdasDontBreakAlignment) {
840 FormatStyle GoogleStyle = getGoogleStyle(FormatStyle::LK_CSharp);
841 FormatStyle MicrosoftStyle = getMicrosoftStyle(FormatStyle::LK_CSharp);
842
843 verifyFormat(R"(//
844 public class Test
845 {
846 private static void MultipleLambdas(BuildReport protoReport)
847 {
848 allSelectedScenes =
849 veryVeryLongCollectionNameThatPutsTheLineLenghtAboveTheThresholds.Where(scene => scene.enabled)
850 .Select(scene => scene.path)
851 .ToArray();
852 preBindEnumerators.RemoveAll(enumerator => !enumerator.MoveNext());
853 if (allSelectedScenes.Count == 0)
854 {
855 return;
856 }
857 Functions();
858 AreWell();
859 Aligned();
860 AfterLambdaBlock();
861 }
862 })",
863 MicrosoftStyle);
864
865 verifyFormat(R"(//
866 public class Test {
867 private static void MultipleLambdas(BuildReport protoReport) {
868 allSelectedScenes = veryVeryLongCollectionNameThatPutsTheLineLenghtAboveTheThresholds
869 .Where(scene => scene.enabled)
870 .Select(scene => scene.path)
871 .ToArray();
872 preBindEnumerators.RemoveAll(enumerator => !enumerator.MoveNext());
873 if (allSelectedScenes.Count == 0) {
874 return;
875 }
876 Functions();
877 AreWell();
878 Aligned();
879 AfterLambdaBlock();
880 }
881 })",
882 GoogleStyle);
883 }
884
TEST_F(FormatTestCSharp,CSharpObjectInitializers)885 TEST_F(FormatTestCSharp, CSharpObjectInitializers) {
886 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
887
888 // Start code fragments with a comment line so that C++ raw string literals
889 // as seen are identical to expected formatted code.
890
891 verifyFormat(R"(//
892 Shape[] shapes = new[] {
893 new Circle {
894 Radius = 2.7281,
895 Colour = Colours.Red,
896 },
897 new Square {
898 Side = 101.1,
899 Colour = Colours.Yellow,
900 },
901 };)",
902 Style);
903
904 // Omitted final `,`s will change the formatting.
905 verifyFormat(R"(//
906 Shape[] shapes = new[] { new Circle { Radius = 2.7281, Colour = Colours.Red },
907 new Square { Side = 101.1, Colour = Colours.Yellow } };)",
908 Style);
909
910 // Lambdas can be supplied as initialiser arguments.
911 verifyFormat(R"(//
912 private Transformer _transformer = new X.Y {
913 Filler = (Shape shape) => { return new Transform.Fill(shape, RED); },
914 Scaler = (Shape shape) => { return new Transform.Resize(shape, 0.1); },
915 };)",
916 Style);
917
918 // Dictionary initialisation.
919 verifyFormat(R"(//
920 var myDict = new Dictionary<string, string> {
921 ["name"] = _donald,
922 ["age"] = Convert.ToString(DateTime.Today.Year - 1934),
923 ["type"] = _duck,
924 };)",
925 Style);
926 }
927
TEST_F(FormatTestCSharp,CSharpArrayInitializers)928 TEST_F(FormatTestCSharp, CSharpArrayInitializers) {
929 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
930
931 verifyFormat(R"(//
932 private MySet<Node>[] setPoints = {
933 new Point<Node>(),
934 new Point<Node>(),
935 };)",
936 Style);
937 }
938
TEST_F(FormatTestCSharp,CSharpNamedArguments)939 TEST_F(FormatTestCSharp, CSharpNamedArguments) {
940 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
941
942 verifyFormat(R"(//
943 PrintOrderDetails(orderNum: 31, productName: "Red Mug", sellerName: "Gift Shop");)",
944 Style);
945
946 // Ensure that trailing comments do not cause problems.
947 verifyFormat(R"(//
948 PrintOrderDetails(orderNum: 31, productName: "Red Mug", // comment
949 sellerName: "Gift Shop");)",
950 Style);
951
952 verifyFormat(R"(foreach (var tickCount in task.Begin(seed: 0)) {)", Style);
953 }
954
TEST_F(FormatTestCSharp,CSharpPropertyAccessors)955 TEST_F(FormatTestCSharp, CSharpPropertyAccessors) {
956 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
957
958 verifyFormat("int Value { get }", Style);
959 verifyFormat("int Value { get; }", Style);
960 verifyFormat("int Value { internal get; }", Style);
961 verifyFormat("int Value { get; } = 0", Style);
962 verifyFormat("int Value { set }", Style);
963 verifyFormat("int Value { set; }", Style);
964 verifyFormat("int Value { init; }", Style);
965 verifyFormat("int Value { internal set; }", Style);
966 verifyFormat("int Value { set; } = 0", Style);
967 verifyFormat("int Value { get; set }", Style);
968 verifyFormat("int Value { get; init; }", Style);
969 verifyFormat("int Value { set; get }", Style);
970 verifyFormat("int Value { get; private set; }", Style);
971 verifyFormat("int Value { get; set; }", Style);
972 verifyFormat("int Value { get; set; } = 0", Style);
973 verifyFormat("int Value { internal get; internal set; }", Style);
974
975 // Do not wrap expression body definitions.
976 verifyFormat(R"(//
977 public string Name {
978 get => _name;
979 set => _name = value;
980 })",
981 Style);
982 verifyFormat(R"(//
983 public string Name {
984 init => _name = value;
985 get => _name;
986 })",
987 Style);
988 verifyFormat(R"(//
989 public string Name {
990 set => _name = value;
991 get => _name;
992 })",
993 Style);
994
995 // Examples taken from
996 // https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties
997 verifyFormat(R"(
998 // Expression body definitions
999 public class SaleItem {
1000 public decimal Price {
1001 get => _cost;
1002 set => _cost = value;
1003 }
1004 })",
1005 Style);
1006
1007 verifyFormat(R"(
1008 // Properties with backing fields
1009 class TimePeriod {
1010 public double Hours {
1011 get { return _seconds / 3600; }
1012 set {
1013 if (value < 0 || value > 24)
1014 throw new ArgumentOutOfRangeException($"{nameof(value)} must be between 0 and 24.");
1015 _seconds = value * 3600;
1016 }
1017 }
1018 })",
1019 Style);
1020
1021 verifyFormat(R"(
1022 // Auto-implemented properties
1023 public class SaleItem {
1024 public decimal Price { get; set; }
1025 })",
1026 Style);
1027
1028 // Add column limit to wrap long lines.
1029 Style.ColumnLimit = 100;
1030
1031 // Examples with assignment to default value.
1032 verifyFormat(R"(
1033 // Long assignment to default value
1034 class MyClass {
1035 public override VeryLongNamedTypeIndeed VeryLongNamedValue { get; set } =
1036 VeryLongNamedTypeIndeed.Create(DefaultFirstArgument, DefaultSecondArgument,
1037 DefaultThirdArgument);
1038 })",
1039 Style);
1040
1041 verifyFormat(R"(
1042 // Long assignment to default value with expression body
1043 class MyClass {
1044 public override VeryLongNamedTypeIndeed VeryLongNamedValue {
1045 get => veryLongNamedField;
1046 set => veryLongNamedField = value;
1047 } = VeryLongNamedTypeIndeed.Create(DefaultFirstArgument, DefaultSecondArgument,
1048 DefaultThirdArgument);
1049 })",
1050 Style);
1051
1052 // Brace wrapping and single-lining of accessor can be controlled by config.
1053 Style.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Never;
1054 Style.BreakBeforeBraces = FormatStyle::BS_Custom;
1055 Style.BraceWrapping.AfterFunction = true;
1056
1057 verifyFormat(R"(//
1058 class TimePeriod {
1059 public double Hours
1060 {
1061 get {
1062 return _seconds / 3600;
1063 }
1064 set {
1065 _seconds = value * 3600;
1066 }
1067 }
1068 })",
1069 Style);
1070
1071 // Microsoft style trivial property accessors have no line break before the
1072 // opening brace.
1073 auto MicrosoftStyle = getMicrosoftStyle(FormatStyle::LK_CSharp);
1074 verifyFormat(R"(//
1075 public class SaleItem
1076 {
1077 public decimal Price { get; set; }
1078 })",
1079 MicrosoftStyle);
1080 }
1081
TEST_F(FormatTestCSharp,DefaultLiteral)1082 TEST_F(FormatTestCSharp, DefaultLiteral) {
1083 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
1084
1085 verifyFormat(
1086 "T[] InitializeArray<T>(int length, T initialValue = default) {}", Style);
1087 verifyFormat("System.Numerics.Complex fillValue = default;", Style);
1088 verifyFormat("int Value { get } = default;", Style);
1089 verifyFormat("int Value { get } = default!;", Style);
1090 verifyFormat(R"(//
1091 public record Person {
1092 public string GetInit { get; init; } = default!;
1093 };)",
1094 Style);
1095 verifyFormat(R"(//
1096 public record Person {
1097 public string GetSet { get; set; } = default!;
1098 };)",
1099 Style);
1100 }
1101
TEST_F(FormatTestCSharp,CSharpSpaces)1102 TEST_F(FormatTestCSharp, CSharpSpaces) {
1103 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
1104 Style.SpaceBeforeSquareBrackets = false;
1105 Style.SpacesInSquareBrackets = false;
1106 Style.SpaceBeforeCpp11BracedList = true;
1107 Style.Cpp11BracedListStyle = false;
1108 Style.SpacesInContainerLiterals = false;
1109 Style.SpaceAfterCStyleCast = false;
1110
1111 verifyFormat(R"(new Car { "Door", 0.1 })", Style);
1112 verifyFormat(R"(new Car { 0.1, "Door" })", Style);
1113 verifyFormat(R"(new string[] { "A" })", Style);
1114 verifyFormat(R"(new string[] {})", Style);
1115 verifyFormat(R"(new Car { someVariableName })", Style);
1116 verifyFormat(R"(new Car { someVariableName })", Style);
1117 verifyFormat(R"(new Dictionary<string, string> { ["Key"] = "Value" };)",
1118 Style);
1119 verifyFormat(R"(Apply(x => x.Name, x => () => x.ID);)", Style);
1120 verifyFormat(R"(bool[] xs = { true, true };)", Style);
1121 verifyFormat(R"(taskContext.Factory.Run(async () => doThing(args);)", Style);
1122 verifyFormat(R"(catch (TestException) when (innerFinallyExecuted))", Style);
1123 verifyFormat(R"(private float[,] Values;)", Style);
1124 verifyFormat(R"(Result this[Index x] => Foo(x);)", Style);
1125
1126 verifyFormat(R"(char[,,] rawCharArray = MakeCharacterGrid();)", Style);
1127 verifyFormat(R"(var (key, value))", Style);
1128
1129 // `&&` is not seen as a reference.
1130 verifyFormat(R"(A == typeof(X) && someBool)", Style);
1131
1132 // Not seen as a C-style cast.
1133 verifyFormat(R"(//
1134 foreach ((A a, B b) in someList) {
1135 })",
1136 Style);
1137
1138 // space after lock in `lock (processes)`.
1139 verifyFormat("lock (process)", Style);
1140
1141 Style.SpacesInSquareBrackets = true;
1142 verifyFormat(R"(private float[ , ] Values;)", Style);
1143 verifyFormat(R"(string dirPath = args?[ 0 ];)", Style);
1144 verifyFormat(R"(char[ ,, ] rawCharArray = MakeCharacterGrid();)", Style);
1145
1146 // Method returning tuple
1147 verifyFormat(R"(public (string name, int age) methodTuple() {})", Style);
1148 verifyFormat(R"(private (string name, int age) methodTuple() {})", Style);
1149 verifyFormat(R"(protected (string name, int age) methodTuple() {})", Style);
1150 verifyFormat(R"(virtual (string name, int age) methodTuple() {})", Style);
1151 verifyFormat(R"(extern (string name, int age) methodTuple() {})", Style);
1152 verifyFormat(R"(static (string name, int age) methodTuple() {})", Style);
1153 verifyFormat(R"(internal (string name, int age) methodTuple() {})", Style);
1154 verifyFormat(R"(abstract (string name, int age) methodTuple() {})", Style);
1155 verifyFormat(R"(sealed (string name, int age) methodTuple() {})", Style);
1156 verifyFormat(R"(override (string name, int age) methodTuple() {})", Style);
1157 verifyFormat(R"(async (string name, int age) methodTuple() {})", Style);
1158 verifyFormat(R"(unsafe (string name, int age) methodTuple() {})", Style);
1159 }
1160
TEST_F(FormatTestCSharp,CSharpNullableTypes)1161 TEST_F(FormatTestCSharp, CSharpNullableTypes) {
1162 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
1163 Style.SpacesInSquareBrackets = false;
1164
1165 verifyFormat(R"(//
1166 public class A {
1167 void foo() {
1168 int? value = some.bar();
1169 }
1170 })",
1171 Style); // int? is nullable not a conditional expression.
1172
1173 verifyFormat(R"(void foo(int? x, int? y, int? z) {})",
1174 Style); // Nullables in function definitions.
1175
1176 verifyFormat(R"(public float? Value;)", Style); // no space before `?`.
1177
1178 verifyFormat(R"(int?[] arr = new int?[10];)",
1179 Style); // An array of a nullable type.
1180
1181 verifyFormat(R"(var x = (int?)y;)", Style); // Cast to a nullable type.
1182
1183 verifyFormat(R"(var x = new MyContainer<int?>();)", Style); // Generics.
1184
1185 verifyFormat(R"(//
1186 public interface I {
1187 int? Function();
1188 })",
1189 Style); // Interface methods.
1190
1191 Style.ColumnLimit = 10;
1192 verifyFormat(R"(//
1193 public VeryLongType? Function(
1194 int arg1,
1195 int arg2) {
1196 //
1197 })",
1198 Style); // ? sticks with identifier.
1199 }
1200
TEST_F(FormatTestCSharp,CSharpArraySubscripts)1201 TEST_F(FormatTestCSharp, CSharpArraySubscripts) {
1202 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
1203
1204 // Do not format array subscript operators as attributes.
1205 verifyFormat(R"(//
1206 if (someThings[index].Contains(myThing)) {
1207 })",
1208 Style);
1209
1210 verifyFormat(R"(//
1211 if (someThings[i][j][k].Contains(myThing)) {
1212 })",
1213 Style);
1214 }
1215
TEST_F(FormatTestCSharp,CSharpGenericTypeConstraints)1216 TEST_F(FormatTestCSharp, CSharpGenericTypeConstraints) {
1217 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
1218
1219 EXPECT_TRUE(Style.BraceWrapping.SplitEmptyRecord);
1220
1221 verifyFormat("class ItemFactory<T>\n"
1222 " where T : new() {\n"
1223 "}",
1224 Style);
1225
1226 verifyFormat("class Dictionary<TKey, TVal>\n"
1227 " where TKey : IComparable<TKey>\n"
1228 " where TVal : IMyInterface {\n"
1229 " public void MyMethod<T>(T t)\n"
1230 " where T : IMyInterface {\n"
1231 " doThing();\n"
1232 " }\n"
1233 "}",
1234 Style);
1235
1236 verifyFormat("class ItemFactory<T>\n"
1237 " where T : new(), IAnInterface<T>, IAnotherInterface<T>, "
1238 "IAnotherInterfaceStill<T> {\n"
1239 "}",
1240 Style);
1241
1242 Style.ColumnLimit = 50; // Force lines to be wrapped.
1243 verifyFormat(R"(//
1244 class ItemFactory<T, U>
1245 where T : new(),
1246 IAnInterface<T>,
1247 IAnotherInterface<T, U>,
1248 IAnotherInterfaceStill<T, U> {
1249 })",
1250 Style);
1251
1252 // In other languages `where` can be used as a normal identifier.
1253 // This example is in C++!
1254 verifyFormat(R"(//
1255 class A {
1256 int f(int where) {}
1257 };)",
1258 getGoogleStyle(FormatStyle::LK_Cpp));
1259 }
1260
TEST_F(FormatTestCSharp,CSharpAfterEnum)1261 TEST_F(FormatTestCSharp, CSharpAfterEnum) {
1262 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
1263 Style.BreakBeforeBraces = FormatStyle::BS_Custom;
1264 Style.BraceWrapping.AfterEnum = false;
1265 Style.AllowShortEnumsOnASingleLine = false;
1266
1267 verifyFormat("enum MyEnum {\n"
1268 " Foo,\n"
1269 " Bar,\n"
1270 "}",
1271 Style);
1272 verifyFormat("internal enum MyEnum {\n"
1273 " Foo,\n"
1274 " Bar,\n"
1275 "}",
1276 Style);
1277 verifyFormat("public enum MyEnum {\n"
1278 " Foo,\n"
1279 " Bar,\n"
1280 "}",
1281 Style);
1282 verifyFormat("protected enum MyEnum {\n"
1283 " Foo,\n"
1284 " Bar,\n"
1285 "}",
1286 Style);
1287 verifyFormat("private enum MyEnum {\n"
1288 " Foo,\n"
1289 " Bar,\n"
1290 "}",
1291 Style);
1292
1293 Style.BraceWrapping.AfterEnum = true;
1294 Style.AllowShortEnumsOnASingleLine = false;
1295
1296 verifyFormat("enum MyEnum\n"
1297 "{\n"
1298 " Foo,\n"
1299 " Bar,\n"
1300 "}",
1301 Style);
1302 verifyFormat("internal enum MyEnum\n"
1303 "{\n"
1304 " Foo,\n"
1305 " Bar,\n"
1306 "}",
1307 Style);
1308 verifyFormat("public enum MyEnum\n"
1309 "{\n"
1310 " Foo,\n"
1311 " Bar,\n"
1312 "}",
1313 Style);
1314 verifyFormat("protected enum MyEnum\n"
1315 "{\n"
1316 " Foo,\n"
1317 " Bar,\n"
1318 "}",
1319 Style);
1320 verifyFormat("private enum MyEnum\n"
1321 "{\n"
1322 " Foo,\n"
1323 " Bar,\n"
1324 "}",
1325 Style);
1326 verifyFormat("/* Foo */ private enum MyEnum\n"
1327 "{\n"
1328 " Foo,\n"
1329 " Bar,\n"
1330 "}",
1331 Style);
1332 verifyFormat("/* Foo */ /* Bar */ private enum MyEnum\n"
1333 "{\n"
1334 " Foo,\n"
1335 " Bar,\n"
1336 "}",
1337 Style);
1338 }
1339
TEST_F(FormatTestCSharp,CSharpAfterClass)1340 TEST_F(FormatTestCSharp, CSharpAfterClass) {
1341 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
1342 Style.BreakBeforeBraces = FormatStyle::BS_Custom;
1343 Style.BraceWrapping.AfterClass = false;
1344
1345 verifyFormat("class MyClass {\n"
1346 " int a;\n"
1347 " int b;\n"
1348 "}",
1349 Style);
1350 verifyFormat("internal class MyClass {\n"
1351 " int a;\n"
1352 " int b;\n"
1353 "}",
1354 Style);
1355 verifyFormat("public class MyClass {\n"
1356 " int a;\n"
1357 " int b;\n"
1358 "}",
1359 Style);
1360 verifyFormat("protected class MyClass {\n"
1361 " int a;\n"
1362 " int b;\n"
1363 "}",
1364 Style);
1365 verifyFormat("private class MyClass {\n"
1366 " int a;\n"
1367 " int b;\n"
1368 "}",
1369 Style);
1370
1371 verifyFormat("interface Interface {\n"
1372 " int a;\n"
1373 " int b;\n"
1374 "}",
1375 Style);
1376 verifyFormat("internal interface Interface {\n"
1377 " int a;\n"
1378 " int b;\n"
1379 "}",
1380 Style);
1381 verifyFormat("public interface Interface {\n"
1382 " int a;\n"
1383 " int b;\n"
1384 "}",
1385 Style);
1386 verifyFormat("protected interface Interface {\n"
1387 " int a;\n"
1388 " int b;\n"
1389 "}",
1390 Style);
1391 verifyFormat("private interface Interface {\n"
1392 " int a;\n"
1393 " int b;\n"
1394 "}",
1395 Style);
1396
1397 Style.BraceWrapping.AfterClass = true;
1398
1399 verifyFormat("class MyClass\n"
1400 "{\n"
1401 " int a;\n"
1402 " int b;\n"
1403 "}",
1404 Style);
1405 verifyFormat("internal class MyClass\n"
1406 "{\n"
1407 " int a;\n"
1408 " int b;\n"
1409 "}",
1410 Style);
1411 verifyFormat("public class MyClass\n"
1412 "{\n"
1413 " int a;\n"
1414 " int b;\n"
1415 "}",
1416 Style);
1417 verifyFormat("protected class MyClass\n"
1418 "{\n"
1419 " int a;\n"
1420 " int b;\n"
1421 "}",
1422 Style);
1423 verifyFormat("private class MyClass\n"
1424 "{\n"
1425 " int a;\n"
1426 " int b;\n"
1427 "}",
1428 Style);
1429
1430 verifyFormat("interface MyInterface\n"
1431 "{\n"
1432 " int a;\n"
1433 " int b;\n"
1434 "}",
1435 Style);
1436 verifyFormat("internal interface MyInterface\n"
1437 "{\n"
1438 " int a;\n"
1439 " int b;\n"
1440 "}",
1441 Style);
1442 verifyFormat("public interface MyInterface\n"
1443 "{\n"
1444 " int a;\n"
1445 " int b;\n"
1446 "}",
1447 Style);
1448 verifyFormat("protected interface MyInterface\n"
1449 "{\n"
1450 " int a;\n"
1451 " int b;\n"
1452 "}",
1453 Style);
1454 verifyFormat("private interface MyInterface\n"
1455 "{\n"
1456 " int a;\n"
1457 " int b;\n"
1458 "}",
1459 Style);
1460 verifyFormat("/* Foo */ private interface MyInterface\n"
1461 "{\n"
1462 " int a;\n"
1463 " int b;\n"
1464 "}",
1465 Style);
1466 verifyFormat("/* Foo */ /* Bar */ private interface MyInterface\n"
1467 "{\n"
1468 " int a;\n"
1469 " int b;\n"
1470 "}",
1471 Style);
1472 }
1473
TEST_F(FormatTestCSharp,NamespaceIndentation)1474 TEST_F(FormatTestCSharp, NamespaceIndentation) {
1475 FormatStyle Style = getMicrosoftStyle(FormatStyle::LK_CSharp);
1476 Style.NamespaceIndentation = FormatStyle::NI_None;
1477
1478 verifyFormat("namespace A\n"
1479 "{\n"
1480 "public interface Name1\n"
1481 "{\n"
1482 "}\n"
1483 "}\n",
1484 Style);
1485
1486 verifyFormat("namespace A.B\n"
1487 "{\n"
1488 "public interface Name1\n"
1489 "{\n"
1490 "}\n"
1491 "}\n",
1492 Style);
1493
1494 Style.NamespaceIndentation = FormatStyle::NI_Inner;
1495
1496 verifyFormat("namespace A\n"
1497 "{\n"
1498 "namespace B\n"
1499 "{\n"
1500 " public interface Name1\n"
1501 " {\n"
1502 " }\n"
1503 "}\n"
1504 "}\n",
1505 Style);
1506
1507 Style.NamespaceIndentation = FormatStyle::NI_All;
1508
1509 verifyFormat("namespace A.B\n"
1510 "{\n"
1511 " public interface Name1\n"
1512 " {\n"
1513 " }\n"
1514 "}\n",
1515 Style);
1516
1517 verifyFormat("namespace A\n"
1518 "{\n"
1519 " namespace B\n"
1520 " {\n"
1521 " public interface Name1\n"
1522 " {\n"
1523 " }\n"
1524 " }\n"
1525 "}\n",
1526 Style);
1527 }
1528
TEST_F(FormatTestCSharp,SwitchExpression)1529 TEST_F(FormatTestCSharp, SwitchExpression) {
1530 FormatStyle Style = getMicrosoftStyle(FormatStyle::LK_CSharp);
1531 verifyFormat("int x = a switch {\n"
1532 " 1 => (0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0),\n"
1533 " 2 => 1,\n"
1534 " _ => 2\n"
1535 "};\n",
1536 Style);
1537 }
1538
TEST_F(FormatTestCSharp,EmptyShortBlock)1539 TEST_F(FormatTestCSharp, EmptyShortBlock) {
1540 auto Style = getLLVMStyle();
1541 Style.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Empty;
1542
1543 verifyFormat("try {\n"
1544 " doA();\n"
1545 "} catch (Exception e) {\n"
1546 " e.printStackTrace();\n"
1547 "}\n",
1548 Style);
1549
1550 verifyFormat("try {\n"
1551 " doA();\n"
1552 "} catch (Exception e) {}\n",
1553 Style);
1554 }
1555
TEST_F(FormatTestCSharp,ShortFunctions)1556 TEST_F(FormatTestCSharp, ShortFunctions) {
1557 FormatStyle Style = getLLVMStyle(FormatStyle::LK_CSharp);
1558 Style.NamespaceIndentation = FormatStyle::NI_All;
1559 Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
1560 verifyFormat("interface Interface {\n"
1561 " void f() { return; }\n"
1562 "};",
1563 Style);
1564 verifyFormat("public interface Interface {\n"
1565 " void f() { return; }\n"
1566 "};",
1567 Style);
1568 verifyFormat("namespace {\n"
1569 " void f() {\n"
1570 " return;\n"
1571 " }\n"
1572 "};",
1573 Style);
1574 // "union" is not a keyword in C#.
1575 verifyFormat("namespace union {\n"
1576 " void f() {\n"
1577 " return;\n"
1578 " }\n"
1579 "};",
1580 Style);
1581 }
1582
1583 } // namespace format
1584 } // end namespace clang
1585