xref: /llvm-project/clang/unittests/Format/FormatTestTableGen.cpp (revision bf0b21aa685264c65a2d7fd4a8b86e3c42dfd729)
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