1 // Copyright 2020 The Tint Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <unordered_set>
16
17 #include "gtest/gtest-spi.h"
18 #include "src/program_builder.h"
19
20 namespace tint {
21 namespace {
22
23 struct Allocator {
24 template <typename T, typename... ARGS>
Createtint::__anonc203a2060111::Allocator25 T* Create(ARGS&&... args) {
26 return alloc.Create<T>(this, std::forward<ARGS>(args)...);
27 }
28
29 private:
30 BlockAllocator<Cloneable> alloc;
31 };
32
33 struct Node : public Castable<Node, Cloneable> {
Nodetint::__anonc203a2060111::Node34 Node(Allocator* alloc,
35 Symbol n,
36 const Node* node_a = nullptr,
37 const Node* node_b = nullptr,
38 const Node* node_c = nullptr)
39 : allocator(alloc), name(n), a(node_a), b(node_b), c(node_c) {}
40 Allocator* const allocator;
41 Symbol name;
42 const Node* a = nullptr;
43 const Node* b = nullptr;
44 const Node* c = nullptr;
45 std::vector<const Node*> vec;
46
Clonetint::__anonc203a2060111::Node47 Node* Clone(CloneContext* ctx) const override {
48 auto* out = allocator->Create<Node>(ctx->Clone(name));
49 out->a = ctx->Clone(a);
50 out->b = ctx->Clone(b);
51 out->c = ctx->Clone(c);
52 out->vec = ctx->Clone(vec);
53 return out;
54 }
55 };
56
57 struct Replaceable : public Castable<Replaceable, Node> {
Replaceabletint::__anonc203a2060111::Replaceable58 Replaceable(Allocator* alloc,
59 Symbol n,
60 const Node* node_a = nullptr,
61 const Node* node_b = nullptr,
62 const Node* node_c = nullptr)
63 : Base(alloc, n, node_a, node_b, node_c) {}
64 };
65
66 struct Replacement : public Castable<Replacement, Replaceable> {
Replacementtint::__anonc203a2060111::Replacement67 Replacement(Allocator* alloc, Symbol n) : Base(alloc, n) {}
68 };
69
70 struct NotANode : public Castable<NotANode, Cloneable> {
NotANodetint::__anonc203a2060111::NotANode71 explicit NotANode(Allocator* alloc) : allocator(alloc) {}
72
73 Allocator* const allocator;
Clonetint::__anonc203a2060111::NotANode74 NotANode* Clone(CloneContext*) const override {
75 return allocator->Create<NotANode>();
76 }
77 };
78
79 struct ProgramNode : public Castable<ProgramNode, Cloneable> {
ProgramNodetint::__anonc203a2060111::ProgramNode80 ProgramNode(Allocator* alloc, ProgramID id, ProgramID cloned_id)
81 : allocator(alloc), program_id(id), cloned_program_id(cloned_id) {}
82
83 Allocator* const allocator;
84 const ProgramID program_id;
85 const ProgramID cloned_program_id;
86
Clonetint::__anonc203a2060111::ProgramNode87 ProgramNode* Clone(CloneContext*) const override {
88 return allocator->Create<ProgramNode>(cloned_program_id, cloned_program_id);
89 }
90 };
91
ProgramIDOf(const ProgramNode * node)92 ProgramID ProgramIDOf(const ProgramNode* node) {
93 return node->program_id;
94 }
95
96 using CloneContextNodeTest = ::testing::Test;
97
TEST_F(CloneContextNodeTest,Clone)98 TEST_F(CloneContextNodeTest, Clone) {
99 Allocator alloc;
100
101 ProgramBuilder builder;
102 Node* original_root;
103 {
104 auto* a_b = alloc.Create<Node>(builder.Symbols().New("a->b"));
105 auto* a = alloc.Create<Node>(builder.Symbols().New("a"), nullptr, a_b);
106 auto* b_a = a; // Aliased
107 auto* b_b = alloc.Create<Node>(builder.Symbols().New("b->b"));
108 auto* b = alloc.Create<Node>(builder.Symbols().New("b"), b_a, b_b);
109 auto* c = b; // Aliased
110 original_root = alloc.Create<Node>(builder.Symbols().New("root"), a, b, c);
111 }
112 Program original(std::move(builder));
113
114 // root
115 // ╭──────────────────┼──────────────────╮
116 // (a) (b) (c)
117 // N <──────┐ N <───────────────┘
118 // ╭────┼────╮ │ ╭────┼────╮
119 // (a) (b) (c) │ (a) (b) (c)
120 // N └───┘ N
121 //
122 // N: Node
123
124 ProgramBuilder cloned;
125 auto* cloned_root = CloneContext(&cloned, &original).Clone(original_root);
126
127 EXPECT_NE(cloned_root->a, nullptr);
128 EXPECT_EQ(cloned_root->a->a, nullptr);
129 EXPECT_NE(cloned_root->a->b, nullptr);
130 EXPECT_EQ(cloned_root->a->c, nullptr);
131 EXPECT_NE(cloned_root->b, nullptr);
132 EXPECT_NE(cloned_root->b->a, nullptr);
133 EXPECT_NE(cloned_root->b->b, nullptr);
134 EXPECT_EQ(cloned_root->b->c, nullptr);
135 EXPECT_NE(cloned_root->c, nullptr);
136
137 EXPECT_NE(cloned_root->a, original_root->a);
138 EXPECT_NE(cloned_root->a->b, original_root->a->b);
139 EXPECT_NE(cloned_root->b, original_root->b);
140 EXPECT_NE(cloned_root->b->a, original_root->b->a);
141 EXPECT_NE(cloned_root->b->b, original_root->b->b);
142 EXPECT_NE(cloned_root->c, original_root->c);
143
144 EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
145 EXPECT_EQ(cloned_root->a->name, cloned.Symbols().Get("a"));
146 EXPECT_EQ(cloned_root->a->b->name, cloned.Symbols().Get("a->b"));
147 EXPECT_EQ(cloned_root->b->name, cloned.Symbols().Get("b"));
148 EXPECT_EQ(cloned_root->b->b->name, cloned.Symbols().Get("b->b"));
149
150 EXPECT_NE(cloned_root->b->a, cloned_root->a); // De-aliased
151 EXPECT_NE(cloned_root->c, cloned_root->b); // De-aliased
152
153 EXPECT_EQ(cloned_root->b->a->name, cloned_root->a->name);
154 EXPECT_EQ(cloned_root->c->name, cloned_root->b->name);
155 }
156
TEST_F(CloneContextNodeTest,CloneWithReplaceAll_Cloneable)157 TEST_F(CloneContextNodeTest, CloneWithReplaceAll_Cloneable) {
158 Allocator alloc;
159
160 ProgramBuilder builder;
161 Node* original_root;
162 {
163 auto* a_b = alloc.Create<Replaceable>(builder.Symbols().New("a->b"));
164 auto* a = alloc.Create<Node>(builder.Symbols().New("a"), nullptr, a_b);
165 auto* b_a = a; // Aliased
166 auto* b =
167 alloc.Create<Replaceable>(builder.Symbols().New("b"), b_a, nullptr);
168 auto* c = b; // Aliased
169 original_root = alloc.Create<Node>(builder.Symbols().New("root"), a, b, c);
170 }
171 Program original(std::move(builder));
172
173 // root
174 // ╭──────────────────┼──────────────────╮
175 // (a) (b) (c)
176 // N <──────┐ R <───────────────┘
177 // ╭────┼────╮ │ ╭────┼────╮
178 // (a) (b) (c) │ (a) (b) (c)
179 // R └───┘
180 //
181 // N: Node
182 // R: Replaceable
183
184 ProgramBuilder cloned;
185
186 CloneContext ctx(&cloned, &original);
187 ctx.ReplaceAll([&](const Replaceable* in) {
188 auto out_name = cloned.Symbols().Register(
189 "replacement:" + original.Symbols().NameFor(in->name));
190 auto b_name = cloned.Symbols().Register(
191 "replacement-child:" + original.Symbols().NameFor(in->name));
192 auto* out = alloc.Create<Replacement>(out_name);
193 out->b = alloc.Create<Node>(b_name);
194 out->c = ctx.Clone(in->a);
195 return out;
196 });
197 auto* cloned_root = ctx.Clone(original_root);
198
199 // root
200 // ╭─────────────────┼──────────────────╮
201 // (a) (b) (c)
202 // N <──────┐ R <───────────────┘
203 // ╭────┼────╮ │ ╭────┼────╮
204 // (a) (b) (c) │ (a) (b) (c)
205 // R │ N |
206 // ╭────┼────╮ └────────────┘
207 // (a) (b) (c)
208 // N
209 //
210 // N: Node
211 // R: Replacement
212
213 EXPECT_NE(cloned_root->a, nullptr);
214 EXPECT_EQ(cloned_root->a->a, nullptr);
215 EXPECT_NE(cloned_root->a->b, nullptr); // Replaced
216 EXPECT_EQ(cloned_root->a->b->a, nullptr); // From replacement
217 EXPECT_NE(cloned_root->a->b->b, nullptr); // From replacement
218 EXPECT_EQ(cloned_root->a->b->c, nullptr); // From replacement
219 EXPECT_EQ(cloned_root->a->c, nullptr);
220 EXPECT_NE(cloned_root->b, nullptr);
221 EXPECT_EQ(cloned_root->b->a, nullptr); // From replacement
222 EXPECT_NE(cloned_root->b->b, nullptr); // From replacement
223 EXPECT_NE(cloned_root->b->c, nullptr); // From replacement
224 EXPECT_NE(cloned_root->c, nullptr);
225
226 EXPECT_NE(cloned_root->a, original_root->a);
227 EXPECT_NE(cloned_root->a->b, original_root->a->b);
228 EXPECT_NE(cloned_root->b, original_root->b);
229 EXPECT_NE(cloned_root->b->a, original_root->b->a);
230 EXPECT_NE(cloned_root->c, original_root->c);
231
232 EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
233 EXPECT_EQ(cloned_root->a->name, cloned.Symbols().Get("a"));
234 EXPECT_EQ(cloned_root->a->b->name, cloned.Symbols().Get("replacement:a->b"));
235 EXPECT_EQ(cloned_root->a->b->b->name,
236 cloned.Symbols().Get("replacement-child:a->b"));
237 EXPECT_EQ(cloned_root->b->name, cloned.Symbols().Get("replacement:b"));
238 EXPECT_EQ(cloned_root->b->b->name,
239 cloned.Symbols().Get("replacement-child:b"));
240
241 EXPECT_NE(cloned_root->b->c, cloned_root->a); // De-aliased
242 EXPECT_NE(cloned_root->c, cloned_root->b); // De-aliased
243
244 EXPECT_EQ(cloned_root->b->c->name, cloned_root->a->name);
245 EXPECT_EQ(cloned_root->c->name, cloned_root->b->name);
246
247 EXPECT_FALSE(Is<Replacement>(cloned_root->a));
248 EXPECT_TRUE(Is<Replacement>(cloned_root->a->b));
249 EXPECT_FALSE(Is<Replacement>(cloned_root->a->b->b));
250 EXPECT_TRUE(Is<Replacement>(cloned_root->b));
251 EXPECT_FALSE(Is<Replacement>(cloned_root->b->b));
252 }
253
TEST_F(CloneContextNodeTest,CloneWithReplaceAll_Symbols)254 TEST_F(CloneContextNodeTest, CloneWithReplaceAll_Symbols) {
255 Allocator alloc;
256
257 ProgramBuilder builder;
258 Node* original_root;
259 {
260 auto* a_b = alloc.Create<Node>(builder.Symbols().New("a->b"));
261 auto* a = alloc.Create<Node>(builder.Symbols().New("a"), nullptr, a_b);
262 auto* b_a = a; // Aliased
263 auto* b_b = alloc.Create<Node>(builder.Symbols().New("b->b"));
264 auto* b = alloc.Create<Node>(builder.Symbols().New("b"), b_a, b_b);
265 auto* c = b; // Aliased
266 original_root = alloc.Create<Node>(builder.Symbols().New("root"), a, b, c);
267 }
268 Program original(std::move(builder));
269
270 // root
271 // ╭──────────────────┼──────────────────╮
272 // (a) (b) (c)
273 // N <──────┐ N <───────────────┘
274 // ╭────┼────╮ │ ╭────┼────╮
275 // (a) (b) (c) │ (a) (b) (c)
276 // N └───┘ N
277 //
278 // N: Node
279
280 ProgramBuilder cloned;
281 auto* cloned_root = CloneContext(&cloned, &original, false)
282 .ReplaceAll([&](Symbol sym) {
283 auto in = original.Symbols().NameFor(sym);
284 auto out = "transformed<" + in + ">";
285 return cloned.Symbols().New(out);
286 })
287 .Clone(original_root);
288
289 EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("transformed<root>"));
290 EXPECT_EQ(cloned_root->a->name, cloned.Symbols().Get("transformed<a>"));
291 EXPECT_EQ(cloned_root->a->b->name, cloned.Symbols().Get("transformed<a->b>"));
292 EXPECT_EQ(cloned_root->b->name, cloned.Symbols().Get("transformed<b>"));
293 EXPECT_EQ(cloned_root->b->b->name, cloned.Symbols().Get("transformed<b->b>"));
294 }
295
TEST_F(CloneContextNodeTest,CloneWithoutTransform)296 TEST_F(CloneContextNodeTest, CloneWithoutTransform) {
297 Allocator a;
298
299 ProgramBuilder builder;
300 auto* original_node = a.Create<Node>(builder.Symbols().New("root"));
301 Program original(std::move(builder));
302
303 ProgramBuilder cloned;
304 CloneContext ctx(&cloned, &original);
305 ctx.ReplaceAll([&](const Node*) {
306 return a.Create<Replacement>(builder.Symbols().New("<unexpected-node>"));
307 });
308
309 auto* cloned_node = ctx.CloneWithoutTransform(original_node);
310 EXPECT_NE(cloned_node, original_node);
311 EXPECT_EQ(cloned_node->name, cloned.Symbols().Get("root"));
312 }
313
TEST_F(CloneContextNodeTest,CloneWithReplacePointer)314 TEST_F(CloneContextNodeTest, CloneWithReplacePointer) {
315 Allocator a;
316
317 ProgramBuilder builder;
318 auto* original_root = a.Create<Node>(builder.Symbols().New("root"));
319 original_root->a = a.Create<Node>(builder.Symbols().New("a"));
320 original_root->b = a.Create<Node>(builder.Symbols().New("b"));
321 original_root->c = a.Create<Node>(builder.Symbols().New("c"));
322 Program original(std::move(builder));
323
324 // root
325 // ╭──────────────────┼──────────────────╮
326 // (a) (b) (c)
327 // Replaced
328
329 ProgramBuilder cloned;
330 auto* replacement = a.Create<Node>(cloned.Symbols().New("replacement"));
331
332 auto* cloned_root = CloneContext(&cloned, &original)
333 .Replace(original_root->b, replacement)
334 .Clone(original_root);
335
336 EXPECT_NE(cloned_root->a, replacement);
337 EXPECT_EQ(cloned_root->b, replacement);
338 EXPECT_NE(cloned_root->c, replacement);
339
340 EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
341 EXPECT_EQ(cloned_root->a->name, cloned.Symbols().Get("a"));
342 EXPECT_EQ(cloned_root->b->name, cloned.Symbols().Get("replacement"));
343 EXPECT_EQ(cloned_root->c->name, cloned.Symbols().Get("c"));
344 }
345
TEST_F(CloneContextNodeTest,CloneWithReplaceFunction)346 TEST_F(CloneContextNodeTest, CloneWithReplaceFunction) {
347 Allocator a;
348
349 ProgramBuilder builder;
350 auto* original_root = a.Create<Node>(builder.Symbols().New("root"));
351 original_root->a = a.Create<Node>(builder.Symbols().New("a"));
352 original_root->b = a.Create<Node>(builder.Symbols().New("b"));
353 original_root->c = a.Create<Node>(builder.Symbols().New("c"));
354 Program original(std::move(builder));
355
356 // root
357 // ╭──────────────────┼──────────────────╮
358 // (a) (b) (c)
359 // Replaced
360
361 ProgramBuilder cloned;
362 auto* replacement = a.Create<Node>(cloned.Symbols().New("replacement"));
363
364 auto* cloned_root =
365 CloneContext(&cloned, &original)
366 .Replace(original_root->b, [=] { return replacement; })
367 .Clone(original_root);
368
369 EXPECT_NE(cloned_root->a, replacement);
370 EXPECT_EQ(cloned_root->b, replacement);
371 EXPECT_NE(cloned_root->c, replacement);
372
373 EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
374 EXPECT_EQ(cloned_root->a->name, cloned.Symbols().Get("a"));
375 EXPECT_EQ(cloned_root->b->name, cloned.Symbols().Get("replacement"));
376 EXPECT_EQ(cloned_root->c->name, cloned.Symbols().Get("c"));
377 }
378
TEST_F(CloneContextNodeTest,CloneWithRemove)379 TEST_F(CloneContextNodeTest, CloneWithRemove) {
380 Allocator a;
381
382 ProgramBuilder builder;
383 auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
384 original_root->a = a.Create<Node>(builder.Symbols().Register("a"));
385 original_root->b = a.Create<Node>(builder.Symbols().Register("b"));
386 original_root->c = a.Create<Node>(builder.Symbols().Register("c"));
387 original_root->vec = {original_root->a, original_root->b, original_root->c};
388 Program original(std::move(builder));
389
390 ProgramBuilder cloned;
391 auto* cloned_root = CloneContext(&cloned, &original)
392 .Remove(original_root->vec, original_root->b)
393 .Clone(original_root);
394
395 EXPECT_EQ(cloned_root->vec.size(), 2u);
396
397 EXPECT_NE(cloned_root->vec[0], cloned_root->a);
398 EXPECT_NE(cloned_root->vec[1], cloned_root->c);
399
400 EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
401 EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));
402 EXPECT_EQ(cloned_root->vec[1]->name, cloned.Symbols().Get("c"));
403 }
404
TEST_F(CloneContextNodeTest,CloneWithInsertFront)405 TEST_F(CloneContextNodeTest, CloneWithInsertFront) {
406 Allocator a;
407
408 ProgramBuilder builder;
409 auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
410 original_root->a = a.Create<Node>(builder.Symbols().Register("a"));
411 original_root->b = a.Create<Node>(builder.Symbols().Register("b"));
412 original_root->c = a.Create<Node>(builder.Symbols().Register("c"));
413 original_root->vec = {original_root->a, original_root->b, original_root->c};
414 Program original(std::move(builder));
415
416 ProgramBuilder cloned;
417 auto* insertion = a.Create<Node>(cloned.Symbols().New("insertion"));
418
419 auto* cloned_root = CloneContext(&cloned, &original)
420 .InsertFront(original_root->vec, insertion)
421 .Clone(original_root);
422
423 EXPECT_EQ(cloned_root->vec.size(), 4u);
424
425 EXPECT_NE(cloned_root->vec[0], cloned_root->a);
426 EXPECT_NE(cloned_root->vec[1], cloned_root->b);
427 EXPECT_NE(cloned_root->vec[2], cloned_root->c);
428
429 EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
430 EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("insertion"));
431 EXPECT_EQ(cloned_root->vec[1]->name, cloned.Symbols().Get("a"));
432 EXPECT_EQ(cloned_root->vec[2]->name, cloned.Symbols().Get("b"));
433 EXPECT_EQ(cloned_root->vec[3]->name, cloned.Symbols().Get("c"));
434 }
435
TEST_F(CloneContextNodeTest,CloneWithInsertFront_Empty)436 TEST_F(CloneContextNodeTest, CloneWithInsertFront_Empty) {
437 Allocator a;
438
439 ProgramBuilder builder;
440 auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
441 original_root->vec = {};
442 Program original(std::move(builder));
443
444 ProgramBuilder cloned;
445 auto* insertion = a.Create<Node>(cloned.Symbols().New("insertion"));
446
447 auto* cloned_root = CloneContext(&cloned, &original)
448 .InsertFront(original_root->vec, insertion)
449 .Clone(original_root);
450
451 EXPECT_EQ(cloned_root->vec.size(), 1u);
452
453 EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
454 EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("insertion"));
455 }
456
TEST_F(CloneContextNodeTest,CloneWithInsertBack)457 TEST_F(CloneContextNodeTest, CloneWithInsertBack) {
458 Allocator a;
459
460 ProgramBuilder builder;
461 auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
462 original_root->a = a.Create<Node>(builder.Symbols().Register("a"));
463 original_root->b = a.Create<Node>(builder.Symbols().Register("b"));
464 original_root->c = a.Create<Node>(builder.Symbols().Register("c"));
465 original_root->vec = {original_root->a, original_root->b, original_root->c};
466 Program original(std::move(builder));
467
468 ProgramBuilder cloned;
469 auto* insertion = a.Create<Node>(cloned.Symbols().New("insertion"));
470
471 auto* cloned_root = CloneContext(&cloned, &original)
472 .InsertBack(original_root->vec, insertion)
473 .Clone(original_root);
474
475 EXPECT_EQ(cloned_root->vec.size(), 4u);
476
477 EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
478 EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));
479 EXPECT_EQ(cloned_root->vec[1]->name, cloned.Symbols().Get("b"));
480 EXPECT_EQ(cloned_root->vec[2]->name, cloned.Symbols().Get("c"));
481 EXPECT_EQ(cloned_root->vec[3]->name, cloned.Symbols().Get("insertion"));
482 }
483
TEST_F(CloneContextNodeTest,CloneWithInsertBack_Empty)484 TEST_F(CloneContextNodeTest, CloneWithInsertBack_Empty) {
485 Allocator a;
486
487 ProgramBuilder builder;
488 auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
489 original_root->vec = {};
490 Program original(std::move(builder));
491
492 ProgramBuilder cloned;
493 auto* insertion = a.Create<Node>(cloned.Symbols().New("insertion"));
494
495 auto* cloned_root = CloneContext(&cloned, &original)
496 .InsertBack(original_root->vec, insertion)
497 .Clone(original_root);
498
499 EXPECT_EQ(cloned_root->vec.size(), 1u);
500
501 EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
502 EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("insertion"));
503 }
504
TEST_F(CloneContextNodeTest,CloneWithInsertFrontAndBack_Empty)505 TEST_F(CloneContextNodeTest, CloneWithInsertFrontAndBack_Empty) {
506 Allocator a;
507
508 ProgramBuilder builder;
509 auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
510 original_root->vec = {};
511 Program original(std::move(builder));
512
513 ProgramBuilder cloned;
514 auto* insertion_front =
515 a.Create<Node>(cloned.Symbols().New("insertion_front"));
516 auto* insertion_back = a.Create<Node>(cloned.Symbols().New("insertion_back"));
517
518 auto* cloned_root = CloneContext(&cloned, &original)
519 .InsertBack(original_root->vec, insertion_back)
520 .InsertFront(original_root->vec, insertion_front)
521 .Clone(original_root);
522
523 EXPECT_EQ(cloned_root->vec.size(), 2u);
524
525 EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
526 EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("insertion_front"));
527 EXPECT_EQ(cloned_root->vec[1]->name, cloned.Symbols().Get("insertion_back"));
528 }
529
TEST_F(CloneContextNodeTest,CloneWithInsertBefore)530 TEST_F(CloneContextNodeTest, CloneWithInsertBefore) {
531 Allocator a;
532
533 ProgramBuilder builder;
534 auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
535 original_root->a = a.Create<Node>(builder.Symbols().Register("a"));
536 original_root->b = a.Create<Node>(builder.Symbols().Register("b"));
537 original_root->c = a.Create<Node>(builder.Symbols().Register("c"));
538 original_root->vec = {original_root->a, original_root->b, original_root->c};
539 Program original(std::move(builder));
540
541 ProgramBuilder cloned;
542 auto* insertion = a.Create<Node>(cloned.Symbols().New("insertion"));
543
544 auto* cloned_root =
545 CloneContext(&cloned, &original)
546 .InsertBefore(original_root->vec, original_root->b, insertion)
547 .Clone(original_root);
548
549 EXPECT_EQ(cloned_root->vec.size(), 4u);
550
551 EXPECT_NE(cloned_root->vec[0], cloned_root->a);
552 EXPECT_NE(cloned_root->vec[2], cloned_root->b);
553 EXPECT_NE(cloned_root->vec[3], cloned_root->c);
554
555 EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
556 EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));
557 EXPECT_EQ(cloned_root->vec[1]->name, cloned.Symbols().Get("insertion"));
558 EXPECT_EQ(cloned_root->vec[2]->name, cloned.Symbols().Get("b"));
559 EXPECT_EQ(cloned_root->vec[3]->name, cloned.Symbols().Get("c"));
560 }
561
TEST_F(CloneContextNodeTest,CloneWithInsertAfter)562 TEST_F(CloneContextNodeTest, CloneWithInsertAfter) {
563 Allocator a;
564
565 ProgramBuilder builder;
566 auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
567 original_root->a = a.Create<Node>(builder.Symbols().Register("a"));
568 original_root->b = a.Create<Node>(builder.Symbols().Register("b"));
569 original_root->c = a.Create<Node>(builder.Symbols().Register("c"));
570 original_root->vec = {original_root->a, original_root->b, original_root->c};
571 Program original(std::move(builder));
572
573 ProgramBuilder cloned;
574 auto* insertion = a.Create<Node>(cloned.Symbols().New("insertion"));
575
576 auto* cloned_root =
577 CloneContext(&cloned, &original)
578 .InsertAfter(original_root->vec, original_root->b, insertion)
579 .Clone(original_root);
580
581 EXPECT_EQ(cloned_root->vec.size(), 4u);
582
583 EXPECT_NE(cloned_root->vec[0], cloned_root->a);
584 EXPECT_NE(cloned_root->vec[1], cloned_root->b);
585 EXPECT_NE(cloned_root->vec[3], cloned_root->c);
586
587 EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
588 EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));
589 EXPECT_EQ(cloned_root->vec[1]->name, cloned.Symbols().Get("b"));
590 EXPECT_EQ(cloned_root->vec[2]->name, cloned.Symbols().Get("insertion"));
591 EXPECT_EQ(cloned_root->vec[3]->name, cloned.Symbols().Get("c"));
592 }
593
TEST_F(CloneContextNodeTest,CloneWithInsertBeforeAndAfterRemoved)594 TEST_F(CloneContextNodeTest, CloneWithInsertBeforeAndAfterRemoved) {
595 Allocator a;
596
597 ProgramBuilder builder;
598 auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
599 original_root->a = a.Create<Node>(builder.Symbols().Register("a"));
600 original_root->b = a.Create<Node>(builder.Symbols().Register("b"));
601 original_root->c = a.Create<Node>(builder.Symbols().Register("c"));
602 original_root->vec = {original_root->a, original_root->b, original_root->c};
603 Program original(std::move(builder));
604
605 ProgramBuilder cloned;
606 auto* insertion_before =
607 a.Create<Node>(cloned.Symbols().New("insertion_before"));
608 auto* insertion_after =
609 a.Create<Node>(cloned.Symbols().New("insertion_after"));
610
611 auto* cloned_root =
612 CloneContext(&cloned, &original)
613 .InsertBefore(original_root->vec, original_root->b, insertion_before)
614 .InsertAfter(original_root->vec, original_root->b, insertion_after)
615 .Remove(original_root->vec, original_root->b)
616 .Clone(original_root);
617
618 EXPECT_EQ(cloned_root->vec.size(), 4u);
619
620 EXPECT_NE(cloned_root->vec[0], cloned_root->a);
621 EXPECT_NE(cloned_root->vec[3], cloned_root->c);
622
623 EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
624 EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));
625 EXPECT_EQ(cloned_root->vec[1]->name,
626 cloned.Symbols().Get("insertion_before"));
627 EXPECT_EQ(cloned_root->vec[2]->name, cloned.Symbols().Get("insertion_after"));
628 EXPECT_EQ(cloned_root->vec[3]->name, cloned.Symbols().Get("c"));
629 }
630
TEST_F(CloneContextNodeTest,CloneIntoSameBuilder)631 TEST_F(CloneContextNodeTest, CloneIntoSameBuilder) {
632 ProgramBuilder builder;
633 CloneContext ctx(&builder);
634 Allocator allocator;
635 auto* original = allocator.Create<Node>(builder.Symbols().New());
636 auto* cloned_a = ctx.Clone(original);
637 auto* cloned_b = ctx.Clone(original);
638 EXPECT_NE(original, cloned_a);
639 EXPECT_NE(original, cloned_b);
640
641 EXPECT_NE(cloned_a, cloned_b);
642 }
643
TEST_F(CloneContextNodeTest,CloneWithReplaceAll_SameTypeTwice)644 TEST_F(CloneContextNodeTest, CloneWithReplaceAll_SameTypeTwice) {
645 std::string node_name = TypeInfo::Of<Node>().name;
646
647 EXPECT_FATAL_FAILURE(
648 {
649 ProgramBuilder cloned;
650 Program original;
651 CloneContext ctx(&cloned, &original);
652 ctx.ReplaceAll([](const Node*) { return nullptr; });
653 ctx.ReplaceAll([](const Node*) { return nullptr; });
654 },
655 "internal compiler error: ReplaceAll() called with a handler for type " +
656 node_name + " that is already handled by a handler for type " +
657 node_name);
658 }
659
TEST_F(CloneContextNodeTest,CloneWithReplaceAll_BaseThenDerived)660 TEST_F(CloneContextNodeTest, CloneWithReplaceAll_BaseThenDerived) {
661 std::string node_name = TypeInfo::Of<Node>().name;
662 std::string replaceable_name = TypeInfo::Of<Replaceable>().name;
663
664 EXPECT_FATAL_FAILURE(
665 {
666 ProgramBuilder cloned;
667 Program original;
668 CloneContext ctx(&cloned, &original);
669 ctx.ReplaceAll([](const Node*) { return nullptr; });
670 ctx.ReplaceAll([](const Replaceable*) { return nullptr; });
671 },
672 "internal compiler error: ReplaceAll() called with a handler for type " +
673 replaceable_name + " that is already handled by a handler for type " +
674 node_name);
675 }
676
TEST_F(CloneContextNodeTest,CloneWithReplaceAll_DerivedThenBase)677 TEST_F(CloneContextNodeTest, CloneWithReplaceAll_DerivedThenBase) {
678 std::string node_name = TypeInfo::Of<Node>().name;
679 std::string replaceable_name = TypeInfo::Of<Replaceable>().name;
680
681 EXPECT_FATAL_FAILURE(
682 {
683 ProgramBuilder cloned;
684 Program original;
685 CloneContext ctx(&cloned, &original);
686 ctx.ReplaceAll([](const Replaceable*) { return nullptr; });
687 ctx.ReplaceAll([](const Node*) { return nullptr; });
688 },
689 "internal compiler error: ReplaceAll() called with a handler for type " +
690 node_name + " that is already handled by a handler for type " +
691 replaceable_name);
692 }
693
TEST_F(CloneContextNodeTest,CloneWithReplacePointer_WithNotANode)694 TEST_F(CloneContextNodeTest, CloneWithReplacePointer_WithNotANode) {
695 EXPECT_FATAL_FAILURE(
696 {
697 Allocator allocator;
698 ProgramBuilder builder;
699 auto* original_root =
700 allocator.Create<Node>(builder.Symbols().New("root"));
701 original_root->a = allocator.Create<Node>(builder.Symbols().New("a"));
702 original_root->b = allocator.Create<Node>(builder.Symbols().New("b"));
703 original_root->c = allocator.Create<Node>(builder.Symbols().New("c"));
704 Program original(std::move(builder));
705
706 // root
707 // ╭──────────────────┼──────────────────╮
708 // (a) (b) (c)
709 // Replaced
710
711 ProgramBuilder cloned;
712 auto* replacement = allocator.Create<NotANode>();
713
714 CloneContext ctx(&cloned, &original);
715 ctx.Replace(original_root->b, replacement);
716
717 ctx.Clone(original_root);
718 },
719 "internal compiler error");
720 }
721
TEST_F(CloneContextNodeTest,CloneWithReplaceFunction_WithNotANode)722 TEST_F(CloneContextNodeTest, CloneWithReplaceFunction_WithNotANode) {
723 EXPECT_FATAL_FAILURE(
724 {
725 Allocator allocator;
726 ProgramBuilder builder;
727 auto* original_root =
728 allocator.Create<Node>(builder.Symbols().New("root"));
729 original_root->a = allocator.Create<Node>(builder.Symbols().New("a"));
730 original_root->b = allocator.Create<Node>(builder.Symbols().New("b"));
731 original_root->c = allocator.Create<Node>(builder.Symbols().New("c"));
732 Program original(std::move(builder));
733
734 // root
735 // ╭──────────────────┼──────────────────╮
736 // (a) (b) (c)
737 // Replaced
738
739 ProgramBuilder cloned;
740 auto* replacement = allocator.Create<NotANode>();
741
742 CloneContext ctx(&cloned, &original);
743 ctx.Replace(original_root->b, [=] { return replacement; });
744
745 ctx.Clone(original_root);
746 },
747 "internal compiler error");
748 }
749
750 using CloneContextTest = ::testing::Test;
751
TEST_F(CloneContextTest,CloneWithReplaceAll_SymbolsTwice)752 TEST_F(CloneContextTest, CloneWithReplaceAll_SymbolsTwice) {
753 EXPECT_FATAL_FAILURE(
754 {
755 ProgramBuilder cloned;
756 Program original;
757 CloneContext ctx(&cloned, &original);
758 ctx.ReplaceAll([](const Symbol s) { return s; });
759 ctx.ReplaceAll([](const Symbol s) { return s; });
760 },
761 "internal compiler error: ReplaceAll(const SymbolTransform&) called "
762 "multiple times on the same CloneContext");
763 }
764
TEST_F(CloneContextTest,CloneNewUnnamedSymbols)765 TEST_F(CloneContextTest, CloneNewUnnamedSymbols) {
766 ProgramBuilder builder;
767 Symbol old_a = builder.Symbols().New();
768 Symbol old_b = builder.Symbols().New();
769 Symbol old_c = builder.Symbols().New();
770 EXPECT_EQ(builder.Symbols().NameFor(old_a), "tint_symbol");
771 EXPECT_EQ(builder.Symbols().NameFor(old_b), "tint_symbol_1");
772 EXPECT_EQ(builder.Symbols().NameFor(old_c), "tint_symbol_2");
773
774 Program original(std::move(builder));
775
776 ProgramBuilder cloned;
777 CloneContext ctx(&cloned, &original, false);
778 Symbol new_x = cloned.Symbols().New();
779 Symbol new_a = ctx.Clone(old_a);
780 Symbol new_y = cloned.Symbols().New();
781 Symbol new_b = ctx.Clone(old_b);
782 Symbol new_z = cloned.Symbols().New();
783 Symbol new_c = ctx.Clone(old_c);
784
785 EXPECT_EQ(cloned.Symbols().NameFor(new_x), "tint_symbol");
786 EXPECT_EQ(cloned.Symbols().NameFor(new_a), "tint_symbol_1");
787 EXPECT_EQ(cloned.Symbols().NameFor(new_y), "tint_symbol_2");
788 EXPECT_EQ(cloned.Symbols().NameFor(new_b), "tint_symbol_1_1");
789 EXPECT_EQ(cloned.Symbols().NameFor(new_z), "tint_symbol_3");
790 EXPECT_EQ(cloned.Symbols().NameFor(new_c), "tint_symbol_2_1");
791 }
792
TEST_F(CloneContextTest,CloneNewSymbols)793 TEST_F(CloneContextTest, CloneNewSymbols) {
794 ProgramBuilder builder;
795 Symbol old_a = builder.Symbols().New("a");
796 Symbol old_b = builder.Symbols().New("b");
797 Symbol old_c = builder.Symbols().New("c");
798 EXPECT_EQ(builder.Symbols().NameFor(old_a), "a");
799 EXPECT_EQ(builder.Symbols().NameFor(old_b), "b");
800 EXPECT_EQ(builder.Symbols().NameFor(old_c), "c");
801
802 Program original(std::move(builder));
803
804 ProgramBuilder cloned;
805 CloneContext ctx(&cloned, &original, false);
806 Symbol new_x = cloned.Symbols().New("a");
807 Symbol new_a = ctx.Clone(old_a);
808 Symbol new_y = cloned.Symbols().New("b");
809 Symbol new_b = ctx.Clone(old_b);
810 Symbol new_z = cloned.Symbols().New("c");
811 Symbol new_c = ctx.Clone(old_c);
812
813 EXPECT_EQ(cloned.Symbols().NameFor(new_x), "a");
814 EXPECT_EQ(cloned.Symbols().NameFor(new_a), "a_1");
815 EXPECT_EQ(cloned.Symbols().NameFor(new_y), "b");
816 EXPECT_EQ(cloned.Symbols().NameFor(new_b), "b_1");
817 EXPECT_EQ(cloned.Symbols().NameFor(new_z), "c");
818 EXPECT_EQ(cloned.Symbols().NameFor(new_c), "c_1");
819 }
820
TEST_F(CloneContextTest,CloneNewSymbols_AfterCloneSymbols)821 TEST_F(CloneContextTest, CloneNewSymbols_AfterCloneSymbols) {
822 ProgramBuilder builder;
823 Symbol old_a = builder.Symbols().New("a");
824 Symbol old_b = builder.Symbols().New("b");
825 Symbol old_c = builder.Symbols().New("c");
826 EXPECT_EQ(builder.Symbols().NameFor(old_a), "a");
827 EXPECT_EQ(builder.Symbols().NameFor(old_b), "b");
828 EXPECT_EQ(builder.Symbols().NameFor(old_c), "c");
829
830 Program original(std::move(builder));
831
832 ProgramBuilder cloned;
833 CloneContext ctx(&cloned, &original);
834 Symbol new_x = cloned.Symbols().New("a");
835 Symbol new_a = ctx.Clone(old_a);
836 Symbol new_y = cloned.Symbols().New("b");
837 Symbol new_b = ctx.Clone(old_b);
838 Symbol new_z = cloned.Symbols().New("c");
839 Symbol new_c = ctx.Clone(old_c);
840
841 EXPECT_EQ(cloned.Symbols().NameFor(new_x), "a_1");
842 EXPECT_EQ(cloned.Symbols().NameFor(new_a), "a");
843 EXPECT_EQ(cloned.Symbols().NameFor(new_y), "b_1");
844 EXPECT_EQ(cloned.Symbols().NameFor(new_b), "b");
845 EXPECT_EQ(cloned.Symbols().NameFor(new_z), "c_1");
846 EXPECT_EQ(cloned.Symbols().NameFor(new_c), "c");
847 }
848
TEST_F(CloneContextTest,ProgramIDs)849 TEST_F(CloneContextTest, ProgramIDs) {
850 ProgramBuilder dst;
851 Program src(ProgramBuilder{});
852 CloneContext ctx(&dst, &src);
853 Allocator allocator;
854 auto* cloned = ctx.Clone(allocator.Create<ProgramNode>(src.ID(), dst.ID()));
855 EXPECT_EQ(cloned->program_id, dst.ID());
856 }
857
TEST_F(CloneContextTest,ProgramIDs_Clone_ObjectNotOwnedBySrc)858 TEST_F(CloneContextTest, ProgramIDs_Clone_ObjectNotOwnedBySrc) {
859 EXPECT_FATAL_FAILURE(
860 {
861 ProgramBuilder dst;
862 Program src(ProgramBuilder{});
863 CloneContext ctx(&dst, &src);
864 Allocator allocator;
865 ctx.Clone(allocator.Create<ProgramNode>(ProgramID::New(), dst.ID()));
866 },
867 R"(internal compiler error: TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, src, object))");
868 }
869
TEST_F(CloneContextTest,ProgramIDs_Clone_ObjectNotOwnedByDst)870 TEST_F(CloneContextTest, ProgramIDs_Clone_ObjectNotOwnedByDst) {
871 EXPECT_FATAL_FAILURE(
872 {
873 ProgramBuilder dst;
874 Program src(ProgramBuilder{});
875 CloneContext ctx(&dst, &src);
876 Allocator allocator;
877 ctx.Clone(allocator.Create<ProgramNode>(src.ID(), ProgramID::New()));
878 },
879 R"(internal compiler error: TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, dst, out))");
880 }
881
882 } // namespace
883
884 TINT_INSTANTIATE_TYPEINFO(Node);
885 TINT_INSTANTIATE_TYPEINFO(Replaceable);
886 TINT_INSTANTIATE_TYPEINFO(Replacement);
887 TINT_INSTANTIATE_TYPEINFO(NotANode);
888 TINT_INSTANTIATE_TYPEINFO(ProgramNode);
889
890 } // namespace tint
891