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 "classProperty.h"
17 #include <string>
18
19 #include "checker/ETSchecker.h"
20 #include "checker/TSchecker.h"
21 #include "compiler/core/ETSGen.h"
22 #include "compiler/core/pandagen.h"
23 #include "compiler/lowering/util.h"
24
25 namespace ark::es2panda::ir {
TransformChildren(const NodeTransformer & cb,std::string_view const transformationName)26 void ClassProperty::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName)
27 {
28 if (auto *transformedNode = cb(key_); key_ != transformedNode) {
29 key_->SetTransformedNode(transformationName, transformedNode);
30 key_ = transformedNode->AsExpression();
31 }
32
33 if (value_ != nullptr) {
34 if (auto *transformedNode = cb(value_); value_ != transformedNode) {
35 value_->SetTransformedNode(transformationName, transformedNode);
36 value_ = transformedNode->AsExpression();
37 }
38 }
39
40 if (typeAnnotation_ != nullptr) {
41 if (auto *transformedNode = cb(typeAnnotation_); typeAnnotation_ != transformedNode) {
42 typeAnnotation_->SetTransformedNode(transformationName, transformedNode);
43 typeAnnotation_ = static_cast<TypeNode *>(transformedNode);
44 }
45 }
46
47 for (auto *&it : VectorIterationGuard(decorators_)) {
48 if (auto *transformedNode = cb(it); it != transformedNode) {
49 it->SetTransformedNode(transformationName, transformedNode);
50 it = transformedNode->AsDecorator();
51 }
52 }
53
54 for (auto *&it : Annotations()) {
55 if (auto *transformedNode = cb(it); it != transformedNode) {
56 it->SetTransformedNode(transformationName, transformedNode);
57 it = transformedNode->AsAnnotationUsage();
58 }
59 }
60 }
61
Iterate(const NodeTraverser & cb) const62 void ClassProperty::Iterate(const NodeTraverser &cb) const
63 {
64 cb(key_);
65
66 if (value_ != nullptr) {
67 cb(value_);
68 }
69
70 if (typeAnnotation_ != nullptr) {
71 cb(typeAnnotation_);
72 }
73
74 for (auto *it : VectorIterationGuard(decorators_)) {
75 cb(it);
76 }
77
78 for (auto *it : Annotations()) {
79 cb(it);
80 }
81 }
82
Dump(ir::AstDumper * dumper) const83 void ClassProperty::Dump(ir::AstDumper *dumper) const
84 {
85 dumper->Add({{"type", "ClassProperty"},
86 {"key", key_},
87 {"value", AstDumper::Optional(value_)},
88 {"accessibility", AstDumper::Optional(AstDumper::ModifierToString(flags_))},
89 {"static", IsStatic()},
90 {"readonly", IsReadonly()},
91 {"declare", IsDeclare()},
92 {"optional", IsOptionalDeclaration()},
93 {"computed", isComputed_},
94 {"typeAnnotation", AstDumper::Optional(typeAnnotation_)},
95 {"definite", IsDefinite()},
96 {"decorators", decorators_},
97 {"annotations", AstDumper::Optional(Annotations())}});
98 }
99
DumpModifiers(ir::SrcDumper * dumper) const100 void ClassProperty::DumpModifiers(ir::SrcDumper *dumper) const
101 {
102 ES2PANDA_ASSERT(key_);
103 if (dumper->IsDeclgen()) {
104 if (key_->Parent()->IsExported()) {
105 dumper->Add("export declare ");
106 } else if (key_->Parent()->IsDefaultExported()) {
107 dumper->Add("export default declare ");
108 }
109 }
110
111 if (compiler::HasGlobalClassParent(this)) {
112 if (key_->Parent()->IsConst()) {
113 dumper->Add("const ");
114 } else {
115 dumper->Add("let ");
116 }
117 return;
118 }
119
120 if (compiler::HasGlobalClassParent(this)) {
121 dumper->Add("let ");
122 return;
123 }
124
125 if (Parent() != nullptr && Parent()->IsClassDefinition() && !Parent()->AsClassDefinition()->IsLocal()) {
126 if (IsPrivate()) {
127 dumper->Add("private ");
128 } else if (IsProtected()) {
129 dumper->Add("protected ");
130 } else if (IsInternal()) {
131 dumper->Add("internal ");
132 } else {
133 dumper->Add("public ");
134 }
135 }
136
137 if (IsStatic()) {
138 dumper->Add("static ");
139 }
140
141 if (IsReadonly()) {
142 dumper->Add("readonly ");
143 }
144 }
145
DumpNamespaceForDeclGen(ir::SrcDumper * dumper) const146 bool ClassProperty::DumpNamespaceForDeclGen(ir::SrcDumper *dumper) const
147 {
148 if (!dumper->IsDeclgen()) {
149 return false;
150 }
151
152 if (Parent() == nullptr) {
153 return false;
154 }
155
156 bool isNamespaceTransformed =
157 Parent()->IsClassDefinition() && Parent()->AsClassDefinition()->IsNamespaceTransformed();
158 if (isNamespaceTransformed) {
159 dumper->Add("let ");
160 return true;
161 }
162 return false;
163 }
164
DumpPrefix(ir::SrcDumper * dumper) const165 void ClassProperty::DumpPrefix(ir::SrcDumper *dumper) const
166 {
167 for (auto *anno : Annotations()) {
168 anno->Dump(dumper);
169 }
170 if (DumpNamespaceForDeclGen(dumper)) {
171 return;
172 }
173 DumpModifiers(dumper);
174 }
175
DumpCheckerTypeForDeclGen(ir::SrcDumper * dumper) const176 void ClassProperty::DumpCheckerTypeForDeclGen(ir::SrcDumper *dumper) const
177 {
178 if (!dumper->IsDeclgen()) {
179 return;
180 }
181
182 if (TsType() == nullptr) {
183 return;
184 }
185
186 auto typeStr = TsType()->ToString();
187 if (TsType()->IsTypeError() && dumper->IsIsolatedDeclgen() && typeAnnotation_ != nullptr) {
188 typeStr = typeAnnotation_->AsETSTypeReference()->Part()->Name()->AsIdentifier()->Name().Mutf8();
189 }
190
191 dumper->Add(": ");
192 dumper->Add(typeStr);
193
194 dumper->PushTask([dumper, typeStr] { dumper->DumpNode(typeStr); });
195 }
196
RegisterUnexportedForDeclGen(ir::SrcDumper * dumper) const197 bool ClassProperty::RegisterUnexportedForDeclGen(ir::SrcDumper *dumper) const
198 {
199 ES2PANDA_ASSERT(key_);
200 if (!dumper->IsDeclgen()) {
201 return false;
202 }
203
204 auto name = key_->AsIdentifier()->Name().Mutf8();
205 if (name.rfind('#', 0) == 0) {
206 return true;
207 }
208
209 if (!compiler::HasGlobalClassParent(this)) {
210 return false;
211 }
212
213 if (dumper->IsIndirectDepPhase()) {
214 return false;
215 }
216
217 if (key_->Parent()->IsExported() || key_->Parent()->IsDefaultExported()) {
218 return false;
219 }
220
221 dumper->AddNode(name, this);
222 return true;
223 }
224
Dump(ir::SrcDumper * dumper) const225 void ClassProperty::Dump(ir::SrcDumper *dumper) const
226 {
227 if (RegisterUnexportedForDeclGen(dumper)) {
228 return;
229 }
230 DumpPrefix(dumper);
231
232 if (key_ != nullptr) {
233 key_->Dump(dumper);
234 }
235
236 if (IsOptionalDeclaration()) {
237 dumper->Add("?");
238 }
239
240 if (IsDefinite()) {
241 dumper->Add("!");
242 }
243
244 if (typeAnnotation_ != nullptr && !dumper->IsDeclgen()) {
245 dumper->Add(": ");
246 typeAnnotation_->Dump(dumper);
247 }
248
249 DumpCheckerTypeForDeclGen(dumper);
250
251 if (value_ != nullptr && !dumper->IsDeclgen()) {
252 dumper->Add(" = ");
253 value_->Dump(dumper);
254 }
255
256 dumper->Add(";");
257 dumper->Endl();
258 }
259
Compile(compiler::PandaGen * pg) const260 void ClassProperty::Compile(compiler::PandaGen *pg) const
261 {
262 pg->GetAstCompiler()->Compile(this);
263 }
264
Compile(compiler::ETSGen * etsg) const265 void ClassProperty::Compile(compiler::ETSGen *etsg) const
266 {
267 etsg->GetAstCompiler()->Compile(this);
268 }
269
Check(checker::TSChecker * checker)270 checker::Type *ClassProperty::Check(checker::TSChecker *checker)
271 {
272 return checker->GetAnalyzer()->Check(this);
273 }
274
Check(checker::ETSChecker * checker)275 checker::VerifiedType ClassProperty::Check(checker::ETSChecker *checker)
276 {
277 return {this, checker->GetAnalyzer()->Check(this)};
278 }
279
Clone(ArenaAllocator * const allocator,AstNode * const parent)280 ClassProperty *ClassProperty::Clone(ArenaAllocator *const allocator, AstNode *const parent)
281 {
282 auto *const key = key_->Clone(allocator, nullptr)->AsExpression();
283 auto *const value = value_ != nullptr ? value_->Clone(allocator, nullptr)->AsExpression() : nullptr;
284 auto *const typeAnnotation = typeAnnotation_ != nullptr ? typeAnnotation_->Clone(allocator, nullptr) : nullptr;
285
286 auto *const clone = allocator->New<ClassProperty>(key, value, typeAnnotation, flags_, allocator, isComputed_);
287
288 if (parent != nullptr) {
289 clone->SetParent(parent);
290 }
291
292 key->SetParent(clone);
293 if (value != nullptr) {
294 value->SetTsType(value_->TsType());
295 value->SetParent(clone);
296 }
297 if (typeAnnotation != nullptr) {
298 typeAnnotation->SetTsType(typeAnnotation->TsType());
299 typeAnnotation->SetParent(clone);
300 }
301
302 for (auto *const decorator : decorators_) {
303 clone->AddDecorator(decorator->Clone(allocator, clone));
304 }
305
306 if (!Annotations().empty()) {
307 ArenaVector<AnnotationUsage *> annotationUsages {allocator->Adapter()};
308 for (auto *annotationUsage : Annotations()) {
309 annotationUsages.push_back(annotationUsage->Clone(allocator, clone)->AsAnnotationUsage());
310 }
311 clone->SetAnnotations(std::move(annotationUsages));
312 }
313
314 clone->SetRange(range_);
315
316 return clone;
317 }
318
Construct(ArenaAllocator * allocator)319 ClassProperty *ClassProperty::Construct(ArenaAllocator *allocator)
320 {
321 return allocator->New<ClassProperty>(nullptr, nullptr, nullptr, ModifierFlags::NONE, allocator, false);
322 }
323
CopyTo(AstNode * other) const324 void ClassProperty::CopyTo(AstNode *other) const
325 {
326 auto otherImpl = other->AsClassProperty();
327
328 otherImpl->typeAnnotation_ = typeAnnotation_;
329 otherImpl->isDefault_ = isDefault_;
330 otherImpl->needInitInStaticBlock_ = needInitInStaticBlock_;
331
332 JsDocAllowed<AnnotationAllowed<ClassElement>>::CopyTo(other);
333 }
334
335 } // namespace ark::es2panda::ir
336