1 //===- unittest/Format/FormatTestCSharp.cpp - Formatting tests for CSharp -===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "FormatTestUtils.h"
10 #include "clang/Format/Format.h"
11 #include "llvm/Support/Debug.h"
12 #include "gtest/gtest.h"
13 
14 #define DEBUG_TYPE "format-test"
15 
16 namespace clang {
17 namespace format {
18 
19 class FormatTestCSharp : public ::testing::Test {
20 protected:
format(llvm::StringRef Code,unsigned Offset,unsigned Length,const FormatStyle & Style)21   static std::string format(llvm::StringRef Code, unsigned Offset,
22                             unsigned Length, const FormatStyle &Style) {
23     LLVM_DEBUG(llvm::errs() << "---\n");
24     LLVM_DEBUG(llvm::errs() << Code << "\n\n");
25     std::vector<tooling::Range> Ranges(1, tooling::Range(Offset, Length));
26     tooling::Replacements Replaces = reformat(Style, Code, Ranges);
27     auto Result = applyAllReplacements(Code, Replaces);
28     EXPECT_TRUE(static_cast<bool>(Result));
29     LLVM_DEBUG(llvm::errs() << "\n" << *Result << "\n\n");
30     return *Result;
31   }
32 
33   static std::string
format(llvm::StringRef Code,const FormatStyle & Style=getMicrosoftStyle (FormatStyle::LK_CSharp))34   format(llvm::StringRef Code,
35          const FormatStyle &Style = getMicrosoftStyle(FormatStyle::LK_CSharp)) {
36     return format(Code, 0, Code.size(), Style);
37   }
38 
getStyleWithColumns(unsigned ColumnLimit)39   static FormatStyle getStyleWithColumns(unsigned ColumnLimit) {
40     FormatStyle Style = getMicrosoftStyle(FormatStyle::LK_CSharp);
41     Style.ColumnLimit = ColumnLimit;
42     return Style;
43   }
44 
verifyFormat(llvm::StringRef Code,const FormatStyle & Style=getMicrosoftStyle (FormatStyle::LK_CSharp))45   static void verifyFormat(
46       llvm::StringRef Code,
47       const FormatStyle &Style = getMicrosoftStyle(FormatStyle::LK_CSharp)) {
48     EXPECT_EQ(Code.str(), format(Code, Style)) << "Expected code is not stable";
49     EXPECT_EQ(Code.str(), format(test::messUp(Code), Style));
50   }
51 };
52 
TEST_F(FormatTestCSharp,CSharpClass)53 TEST_F(FormatTestCSharp, CSharpClass) {
54   verifyFormat("public class SomeClass\n"
55                "{\n"
56                "    void f()\n"
57                "    {\n"
58                "    }\n"
59                "    int g()\n"
60                "    {\n"
61                "        return 0;\n"
62                "    }\n"
63                "    void h()\n"
64                "    {\n"
65                "        while (true)\n"
66                "            f();\n"
67                "        for (;;)\n"
68                "            f();\n"
69                "        if (true)\n"
70                "            f();\n"
71                "    }\n"
72                "}");
73 }
74 
TEST_F(FormatTestCSharp,AccessModifiers)75 TEST_F(FormatTestCSharp, AccessModifiers) {
76   verifyFormat("public String toString()\n"
77                "{\n"
78                "}");
79   verifyFormat("private String toString()\n"
80                "{\n"
81                "}");
82   verifyFormat("protected String toString()\n"
83                "{\n"
84                "}");
85   verifyFormat("internal String toString()\n"
86                "{\n"
87                "}");
88 
89   verifyFormat("public override String toString()\n"
90                "{\n"
91                "}");
92   verifyFormat("private override String toString()\n"
93                "{\n"
94                "}");
95   verifyFormat("protected override String toString()\n"
96                "{\n"
97                "}");
98   verifyFormat("internal override String toString()\n"
99                "{\n"
100                "}");
101 
102   verifyFormat("internal static String toString()\n"
103                "{\n"
104                "}");
105 }
106 
TEST_F(FormatTestCSharp,NoStringLiteralBreaks)107 TEST_F(FormatTestCSharp, NoStringLiteralBreaks) {
108   verifyFormat("foo("
109                "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
110                "aaaaaa\");");
111 }
112 
TEST_F(FormatTestCSharp,CSharpVerbatiumStringLiterals)113 TEST_F(FormatTestCSharp, CSharpVerbatiumStringLiterals) {
114   verifyFormat("foo(@\"aaaaaaaa\\abc\\aaaa\");");
115   // @"ABC\" + ToString("B") - handle embedded \ in literal string at
116   // the end
117   //
118   /*
119    * After removal of Lexer change we are currently not able
120    * To handle these cases
121    verifyFormat("string s = @\"ABC\\\" + ToString(\"B\");");
122    verifyFormat("string s = @\"ABC\"\"DEF\"\"GHI\"");
123    verifyFormat("string s = @\"ABC\"\"DEF\"\"\"");
124    verifyFormat("string s = @\"ABC\"\"DEF\"\"\" + abc");
125   */
126 }
127 
TEST_F(FormatTestCSharp,CSharpInterpolatedStringLiterals)128 TEST_F(FormatTestCSharp, CSharpInterpolatedStringLiterals) {
129   verifyFormat("foo($\"aaaaaaaa{aaa}aaaa\");");
130   verifyFormat("foo($\"aaaa{A}\");");
131   verifyFormat(
132       "foo($\"aaaa{A}"
133       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\");");
134   verifyFormat("Name = $\"{firstName} {lastName}\";");
135 
136   // $"ABC\" + ToString("B") - handle embedded \ in literal string at
137   // the end
138   verifyFormat("string s = $\"A{abc}BC\" + ToString(\"B\");");
139   verifyFormat("$\"{domain}\\\\{user}\"");
140   verifyFormat(
141       "var verbatimInterpolated = $@\"C:\\Users\\{userName}\\Documents\\\";");
142 }
143 
TEST_F(FormatTestCSharp,CSharpFatArrows)144 TEST_F(FormatTestCSharp, CSharpFatArrows) {
145   verifyFormat("Task serverTask = Task.Run(async() => {");
146   verifyFormat("public override string ToString() => \"{Name}\\{Age}\";");
147 }
148 
TEST_F(FormatTestCSharp,CSharpNullConditional)149 TEST_F(FormatTestCSharp, CSharpNullConditional) {
150   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
151   Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
152 
153   verifyFormat(
154       "public Person(string firstName, string lastName, int? age=null)");
155 
156   verifyFormat("foo () {\n"
157                "  switch (args?.Length) {}\n"
158                "}",
159                Style);
160 
161   verifyFormat("switch (args?.Length) {}", Style);
162 
163   verifyFormat("public static void Main(string[] args)\n"
164                "{\n"
165                "    string dirPath = args?[0];\n"
166                "}");
167 
168   Style.SpaceBeforeParens = FormatStyle::SBPO_Never;
169 
170   verifyFormat("switch(args?.Length) {}", Style);
171 }
172 
TEST_F(FormatTestCSharp,Attributes)173 TEST_F(FormatTestCSharp, Attributes) {
174   verifyFormat("[STAThread]\n"
175                "static void Main(string[] args)\n"
176                "{\n"
177                "}");
178 
179   verifyFormat("[TestMethod]\n"
180                "private class Test\n"
181                "{\n"
182                "}");
183 
184   verifyFormat("[TestMethod]\n"
185                "protected class Test\n"
186                "{\n"
187                "}");
188 
189   verifyFormat("[TestMethod]\n"
190                "internal class Test\n"
191                "{\n"
192                "}");
193 
194   verifyFormat("[TestMethod]\n"
195                "class Test\n"
196                "{\n"
197                "}");
198 
199   verifyFormat("[TestMethod]\n"
200                "[DeploymentItem(\"Test.txt\")]\n"
201                "public class Test\n"
202                "{\n"
203                "}");
204 
205   verifyFormat("[System.AttributeUsage(System.AttributeTargets.Method)]\n"
206                "[System.Runtime.InteropServices.ComVisible(true)]\n"
207                "public sealed class STAThreadAttribute : Attribute\n"
208                "{\n"
209                "}");
210 
211   verifyFormat("[Verb(\"start\", HelpText = \"Starts the server listening on "
212                "provided port\")]\n"
213                "class Test\n"
214                "{\n"
215                "}");
216 
217   verifyFormat("[TestMethod]\n"
218                "public string Host\n"
219                "{\n"
220                "    set;\n"
221                "    get;\n"
222                "}");
223 
224   verifyFormat("[TestMethod(\"start\", HelpText = \"Starts the server "
225                "listening on provided host\")]\n"
226                "public string Host\n"
227                "{\n"
228                "    set;\n"
229                "    get;\n"
230                "}");
231 }
232 
TEST_F(FormatTestCSharp,CSharpUsing)233 TEST_F(FormatTestCSharp, CSharpUsing) {
234   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
235   Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
236   verifyFormat("public void foo () {\n"
237                "  using (StreamWriter sw = new StreamWriter (filenameA)) {}\n"
238                "}",
239                Style);
240 
241   verifyFormat("using (StreamWriter sw = new StreamWriter (filenameB)) {}",
242                Style);
243 
244   Style.SpaceBeforeParens = FormatStyle::SBPO_Never;
245   verifyFormat("public void foo() {\n"
246                "  using(StreamWriter sw = new StreamWriter(filenameB)) {}\n"
247                "}",
248                Style);
249 
250   verifyFormat("using(StreamWriter sw = new StreamWriter(filenameB)) {}",
251                Style);
252 }
253 
TEST_F(FormatTestCSharp,CSharpRegions)254 TEST_F(FormatTestCSharp, CSharpRegions) {
255   verifyFormat("#region aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaa "
256                "aaaaaaaaaaaaaaa long region");
257 }
258 
TEST_F(FormatTestCSharp,CSharpKeyWordEscaping)259 TEST_F(FormatTestCSharp, CSharpKeyWordEscaping) {
260   verifyFormat("public enum var { none, @string, bool, @enum }");
261 }
262 
TEST_F(FormatTestCSharp,CSharpNullCoalescing)263 TEST_F(FormatTestCSharp, CSharpNullCoalescing) {
264   verifyFormat("var test = ABC ?? DEF");
265   verifyFormat("string myname = name ?? \"ABC\";");
266   verifyFormat("return _name ?? \"DEF\";");
267 }
268 
TEST_F(FormatTestCSharp,AttributesIndentation)269 TEST_F(FormatTestCSharp, AttributesIndentation) {
270   FormatStyle Style = getMicrosoftStyle(FormatStyle::LK_CSharp);
271   Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None;
272 
273   verifyFormat("[STAThread]\n"
274                "static void Main(string[] args)\n"
275                "{\n"
276                "}",
277                Style);
278 
279   verifyFormat("[STAThread]\n"
280                "void "
281                "veryLooooooooooooooongFunctionName(string[] args)\n"
282                "{\n"
283                "}",
284                Style);
285 
286   verifyFormat("[STAThread]\n"
287                "veryLoooooooooooooooooooongReturnType "
288                "veryLooooooooooooooongFunctionName(string[] args)\n"
289                "{\n"
290                "}",
291                Style);
292 
293   verifyFormat("[SuppressMessage(\"A\", \"B\", Justification = \"C\")]\n"
294                "public override X Y()\n"
295                "{\n"
296                "}\n",
297                Style);
298 
299   verifyFormat("[SuppressMessage]\n"
300                "public X Y()\n"
301                "{\n"
302                "}\n",
303                Style);
304 
305   verifyFormat("[SuppressMessage]\n"
306                "public override X Y()\n"
307                "{\n"
308                "}\n",
309                Style);
310 
311   verifyFormat("public A(B b) : base(b)\n"
312                "{\n"
313                "    [SuppressMessage]\n"
314                "    public override X Y()\n"
315                "    {\n"
316                "    }\n"
317                "}\n",
318                Style);
319 
320   verifyFormat("public A : Base\n"
321                "{\n"
322                "}\n"
323                "[Test]\n"
324                "public Foo()\n"
325                "{\n"
326                "}\n",
327                Style);
328 
329   verifyFormat("namespace\n"
330                "{\n"
331                "public A : Base\n"
332                "{\n"
333                "}\n"
334                "[Test]\n"
335                "public Foo()\n"
336                "{\n"
337                "}\n"
338                "}\n",
339                Style);
340 }
341 
TEST_F(FormatTestCSharp,CSharpSpaceBefore)342 TEST_F(FormatTestCSharp, CSharpSpaceBefore) {
343   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
344   Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
345 
346   verifyFormat("List<string> list;", Style);
347   verifyFormat("Dictionary<string, string> dict;", Style);
348 
349   verifyFormat("for (int i = 0; i < size (); i++) {\n"
350                "}",
351                Style);
352   verifyFormat("foreach (var x in y) {\n"
353                "}",
354                Style);
355   verifyFormat("switch (x) {}", Style);
356   verifyFormat("do {\n"
357                "} while (x);",
358                Style);
359 
360   Style.SpaceBeforeParens = FormatStyle::SBPO_Never;
361 
362   verifyFormat("List<string> list;", Style);
363   verifyFormat("Dictionary<string, string> dict;", Style);
364 
365   verifyFormat("for(int i = 0; i < size(); i++) {\n"
366                "}",
367                Style);
368   verifyFormat("foreach(var x in y) {\n"
369                "}",
370                Style);
371   verifyFormat("switch(x) {}", Style);
372   verifyFormat("do {\n"
373                "} while(x);",
374                Style);
375 }
376 
377 } // namespace format
378 } // end namespace clang
379