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
24namespace ark::es2panda::ir {
25
26ScriptFunction *MethodDefinition::Function()
27{
28    return value_->IsFunctionExpression() ? value_->AsFunctionExpression()->Function() : nullptr;
29}
30
31const ScriptFunction *MethodDefinition::Function() const
32{
33    return value_->IsFunctionExpression() ? value_->AsFunctionExpression()->Function() : nullptr;
34}
35
36PrivateFieldKind 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
54void 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
68void 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
84void 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
111void 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
153void 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
198void 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
223void MethodDefinition::Compile(compiler::PandaGen *pg) const
224{
225    pg->GetAstCompiler()->Compile(this);
226}
227
228void MethodDefinition::Compile(compiler::ETSGen *etsg) const
229{
230    etsg->GetAstCompiler()->Compile(this);
231}
232
233checker::Type *MethodDefinition::Check(checker::TSChecker *checker)
234{
235    return checker->GetAnalyzer()->Check(this);
236}
237
238checker::Type *MethodDefinition::Check(checker::ETSChecker *checker)
239{
240    return checker->GetAnalyzer()->Check(this);
241}
242
243MethodDefinition *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