1 /**
2 * Copyright (c) 2024-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
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 "test/utils/asm_test.h"
25
26 namespace ark::es2panda::compiler::test {
27
28 class RestParameterTest : public ::test::utils::AsmTest {
29 public:
30 RestParameterTest() = default;
31
32 ~RestParameterTest() override = default;
33
CheckRestParameterFlag(std::string_view functionName,bool isStatic)34 void CheckRestParameterFlag(std::string_view functionName, bool isStatic)
35 {
36 pandasm::Function *fn =
37 GetFunction(functionName, isStatic ? program_->functionStaticTable : program_->functionInstanceTable);
38 ASSERT_TRUE(fn != nullptr) << "Function '" << functionName << "' not found";
39 ASSERT_TRUE(HasRestParameterFlag(fn)) << "Function '" << fn->name << "' doesn't have ACC_VARARGS flag";
40 }
41
CheckNoRestParameterFlag(std::string_view functionName,bool isStatic)42 void CheckNoRestParameterFlag(std::string_view functionName, bool isStatic)
43 {
44 pandasm::Function *fn =
45 GetFunction(functionName, isStatic ? program_->functionStaticTable : program_->functionInstanceTable);
46 ASSERT_TRUE(fn != nullptr) << "Function '" << functionName << "' not found";
47 ASSERT_FALSE(HasRestParameterFlag(fn)) << "Function '" << fn->name << "' has ACC_VARARGS flag";
48 }
49
50 private:
HasRestParameterFlag(pandasm::Function * fn)51 bool HasRestParameterFlag(pandasm::Function *fn)
52 {
53 return (fn->metadata->GetAccessFlags() & ACC_VARARGS) != 0;
54 }
55
56 NO_COPY_SEMANTIC(RestParameterTest);
57 NO_MOVE_SEMANTIC(RestParameterTest);
58 };
59
60 // === Function ===
TEST_F(RestParameterTest,function_without_rest_parameters_0)61 TEST_F(RestParameterTest, function_without_rest_parameters_0)
62 {
63 SetCurrentProgram(R"(
64 function fn(): void {
65 }
66 )");
67 CheckNoRestParameterFlag("dummy.ETSGLOBAL.fn:void;", true);
68 }
69
TEST_F(RestParameterTest,function_without_rest_parameters_1)70 TEST_F(RestParameterTest, function_without_rest_parameters_1)
71 {
72 SetCurrentProgram(R"(
73 function fn(args: FixedArray<int>): void {
74 }
75 )");
76 CheckNoRestParameterFlag("dummy.ETSGLOBAL.fn:i32[];void;", true);
77 }
78
TEST_F(RestParameterTest,function_without_rest_parameters_2)79 TEST_F(RestParameterTest, function_without_rest_parameters_2)
80 {
81 SetCurrentProgram(R"(
82 function fn(arg0: int, args: FixedArray<String>): void {
83 }
84 )");
85 CheckNoRestParameterFlag("dummy.ETSGLOBAL.fn:i32;std.core.String[];void;", true);
86 }
87
TEST_F(RestParameterTest,function_with_rest_parameter_0)88 TEST_F(RestParameterTest, function_with_rest_parameter_0)
89 {
90 SetCurrentProgram(R"(
91 function fn(...args: FixedArray<String>): void {
92 }
93 )");
94 CheckRestParameterFlag("dummy.ETSGLOBAL.fn:std.core.String[];void;", true);
95 }
96
TEST_F(RestParameterTest,function_with_rest_parameter_1)97 TEST_F(RestParameterTest, function_with_rest_parameter_1)
98 {
99 SetCurrentProgram(R"(
100 function fn(o: Object, ...args: FixedArray<int>): void {
101 }
102 )");
103 CheckRestParameterFlag("dummy.ETSGLOBAL.fn:std.core.Object;i32[];void;", true);
104 }
105
106 // === Method of class ===
TEST_F(RestParameterTest,class_method_without_rest_parameters_0)107 TEST_F(RestParameterTest, class_method_without_rest_parameters_0)
108 {
109 SetCurrentProgram(R"(
110 class A {
111 fn() {};
112 }
113 )");
114 CheckNoRestParameterFlag("dummy.A.fn:void;", false);
115 }
116
TEST_F(RestParameterTest,class_method_without_rest_parameters_1)117 TEST_F(RestParameterTest, class_method_without_rest_parameters_1)
118 {
119 SetCurrentProgram(R"(
120 class A {
121 fn(arg0: int) {};
122 }
123 )");
124 CheckNoRestParameterFlag("dummy.A.fn:i32;void;", false);
125 }
126
TEST_F(RestParameterTest,class_method_with_rest_parameters_0)127 TEST_F(RestParameterTest, class_method_with_rest_parameters_0)
128 {
129 SetCurrentProgram(R"(
130 class A {
131 fn(...args: FixedArray<int>) {};
132 }
133 )");
134 CheckRestParameterFlag("dummy.A.fn:i32[];void;", false);
135 }
136
137 // === Static method of class ===
TEST_F(RestParameterTest,static_class_method_without_rest_parameters_0)138 TEST_F(RestParameterTest, static_class_method_without_rest_parameters_0)
139 {
140 SetCurrentProgram(R"(
141 class A {
142 static fn() {};
143 }
144 )");
145 CheckNoRestParameterFlag("dummy.A.fn:void;", true);
146 }
147
TEST_F(RestParameterTest,static_class_method_without_rest_parameters_1)148 TEST_F(RestParameterTest, static_class_method_without_rest_parameters_1)
149 {
150 SetCurrentProgram(R"(
151 class A {
152 static fn(arg0: int) {};
153 }
154 )");
155 CheckNoRestParameterFlag("dummy.A.fn:i32;void;", true);
156 }
157
TEST_F(RestParameterTest,static_class_method_with_rest_parameters_0)158 TEST_F(RestParameterTest, static_class_method_with_rest_parameters_0)
159 {
160 SetCurrentProgram(R"(
161 class A {
162 static fn(...args: FixedArray<int>) {};
163 }
164 )");
165 CheckRestParameterFlag("dummy.A.fn:i32[];void;", true);
166 }
167
TEST_F(RestParameterTest,static_class_method_with_rest_parameters_1)168 TEST_F(RestParameterTest, static_class_method_with_rest_parameters_1)
169 {
170 SetCurrentProgram(R"(
171 class A {
172 static fn(a: FixedArray<String>, ...args: FixedArray<int>) {};
173 }
174 )");
175 CheckRestParameterFlag("dummy.A.fn:std.core.String[];i32[];void;", true);
176 }
177
178 // === Constructor of class ===
TEST_F(RestParameterTest,class_constructor_without_rest_parameters_0)179 TEST_F(RestParameterTest, class_constructor_without_rest_parameters_0)
180 {
181 SetCurrentProgram(R"(
182 class A {
183 constructor() {};
184 }
185 )");
186 CheckNoRestParameterFlag("dummy.A.<ctor>:void;", false);
187 }
188
TEST_F(RestParameterTest,class_constructor_without_rest_parameters_1)189 TEST_F(RestParameterTest, class_constructor_without_rest_parameters_1)
190 {
191 SetCurrentProgram(R"(
192 class A {
193 constructor(args: FixedArray<String>) {};
194 }
195 )");
196 CheckNoRestParameterFlag("dummy.A.<ctor>:std.core.String[];void;", false);
197 }
198
TEST_F(RestParameterTest,class_constructor_with_rest_parameters_0)199 TEST_F(RestParameterTest, class_constructor_with_rest_parameters_0)
200 {
201 SetCurrentProgram(R"(
202 class A {
203 constructor(...args: FixedArray<int>) {};
204 }
205 )");
206 CheckRestParameterFlag("dummy.A.<ctor>:i32[];void;", false);
207 }
208
TEST_F(RestParameterTest,class_constructor_with_rest_parameters_1)209 TEST_F(RestParameterTest, class_constructor_with_rest_parameters_1)
210 {
211 SetCurrentProgram(R"(
212 class A {
213 constructor(v0: long, ...args: FixedArray<String>) {};
214 }
215 )");
216 CheckRestParameterFlag("dummy.A.<ctor>:i64;std.core.String[];void;", false);
217 }
218
219 // === Method of interface ===
TEST_F(RestParameterTest,interface_without_rest_parameters_0)220 TEST_F(RestParameterTest, interface_without_rest_parameters_0)
221 {
222 SetCurrentProgram(R"(
223 interface A {
224 fn() {};
225 }
226 )");
227 CheckNoRestParameterFlag("dummy.A.fn:void;", false);
228 }
229
TEST_F(RestParameterTest,interface_without_rest_parameters_1)230 TEST_F(RestParameterTest, interface_without_rest_parameters_1)
231 {
232 SetCurrentProgram(R"(
233 interface A {
234 fn(args: FixedArray<String>) {};
235 }
236 )");
237 CheckNoRestParameterFlag("dummy.A.fn:std.core.String[];void;", false);
238 }
239
TEST_F(RestParameterTest,interface_with_rest_parameters_0)240 TEST_F(RestParameterTest, interface_with_rest_parameters_0)
241 {
242 SetCurrentProgram(R"(
243 interface A {
244 fn(...args: FixedArray<Object>) {};
245 }
246 )");
247 CheckRestParameterFlag("dummy.A.fn:std.core.Object[];void;", false);
248 }
249
TEST_F(RestParameterTest,interface_with_rest_parameters_1)250 TEST_F(RestParameterTest, interface_with_rest_parameters_1)
251 {
252 SetCurrentProgram(R"(
253 interface A {
254 fn(o: Object, ...args: FixedArray<String>) {};
255 }
256 )");
257 CheckRestParameterFlag("dummy.A.fn:std.core.Object;std.core.String[];void;", false);
258 }
259
260 // === Lambda method ===
TEST_F(RestParameterTest,lambda_without_rest_parameters_0)261 TEST_F(RestParameterTest, lambda_without_rest_parameters_0)
262 {
263 SetCurrentProgram(R"(
264 let fn: ()=>int = (): int => {
265 return 1;
266 }
267 )");
268 CheckNoRestParameterFlag("dummy.ETSGLOBAL.lambda$invoke$0:i32;", true);
269 }
270
TEST_F(RestParameterTest,lambda_without_rest_parameters_1)271 TEST_F(RestParameterTest, lambda_without_rest_parameters_1)
272 {
273 SetCurrentProgram(R"(
274 let fn: (args: FixedArray<long>)=>int = (args: FixedArray<long>): int => {
275 return 1;
276 }
277 )");
278 CheckNoRestParameterFlag("dummy.ETSGLOBAL.lambda$invoke$0:i64[];i32;", true);
279 }
280
281 // === Abstract method of abstract class ===
TEST_F(RestParameterTest,abstract_function_without_rest_parameter_0)282 TEST_F(RestParameterTest, abstract_function_without_rest_parameter_0)
283 {
284 SetCurrentProgram(R"(
285 abstract class A {
286 abstract fn(): void
287 }
288 )");
289 CheckNoRestParameterFlag("dummy.A.fn:void;", false);
290 }
291
TEST_F(RestParameterTest,abstract_function_without_rest_parameter_1)292 TEST_F(RestParameterTest, abstract_function_without_rest_parameter_1)
293 {
294 SetCurrentProgram(R"(
295 abstract class A {
296 abstract fn(args: FixedArray<String>): void
297 }
298 )");
299 CheckNoRestParameterFlag("dummy.A.fn:std.core.String[];void;", false);
300 }
301
TEST_F(RestParameterTest,abstract_function_with_rest_parameter_0)302 TEST_F(RestParameterTest, abstract_function_with_rest_parameter_0)
303 {
304 SetCurrentProgram(R"(
305 abstract class A {
306 abstract fn(...args: FixedArray<String>): void
307 }
308 )");
309 CheckRestParameterFlag("dummy.A.fn:std.core.String[];void;", false);
310 }
311
TEST_F(RestParameterTest,abstract_function_with_rest_parameter_1)312 TEST_F(RestParameterTest, abstract_function_with_rest_parameter_1)
313 {
314 SetCurrentProgram(R"(
315 abstract class A {
316 abstract fn(v: int, ...args: FixedArray<String>): void
317 }
318 )");
319 CheckRestParameterFlag("dummy.A.fn:i32;std.core.String[];void;", false);
320 }
321
322 // === External methods ===
TEST_F(RestParameterTest,external_function_with_rest_parameter_0)323 TEST_F(RestParameterTest, external_function_with_rest_parameter_0)
324 {
325 SetCurrentProgram("");
326 CheckRestParameterFlag("std.core.LambdaValue.invoke:escompat.Array;std.core.Object;", false);
327 }
328
TEST_F(RestParameterTest,external_function_with_rest_parameter_1)329 TEST_F(RestParameterTest, external_function_with_rest_parameter_1)
330 {
331 SetCurrentProgram("");
332 CheckRestParameterFlag("escompat.Math.max:escompat.Array;f64;", true);
333 }
334
335 } // namespace ark::es2panda::compiler::test
336