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(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 | |
56 | TEST_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 | |
65 | TEST_F(FormatTestTableGen, NoSpacesInSquareBracketLists) { |
66 | verifyFormat(Code: "def flag : Flag<[\"-\", \"--\"], \"foo\">;" ); |
67 | } |
68 | |
69 | TEST_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 | |
78 | TEST_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 | |
107 | TEST_F(FormatTestTableGen, Include) { |
108 | verifyFormat(Code: "include \"test/IncludeFile.h\"" ); |
109 | } |
110 | |
111 | TEST_F(FormatTestTableGen, Types) { |
112 | verifyFormat(Code: "def Types : list<int>, bits<3>, list<list<string>> {}" ); |
113 | } |
114 | |
115 | TEST_F(FormatTestTableGen, SimpleValue1_SingleLiterals) { |
116 | verifyFormat(Code: "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(Result: DefWithCode, MessedUp: DefWithCodeMessedUp); |
144 | } |
145 | |
146 | TEST_F(FormatTestTableGen, SimpleValue2) { |
147 | verifyFormat(Code: "def SimpleValue2 {\n" |
148 | " let True = true;\n" |
149 | " let False = false;\n" |
150 | "}" ); |
151 | } |
152 | |
153 | TEST_F(FormatTestTableGen, SimpleValue3) { |
154 | verifyFormat(Code: "class SimpleValue3<int x> { int Question = ?; }" ); |
155 | } |
156 | |
157 | TEST_F(FormatTestTableGen, SimpleValue4) { |
158 | verifyFormat(Code: "def SimpleValue4 { let ValueList = {1, 2, 3}; }" ); |
159 | } |
160 | |
161 | TEST_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 | |
172 | TEST_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 | |
190 | TEST_F(FormatTestTableGen, SimpleValue7) { |
191 | verifyFormat(Code: "def SimpleValue7 { let Identifier = SimpleValue; }" ); |
192 | } |
193 | |
194 | TEST_F(FormatTestTableGen, SimpleValue8) { |
195 | verifyFormat(Code: "def SimpleValue8 { let Class = SimpleValue3<3>; }" ); |
196 | } |
197 | |
198 | TEST_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 | |
209 | TEST_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 | |
220 | TEST_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 | |
236 | TEST_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 | |
249 | TEST_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 | |
256 | TEST_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 | |
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(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 | |
302 | TEST_F(FormatTestTableGen, Defm) { |
303 | verifyFormat(Code: "defm : Multiclass<0>;" ); |
304 | |
305 | verifyFormat(Code: "defm Defm1 : Multiclass<1>;" ); |
306 | } |
307 | |
308 | TEST_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 | |
315 | TEST_F(FormatTestTableGen, Defvar) { |
316 | verifyFormat(Code: "defvar DefVar1 = !cond(!ge(!size(PaseOperator.Paste), 1): 1,\n" |
317 | " true: 0);" ); |
318 | } |
319 | |
320 | TEST_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 | |
330 | TEST_F(FormatTestTableGen, Dump) { verifyFormat(Code: "dump \"Dump\";" ); } |
331 | |
332 | TEST_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 | |
340 | TEST_F(FormatTestTableGen, Assert) { |
341 | verifyFormat(Code: "assert !le(DefVar1, 0), \"Assert1\";" ); |
342 | } |
343 | |
344 | TEST_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 | |
381 | TEST_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 | |
423 | TEST_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 | |
455 | TEST_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 | |
469 | TEST_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 | |