1 /**
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
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
16 #include <gtest/gtest.h>
17 #include "compiler/lowering/phase.h"
18 #include "ir/astNodeHistory.h"
19
20 namespace ark::es2panda {
21
22 class NodeHistoryTest : public testing::Test {
23 public:
24 ~NodeHistoryTest() override = default;
25
SetUpTestCase()26 static void SetUpTestCase()
27 {
28 ark::mem::MemConfig::Initialize(0, 0, ark::es2panda::COMPILER_SIZE, 0, 0, 0);
29 ark::PoolManager::Initialize();
30 }
31
NodeHistoryTest()32 NodeHistoryTest()
33 {
34 allocator_ = std::make_unique<ArenaAllocator>(SpaceType::SPACE_TYPE_COMPILER);
35 phaseManager_ = std::make_unique<compiler::PhaseManager>(ScriptExtension::ETS, Allocator());
36 compiler::SetPhaseManager(phaseManager_.get());
37 }
38
39 NO_COPY_SEMANTIC(NodeHistoryTest);
40 NO_MOVE_SEMANTIC(NodeHistoryTest);
41
Allocator() const42 ArenaAllocator *Allocator() const
43 {
44 return allocator_.get();
45 }
46
PhaseManager() const47 compiler::PhaseManager *PhaseManager() const
48 {
49 return phaseManager_.get();
50 }
51
52 private:
53 std::unique_ptr<ArenaAllocator> allocator_;
54 std::unique_ptr<compiler::PhaseManager> phaseManager_;
55 };
56
57 constexpr int32_t PHASE_ID_0 = 0;
58 constexpr int32_t PHASE_ID_1 = 1;
59 constexpr int32_t PHASE_ID_2 = 2;
60 constexpr int32_t PHASE_ID_3 = 3;
61 constexpr int32_t PHASE_ID_4 = 4;
62 constexpr int32_t PHASE_ID_5 = 5;
63
64 constexpr int32_t INDEX_0 = 0;
65 constexpr int32_t INDEX_1 = 1;
66 constexpr int32_t INDEX_2 = 2;
67 constexpr int32_t INDEX_3 = 3;
68 constexpr int32_t INDEX_4 = 4;
69
70 constexpr int32_t VALUE_0 = 0;
71 constexpr int32_t VALUE_1 = 1;
72 constexpr int32_t VALUE_2 = 2;
73 constexpr int32_t VALUE_3 = 3;
74 constexpr int32_t VALUE_4 = 4;
75
76 constexpr int32_t SIZE_5 = 5;
77
78 // CC-OFFNXT(huge_method, G.FUN.01-CPP, G.FUD.05) solid logic
TEST_F(NodeHistoryTest,DoubleLinkedList)79 TEST_F(NodeHistoryTest, DoubleLinkedList)
80 {
81 util::ArenaDoubleLinkedList<int> list {Allocator()};
82
83 ASSERT_EQ(list.Head(), nullptr);
84 ASSERT_EQ(list.Tail(), nullptr);
85 ASSERT_TRUE(list.Empty());
86
87 // Make list: (1,2,4,0,3)
88 std::array<int, SIZE_5> data = {VALUE_0, VALUE_1, VALUE_2, VALUE_3, VALUE_4};
89
90 auto item4 = list.Append(data[INDEX_4]);
91 auto item0 = list.Append(data[INDEX_0]);
92 auto item3 = list.Insert(item0, data[INDEX_3]);
93 auto item1 = list.Prepend(data[INDEX_1]);
94 auto item2 = list.Insert(item1, data[INDEX_2]);
95
96 ASSERT_FALSE(list.Empty());
97
98 ASSERT_EQ(item0->data, data[INDEX_0]);
99 ASSERT_EQ(item1->data, data[INDEX_1]);
100 ASSERT_EQ(item2->data, data[INDEX_2]);
101 ASSERT_EQ(item3->data, data[INDEX_3]);
102 ASSERT_EQ(item4->data, data[INDEX_4]);
103
104 ASSERT_EQ(list.Head(), item1);
105 ASSERT_EQ(item1->next, item2);
106 ASSERT_EQ(item2->next, item4);
107 ASSERT_EQ(item4->next, item0);
108 ASSERT_EQ(item0->next, item3);
109 ASSERT_EQ(item3, list.Tail());
110 ASSERT_EQ(list.Tail()->next, nullptr);
111
112 ASSERT_EQ(item3->prev, item0);
113 ASSERT_EQ(item0->prev, item4);
114 ASSERT_EQ(item4->prev, item2);
115 ASSERT_EQ(item2->prev, item1);
116 ASSERT_EQ(item1->prev, nullptr);
117
118 ASSERT_EQ(item2->prev->next, item2);
119 ASSERT_EQ(item4->prev->next, item4);
120 ASSERT_EQ(item0->prev->next, item0);
121
122 ASSERT_EQ(item2->next->prev, item2);
123 ASSERT_EQ(item4->next->prev, item4);
124 ASSERT_EQ(item0->next->prev, item0);
125
126 list.Erase(item4);
127 ASSERT_EQ(item2->next, item0);
128 ASSERT_EQ(item0->prev, item2);
129
130 list.Erase(item0);
131 ASSERT_EQ(item2->next, item3);
132 ASSERT_EQ(item3->prev, item2);
133
134 list.Erase(list.Tail());
135 ASSERT_EQ(list.Tail(), item2);
136 ASSERT_EQ(item2->next, nullptr);
137 ASSERT_EQ(item2->prev, item1);
138
139 list.Erase(list.Head());
140 ASSERT_EQ(list.Head(), item2);
141 ASSERT_EQ(item2->next, nullptr);
142 ASSERT_EQ(item2->prev, nullptr);
143
144 list.Erase(item2);
145 ASSERT_EQ(list.Head(), nullptr);
146 ASSERT_EQ(list.Tail(), nullptr);
147 ASSERT_TRUE(list.Empty());
148 }
149
TEST_F(NodeHistoryTest,HistoryAt)150 TEST_F(NodeHistoryTest, HistoryAt)
151 {
152 ASSERT_EQ(PhaseManager()->CurrentPhaseId(), compiler::PARSER_PHASE_ID);
153
154 PhaseManager()->SetCurrentPhaseId(PHASE_ID_0);
155 auto identifier = Allocator()->New<ir::Identifier>(Allocator())->AsIdentifier();
156 auto history = Allocator()->New<ir::AstNodeHistory>(identifier, PhaseManager()->CurrentPhaseId(), Allocator());
157
158 ASSERT_EQ(history->At(compiler::PARSER_PHASE_ID), nullptr);
159 ASSERT_EQ(history->At(PHASE_ID_0), identifier);
160 ASSERT_EQ(history->At(PHASE_ID_1), nullptr);
161 }
162
TEST_F(NodeHistoryTest,HistoryGet)163 TEST_F(NodeHistoryTest, HistoryGet)
164 {
165 ASSERT_EQ(PhaseManager()->CurrentPhaseId(), compiler::PARSER_PHASE_ID);
166
167 PhaseManager()->SetCurrentPhaseId(PHASE_ID_0);
168 auto identifier = Allocator()->New<ir::Identifier>(Allocator())->AsIdentifier();
169 auto history = Allocator()->New<ir::AstNodeHistory>(identifier, PhaseManager()->CurrentPhaseId(), Allocator());
170
171 ASSERT_EQ(history->Get(compiler::PARSER_PHASE_ID), nullptr);
172 ASSERT_EQ(history->Get(PHASE_ID_0), identifier);
173 ASSERT_EQ(history->Get(PHASE_ID_1), identifier);
174 ASSERT_EQ(history->Get(PHASE_ID_2), identifier);
175 ASSERT_EQ(history->Get(PHASE_ID_3), identifier);
176 }
177
178 // CC-OFFNXT(huge_method, G.FUN.01-CPP, G.FUD.05) solid logic
TEST_F(NodeHistoryTest,HistorySet)179 TEST_F(NodeHistoryTest, HistorySet)
180 {
181 ASSERT_EQ(PhaseManager()->CurrentPhaseId(), compiler::PARSER_PHASE_ID);
182
183 PhaseManager()->SetCurrentPhaseId(PHASE_ID_0);
184 auto identifier0 = Allocator()->New<ir::Identifier>(Allocator())->AsIdentifier();
185 auto history = Allocator()->New<ir::AstNodeHistory>(identifier0, PhaseManager()->CurrentPhaseId(), Allocator());
186
187 PhaseManager()->SetCurrentPhaseId(PHASE_ID_1);
188 auto identifier1 = Allocator()->New<ir::Identifier>(Allocator())->AsIdentifier();
189 history->Set(identifier1, PhaseManager()->CurrentPhaseId());
190
191 PhaseManager()->SetCurrentPhaseId(PHASE_ID_2);
192 auto identifier2 = Allocator()->New<ir::Identifier>(Allocator())->AsIdentifier();
193 history->Set(identifier2, PhaseManager()->CurrentPhaseId());
194
195 PhaseManager()->SetCurrentPhaseId(PHASE_ID_3);
196 history->Set(nullptr, PhaseManager()->CurrentPhaseId());
197
198 // Search forward
199 ASSERT_EQ(history->Get(compiler::PARSER_PHASE_ID), nullptr);
200 ASSERT_EQ(history->Get(PHASE_ID_0), identifier0);
201 ASSERT_EQ(history->Get(PHASE_ID_1), identifier1);
202 ASSERT_EQ(history->Get(PHASE_ID_2), identifier2);
203 ASSERT_EQ(history->Get(PHASE_ID_3), nullptr);
204 ASSERT_EQ(history->Get(PHASE_ID_4), nullptr);
205 ASSERT_EQ(history->Get(PHASE_ID_5), nullptr);
206
207 // Search backward
208 ASSERT_EQ(history->Get(PHASE_ID_5), nullptr);
209 ASSERT_EQ(history->Get(PHASE_ID_4), nullptr);
210 ASSERT_EQ(history->Get(PHASE_ID_3), nullptr);
211 ASSERT_EQ(history->Get(PHASE_ID_2), identifier2);
212 ASSERT_EQ(history->Get(PHASE_ID_1), identifier1);
213 ASSERT_EQ(history->Get(PHASE_ID_0), identifier0);
214 ASSERT_EQ(history->Get(compiler::PARSER_PHASE_ID), nullptr);
215
216 // Search random
217 ASSERT_EQ(history->Get(PHASE_ID_1), identifier1);
218 ASSERT_EQ(history->Get(PHASE_ID_5), nullptr);
219 ASSERT_EQ(history->Get(PHASE_ID_2), identifier2);
220 ASSERT_EQ(history->Get(PHASE_ID_4), nullptr);
221 ASSERT_EQ(history->Get(PHASE_ID_0), identifier0);
222 ASSERT_EQ(history->Get(compiler::PARSER_PHASE_ID), nullptr);
223 ASSERT_EQ(history->Get(PHASE_ID_3), nullptr);
224
225 // Search precise
226 ASSERT_EQ(history->At(compiler::PARSER_PHASE_ID), nullptr);
227 ASSERT_EQ(history->At(PHASE_ID_0), identifier0);
228 ASSERT_EQ(history->At(PHASE_ID_1), identifier1);
229 ASSERT_EQ(history->At(PHASE_ID_2), identifier2);
230 ASSERT_EQ(history->At(PHASE_ID_3), nullptr);
231 ASSERT_EQ(history->At(PHASE_ID_4), nullptr);
232 ASSERT_EQ(history->At(PHASE_ID_5), nullptr);
233 }
234
TEST_F(NodeHistoryTest,HistoryReplace)235 TEST_F(NodeHistoryTest, HistoryReplace)
236 {
237 ASSERT_EQ(PhaseManager()->CurrentPhaseId(), compiler::PARSER_PHASE_ID);
238
239 PhaseManager()->SetCurrentPhaseId(PHASE_ID_0);
240 auto identifier0Orig = Allocator()->New<ir::Identifier>(Allocator())->AsIdentifier();
241 auto history = Allocator()->New<ir::AstNodeHistory>(identifier0Orig, PhaseManager()->CurrentPhaseId(), Allocator());
242
243 PhaseManager()->SetCurrentPhaseId(PHASE_ID_1);
244 auto identifier1Orig = Allocator()->New<ir::Identifier>(Allocator())->AsIdentifier();
245 history->Set(identifier1Orig, PhaseManager()->CurrentPhaseId());
246
247 ASSERT_EQ(history->Get(compiler::PARSER_PHASE_ID), nullptr);
248 ASSERT_EQ(history->Get(PHASE_ID_0), identifier0Orig);
249 ASSERT_EQ(history->Get(PHASE_ID_1), identifier1Orig);
250 ASSERT_EQ(history->Get(PHASE_ID_2), identifier1Orig);
251 ASSERT_EQ(history->Get(PHASE_ID_3), identifier1Orig);
252
253 ASSERT_EQ(history->At(compiler::PARSER_PHASE_ID), nullptr);
254 ASSERT_EQ(history->At(PHASE_ID_0), identifier0Orig);
255 ASSERT_EQ(history->At(PHASE_ID_1), identifier1Orig);
256 ASSERT_EQ(history->At(PHASE_ID_2), nullptr);
257
258 PhaseManager()->SetCurrentPhaseId(PHASE_ID_0);
259 auto identifier0New = Allocator()->New<ir::Identifier>(Allocator())->AsIdentifier();
260 history->Set(identifier0New, PhaseManager()->CurrentPhaseId());
261
262 PhaseManager()->SetCurrentPhaseId(PHASE_ID_1);
263 auto identifier1New = Allocator()->New<ir::Identifier>(Allocator())->AsIdentifier();
264 history->Set(identifier1New, PhaseManager()->CurrentPhaseId());
265
266 PhaseManager()->SetCurrentPhaseId(PHASE_ID_2);
267 history->Set(nullptr, PhaseManager()->CurrentPhaseId());
268
269 ASSERT_EQ(history->Get(compiler::PARSER_PHASE_ID), nullptr);
270 ASSERT_EQ(history->Get(PHASE_ID_0), identifier0New);
271 ASSERT_EQ(history->Get(PHASE_ID_1), identifier1New);
272 ASSERT_EQ(history->Get(PHASE_ID_2), nullptr);
273 ASSERT_EQ(history->Get(PHASE_ID_3), nullptr);
274
275 ASSERT_EQ(history->At(compiler::PARSER_PHASE_ID), nullptr);
276 ASSERT_EQ(history->At(PHASE_ID_0), identifier0New);
277 ASSERT_EQ(history->At(PHASE_ID_1), identifier1New);
278 ASSERT_EQ(history->At(PHASE_ID_2), nullptr);
279 }
280
NewClassDefinition(ArenaAllocator * allocator)281 ir::ClassDefinition *NewClassDefinition(ArenaAllocator *allocator)
282 {
283 ArenaVector<ir::AstNode *> body {allocator->Adapter()};
284 return allocator
285 ->New<ir::ClassDefinition>(allocator, nullptr, std::move(body), ir::ClassDefinitionModifiers::NONE,
286 ir::ModifierFlags::NONE, Language::Id::ETS)
287 ->AsClassDefinition();
288 }
289
290 /// NOTE(mivanov): To be enabled after #24153/#24424 implemented
TEST_F(NodeHistoryTest,DISABLED_UpdateField)291 TEST_F(NodeHistoryTest, DISABLED_UpdateField)
292 {
293 ASSERT_EQ(PhaseManager()->CurrentPhaseId(), compiler::PARSER_PHASE_ID);
294
295 auto definition = NewClassDefinition(Allocator());
296 ASSERT_FALSE(definition->IsAbstract());
297 definition->ClearModifier(ir::ModifierFlags::ABSTRACT);
298 ASSERT_FALSE(definition->IsAbstract());
299 definition->AddModifier(ir::ModifierFlags::FINAL);
300 ASSERT_TRUE(definition->IsFinal());
301
302 PhaseManager()->SetCurrentPhaseId(PHASE_ID_0);
303 definition->AddModifier(ir::ModifierFlags::ABSTRACT);
304 ASSERT_TRUE(definition->IsAbstract());
305 definition->ClearModifier(ir::ModifierFlags::FINAL);
306 ASSERT_FALSE(definition->IsFinal());
307
308 PhaseManager()->SetCurrentPhaseId(PHASE_ID_1);
309 definition->ClearModifier(ir::ModifierFlags::ABSTRACT);
310 ASSERT_FALSE(definition->IsAbstract());
311 definition->AddModifier(ir::ModifierFlags::FINAL);
312 ASSERT_TRUE(definition->IsFinal());
313
314 PhaseManager()->SetCurrentPhaseId(PHASE_ID_2);
315 definition->ClearModifier(ir::ModifierFlags::FINAL);
316 ASSERT_FALSE(definition->IsFinal());
317
318 PhaseManager()->Restart();
319 ASSERT_FALSE(definition->IsAbstract());
320 ASSERT_TRUE(definition->IsFinal());
321
322 PhaseManager()->SetCurrentPhaseId(PHASE_ID_0);
323 ASSERT_TRUE(definition->IsAbstract());
324 ASSERT_FALSE(definition->IsFinal());
325
326 PhaseManager()->SetCurrentPhaseId(PHASE_ID_1);
327 ASSERT_FALSE(definition->IsAbstract());
328 ASSERT_TRUE(definition->IsFinal());
329
330 PhaseManager()->SetCurrentPhaseId(PHASE_ID_2);
331 ASSERT_FALSE(definition->IsAbstract());
332 ASSERT_FALSE(definition->IsFinal());
333 }
334
335 /// NOTE(mivanov): To be enabled after #24153/#24424 implemented
TEST_F(NodeHistoryTest,DISABLED_UpdateChild)336 TEST_F(NodeHistoryTest, DISABLED_UpdateChild)
337 {
338 ASSERT_EQ(PhaseManager()->CurrentPhaseId(), compiler::PARSER_PHASE_ID);
339
340 auto declaration =
341 Allocator()->New<ir::ClassDeclaration>(NewClassDefinition(Allocator()), Allocator())->AsClassDeclaration();
342 ASSERT_EQ(declaration->Definition()->Ident(), nullptr);
343
344 PhaseManager()->SetCurrentPhaseId(PHASE_ID_0);
345 auto identifier0 = Allocator()->New<ir::Identifier>(Allocator())->AsIdentifier();
346 declaration->Definition()->SetIdent(identifier0);
347 ASSERT_EQ(declaration->Definition()->Ident(), identifier0);
348
349 PhaseManager()->SetCurrentPhaseId(PHASE_ID_1);
350 auto identifier1 = Allocator()->New<ir::Identifier>(Allocator())->AsIdentifier();
351 declaration->Definition()->SetIdent(identifier1);
352 ASSERT_EQ(declaration->Definition()->Ident(), identifier1);
353
354 PhaseManager()->SetCurrentPhaseId(PHASE_ID_2);
355 declaration->Definition()->SetIdent(nullptr);
356 ASSERT_EQ(declaration->Definition()->Ident(), nullptr);
357
358 PhaseManager()->Restart();
359 ASSERT_EQ(declaration->Definition()->Ident(), nullptr);
360
361 PhaseManager()->SetCurrentPhaseId(PHASE_ID_0);
362 ASSERT_EQ(declaration->Definition()->Ident(), identifier0);
363
364 PhaseManager()->SetCurrentPhaseId(PHASE_ID_1);
365 ASSERT_EQ(declaration->Definition()->Ident(), identifier1);
366
367 PhaseManager()->SetCurrentPhaseId(PHASE_ID_2);
368 ASSERT_EQ(declaration->Definition()->Ident(), nullptr);
369 }
370 } // namespace ark::es2panda
371