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 "classDefinition.h"
17
18#include "checker/TSchecker.h"
19#include "checker/ETSchecker.h"
20#include "compiler/core/ETSGen.h"
21#include "compiler/core/pandagen.h"
22#include "ir/astDump.h"
23#include "ir/srcDump.h"
24#include "ir/base/classStaticBlock.h"
25#include "ir/base/methodDefinition.h"
26#include "ir/base/scriptFunction.h"
27#include "ir/expressions/identifier.h"
28#include "ir/ts/tsClassImplements.h"
29
30namespace ark::es2panda::ir {
31const FunctionExpression *ClassDefinition::Ctor() const
32{
33    return ctor_ != nullptr ? ctor_->Value()->AsFunctionExpression() : nullptr;
34}
35
36bool ClassDefinition::HasPrivateMethod() const
37{
38    return std::any_of(body_.cbegin(), body_.cend(), [](auto *element) {
39        return element->IsMethodDefinition() && element->AsClassElement()->IsPrivateElement();
40    });
41}
42
43bool ClassDefinition::HasComputedInstanceField() const
44{
45    return std::any_of(body_.cbegin(), body_.cend(), [](auto *element) {
46        return element->IsClassProperty() && element->AsClassElement()->IsComputed() &&
47               !(element->AsClassElement()->Modifiers() & ir::ModifierFlags::STATIC);
48    });
49}
50
51bool ClassDefinition::HasMatchingPrivateKey(const util::StringView &name) const
52{
53    return std::any_of(body_.cbegin(), body_.cend(), [&name](auto *element) {
54        return element->AsClassElement()->IsPrivateElement() && element->AsClassElement()->Id()->Name() == name;
55    });
56}
57
58void ClassDefinition::TransformChildren(const NodeTransformer &cb, std::string_view transformationName)
59{
60    if (ident_ != nullptr) {
61        if (auto *transformedNode = cb(ident_); ident_ != transformedNode) {
62            ident_->SetTransformedNode(transformationName, transformedNode);
63            ident_ = transformedNode->AsIdentifier();
64        }
65    }
66
67    if (typeParams_ != nullptr) {
68        if (auto *transformedNode = cb(typeParams_); typeParams_ != transformedNode) {
69            typeParams_->SetTransformedNode(transformationName, transformedNode);
70            typeParams_ = transformedNode->AsTSTypeParameterDeclaration();
71        }
72    }
73
74    if (superClass_ != nullptr) {
75        if (auto *transformedNode = cb(superClass_); superClass_ != transformedNode) {
76            superClass_->SetTransformedNode(transformationName, transformedNode);
77            superClass_ = transformedNode->AsExpression();
78        }
79    }
80
81    if (superTypeParams_ != nullptr) {
82        if (auto *transformedNode = cb(superTypeParams_); superTypeParams_ != transformedNode) {
83            superTypeParams_->SetTransformedNode(transformationName, transformedNode);
84            superTypeParams_ = transformedNode->AsTSTypeParameterInstantiation();
85        }
86    }
87
88    for (auto *&it : implements_) {
89        if (auto *transformedNode = cb(it); it != transformedNode) {
90            it->SetTransformedNode(transformationName, transformedNode);
91            it = transformedNode->AsTSClassImplements();
92        }
93    }
94
95    if (ctor_ != nullptr) {
96        if (auto *transformedNode = cb(ctor_); ctor_ != transformedNode) {
97            ctor_->SetTransformedNode(transformationName, transformedNode);
98            ctor_ = transformedNode->AsMethodDefinition();
99        }
100    }
101
102    for (auto *&it : body_) {
103        if (auto *transformedNode = cb(it); it != transformedNode) {
104            it->SetTransformedNode(transformationName, transformedNode);
105            it = transformedNode;
106        }
107    }
108}
109
110void ClassDefinition::Iterate(const NodeTraverser &cb) const
111{
112    if (ident_ != nullptr) {
113        cb(ident_);
114    }
115
116    if (typeParams_ != nullptr) {
117        cb(typeParams_);
118    }
119
120    if (superClass_ != nullptr) {
121        cb(superClass_);
122    }
123
124    if (superTypeParams_ != nullptr) {
125        cb(superTypeParams_);
126    }
127
128    // Survives adding new elements to the end
129    // NOLINTNEXTLINE(modernize-loop-convert)
130    for (size_t ix = 0; ix < implements_.size(); ix++) {
131        cb(implements_[ix]);
132    }
133
134    if (ctor_ != nullptr) {
135        cb(ctor_);
136    }
137
138    // NOLINTNEXTLINE(modernize-loop-convert)
139    for (size_t ix = 0; ix < body_.size(); ix++) {
140        cb(body_[ix]);
141    }
142}
143
144void ClassDefinition::SetIdent(ir::Identifier *ident) noexcept
145{
146    ident_ = ident;
147    if (ident_ != nullptr) {
148        ident_->SetParent(this);
149    }
150}
151
152void ClassDefinition::Dump(ir::AstDumper *dumper) const
153{
154    auto propFilter = [](AstNode *prop) -> bool {
155        return !prop->IsClassStaticBlock() || !prop->AsClassStaticBlock()->Function()->IsHidden();
156    };
157    dumper->Add({{"id", AstDumper::Nullish(ident_)},
158                 {"typeParameters", AstDumper::Optional(typeParams_)},
159                 {"superClass", AstDumper::Nullish(superClass_)},
160                 {"superTypeParameters", AstDumper::Optional(superTypeParams_)},
161                 {"implements", implements_},
162                 {"constructor", AstDumper::Optional(ctor_)},
163                 {"body", body_, propFilter}});
164}
165
166// This method is needed by OHOS CI code checker
167void ClassDefinition::DumpBody(ir::SrcDumper *dumper) const
168{
169    dumper->Add(" {");
170    if (!body_.empty()) {
171        dumper->IncrIndent();
172        dumper->Endl();
173        for (auto elem : body_) {
174            elem->Dump(dumper);
175            if (elem == body_.back()) {
176                dumper->DecrIndent();
177            }
178            dumper->Endl();
179        }
180    }
181    dumper->Add("}");
182}
183
184void ClassDefinition::Dump(ir::SrcDumper *dumper) const
185{
186    ASSERT(ident_ != nullptr);
187
188    if (IsExtern()) {
189        dumper->Add("extern ");
190    }
191
192    if (IsExported()) {
193        dumper->Add("export ");
194    }
195
196    if (IsDeclare()) {
197        dumper->Add("declare ");
198    }
199
200    if (IsFinal()) {
201        dumper->Add("final ");
202    }
203
204    if (IsAbstract()) {
205        dumper->Add("abstract ");
206    }
207
208    dumper->Add("class ");
209    ident_->Dump(dumper);
210
211    if (typeParams_ != nullptr) {
212        dumper->Add("<");
213        typeParams_->Dump(dumper);
214        dumper->Add("> ");
215    }
216
217    if (superClass_ != nullptr) {
218        dumper->Add(" extends ");
219        superClass_->Dump(dumper);
220    }
221
222    if (!implements_.empty()) {
223        dumper->Add(" implements ");
224        for (auto interface : implements_) {
225            interface->Dump(dumper);
226            if (interface != implements_.back()) {
227                dumper->Add(", ");
228            }
229        }
230    }
231
232    if (!IsDeclare() || !body_.empty()) {
233        DumpBody(dumper);
234    }
235    if (IsLocal()) {
236        dumper->Add(";");
237    }
238    dumper->Endl();
239}
240
241void ClassDefinition::Compile(compiler::PandaGen *pg) const
242{
243    pg->GetAstCompiler()->Compile(this);
244}
245
246void ClassDefinition::Compile(compiler::ETSGen *etsg) const
247{
248    etsg->GetAstCompiler()->Compile(this);
249}
250
251checker::Type *ClassDefinition::Check(checker::TSChecker *checker)
252{
253    return checker->GetAnalyzer()->Check(this);
254}
255
256checker::Type *ClassDefinition::Check(checker::ETSChecker *checker)
257{
258    return checker->GetAnalyzer()->Check(this);
259}
260
261int ClassDefinition::classCounter_ = 0;
262
263}  // namespace ark::es2panda::ir
264