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 26namespace ark::es2panda::compiler::test { 27 28class RestParameterTest : public testing::Test { 29public: 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 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 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 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 67private: 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 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 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 104private: 105 std::unique_ptr<pandasm::Program> program_ {}; 106}; 107 108// === Function === 109TEST_F(RestParameterTest, function_without_rest_parameters_0) 110{ 111 SetCurrentProgram(R"( 112 function fn(): void { 113 } 114 )"); 115 CheckNoRestParameterFlag("ETSGLOBAL.fn:void;"); 116} 117 118TEST_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 127TEST_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 136TEST_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 145TEST_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 === 155TEST_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 165TEST_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 175TEST_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 === 186TEST_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 196TEST_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 206TEST_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 216TEST_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 === 227TEST_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 237TEST_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 247TEST_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 257TEST_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 === 268TEST_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 278TEST_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 288TEST_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 298TEST_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 === 309TEST_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 319TEST_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 === 330TEST_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 340TEST_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 350TEST_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 360TEST_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 === 371TEST_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 377TEST_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