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