1/* 2 * Copyright (c) 2021 - 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 "checker/ets/dynamic/dynamicCall.h" 17 18#include "ir/ets/etsTypeReference.h" 19#include "ir/ets/etsTypeReferencePart.h" 20#include "ir/module/importSpecifier.h" 21#include "ir/ts/tsQualifiedName.h" 22#include "ir/expressions/memberExpression.h" 23 24namespace ark::es2panda::checker { 25 26DynamicCall::Result DynamicCall::ResolveCall(const varbinder::ETSBinder *varbinder, const ir::Expression *callee) 27{ 28 auto calleeName = NameHolder(varbinder->Allocator()->Adapter()); 29 30 if (callee->IsETSTypeReference()) { 31 // new A.B.C() => call js.new(A, ".B.C") 32 callee = callee->AsETSTypeReference()->Part()->Name(); 33 while (callee->IsTSQualifiedName()) { 34 auto *qname = callee->AsTSQualifiedName(); 35 callee = qname->Left(); 36 calleeName.emplace_back(qname->Right()->AsIdentifier()->Name()); 37 } 38 ASSERT(callee->IsIdentifier()); 39 } else if (callee->IsMemberExpression()) { 40 const auto memberExpr = callee->AsMemberExpression(); 41 callee = SqueezeExpr(memberExpr, calleeName); 42 } 43 if (callee->IsIdentifier()) { 44 // kinda optimization in case: 45 // `import X from Y` to use (load Y, call "X"), instead of (load Y, load X, call) 46 const auto var = callee->AsIdentifier()->Variable(); 47 const auto *data = varbinder->DynamicImportDataForVar(var); 48 if (data != nullptr && data->specifier != nullptr && data->specifier->IsImportSpecifier()) { 49 calleeName.emplace_back(data->specifier->AsImportSpecifier()->Imported()->Name()); 50 std::reverse(calleeName.begin(), calleeName.end()); 51 return {data->import, calleeName}; 52 } 53 } 54 std::reverse(calleeName.begin(), calleeName.end()); 55 return {callee, calleeName}; 56} 57 58DynamicCall::Result DynamicCall::SqueezeExpr(ArenaAllocator *allocator, const ir::MemberExpression *expr) 59{ 60 NameHolder name(allocator->Adapter()); 61 auto obj = SqueezeExpr(expr, name); 62 std::reverse(name.begin(), name.end()); 63 return {obj, name}; 64} 65 66const ir::Expression *DynamicCall::SqueezeExpr(const ir::MemberExpression *memberExpr, NameHolder &name) 67{ 68 if (!memberExpr->Object()->TsType()->IsETSDynamicType() || memberExpr->IsComputed()) { 69 return memberExpr; 70 } 71 ASSERT(memberExpr->Property()->IsIdentifier()); 72 name.emplace_back(memberExpr->Property()->AsIdentifier()->Name()); 73 if (memberExpr->Object()->IsMemberExpression()) { 74 return SqueezeExpr(memberExpr->Object()->AsMemberExpression(), name); 75 } 76 return memberExpr->Object(); 77} 78 79} // namespace ark::es2panda::checker 80