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