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