brintos

brintos / llvm-project-archived public Read only

0
0
Text · 21.9 KiB · 1f4245b Raw
620 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "FormatTestUtils.h"10#include "clang/Format/Format.h"11 12#include "llvm/Support/Debug.h"13#include "gtest/gtest.h"14 15#define DEBUG_TYPE "definition-block-separator-test"16 17namespace clang {18namespace format {19namespace {20 21class DefinitionBlockSeparatorTest : public testing::Test {22protected:23  static std::string24  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;34  }35 36  static std::string37  separateDefinitionBlocks(StringRef Code,38                           const FormatStyle &Style = getLLVMStyle()) {39    return separateDefinitionBlocks(40        Code,41        /*Ranges=*/{1, tooling::Range(0, Code.size())}, Style);42  }43 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;52    }53 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      else61        InverseStyle.SeparateDefinitionBlocks = FormatStyle::SDS_Always;62      EXPECT_NE(ExpectedCode,63                separateDefinitionBlocks(ExpectedCode, InverseStyle))64          << "Inverse formatting makes no difference";65    }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;70  }71 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;80        }81      }82      Result.push_back(Char);83    }84    return Result;85  }86};87 88#define verifyFormat(...) _verifyFormat(__FILE__, __LINE__, __VA_ARGS__)89 90TEST_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);103 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);112 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);121 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);130 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);139 140  verifyFormat("enum Foo { FOO, BAR };\n"141               "\n"142               "enum Bar { FOOBAR, BARFOO };",143               Style);144 145  FormatStyle BreakAfterReturnTypeStyle = Style;146  BreakAfterReturnTypeStyle.BreakAfterReturnType = FormatStyle::RTBS_All;147  // Test uppercased long typename148  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);162}163 164TEST_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);176}177 178TEST_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);211}212 213TEST_F(DefinitionBlockSeparatorTest, UntouchBlockStartStyle) {214  // Returns a std::pair of two strings, with the first one for passing into215  // 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);247  };248 249  FormatStyle AlwaysStyle = getLLVMStyle();250  AlwaysStyle.SeparateDefinitionBlocks = FormatStyle::SDS_Always;251 252  FormatStyle NeverStyle = getLLVMStyle();253  NeverStyle.SeparateDefinitionBlocks = FormatStyle::SDS_Never;254 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));260 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));266 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));273 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));280}281 282TEST_F(DefinitionBlockSeparatorTest, Always) {283  FormatStyle Style = getLLVMStyle();284  Style.SeparateDefinitionBlocks = FormatStyle::SDS_Always;285 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);293 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);346}347 348TEST_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));397}398 399TEST_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);461}462 463TEST_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);487}488 489TEST_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);538}539 540TEST_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               "}\r\n"578               "\r\n"579               "public class LogFactory<TLogger>\r\n"580               "    where TLogger : class, new() {\r\n"581               "  int i;\r\n"582               "}",583               Style);584}585 586TEST_F(DefinitionBlockSeparatorTest, JavaScript) {587  FormatStyle Style = getLLVMStyle(FormatStyle::LK_JavaScript);588  Style.SeparateDefinitionBlocks = FormatStyle::SDS_Always;589  Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None;590  Style.AllowShortEnumsOnASingleLine = false;591  verifyFormat("export const enum Foo {\n"592               "  A = 1,\n"593               "  B\n"594               "}\n"595               "\n"596               "export function A() {\n"597               "}\n"598               "\n"599               "export default function B() {\n"600               "}\n"601               "\n"602               "export function C() {\n"603               "}\n"604               "\n"605               "var t, p, q;\n"606               "\n"607               "export abstract class X {\n"608               "  y: number;\n"609               "}\n"610               "\n"611               "export const enum Bar {\n"612               "  D = 1,\n"613               "  E\n"614               "}",615               Style);616}617} // namespace618} // namespace format619} // namespace clang620