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