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
30 namespace ark::es2panda::ir {
Ctor() const31 const FunctionExpression *ClassDefinition::Ctor() const
32 {
33 return ctor_ != nullptr ? ctor_->Value()->AsFunctionExpression() : nullptr;
34 }
35
HasPrivateMethod() const36 bool 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
HasComputedInstanceField() const43 bool 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
HasMatchingPrivateKey(const util::StringView & name) const51 bool 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
TransformChildren(const NodeTransformer & cb,std::string_view transformationName)58 void 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 for (auto *&it : annotations_) {
96 if (auto *transformedNode = cb(it); it != transformedNode) {
97 it->SetTransformedNode(transformationName, transformedNode);
98 it = transformedNode->AsAnnotationUsage();
99 }
100 }
101
102 if (ctor_ != nullptr) {
103 if (auto *transformedNode = cb(ctor_); ctor_ != transformedNode) {
104 ctor_->SetTransformedNode(transformationName, transformedNode);
105 ctor_ = transformedNode->AsMethodDefinition();
106 }
107 }
108
109 for (auto *&it : body_) {
110 if (auto *transformedNode = cb(it); it != transformedNode) {
111 it->SetTransformedNode(transformationName, transformedNode);
112 it = transformedNode;
113 }
114 }
115 }
116
Iterate(const NodeTraverser & cb) const117 void ClassDefinition::Iterate(const NodeTraverser &cb) const
118 {
119 if (ident_ != nullptr) {
120 cb(ident_);
121 }
122
123 if (typeParams_ != nullptr) {
124 cb(typeParams_);
125 }
126
127 if (superClass_ != nullptr) {
128 cb(superClass_);
129 }
130
131 if (superTypeParams_ != nullptr) {
132 cb(superTypeParams_);
133 }
134
135 // Survives adding new elements to the end
136 // NOLINTNEXTLINE(modernize-loop-convert)
137 for (size_t ix = 0; ix < implements_.size(); ix++) {
138 cb(implements_[ix]);
139 }
140
141 for (auto *it : annotations_) {
142 cb(it);
143 }
144
145 if (ctor_ != nullptr) {
146 cb(ctor_);
147 }
148
149 // NOLINTNEXTLINE(modernize-loop-convert)
150 for (size_t ix = 0; ix < body_.size(); ix++) {
151 cb(body_[ix]);
152 }
153 }
154
SetIdent(ir::Identifier * ident)155 void ClassDefinition::SetIdent(ir::Identifier *ident) noexcept
156 {
157 ident_ = ident;
158 if (ident_ != nullptr) {
159 ident_->SetParent(this);
160 }
161 }
162
Dump(ir::AstDumper * dumper) const163 void ClassDefinition::Dump(ir::AstDumper *dumper) const
164 {
165 auto propFilter = [](AstNode *prop) -> bool {
166 return !prop->IsClassStaticBlock() || !prop->AsClassStaticBlock()->Function()->IsHidden();
167 };
168 dumper->Add({{"id", AstDumper::Nullish(ident_)},
169 {"typeParameters", AstDumper::Optional(typeParams_)},
170 {"superClass", AstDumper::Nullish(superClass_)},
171 {"superTypeParameters", AstDumper::Optional(superTypeParams_)},
172 {"implements", implements_},
173 {"annotations", AstDumper::Optional(annotations_)},
174 {"constructor", AstDumper::Optional(ctor_)},
175 {"body", body_, propFilter}});
176 }
177
178 // This method is needed by OHOS CI code checker
DumpBody(ir::SrcDumper * dumper) const179 void ClassDefinition::DumpBody(ir::SrcDumper *dumper) const
180 {
181 dumper->Add(" {");
182 if (!body_.empty()) {
183 dumper->IncrIndent();
184 dumper->Endl();
185 for (auto elem : body_) {
186 elem->Dump(dumper);
187 if (elem == body_.back()) {
188 dumper->DecrIndent();
189 }
190 dumper->Endl();
191 }
192 }
193 dumper->Add("}");
194 }
195
Dump(ir::SrcDumper * dumper) const196 void ClassDefinition::Dump(ir::SrcDumper *dumper) const
197 {
198 for (auto *anno : annotations_) {
199 anno->Dump(dumper);
200 }
201 ASSERT(ident_ != nullptr);
202
203 if (IsExtern()) {
204 dumper->Add("extern ");
205 }
206
207 if (IsExported()) {
208 dumper->Add("export ");
209 }
210
211 if (IsDeclare()) {
212 dumper->Add("declare ");
213 }
214
215 if (IsFinal()) {
216 dumper->Add("final ");
217 }
218
219 if (IsAbstract()) {
220 dumper->Add("abstract ");
221 }
222
223 dumper->Add("class ");
224 ident_->Dump(dumper);
225
226 if (typeParams_ != nullptr) {
227 dumper->Add("<");
228 typeParams_->Dump(dumper);
229 dumper->Add("> ");
230 }
231
232 if (superClass_ != nullptr) {
233 dumper->Add(" extends ");
234 superClass_->Dump(dumper);
235 }
236
237 DumpItems(dumper, " implements ", implements_);
238
239 if (!IsDeclare() || !body_.empty()) {
240 DumpBody(dumper);
241 }
242 if (IsLocal()) {
243 dumper->Add(";");
244 }
245 dumper->Endl();
246 }
247
Compile(compiler::PandaGen * pg) const248 void ClassDefinition::Compile(compiler::PandaGen *pg) const
249 {
250 pg->GetAstCompiler()->Compile(this);
251 }
252
Compile(compiler::ETSGen * etsg) const253 void ClassDefinition::Compile(compiler::ETSGen *etsg) const
254 {
255 etsg->GetAstCompiler()->Compile(this);
256 }
257
Check(checker::TSChecker * checker)258 checker::Type *ClassDefinition::Check(checker::TSChecker *checker)
259 {
260 return checker->GetAnalyzer()->Check(this);
261 }
262
Check(checker::ETSChecker * checker)263 checker::Type *ClassDefinition::Check(checker::ETSChecker *checker)
264 {
265 return checker->GetAnalyzer()->Check(this);
266 }
267
268 int ClassDefinition::classCounter_ = 0;
269
270 } // namespace ark::es2panda::ir
271