1 //===- unittest/Format/FormatTestTableGen.cpp -----------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "FormatTestUtils.h"
10 #include "clang/Format/Format.h"
11 #include "llvm/Support/Debug.h"
12 #include "gtest/gtest.h"
14 #define DEBUG_TYPE "format-test"
19 class FormatTestTableGen
: public testing::Test
{
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");
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
);
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
)));
44 static void verifyFormat(StringRef Result
, StringRef MessedUp
) {
45 EXPECT_EQ(Result
, format(MessedUp
));
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
));
56 TEST_F(FormatTestTableGen
, FormatStringBreak
) {
57 verifyFormat("include \"OptParser.td\"\n"
58 "def flag : Flag<\"--foo\">,\n"
60 " \"This is a very, very, very, very, \"\n"
61 " \"very, very, very, very, very, very, \"\n"
62 " \"very long help string\">;");
65 TEST_F(FormatTestTableGen
, NoSpacesInSquareBracketLists
) {
66 verifyFormat("def flag : Flag<[\"-\", \"--\"], \"foo\">;");
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"
78 TEST_F(FormatTestTableGen
, BangOperators
) {
79 verifyFormat("def BangOperators {\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"
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"
93 " !eq(size, 16): 1,\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"
102 " true: // default\n"
103 " \"positivepositive\");\n"
107 TEST_F(FormatTestTableGen
, Include
) {
108 verifyFormat("include \"test/IncludeFile.h\"");
111 TEST_F(FormatTestTableGen
, Types
) {
112 verifyFormat("def Types : list<int>, bits<3>, list<list<string>> {}");
115 TEST_F(FormatTestTableGen
, SimpleValue1_SingleLiterals
) {
116 verifyFormat("def SimpleValue {\n"
117 " let Integer = 42;\n"
118 " let String = \"some string\";\n"
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"
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"
133 StringRef DefWithCodeMessedUp
=
134 "def SimpleValueCode { let \n"
136 " [{ A TokCode is nothing more than a multi-line string "
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"
143 verifyFormat(DefWithCode
, DefWithCodeMessedUp
);
146 TEST_F(FormatTestTableGen
, SimpleValue2
) {
147 verifyFormat("def SimpleValue2 {\n"
148 " let True = true;\n"
149 " let False = false;\n"
153 TEST_F(FormatTestTableGen
, SimpleValue3
) {
154 verifyFormat("class SimpleValue3<int x> { int Question = ?; }");
157 TEST_F(FormatTestTableGen
, SimpleValue4
) {
158 verifyFormat("def SimpleValue4 { let ValueList = {1, 2, 3}; }");
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"
167 " let SquareBitsListWithType = [ {1, 2},\n"
168 " {3, 4} ]<list<bits<8>>>;\n"
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"
185 " let DAGArgBang = (!cast<SomeType>(\"Some\") i32:$src1,\n"
190 TEST_F(FormatTestTableGen
, SimpleValue7
) {
191 verifyFormat("def SimpleValue7 { let Identifier = SimpleValue; }");
194 TEST_F(FormatTestTableGen
, SimpleValue8
) {
195 verifyFormat("def SimpleValue8 { let Class = SimpleValue3<3>; }");
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"
209 TEST_F(FormatTestTableGen
, PasteOperator
) {
210 verifyFormat("def Paste#\"Operator\" { string Paste = \"Paste\"#operator; }");
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"
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"
225 " code Item3 = [{ Item3 }];\n"
227 " let Item5{1, 2} = 5;\n"
228 " defvar Item6 = 6;\n"
230 " assert !ge(x, 0), \"Assert7\";\n"
233 verifyFormat("class FPFormat<bits<3> val> { bits<3> Value = val; }");
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"
244 verifyFormat("class FPFormat<bits<3> val> { bits<3> Value = val; }");
246 verifyFormat("def NotFP : FPFormat<0>;");
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"
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"
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"
268 " !mul(!add(x, i), !sub(x, i)),\n"
269 " !sub(x, !add(i, 1))))>;\n"
271 " if !gt(x, 0) then {\n"
272 " def : IfThen<x>;\n"
274 " def : IfElse<x>;\n"
276 " if (dagid x, 0) then {\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"
284 " !mul(!add(y, i), !sub(x, i)),\n"
285 " !sub(z, !add(i, 1))))>;\n"
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"
299 "multiclass MultiClass2<int i> { def : Def#x<i>; }");
302 TEST_F(FormatTestTableGen
, Defm
) {
303 verifyFormat("defm : Multiclass<0>;");
305 verifyFormat("defm Defm1 : Multiclass<1>;");
308 TEST_F(FormatTestTableGen
, Defset
) {
309 verifyFormat("defset list<Class> DefSet1 = {\n"
310 " def Def1 : Class<1>;\n"
311 " def Def2 : Class<2>;\n"
315 TEST_F(FormatTestTableGen
, Defvar
) {
316 verifyFormat("defvar DefVar1 = !cond(!ge(!size(PaseOperator.Paste), 1): 1,\n"
320 TEST_F(FormatTestTableGen
, ForEach
) {
322 "foreach i = [1, 2, 3] in {\n"
323 " def : Foreach#i<(item type:$src1),\n"
325 " !shl(!mul(x, i), !size(\"string\")),\n"
326 " !size(!strconcat(\"a\", \"b\", \"c\"))))>;\n"
330 TEST_F(FormatTestTableGen
, Dump
) { verifyFormat("dump \"Dump\";"); }
332 TEST_F(FormatTestTableGen
, If
) {
333 verifyFormat("if !gt(x, 0) then {\n"
334 " def : IfThen<x>;\n"
336 " def : IfElse<x>;\n"
340 TEST_F(FormatTestTableGen
, Assert
) {
341 verifyFormat("assert !le(DefVar1, 0), \"Assert1\";");
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"
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"
361 verifyFormat("def Def : Parent {\n"
362 " let dagarg = (other a:$src1,\n"
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"
375 verifyFormat("def Def : Parent {\n"
376 " let dagarg = (other a:$src1, aa:$src2, aaa:$src3)\n"
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"
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"
399 verifyFormat("def Def : Parent {\n"
400 " let dagarg = (other\n"
407 // Then, limit the DAGArg operator only to "ins".
408 Style
.TableGenBreakingDAGArgOperators
= {"ins"};
409 verifyFormat("def Def : Parent {\n"
410 " let dagarg = (ins\n"
417 verifyFormat("def Def : Parent {\n"
418 " let dagarg = (other a:$src1, aa:$src2, aaa:$src3);\n"
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"
436 verifyFormat("def Def : Parent {\n"
437 " let dagarg = (not a:$src1, aa:$src2, aaa:$src2)\n"
440 Style
.AlignConsecutiveTableGenBreakingDAGArgColons
.Enabled
= true;
441 verifyFormat("def Def : Parent {\n"
442 " let dagarg = (ins\n"
449 verifyFormat("def Def : Parent {\n"
450 " let dagarg = (not a:$src1, aa:$src2, aaa:$src2)\n"
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"
462 Style
.AlignConsecutiveTableGenCondOperatorColons
.Enabled
= true;
463 verifyFormat("let CondOpe1 = !cond(!eq(size, 1) : 1,\n"
464 " !eq(size, 16): 1,\n"
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 {}",
476 Style
.AlignConsecutiveTableGenDefinitionColons
.Enabled
= true;
477 verifyFormat("def Def : Parent {}\n"
478 "def DefDef : Parent {}\n"
479 "def DefDefDef : Parent {}",
483 } // namespace format
484 } // end namespace clang