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
24 namespace ark::es2panda::checker {
25
ResolveCall(const varbinder::ETSBinder *varbinder, const ir::Expression *callee)26 DynamicCall::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
SqueezeExpr(ArenaAllocator *allocator, const ir::MemberExpression *expr)58 DynamicCall::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
SqueezeExpr(const ir::MemberExpression *memberExpr, NameHolder &name)66 const 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