1 /**
2 * Copyright (c) 2024 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
18 #include "assembler/assembly-program.h"
19 #include "es2panda.h"
20 #include "generated/signatures.h"
21 #include "libpandabase/mem/mem.h"
22 #include "macros.h"
23 #include "mem/pool_manager.h"
24 #include "util/options.h"
25
26 namespace ark::es2panda::compiler::test {
27
28 class RestParameterTest : public testing::Test {
29 public:
RestParameterTest()30 RestParameterTest()
31 {
32 const auto compilerSize = 268435456;
33
34 mem::MemConfig::Initialize(0, 0, compilerSize, 0, 0, 0);
35 PoolManager::Initialize(PoolType::MMAP);
36 }
37 ~RestParameterTest() override
38 {
39 PoolManager::Finalize();
40 mem::MemConfig::Finalize();
41 }
42
SetCurrentProgram(std::string_view src)43 void SetCurrentProgram(std::string_view src)
44 {
45 int argc = 1;
46 const char *argv = "../../../../bin/es2panda"; // NOLINT(modernize-avoid-c-arrays)
47 static constexpr std::string_view FILE_NAME = "dummy.sts";
48
49 program_ = GetProgram(argc, &argv, FILE_NAME, src);
50 ASSERT_NE(program_.get(), nullptr);
51 }
52
CheckRestParameterFlag(std::string_view functionName)53 void CheckRestParameterFlag(std::string_view functionName)
54 {
55 pandasm::Function *fn = GetFunction(functionName);
56 ASSERT_TRUE(fn != nullptr) << "Function '" << functionName << "' not found";
57 ASSERT_TRUE(HasRestParameterFlag(fn)) << "Function '" << fn->name << "' doesn't have ACC_VARARGS flag";
58 }
59
CheckNoRestParameterFlag(std::string_view functionName)60 void CheckNoRestParameterFlag(std::string_view functionName)
61 {
62 pandasm::Function *fn = GetFunction(functionName);
63 ASSERT_TRUE(fn != nullptr) << "Function '" << functionName << "' not found";
64 ASSERT_FALSE(HasRestParameterFlag(fn)) << "Function '" << fn->name << "' has ACC_VARARGS flag";
65 }
66
67 private:
HasRestParameterFlag(pandasm::Function *fn)68 bool HasRestParameterFlag(pandasm::Function *fn)
69 {
70 return (fn->metadata->GetAccessFlags() & ACC_VARARGS) != 0;
71 }
72
73 NO_COPY_SEMANTIC(RestParameterTest);
74 NO_MOVE_SEMANTIC(RestParameterTest);
75
GetProgram(int argc, const char **argv, std::string_view fileName, std::string_view src)76 static std::unique_ptr<pandasm::Program> GetProgram(int argc, const char **argv, std::string_view fileName,
77 std::string_view src)
78 {
79 auto options = std::make_unique<es2panda::util::Options>();
80 if (!options->Parse(argc, argv)) {
81 std::cerr << options->ErrorMsg() << std::endl;
82 return nullptr;
83 }
84
85 Logger::ComponentMask mask {};
86 mask.set(Logger::Component::ES2PANDA);
87 Logger::InitializeStdLogging(Logger::LevelFromString(options->LogLevel()), mask);
88
89 es2panda::Compiler compiler(options->Extension(), options->ThreadCount());
90 es2panda::SourceFile input(fileName, src, options->ParseModule());
91
92 return std::unique_ptr<pandasm::Program>(compiler.Compile(input, *options));
93 }
94
GetFunction(std::string_view functionName)95 pandasm::Function *GetFunction(std::string_view functionName)
96 {
97 auto it = program_->functionTable.find(functionName.data());
98 if (it == program_->functionTable.end()) {
99 return nullptr;
100 }
101 return &it->second;
102 }
103
104 private:
105 std::unique_ptr<pandasm::Program> program_ {};
106 };
107
108 // === Function ===
TEST_F(RestParameterTest, function_without_rest_parameters_0)109 TEST_F(RestParameterTest, function_without_rest_parameters_0)
110 {
111 SetCurrentProgram(R"(
112 function fn(): void {
113 }
114 )");
115 CheckNoRestParameterFlag("ETSGLOBAL.fn:void;");
116 }
117
TEST_F(RestParameterTest, function_without_rest_parameters_1)118 TEST_F(RestParameterTest, function_without_rest_parameters_1)
119 {
120 SetCurrentProgram(R"(
121 function fn(args: int[]): void {
122 }
123 )");
124 CheckNoRestParameterFlag("ETSGLOBAL.fn:i32[];void;");
125 }
126
TEST_F(RestParameterTest, function_without_rest_parameters_2)127 TEST_F(RestParameterTest, function_without_rest_parameters_2)
128 {
129 SetCurrentProgram(R"(
130 function fn(arg0: int, args: String[]): void {
131 }
132 )");
133 CheckNoRestParameterFlag("ETSGLOBAL.fn:i32;std.core.String[];void;");
134 }
135
TEST_F(RestParameterTest, function_with_rest_parameter_0)136 TEST_F(RestParameterTest, function_with_rest_parameter_0)
137 {
138 SetCurrentProgram(R"(
139 function fn(...args: String[]): void {
140 }
141 )");
142 CheckRestParameterFlag("ETSGLOBAL.fn:std.core.String[];void;");
143 }
144
TEST_F(RestParameterTest, function_with_rest_parameter_1)145 TEST_F(RestParameterTest, function_with_rest_parameter_1)
146 {
147 SetCurrentProgram(R"(
148 function fn(o: Object, ...args: int[]): void {
149 }
150 )");
151 CheckRestParameterFlag("ETSGLOBAL.fn:std.core.Object;i32[];void;");
152 }
153
154 // === Method of class ===
TEST_F(RestParameterTest, class_method_without_rest_parameters_0)155 TEST_F(RestParameterTest, class_method_without_rest_parameters_0)
156 {
157 SetCurrentProgram(R"(
158 class A {
159 fn() {};
160 }
161 )");
162 CheckNoRestParameterFlag("A.fn:void;");
163 }
164
TEST_F(RestParameterTest, class_method_without_rest_parameters_1)165 TEST_F(RestParameterTest, class_method_without_rest_parameters_1)
166 {
167 SetCurrentProgram(R"(
168 class A {
169 fn(arg0: int) {};
170 }
171 )");
172 CheckNoRestParameterFlag("A.fn:i32;void;");
173 }
174
TEST_F(RestParameterTest, class_method_with_rest_parameters_0)175 TEST_F(RestParameterTest, class_method_with_rest_parameters_0)
176 {
177 SetCurrentProgram(R"(
178 class A {
179 fn(...args: int[]) {};
180 }
181 )");
182 CheckRestParameterFlag("A.fn:i32[];void;");
183 }
184
185 // === Static method of class ===
TEST_F(RestParameterTest, static_class_method_without_rest_parameters_0)186 TEST_F(RestParameterTest, static_class_method_without_rest_parameters_0)
187 {
188 SetCurrentProgram(R"(
189 class A {
190 static fn() {};
191 }
192 )");
193 CheckNoRestParameterFlag("A.fn:void;");
194 }
195
TEST_F(RestParameterTest, static_class_method_without_rest_parameters_1)196 TEST_F(RestParameterTest, static_class_method_without_rest_parameters_1)
197 {
198 SetCurrentProgram(R"(
199 class A {
200 static fn(arg0: int) {};
201 }
202 )");
203 CheckNoRestParameterFlag("A.fn:i32;void;");
204 }
205
TEST_F(RestParameterTest, static_class_method_with_rest_parameters_0)206 TEST_F(RestParameterTest, static_class_method_with_rest_parameters_0)
207 {
208 SetCurrentProgram(R"(
209 class A {
210 static fn(...args: int[]) {};
211 }
212 )");
213 CheckRestParameterFlag("A.fn:i32[];void;");
214 }
215
TEST_F(RestParameterTest, static_class_method_with_rest_parameters_1)216 TEST_F(RestParameterTest, static_class_method_with_rest_parameters_1)
217 {
218 SetCurrentProgram(R"(
219 class A {
220 static fn(a: String[], ...args: int[]) {};
221 }
222 )");
223 CheckRestParameterFlag("A.fn:std.core.String[];i32[];void;");
224 }
225
226 // === Constructor of class ===
TEST_F(RestParameterTest, class_constructor_without_rest_parameters_0)227 TEST_F(RestParameterTest, class_constructor_without_rest_parameters_0)
228 {
229 SetCurrentProgram(R"(
230 class A {
231 constructor() {};
232 }
233 )");
234 CheckNoRestParameterFlag("A.<ctor>:void;");
235 }
236
TEST_F(RestParameterTest, class_constructor_without_rest_parameters_1)237 TEST_F(RestParameterTest, class_constructor_without_rest_parameters_1)
238 {
239 SetCurrentProgram(R"(
240 class A {
241 constructor(args: String[]) {};
242 }
243 )");
244 CheckNoRestParameterFlag("A.<ctor>:std.core.String[];void;");
245 }
246
TEST_F(RestParameterTest, class_constructor_with_rest_parameters_0)247 TEST_F(RestParameterTest, class_constructor_with_rest_parameters_0)
248 {
249 SetCurrentProgram(R"(
250 class A {
251 constructor(...args: int[]) {};
252 }
253 )");
254 CheckRestParameterFlag("A.<ctor>:i32[];void;");
255 }
256
TEST_F(RestParameterTest, class_constructor_with_rest_parameters_1)257 TEST_F(RestParameterTest, class_constructor_with_rest_parameters_1)
258 {
259 SetCurrentProgram(R"(
260 class A {
261 constructor(v0: long, ...args: String[]) {};
262 }
263 )");
264 CheckRestParameterFlag("A.<ctor>:i64;std.core.String[];void;");
265 }
266
267 // === Method of interface ===
TEST_F(RestParameterTest, interface_without_rest_parameters_0)268 TEST_F(RestParameterTest, interface_without_rest_parameters_0)
269 {
270 SetCurrentProgram(R"(
271 interface A {
272 fn() {};
273 }
274 )");
275 CheckNoRestParameterFlag("A.fn:void;");
276 }
277
TEST_F(RestParameterTest, interface_without_rest_parameters_1)278 TEST_F(RestParameterTest, interface_without_rest_parameters_1)
279 {
280 SetCurrentProgram(R"(
281 interface A {
282 fn(args: String[]) {};
283 }
284 )");
285 CheckNoRestParameterFlag("A.fn:std.core.String[];void;");
286 }
287
TEST_F(RestParameterTest, interface_with_rest_parameters_0)288 TEST_F(RestParameterTest, interface_with_rest_parameters_0)
289 {
290 SetCurrentProgram(R"(
291 interface A {
292 fn(...args: Object[]) {};
293 }
294 )");
295 CheckRestParameterFlag("A.fn:std.core.Object[];void;");
296 }
297
TEST_F(RestParameterTest, interface_with_rest_parameters_1)298 TEST_F(RestParameterTest, interface_with_rest_parameters_1)
299 {
300 SetCurrentProgram(R"(
301 interface A {
302 fn(o: Object, ...args: String[]) {};
303 }
304 )");
305 CheckRestParameterFlag("A.fn:std.core.Object;std.core.String[];void;");
306 }
307
308 // === Lambda method ===
TEST_F(RestParameterTest, lambda_without_rest_parameters_0)309 TEST_F(RestParameterTest, lambda_without_rest_parameters_0)
310 {
311 SetCurrentProgram(R"(
312 let fn: ()=>int = (): int => {
313 return 1;
314 }
315 )");
316 CheckNoRestParameterFlag("LambdaObject-ETSGLOBAL$lambda$invoke$0.invoke:i32;");
317 }
318
TEST_F(RestParameterTest, lambda_without_rest_parameters_1)319 TEST_F(RestParameterTest, lambda_without_rest_parameters_1)
320 {
321 SetCurrentProgram(R"(
322 let fn: (args: long[])=>int = (args: long[]): int => {
323 return 1;
324 }
325 )");
326 CheckNoRestParameterFlag("LambdaObject-ETSGLOBAL$lambda$invoke$0.invoke:i64[];i32;");
327 }
328
329 // === Abstract method of abstract class ===
TEST_F(RestParameterTest, abstract_function_without_rest_parameter_0)330 TEST_F(RestParameterTest, abstract_function_without_rest_parameter_0)
331 {
332 SetCurrentProgram(R"(
333 abstract class A {
334 abstract fn(): void
335 }
336 )");
337 CheckNoRestParameterFlag("A.fn:void;");
338 }
339
TEST_F(RestParameterTest, abstract_function_without_rest_parameter_1)340 TEST_F(RestParameterTest, abstract_function_without_rest_parameter_1)
341 {
342 SetCurrentProgram(R"(
343 abstract class A {
344 abstract fn(args: String[]): void
345 }
346 )");
347 CheckNoRestParameterFlag("A.fn:std.core.String[];void;");
348 }
349
TEST_F(RestParameterTest, abstract_function_with_rest_parameter_0)350 TEST_F(RestParameterTest, abstract_function_with_rest_parameter_0)
351 {
352 SetCurrentProgram(R"(
353 abstract class A {
354 abstract fn(...args: String[]): void
355 }
356 )");
357 CheckRestParameterFlag("A.fn:std.core.String[];void;");
358 }
359
TEST_F(RestParameterTest, abstract_function_with_rest_parameter_1)360 TEST_F(RestParameterTest, abstract_function_with_rest_parameter_1)
361 {
362 SetCurrentProgram(R"(
363 abstract class A {
364 abstract fn(v: int, ...args: String[]): void
365 }
366 )");
367 CheckRestParameterFlag("A.fn:i32;std.core.String[];void;");
368 }
369
370 // === External methods ===
TEST_F(RestParameterTest, external_function_with_rest_parameter_0)371 TEST_F(RestParameterTest, external_function_with_rest_parameter_0)
372 {
373 SetCurrentProgram("");
374 CheckRestParameterFlag("std.core.LambdaValue.invoke:std.core.Object[];std.core.Object;");
375 }
376
TEST_F(RestParameterTest, external_function_with_rest_parameter_1)377 TEST_F(RestParameterTest, external_function_with_rest_parameter_1)
378 {
379 SetCurrentProgram("");
380 CheckRestParameterFlag("escompat.Math.max:f64[];f64;");
381 }
382
383 } // namespace ark::es2panda::compiler::test
384