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
16namespace clang {
17namespace format {
18
19class FormatTestTableGen : public ::testing::Test {
20protected:
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(Language: FormatStyle::LK_TableGen);
35 Style.ColumnLimit = 60; // To make writing tests easier.
36 return format(Code, Offset: 0, Length: 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
56TEST_F(FormatTestTableGen, FormatStringBreak) {
57 verifyFormat(Code: "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
65TEST_F(FormatTestTableGen, NoSpacesInSquareBracketLists) {
66 verifyFormat(Code: "def flag : Flag<[\"-\", \"--\"], \"foo\">;");
67}
68
69TEST_F(FormatTestTableGen, LiteralsAndIdentifiers) {
70 verifyFormat(Code: "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
78TEST_F(FormatTestTableGen, BangOperators) {
79 verifyFormat(Code: "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
107TEST_F(FormatTestTableGen, Include) {
108 verifyFormat(Code: "include \"test/IncludeFile.h\"");
109}
110
111TEST_F(FormatTestTableGen, Types) {
112 verifyFormat(Code: "def Types : list<int>, bits<3>, list<list<string>> {}");
113}
114
115TEST_F(FormatTestTableGen, SimpleValue1_SingleLiterals) {
116 verifyFormat(Code: "def SimpleValue {\n"
117 " let Integer = 42;\n"
118 " let String = \"some string\";\n"
119 "}");
120}
121
122TEST_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(Result: DefWithCode, MessedUp: DefWithCodeMessedUp);
144}
145
146TEST_F(FormatTestTableGen, SimpleValue2) {
147 verifyFormat(Code: "def SimpleValue2 {\n"
148 " let True = true;\n"
149 " let False = false;\n"
150 "}");
151}
152
153TEST_F(FormatTestTableGen, SimpleValue3) {
154 verifyFormat(Code: "class SimpleValue3<int x> { int Question = ?; }");
155}
156
157TEST_F(FormatTestTableGen, SimpleValue4) {
158 verifyFormat(Code: "def SimpleValue4 { let ValueList = {1, 2, 3}; }");
159}
160
161TEST_F(FormatTestTableGen, SimpleValue5) {
162 verifyFormat(Code: "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
172TEST_F(FormatTestTableGen, SimpleValue6) {
173 verifyFormat(Code: "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
190TEST_F(FormatTestTableGen, SimpleValue7) {
191 verifyFormat(Code: "def SimpleValue7 { let Identifier = SimpleValue; }");
192}
193
194TEST_F(FormatTestTableGen, SimpleValue8) {
195 verifyFormat(Code: "def SimpleValue8 { let Class = SimpleValue3<3>; }");
196}
197
198TEST_F(FormatTestTableGen, ValueSuffix) {
199 verifyFormat(Code: "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
209TEST_F(FormatTestTableGen, PasteOperator) {
210 verifyFormat(Code: "def Paste#\"Operator\" { string Paste = \"Paste\"#operator; }");
211
212 verifyFormat(Code: "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
220TEST_F(FormatTestTableGen, ClassDefinition) {
221 verifyFormat(Code: "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(Code: "class FPFormat<bits<3> val> { bits<3> Value = val; }");
234}
235
236TEST_F(FormatTestTableGen, Def) {
237 verifyFormat(Code: "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(Code: "class FPFormat<bits<3> val> { bits<3> Value = val; }");
245
246 verifyFormat(Code: "def NotFP : FPFormat<0>;");
247}
248
249TEST_F(FormatTestTableGen, Let) {
250 verifyFormat(Code: "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
256TEST_F(FormatTestTableGen, MultiClass) {
257 verifyFormat(Code: "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
292TEST_F(FormatTestTableGen, MultiClassesWithPasteOperator) {
293 // This is a sensitive example for the handling of the paste operators in
294 // brace type calculation.
295 verifyFormat(Code: "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
302TEST_F(FormatTestTableGen, Defm) {
303 verifyFormat(Code: "defm : Multiclass<0>;");
304
305 verifyFormat(Code: "defm Defm1 : Multiclass<1>;");
306}
307
308TEST_F(FormatTestTableGen, Defset) {
309 verifyFormat(Code: "defset list<Class> DefSet1 = {\n"
310 " def Def1 : Class<1>;\n"
311 " def Def2 : Class<2>;\n"
312 "}");
313}
314
315TEST_F(FormatTestTableGen, Defvar) {
316 verifyFormat(Code: "defvar DefVar1 = !cond(!ge(!size(PaseOperator.Paste), 1): 1,\n"
317 " true: 0);");
318}
319
320TEST_F(FormatTestTableGen, ForEach) {
321 verifyFormat(
322 Code: "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
330TEST_F(FormatTestTableGen, Dump) { verifyFormat(Code: "dump \"Dump\";"); }
331
332TEST_F(FormatTestTableGen, If) {
333 verifyFormat(Code: "if !gt(x, 0) then {\n"
334 " def : IfThen<x>;\n"
335 "} else {\n"
336 " def : IfElse<x>;\n"
337 "}");
338}
339
340TEST_F(FormatTestTableGen, Assert) {
341 verifyFormat(Code: "assert !le(DefVar1, 0), \"Assert1\";");
342}
343
344TEST_F(FormatTestTableGen, DAGArgBreakElements) {
345 FormatStyle Style = getGoogleStyle(Language: 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(Code: "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(Code: "def Def : Parent {\n"
356 " let dagarg = (ins a:$src1,\n"
357 " aa:$src2,\n"
358 " aaa:$src3);\n"
359 "}",
360 Style);
361 verifyFormat(Code: "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(Code: "def Def : Parent {\n"
370 " let dagarg = (ins a:$src1,\n"
371 " aa:$src2,\n"
372 " aaa:$src3);\n"
373 "}",
374 Style);
375 verifyFormat(Code: "def Def : Parent {\n"
376 " let dagarg = (other a:$src1, aa:$src2, aaa:$src3)\n"
377 "}",
378 Style);
379}
380
381TEST_F(FormatTestTableGen, DAGArgBreakAll) {
382 FormatStyle Style = getGoogleStyle(Language: FormatStyle::LK_TableGen);
383 Style.ColumnLimit = 60;
384 // By default, the DAGArg does not have a break inside.
385 verifyFormat(Code: "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(Code: "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(Code: "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(Code: "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(Code: "def Def : Parent {\n"
418 " let dagarg = (other a:$src1, aa:$src2, aaa:$src3);\n"
419 "}",
420 Style);
421}
422
423TEST_F(FormatTestTableGen, DAGArgAlignment) {
424 FormatStyle Style = getGoogleStyle(Language: FormatStyle::LK_TableGen);
425 Style.ColumnLimit = 60;
426 Style.TableGenBreakInsideDAGArg = FormatStyle::DAS_BreakAll;
427 Style.TableGenBreakingDAGArgOperators = {"ins", "outs"};
428 verifyFormat(Code: "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(Code: "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(Code: "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(Code: "def Def : Parent {\n"
450 " let dagarg = (not a:$src1, aa:$src2, aaa:$src2)\n"
451 "}",
452 Style);
453}
454
455TEST_F(FormatTestTableGen, CondOperatorAlignment) {
456 FormatStyle Style = getGoogleStyle(Language: FormatStyle::LK_TableGen);
457 Style.ColumnLimit = 60;
458 verifyFormat(Code: "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(Code: "let CondOpe1 = !cond(!eq(size, 1) : 1,\n"
464 " !eq(size, 16): 1,\n"
465 " true : 0);",
466 Style);
467}
468
469TEST_F(FormatTestTableGen, DefAlignment) {
470 FormatStyle Style = getGoogleStyle(Language: FormatStyle::LK_TableGen);
471 Style.ColumnLimit = 60;
472 verifyFormat(Code: "def Def : Parent {}\n"
473 "def DefDef : Parent {}\n"
474 "def DefDefDef : Parent {}",
475 Style);
476 Style.AlignConsecutiveTableGenDefinitionColons.Enabled = true;
477 verifyFormat(Code: "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

source code of clang/unittests/Format/FormatTestTableGen.cpp