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 "}\n"); 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 "}\n"); 105 } 106 107 TEST_F(FormatTestTableGen, Include) { 108 verifyFormat("include \"test/IncludeFile.h\"\n"); 109 } 110 111 TEST_F(FormatTestTableGen, Types) { 112 verifyFormat("def Types : list<int>, bits<3>, list<list<string>> {}\n"); 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 "}\n"); 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 "}\n"; 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 " } \n"; 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 "}\n"); 151 } 152 153 TEST_F(FormatTestTableGen, SimpleValue3) { 154 verifyFormat("class SimpleValue3<int x> { int Question = ?; }\n"); 155 } 156 157 TEST_F(FormatTestTableGen, SimpleValue4) { 158 verifyFormat("def SimpleValue4 { let ValueList = {1, 2, 3}; }\n"); 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 "}\n"); 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 "}\n"); 188 } 189 190 TEST_F(FormatTestTableGen, SimpleValue7) { 191 verifyFormat("def SimpleValue7 { let Identifier = SimpleValue; }\n"); 192 } 193 194 TEST_F(FormatTestTableGen, SimpleValue8) { 195 verifyFormat("def SimpleValue8 { let Class = SimpleValue3<3>; }\n"); 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 "}\n"); 207 } 208 209 TEST_F(FormatTestTableGen, PasteOperator) { 210 verifyFormat( 211 "def Paste#\"Operator\" { string Paste = \"Paste\"#operator; }\n"); 212 213 verifyFormat("def [\"Traring\", \"Paste\"]# {\n" 214 " string X = Traring#;\n" 215 " string Y = List<\"Operator\">#;\n" 216 " string Z = [\"Traring\", \"Paste\", \"Traring\", \"Paste\",\n" 217 " \"Traring\", \"Paste\"]#;\n" 218 "}\n"); 219 } 220 221 TEST_F(FormatTestTableGen, ClassDefinition) { 222 verifyFormat("class Class<int x, int y = 1, string z = \"z\", int w = -1>\n" 223 " : Parent1, Parent2<x, y> {\n" 224 " int Item1 = 1;\n" 225 " int Item2;\n" 226 " code Item3 = [{ Item3 }];\n" 227 " let Item4 = 4;\n" 228 " let Item5{1, 2} = 5;\n" 229 " defvar Item6 = 6;\n" 230 " let Item7 = ?;\n" 231 " assert !ge(x, 0), \"Assert7\";\n" 232 "}\n"); 233 234 verifyFormat("class FPFormat<bits<3> val> { bits<3> Value = val; }\n"); 235 } 236 237 TEST_F(FormatTestTableGen, Def) { 238 verifyFormat("def Def : Parent1<Def>, Parent2(defs Def) {\n" 239 " code Item1 = [{ Item1 }];\n" 240 " let Item2{1, 3...4} = {1, 2};\n" 241 " defvar Item3 = (ops nodty:$node1, nodty:$node2);\n" 242 " assert !le(Item2, 0), \"Assert4\";\n" 243 "}\n"); 244 245 verifyFormat("class FPFormat<bits<3> val> { bits<3> Value = val; }\n"); 246 247 verifyFormat("def NotFP : FPFormat<0>;\n"); 248 } 249 250 TEST_F(FormatTestTableGen, Let) { 251 verifyFormat("let x = 1, y = value<type>,\n" 252 " z = !and(!gt(!add(1, 2), !sub(3, 4)), !isa<Ty>($x)) in {\n" 253 " class Class1 : Parent<x, y> { let Item1 = z; }\n" 254 "}\n"); 255 } 256 257 TEST_F(FormatTestTableGen, MultiClass) { 258 verifyFormat("multiclass Multiclass<int x> {\n" 259 " def : Def1<(item type:$src1),\n" 260 " (!if(!ge(x, 0), !mul(!add(x, 1), !sub(x, 2)),\n" 261 " !sub(x, 2)))>;\n" 262 " def Def2 : value<type>;\n" 263 " def Def3 : type { let value = 1; }\n" 264 " defm : SomeMultiClass<Def1, Def2>;\n" 265 " defvar DefVar = 6;\n" 266 " foreach i = [1, 2, 3] in {\n" 267 " def : Foreach#i<(item type:$src1),\n" 268 " (!if(!gt(x, i),\n" 269 " !mul(!add(x, i), !sub(x, i)),\n" 270 " !sub(x, !add(i, 1))))>;\n" 271 " }\n" 272 " if !gt(x, 0) then {\n" 273 " def : IfThen<x>;\n" 274 " } else {\n" 275 " def : IfElse<x>;\n" 276 " }\n" 277 " if (dagid x, 0) then {\n" 278 " def : If2<1>;\n" 279 " }\n" 280 " let y = 1, z = 2 in {\n" 281 " multiclass Multiclass2<int x> {\n" 282 " foreach i = [1, 2, 3] in {\n" 283 " def : Foreach#i<(item type:$src1),\n" 284 " (!if(!gt(z, i),\n" 285 " !mul(!add(y, i), !sub(x, i)),\n" 286 " !sub(z, !add(i, 1))))>;\n" 287 " }\n" 288 " }\n" 289 " }\n" 290 "}\n"); 291 } 292 293 TEST_F(FormatTestTableGen, MultiClassesWithPasteOperator) { 294 // This is a sensitive example for the handling of the paste operators in 295 // brace type calculation. 296 verifyFormat("multiclass MultiClass1<int i> {\n" 297 " def : Def#x<i>;\n" 298 " def : Def#y<i>;\n" 299 "}\n" 300 "multiclass MultiClass2<int i> { def : Def#x<i>; }\n"); 301 } 302 303 TEST_F(FormatTestTableGen, Defm) { 304 verifyFormat("defm : Multiclass<0>;\n"); 305 306 verifyFormat("defm Defm1 : Multiclass<1>;\n"); 307 } 308 309 TEST_F(FormatTestTableGen, Defset) { 310 verifyFormat("defset list<Class> DefSet1 = {\n" 311 " def Def1 : Class<1>;\n" 312 " def Def2 : Class<2>;\n" 313 "}\n"); 314 } 315 316 TEST_F(FormatTestTableGen, Defvar) { 317 verifyFormat("defvar DefVar1 = !cond(!ge(!size(PaseOperator.Paste), 1): 1,\n" 318 " true: 0);\n"); 319 } 320 321 TEST_F(FormatTestTableGen, ForEach) { 322 verifyFormat( 323 "foreach i = [1, 2, 3] in {\n" 324 " def : Foreach#i<(item type:$src1),\n" 325 " (!if(!lt(x, i),\n" 326 " !shl(!mul(x, i), !size(\"string\")),\n" 327 " !size(!strconcat(\"a\", \"b\", \"c\"))))>;\n" 328 "}\n"); 329 } 330 331 TEST_F(FormatTestTableGen, Dump) { verifyFormat("dump \"Dump\";\n"); } 332 333 TEST_F(FormatTestTableGen, If) { 334 verifyFormat("if !gt(x, 0) then {\n" 335 " def : IfThen<x>;\n" 336 "} else {\n" 337 " def : IfElse<x>;\n" 338 "}\n"); 339 } 340 341 TEST_F(FormatTestTableGen, Assert) { 342 verifyFormat("assert !le(DefVar1, 0), \"Assert1\";\n"); 343 } 344 345 TEST_F(FormatTestTableGen, DAGArgBreakElements) { 346 FormatStyle Style = getGoogleStyle(FormatStyle::LK_TableGen); 347 Style.ColumnLimit = 60; 348 // By default, the DAGArg does not have a break inside. 349 ASSERT_EQ(Style.TableGenBreakInsideDAGArg, FormatStyle::DAS_DontBreak); 350 verifyFormat("def Def : Parent {\n" 351 " let dagarg = (ins a:$src1, aa:$src2, aaa:$src3)\n" 352 "}\n", 353 Style); 354 // This option forces to break inside the DAGArg. 355 Style.TableGenBreakInsideDAGArg = FormatStyle::DAS_BreakElements; 356 verifyFormat("def Def : Parent {\n" 357 " let dagarg = (ins a:$src1,\n" 358 " aa:$src2,\n" 359 " aaa:$src3);\n" 360 "}\n", 361 Style); 362 verifyFormat("def Def : Parent {\n" 363 " let dagarg = (other a:$src1,\n" 364 " aa:$src2,\n" 365 " aaa:$src3);\n" 366 "}\n", 367 Style); 368 // Then, limit the DAGArg operator only to "ins". 369 Style.TableGenBreakingDAGArgOperators = {"ins"}; 370 verifyFormat("def Def : Parent {\n" 371 " let dagarg = (ins a:$src1,\n" 372 " aa:$src2,\n" 373 " aaa:$src3);\n" 374 "}\n", 375 Style); 376 verifyFormat("def Def : Parent {\n" 377 " let dagarg = (other a:$src1, aa:$src2, aaa:$src3)\n" 378 "}\n", 379 Style); 380 } 381 382 TEST_F(FormatTestTableGen, DAGArgBreakAll) { 383 FormatStyle Style = getGoogleStyle(FormatStyle::LK_TableGen); 384 Style.ColumnLimit = 60; 385 // By default, the DAGArg does not have a break inside. 386 verifyFormat("def Def : Parent {\n" 387 " let dagarg = (ins a:$src1, aa:$src2, aaa:$src3)\n" 388 "}\n", 389 Style); 390 // This option forces to break inside the DAGArg. 391 Style.TableGenBreakInsideDAGArg = FormatStyle::DAS_BreakAll; 392 verifyFormat("def Def : Parent {\n" 393 " let dagarg = (ins\n" 394 " a:$src1,\n" 395 " aa:$src2,\n" 396 " aaa:$src3\n" 397 " );\n" 398 "}\n", 399 Style); 400 verifyFormat("def Def : Parent {\n" 401 " let dagarg = (other\n" 402 " a:$src1,\n" 403 " aa:$src2,\n" 404 " aaa:$src3\n" 405 " );\n" 406 "}\n", 407 Style); 408 // Then, limit the DAGArg operator only to "ins". 409 Style.TableGenBreakingDAGArgOperators = {"ins"}; 410 verifyFormat("def Def : Parent {\n" 411 " let dagarg = (ins\n" 412 " a:$src1,\n" 413 " aa:$src2,\n" 414 " aaa:$src3\n" 415 " );\n" 416 "}\n", 417 Style); 418 verifyFormat("def Def : Parent {\n" 419 " let dagarg = (other a:$src1, aa:$src2, aaa:$src3);\n" 420 "}\n", 421 Style); 422 } 423 424 TEST_F(FormatTestTableGen, DAGArgAlignment) { 425 FormatStyle Style = getGoogleStyle(FormatStyle::LK_TableGen); 426 Style.ColumnLimit = 60; 427 Style.TableGenBreakInsideDAGArg = FormatStyle::DAS_BreakAll; 428 Style.TableGenBreakingDAGArgOperators = {"ins", "outs"}; 429 verifyFormat("def Def : Parent {\n" 430 " let dagarg = (ins\n" 431 " a:$src1,\n" 432 " aa:$src2,\n" 433 " aaa:$src3\n" 434 " )\n" 435 "}\n", 436 Style); 437 verifyFormat("def Def : Parent {\n" 438 " let dagarg = (not a:$src1, aa:$src2, aaa:$src2)\n" 439 "}\n", 440 Style); 441 Style.AlignConsecutiveTableGenBreakingDAGArgColons.Enabled = true; 442 verifyFormat("def Def : Parent {\n" 443 " let dagarg = (ins\n" 444 " a :$src1,\n" 445 " aa :$src2,\n" 446 " aaa:$src3\n" 447 " )\n" 448 "}\n", 449 Style); 450 verifyFormat("def Def : Parent {\n" 451 " let dagarg = (not a:$src1, aa:$src2, aaa:$src2)\n" 452 "}\n", 453 Style); 454 } 455 456 TEST_F(FormatTestTableGen, CondOperatorAlignment) { 457 FormatStyle Style = getGoogleStyle(FormatStyle::LK_TableGen); 458 Style.ColumnLimit = 60; 459 verifyFormat("let CondOpe1 = !cond(!eq(size, 1): 1,\n" 460 " !eq(size, 16): 1,\n" 461 " true: 0);\n", 462 Style); 463 Style.AlignConsecutiveTableGenCondOperatorColons.Enabled = true; 464 verifyFormat("let CondOpe1 = !cond(!eq(size, 1) : 1,\n" 465 " !eq(size, 16): 1,\n" 466 " true : 0);\n", 467 Style); 468 } 469 470 TEST_F(FormatTestTableGen, DefAlignment) { 471 FormatStyle Style = getGoogleStyle(FormatStyle::LK_TableGen); 472 Style.ColumnLimit = 60; 473 verifyFormat("def Def : Parent {}\n" 474 "def DefDef : Parent {}\n" 475 "def DefDefDef : Parent {}\n", 476 Style); 477 Style.AlignConsecutiveTableGenDefinitionColons.Enabled = true; 478 verifyFormat("def Def : Parent {}\n" 479 "def DefDef : Parent {}\n" 480 "def DefDefDef : Parent {}\n", 481 Style); 482 } 483 484 } // namespace format 485 } // end namespace clang 486