[gn build] Port 0e80f9a1b51e
[llvm-project.git] / clang / unittests / Format / DefinitionBlockSeparatorTest.cpp
blobb26b9f4f4ff62b8765684b952e15fa9a94891d0f
1 //===- DefinitionBlockSeparatorTest.cpp - Formatting unit tests -----------===//
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 //===----------------------------------------------------------------------===//
9 #include "FormatTestUtils.h"
10 #include "clang/Format/Format.h"
12 #include "llvm/Support/Debug.h"
13 #include "gtest/gtest.h"
15 #define DEBUG_TYPE "definition-block-separator-test"
17 namespace clang {
18 namespace format {
19 namespace {
21 class DefinitionBlockSeparatorTest : public testing::Test {
22 protected:
23 static std::string
24 separateDefinitionBlocks(StringRef Code,
25 const std::vector<tooling::Range> &Ranges,
26 const FormatStyle &Style = getLLVMStyle()) {
27 LLVM_DEBUG(llvm::errs() << "---\n");
28 LLVM_DEBUG(llvm::errs() << Code << "\n\n");
29 tooling::Replacements Replaces = reformat(Style, Code, Ranges, "<stdin>");
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;
36 static std::string
37 separateDefinitionBlocks(StringRef Code,
38 const FormatStyle &Style = getLLVMStyle()) {
39 return separateDefinitionBlocks(
40 Code,
41 /*Ranges=*/{1, tooling::Range(0, Code.size())}, Style);
44 static void _verifyFormat(const char *File, int Line, StringRef Code,
45 const FormatStyle &Style = getLLVMStyle(),
46 StringRef ExpectedCode = "", bool Inverse = true) {
47 testing::ScopedTrace t(File, Line, testing::Message() << Code.str());
48 bool HasOriginalCode = true;
49 if (ExpectedCode == "") {
50 ExpectedCode = Code;
51 HasOriginalCode = false;
54 EXPECT_EQ(ExpectedCode, separateDefinitionBlocks(ExpectedCode, Style))
55 << "Expected code is not stable";
56 if (Inverse) {
57 FormatStyle InverseStyle = Style;
58 if (Style.SeparateDefinitionBlocks == FormatStyle::SDS_Always)
59 InverseStyle.SeparateDefinitionBlocks = FormatStyle::SDS_Never;
60 else
61 InverseStyle.SeparateDefinitionBlocks = FormatStyle::SDS_Always;
62 EXPECT_NE(ExpectedCode,
63 separateDefinitionBlocks(ExpectedCode, InverseStyle))
64 << "Inverse formatting makes no difference";
66 std::string CodeToFormat =
67 HasOriginalCode ? Code.str() : removeEmptyLines(Code);
68 std::string Result = separateDefinitionBlocks(CodeToFormat, Style);
69 EXPECT_EQ(ExpectedCode, Result) << "Test failed. Formatted:\n" << Result;
72 static std::string removeEmptyLines(StringRef Code) {
73 std::string Result = "";
74 for (auto Char : Code.str()) {
75 if (Result.size()) {
76 auto LastChar = Result.back();
77 if ((Char == '\n' && LastChar == '\n') ||
78 (Char == '\r' && (LastChar == '\r' || LastChar == '\n'))) {
79 continue;
82 Result.push_back(Char);
84 return Result;
88 #define verifyFormat(...) _verifyFormat(__FILE__, __LINE__, __VA_ARGS__)
90 TEST_F(DefinitionBlockSeparatorTest, Basic) {
91 FormatStyle Style = getLLVMStyle();
92 Style.SeparateDefinitionBlocks = FormatStyle::SDS_Always;
93 verifyFormat("int foo(int i, int j) {\n"
94 " int r = i + j;\n"
95 " return r;\n"
96 "}\n"
97 "\n"
98 "int bar(int j, int k) {\n"
99 " int r = j + k;\n"
100 " return r;\n"
101 "}",
102 Style);
104 verifyFormat("struct foo {\n"
105 " int i, j;\n"
106 "};\n"
107 "\n"
108 "struct bar {\n"
109 " int j, k;\n"
110 "};",
111 Style);
113 verifyFormat("union foo {\n"
114 " int i, j;\n"
115 "};\n"
116 "\n"
117 "union bar {\n"
118 " int j, k;\n"
119 "};",
120 Style);
122 verifyFormat("class foo {\n"
123 " int i, j;\n"
124 "};\n"
125 "\n"
126 "class bar {\n"
127 " int j, k;\n"
128 "};",
129 Style);
131 verifyFormat("namespace foo {\n"
132 "int i, j;\n"
133 "}\n"
134 "\n"
135 "namespace bar {\n"
136 "int j, k;\n"
137 "}",
138 Style);
140 verifyFormat("enum Foo { FOO, BAR };\n"
141 "\n"
142 "enum Bar { FOOBAR, BARFOO };",
143 Style);
145 FormatStyle BreakAfterReturnTypeStyle = Style;
146 BreakAfterReturnTypeStyle.BreakAfterReturnType = FormatStyle::RTBS_All;
147 // Test uppercased long typename
148 verifyFormat("class Foo {\n"
149 " void\n"
150 " Bar(int t, int p) {\n"
151 " int r = t + p;\n"
152 " return r;\n"
153 " }\n"
154 "\n"
155 " HRESULT\n"
156 " Foobar(int t, int p) {\n"
157 " int r = t * p;\n"
158 " return r;\n"
159 " }\n"
160 "}",
161 BreakAfterReturnTypeStyle);
164 TEST_F(DefinitionBlockSeparatorTest, FormatConflict) {
165 FormatStyle Style = getLLVMStyle();
166 Style.SeparateDefinitionBlocks = FormatStyle::SDS_Always;
167 StringRef Code = "class Test {\n"
168 "public:\n"
169 " static void foo() {\n"
170 " int t;\n"
171 " return 1;\n"
172 " }\n"
173 "};";
174 std::vector<tooling::Range> Ranges = {1, tooling::Range(0, Code.size())};
175 EXPECT_EQ(reformat(Style, Code, Ranges, "<stdin>").size(), 0u);
178 TEST_F(DefinitionBlockSeparatorTest, CommentBlock) {
179 FormatStyle Style = getLLVMStyle();
180 Style.SeparateDefinitionBlocks = FormatStyle::SDS_Always;
181 std::string Prefix = "enum Foo { FOO, BAR };\n"
182 "\n"
183 "/*\n"
184 "test1\n"
185 "test2\n"
186 "*/\n"
187 "int foo(int i, int j) {\n"
188 " int r = i + j;\n"
189 " return r;\n"
190 "}\n";
191 std::string Suffix = "enum Bar { FOOBAR, BARFOO };\n"
192 "\n"
193 "/* Comment block in one line*/\n"
194 "int bar3(int j, int k) {\n"
195 " // A comment\n"
196 " int r = j % k;\n"
197 " return r;\n"
198 "}\n";
199 std::string CommentedCode = "/*\n"
200 "int bar2(int j, int k) {\n"
201 " int r = j / k;\n"
202 " return r;\n"
203 "}\n"
204 "*/\n";
205 verifyFormat(removeEmptyLines(Prefix) + "\n" + CommentedCode + "\n" +
206 removeEmptyLines(Suffix),
207 Style, Prefix + "\n" + CommentedCode + "\n" + Suffix);
208 verifyFormat(removeEmptyLines(Prefix) + "\n" + CommentedCode +
209 removeEmptyLines(Suffix),
210 Style, Prefix + "\n" + CommentedCode + Suffix);
213 TEST_F(DefinitionBlockSeparatorTest, UntouchBlockStartStyle) {
214 // Returns a std::pair of two strings, with the first one for passing into
215 // Always test and the second one be the expected result of the first string.
216 auto MakeUntouchTest = [&](std::string BlockHeader, std::string BlockChanger,
217 std::string BlockFooter, bool BlockEndNewLine) {
218 std::string CodePart1 = "enum Foo { FOO, BAR };\n"
219 "\n"
220 "/*\n"
221 "test1\n"
222 "test2\n"
223 "*/\n"
224 "int foo(int i, int j) {\n"
225 " int r = i + j;\n"
226 " return r;\n"
227 "}\n";
228 std::string CodePart2 = "/* Comment block in one line*/\n"
229 "enum Bar { FOOBAR, BARFOO };\n"
230 "\n"
231 "int bar3(int j, int k) {\n"
232 " // A comment\n"
233 " int r = j % k;\n"
234 " return r;\n"
235 "}\n";
236 std::string CodePart3 = "int bar2(int j, int k) {\n"
237 " int r = j / k;\n"
238 " return r;\n"
239 "}\n";
240 std::string ConcatAll = BlockHeader + CodePart1 + BlockChanger + CodePart2 +
241 BlockFooter + (BlockEndNewLine ? "\n" : "") +
242 CodePart3;
243 return std::make_pair(BlockHeader + removeEmptyLines(CodePart1) +
244 BlockChanger + removeEmptyLines(CodePart2) +
245 BlockFooter + removeEmptyLines(CodePart3),
246 ConcatAll);
249 FormatStyle AlwaysStyle = getLLVMStyle();
250 AlwaysStyle.SeparateDefinitionBlocks = FormatStyle::SDS_Always;
252 FormatStyle NeverStyle = getLLVMStyle();
253 NeverStyle.SeparateDefinitionBlocks = FormatStyle::SDS_Never;
255 auto TestKit = MakeUntouchTest("/* FOOBAR */\n"
256 "#ifdef FOO\n\n",
257 "\n#elifndef BAR\n\n", "\n#endif\n\n", false);
258 verifyFormat(TestKit.first, AlwaysStyle, TestKit.second);
259 verifyFormat(TestKit.second, NeverStyle, removeEmptyLines(TestKit.second));
261 TestKit = MakeUntouchTest("/* FOOBAR */\n"
262 "#ifdef FOO\n",
263 "#elifndef BAR\n", "#endif\n", false);
264 verifyFormat(TestKit.first, AlwaysStyle, TestKit.second);
265 verifyFormat(TestKit.second, NeverStyle, removeEmptyLines(TestKit.second));
267 TestKit = MakeUntouchTest("namespace Ns {\n\n",
268 "\n} // namespace Ns\n\n"
269 "namespace {\n\n",
270 "\n} // namespace\n", true);
271 verifyFormat(TestKit.first, AlwaysStyle, TestKit.second);
272 verifyFormat(TestKit.second, NeverStyle, removeEmptyLines(TestKit.second));
274 TestKit = MakeUntouchTest("namespace Ns {\n",
275 "} // namespace Ns\n\n"
276 "namespace {\n",
277 "} // namespace\n", true);
278 verifyFormat(TestKit.first, AlwaysStyle, TestKit.second);
279 verifyFormat(TestKit.second, NeverStyle, removeEmptyLines(TestKit.second));
282 TEST_F(DefinitionBlockSeparatorTest, Always) {
283 FormatStyle Style = getLLVMStyle();
284 Style.SeparateDefinitionBlocks = FormatStyle::SDS_Always;
286 verifyFormat("// clang-format off\n"
287 "template<class T>\n"
288 "concept C = not A<S<T>>;\n"
289 "// clang-format on\n"
290 "\n"
291 "struct E {};",
292 Style);
294 std::string Prefix = "namespace {\n";
295 std::string Infix = "\n"
296 "// Enum test1\n"
297 "// Enum test2\n"
298 "enum Foo { FOO, BAR };\n"
299 "\n"
300 "/*\n"
301 "test1\n"
302 "test2\n"
303 "*/\n"
304 "/*const*/ int foo(int i, int j) {\n"
305 " int r = i + j;\n"
306 " return r;\n"
307 "}\n"
308 "\n"
309 "// Foobar\n"
310 "int i, j, k;\n"
311 "\n"
312 "// Comment for function\n"
313 "// Comment line 2\n"
314 "// Comment line 3\n"
315 "int bar(int j, int k) {\n"
316 " {\n"
317 " int r = j * k;\n"
318 " return r;\n"
319 " }\n"
320 "}\n"
321 "\n"
322 "int bar2(int j, int k) {\n"
323 " int r = j / k;\n"
324 " return r;\n"
325 "}\n"
326 "\n"
327 "/* Comment block in one line*/\n"
328 "enum Bar { FOOBAR, BARFOO };\n"
329 "\n"
330 "int bar3(int j, int k, const enum Bar b) {\n"
331 " // A comment\n"
332 " int r = j % k;\n"
333 " if (struct S = getS()) {\n"
334 " // if condition\n"
335 " }\n"
336 " return r;\n"
337 "}\n";
338 std::string Postfix = "\n"
339 "} // namespace\n"
340 "\n"
341 "namespace T {\n"
342 "int i, j, k;\n"
343 "} // namespace T";
344 verifyFormat(Prefix + removeEmptyLines(Infix) + removeEmptyLines(Postfix),
345 Style, Prefix + Infix + Postfix);
348 TEST_F(DefinitionBlockSeparatorTest, Never) {
349 FormatStyle Style = getLLVMStyle();
350 Style.SeparateDefinitionBlocks = FormatStyle::SDS_Never;
351 std::string Prefix = "namespace {\n";
352 std::string Postfix = "// Enum test1\n"
353 "// Enum test2\n"
354 "enum Foo { FOO, BAR };\n"
355 "\n"
356 "/*\n"
357 "test1\n"
358 "test2\n"
359 "*/\n"
360 "/*const*/ int foo(int i, int j) {\n"
361 " int r = i + j;\n"
362 " return r;\n"
363 "}\n"
364 "\n"
365 "// Foobar\n"
366 "int i, j, k;\n"
367 "\n"
368 "// Comment for function\n"
369 "// Comment line 2\n"
370 "// Comment line 3\n"
371 "int bar(int j, int k) {\n"
372 " {\n"
373 " int r = j * k;\n"
374 " return r;\n"
375 " }\n"
376 "}\n"
377 "\n"
378 "int bar2(int j, int k) {\n"
379 " int r = j / k;\n"
380 " return r;\n"
381 "}\n"
382 "\n"
383 "/* Comment block in one line*/\n"
384 "enum Bar { FOOBAR, BARFOO };\n"
385 "\n"
386 "int bar3(int j, int k, const enum Bar b) {\n"
387 " // A comment\n"
388 " int r = j % k;\n"
389 " if (struct S = getS()) {\n"
390 " // if condition\n"
391 " }\n"
392 " return r;\n"
393 "}\n"
394 "} // namespace";
395 verifyFormat(Prefix + "\n\n\n" + Postfix, Style,
396 Prefix + removeEmptyLines(Postfix));
399 TEST_F(DefinitionBlockSeparatorTest, OpeningBracketOwnsLine) {
400 FormatStyle Style = getLLVMStyle();
401 Style.BreakBeforeBraces = FormatStyle::BS_Allman;
402 Style.SeparateDefinitionBlocks = FormatStyle::SDS_Always;
403 verifyFormat("namespace NS\n"
404 "{\n"
405 "// Enum test1\n"
406 "// Enum test2\n"
407 "enum Foo\n"
408 "{\n"
409 " FOO,\n"
410 " BAR\n"
411 "};\n"
412 "\n"
413 "/*\n"
414 "test1\n"
415 "test2\n"
416 "*/\n"
417 "/*const*/ int foo(int i, int j)\n"
418 "{\n"
419 " int r = i + j;\n"
420 " return r;\n"
421 "}\n"
422 "\n"
423 "// Foobar\n"
424 "int i, j, k;\n"
425 "\n"
426 "// Comment for function\n"
427 "// Comment line 2\n"
428 "// Comment line 3\n"
429 "int bar(int j, int k)\n"
430 "{\n"
431 " {\n"
432 " int r = j * k;\n"
433 " return r;\n"
434 " }\n"
435 "}\n"
436 "\n"
437 "int bar2(int j, int k)\n"
438 "{\n"
439 " int r = j / k;\n"
440 " return r;\n"
441 "}\n"
442 "\n"
443 "enum Bar\n"
444 "{\n"
445 " FOOBAR,\n"
446 " BARFOO\n"
447 "};\n"
448 "\n"
449 "int bar3(int j, int k, const enum Bar b)\n"
450 "{\n"
451 " // A comment\n"
452 " int r = j % k;\n"
453 " if (struct S = getS())\n"
454 " {\n"
455 " // if condition\n"
456 " }\n"
457 " return r;\n"
458 "}\n"
459 "} // namespace NS",
460 Style);
463 TEST_F(DefinitionBlockSeparatorTest, TryBlocks) {
464 FormatStyle Style = getLLVMStyle();
465 Style.BreakBeforeBraces = FormatStyle::BS_Allman;
466 Style.SeparateDefinitionBlocks = FormatStyle::SDS_Always;
467 verifyFormat("void FunctionWithInternalTry()\n"
468 "{\n"
469 " try\n"
470 " {\n"
471 " return;\n"
472 " }\n"
473 " catch (const std::exception &)\n"
474 " {\n"
475 " }\n"
476 "}",
477 Style, "", /*Inverse=*/false);
478 verifyFormat("void FunctionWithTryBlock()\n"
479 "try\n"
480 "{\n"
481 " return;\n"
482 "}\n"
483 "catch (const std::exception &)\n"
484 "{\n"
485 "}",
486 Style, "", /*Inverse=*/false);
489 TEST_F(DefinitionBlockSeparatorTest, Leave) {
490 FormatStyle Style = getLLVMStyle();
491 Style.SeparateDefinitionBlocks = FormatStyle::SDS_Leave;
492 Style.MaxEmptyLinesToKeep = 3;
493 std::string LeaveAs = "namespace {\n"
494 "\n"
495 "// Enum test1\n"
496 "// Enum test2\n"
497 "enum Foo { FOO, BAR };\n"
498 "\n\n\n"
499 "/*\n"
500 "test1\n"
501 "test2\n"
502 "*/\n"
503 "/*const*/ int foo(int i, int j) {\n"
504 " int r = i + j;\n"
505 " return r;\n"
506 "}\n"
507 "\n"
508 "// Foobar\n"
509 "int i, j, k;\n"
510 "\n"
511 "// Comment for function\n"
512 "// Comment line 2\n"
513 "// Comment line 3\n"
514 "int bar(int j, int k) {\n"
515 " {\n"
516 " int r = j * k;\n"
517 " return r;\n"
518 " }\n"
519 "}\n"
520 "\n"
521 "int bar2(int j, int k) {\n"
522 " int r = j / k;\n"
523 " return r;\n"
524 "}\n"
525 "\n"
526 "// Comment for inline enum\n"
527 "enum Bar { FOOBAR, BARFOO };\n"
528 "int bar3(int j, int k, const enum Bar b) {\n"
529 " // A comment\n"
530 " int r = j % k;\n"
531 " if (struct S = getS()) {\n"
532 " // if condition\n"
533 " }\n"
534 " return r;\n"
535 "}\n"
536 "} // namespace";
537 verifyFormat(LeaveAs, Style, LeaveAs);
540 TEST_F(DefinitionBlockSeparatorTest, CSharp) {
541 FormatStyle Style = getLLVMStyle(FormatStyle::LK_CSharp);
542 Style.SeparateDefinitionBlocks = FormatStyle::SDS_Always;
543 Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None;
544 Style.AllowShortEnumsOnASingleLine = false;
545 verifyFormat("namespace {\r\n"
546 "public class SomeTinyClass {\r\n"
547 " int X;\r\n"
548 "}\r\n"
549 "\r\n"
550 "public class AnotherTinyClass {\r\n"
551 " int Y;\r\n"
552 "}\r\n"
553 "\r\n"
554 "internal static String toString() {\r\n"
555 "}\r\n"
556 "\r\n"
557 "// Comment for enum\r\n"
558 "public enum var {\r\n"
559 " none,\r\n"
560 " @string,\r\n"
561 " bool,\r\n"
562 " @enum\r\n"
563 "}\r\n"
564 "\r\n"
565 "// Test\r\n"
566 "[STAThread]\r\n"
567 "static void Main(string[] args) {\r\n"
568 " Console.WriteLine(\"HelloWorld\");\r\n"
569 "}\r\n"
570 "\r\n"
571 "static decimal Test() {\r\n"
572 "}\r\n"
573 "}\r\n"
574 "\r\n"
575 "public class FoobarClass {\r\n"
576 " int foobar;\r\n"
577 "}",
578 Style);
581 TEST_F(DefinitionBlockSeparatorTest, JavaScript) {
582 FormatStyle Style = getLLVMStyle(FormatStyle::LK_JavaScript);
583 Style.SeparateDefinitionBlocks = FormatStyle::SDS_Always;
584 Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None;
585 Style.AllowShortEnumsOnASingleLine = false;
586 verifyFormat("export const enum Foo {\n"
587 " A = 1,\n"
588 " B\n"
589 "}\n"
590 "\n"
591 "export function A() {\n"
592 "}\n"
593 "\n"
594 "export default function B() {\n"
595 "}\n"
596 "\n"
597 "export function C() {\n"
598 "}\n"
599 "\n"
600 "var t, p, q;\n"
601 "\n"
602 "export abstract class X {\n"
603 " y: number;\n"
604 "}\n"
605 "\n"
606 "export const enum Bar {\n"
607 " D = 1,\n"
608 " E\n"
609 "}",
610 Style);
612 } // namespace
613 } // namespace format
614 } // namespace clang