xref: /llvm-project/clang/unittests/Format/FormatTestCSharp.cpp (revision 07c1978b15b4e9daefbf358e6fd185b5aa269f98)
1cbb726d0SPaul Hoad //===- unittest/Format/FormatTestCSharp.cpp - Formatting tests for CSharp -===//
2cbb726d0SPaul Hoad //
3cbb726d0SPaul Hoad // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4cbb726d0SPaul Hoad // See https://llvm.org/LICENSE.txt for license information.
5cbb726d0SPaul Hoad // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6cbb726d0SPaul Hoad //
7cbb726d0SPaul Hoad //===----------------------------------------------------------------------===//
8cbb726d0SPaul Hoad 
9cbb726d0SPaul Hoad #include "FormatTestUtils.h"
10cbb726d0SPaul Hoad #include "clang/Format/Format.h"
11cbb726d0SPaul Hoad #include "llvm/Support/Debug.h"
12cbb726d0SPaul Hoad #include "gtest/gtest.h"
13cbb726d0SPaul Hoad 
14cbb726d0SPaul Hoad #define DEBUG_TYPE "format-test"
15cbb726d0SPaul Hoad 
16cbb726d0SPaul Hoad namespace clang {
17cbb726d0SPaul Hoad namespace format {
18cbb726d0SPaul Hoad 
19cbb726d0SPaul Hoad class FormatTestCSharp : public ::testing::Test {
20cbb726d0SPaul Hoad protected:
21cbb726d0SPaul Hoad   static std::string format(llvm::StringRef Code, unsigned Offset,
22cbb726d0SPaul Hoad                             unsigned Length, const FormatStyle &Style) {
23cbb726d0SPaul Hoad     LLVM_DEBUG(llvm::errs() << "---\n");
24cbb726d0SPaul Hoad     LLVM_DEBUG(llvm::errs() << Code << "\n\n");
25cbb726d0SPaul Hoad     std::vector<tooling::Range> Ranges(1, tooling::Range(Offset, Length));
26cbb726d0SPaul Hoad     tooling::Replacements Replaces = reformat(Style, Code, Ranges);
27cbb726d0SPaul Hoad     auto Result = applyAllReplacements(Code, Replaces);
28cbb726d0SPaul Hoad     EXPECT_TRUE(static_cast<bool>(Result));
29cbb726d0SPaul Hoad     LLVM_DEBUG(llvm::errs() << "\n" << *Result << "\n\n");
30cbb726d0SPaul Hoad     return *Result;
31cbb726d0SPaul Hoad   }
32cbb726d0SPaul Hoad 
33cbb726d0SPaul Hoad   static std::string
34cbb726d0SPaul Hoad   format(llvm::StringRef Code,
35a2f963bbSPaul Hoad          const FormatStyle &Style = getMicrosoftStyle(FormatStyle::LK_CSharp)) {
36cbb726d0SPaul Hoad     return format(Code, 0, Code.size(), Style);
37cbb726d0SPaul Hoad   }
38cbb726d0SPaul Hoad 
39cbb726d0SPaul Hoad   static FormatStyle getStyleWithColumns(unsigned ColumnLimit) {
40a2f963bbSPaul Hoad     FormatStyle Style = getMicrosoftStyle(FormatStyle::LK_CSharp);
41cbb726d0SPaul Hoad     Style.ColumnLimit = ColumnLimit;
42cbb726d0SPaul Hoad     return Style;
43cbb726d0SPaul Hoad   }
44cbb726d0SPaul Hoad 
45cbb726d0SPaul Hoad   static void verifyFormat(
46cbb726d0SPaul Hoad       llvm::StringRef Code,
47a2f963bbSPaul Hoad       const FormatStyle &Style = getMicrosoftStyle(FormatStyle::LK_CSharp)) {
48cbb726d0SPaul Hoad     EXPECT_EQ(Code.str(), format(Code, Style)) << "Expected code is not stable";
49cbb726d0SPaul Hoad     EXPECT_EQ(Code.str(), format(test::messUp(Code), Style));
50cbb726d0SPaul Hoad   }
51cbb726d0SPaul Hoad };
52cbb726d0SPaul Hoad 
53cbb726d0SPaul Hoad TEST_F(FormatTestCSharp, CSharpClass) {
54a2f963bbSPaul Hoad   verifyFormat("public class SomeClass\n"
55a2f963bbSPaul Hoad                "{\n"
56a2f963bbSPaul Hoad                "    void f()\n"
57a2f963bbSPaul Hoad                "    {\n"
58a2f963bbSPaul Hoad                "    }\n"
59a2f963bbSPaul Hoad                "    int g()\n"
60a2f963bbSPaul Hoad                "    {\n"
61a2f963bbSPaul Hoad                "        return 0;\n"
62a2f963bbSPaul Hoad                "    }\n"
63a2f963bbSPaul Hoad                "    void h()\n"
64a2f963bbSPaul Hoad                "    {\n"
65a2f963bbSPaul Hoad                "        while (true)\n"
66a2f963bbSPaul Hoad                "            f();\n"
67a2f963bbSPaul Hoad                "        for (;;)\n"
68a2f963bbSPaul Hoad                "            f();\n"
69a2f963bbSPaul Hoad                "        if (true)\n"
70a2f963bbSPaul Hoad                "            f();\n"
71cbb726d0SPaul Hoad                "    }\n"
72cbb726d0SPaul Hoad                "}");
73f40a7972SJonathan Coe 
74f40a7972SJonathan Coe   // Ensure that small and empty classes are handled correctly with condensed
75f40a7972SJonathan Coe   // (Google C++-like) brace-breaking style.
76f40a7972SJonathan Coe   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
77f40a7972SJonathan Coe   Style.BreakBeforeBraces = FormatStyle::BS_Attach;
78f40a7972SJonathan Coe 
79f40a7972SJonathan Coe   verifyFormat("public class SomeEmptyClass {}", Style);
80f40a7972SJonathan Coe 
81f40a7972SJonathan Coe   verifyFormat("public class SomeTinyClass {\n"
82f40a7972SJonathan Coe                "  int X;\n"
83f40a7972SJonathan Coe                "}",
84f40a7972SJonathan Coe                Style);
85f40a7972SJonathan Coe   verifyFormat("private class SomeTinyClass {\n"
86f40a7972SJonathan Coe                "  int X;\n"
87f40a7972SJonathan Coe                "}",
88f40a7972SJonathan Coe                Style);
89f40a7972SJonathan Coe   verifyFormat("protected class SomeTinyClass {\n"
90f40a7972SJonathan Coe                "  int X;\n"
91f40a7972SJonathan Coe                "}",
92f40a7972SJonathan Coe                Style);
93f40a7972SJonathan Coe   verifyFormat("internal class SomeTinyClass {\n"
94f40a7972SJonathan Coe                "  int X;\n"
95f40a7972SJonathan Coe                "}",
96f40a7972SJonathan Coe                Style);
97cbb726d0SPaul Hoad }
98cbb726d0SPaul Hoad 
99cbb726d0SPaul Hoad TEST_F(FormatTestCSharp, AccessModifiers) {
100a2f963bbSPaul Hoad   verifyFormat("public String toString()\n"
101a2f963bbSPaul Hoad                "{\n"
102a2f963bbSPaul Hoad                "}");
103a2f963bbSPaul Hoad   verifyFormat("private String toString()\n"
104a2f963bbSPaul Hoad                "{\n"
105a2f963bbSPaul Hoad                "}");
106a2f963bbSPaul Hoad   verifyFormat("protected String toString()\n"
107a2f963bbSPaul Hoad                "{\n"
108a2f963bbSPaul Hoad                "}");
109a2f963bbSPaul Hoad   verifyFormat("internal String toString()\n"
110a2f963bbSPaul Hoad                "{\n"
111a2f963bbSPaul Hoad                "}");
112cbb726d0SPaul Hoad 
113a2f963bbSPaul Hoad   verifyFormat("public override String toString()\n"
114a2f963bbSPaul Hoad                "{\n"
115a2f963bbSPaul Hoad                "}");
116a2f963bbSPaul Hoad   verifyFormat("private override String toString()\n"
117a2f963bbSPaul Hoad                "{\n"
118a2f963bbSPaul Hoad                "}");
119a2f963bbSPaul Hoad   verifyFormat("protected override String toString()\n"
120a2f963bbSPaul Hoad                "{\n"
121a2f963bbSPaul Hoad                "}");
122a2f963bbSPaul Hoad   verifyFormat("internal override String toString()\n"
123a2f963bbSPaul Hoad                "{\n"
124a2f963bbSPaul Hoad                "}");
125cbb726d0SPaul Hoad 
126a2f963bbSPaul Hoad   verifyFormat("internal static String toString()\n"
127a2f963bbSPaul Hoad                "{\n"
128a2f963bbSPaul Hoad                "}");
129cbb726d0SPaul Hoad }
130cbb726d0SPaul Hoad 
131cbb726d0SPaul Hoad TEST_F(FormatTestCSharp, NoStringLiteralBreaks) {
132cbb726d0SPaul Hoad   verifyFormat("foo("
133cbb726d0SPaul Hoad                "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
134cbb726d0SPaul Hoad                "aaaaaa\");");
135cbb726d0SPaul Hoad }
136cbb726d0SPaul Hoad 
137cbb726d0SPaul Hoad TEST_F(FormatTestCSharp, CSharpVerbatiumStringLiterals) {
138cbb726d0SPaul Hoad   verifyFormat("foo(@\"aaaaaaaa\\abc\\aaaa\");");
139cbb726d0SPaul Hoad   // @"ABC\" + ToString("B") - handle embedded \ in literal string at
140cbb726d0SPaul Hoad   // the end
141cbb726d0SPaul Hoad   //
142cbb726d0SPaul Hoad   /*
143cbb726d0SPaul Hoad    * After removal of Lexer change we are currently not able
144cbb726d0SPaul Hoad    * To handle these cases
145cbb726d0SPaul Hoad    verifyFormat("string s = @\"ABC\\\" + ToString(\"B\");");
146cbb726d0SPaul Hoad    verifyFormat("string s = @\"ABC\"\"DEF\"\"GHI\"");
147cbb726d0SPaul Hoad    verifyFormat("string s = @\"ABC\"\"DEF\"\"\"");
148cbb726d0SPaul Hoad    verifyFormat("string s = @\"ABC\"\"DEF\"\"\" + abc");
149cbb726d0SPaul Hoad   */
150cbb726d0SPaul Hoad }
151cbb726d0SPaul Hoad 
152cbb726d0SPaul Hoad TEST_F(FormatTestCSharp, CSharpInterpolatedStringLiterals) {
153cbb726d0SPaul Hoad   verifyFormat("foo($\"aaaaaaaa{aaa}aaaa\");");
154cbb726d0SPaul Hoad   verifyFormat("foo($\"aaaa{A}\");");
155cbb726d0SPaul Hoad   verifyFormat(
156cbb726d0SPaul Hoad       "foo($\"aaaa{A}"
157cbb726d0SPaul Hoad       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\");");
158cbb726d0SPaul Hoad   verifyFormat("Name = $\"{firstName} {lastName}\";");
159cbb726d0SPaul Hoad 
160cbb726d0SPaul Hoad   // $"ABC\" + ToString("B") - handle embedded \ in literal string at
161cbb726d0SPaul Hoad   // the end
162cbb726d0SPaul Hoad   verifyFormat("string s = $\"A{abc}BC\" + ToString(\"B\");");
163cbb726d0SPaul Hoad   verifyFormat("$\"{domain}\\\\{user}\"");
164cbb726d0SPaul Hoad   verifyFormat(
165cbb726d0SPaul Hoad       "var verbatimInterpolated = $@\"C:\\Users\\{userName}\\Documents\\\";");
166cbb726d0SPaul Hoad }
167cbb726d0SPaul Hoad 
168cbb726d0SPaul Hoad TEST_F(FormatTestCSharp, CSharpFatArrows) {
169cbb726d0SPaul Hoad   verifyFormat("Task serverTask = Task.Run(async() => {");
170cbb726d0SPaul Hoad   verifyFormat("public override string ToString() => \"{Name}\\{Age}\";");
171cbb726d0SPaul Hoad }
172cbb726d0SPaul Hoad 
173c3af063cSJonathan Coe TEST_F(FormatTestCSharp, CSharpConditionalExpressions) {
174c3af063cSJonathan Coe   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
175c3af063cSJonathan Coe   // conditional expression is not seen as a NullConditional.
176c3af063cSJonathan Coe   verifyFormat("var y = A < B ? -1 : 1;", Style);
177c3af063cSJonathan Coe }
178c3af063cSJonathan Coe 
179cbb726d0SPaul Hoad TEST_F(FormatTestCSharp, CSharpNullConditional) {
1804c056583SPaul Hoad   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
1814c056583SPaul Hoad   Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
1824c056583SPaul Hoad 
183cbb726d0SPaul Hoad   verifyFormat(
184cbb726d0SPaul Hoad       "public Person(string firstName, string lastName, int? age = null)");
185cbb726d0SPaul Hoad 
1864c056583SPaul Hoad   verifyFormat("foo () {\n"
1874c056583SPaul Hoad                "  switch (args?.Length) {}\n"
1884c056583SPaul Hoad                "}",
1894c056583SPaul Hoad                Style);
1904c056583SPaul Hoad 
1914c056583SPaul Hoad   verifyFormat("switch (args?.Length) {}", Style);
192cbb726d0SPaul Hoad 
193a2f963bbSPaul Hoad   verifyFormat("public static void Main(string[] args)\n"
194a2f963bbSPaul Hoad                "{\n"
195a2f963bbSPaul Hoad                "    string dirPath = args?[0];\n"
196a2f963bbSPaul Hoad                "}");
1974c056583SPaul Hoad 
1984c056583SPaul Hoad   Style.SpaceBeforeParens = FormatStyle::SBPO_Never;
1994c056583SPaul Hoad 
2004c056583SPaul Hoad   verifyFormat("switch(args?.Length) {}", Style);
201cbb726d0SPaul Hoad }
202cbb726d0SPaul Hoad 
203cbb726d0SPaul Hoad TEST_F(FormatTestCSharp, Attributes) {
204cbb726d0SPaul Hoad   verifyFormat("[STAThread]\n"
205a2f963bbSPaul Hoad                "static void Main(string[] args)\n"
206a2f963bbSPaul Hoad                "{\n"
207a2f963bbSPaul Hoad                "}");
208cbb726d0SPaul Hoad 
209cbb726d0SPaul Hoad   verifyFormat("[TestMethod]\n"
210a2f963bbSPaul Hoad                "private class Test\n"
211a2f963bbSPaul Hoad                "{\n"
212a2f963bbSPaul Hoad                "}");
213cbb726d0SPaul Hoad 
214cbb726d0SPaul Hoad   verifyFormat("[TestMethod]\n"
215a2f963bbSPaul Hoad                "protected class Test\n"
216a2f963bbSPaul Hoad                "{\n"
217a2f963bbSPaul Hoad                "}");
218cbb726d0SPaul Hoad 
219cbb726d0SPaul Hoad   verifyFormat("[TestMethod]\n"
220a2f963bbSPaul Hoad                "internal class Test\n"
221a2f963bbSPaul Hoad                "{\n"
222a2f963bbSPaul Hoad                "}");
223cbb726d0SPaul Hoad 
224cbb726d0SPaul Hoad   verifyFormat("[TestMethod]\n"
225a2f963bbSPaul Hoad                "class Test\n"
226a2f963bbSPaul Hoad                "{\n"
227a2f963bbSPaul Hoad                "}");
228cbb726d0SPaul Hoad 
229cbb726d0SPaul Hoad   verifyFormat("[TestMethod]\n"
230cbb726d0SPaul Hoad                "[DeploymentItem(\"Test.txt\")]\n"
231a2f963bbSPaul Hoad                "public class Test\n"
232a2f963bbSPaul Hoad                "{\n"
233a2f963bbSPaul Hoad                "}");
234cbb726d0SPaul Hoad 
235cbb726d0SPaul Hoad   verifyFormat("[System.AttributeUsage(System.AttributeTargets.Method)]\n"
236cbb726d0SPaul Hoad                "[System.Runtime.InteropServices.ComVisible(true)]\n"
237a2f963bbSPaul Hoad                "public sealed class STAThreadAttribute : Attribute\n"
238a2f963bbSPaul Hoad                "{\n"
239a2f963bbSPaul Hoad                "}");
240cbb726d0SPaul Hoad 
241cbb726d0SPaul Hoad   verifyFormat("[Verb(\"start\", HelpText = \"Starts the server listening on "
242cbb726d0SPaul Hoad                "provided port\")]\n"
243a2f963bbSPaul Hoad                "class Test\n"
244a2f963bbSPaul Hoad                "{\n"
245a2f963bbSPaul Hoad                "}");
246cbb726d0SPaul Hoad 
247cbb726d0SPaul Hoad   verifyFormat("[TestMethod]\n"
248a2f963bbSPaul Hoad                "public string Host\n"
2492bd6974aSJonathan Coe                "{ set; get; }");
250cbb726d0SPaul Hoad 
251cbb726d0SPaul Hoad   verifyFormat("[TestMethod(\"start\", HelpText = \"Starts the server "
252cbb726d0SPaul Hoad                "listening on provided host\")]\n"
253a2f963bbSPaul Hoad                "public string Host\n"
2542bd6974aSJonathan Coe                "{ set; get; }");
25550d8977cSJonathan Coe 
25650d8977cSJonathan Coe   verifyFormat(
25750d8977cSJonathan Coe       "[DllImport(\"Hello\", EntryPoint = \"hello_world\")]\n"
25850d8977cSJonathan Coe       "// The const char* returned by hello_world must not be deleted.\n"
25950d8977cSJonathan Coe       "private static extern IntPtr HelloFromCpp();)");
260ca1fd460SJonathan Coe 
261b46f925dSJonathan Coe   // Class attributes go on their own line and do not affect layout of
262b46f925dSJonathan Coe   // interfaces. Line wrapping decisions previously caused each interface to be
263b46f925dSJonathan Coe   // on its own line.
264b46f925dSJonathan Coe   verifyFormat("[SomeAttribute]\n"
265b46f925dSJonathan Coe                "[SomeOtherAttribute]\n"
266b46f925dSJonathan Coe                "public class A : IShape, IAnimal, IVehicle\n"
267b46f925dSJonathan Coe                "{\n"
268b46f925dSJonathan Coe                "    int X;\n"
269b46f925dSJonathan Coe                "}");
270b46f925dSJonathan Coe 
271b46f925dSJonathan Coe   // Attributes in a method declaration do not cause line wrapping.
272b46f925dSJonathan Coe   verifyFormat("void MethodA([In][Out] ref double x)\n"
273b46f925dSJonathan Coe                "{\n"
274b46f925dSJonathan Coe                "}");
275b46f925dSJonathan Coe 
2769f8a7e82SJonathan Coe   // [] in an attribute do not cause premature line wrapping or indenting.
2779f8a7e82SJonathan Coe   verifyFormat(R"(//
2789f8a7e82SJonathan Coe public class A
2799f8a7e82SJonathan Coe {
2809f8a7e82SJonathan Coe     [SomeAttribute(new[] { RED, GREEN, BLUE }, -1.0f, 1.0f)]
2819f8a7e82SJonathan Coe     [DoNotSerialize]
2829f8a7e82SJonathan Coe     public Data MemberVariable;
2839f8a7e82SJonathan Coe })");
2849f8a7e82SJonathan Coe 
285ca1fd460SJonathan Coe   //  Unwrappable lines go on a line of their own.
286ca1fd460SJonathan Coe   // 'target:' is not treated as a label.
287ca1fd460SJonathan Coe   // Modify Style to enforce a column limit.
288ca1fd460SJonathan Coe   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
289ca1fd460SJonathan Coe   Style.ColumnLimit = 10;
290ca1fd460SJonathan Coe   verifyFormat(R"([assembly:InternalsVisibleTo(
291ca1fd460SJonathan Coe     "SomeAssembly, PublicKey=SomePublicKeyThatExceedsTheColumnLimit")])",
292ca1fd460SJonathan Coe                Style);
293cbb726d0SPaul Hoad }
294cbb726d0SPaul Hoad 
295719087bbSPaul Hoad TEST_F(FormatTestCSharp, CSharpUsing) {
296719087bbSPaul Hoad   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
297719087bbSPaul Hoad   Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
298719087bbSPaul Hoad   verifyFormat("public void foo () {\n"
299719087bbSPaul Hoad                "  using (StreamWriter sw = new StreamWriter (filenameA)) {}\n"
3001e0174a9SKrasimir Georgiev                "  using () {}\n"
301719087bbSPaul Hoad                "}",
302719087bbSPaul Hoad                Style);
303719087bbSPaul Hoad 
3041e0174a9SKrasimir Georgiev   // Ensure clang-format affects top-level snippets correctly.
3054c056583SPaul Hoad   verifyFormat("using (StreamWriter sw = new StreamWriter (filenameB)) {}",
3064c056583SPaul Hoad                Style);
3074c056583SPaul Hoad 
308719087bbSPaul Hoad   Style.SpaceBeforeParens = FormatStyle::SBPO_Never;
309719087bbSPaul Hoad   verifyFormat("public void foo() {\n"
310719087bbSPaul Hoad                "  using(StreamWriter sw = new StreamWriter(filenameB)) {}\n"
3111e0174a9SKrasimir Georgiev                "  using() {}\n"
312719087bbSPaul Hoad                "}",
313719087bbSPaul Hoad                Style);
3144c056583SPaul Hoad 
3151e0174a9SKrasimir Georgiev   // Ensure clang-format affects top-level snippets correctly.
3161e0174a9SKrasimir Georgiev   verifyFormat("using(StreamWriter sw = new StreamWriter(filenameB)) {}",
3171e0174a9SKrasimir Georgiev                Style);
3181e0174a9SKrasimir Georgiev 
3191e0174a9SKrasimir Georgiev   Style.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements;
3201e0174a9SKrasimir Georgiev   verifyFormat("public void foo() {\n"
3211e0174a9SKrasimir Georgiev                "  using (StreamWriter sw = new StreamWriter(filenameA)) {}\n"
3221e0174a9SKrasimir Georgiev                "  using () {}\n"
3231e0174a9SKrasimir Georgiev                "}",
3241e0174a9SKrasimir Georgiev                Style);
3251e0174a9SKrasimir Georgiev 
3261e0174a9SKrasimir Georgiev   // Ensure clang-format affects top-level snippets correctly.
3271e0174a9SKrasimir Georgiev   verifyFormat("using (StreamWriter sw = new StreamWriter(filenameB)) {}",
3281e0174a9SKrasimir Georgiev                Style);
3291e0174a9SKrasimir Georgiev 
3301e0174a9SKrasimir Georgiev   Style.SpaceBeforeParens = FormatStyle::SBPO_NonEmptyParentheses;
3311e0174a9SKrasimir Georgiev   verifyFormat("public void foo() {\n"
3321e0174a9SKrasimir Georgiev                "  using (StreamWriter sw = new StreamWriter (filenameA)) {}\n"
3331e0174a9SKrasimir Georgiev                "  using() {}\n"
3341e0174a9SKrasimir Georgiev                "}",
3351e0174a9SKrasimir Georgiev                Style);
3361e0174a9SKrasimir Georgiev 
3371e0174a9SKrasimir Georgiev   // Ensure clang-format affects top-level snippets correctly.
3384c056583SPaul Hoad   verifyFormat("using (StreamWriter sw = new StreamWriter (filenameB)) {}",
3394c056583SPaul Hoad                Style);
340719087bbSPaul Hoad }
341719087bbSPaul Hoad 
342cbb726d0SPaul Hoad TEST_F(FormatTestCSharp, CSharpRegions) {
343cbb726d0SPaul Hoad   verifyFormat("#region aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaa "
344cbb726d0SPaul Hoad                "aaaaaaaaaaaaaaa long region");
345cbb726d0SPaul Hoad }
346cbb726d0SPaul Hoad 
347cbb726d0SPaul Hoad TEST_F(FormatTestCSharp, CSharpKeyWordEscaping) {
348cbb726d0SPaul Hoad   verifyFormat("public enum var { none, @string, bool, @enum }");
349cbb726d0SPaul Hoad }
350cbb726d0SPaul Hoad 
351cbb726d0SPaul Hoad TEST_F(FormatTestCSharp, CSharpNullCoalescing) {
352cbb726d0SPaul Hoad   verifyFormat("var test = ABC ?? DEF");
353cbb726d0SPaul Hoad   verifyFormat("string myname = name ?? \"ABC\";");
354cbb726d0SPaul Hoad   verifyFormat("return _name ?? \"DEF\";");
355cbb726d0SPaul Hoad }
356cbb726d0SPaul Hoad 
357a2f963bbSPaul Hoad TEST_F(FormatTestCSharp, AttributesIndentation) {
358a2f963bbSPaul Hoad   FormatStyle Style = getMicrosoftStyle(FormatStyle::LK_CSharp);
359a2f963bbSPaul Hoad   Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None;
360a2f963bbSPaul Hoad 
361a2f963bbSPaul Hoad   verifyFormat("[STAThread]\n"
362a2f963bbSPaul Hoad                "static void Main(string[] args)\n"
363a2f963bbSPaul Hoad                "{\n"
364a2f963bbSPaul Hoad                "}",
365a2f963bbSPaul Hoad                Style);
366a2f963bbSPaul Hoad 
367a2f963bbSPaul Hoad   verifyFormat("[STAThread]\n"
368a2f963bbSPaul Hoad                "void "
369a2f963bbSPaul Hoad                "veryLooooooooooooooongFunctionName(string[] args)\n"
370a2f963bbSPaul Hoad                "{\n"
371a2f963bbSPaul Hoad                "}",
372a2f963bbSPaul Hoad                Style);
373a2f963bbSPaul Hoad 
374a2f963bbSPaul Hoad   verifyFormat("[STAThread]\n"
375a2f963bbSPaul Hoad                "veryLoooooooooooooooooooongReturnType "
376a2f963bbSPaul Hoad                "veryLooooooooooooooongFunctionName(string[] args)\n"
377a2f963bbSPaul Hoad                "{\n"
378a2f963bbSPaul Hoad                "}",
379a2f963bbSPaul Hoad                Style);
380a2f963bbSPaul Hoad 
381a2f963bbSPaul Hoad   verifyFormat("[SuppressMessage(\"A\", \"B\", Justification = \"C\")]\n"
382a2f963bbSPaul Hoad                "public override X Y()\n"
383a2f963bbSPaul Hoad                "{\n"
384a2f963bbSPaul Hoad                "}\n",
385a2f963bbSPaul Hoad                Style);
386a2f963bbSPaul Hoad 
387a2f963bbSPaul Hoad   verifyFormat("[SuppressMessage]\n"
388a2f963bbSPaul Hoad                "public X Y()\n"
389a2f963bbSPaul Hoad                "{\n"
390a2f963bbSPaul Hoad                "}\n",
391a2f963bbSPaul Hoad                Style);
392a2f963bbSPaul Hoad 
393a2f963bbSPaul Hoad   verifyFormat("[SuppressMessage]\n"
394a2f963bbSPaul Hoad                "public override X Y()\n"
395a2f963bbSPaul Hoad                "{\n"
396a2f963bbSPaul Hoad                "}\n",
397a2f963bbSPaul Hoad                Style);
398a2f963bbSPaul Hoad 
399a2f963bbSPaul Hoad   verifyFormat("public A(B b) : base(b)\n"
400a2f963bbSPaul Hoad                "{\n"
401a2f963bbSPaul Hoad                "    [SuppressMessage]\n"
402a2f963bbSPaul Hoad                "    public override X Y()\n"
403a2f963bbSPaul Hoad                "    {\n"
404a2f963bbSPaul Hoad                "    }\n"
405a2f963bbSPaul Hoad                "}\n",
406a2f963bbSPaul Hoad                Style);
4072f209ccfSmydeveloperday 
4082f209ccfSmydeveloperday   verifyFormat("public A : Base\n"
4092f209ccfSmydeveloperday                "{\n"
4102f209ccfSmydeveloperday                "}\n"
4112f209ccfSmydeveloperday                "[Test]\n"
4122f209ccfSmydeveloperday                "public Foo()\n"
4132f209ccfSmydeveloperday                "{\n"
4142f209ccfSmydeveloperday                "}\n",
4152f209ccfSmydeveloperday                Style);
4162f209ccfSmydeveloperday 
4172f209ccfSmydeveloperday   verifyFormat("namespace\n"
4182f209ccfSmydeveloperday                "{\n"
4192f209ccfSmydeveloperday                "public A : Base\n"
4202f209ccfSmydeveloperday                "{\n"
4212f209ccfSmydeveloperday                "}\n"
4222f209ccfSmydeveloperday                "[Test]\n"
4232f209ccfSmydeveloperday                "public Foo()\n"
4242f209ccfSmydeveloperday                "{\n"
4252f209ccfSmydeveloperday                "}\n"
4262f209ccfSmydeveloperday                "}\n",
4272f209ccfSmydeveloperday                Style);
428a2f963bbSPaul Hoad }
429a2f963bbSPaul Hoad 
4304c056583SPaul Hoad TEST_F(FormatTestCSharp, CSharpSpaceBefore) {
4314c056583SPaul Hoad   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
4324c056583SPaul Hoad   Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
4334c056583SPaul Hoad 
4344c056583SPaul Hoad   verifyFormat("List<string> list;", Style);
4354c056583SPaul Hoad   verifyFormat("Dictionary<string, string> dict;", Style);
4364c056583SPaul Hoad 
4374c056583SPaul Hoad   verifyFormat("for (int i = 0; i < size (); i++) {\n"
4384c056583SPaul Hoad                "}",
4394c056583SPaul Hoad                Style);
4404c056583SPaul Hoad   verifyFormat("foreach (var x in y) {\n"
4414c056583SPaul Hoad                "}",
4424c056583SPaul Hoad                Style);
4434c056583SPaul Hoad   verifyFormat("switch (x) {}", Style);
4444c056583SPaul Hoad   verifyFormat("do {\n"
4454c056583SPaul Hoad                "} while (x);",
4464c056583SPaul Hoad                Style);
4474c056583SPaul Hoad 
4484c056583SPaul Hoad   Style.SpaceBeforeParens = FormatStyle::SBPO_Never;
4494c056583SPaul Hoad 
4504c056583SPaul Hoad   verifyFormat("List<string> list;", Style);
4514c056583SPaul Hoad   verifyFormat("Dictionary<string, string> dict;", Style);
4524c056583SPaul Hoad 
4534c056583SPaul Hoad   verifyFormat("for(int i = 0; i < size(); i++) {\n"
4544c056583SPaul Hoad                "}",
4554c056583SPaul Hoad                Style);
4564c056583SPaul Hoad   verifyFormat("foreach(var x in y) {\n"
4574c056583SPaul Hoad                "}",
4584c056583SPaul Hoad                Style);
4594c056583SPaul Hoad   verifyFormat("switch(x) {}", Style);
4604c056583SPaul Hoad   verifyFormat("do {\n"
4614c056583SPaul Hoad                "} while(x);",
4624c056583SPaul Hoad                Style);
4634c056583SPaul Hoad }
4644c056583SPaul Hoad 
465d82adf32Smydeveloperday TEST_F(FormatTestCSharp, CSharpSpaceAfterCStyleCast) {
466d82adf32Smydeveloperday   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
467d82adf32Smydeveloperday 
468d82adf32Smydeveloperday   verifyFormat("(int)x / y;", Style);
469d82adf32Smydeveloperday 
470d82adf32Smydeveloperday   Style.SpaceAfterCStyleCast = true;
471d82adf32Smydeveloperday   verifyFormat("(int) x / y;", Style);
472d82adf32Smydeveloperday }
473d82adf32Smydeveloperday 
47436a8f7f6SKrasimir Georgiev TEST_F(FormatTestCSharp, CSharpEscapedQuotesInVerbatimStrings) {
47536a8f7f6SKrasimir Georgiev   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
47636a8f7f6SKrasimir Georgiev 
477f9f0919dSJonathan Coe   verifyFormat(R"(string str = @"""";)", Style);
478f9f0919dSJonathan Coe   verifyFormat(R"(string str = @"""Hello world""";)", Style);
479f9f0919dSJonathan Coe   verifyFormat(R"(string str = $@"""Hello {friend}""";)", Style);
48036a8f7f6SKrasimir Georgiev }
48136a8f7f6SKrasimir Georgiev 
4829d212e83SJonathan Coe TEST_F(FormatTestCSharp, CSharpQuotesInInterpolatedStrings) {
4839d212e83SJonathan Coe   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
4849d212e83SJonathan Coe 
4859d212e83SJonathan Coe   verifyFormat(R"(string str1 = $"{null ?? "null"}";)", Style);
4869d212e83SJonathan Coe   verifyFormat(R"(string str2 = $"{{{braceCount} braces";)", Style);
4879d212e83SJonathan Coe   verifyFormat(R"(string str3 = $"{braceCount}}} braces";)", Style);
4889d212e83SJonathan Coe }
4899d212e83SJonathan Coe 
490f9f0919dSJonathan Coe TEST_F(FormatTestCSharp, CSharpNewlinesInVerbatimStrings) {
491f9f0919dSJonathan Coe   // Use MS style as Google Style inserts a line break before multiline strings.
492f9f0919dSJonathan Coe 
493f9f0919dSJonathan Coe   // verifyFormat does not understand multiline C# string-literals
494f9f0919dSJonathan Coe   // so check the format explicitly.
495f9f0919dSJonathan Coe 
496f9f0919dSJonathan Coe   FormatStyle Style = getMicrosoftStyle(FormatStyle::LK_CSharp);
497f9f0919dSJonathan Coe 
498f9f0919dSJonathan Coe   std::string Code = R"(string s1 = $@"some code:
499f9f0919dSJonathan Coe   class {className} {{
500f9f0919dSJonathan Coe     {className}() {{}}
501f9f0919dSJonathan Coe   }}";)";
502f9f0919dSJonathan Coe 
503f9f0919dSJonathan Coe   EXPECT_EQ(Code, format(Code, Style));
504f9f0919dSJonathan Coe 
505f9f0919dSJonathan Coe   // Multiline string in the middle of a function call.
506f9f0919dSJonathan Coe   Code = R"(
507f9f0919dSJonathan Coe var x = foo(className, $@"some code:
508f9f0919dSJonathan Coe   class {className} {{
509f9f0919dSJonathan Coe     {className}() {{}}
510f9f0919dSJonathan Coe   }}",
511f9f0919dSJonathan Coe             y);)"; // y aligned with `className` arg.
512f9f0919dSJonathan Coe 
513f9f0919dSJonathan Coe   EXPECT_EQ(Code, format(Code, Style));
514f9f0919dSJonathan Coe 
515f9f0919dSJonathan Coe   // Interpolated string with embedded multiline string.
516f9f0919dSJonathan Coe   Code = R"(Console.WriteLine($"{string.Join(@",
517f9f0919dSJonathan Coe 		", values)}");)";
518f9f0919dSJonathan Coe 
519f9f0919dSJonathan Coe   EXPECT_EQ(Code, format(Code, Style));
520f9f0919dSJonathan Coe }
521f9f0919dSJonathan Coe 
5220bb60e29SJonathan Coe TEST_F(FormatTestCSharp, CSharpObjectInitializers) {
5230bb60e29SJonathan Coe   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
5240bb60e29SJonathan Coe 
525a11ff39bSJonathan Coe   // Start code fragments with a comment line so that C++ raw string literals
5260bb60e29SJonathan Coe   // as seen are identical to expected formatted code.
5270bb60e29SJonathan Coe 
5280bb60e29SJonathan Coe   verifyFormat(R"(//
5290bb60e29SJonathan Coe Shape[] shapes = new[] {
5300bb60e29SJonathan Coe   new Circle {
5310bb60e29SJonathan Coe     Radius = 2.7281,
5320bb60e29SJonathan Coe     Colour = Colours.Red,
5330bb60e29SJonathan Coe   },
5340bb60e29SJonathan Coe   new Square {
5350bb60e29SJonathan Coe     Side = 101.1,
5360bb60e29SJonathan Coe     Colour = Colours.Yellow,
5370bb60e29SJonathan Coe   },
5380bb60e29SJonathan Coe };)",
5390bb60e29SJonathan Coe                Style);
5400bb60e29SJonathan Coe 
5410bb60e29SJonathan Coe   // Omitted final `,`s will change the formatting.
5420bb60e29SJonathan Coe   verifyFormat(R"(//
5430bb60e29SJonathan Coe Shape[] shapes = new[] { new Circle { Radius = 2.7281, Colour = Colours.Red },
544eb682b80SJonathan Coe                          new Square { Side = 101.1, Colour = Colours.Yellow } };)",
5450bb60e29SJonathan Coe                Style);
5467d2fdd3fSJonathan Coe 
5477d2fdd3fSJonathan Coe   // Lambdas can be supplied as initialiser arguments.
5487d2fdd3fSJonathan Coe   verifyFormat(R"(//
5497d2fdd3fSJonathan Coe private Transformer _transformer = new X.Y {
5507d2fdd3fSJonathan Coe   Filler = (Shape shape) => { return new Transform.Fill(shape, RED); },
5517d2fdd3fSJonathan Coe   Scaler = (Shape shape) => { return new Transform.Resize(shape, 0.1); },
5527d2fdd3fSJonathan Coe };)",
5537d2fdd3fSJonathan Coe                Style);
5540c28a093SJonathan Coe 
5550c28a093SJonathan Coe   // Dictionary initialisation.
5560c28a093SJonathan Coe   verifyFormat(R"(//
5570c28a093SJonathan Coe var myDict = new Dictionary<string, string> {
5580c28a093SJonathan Coe   ["name"] = _donald,
5590c28a093SJonathan Coe   ["age"] = Convert.ToString(DateTime.Today.Year - 1934),
5600c28a093SJonathan Coe   ["type"] = _duck,
5610c28a093SJonathan Coe };)",
5620c28a093SJonathan Coe                Style);
5630bb60e29SJonathan Coe }
5640bb60e29SJonathan Coe 
5655e1a026cSJonathan Coe TEST_F(FormatTestCSharp, CSharpArrayInitializers) {
5665e1a026cSJonathan Coe   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
5675e1a026cSJonathan Coe 
5685e1a026cSJonathan Coe   verifyFormat(R"(//
5695e1a026cSJonathan Coe private MySet<Node>[] setPoints = {
5705e1a026cSJonathan Coe   new Point<Node>(),
5715e1a026cSJonathan Coe   new Point<Node>(),
5725e1a026cSJonathan Coe };)",
5735e1a026cSJonathan Coe                Style);
5745e1a026cSJonathan Coe }
5755e1a026cSJonathan Coe 
576a11ff39bSJonathan Coe TEST_F(FormatTestCSharp, CSharpNamedArguments) {
577a11ff39bSJonathan Coe   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
578a11ff39bSJonathan Coe 
579a11ff39bSJonathan Coe   verifyFormat(R"(//
580a11ff39bSJonathan Coe PrintOrderDetails(orderNum: 31, productName: "Red Mug",
581a11ff39bSJonathan Coe                   sellerName: "Gift Shop");)",
582a11ff39bSJonathan Coe                Style);
583a11ff39bSJonathan Coe 
584a11ff39bSJonathan Coe   // Ensure that trailing comments do not cause problems.
585a11ff39bSJonathan Coe   verifyFormat(R"(//
586a11ff39bSJonathan Coe PrintOrderDetails(orderNum: 31, productName: "Red Mug",  // comment
587a11ff39bSJonathan Coe                   sellerName: "Gift Shop");)",
588a11ff39bSJonathan Coe                Style);
5897dfe0cc7SJonathan Coe 
5907dfe0cc7SJonathan Coe   verifyFormat(R"(foreach (var tickCount in task.Begin(seed: 0)) {)", Style);
591a11ff39bSJonathan Coe }
592a11ff39bSJonathan Coe 
5932bd6974aSJonathan Coe TEST_F(FormatTestCSharp, CSharpPropertyAccessors) {
5942bd6974aSJonathan Coe   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
5952bd6974aSJonathan Coe 
5962bd6974aSJonathan Coe   verifyFormat("int Value { get }", Style);
5972bd6974aSJonathan Coe   verifyFormat("int Value { get; }", Style);
5982bd6974aSJonathan Coe   verifyFormat("int Value { internal get; }", Style);
5992bd6974aSJonathan Coe   verifyFormat("int Value { get; } = 0", Style);
6002bd6974aSJonathan Coe   verifyFormat("int Value { set }", Style);
6012bd6974aSJonathan Coe   verifyFormat("int Value { set; }", Style);
6022bd6974aSJonathan Coe   verifyFormat("int Value { internal set; }", Style);
6032bd6974aSJonathan Coe   verifyFormat("int Value { set; } = 0", Style);
6042bd6974aSJonathan Coe   verifyFormat("int Value { get; set }", Style);
6052bd6974aSJonathan Coe   verifyFormat("int Value { set; get }", Style);
6062bd6974aSJonathan Coe   verifyFormat("int Value { get; private set; }", Style);
6072bd6974aSJonathan Coe   verifyFormat("int Value { get; set; }", Style);
6082bd6974aSJonathan Coe   verifyFormat("int Value { get; set; } = 0", Style);
6092bd6974aSJonathan Coe   verifyFormat("int Value { internal get; internal set; }", Style);
6102bd6974aSJonathan Coe 
6112bd6974aSJonathan Coe   // Do not wrap expression body definitions.
6122bd6974aSJonathan Coe   verifyFormat(R"(//
6132bd6974aSJonathan Coe public string Name {
6142bd6974aSJonathan Coe   get => _name;
6152bd6974aSJonathan Coe   set => _name = value;
6162bd6974aSJonathan Coe })",
6172bd6974aSJonathan Coe                Style);
618e8c5fea2SJonathan Coe }
619e8c5fea2SJonathan Coe 
620e8c5fea2SJonathan Coe TEST_F(FormatTestCSharp, CSharpSpaces) {
621e8c5fea2SJonathan Coe   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
622e8c5fea2SJonathan Coe   Style.SpaceBeforeSquareBrackets = false;
623e8c5fea2SJonathan Coe   Style.SpacesInSquareBrackets = false;
624e8c5fea2SJonathan Coe   Style.SpaceBeforeCpp11BracedList = true;
625e8c5fea2SJonathan Coe   Style.Cpp11BracedListStyle = false;
626e8c5fea2SJonathan Coe   Style.SpacesInContainerLiterals = false;
627*07c1978bSJonathan Coe   Style.SpaceAfterCStyleCast = false;
628e8c5fea2SJonathan Coe 
629e8c5fea2SJonathan Coe   verifyFormat(R"(new Car { "Door", 0.1 })", Style);
630e8c5fea2SJonathan Coe   verifyFormat(R"(new Car { 0.1, "Door" })", Style);
631e8c5fea2SJonathan Coe   verifyFormat(R"(new string[] { "A" })", Style);
632e8c5fea2SJonathan Coe   verifyFormat(R"(new string[] {})", Style);
633e8c5fea2SJonathan Coe   verifyFormat(R"(new Car { someVariableName })", Style);
634e8c5fea2SJonathan Coe   verifyFormat(R"(new Car { someVariableName })", Style);
635e8c5fea2SJonathan Coe   verifyFormat(R"(new Dictionary<string, string> { ["Key"] = "Value" };)",
636e8c5fea2SJonathan Coe                Style);
637e8c5fea2SJonathan Coe   verifyFormat(R"(Apply(x => x.Name, x => () => x.ID);)", Style);
638e8c5fea2SJonathan Coe   verifyFormat(R"(bool[] xs = { true, true };)", Style);
639e8c5fea2SJonathan Coe   verifyFormat(R"(taskContext.Factory.Run(async () => doThing(args);)", Style);
640e8c5fea2SJonathan Coe   verifyFormat(R"(catch (TestException) when (innerFinallyExecuted))", Style);
641548e540dSJonathan Coe   verifyFormat(R"(private float[,] Values;)", Style);
6425c917bd9SJonathan Coe   verifyFormat(R"(Result this[Index x] => Foo(x);)", Style);
643548e540dSJonathan Coe 
64404336adaSJonathan Coe   verifyFormat(R"(char[,,] rawCharArray = MakeCharacterGrid();)", Style);
64504336adaSJonathan Coe 
646*07c1978bSJonathan Coe   // Not seen as a C-style cast.
647*07c1978bSJonathan Coe   verifyFormat(R"(//
648*07c1978bSJonathan Coe foreach ((A a, B b) in someList) {
649*07c1978bSJonathan Coe })",
650*07c1978bSJonathan Coe                Style);
651*07c1978bSJonathan Coe 
652548e540dSJonathan Coe   Style.SpacesInSquareBrackets = true;
653548e540dSJonathan Coe   verifyFormat(R"(private float[ , ] Values;)", Style);
6549c4afce7SJonathan Coe   verifyFormat(R"(string dirPath = args?[ 0 ];)", Style);
65504336adaSJonathan Coe   verifyFormat(R"(char[ ,, ] rawCharArray = MakeCharacterGrid();)", Style);
6565f52a93bSJonathan Coe }
6575f52a93bSJonathan Coe 
6585f52a93bSJonathan Coe TEST_F(FormatTestCSharp, CSharpNullableTypes) {
6595f52a93bSJonathan Coe   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
6605f52a93bSJonathan Coe   Style.SpacesInSquareBrackets = false;
6615f52a93bSJonathan Coe 
662fe61bc1aSJonathan Coe   verifyFormat(R"(//
663fe61bc1aSJonathan Coe public class A {
664fe61bc1aSJonathan Coe   void foo() { int? value = some.bar(); }
665fe61bc1aSJonathan Coe })",
666fe61bc1aSJonathan Coe                Style); // int? is nullable not a conditional expression.
667fe61bc1aSJonathan Coe 
668fe61bc1aSJonathan Coe   verifyFormat(R"(void foo(int? x, int? y, int? z) {})",
669fe61bc1aSJonathan Coe                Style); // Nullables in function definitions.
670fe61bc1aSJonathan Coe 
6715f52a93bSJonathan Coe   verifyFormat(R"(public float? Value;)", Style); // no space before `?`.
672fe61bc1aSJonathan Coe 
6735f52a93bSJonathan Coe   verifyFormat(R"(int?[] arr = new int?[10];)",
6745f52a93bSJonathan Coe                Style); // An array of a nullable type.
6751fb9c298SJonathan Coe 
6761fb9c298SJonathan Coe   verifyFormat(R"(var x = (int?)y;)", Style); // Cast to a nullable type.
6771fb9c298SJonathan Coe 
6781fb9c298SJonathan Coe   verifyFormat(R"(var x = new MyContainer<int?>();)", Style); // Generics.
6792bd6974aSJonathan Coe }
6802bd6974aSJonathan Coe 
681736fef97SJonathan Coe TEST_F(FormatTestCSharp, CSharpArraySubscripts) {
682736fef97SJonathan Coe   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
683736fef97SJonathan Coe 
684736fef97SJonathan Coe   // Do not format array subscript operators as attributes.
685b28ed9ceSJonathan Coe   verifyFormat(R"(//
686b28ed9ceSJonathan Coe if (someThings[index].Contains(myThing)) {
687b28ed9ceSJonathan Coe })",
688b28ed9ceSJonathan Coe                Style);
689b28ed9ceSJonathan Coe 
690b28ed9ceSJonathan Coe   verifyFormat(R"(//
691b28ed9ceSJonathan Coe if (someThings[i][j][k].Contains(myThing)) {
692b28ed9ceSJonathan Coe })",
693b28ed9ceSJonathan Coe                Style);
694736fef97SJonathan Coe }
695736fef97SJonathan Coe 
696dcbcec48SJonathan Coe TEST_F(FormatTestCSharp, CSharpGenericTypeConstraints) {
697dcbcec48SJonathan Coe   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
698dcbcec48SJonathan Coe 
699dcbcec48SJonathan Coe   verifyFormat(R"(//
700dcbcec48SJonathan Coe class ItemFactory<T>
701dcbcec48SJonathan Coe     where T : new() {})", Style);
702dcbcec48SJonathan Coe 
703dcbcec48SJonathan Coe   verifyFormat(R"(//
704dcbcec48SJonathan Coe class Dictionary<TKey, TVal>
705dcbcec48SJonathan Coe     where TKey : IComparable<TKey>
706dcbcec48SJonathan Coe     where TVal : IMyInterface {
707dcbcec48SJonathan Coe   public void MyMethod<T>(T t)
708dcbcec48SJonathan Coe       where T : IMyInterface { doThing(); }
709dcbcec48SJonathan Coe })",
710dcbcec48SJonathan Coe                Style);
71178e2a3c6SJonathan Coe 
71278e2a3c6SJonathan Coe   verifyFormat(R"(//
71378e2a3c6SJonathan Coe class ItemFactory<T>
71478e2a3c6SJonathan Coe     where T : new(),
71578e2a3c6SJonathan Coe               IAnInterface<T>,
71678e2a3c6SJonathan Coe               IAnotherInterface<T>,
71778e2a3c6SJonathan Coe               IAnotherInterfaceStill<T> {})",
718d1b412aeSJonathan Coe                Style);
719d1b412aeSJonathan Coe 
720d1b412aeSJonathan Coe   Style.ColumnLimit = 50; // Force lines to be wrapped.
721d1b412aeSJonathan Coe   verifyFormat(R"(//
722d1b412aeSJonathan Coe class ItemFactory<T, U>
723d1b412aeSJonathan Coe     where T : new(),
724d1b412aeSJonathan Coe               IAnInterface<T>,
725d1b412aeSJonathan Coe               IAnotherInterface<T, U>,
726d1b412aeSJonathan Coe               IAnotherInterfaceStill<T, U> {})",
72778e2a3c6SJonathan Coe                Style);
7280574030cSKrasimir Georgiev 
7290574030cSKrasimir Georgiev   // In other languages `where` can be used as a normal identifier.
7300574030cSKrasimir Georgiev   // This example is in C++!
7310574030cSKrasimir Georgiev   verifyFormat(R"(//
7320574030cSKrasimir Georgiev class A {
7330574030cSKrasimir Georgiev   int f(int where) {}
7340574030cSKrasimir Georgiev };)",
7350574030cSKrasimir Georgiev                getGoogleStyle(FormatStyle::LK_Cpp));
736dcbcec48SJonathan Coe }
737dcbcec48SJonathan Coe 
738cbb726d0SPaul Hoad } // namespace format
739cbb726d0SPaul Hoad } // end namespace clang
740