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