FormatTestCSharp.cpp 11 KB

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