1 // Copyright 2021 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 "src/ast/traverse_expressions.h"
16 #include "gmock/gmock.h"
17 #include "src/ast/test_helper.h"
18
19 namespace tint {
20 namespace ast {
21 namespace {
22
23 using ::testing::ElementsAre;
24
25 using TraverseExpressionsTest = TestHelper;
26
TEST_F(TraverseExpressionsTest,DescendIndexAccessor)27 TEST_F(TraverseExpressionsTest, DescendIndexAccessor) {
28 std::vector<const ast::Expression*> e = {Expr(1), Expr(1), Expr(1), Expr(1)};
29 std::vector<const ast::Expression*> i = {IndexAccessor(e[0], e[1]),
30 IndexAccessor(e[2], e[3])};
31 auto* root = IndexAccessor(i[0], i[1]);
32 {
33 std::vector<const ast::Expression*> l2r;
34 TraverseExpressions<TraverseOrder::LeftToRight>(
35 root, Diagnostics(), [&](const ast::Expression* expr) {
36 l2r.push_back(expr);
37 return ast::TraverseAction::Descend;
38 });
39 EXPECT_THAT(l2r, ElementsAre(root, i[0], e[0], e[1], i[1], e[2], e[3]));
40 }
41 {
42 std::vector<const ast::Expression*> r2l;
43 TraverseExpressions<TraverseOrder::RightToLeft>(
44 root, Diagnostics(), [&](const ast::Expression* expr) {
45 r2l.push_back(expr);
46 return ast::TraverseAction::Descend;
47 });
48 EXPECT_THAT(r2l, ElementsAre(root, i[1], e[3], e[2], i[0], e[1], e[0]));
49 }
50 }
51
TEST_F(TraverseExpressionsTest,DescendBinaryExpression)52 TEST_F(TraverseExpressionsTest, DescendBinaryExpression) {
53 std::vector<const ast::Expression*> e = {Expr(1), Expr(1), Expr(1), Expr(1)};
54 std::vector<const ast::Expression*> i = {Add(e[0], e[1]), Sub(e[2], e[3])};
55 auto* root = Mul(i[0], i[1]);
56 {
57 std::vector<const ast::Expression*> l2r;
58 TraverseExpressions<TraverseOrder::LeftToRight>(
59 root, Diagnostics(), [&](const ast::Expression* expr) {
60 l2r.push_back(expr);
61 return ast::TraverseAction::Descend;
62 });
63 EXPECT_THAT(l2r, ElementsAre(root, i[0], e[0], e[1], i[1], e[2], e[3]));
64 }
65 {
66 std::vector<const ast::Expression*> r2l;
67 TraverseExpressions<TraverseOrder::RightToLeft>(
68 root, Diagnostics(), [&](const ast::Expression* expr) {
69 r2l.push_back(expr);
70 return ast::TraverseAction::Descend;
71 });
72 EXPECT_THAT(r2l, ElementsAre(root, i[1], e[3], e[2], i[0], e[1], e[0]));
73 }
74 }
75
TEST_F(TraverseExpressionsTest,DescendBitcastExpression)76 TEST_F(TraverseExpressionsTest, DescendBitcastExpression) {
77 auto* e = Expr(1);
78 auto* b0 = Bitcast<i32>(e);
79 auto* b1 = Bitcast<i32>(b0);
80 auto* b2 = Bitcast<i32>(b1);
81 auto* root = Bitcast<i32>(b2);
82 {
83 std::vector<const ast::Expression*> l2r;
84 TraverseExpressions<TraverseOrder::LeftToRight>(
85 root, Diagnostics(), [&](const ast::Expression* expr) {
86 l2r.push_back(expr);
87 return ast::TraverseAction::Descend;
88 });
89 EXPECT_THAT(l2r, ElementsAre(root, b2, b1, b0, e));
90 }
91 {
92 std::vector<const ast::Expression*> r2l;
93 TraverseExpressions<TraverseOrder::RightToLeft>(
94 root, Diagnostics(), [&](const ast::Expression* expr) {
95 r2l.push_back(expr);
96 return ast::TraverseAction::Descend;
97 });
98 EXPECT_THAT(r2l, ElementsAre(root, b2, b1, b0, e));
99 }
100 }
101
TEST_F(TraverseExpressionsTest,DescendCallExpression)102 TEST_F(TraverseExpressionsTest, DescendCallExpression) {
103 std::vector<const ast::Expression*> e = {Expr(1), Expr(1), Expr(1), Expr(1)};
104 std::vector<const ast::Expression*> c = {Call("a", e[0], e[1]),
105 Call("b", e[2], e[3])};
106 auto* root = Call("c", c[0], c[1]);
107 {
108 std::vector<const ast::Expression*> l2r;
109 TraverseExpressions<TraverseOrder::LeftToRight>(
110 root, Diagnostics(), [&](const ast::Expression* expr) {
111 l2r.push_back(expr);
112 return ast::TraverseAction::Descend;
113 });
114 EXPECT_THAT(l2r, ElementsAre(root, c[0], e[0], e[1], c[1], e[2], e[3]));
115 }
116 {
117 std::vector<const ast::Expression*> r2l;
118 TraverseExpressions<TraverseOrder::RightToLeft>(
119 root, Diagnostics(), [&](const ast::Expression* expr) {
120 r2l.push_back(expr);
121 return ast::TraverseAction::Descend;
122 });
123 EXPECT_THAT(r2l, ElementsAre(root, c[1], e[3], e[2], c[0], e[1], e[0]));
124 }
125 }
126
127 // TODO(crbug.com/tint/1257): Test ignores member accessor 'member' field.
128 // Replace with the test below when fixed.
TEST_F(TraverseExpressionsTest,DescendMemberIndexExpression)129 TEST_F(TraverseExpressionsTest, DescendMemberIndexExpression) {
130 auto* e = Expr(1);
131 auto* m = MemberAccessor(e, Expr("a"));
132 auto* root = MemberAccessor(m, Expr("b"));
133 {
134 std::vector<const ast::Expression*> l2r;
135 TraverseExpressions<TraverseOrder::LeftToRight>(
136 root, Diagnostics(), [&](const ast::Expression* expr) {
137 l2r.push_back(expr);
138 return ast::TraverseAction::Descend;
139 });
140 EXPECT_THAT(l2r, ElementsAre(root, m, e));
141 }
142 {
143 std::vector<const ast::Expression*> r2l;
144 TraverseExpressions<TraverseOrder::RightToLeft>(
145 root, Diagnostics(), [&](const ast::Expression* expr) {
146 r2l.push_back(expr);
147 return ast::TraverseAction::Descend;
148 });
149 EXPECT_THAT(r2l, ElementsAre(root, m, e));
150 }
151 }
152
153 // TODO(crbug.com/tint/1257): The correct test for DescendMemberIndexExpression.
TEST_F(TraverseExpressionsTest,DISABLED_DescendMemberIndexExpression)154 TEST_F(TraverseExpressionsTest, DISABLED_DescendMemberIndexExpression) {
155 auto* e = Expr(1);
156 std::vector<const ast::IdentifierExpression*> i = {Expr("a"), Expr("b")};
157 auto* m = MemberAccessor(e, i[0]);
158 auto* root = MemberAccessor(m, i[1]);
159 {
160 std::vector<const ast::Expression*> l2r;
161 TraverseExpressions<TraverseOrder::LeftToRight>(
162 root, Diagnostics(), [&](const ast::Expression* expr) {
163 l2r.push_back(expr);
164 return ast::TraverseAction::Descend;
165 });
166 EXPECT_THAT(l2r, ElementsAre(root, m, e, i[0], i[1]));
167 }
168 {
169 std::vector<const ast::Expression*> r2l;
170 TraverseExpressions<TraverseOrder::RightToLeft>(
171 root, Diagnostics(), [&](const ast::Expression* expr) {
172 r2l.push_back(expr);
173 return ast::TraverseAction::Descend;
174 });
175 EXPECT_THAT(r2l, ElementsAre(root, i[1], m, i[0], e));
176 }
177 }
178
TEST_F(TraverseExpressionsTest,DescendUnaryExpression)179 TEST_F(TraverseExpressionsTest, DescendUnaryExpression) {
180 auto* e = Expr(1);
181 auto* u0 = AddressOf(e);
182 auto* u1 = Deref(u0);
183 auto* u2 = AddressOf(u1);
184 auto* root = Deref(u2);
185 {
186 std::vector<const ast::Expression*> l2r;
187 TraverseExpressions<TraverseOrder::LeftToRight>(
188 root, Diagnostics(), [&](const ast::Expression* expr) {
189 l2r.push_back(expr);
190 return ast::TraverseAction::Descend;
191 });
192 EXPECT_THAT(l2r, ElementsAre(root, u2, u1, u0, e));
193 }
194 {
195 std::vector<const ast::Expression*> r2l;
196 TraverseExpressions<TraverseOrder::RightToLeft>(
197 root, Diagnostics(), [&](const ast::Expression* expr) {
198 r2l.push_back(expr);
199 return ast::TraverseAction::Descend;
200 });
201 EXPECT_THAT(r2l, ElementsAre(root, u2, u1, u0, e));
202 }
203 }
204
TEST_F(TraverseExpressionsTest,Skip)205 TEST_F(TraverseExpressionsTest, Skip) {
206 std::vector<const ast::Expression*> e = {Expr(1), Expr(1), Expr(1), Expr(1)};
207 std::vector<const ast::Expression*> i = {IndexAccessor(e[0], e[1]),
208 IndexAccessor(e[2], e[3])};
209 auto* root = IndexAccessor(i[0], i[1]);
210 std::vector<const ast::Expression*> order;
211 TraverseExpressions<TraverseOrder::LeftToRight>(
212 root, Diagnostics(), [&](const ast::Expression* expr) {
213 order.push_back(expr);
214 return expr == i[0] ? ast::TraverseAction::Skip
215 : ast::TraverseAction::Descend;
216 });
217 EXPECT_THAT(order, ElementsAre(root, i[0], i[1], e[2], e[3]));
218 }
219
TEST_F(TraverseExpressionsTest,Stop)220 TEST_F(TraverseExpressionsTest, Stop) {
221 std::vector<const ast::Expression*> e = {Expr(1), Expr(1), Expr(1), Expr(1)};
222 std::vector<const ast::Expression*> i = {IndexAccessor(e[0], e[1]),
223 IndexAccessor(e[2], e[3])};
224 auto* root = IndexAccessor(i[0], i[1]);
225 std::vector<const ast::Expression*> order;
226 TraverseExpressions<TraverseOrder::LeftToRight>(
227 root, Diagnostics(), [&](const ast::Expression* expr) {
228 order.push_back(expr);
229 return expr == i[0] ? ast::TraverseAction::Stop
230 : ast::TraverseAction::Descend;
231 });
232 EXPECT_THAT(order, ElementsAre(root, i[0]));
233 }
234
235 } // namespace
236 } // namespace ast
237 } // namespace tint
238