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