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 "methodDefinition.h"
17 
18 #include "checker/TSchecker.h"
19 #include "compiler/core/ETSGen.h"
20 #include "compiler/core/pandagen.h"
21 #include "ir/astDump.h"
22 #include "ir/srcDump.h"
23 
24 namespace ark::es2panda::ir {
25 
Function()26 ScriptFunction *MethodDefinition::Function()
27 {
28     return value_->IsFunctionExpression() ? value_->AsFunctionExpression()->Function() : nullptr;
29 }
30 
Function() const31 const ScriptFunction *MethodDefinition::Function() const
32 {
33     return value_->IsFunctionExpression() ? value_->AsFunctionExpression()->Function() : nullptr;
34 }
35 
ToPrivateFieldKind(bool const isStatic) const36 PrivateFieldKind MethodDefinition::ToPrivateFieldKind(bool const isStatic) const
37 {
38     switch (kind_) {
39         case MethodDefinitionKind::METHOD: {
40             return isStatic ? PrivateFieldKind::STATIC_METHOD : PrivateFieldKind::METHOD;
41         }
42         case MethodDefinitionKind::GET: {
43             return isStatic ? PrivateFieldKind::STATIC_GET : PrivateFieldKind::GET;
44         }
45         case MethodDefinitionKind::SET: {
46             return isStatic ? PrivateFieldKind::STATIC_SET : PrivateFieldKind::SET;
47         }
48         default: {
49             UNREACHABLE();
50         }
51     }
52 }
53 
ResolveReferences(const NodeTraverser &cb) const54 void MethodDefinition::ResolveReferences(const NodeTraverser &cb) const
55 {
56     cb(key_);
57     cb(value_);
58 
59     for (auto *it : overloads_) {
60         cb(it);
61     }
62 
63     for (auto *it : decorators_) {
64         cb(it);
65     }
66 }
67 
Iterate(const NodeTraverser &cb) const68 void MethodDefinition::Iterate(const NodeTraverser &cb) const
69 {
70     cb(key_);
71     cb(value_);
72 
73     for (auto *it : overloads_) {
74         if (it->Parent() == this) {
75             cb(it);
76         }
77     }
78 
79     for (auto *it : decorators_) {
80         cb(it);
81     }
82 }
83 
TransformChildren(const NodeTransformer &cb, std::string_view const transformationName)84 void MethodDefinition::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName)
85 {
86     if (auto *transformedNode = cb(key_); key_ != transformedNode) {
87         key_->SetTransformedNode(transformationName, transformedNode);
88         key_ = transformedNode->AsExpression();
89     }
90 
91     if (auto *transformedNode = cb(value_); value_ != transformedNode) {
92         value_->SetTransformedNode(transformationName, transformedNode);
93         value_ = transformedNode->AsExpression();
94     }
95 
96     for (auto *&it : overloads_) {
97         if (auto *transformedNode = cb(it); it != transformedNode) {
98             it->SetTransformedNode(transformationName, transformedNode);
99             it = transformedNode->AsMethodDefinition();
100         }
101     }
102 
103     for (auto *&it : decorators_) {
104         if (auto *transformedNode = cb(it); it != transformedNode) {
105             it->SetTransformedNode(transformationName, transformedNode);
106             it = transformedNode->AsDecorator();
107         }
108     }
109 }
110 
Dump(ir::AstDumper *dumper) const111 void MethodDefinition::Dump(ir::AstDumper *dumper) const
112 {
113     const char *kind = nullptr;
114 
115     switch (kind_) {
116         case MethodDefinitionKind::CONSTRUCTOR: {
117             kind = "constructor";
118             break;
119         }
120         case MethodDefinitionKind::METHOD: {
121             kind = "method";
122             break;
123         }
124         case MethodDefinitionKind::EXTENSION_METHOD: {
125             kind = "extensionmethod";
126             break;
127         }
128         case MethodDefinitionKind::GET: {
129             kind = "get";
130             break;
131         }
132         case MethodDefinitionKind::SET: {
133             kind = "set";
134             break;
135         }
136         default: {
137             UNREACHABLE();
138         }
139     }
140 
141     dumper->Add({{"type", "MethodDefinition"},
142                  {"key", key_},
143                  {"kind", kind},
144                  {"accessibility", AstDumper::Optional(AstDumper::ModifierToString(flags_))},
145                  {"static", IsStatic()},
146                  {"optional", IsOptionalDeclaration()},
147                  {"computed", isComputed_},
148                  {"value", value_},
149                  {"overloads", overloads_},
150                  {"decorators", decorators_}});
151 }
152 
DumpPrefix(ir::SrcDumper *dumper) const153 void MethodDefinition::DumpPrefix(ir::SrcDumper *dumper) const
154 {
155     if (Parent() != nullptr && Parent()->IsClassDefinition() && !Parent()->AsClassDefinition()->IsLocal()) {
156         if (IsPrivate()) {
157             dumper->Add("private ");
158         } else if (IsProtected()) {
159             dumper->Add("protected ");
160         } else if (IsInternal()) {
161             dumper->Add("internal ");
162         } else {
163             dumper->Add("public ");
164         }
165     }
166 
167     if (IsStatic()) {
168         dumper->Add("static ");
169     }
170 
171     if (IsAbstract()) {
172         dumper->Add("abstract ");
173     }
174 
175     if (IsFinal()) {
176         dumper->Add("final ");
177     }
178 
179     if (IsNative()) {
180         dumper->Add("native ");
181     }
182 
183     if (IsAsync()) {
184         dumper->Add("async ");
185     }
186 
187     if (IsOverride()) {
188         dumper->Add("override ");
189     }
190 
191     if (kind_ == MethodDefinitionKind::GET) {
192         dumper->Add("get ");
193     } else if (kind_ == MethodDefinitionKind::SET) {
194         dumper->Add("set ");
195     }
196 }
197 
Dump(ir::SrcDumper *dumper) const198 void MethodDefinition::Dump(ir::SrcDumper *dumper) const
199 {
200     for (auto method : overloads_) {
201         method->Dump(dumper);
202         dumper->Endl();
203     }
204 
205     // Do not dump default constructor
206     if (Parent() != nullptr && Parent()->IsClassDefinition() && value_->IsFunctionExpression() &&
207         value_->AsFunctionExpression()->Function() != nullptr &&
208         value_->AsFunctionExpression()->Function()->IsImplicitSuperCallNeeded()) {
209         return;
210     }
211 
212     DumpPrefix(dumper);
213 
214     if (key_ != nullptr) {
215         key_->Dump(dumper);
216     }
217 
218     if (value_ != nullptr) {
219         value_->Dump(dumper);
220     }
221 }
222 
Compile(compiler::PandaGen *pg) const223 void MethodDefinition::Compile(compiler::PandaGen *pg) const
224 {
225     pg->GetAstCompiler()->Compile(this);
226 }
227 
Compile(compiler::ETSGen *etsg) const228 void MethodDefinition::Compile(compiler::ETSGen *etsg) const
229 {
230     etsg->GetAstCompiler()->Compile(this);
231 }
232 
Check(checker::TSChecker *checker)233 checker::Type *MethodDefinition::Check(checker::TSChecker *checker)
234 {
235     return checker->GetAnalyzer()->Check(this);
236 }
237 
Check(checker::ETSChecker *checker)238 checker::Type *MethodDefinition::Check(checker::ETSChecker *checker)
239 {
240     return checker->GetAnalyzer()->Check(this);
241 }
242 
Clone(ArenaAllocator *const allocator, AstNode *const parent)243 MethodDefinition *MethodDefinition::Clone(ArenaAllocator *const allocator, AstNode *const parent)
244 {
245     auto *const key = key_ != nullptr ? key_->Clone(allocator, nullptr)->AsExpression() : nullptr;
246     auto *const value = value_ != nullptr ? value_->Clone(allocator, nullptr)->AsExpression() : nullptr;
247 
248     if (auto *const clone = allocator->New<MethodDefinition>(kind_, key, value, flags_, allocator, isComputed_);
249         clone != nullptr) {
250         if (parent != nullptr) {
251             clone->SetParent(parent);
252         }
253 
254         if (key != nullptr) {
255             key->SetParent(clone);
256         }
257 
258         if (value != nullptr) {
259             value->SetParent(clone);
260         }
261 
262         for (auto *const decorator : decorators_) {
263             clone->AddDecorator(decorator->Clone(allocator, clone));
264         }
265 
266         for (auto *const overloads : overloads_) {
267             clone->AddOverload(overloads->Clone(allocator, clone));
268         }
269 
270         return clone;
271     }
272 
273     throw Error(ErrorType::GENERIC, "", CLONE_ALLOCATION_ERROR);
274 }
275 }  // namespace ark::es2panda::ir
276