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: 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 34 format(llvm::StringRef Code, 35 const FormatStyle &Style = getMicrosoftStyle(FormatStyle::LK_CSharp)) { 36 return format(Code, 0, Code.size(), Style); 37 } 38 39 static FormatStyle getStyleWithColumns(unsigned ColumnLimit) { 40 FormatStyle Style = getMicrosoftStyle(FormatStyle::LK_CSharp); 41 Style.ColumnLimit = ColumnLimit; 42 return Style; 43 } 44 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 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 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 107 TEST_F(FormatTestCSharp, NoStringLiteralBreaks) { 108 verifyFormat("foo(" 109 "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 110 "aaaaaa\");"); 111 } 112 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 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 144 TEST_F(FormatTestCSharp, CSharpFatArrows) { 145 verifyFormat("Task serverTask = Task.Run(async() => {"); 146 verifyFormat("public override string ToString() => \"{Name}\\{Age}\";"); 147 } 148 149 TEST_F(FormatTestCSharp, CSharpNullConditional) { 150 verifyFormat( 151 "public Person(string firstName, string lastName, int? age=null)"); 152 153 verifyFormat("switch(args?.Length)"); 154 155 verifyFormat("public static void Main(string[] args)\n" 156 "{\n" 157 " string dirPath = args?[0];\n" 158 "}"); 159 } 160 161 TEST_F(FormatTestCSharp, Attributes) { 162 verifyFormat("[STAThread]\n" 163 "static void Main(string[] args)\n" 164 "{\n" 165 "}"); 166 167 verifyFormat("[TestMethod]\n" 168 "private class Test\n" 169 "{\n" 170 "}"); 171 172 verifyFormat("[TestMethod]\n" 173 "protected class Test\n" 174 "{\n" 175 "}"); 176 177 verifyFormat("[TestMethod]\n" 178 "internal class Test\n" 179 "{\n" 180 "}"); 181 182 verifyFormat("[TestMethod]\n" 183 "class Test\n" 184 "{\n" 185 "}"); 186 187 verifyFormat("[TestMethod]\n" 188 "[DeploymentItem(\"Test.txt\")]\n" 189 "public class Test\n" 190 "{\n" 191 "}"); 192 193 verifyFormat("[System.AttributeUsage(System.AttributeTargets.Method)]\n" 194 "[System.Runtime.InteropServices.ComVisible(true)]\n" 195 "public sealed class STAThreadAttribute : Attribute\n" 196 "{\n" 197 "}"); 198 199 verifyFormat("[Verb(\"start\", HelpText = \"Starts the server listening on " 200 "provided port\")]\n" 201 "class Test\n" 202 "{\n" 203 "}"); 204 205 verifyFormat("[TestMethod]\n" 206 "public string Host\n" 207 "{\n" 208 " set;\n" 209 " get;\n" 210 "}"); 211 212 verifyFormat("[TestMethod(\"start\", HelpText = \"Starts the server " 213 "listening on provided host\")]\n" 214 "public string Host\n" 215 "{\n" 216 " set;\n" 217 " get;\n" 218 "}"); 219 } 220 221 TEST_F(FormatTestCSharp, CSharpUsing) { 222 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); 223 Style.SpaceBeforeParens = FormatStyle::SBPO_Always; 224 verifyFormat("public void foo() {\n" 225 " using (StreamWriter sw = new StreamWriter (filenameA)) {}\n" 226 "}", 227 Style); 228 229 Style.SpaceBeforeParens = FormatStyle::SBPO_Never; 230 verifyFormat("public void foo() {\n" 231 " using(StreamWriter sw = new StreamWriter(filenameB)) {}\n" 232 "}", 233 Style); 234 } 235 236 TEST_F(FormatTestCSharp, CSharpRegions) { 237 verifyFormat("#region aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaa " 238 "aaaaaaaaaaaaaaa long region"); 239 } 240 241 TEST_F(FormatTestCSharp, CSharpKeyWordEscaping) { 242 verifyFormat("public enum var { none, @string, bool, @enum }"); 243 } 244 245 TEST_F(FormatTestCSharp, CSharpNullCoalescing) { 246 verifyFormat("var test = ABC ?? DEF"); 247 verifyFormat("string myname = name ?? \"ABC\";"); 248 verifyFormat("return _name ?? \"DEF\";"); 249 } 250 251 TEST_F(FormatTestCSharp, AttributesIndentation) { 252 FormatStyle Style = getMicrosoftStyle(FormatStyle::LK_CSharp); 253 Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None; 254 255 verifyFormat("[STAThread]\n" 256 "static void Main(string[] args)\n" 257 "{\n" 258 "}", 259 Style); 260 261 verifyFormat("[STAThread]\n" 262 "void " 263 "veryLooooooooooooooongFunctionName(string[] args)\n" 264 "{\n" 265 "}", 266 Style); 267 268 verifyFormat("[STAThread]\n" 269 "veryLoooooooooooooooooooongReturnType " 270 "veryLooooooooooooooongFunctionName(string[] args)\n" 271 "{\n" 272 "}", 273 Style); 274 275 verifyFormat("[SuppressMessage(\"A\", \"B\", Justification = \"C\")]\n" 276 "public override X Y()\n" 277 "{\n" 278 "}\n", 279 Style); 280 281 verifyFormat("[SuppressMessage]\n" 282 "public X Y()\n" 283 "{\n" 284 "}\n", 285 Style); 286 287 verifyFormat("[SuppressMessage]\n" 288 "public override X Y()\n" 289 "{\n" 290 "}\n", 291 Style); 292 293 verifyFormat("public A(B b) : base(b)\n" 294 "{\n" 295 " [SuppressMessage]\n" 296 " public override X Y()\n" 297 " {\n" 298 " }\n" 299 "}\n", 300 Style); 301 } 302 303 } // namespace format 304 } // end namespace clang 305