502 lines · cpp
1//===- unittest/Format/FormatTestTableGen.cpp -----------------------------===//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#include "llvm/Support/Debug.h"12#include "gtest/gtest.h"13 14#define DEBUG_TYPE "format-test"15 16namespace clang {17namespace format {18 19class FormatTestTableGen : public testing::Test {20protected:21 static std::string format(StringRef Code, unsigned Offset, unsigned Length,22 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(StringRef Code) {34 FormatStyle Style = getGoogleStyle(FormatStyle::LK_TableGen);35 Style.ColumnLimit = 60; // To make writing tests easier.36 return format(Code, 0, Code.size(), Style);37 }38 39 static void verifyFormat(StringRef Code) {40 EXPECT_EQ(Code.str(), format(Code)) << "Expected code is not stable";41 EXPECT_EQ(Code.str(), format(test::messUp(Code)));42 }43 44 static void verifyFormat(StringRef Result, StringRef MessedUp) {45 EXPECT_EQ(Result, format(MessedUp));46 }47 48 static void verifyFormat(StringRef Code, const FormatStyle &Style) {49 EXPECT_EQ(Code.str(), format(Code, 0, Code.size(), Style))50 << "Expected code is not stable";51 auto MessUp = test::messUp(Code);52 EXPECT_EQ(Code.str(), format(MessUp, 0, MessUp.size(), Style));53 }54};55 56TEST_F(FormatTestTableGen, FormatStringBreak) {57 verifyFormat("include \"OptParser.td\"\n"58 "def flag : Flag<\"--foo\">,\n"59 " HelpText<\n"60 " \"This is a very, very, very, very, \"\n"61 " \"very, very, very, very, very, very, \"\n"62 " \"very long help string\">;");63}64 65TEST_F(FormatTestTableGen, NoSpacesInSquareBracketLists) {66 verifyFormat("def flag : Flag<[\"-\", \"--\"], \"foo\">;");67}68 69TEST_F(FormatTestTableGen, LiteralsAndIdentifiers) {70 verifyFormat("def LiteralAndIdentifiers {\n"71 " let someInteger = -42;\n"72 " let 0startID = $TokVarName;\n"73 " let 0xstartInteger = 0x42;\n"74 " let someIdentifier = $TokVarName;\n"75 "}");76}77 78TEST_F(FormatTestTableGen, BangOperators) {79 verifyFormat("def BangOperators {\n"80 " let IfOpe = !if(\n"81 " !not(!and(!gt(!add(1, 2), !sub(3, 4)), !isa<Ty>($x))),\n"82 " !foldl(0, !listconcat(!range(5, 6), !range(7, 8)),\n"83 " total, rec, !add(total, rec.Number)),\n"84 " !tail(!range(9, 10)));\n"85 " let ForeachOpe = !foreach(\n"86 " arg, arglist,\n"87 " !if(!isa<SomeType>(arg.Type),\n"88 " !add(!cast<SomeOtherType>(arg).Number, x), arg));\n"89 " let CondOpe1 = !cond(!eq(size, 1): 1,\n"90 " !eq(size, 2): 1,\n"91 " !eq(size, 4): 1,\n"92 " !eq(size, 8): 1,\n"93 " !eq(size, 16): 1,\n"94 " true: 0);\n"95 " let CondOpe2 = !cond(!lt(x, 0): \"negativenegative\",\n"96 " !eq(x, 0): \"zerozero\",\n"97 " true: \"positivepositive\");\n"98 " let CondOpe2WithComment = !cond(!lt(x, 0): // negative\n"99 " \"negativenegative\",\n"100 " !eq(x, 0): // zero\n"101 " \"zerozero\",\n"102 " true: // default\n"103 " \"positivepositive\");\n"104 " let CondOpe3WithCommentAfterLParen = !cond(\n"105 " // comment\n"106 " !eq(/* comment */ x, 0): \"zero\");\n"107 "}");108}109 110TEST_F(FormatTestTableGen, Include) {111 verifyFormat("include \"test/IncludeFile.h\"");112}113 114TEST_F(FormatTestTableGen, Types) {115 verifyFormat("def Types : list<int>, bits<3>, list<list<string>> {}");116}117 118TEST_F(FormatTestTableGen, SimpleValue1_SingleLiterals) {119 verifyFormat("def SimpleValue {\n"120 " let Integer = 42;\n"121 " let String = \"some string\";\n"122 "}");123}124 125TEST_F(FormatTestTableGen, SimpleValue1_MultilineString) {126 // test::messUp does not understand multiline TableGen code-literals.127 // We have to give the result and the strings to format manually.128 StringRef DefWithCode =129 "def SimpleValueCode {\n"130 " let Code =\n"131 " [{ A TokCode is nothing more than a multi-line string literal "132 "delimited by \\[{ and }\\]. It can break across lines and the line "133 "breaks are retained in the string. \n"134 "(https://llvm.org/docs/TableGen/ProgRef.html#grammar-token-TokCode)}];\n"135 "}";136 StringRef DefWithCodeMessedUp =137 "def SimpleValueCode { let \n"138 "Code= \n"139 " [{ A TokCode is nothing more than a multi-line string "140 "literal "141 "delimited by \\[{ and }\\]. It can break across lines and the line "142 "breaks are retained in the string. \n"143 "(https://llvm.org/docs/TableGen/ProgRef.html#grammar-token-TokCode)}] \n"144 " ; \n"145 " } ";146 verifyFormat(DefWithCode, DefWithCodeMessedUp);147}148 149TEST_F(FormatTestTableGen, SimpleValue2) {150 verifyFormat("def SimpleValue2 {\n"151 " let True = true;\n"152 " let False = false;\n"153 "}");154}155 156TEST_F(FormatTestTableGen, SimpleValue3) {157 verifyFormat("class SimpleValue3<int x> { int Question = ?; }");158}159 160TEST_F(FormatTestTableGen, SimpleValue4) {161 verifyFormat("def SimpleValue4 { let ValueList = {1, 2, 3}; }");162}163 164TEST_F(FormatTestTableGen, SimpleValue5) {165 verifyFormat("def SimpleValue5 {\n"166 " let SquareList = [1, 4, 9];\n"167 " let SquareListWithType = [\"a\", \"b\", \"c\"]<string>;\n"168 " let SquareListListWithType = [[1, 2], [3, 4, 5], [7]]<\n"169 " list<int>>;\n"170 " let SquareBitsListWithType = [ {1, 2},\n"171 " {3, 4} ]<list<bits<8>>>;\n"172 "}");173}174 175TEST_F(FormatTestTableGen, SimpleValue6) {176 verifyFormat("def SimpleValue6 {\n"177 " let DAGArgIns = (ins i32:$src1, i32:$src2);\n"178 " let DAGArgOuts = (outs i32:$dst1, i32:$dst2, i32:$dst3,\n"179 " i32:$dst4, i32:$dst5, i32:$dst6, i32:$dst7);\n"180 " let DAGArgOutsWithComment = (outs i32:$dst1, // dst1\n"181 " i32:$dst2, // dst2\n"182 " i32:$dst3, // dst3\n"183 " i32:$dst4, // dst4\n"184 " i32:$dst5, // dst5\n"185 " i32:$dst6, // dst6\n"186 " i32:$dst7 // dst7\n"187 " );\n"188 " let DAGArgBang = (!cast<SomeType>(\"Some\") i32:$src1,\n"189 " i32:$src2);\n"190 " let NestedDAGArg = ((DAGArg1 (v111 v112, v113), v12) v2,\n"191 " (DAGArg3 (v31 v32)));\n"192 "}");193}194 195TEST_F(FormatTestTableGen, SimpleValue6_NestedInPat) {196 verifyFormat("def : Pat<(vec.vt (avg (vec.vt V128:$l), (vec.vt V128:$r))),\n"197 " (inst $l, $r)>;");198}199 200TEST_F(FormatTestTableGen, SimpleValue7) {201 verifyFormat("def SimpleValue7 { let Identifier = SimpleValue; }");202}203 204TEST_F(FormatTestTableGen, SimpleValue8) {205 verifyFormat("def SimpleValue8 { let Class = SimpleValue3<3>; }");206}207 208TEST_F(FormatTestTableGen, ValueSuffix) {209 verifyFormat("def SuffixedValues {\n"210 " let Bit = value{17};\n"211 " let Bits = value{8...15};\n"212 " let List = value[1];\n"213 " let Slice1 = value[1, ];\n"214 " let Slice2 = value[4...7, 17, 2...3, 4];\n"215 " let Field = value.field;\n"216 "}");217}218 219TEST_F(FormatTestTableGen, PasteOperator) {220 verifyFormat("def Paste#\"Operator\" { string Paste = \"Paste\"#operator; }");221 222 verifyFormat("def [\"Traring\", \"Paste\"]# {\n"223 " string X = Traring#;\n"224 " string Y = List<\"Operator\">#;\n"225 " string Z = [\"Traring\", \"Paste\", \"Traring\", \"Paste\",\n"226 " \"Traring\", \"Paste\"]#;\n"227 "}");228 229 verifyFormat("def x#x {}", "def x\n"230 "#x {}");231 verifyFormat("def x#x {}", "def x\n"232 "#\n"233 "x {}");234 verifyFormat("def x#x");235}236 237TEST_F(FormatTestTableGen, ClassDefinition) {238 verifyFormat("class Class<int x, int y = 1, string z = \"z\", int w = -1>\n"239 " : Parent1, Parent2<x, y> {\n"240 " int Item1 = 1;\n"241 " int Item2;\n"242 " code Item3 = [{ Item3 }];\n"243 " let Item4 = 4;\n"244 " let Item5{1, 2} = 5;\n"245 " defvar Item6 = 6;\n"246 " let Item7 = ?;\n"247 " assert !ge(x, 0), \"Assert7\";\n"248 "}");249 250 verifyFormat("class FPFormat<bits<3> val> { bits<3> Value = val; }");251}252 253TEST_F(FormatTestTableGen, Def) {254 verifyFormat("def Def : Parent1<Def>, Parent2(defs Def) {\n"255 " code Item1 = [{ Item1 }];\n"256 " let Item2{1, 3...4} = {1, 2};\n"257 " defvar Item3 = (ops nodty:$node1, nodty:$node2);\n"258 " assert !le(Item2, 0), \"Assert4\";\n"259 "}");260 261 verifyFormat("class FPFormat<bits<3> val> { bits<3> Value = val; }");262 263 verifyFormat("def NotFP : FPFormat<0>;");264}265 266TEST_F(FormatTestTableGen, Let) {267 verifyFormat("let x = 1, y = value<type>,\n"268 " z = !and(!gt(!add(1, 2), !sub(3, 4)), !isa<Ty>($x)) in {\n"269 " class Class1 : Parent<x, y> { let Item1 = z; }\n"270 "}");271}272 273TEST_F(FormatTestTableGen, MultiClass) {274 verifyFormat("multiclass Multiclass<int x> {\n"275 " def : Def1<(item type:$src1),\n"276 " (!if(!ge(x, 0), !mul(!add(x, 1), !sub(x, 2)),\n"277 " !sub(x, 2)))>;\n"278 " def Def2 : value<type>;\n"279 " def Def3 : type { let value = 1; }\n"280 " defm : SomeMultiClass<Def1, Def2>;\n"281 " defvar DefVar = 6;\n"282 " foreach i = [1, 2, 3] in {\n"283 " def : Foreach#i<(item type:$src1),\n"284 " (!if(!gt(x, i),\n"285 " !mul(!add(x, i), !sub(x, i)),\n"286 " !sub(x, !add(i, 1))))>;\n"287 " }\n"288 " if !gt(x, 0) then {\n"289 " def : IfThen<x>;\n"290 " } else {\n"291 " def : IfElse<x>;\n"292 " }\n"293 " if (dagid x, 0) then {\n"294 " def : If2<1>;\n"295 " }\n"296 " let y = 1, z = 2 in {\n"297 " multiclass Multiclass2<int x> {\n"298 " foreach i = [1, 2, 3] in {\n"299 " def : Foreach#i<(item type:$src1),\n"300 " (!if(!gt(z, i),\n"301 " !mul(!add(y, i), !sub(x, i)),\n"302 " !sub(z, !add(i, 1))))>;\n"303 " }\n"304 " }\n"305 " }\n"306 "}");307}308 309TEST_F(FormatTestTableGen, MultiClassesWithPasteOperator) {310 // This is a sensitive example for the handling of the paste operators in311 // brace type calculation.312 verifyFormat("multiclass MultiClass1<int i> {\n"313 " def : Def#x<i>;\n"314 " def : Def#y<i>;\n"315 "}\n"316 "multiclass MultiClass2<int i> { def : Def#x<i>; }");317}318 319TEST_F(FormatTestTableGen, Defm) {320 verifyFormat("defm : Multiclass<0>;");321 322 verifyFormat("defm Defm1 : Multiclass<1>;");323}324 325TEST_F(FormatTestTableGen, Defset) {326 verifyFormat("defset list<Class> DefSet1 = {\n"327 " def Def1 : Class<1>;\n"328 " def Def2 : Class<2>;\n"329 "}");330}331 332TEST_F(FormatTestTableGen, Defvar) {333 verifyFormat("defvar DefVar1 = !cond(!ge(!size(PaseOperator.Paste), 1): 1,\n"334 " true: 0);");335}336 337TEST_F(FormatTestTableGen, ForEach) {338 verifyFormat(339 "foreach i = [1, 2, 3] in {\n"340 " def : Foreach#i<(item type:$src1),\n"341 " (!if(!lt(x, i),\n"342 " !shl(!mul(x, i), !size(\"string\")),\n"343 " !size(!strconcat(\"a\", \"b\", \"c\"))))>;\n"344 "}");345}346 347TEST_F(FormatTestTableGen, Dump) { verifyFormat("dump \"Dump\";"); }348 349TEST_F(FormatTestTableGen, If) {350 verifyFormat("if !gt(x, 0) then {\n"351 " def : IfThen<x>;\n"352 "} else {\n"353 " def : IfElse<x>;\n"354 "}");355}356 357TEST_F(FormatTestTableGen, Assert) {358 verifyFormat("assert !le(DefVar1, 0), \"Assert1\";");359}360 361TEST_F(FormatTestTableGen, DAGArgBreakElements) {362 FormatStyle Style = getGoogleStyle(FormatStyle::LK_TableGen);363 Style.ColumnLimit = 60;364 // By default, the DAGArg does not have a break inside.365 ASSERT_EQ(Style.TableGenBreakInsideDAGArg, FormatStyle::DAS_DontBreak);366 verifyFormat("def Def : Parent {\n"367 " let dagarg = (ins a:$src1, aa:$src2, aaa:$src3)\n"368 "}",369 Style);370 // This option forces to break inside the DAGArg.371 Style.TableGenBreakInsideDAGArg = FormatStyle::DAS_BreakElements;372 verifyFormat("def Def : Parent {\n"373 " let dagarg = (ins a:$src1,\n"374 " aa:$src2,\n"375 " aaa:$src3);\n"376 "}",377 Style);378 verifyFormat("def Def : Parent {\n"379 " let dagarg = (other a:$src1,\n"380 " aa:$src2,\n"381 " aaa:$src3);\n"382 "}",383 Style);384 // Then, limit the DAGArg operator only to "ins".385 Style.TableGenBreakingDAGArgOperators = {"ins"};386 verifyFormat("def Def : Parent {\n"387 " let dagarg = (ins a:$src1,\n"388 " aa:$src2,\n"389 " aaa:$src3);\n"390 "}",391 Style);392 verifyFormat("def Def : Parent {\n"393 " let dagarg = (other a:$src1, aa:$src2, aaa:$src3)\n"394 "}",395 Style);396}397 398TEST_F(FormatTestTableGen, DAGArgBreakAll) {399 FormatStyle Style = getGoogleStyle(FormatStyle::LK_TableGen);400 Style.ColumnLimit = 60;401 // By default, the DAGArg does not have a break inside.402 verifyFormat("def Def : Parent {\n"403 " let dagarg = (ins a:$src1, aa:$src2, aaa:$src3)\n"404 "}",405 Style);406 // This option forces to break inside the DAGArg.407 Style.TableGenBreakInsideDAGArg = FormatStyle::DAS_BreakAll;408 verifyFormat("def Def : Parent {\n"409 " let dagarg = (ins\n"410 " a:$src1,\n"411 " aa:$src2,\n"412 " aaa:$src3\n"413 " );\n"414 "}",415 Style);416 verifyFormat("def Def : Parent {\n"417 " let dagarg = (other\n"418 " a:$src1,\n"419 " aa:$src2,\n"420 " aaa:$src3\n"421 " );\n"422 "}",423 Style);424 // Then, limit the DAGArg operator only to "ins".425 Style.TableGenBreakingDAGArgOperators = {"ins"};426 verifyFormat("def Def : Parent {\n"427 " let dagarg = (ins\n"428 " a:$src1,\n"429 " aa:$src2,\n"430 " aaa:$src3\n"431 " );\n"432 "}",433 Style);434 verifyFormat("def Def : Parent {\n"435 " let dagarg = (other a:$src1, aa:$src2, aaa:$src3);\n"436 "}",437 Style);438}439 440TEST_F(FormatTestTableGen, DAGArgAlignment) {441 FormatStyle Style = getGoogleStyle(FormatStyle::LK_TableGen);442 Style.ColumnLimit = 60;443 Style.TableGenBreakInsideDAGArg = FormatStyle::DAS_BreakAll;444 Style.TableGenBreakingDAGArgOperators = {"ins", "outs"};445 verifyFormat("def Def : Parent {\n"446 " let dagarg = (ins\n"447 " a:$src1,\n"448 " aa:$src2,\n"449 " aaa:$src3\n"450 " )\n"451 "}",452 Style);453 verifyFormat("def Def : Parent {\n"454 " let dagarg = (not a:$src1, aa:$src2, aaa:$src2)\n"455 "}",456 Style);457 Style.AlignConsecutiveTableGenBreakingDAGArgColons.Enabled = true;458 verifyFormat("def Def : Parent {\n"459 " let dagarg = (ins\n"460 " a :$src1,\n"461 " aa :$src2,\n"462 " aaa:$src3\n"463 " )\n"464 "}",465 Style);466 verifyFormat("def Def : Parent {\n"467 " let dagarg = (not a:$src1, aa:$src2, aaa:$src2)\n"468 "}",469 Style);470}471 472TEST_F(FormatTestTableGen, CondOperatorAlignment) {473 FormatStyle Style = getGoogleStyle(FormatStyle::LK_TableGen);474 Style.ColumnLimit = 60;475 verifyFormat("let CondOpe1 = !cond(!eq(size, 1): 1,\n"476 " !eq(size, 16): 1,\n"477 " true: 0);",478 Style);479 Style.AlignConsecutiveTableGenCondOperatorColons.Enabled = true;480 verifyFormat("let CondOpe1 = !cond(!eq(size, 1) : 1,\n"481 " !eq(size, 16): 1,\n"482 " true : 0);",483 Style);484}485 486TEST_F(FormatTestTableGen, DefAlignment) {487 FormatStyle Style = getGoogleStyle(FormatStyle::LK_TableGen);488 Style.ColumnLimit = 60;489 verifyFormat("def Def : Parent {}\n"490 "def DefDef : Parent {}\n"491 "def DefDefDef : Parent {}",492 Style);493 Style.AlignConsecutiveTableGenDefinitionColons.Enabled = true;494 verifyFormat("def Def : Parent {}\n"495 "def DefDef : Parent {}\n"496 "def DefDefDef : Parent {}",497 Style);498}499 500} // namespace format501} // end namespace clang502