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 "checker/ETSchecker.h"
17 #include "checker/ets/typeRelationContext.h"
18 #include "checker/types/ets/etsDynamicType.h"
19 #include "checker/types/ets/etsObjectType.h"
20 #include "checker/types/ets/etsTupleType.h"
21 #include "checker/types/ets/etsPartialTypeParameter.h"
22 #include "ir/base/classDefinition.h"
23 #include "ir/base/classElement.h"
24 #include "ir/base/classProperty.h"
25 #include "ir/base/classStaticBlock.h"
26 #include "ir/base/methodDefinition.h"
27 #include "ir/base/scriptFunction.h"
28 #include "ir/ets/etsNewClassInstanceExpression.h"
29 #include "ir/ets/etsTypeReference.h"
30 #include "ir/ets/etsTypeReferencePart.h"
31 #include "ir/ets/etsUnionType.h"
32 #include "ir/expressions/assignmentExpression.h"
33 #include "ir/expressions/callExpression.h"
34 #include "ir/expressions/functionExpression.h"
35 #include "ir/expressions/identifier.h"
36 #include "ir/expressions/memberExpression.h"
37 #include "ir/statements/blockStatement.h"
38 #include "ir/statements/expressionStatement.h"
39 #include "ir/statements/variableDeclarator.h"
40 #include "ir/ts/tsClassImplements.h"
41 #include "ir/ts/tsInterfaceDeclaration.h"
42 #include "ir/ts/tsInterfaceHeritage.h"
43 #include "ir/ts/tsTypeParameter.h"
44 #include "ir/ts/tsTypeParameterDeclaration.h"
45 #include "varbinder/declaration.h"
46 #include "varbinder/variableFlags.h"
47 #include "generated/signatures.h"
48 #include "generated/diagnostic.h"
49 #include "util/helpers.h"
50
51 namespace ark::es2panda::checker {
52
CheckGetterSetterDecl(varbinder::LocalVariable const * child,varbinder::LocalVariable const * parent)53 static bool CheckGetterSetterDecl(varbinder::LocalVariable const *child, varbinder::LocalVariable const *parent)
54 {
55 auto readonlyCheck = [](varbinder::LocalVariable const *var, bool isParent, bool isReadonly) {
56 if (!var->TsType()->IsETSMethodType()) {
57 return true;
58 }
59
60 auto *functionType = var->TsType()->AsETSFunctionType();
61 auto getter = functionType->FindGetter();
62 if (getter == nullptr) {
63 return false;
64 }
65
66 auto setter = functionType->FindSetter();
67 if (!isParent && setter == nullptr && !isReadonly) {
68 return false;
69 }
70
71 if (isParent && setter != nullptr && isReadonly) {
72 return false;
73 }
74
75 return true;
76 };
77
78 bool checkChild = readonlyCheck(child, false, parent->Declaration()->Type() == varbinder::DeclType::READONLY);
79 bool checkParent = readonlyCheck(parent, true, child->Declaration()->Type() == varbinder::DeclType::READONLY);
80 return checkChild && checkParent && (child->TsType()->IsETSFunctionType() || parent->TsType()->IsETSFunctionType());
81 }
82
CheckFunctionDecl(varbinder::LocalVariable * child,varbinder::LocalVariable * parent)83 static bool CheckFunctionDecl(varbinder::LocalVariable *child, varbinder::LocalVariable *parent)
84 {
85 ES2PANDA_ASSERT(child->Declaration()->Type() == parent->Declaration()->Type());
86 if (!child->TsType()->IsETSMethodType() || !parent->TsType()->IsETSMethodType()) {
87 return true;
88 }
89
90 const auto *childType = child->TsType()->AsETSFunctionType();
91 const auto *parentType = parent->TsType()->AsETSFunctionType();
92 bool childIsField = (childType->FindGetter() != nullptr) || (childType->FindSetter() != nullptr);
93 bool parentIsField = (parentType->FindGetter() != nullptr) || (parentType->FindSetter() != nullptr);
94 return childIsField == parentIsField;
95 }
96
GetSuperType(ETSObjectType * type)97 ETSObjectType *ETSChecker::GetSuperType(ETSObjectType *type)
98 {
99 ComputeSuperType(type);
100 if (type == GlobalETSObjectType()) {
101 return GlobalETSObjectType();
102 }
103 if (type->SuperType() == nullptr) {
104 return nullptr;
105 }
106 return type->SuperType();
107 }
108
CheckObjectTypeAndSuperType(ETSChecker * checker,ETSObjectType * type)109 static bool CheckObjectTypeAndSuperType(ETSChecker *checker, ETSObjectType *type)
110 {
111 if (type->HasObjectFlag(ETSObjectFlags::RESOLVED_SUPER)) {
112 return true;
113 }
114
115 ES2PANDA_ASSERT(type->Variable() && type->GetDeclNode()->IsClassDefinition());
116 auto *classDef = type->GetDeclNode()->AsClassDefinition();
117 auto cName = classDef->Ident()->Name();
118 if (cName == compiler::Signatures::PARTIAL_TYPE_NAME || cName == compiler::Signatures::READONLY_TYPE_NAME ||
119 cName == compiler::Signatures::REQUIRED_TYPE_NAME || cName == compiler::Signatures::FIXED_ARRAY_TYPE_NAME) {
120 checker->LogError(diagnostic::USING_RESERVED_NAME_AS_VARIABLE_OR_TYPE_NAME, {cName},
121 type->GetDeclNode()->Start());
122 type->SetSuperType(checker->GlobalETSObjectType());
123 return true;
124 }
125
126 if (classDef->Super() == nullptr || !classDef->Super()->IsTypeNode()) {
127 type->AddObjectFlag(ETSObjectFlags::RESOLVED_SUPER);
128 if (type != checker->GlobalETSObjectType()) {
129 type->SetSuperType(checker->GlobalETSObjectType());
130 }
131 return true;
132 }
133
134 return false;
135 }
136
ComputeSuperType(ETSObjectType * type)137 bool ETSChecker::ComputeSuperType(ETSObjectType *type)
138 {
139 if (CheckObjectTypeAndSuperType(this, type)) {
140 return true;
141 }
142 auto *classDef = type->GetDeclNode()->AsClassDefinition();
143
144 TypeStackElement tse(this, type, {{diagnostic::CYCLIC_INHERITANCE, {type->Name()}}}, classDef->Ident()->Start());
145 if (tse.HasTypeError()) {
146 type->AddObjectFlag(ETSObjectFlags::RESOLVED_SUPER);
147 return false;
148 }
149
150 auto superName = classDef->Super()->AsETSTypeReference()->Part()->GetIdent()->Name();
151 if (superName == compiler::Signatures::PARTIAL_TYPE_NAME || superName == compiler::Signatures::READONLY_TYPE_NAME ||
152 superName == compiler::Signatures::REQUIRED_TYPE_NAME) {
153 LogError(diagnostic::EXTENDING_UTILITY_TYPE, {classDef->Ident()->Name()}, classDef->Super()->Start());
154 return false;
155 }
156
157 Type *superType = classDef->Super()->AsTypeNode()->GetType(this);
158 if (superType == nullptr) {
159 return true;
160 }
161 if (!superType->IsETSObjectType() || !superType->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::CLASS)) {
162 LogError(diagnostic::EXTENDING_UTILITY_TYPE, {classDef->Ident()->Name()}, classDef->Super()->Start());
163 type->SetSuperType(GlobalETSObjectType());
164 return true;
165 }
166
167 ETSObjectType *superObj = superType->AsETSObjectType();
168
169 // struct node has class definition, too
170 if (superObj->GetDeclNode()->Parent()->IsETSStructDeclaration()) {
171 LogError(diagnostic::EXTENDING_STRUCT, {classDef->Ident()->Name()}, classDef->Super()->Start());
172 }
173
174 if (superObj->GetDeclNode()->IsFinal()) {
175 LogError(diagnostic::EXTENDING_FINAL, {}, classDef->Super()->Start());
176 /* It still makes sense to treat superObj as the supertype in future checking */
177 }
178 if (GetSuperType(superObj) == nullptr) {
179 superObj = GlobalETSObjectType();
180 }
181 type->SetSuperType(superObj);
182 type->AddObjectFlag(ETSObjectFlags::RESOLVED_SUPER);
183 return true;
184 }
185
ValidateImplementedInterface(ETSObjectType * type,Type * interface,std::unordered_set<Type * > * extendsSet,const lexer::SourcePosition & pos)186 void ETSChecker::ValidateImplementedInterface(ETSObjectType *type, Type *interface,
187 std::unordered_set<Type *> *extendsSet, const lexer::SourcePosition &pos)
188 {
189 ES2PANDA_ASSERT(interface != nullptr);
190 if (!interface->IsETSObjectType() || !interface->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::INTERFACE)) {
191 LogError(diagnostic::NOT_INTERFACE, {}, pos);
192 return;
193 }
194
195 if (!extendsSet->insert(interface).second) {
196 LogError(diagnostic::REPEATED_INTERFACE, {}, pos);
197 }
198
199 auto *baseType = GetOriginalBaseType(interface);
200 if (baseType != interface && !extendsSet->insert(baseType).second) {
201 LogError(diagnostic::CONFLICTING_GENERIC_INTERFACE_IMPLS, {baseType}, pos);
202 }
203
204 GetInterfaces(interface->AsETSObjectType());
205 auto *declNode = interface->AsETSObjectType()->GetDeclNode()->AsTSInterfaceDeclaration();
206 if (declNode->TsType() != nullptr && declNode->TsType()->IsTypeError()) {
207 return;
208 }
209 type->AddInterface(interface->AsETSObjectType());
210 }
211
GetInterfacesOfClass(ETSObjectType * type)212 void ETSChecker::GetInterfacesOfClass(ETSObjectType *type)
213 {
214 if (type->HasObjectFlag(ETSObjectFlags::RESOLVED_INTERFACES)) {
215 return;
216 }
217
218 const auto *declNode = type->GetDeclNode()->AsClassDefinition();
219
220 std::unordered_set<Type *> extendsSet;
221 for (auto *it : declNode->Implements()) {
222 ValidateImplementedInterface(type, it->Expr()->AsTypeNode()->GetType(this), &extendsSet, it->Start());
223 }
224 type->AddObjectFlag(ETSObjectFlags::RESOLVED_INTERFACES);
225 }
226
GetInterfacesOfInterface(ETSObjectType * type)227 void ETSChecker::GetInterfacesOfInterface(ETSObjectType *type)
228 {
229 if (type->HasObjectFlag(ETSObjectFlags::RESOLVED_INTERFACES)) {
230 return;
231 }
232
233 auto *declNode = type->GetDeclNode()->AsTSInterfaceDeclaration();
234
235 TypeStackElement tse(this, type, {{diagnostic::CYCLIC_INHERITANCE, {type->Name()}}}, declNode->Id()->Start());
236 if (tse.HasTypeError()) {
237 type->AddObjectFlag(ETSObjectFlags::RESOLVED_INTERFACES);
238 declNode->SetTsType(GlobalTypeError());
239 return;
240 }
241
242 std::unordered_set<Type *> extendsSet;
243 for (auto *it : declNode->Extends()) {
244 ValidateImplementedInterface(type, it->Expr()->AsTypeNode()->GetType(this), &extendsSet, it->Start());
245 }
246 type->AddObjectFlag(ETSObjectFlags::RESOLVED_INTERFACES);
247 }
248
GetInterfaces(ETSObjectType * type)249 ArenaVector<ETSObjectType *> ETSChecker::GetInterfaces(ETSObjectType *type)
250 {
251 ES2PANDA_ASSERT(type->GetDeclNode()->IsClassDefinition() || type->GetDeclNode()->IsTSInterfaceDeclaration());
252
253 if (type->GetDeclNode()->IsClassDefinition()) {
254 GetInterfacesOfClass(type);
255 } else {
256 GetInterfacesOfInterface(type);
257 }
258
259 return type->Interfaces();
260 }
261
CreateUnconstrainedTypeParameters(ir::TSTypeParameterDeclaration const * typeParams)262 std::pair<ArenaVector<Type *>, bool> ETSChecker::CreateUnconstrainedTypeParameters(
263 ir::TSTypeParameterDeclaration const *typeParams)
264 {
265 bool ok = true;
266 ArenaVector<Type *> result {ProgramAllocator()->Adapter()};
267 checker::ScopeContext scopeCtx(this, typeParams->Scope());
268
269 // Note: we have to run pure check loop first to avoid endless loop because of possible circular dependencies
270 Type2TypeMap extends {};
271 TypeSet typeParameterDecls {};
272 for (auto *const typeParam : typeParams->Params()) {
273 ok &= CheckDefaultTypeParameter(typeParam, typeParameterDecls);
274 if (auto *const constraint = typeParam->Constraint();
275 constraint != nullptr && constraint->IsETSTypeReference() &&
276 constraint->AsETSTypeReference()->Part()->Name()->IsIdentifier()) {
277 ok &= CheckTypeParameterConstraint(typeParam, extends);
278 }
279 }
280
281 for (auto *const typeParam : typeParams->Params()) {
282 result.emplace_back(SetUpParameterType(typeParam));
283 }
284
285 return {result, ok};
286 }
287
AssignTypeParameterConstraints(ir::TSTypeParameterDeclaration const * typeParams)288 void ETSChecker::AssignTypeParameterConstraints(ir::TSTypeParameterDeclaration const *typeParams)
289 {
290 ConstraintCheckScope ctScope(this);
291 // The type parameter might be used in the constraint, like 'K extend Comparable<K>',
292 // so we need to create their type first, then set up the constraint
293 for (auto *const param : typeParams->Params()) {
294 SetUpTypeParameterConstraint(param);
295 }
296 ctScope.TryCheckConstraints();
297 }
298
CheckDefaultTypeParameter(const ir::TSTypeParameter * param,TypeSet & typeParameterDecls)299 bool ETSChecker::CheckDefaultTypeParameter(const ir::TSTypeParameter *param, TypeSet &typeParameterDecls)
300 {
301 bool ok = true;
302 const auto typeParamVar = param->Name()->Variable();
303 if (typeParameterDecls.count(typeParamVar) != 0U) {
304 LogError(diagnostic::DUPLICATE_TYPE_PARAM, {param->Name()->Name().Utf8()}, param->Start());
305 return false;
306 }
307
308 std::function<void(ir::AstNode *)> checkDefault = [&typeParameterDecls, this, &checkDefault,
309 &ok](ir::AstNode *node) -> void {
310 if (node->IsETSTypeReferencePart()) {
311 ir::ETSTypeReferencePart *defaultTypePart = node->AsETSTypeReferencePart();
312 if (defaultTypePart->Name()->IsTSQualifiedName()) {
313 defaultTypePart->Name()->Check(this);
314 }
315 if (IsFixedArray(defaultTypePart)) {
316 defaultTypePart->Check(this);
317 }
318 auto *const variable = defaultTypePart->GetIdent()->Variable();
319 auto defaultType = variable == nullptr ? defaultTypePart->TsType() : variable->TsType();
320 if (defaultType == nullptr && variable != nullptr &&
321 (variable->Flags() & varbinder::VariableFlags::TYPE_PARAMETER) != 0U &&
322 typeParameterDecls.count(variable) == 0U) {
323 LogError(diagnostic::TYPE_PARAM_USE_BEFORE_DEFINE,
324 {defaultTypePart->Name()->AsIdentifier()->Name().Utf8()}, node->Start());
325 ok = false;
326 } else if (defaultType != nullptr && defaultType->IsTypeError()) {
327 ok = false;
328 }
329 }
330 node->Iterate(checkDefault);
331 };
332
333 if (param->DefaultType() != nullptr) {
334 param->DefaultType()->Iterate(checkDefault);
335 }
336
337 typeParameterDecls.emplace(typeParamVar);
338 return ok;
339 }
340
CheckTypeParameterConstraint(ir::TSTypeParameter * param,Type2TypeMap & extends)341 bool ETSChecker::CheckTypeParameterConstraint(ir::TSTypeParameter *param, Type2TypeMap &extends)
342 {
343 const auto typeParamVar = param->Name()->Variable();
344 const auto constraintVar = param->Constraint()->AsETSTypeReference()->Part()->GetIdent()->Variable();
345 extends.emplace(typeParamVar, constraintVar);
346 auto it = extends.find(constraintVar);
347 while (it != extends.cend()) {
348 if (it->second == typeParamVar) {
349 LogError(diagnostic::TYPE_PARAM_CIRCULAR_CONSTRAINT, {param->Name()->Name().Utf8()},
350 param->Constraint()->Start());
351 return false;
352 }
353 it = extends.find(it->second);
354 }
355
356 return true;
357 }
358
SetUpTypeParameterConstraint(ir::TSTypeParameter * const param)359 void ETSChecker::SetUpTypeParameterConstraint(ir::TSTypeParameter *const param)
360 {
361 ETSTypeParameter *const paramType = param->Name()->Variable()->TsType()->AsETSTypeParameter();
362 auto const traverseReferenced =
363 [this, scope = param->Parent()->AsTSTypeParameterDeclaration()->Scope()](ir::TypeNode *typeNode) {
364 if (!typeNode->IsETSTypeReference()) {
365 return;
366 }
367 const auto typeName = typeNode->AsETSTypeReference()->Part()->GetIdent()->Name();
368 auto *const found = scope->FindLocal(typeName, varbinder::ResolveBindingOptions::BINDINGS);
369 if (found != nullptr) {
370 SetUpTypeParameterConstraint(found->Declaration()->Node()->AsTSTypeParameter());
371 }
372 };
373
374 if (param->Constraint() != nullptr) {
375 traverseReferenced(param->Constraint());
376 paramType->SetConstraintType(param->Constraint()->GetType(this));
377 } else {
378 paramType->SetConstraintType(GlobalETSAnyType());
379 }
380
381 if (param->DefaultType() != nullptr) {
382 traverseReferenced(param->DefaultType());
383 // NOTE: #14993 ensure default matches constraint
384 paramType->SetDefaultType(MaybeBoxType(param->DefaultType()->GetType(this)));
385 }
386 }
387
SetUpParameterType(ir::TSTypeParameter * const param)388 ETSTypeParameter *ETSChecker::SetUpParameterType(ir::TSTypeParameter *const param)
389 {
390 auto *const var = param->Name()->Variable();
391 ES2PANDA_ASSERT(var != nullptr);
392
393 if (var->TsType() != nullptr) {
394 return var->TsType()->AsETSTypeParameter();
395 }
396
397 auto *const paramType = CreateTypeParameter();
398 ES2PANDA_ASSERT(paramType != nullptr);
399 paramType->AddTypeFlag(TypeFlag::GENERIC);
400 paramType->SetDeclNode(param);
401 paramType->SetVariable(param->Variable());
402 // NOTE: #15026 recursive type parameter workaround
403 paramType->SetConstraintType(GlobalETSAnyType());
404
405 var->SetTsType(paramType);
406 return paramType;
407 }
408
CreateTypeForClassOrInterfaceTypeParameters(ETSObjectType * type)409 void ETSChecker::CreateTypeForClassOrInterfaceTypeParameters(ETSObjectType *type)
410 {
411 if (type->HasObjectFlag(ETSObjectFlags::RESOLVED_TYPE_PARAMS)) {
412 return;
413 }
414
415 ir::TSTypeParameterDeclaration *typeParams = type->GetDeclNode()->IsClassDefinition()
416 ? type->GetDeclNode()->AsClassDefinition()->TypeParams()
417 : type->GetDeclNode()->AsTSInterfaceDeclaration()->TypeParams();
418 auto [typeParamTypes, ok] = CreateUnconstrainedTypeParameters(typeParams);
419 type->SetTypeArguments(std::move(typeParamTypes));
420 if (ok) {
421 AssignTypeParameterConstraints(typeParams);
422 }
423 type->AddObjectFlag(ETSObjectFlags::RESOLVED_TYPE_PARAMS);
424 type->AddObjectFlag(ETSObjectFlags::INCOMPLETE_INSTANTIATION);
425 }
426
BuildBasicInterfaceProperties(ir::TSInterfaceDeclaration * interfaceDecl)427 Type *ETSChecker::BuildBasicInterfaceProperties(ir::TSInterfaceDeclaration *interfaceDecl)
428 {
429 auto *var = interfaceDecl->Id()->Variable();
430 if (var == nullptr) {
431 ES2PANDA_ASSERT(IsAnyError());
432 return GlobalTypeError();
433 }
434
435 checker::ETSObjectType *interfaceType {};
436 if (var->TsType() == nullptr) {
437 interfaceType = CreateETSObjectTypeOrBuiltin(interfaceDecl, checker::ETSObjectFlags::INTERFACE);
438 interfaceType->SetVariable(var);
439 var->SetTsType(interfaceType);
440 } else if (var->TsType()->IsETSObjectType()) {
441 interfaceType = var->TsType()->AsETSObjectType();
442 } else {
443 ES2PANDA_ASSERT(IsAnyError());
444 return GlobalTypeError();
445 }
446
447 // Save before we mess with savedContext.
448 bool builtinsInitialized = HasStatus(CheckerStatus::BUILTINS_INITIALIZED);
449
450 auto *enclosingClass = Context().ContainingClass();
451 interfaceType->SetEnclosingType(enclosingClass);
452 CheckerStatus newStatus = CheckerStatus::IN_INTERFACE;
453 auto savedContext = checker::SavedCheckerContext(this, newStatus, interfaceType);
454 ConstraintCheckScope ctScope(this);
455 if (interfaceDecl->TypeParams() != nullptr) {
456 interfaceType->AddTypeFlag(TypeFlag::GENERIC);
457 CreateTypeForClassOrInterfaceTypeParameters(interfaceType);
458 }
459
460 GetInterfaces(interfaceType);
461 interfaceType->SetSuperType(GlobalETSObjectType());
462 ctScope.TryCheckConstraints();
463
464 // Skip this check if the builtins are not initialized.
465 // They will be initialized in different order,
466 // and it is possible that the FunctionType interface is not yet created.
467 if (builtinsInitialized) {
468 CheckInterfaceFunctions(interfaceType);
469 }
470
471 return interfaceType;
472 }
473
BuildBasicClassProperties(ir::ClassDefinition * classDef)474 Type *ETSChecker::BuildBasicClassProperties(ir::ClassDefinition *classDef)
475 {
476 if (classDef->IsFinal() && classDef->IsAbstract()) {
477 LogError(diagnostic::ABSTRACT_IS_FINAL, {}, classDef->Start());
478 }
479
480 auto *var = classDef->Ident()->Variable();
481 if (var == nullptr) {
482 ES2PANDA_ASSERT(IsAnyError());
483 return GlobalTypeError();
484 }
485
486 checker::ETSObjectType *classType {};
487 if (var->TsType() == nullptr) {
488 classType = CreateETSObjectTypeOrBuiltin(classDef, checker::ETSObjectFlags::CLASS);
489 classType->SetVariable(var);
490 var->SetTsType(classType);
491 if (classDef->IsAbstract()) {
492 classType->AddObjectFlag(checker::ETSObjectFlags::ABSTRACT);
493 }
494 } else if (var->TsType()->IsETSObjectType()) {
495 classType = var->TsType()->AsETSObjectType();
496 } else {
497 ES2PANDA_ASSERT(IsAnyError());
498 return GlobalTypeError();
499 }
500
501 classDef->SetTsType(classType);
502
503 ConstraintCheckScope ctScope(this);
504 if (classDef->TypeParams() != nullptr) {
505 classType->AddTypeFlag(TypeFlag::GENERIC);
506 CreateTypeForClassOrInterfaceTypeParameters(classType);
507 }
508
509 auto *enclosingClass = Context().ContainingClass();
510 classType->SetEnclosingType(enclosingClass);
511 CheckerStatus newStatus = CheckerStatus::IN_CLASS;
512
513 if (classDef->IsInner()) {
514 newStatus |= CheckerStatus::INNER_CLASS;
515 classType->AddObjectFlag(checker::ETSObjectFlags::INNER);
516 }
517
518 auto savedContext = checker::SavedCheckerContext(this, newStatus, classType);
519
520 if (!classType->HasObjectFlag(ETSObjectFlags::RESOLVED_SUPER)) {
521 GetSuperType(classType);
522 GetInterfaces(classType);
523 }
524 ctScope.TryCheckConstraints();
525 return classType;
526 }
527
BuildAnonymousClassProperties(ir::ClassDefinition * classDef,ETSObjectType * superType)528 ETSObjectType *ETSChecker::BuildAnonymousClassProperties(ir::ClassDefinition *classDef, ETSObjectType *superType)
529 {
530 auto classType = CreateETSObjectType(classDef, checker::ETSObjectFlags::CLASS);
531 classDef->SetTsType(classType);
532 ES2PANDA_ASSERT(classType != nullptr);
533 classType->SetSuperType(superType);
534 classType->AddObjectFlag(checker::ETSObjectFlags::RESOLVED_SUPER);
535
536 return classType;
537 }
538
ResolveDeclaredFieldsOfObject(ETSChecker * checker,const ETSObjectType * type,varbinder::ClassScope * scope)539 static void ResolveDeclaredFieldsOfObject(ETSChecker *checker, const ETSObjectType *type, varbinder::ClassScope *scope)
540 {
541 for (auto &[_, it] : scope->InstanceFieldScope()->Bindings()) {
542 (void)_;
543 ES2PANDA_ASSERT(it->Declaration()->Node()->IsClassProperty());
544 auto *classProp = it->Declaration()->Node()->AsClassProperty();
545 it->AddFlag(checker->GetAccessFlagFromNode(classProp));
546 type->AddProperty<PropertyType::INSTANCE_FIELD>(it->AsLocalVariable());
547 }
548
549 for (auto &[_, it] : scope->StaticFieldScope()->Bindings()) {
550 (void)_;
551 ES2PANDA_ASSERT(it->Declaration()->Node()->IsClassProperty());
552 auto *classProp = it->Declaration()->Node()->AsClassProperty();
553 it->AddFlag(checker->GetAccessFlagFromNode(classProp));
554 type->AddProperty<PropertyType::STATIC_FIELD>(it->AsLocalVariable());
555 }
556 }
557
558 // CC-OFFNXT(huge_method[C++], G.FUN.01-CPP) solid logic
ResolveDeclaredMethodsOfObject(ETSChecker * checker,const ETSObjectType * type,varbinder::ClassScope * scope)559 static void ResolveDeclaredMethodsOfObject(ETSChecker *checker, const ETSObjectType *type, varbinder::ClassScope *scope)
560 {
561 for (auto &[_, it] : scope->InstanceMethodScope()->Bindings()) {
562 (void)_;
563 auto *method = it->Declaration()->Node()->AsMethodDefinition();
564 auto *function = method->Function();
565 ES2PANDA_ASSERT(function != nullptr);
566 if (function->IsProxy()) {
567 continue;
568 }
569
570 it->AddFlag(checker->GetAccessFlagFromNode(method));
571 auto *funcType = checker->BuildMethodSignature(method);
572 if (!funcType->IsTypeError()) {
573 funcType->SetVariable(it);
574 }
575 it->SetTsType(funcType);
576 method->SetTsType(funcType);
577 type->AddProperty<PropertyType::INSTANCE_METHOD>(it->AsLocalVariable());
578 }
579
580 for (auto &[_, it] : scope->StaticMethodScope()->Bindings()) {
581 (void)_;
582 if (!it->Declaration()->Node()->IsMethodDefinition()) {
583 continue;
584 }
585
586 auto *method = it->Declaration()->Node()->AsMethodDefinition();
587 auto *function = method->Function();
588 ES2PANDA_ASSERT(function != nullptr);
589 if (function->IsProxy()) {
590 continue;
591 }
592
593 it->AddFlag(checker->GetAccessFlagFromNode(method));
594 auto *funcType = checker->BuildMethodSignature(method);
595 if (!funcType->IsTypeError()) {
596 funcType->SetVariable(it);
597 }
598 it->SetTsType(funcType);
599 method->SetTsType(funcType);
600
601 if (method->IsConstructor() && funcType->IsETSFunctionType()) {
602 type->AddConstructSignature(funcType->AsETSFunctionType()->CallSignatures());
603 continue;
604 }
605
606 type->AddProperty<PropertyType::STATIC_METHOD>(it->AsLocalVariable());
607 }
608 }
609
ResolveDeclaredDeclsOfObject(ETSChecker * checker,const ETSObjectType * type,varbinder::ClassScope * scope)610 static void ResolveDeclaredDeclsOfObject(ETSChecker *checker, const ETSObjectType *type, varbinder::ClassScope *scope)
611 {
612 for (auto &[_, it] : scope->InstanceDeclScope()->Bindings()) {
613 (void)_;
614 it->AddFlag(checker->GetAccessFlagFromNode(it->Declaration()->Node()));
615 type->AddProperty<PropertyType::INSTANCE_DECL>(it->AsLocalVariable());
616 }
617
618 for (auto &[_, it] : scope->StaticDeclScope()->Bindings()) {
619 (void)_;
620 it->AddFlag(checker->GetAccessFlagFromNode(it->Declaration()->Node()));
621 type->AddProperty<PropertyType::STATIC_DECL>(it->AsLocalVariable());
622 }
623 for (auto &[_, it] : scope->TypeAliasScope()->Bindings()) {
624 (void)_;
625 it->AddFlag(checker->GetAccessFlagFromNode(it->Declaration()->Node()));
626 type->AddProperty<PropertyType::STATIC_DECL>(it->AsLocalVariable());
627 }
628 }
629
ResolveDeclaredMembersOfObject(const Type * type)630 void ETSChecker::ResolveDeclaredMembersOfObject(const Type *type)
631 {
632 if (!type->IsETSObjectType() || type->AsETSObjectType()->IsPropertiesInstantiated()) {
633 return;
634 }
635
636 auto *objectType = type->AsETSObjectType();
637 auto *declNode = objectType->GetDeclNode();
638
639 // Note: the DeclNode of ETSStringLiteralType is totally the same as its super type: `ETSObjectType-String`.
640 if (objectType->IsETSStringLiteralType() || declNode == nullptr ||
641 !(declNode->IsClassDefinition() || declNode->IsTSInterfaceDeclaration())) {
642 return;
643 }
644
645 if (objectType->IsGeneric() && objectType != objectType->GetOriginalBaseType()) {
646 const auto *baseType = objectType->GetOriginalBaseType();
647 auto *baseDeclNode = baseType->GetDeclNode();
648 checker::CheckerStatus baseStatus = baseDeclNode->IsTSInterfaceDeclaration()
649 ? checker::CheckerStatus::IN_INTERFACE
650 : checker::CheckerStatus::IN_CLASS;
651 auto baseScope = baseDeclNode->IsTSInterfaceDeclaration() ? baseDeclNode->AsTSInterfaceDeclaration()->Scope()
652 : baseDeclNode->AsClassDefinition()->Scope();
653 auto savedContext = checker::SavedCheckerContext(this, baseStatus, baseType);
654 checker::ScopeContext scopeCtx(this, baseScope);
655 ResolveDeclaredMembersOfObject(baseType);
656 return;
657 }
658
659 checker::CheckerStatus status =
660 declNode->IsTSInterfaceDeclaration() ? checker::CheckerStatus::IN_INTERFACE : checker::CheckerStatus::IN_CLASS;
661 auto *scope = declNode->IsTSInterfaceDeclaration() ? declNode->AsTSInterfaceDeclaration()->Scope()
662 : declNode->AsClassDefinition()->Scope();
663 auto savedContext = checker::SavedCheckerContext(this, status, objectType);
664 checker::ScopeContext scopeCtx(this, scope);
665
666 ResolveDeclaredDeclsOfObject(this, objectType, scope->AsClassScope());
667 ResolveDeclaredFieldsOfObject(this, objectType, scope->AsClassScope());
668 ResolveDeclaredMethodsOfObject(this, objectType, scope->AsClassScope());
669 }
670
HasETSFunctionType(ir::TypeNode * typeAnnotation)671 bool ETSChecker::HasETSFunctionType(ir::TypeNode *typeAnnotation)
672 {
673 if (typeAnnotation->IsETSFunctionType()) {
674 return true;
675 }
676 std::unordered_set<ir::TypeNode *> childrenSet;
677
678 if (!typeAnnotation->IsETSTypeReference()) {
679 return false;
680 }
681
682 auto const addTypeAlias = [&childrenSet, &typeAnnotation](varbinder::Decl *typeDecl) {
683 typeAnnotation = typeDecl->Node()->AsTSTypeAliasDeclaration()->TypeAnnotation();
684 if (!typeAnnotation->IsETSUnionType()) {
685 childrenSet.insert(typeAnnotation);
686 return;
687 }
688 for (auto *type : typeAnnotation->AsETSUnionType()->Types()) {
689 if (type->IsETSTypeReference()) {
690 childrenSet.insert(type);
691 }
692 }
693 };
694
695 auto *typeDecl = typeAnnotation->AsETSTypeReference()->Part()->GetIdent()->Variable()->Declaration();
696 if (typeDecl != nullptr && typeDecl->IsTypeAliasDecl()) {
697 addTypeAlias(typeDecl);
698 }
699
700 for (auto *child : childrenSet) {
701 if (HasETSFunctionType(child)) {
702 return true;
703 }
704 }
705 return false;
706 }
707
CollectAbstractSignaturesFromObject(const ETSObjectType * objType)708 std::vector<Signature *> ETSChecker::CollectAbstractSignaturesFromObject(const ETSObjectType *objType)
709 {
710 std::vector<Signature *> abstracts;
711 for (const auto &prop : objType->Methods()) {
712 GetTypeOfVariable(prop);
713
714 if (!prop->TsType()->IsETSFunctionType()) {
715 continue;
716 }
717
718 for (auto *sig : prop->TsType()->AsETSFunctionType()->CallSignatures()) {
719 if (sig->HasSignatureFlag(SignatureFlags::ABSTRACT) && !sig->HasSignatureFlag(SignatureFlags::PRIVATE)) {
720 abstracts.push_back(sig);
721 }
722 }
723 }
724
725 return abstracts;
726 }
727
CreateFunctionTypesFromAbstracts(const std::vector<Signature * > & abstracts,ArenaVector<ETSFunctionType * > * target)728 void ETSChecker::CreateFunctionTypesFromAbstracts(const std::vector<Signature *> &abstracts,
729 ArenaVector<ETSFunctionType *> *target)
730 {
731 for (auto *it : abstracts) {
732 auto name = it->Function()->Id()->Name();
733 auto *found = FindFunctionInVectorGivenByName(name, *target);
734 if (found != nullptr) {
735 found->AddCallSignature(it);
736 } else {
737 target->push_back(CreateETSMethodType(name, {{it}, ProgramAllocator()->Adapter()}));
738 }
739 }
740 }
741
ComputeAbstractsFromInterface(ETSObjectType * interfaceType)742 void ETSChecker::ComputeAbstractsFromInterface(ETSObjectType *interfaceType)
743 {
744 auto cachedComputedAbstracts = GetCachedComputedAbstracts();
745 ES2PANDA_ASSERT(cachedComputedAbstracts != nullptr);
746 auto cached = cachedComputedAbstracts->find(interfaceType);
747 if (cached != cachedComputedAbstracts->end()) {
748 return;
749 }
750
751 for (auto *it : interfaceType->Interfaces()) {
752 ComputeAbstractsFromInterface(it);
753 }
754
755 ArenaVector<ETSFunctionType *> merged(ProgramAllocator()->Adapter());
756 CreateFunctionTypesFromAbstracts(CollectAbstractSignaturesFromObject(interfaceType), &merged);
757 ArenaUnorderedSet<ETSObjectType *> abstractInheritanceTarget(ProgramAllocator()->Adapter());
758
759 for (auto *interface : interfaceType->Interfaces()) {
760 auto found = cachedComputedAbstracts->find(interface);
761 ES2PANDA_ASSERT(found != cachedComputedAbstracts->end());
762
763 if (!abstractInheritanceTarget.insert(found->first).second) {
764 continue;
765 }
766
767 MergeComputedAbstracts(merged, found->second.first);
768
769 for (auto *base : found->second.second) {
770 abstractInheritanceTarget.insert(base);
771 }
772 }
773
774 cachedComputedAbstracts->insert({interfaceType, {merged, abstractInheritanceTarget}});
775 }
776
GetAbstractsForClass(ETSObjectType * classType)777 ArenaVector<ETSFunctionType *> &ETSChecker::GetAbstractsForClass(ETSObjectType *classType)
778 {
779 ArenaVector<ETSFunctionType *> merged(ProgramAllocator()->Adapter());
780 CreateFunctionTypesFromAbstracts(CollectAbstractSignaturesFromObject(classType), &merged);
781
782 ArenaUnorderedSet<ETSObjectType *> abstractInheritanceTarget(ProgramAllocator()->Adapter());
783 if (classType->SuperType() != nullptr) {
784 auto base = GetCachedComputedAbstracts()->find(classType->SuperType());
785 ES2PANDA_ASSERT(base != GetCachedComputedAbstracts()->end());
786 MergeComputedAbstracts(merged, base->second.first);
787
788 abstractInheritanceTarget.insert(base->first);
789 for (auto *it : base->second.second) {
790 abstractInheritanceTarget.insert(it);
791 }
792 }
793
794 for (auto *it : classType->Interfaces()) {
795 ComputeAbstractsFromInterface(it);
796 auto found = GetCachedComputedAbstracts()->find(it);
797 ES2PANDA_ASSERT(found != GetCachedComputedAbstracts()->end());
798
799 if (!abstractInheritanceTarget.insert(found->first).second) {
800 continue;
801 }
802
803 MergeComputedAbstracts(merged, found->second.first);
804
805 for (auto *interface : found->second.second) {
806 abstractInheritanceTarget.insert(interface);
807 }
808 }
809
810 return GetCachedComputedAbstracts()->insert({classType, {merged, abstractInheritanceTarget}}).first->second.first;
811 }
812
DoObjectImplementInterface(const ETSObjectType * interfaceType,const ETSObjectType * target,const ETSChecker * checker)813 [[maybe_unused]] static bool DoObjectImplementInterface(const ETSObjectType *interfaceType, const ETSObjectType *target,
814 const ETSChecker *checker)
815 {
816 auto &interfaces = interfaceType->Interfaces();
817 return std::any_of(interfaces.begin(), interfaces.end(), [&target, checker](auto *it) {
818 return it->IsSameBasedGeneric(checker->Relation(), target) || DoObjectImplementInterface(it, target, checker);
819 });
820 }
821
CheckIfInterfaceCanBeFoundOnDifferentPaths(const ETSObjectType * classType,const ETSObjectType * interfaceType,const ETSChecker * checker)822 static bool CheckIfInterfaceCanBeFoundOnDifferentPaths(const ETSObjectType *classType,
823 const ETSObjectType *interfaceType, const ETSChecker *checker)
824 {
825 return std::count_if(classType->Interfaces().begin(), classType->Interfaces().end(),
826 [&interfaceType, checker](auto *it) {
827 return DoObjectImplementInterface(it, interfaceType, checker);
828 }) == 1;
829 }
830
GetInterfacesOfClass(ETSObjectType * type,ArenaVector<ETSObjectType * > & interfaces)831 void ETSChecker::GetInterfacesOfClass(ETSObjectType *type, ArenaVector<ETSObjectType *> &interfaces)
832 {
833 for (auto &classInterface : type->Interfaces()) {
834 if (std::find(interfaces.begin(), interfaces.end(), classInterface) == interfaces.end()) {
835 interfaces.emplace_back(classInterface);
836 GetInterfacesOfClass(classInterface, interfaces);
837 }
838 }
839 }
840
CheckIfOverrideIsValidInInterface(ETSObjectType * classType,Signature * sig,Signature * sigFunc)841 void ETSChecker::CheckIfOverrideIsValidInInterface(ETSObjectType *classType, Signature *sig, Signature *sigFunc)
842 {
843 bool throwError = false;
844 if (AreOverrideCompatible(sig, sigFunc) && sigFunc->Function()->IsStatic() == sig->Function()->IsStatic()) {
845 SavedTypeRelationFlagsContext const savedFlags(Relation(), Relation()->GetTypeRelationFlags() |
846 TypeRelationFlag::IGNORE_TYPE_PARAMETERS);
847 if (CheckIfInterfaceCanBeFoundOnDifferentPaths(classType, sigFunc->Owner(), this) &&
848 (Relation()->IsSupertypeOf(sigFunc->Owner(), sig->Owner()) ||
849 Relation()->IsSupertypeOf(sig->Owner(), sigFunc->Owner()))) {
850 return;
851 }
852 throwError = true;
853 } else if (sigFunc->Function()->IsStatic() == sig->Function()->IsStatic()) {
854 Relation()->Result(false);
855 SavedTypeRelationFlagsContext savedFlagsCtx(Relation(), TypeRelationFlag::NO_RETURN_TYPE_CHECK);
856
857 Relation()->SignatureIsIdenticalTo(sig, sigFunc);
858 if ((Relation()->IsTrue() &&
859 (sig->GetSignatureInfo()->restVar == nullptr) == (sigFunc->GetSignatureInfo()->restVar == nullptr)) ||
860 (HasSameAssemblySignature(sigFunc, sig))) {
861 throwError = true;
862 }
863 }
864 if (throwError) {
865 LogError(diagnostic::INTERFACE_METHOD_COLLISION,
866 {sig->Function()->Id()->Name(), sig->Owner()->Name(), sigFunc->Owner()->Name()},
867 classType->GetDeclNode()->Start());
868 }
869 }
870
CheckFunctionRedeclarationInInterface(ETSObjectType * classType,ArenaVector<Signature * > & similarSignatures,Signature * sigFunc)871 void ETSChecker::CheckFunctionRedeclarationInInterface(ETSObjectType *classType,
872 ArenaVector<Signature *> &similarSignatures, Signature *sigFunc)
873 {
874 for (auto *const sig : similarSignatures) {
875 if (sig == sigFunc) {
876 return;
877 }
878 ES2PANDA_ASSERT(sigFunc != nullptr);
879 if (sigFunc->Function()->Id()->Name() == sig->Function()->Id()->Name()) {
880 if (classType->IsSameBasedGeneric(Relation(), sig->Owner())) {
881 return;
882 }
883 if (Relation()->IsIdenticalTo(sig->Owner(), sigFunc->Owner())) {
884 continue;
885 }
886 CheckIfOverrideIsValidInInterface(classType, sig, sigFunc);
887 }
888 }
889
890 similarSignatures.push_back(sigFunc);
891 }
892
CallRedeclarationCheckForCorrectSignature(ir::MethodDefinition * method,ETSFunctionType * funcType,ArenaVector<Signature * > & similarSignatures,ETSObjectType * classType,ETSChecker * checker)893 static void CallRedeclarationCheckForCorrectSignature(ir::MethodDefinition *method, ETSFunctionType *funcType,
894 ArenaVector<Signature *> &similarSignatures,
895 ETSObjectType *classType, ETSChecker *checker)
896 {
897 ir::ScriptFunction *func = method->Function();
898 ES2PANDA_ASSERT(func != nullptr);
899 if (!func->IsAbstract()) {
900 auto *sigFunc = funcType->FindSignature(func);
901 checker->CheckFunctionRedeclarationInInterface(classType, similarSignatures, sigFunc);
902 }
903 }
904
CheckInterfaceFunctions(ETSObjectType * classType)905 void ETSChecker::CheckInterfaceFunctions(ETSObjectType *classType)
906 {
907 ArenaVector<ETSObjectType *> interfaces(ProgramAllocator()->Adapter());
908 ArenaVector<Signature *> similarSignatures(ProgramAllocator()->Adapter());
909 interfaces.emplace_back(classType);
910 GetInterfacesOfClass(classType, interfaces);
911
912 for (auto *const &interface : interfaces) {
913 for (auto *const &prop : interface->Methods()) {
914 ir::MethodDefinition *node = prop->Declaration()->Node()->AsMethodDefinition();
915 if (prop->TsType()->IsTypeError()) {
916 continue;
917 }
918 auto *funcType = prop->TsType()->AsETSFunctionType();
919 CallRedeclarationCheckForCorrectSignature(node, funcType, similarSignatures, classType, this);
920 for (auto *const &overload : node->Overloads()) {
921 CallRedeclarationCheckForCorrectSignature(overload, funcType, similarSignatures, classType, this);
922 }
923 }
924 }
925 }
926
927 /// Traverse the interface inheritance tree and collects implemented methods
CollectImplementedMethodsFromInterfaces(ETSObjectType * classType,std::vector<Signature * > * implementedSignatures,const ArenaVector<ETSFunctionType * > & abstractsToBeImplemented)928 void ETSChecker::CollectImplementedMethodsFromInterfaces(ETSObjectType *classType,
929 std::vector<Signature *> *implementedSignatures,
930 const ArenaVector<ETSFunctionType *> &abstractsToBeImplemented)
931 {
932 std::vector<ETSObjectType *> collectedInterfaces;
933
934 for (auto &classInterface : classType->Interfaces()) {
935 collectedInterfaces.emplace_back(classInterface);
936 }
937
938 size_t index = 0;
939
940 while (index < collectedInterfaces.size()) {
941 for (auto &it : abstractsToBeImplemented) {
942 for (const auto &prop : collectedInterfaces[index]->Methods()) {
943 GetTypeOfVariable(prop);
944 AddImplementedSignature(implementedSignatures, prop, it);
945 }
946 }
947
948 for (auto ¤tInterfaceChild : collectedInterfaces[index]->Interfaces()) {
949 collectedInterfaces.emplace_back(currentInterfaceChild);
950 }
951
952 index++;
953 }
954 }
955
ValidateAbstractSignature(ArenaVector<ETSFunctionType * >::iterator & it,ArenaVector<ETSFunctionType * > & abstractsToBeImplemented,const std::vector<Signature * > & implementedSignatures,bool & functionOverridden,Accessor & isGetSetExternal)956 void ETSChecker::ValidateAbstractSignature(ArenaVector<ETSFunctionType *>::iterator &it,
957 ArenaVector<ETSFunctionType *> &abstractsToBeImplemented,
958 const std::vector<Signature *> &implementedSignatures,
959 bool &functionOverridden, Accessor &isGetSetExternal)
960 {
961 for (auto abstractSignature = (*it)->CallSignatures().begin();
962 abstractSignature != (*it)->CallSignatures().end();) {
963 bool foundSignature = false;
964 isGetSetExternal.isGetter = (*abstractSignature)->HasSignatureFlag(SignatureFlags::GETTER);
965 isGetSetExternal.isSetter = (*abstractSignature)->HasSignatureFlag(SignatureFlags::SETTER);
966 isGetSetExternal.isExternal = (*abstractSignature)->Function()->IsExternal();
967 for (auto *const implemented : implementedSignatures) {
968 if (implemented->HasSignatureFlag(SignatureFlags::NEED_RETURN_TYPE)) {
969 implemented->OwnerVar()->Declaration()->Node()->Check(this);
970 }
971 Signature *substImplemented = AdjustForTypeParameters(*abstractSignature, implemented);
972
973 if (substImplemented == nullptr) {
974 continue;
975 }
976
977 if (!AreOverrideCompatible(*abstractSignature, substImplemented) ||
978 !IsReturnTypeSubstitutable(substImplemented, *abstractSignature)) {
979 continue;
980 }
981
982 if ((*it)->CallSignatures().size() > 1) {
983 abstractSignature = (*it)->CallSignatures().erase(abstractSignature);
984 foundSignature = true;
985 } else {
986 it = abstractsToBeImplemented.erase(it);
987 functionOverridden = true;
988 }
989
990 break;
991 }
992
993 if (functionOverridden) {
994 break;
995 }
996
997 if (!foundSignature) {
998 ++abstractSignature;
999 }
1000 }
1001 }
1002
ValidateNonOverriddenFunction(ETSObjectType * classType,ArenaVector<ETSFunctionType * >::iterator & it,ArenaVector<ETSFunctionType * > & abstractsToBeImplemented,bool & functionOverridden,const Accessor & isGetSet)1003 void ETSChecker::ValidateNonOverriddenFunction(ETSObjectType *classType, ArenaVector<ETSFunctionType *>::iterator &it,
1004 ArenaVector<ETSFunctionType *> &abstractsToBeImplemented,
1005 bool &functionOverridden, const Accessor &isGetSet)
1006 {
1007 auto superClassType = classType->SuperType();
1008 while (!functionOverridden && superClassType != nullptr) {
1009 for (auto *field : superClassType->Fields()) {
1010 if (field->Name() == (*it)->Name()) {
1011 auto *newProp = field->Declaration()
1012 ->Node()
1013 ->Clone(ProgramAllocator(), classType->GetDeclNode())
1014 ->AsClassProperty();
1015 newProp->AddModifier(ir::ModifierFlags::SUPER_OWNER);
1016 newProp->AddModifier(isGetSet.isGetter && isGetSet.isSetter ? ir::ModifierFlags::GETTER_SETTER
1017 : isGetSet.isGetter ? ir::ModifierFlags::GETTER
1018 : ir::ModifierFlags::SETTER);
1019 auto *newFieldDecl =
1020 ProgramAllocator()->New<varbinder::LetDecl>(newProp->Key()->AsIdentifier()->Name());
1021 newFieldDecl->BindNode(newProp);
1022
1023 auto newFieldVar = classType->GetDeclNode()
1024 ->Scope()
1025 ->AsClassScope()
1026 ->InstanceFieldScope()
1027 ->AddDecl(ProgramAllocator(), newFieldDecl, ScriptExtension::ETS)
1028 ->AsLocalVariable();
1029 newFieldVar->AddFlag(varbinder::VariableFlags::PROPERTY);
1030 newFieldVar->AddFlag(varbinder::VariableFlags::PUBLIC);
1031 classType->AddProperty<PropertyType::INSTANCE_FIELD>(newFieldVar);
1032 it = abstractsToBeImplemented.erase(it);
1033 functionOverridden = true;
1034 break;
1035 }
1036 }
1037
1038 superClassType = superClassType->SuperType();
1039 }
1040 }
1041
ApplyModifiersAndRemoveImplementedAbstracts(ArenaVector<ETSFunctionType * >::iterator & it,ArenaVector<ETSFunctionType * > & abstractsToBeImplemented,ETSObjectType * classType,bool & functionOverridden,const Accessor & isGetSetExternal)1042 void ETSChecker::ApplyModifiersAndRemoveImplementedAbstracts(ArenaVector<ETSFunctionType *>::iterator &it,
1043 ArenaVector<ETSFunctionType *> &abstractsToBeImplemented,
1044 ETSObjectType *classType, bool &functionOverridden,
1045 const Accessor &isGetSetExternal)
1046 {
1047 for (auto *field : classType->Fields()) {
1048 if (field->Name() == (*it)->Name()) {
1049 field->Declaration()->Node()->AddModifier(isGetSetExternal.isGetter && isGetSetExternal.isSetter
1050 ? ir::ModifierFlags::GETTER_SETTER
1051 : isGetSetExternal.isGetter ? ir::ModifierFlags::GETTER
1052 : ir::ModifierFlags::SETTER);
1053 it = abstractsToBeImplemented.erase(it);
1054 functionOverridden = true;
1055 break;
1056 }
1057 }
1058 }
1059
ValidateAbstractMethodsToBeImplemented(ArenaVector<ETSFunctionType * > & abstractsToBeImplemented,ETSObjectType * classType,const std::vector<Signature * > & implementedSignatures)1060 void ETSChecker::ValidateAbstractMethodsToBeImplemented(ArenaVector<ETSFunctionType *> &abstractsToBeImplemented,
1061 ETSObjectType *classType,
1062 const std::vector<Signature *> &implementedSignatures)
1063 {
1064 SavedTypeRelationFlagsContext savedFlagsCtx(Relation(), TypeRelationFlag::NO_RETURN_TYPE_CHECK);
1065 for (auto it = abstractsToBeImplemented.begin(); it != abstractsToBeImplemented.end();) {
1066 bool functionOverridden = false;
1067 Accessor isGetSetExternal;
1068
1069 ValidateAbstractSignature(it, abstractsToBeImplemented, implementedSignatures, functionOverridden,
1070 isGetSetExternal);
1071
1072 if (functionOverridden) {
1073 continue;
1074 }
1075
1076 if (!isGetSetExternal.isGetter && !isGetSetExternal.isSetter) {
1077 it++;
1078 continue;
1079 }
1080
1081 ApplyModifiersAndRemoveImplementedAbstracts(it, abstractsToBeImplemented, classType, functionOverridden,
1082 isGetSetExternal);
1083
1084 if (functionOverridden) {
1085 continue;
1086 }
1087
1088 ValidateNonOverriddenFunction(classType, it, abstractsToBeImplemented, functionOverridden, isGetSetExternal);
1089
1090 if (!functionOverridden) {
1091 it++;
1092 }
1093 }
1094 }
1095
MaybeReportErrorsForOverridingValidation(ArenaVector<ETSFunctionType * > & abstractsToBeImplemented,ETSObjectType * classType,const lexer::SourcePosition & pos,bool reportError)1096 void ETSChecker::MaybeReportErrorsForOverridingValidation(ArenaVector<ETSFunctionType *> &abstractsToBeImplemented,
1097 ETSObjectType *classType, const lexer::SourcePosition &pos,
1098 bool reportError)
1099 {
1100 if (!abstractsToBeImplemented.empty() && reportError) {
1101 auto unimplementedSignature = abstractsToBeImplemented.front()->CallSignatures().front();
1102 auto containingObjectName = GetContainingObjectNameFromSignature(unimplementedSignature);
1103 if (unimplementedSignature->HasSignatureFlag(SignatureFlags::GETTER)) {
1104 LogError(diagnostic::GETTER_MISSING_IMPL,
1105 {classType->Name(), unimplementedSignature->Function()->Id()->Name(), containingObjectName}, pos);
1106 return;
1107 }
1108 if (unimplementedSignature->HasSignatureFlag(SignatureFlags::SETTER)) {
1109 LogError(diagnostic::SETTER_MISSING_IMPL,
1110 {classType->Name(), unimplementedSignature->Function()->Id()->Name(), containingObjectName}, pos);
1111 return;
1112 }
1113 LogError(diagnostic::MISSING_OVERRIDE_OF_ABSTRACT_METH,
1114 {classType->Name(), unimplementedSignature->Function()->Id()->Name(), unimplementedSignature,
1115 containingObjectName},
1116 pos);
1117 }
1118 }
1119
ValidateOverriding(ETSObjectType * classType,const lexer::SourcePosition & pos)1120 void ETSChecker::ValidateOverriding(ETSObjectType *classType, const lexer::SourcePosition &pos)
1121 {
1122 if (classType->HasObjectFlag(ETSObjectFlags::CHECKED_COMPATIBLE_ABSTRACTS)) {
1123 return;
1124 }
1125
1126 bool throwError = true;
1127 if (classType->HasObjectFlag(ETSObjectFlags::ABSTRACT)) {
1128 throwError = false;
1129 }
1130
1131 if (classType->SuperType() != nullptr) {
1132 ValidateOverriding(classType->SuperType(), classType->SuperType()->GetDeclNode()->Start());
1133 }
1134
1135 auto &abstractsToBeImplemented = GetAbstractsForClass(classType);
1136 std::vector<Signature *> implementedSignatures;
1137
1138 // Since interfaces can define function bodies we have to collect the implemented ones first
1139 CollectImplementedMethodsFromInterfaces(classType, &implementedSignatures, abstractsToBeImplemented);
1140 CheckInterfaceFunctions(classType);
1141
1142 auto *superIter = classType;
1143 do {
1144 for (auto &it : abstractsToBeImplemented) {
1145 for (const auto &prop : superIter->Methods()) {
1146 GetTypeOfVariable(prop);
1147 AddImplementedSignature(&implementedSignatures, prop, it);
1148 }
1149 }
1150 superIter = superIter->SuperType();
1151 } while (superIter != nullptr);
1152 ValidateAbstractMethodsToBeImplemented(abstractsToBeImplemented, classType, implementedSignatures);
1153 MaybeReportErrorsForOverridingValidation(abstractsToBeImplemented, classType, pos, throwError);
1154
1155 classType->AddObjectFlag(ETSObjectFlags::CHECKED_COMPATIBLE_ABSTRACTS);
1156 }
1157
AddImplementedSignature(std::vector<Signature * > * implementedSignatures,varbinder::LocalVariable * function,ETSFunctionType * it)1158 void ETSChecker::AddImplementedSignature(std::vector<Signature *> *implementedSignatures,
1159 varbinder::LocalVariable *function, ETSFunctionType *it)
1160 {
1161 if (!function->TsType()->IsETSFunctionType()) {
1162 return;
1163 }
1164
1165 for (auto signature : function->TsType()->AsETSFunctionType()->CallSignatures()) {
1166 if (signature->Function()->IsAbstract() || signature->Function()->IsStatic()) {
1167 continue;
1168 }
1169
1170 if (signature->Function()->Id()->Name() == it->Name()) {
1171 implementedSignatures->emplace_back(signature);
1172 }
1173 }
1174 }
1175
CheckLocalClass(ir::ClassDefinition * classDef,CheckerStatus & checkerStatus)1176 void ETSChecker::CheckLocalClass(ir::ClassDefinition *classDef, CheckerStatus &checkerStatus)
1177 {
1178 if (!classDef->IsLocal()) {
1179 return;
1180 }
1181 checkerStatus |= CheckerStatus::IN_LOCAL_CLASS;
1182 if (!classDef->Parent()->Parent()->IsBlockStatement()) {
1183 LogError(diagnostic::LOCAL_CLASS_INVALID_CTX, {}, classDef->Start());
1184 }
1185 // NOTE(dkofanov): Related to spec 17.9.3 expecting CTE (native methods in local classes).
1186 // Actually, if I'm not mistaken, the only reason to forbid this is problematic binding of native method to the
1187 // mangled local class method, which is not really a reason for such restrictions. The spec should be revisited in
1188 // the future.
1189 if (classDef->HasNativeMethod()) {
1190 LogError(diagnostic::LOCAL_CLASS_NATIVE_METHOD, {classDef->Ident()->Name()}, classDef->Start());
1191 }
1192 }
1193
1194 // CC-OFFNXT(huge_method[C++], G.FUN.01-CPP) solid logic
CheckClassDefinition(ir::ClassDefinition * classDef)1195 void ETSChecker::CheckClassDefinition(ir::ClassDefinition *classDef)
1196 {
1197 classDef->SetClassDefinitionChecked();
1198
1199 if (classDef->TsType() == nullptr) {
1200 ES2PANDA_ASSERT(IsAnyError());
1201 classDef->SetTsType(GlobalTypeError());
1202 }
1203
1204 if (classDef->TsType()->IsTypeError()) {
1205 return;
1206 }
1207
1208 auto *classType = classDef->TsType()->AsETSObjectType();
1209 if (classType->SuperType() != nullptr) {
1210 classType->SuperType()->GetDeclNode()->Check(this);
1211 }
1212
1213 if (classType->GetDeclNode() != classDef) {
1214 ES2PANDA_ASSERT(IsAnyError());
1215 classDef->SetTsType(GlobalTypeError());
1216 return;
1217 }
1218
1219 auto newStatus = checker::CheckerStatus::IN_CLASS;
1220 if (Context().ContainingClass() != classType) {
1221 classType->SetEnclosingType(Context().ContainingClass());
1222 }
1223
1224 if (classDef->IsInner()) {
1225 newStatus |= CheckerStatus::INNER_CLASS;
1226 classType->AddObjectFlag(checker::ETSObjectFlags::INNER);
1227 }
1228
1229 classDef->IsModule() ? classType->AddObjectFlag(checker::ETSObjectFlags::GLOBAL)
1230 : CheckLocalClass(classDef, newStatus);
1231
1232 checker::ScopeContext scopeCtx(this, classDef->Scope());
1233 auto savedContext = SavedCheckerContext(this, newStatus, classType);
1234
1235 ResolveDeclaredMembersOfObject(classType);
1236
1237 if (classDef->IsAbstract()) {
1238 AddStatus(checker::CheckerStatus::IN_ABSTRACT);
1239 classType->AddObjectFlag(checker::ETSObjectFlags::ABSTRACT);
1240 }
1241
1242 if (classDef->IsStatic() && !Context().ContainingClass()->HasObjectFlag(ETSObjectFlags::GLOBAL)) {
1243 AddStatus(checker::CheckerStatus::IN_STATIC_CONTEXT);
1244 }
1245
1246 // NOTE(gogabr): temporary, until we have proper bridges, see #16485
1247 // Don't check overriding for synthetic functional classes.
1248 if ((static_cast<ir::AstNode *>(classDef)->Modifiers() & ir::ModifierFlags::FUNCTIONAL) == 0) {
1249 ValidateOverriding(classType, classDef->Start());
1250 }
1251
1252 // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
1253 TransformProperties(classType);
1254 CheckClassElement(classDef);
1255
1256 if (classType->SuperType() == nullptr) {
1257 return;
1258 }
1259
1260 CheckClassAnnotations(classDef);
1261
1262 if (classDef->IsGlobal()) {
1263 return;
1264 }
1265
1266 CheckConstructors(classDef, classType);
1267 CheckValidInheritance(classType, classDef);
1268 CheckConstFields(classType);
1269 CheckGetterSetterProperties(classType);
1270 CheckInvokeMethodsLegitimacy(classType);
1271 CheckTypeParameterVariance(classDef);
1272 }
1273
CheckClassElement(ir::ClassDefinition * classDef)1274 void ETSChecker::CheckClassElement(ir::ClassDefinition *classDef)
1275 {
1276 for (auto *it : classDef->Body()) {
1277 if (!it->IsClassProperty()) {
1278 if (it->IsETSModule() && it->AsETSModule()->IsNamespace()) {
1279 ES2PANDA_ASSERT(IsAnyError());
1280 continue;
1281 }
1282 }
1283 it->Check(this);
1284 }
1285 }
1286
CheckClassAnnotations(ir::ClassDefinition * classDef)1287 void ETSChecker::CheckClassAnnotations(ir::ClassDefinition *classDef)
1288 {
1289 CheckAnnotations(classDef->Annotations());
1290 if (classDef->TypeParams() != nullptr) {
1291 for (auto *param : classDef->TypeParams()->Params()) {
1292 CheckAnnotations(param->Annotations());
1293 }
1294 }
1295 }
1296
CheckInterfaceAnnotations(ir::TSInterfaceDeclaration * interfaceDecl)1297 void ETSChecker::CheckInterfaceAnnotations(ir::TSInterfaceDeclaration *interfaceDecl)
1298 {
1299 CheckAnnotations(interfaceDecl->Annotations());
1300 if (interfaceDecl->TypeParams() != nullptr) {
1301 for (auto *param : interfaceDecl->TypeParams()->Params()) {
1302 CheckAnnotations(param->Annotations());
1303 }
1304 }
1305 }
1306
CheckConstructors(ir::ClassDefinition * classDef,ETSObjectType * classType)1307 void ETSChecker::CheckConstructors(ir::ClassDefinition *classDef, ETSObjectType *classType)
1308 {
1309 if (!classDef->IsDeclare()) {
1310 for (auto *it : classType->ConstructSignatures()) {
1311 if (it->Function()->Body() == nullptr) {
1312 continue;
1313 }
1314 CheckCyclicConstructorCall(it);
1315 CheckImplicitSuper(classType, it);
1316 CheckThisOrSuperCallInConstructor(classType, it);
1317 }
1318 }
1319 }
1320
CheckImplicitSuper(ETSObjectType * classType,Signature * ctorSig)1321 void ETSChecker::CheckImplicitSuper(ETSObjectType *classType, Signature *ctorSig)
1322 {
1323 if (classType == GlobalETSObjectType()) {
1324 return;
1325 }
1326
1327 if (ctorSig->Function()->IsNative() && ctorSig->Function()->IsConstructor()) {
1328 return;
1329 }
1330
1331 auto &stmts = ctorSig->Function()->Body()->AsBlockStatement()->Statements();
1332 const auto thisCall = std::find_if(stmts.begin(), stmts.end(), [](const ir::Statement *stmt) {
1333 return stmt->IsExpressionStatement() && stmt->AsExpressionStatement()->GetExpression()->IsCallExpression() &&
1334 stmt->AsExpressionStatement()->GetExpression()->AsCallExpression()->Callee()->IsThisExpression();
1335 });
1336 // There is an alternate constructor invocation, no need for super constructor invocation
1337 if (thisCall != stmts.end()) {
1338 return;
1339 }
1340
1341 const auto superExpr = std::find_if(stmts.begin(), stmts.end(), [](const ir::Statement *stmt) {
1342 return stmt->IsExpressionStatement() && stmt->AsExpressionStatement()->GetExpression()->IsCallExpression() &&
1343 stmt->AsExpressionStatement()->GetExpression()->AsCallExpression()->Callee()->IsSuperExpression();
1344 });
1345 // There is no super expression
1346 if (superExpr == stmts.end()) {
1347 const auto superTypeCtorSigs = classType->SuperType()->ConstructSignatures();
1348 const auto superTypeCtorSig = std::find_if(superTypeCtorSigs.begin(), superTypeCtorSigs.end(),
1349 [](const Signature *sig) { return sig->MinArgCount() == 0; });
1350 // Super type has no parameterless ctor
1351 if (superTypeCtorSig == superTypeCtorSigs.end()) {
1352 LogError(diagnostic::CTOR_MISSING_SUPER_CALL, {}, ctorSig->Function()->Start());
1353 }
1354
1355 ctorSig->Function()->AddFlag(ir::ScriptFunctionFlags::IMPLICIT_SUPER_CALL_NEEDED);
1356 }
1357 }
1358
CheckThisOrSuperCallInConstructor(ETSObjectType * classType,Signature * ctorSig)1359 void ETSChecker::CheckThisOrSuperCallInConstructor(ETSObjectType *classType, Signature *ctorSig)
1360 {
1361 if (classType == GlobalETSObjectType()) {
1362 return;
1363 }
1364
1365 if (ctorSig->Function()->IsNative() && ctorSig->Function()->IsConstructor()) {
1366 return;
1367 }
1368
1369 for (auto it : ctorSig->Function()->Body()->AsBlockStatement()->Statements()) {
1370 if (it->IsExpressionStatement() && it->AsExpressionStatement()->GetExpression()->IsCallExpression() &&
1371 (it->AsExpressionStatement()->GetExpression()->AsCallExpression()->Callee()->IsThisExpression() ||
1372 it->AsExpressionStatement()->GetExpression()->AsCallExpression()->Callee()->IsSuperExpression())) {
1373 ArenaVector<const ir::Expression *> expressions =
1374 ArenaVector<const ir::Expression *>(ProgramAllocator()->Adapter());
1375 expressions.insert(expressions.end(),
1376 it->AsExpressionStatement()->GetExpression()->AsCallExpression()->Arguments().begin(),
1377 it->AsExpressionStatement()->GetExpression()->AsCallExpression()->Arguments().end());
1378 CheckExpressionsInConstructor(expressions);
1379 }
1380 }
1381 }
1382
CheckExpressionsInConstructor(const ArenaVector<const ir::Expression * > & arguments)1383 void ETSChecker::CheckExpressionsInConstructor(const ArenaVector<const ir::Expression *> &arguments)
1384 {
1385 for (auto *arg : arguments) {
1386 auto expressions = CheckMemberOrCallOrObjectExpressionInConstructor(arg);
1387
1388 if (arg->IsETSNewClassInstanceExpression()) {
1389 expressions.insert(expressions.end(), arg->AsETSNewClassInstanceExpression()->GetArguments().begin(),
1390 arg->AsETSNewClassInstanceExpression()->GetArguments().end());
1391 } else if (arg->IsArrayExpression()) {
1392 expressions.insert(expressions.end(), arg->AsArrayExpression()->Elements().begin(),
1393 arg->AsArrayExpression()->Elements().end());
1394 } else if (arg->IsBinaryExpression()) {
1395 expressions.push_back(arg->AsBinaryExpression()->Left());
1396 expressions.push_back(arg->AsBinaryExpression()->Right());
1397 } else if (arg->IsAssignmentExpression()) {
1398 expressions.push_back(arg->AsAssignmentExpression()->Left());
1399 expressions.push_back(arg->AsAssignmentExpression()->Right());
1400 } else if (arg->IsTSAsExpression()) {
1401 expressions.push_back(arg->AsTSAsExpression()->Expr());
1402 } else if (arg->IsConditionalExpression()) {
1403 expressions.push_back(arg->AsConditionalExpression()->Test());
1404 expressions.push_back(arg->AsConditionalExpression()->Consequent());
1405 expressions.push_back(arg->AsConditionalExpression()->Alternate());
1406 } else if (arg->IsTypeofExpression()) {
1407 expressions.push_back(arg->AsTypeofExpression()->Argument());
1408 } else if (arg->IsTSNonNullExpression()) {
1409 expressions.push_back(arg->AsTSNonNullExpression()->Expr());
1410 } else if (arg->IsUnaryExpression()) {
1411 expressions.push_back(arg->AsUnaryExpression()->Argument());
1412 } else if (arg->IsUpdateExpression()) {
1413 expressions.push_back(arg->AsUpdateExpression()->Argument());
1414 }
1415
1416 if (!expressions.empty()) {
1417 CheckExpressionsInConstructor(expressions);
1418 }
1419 }
1420 }
1421
CheckMemberOrCallOrObjectExpressionInConstructor(const ir::Expression * arg)1422 ArenaVector<const ir::Expression *> ETSChecker::CheckMemberOrCallOrObjectExpressionInConstructor(
1423 const ir::Expression *arg)
1424 {
1425 ArenaVector<const ir::Expression *> expressions =
1426 ArenaVector<const ir::Expression *>(ProgramAllocator()->Adapter());
1427
1428 if (arg->IsMemberExpression()) {
1429 if ((arg->AsMemberExpression()->Object()->IsSuperExpression() ||
1430 arg->AsMemberExpression()->Object()->IsThisExpression())) {
1431 const auto what = (arg->AsMemberExpression()->Object()->IsSuperExpression() ? "super" : "this");
1432 LogError(diagnostic::THIS_OR_SUPER_IN_CTOR, {what}, arg->Start());
1433 }
1434
1435 expressions.push_back(arg->AsMemberExpression()->Property());
1436 expressions.push_back(arg->AsMemberExpression()->Object());
1437 } else if (arg->IsCallExpression()) {
1438 expressions.insert(expressions.end(), arg->AsCallExpression()->Arguments().begin(),
1439 arg->AsCallExpression()->Arguments().end());
1440
1441 if (arg->AsCallExpression()->Callee()->IsMemberExpression() &&
1442 (arg->AsCallExpression()->Callee()->AsMemberExpression()->Object()->IsSuperExpression() ||
1443 arg->AsCallExpression()->Callee()->AsMemberExpression()->Object()->IsThisExpression()) &&
1444 !arg->AsCallExpression()->Callee()->AsMemberExpression()->Property()->IsStatic()) {
1445 const auto what =
1446 (arg->AsCallExpression()->Callee()->AsMemberExpression()->Object()->IsSuperExpression() ? "super"
1447 : "this");
1448 LogError(diagnostic::THIS_OR_SUPER_IN_CTOR, {what}, arg->Start());
1449 }
1450 } else if (arg->IsObjectExpression()) {
1451 for (auto *prop : arg->AsObjectExpression()->Properties()) {
1452 expressions.push_back(prop->AsProperty()->Value());
1453 }
1454 }
1455
1456 return expressions;
1457 }
1458
CheckConstFields(const ETSObjectType * classType)1459 void ETSChecker::CheckConstFields(const ETSObjectType *classType)
1460 {
1461 for (const auto &prop : classType->Fields()) {
1462 if (!(prop->Declaration()->IsConstDecl() || prop->Declaration()->IsReadonlyDecl()) ||
1463 !prop->HasFlag(varbinder::VariableFlags::EXPLICIT_INIT_REQUIRED)) {
1464 continue;
1465 }
1466 CheckConstFieldInitialized(classType, prop);
1467 }
1468 }
1469
CheckConstFieldInitialized(const ETSObjectType * classType,varbinder::LocalVariable * classVar)1470 void ETSChecker::CheckConstFieldInitialized(const ETSObjectType *classType, varbinder::LocalVariable *classVar)
1471 {
1472 const bool classVarStatic = classVar->Declaration()->Node()->AsClassProperty()->IsStatic();
1473 for (const auto &prop : classType->Methods()) {
1474 if (!prop->TsType()->IsETSFunctionType()) {
1475 continue;
1476 }
1477
1478 const auto &callSigs = prop->TsType()->AsETSFunctionType()->CallSignatures();
1479 for (const auto *signature : callSigs) {
1480 if ((signature->Function()->IsConstructor() && !classVarStatic) ||
1481 (signature->Function()->IsStaticBlock() && classVarStatic)) {
1482 CheckConstFieldInitialized(signature, classVar);
1483 }
1484 }
1485 }
1486 }
1487
FindAssignment(const ir::AstNode * node,const varbinder::LocalVariable * classVar,bool & initialized)1488 void ETSChecker::FindAssignment(const ir::AstNode *node, const varbinder::LocalVariable *classVar, bool &initialized)
1489 {
1490 if (node->IsAssignmentExpression() && node->AsAssignmentExpression()->Target() == classVar) {
1491 if (initialized) {
1492 LogError(diagnostic::MAYBE_DOUBLE_INIT, {classVar->Declaration()->Name()}, node->Start());
1493 }
1494
1495 initialized = true;
1496 return;
1497 }
1498
1499 FindAssignments(node, classVar, initialized);
1500 }
1501
FindAssignments(const ir::AstNode * node,const varbinder::LocalVariable * classVar,bool & initialized)1502 void ETSChecker::FindAssignments(const ir::AstNode *node, const varbinder::LocalVariable *classVar, bool &initialized)
1503 {
1504 node->Iterate(
1505 [this, classVar, &initialized](ir::AstNode *childNode) { FindAssignment(childNode, classVar, initialized); });
1506 }
1507
CheckConstFieldInitialized(const Signature * signature,varbinder::LocalVariable * classVar)1508 void ETSChecker::CheckConstFieldInitialized(const Signature *signature, varbinder::LocalVariable *classVar)
1509 {
1510 bool initialized = false;
1511 const auto &stmts = signature->Function()->Body()->AsBlockStatement()->Statements();
1512 const auto it = stmts.begin();
1513 if (it != stmts.end()) {
1514 if (const auto *first = *it;
1515 first->IsExpressionStatement() && first->AsExpressionStatement()->GetExpression()->IsCallExpression() &&
1516 first->AsExpressionStatement()->GetExpression()->AsCallExpression()->Callee()->IsThisExpression()) {
1517 initialized = true;
1518 }
1519 }
1520
1521 // NOTE: szd. control flow
1522 FindAssignments(signature->Function()->Body(), classVar, initialized);
1523 if (!initialized) {
1524 LogError(diagnostic::MAYBE_MISSING_INIT, {classVar->Declaration()->Name()}, signature->Function()->End());
1525 }
1526
1527 classVar->RemoveFlag(varbinder::VariableFlags::EXPLICIT_INIT_REQUIRED);
1528 }
1529
CheckInnerClassMembers(const ETSObjectType * classType)1530 void ETSChecker::CheckInnerClassMembers(const ETSObjectType *classType)
1531 {
1532 for (const auto &[_, it] : classType->StaticMethods()) {
1533 (void)_;
1534 LogError(diagnostic::INNER_CLASS_WITH_STATIC_METH, {}, it->Declaration()->Node()->Start());
1535 }
1536
1537 for (const auto &[_, it] : classType->StaticFields()) {
1538 (void)_;
1539 if (!it->Declaration()->IsReadonlyDecl()) {
1540 LogError(diagnostic::INNER_CLASS_MUTABLE_STATIC_PROP, {}, it->Declaration()->Node()->Start());
1541 }
1542 }
1543 }
1544
ExtractNumericValue(Type const * const indexType)1545 lexer::Number ETSChecker::ExtractNumericValue(Type const *const indexType)
1546 {
1547 TypeFlag typeKind = ETSType(indexType);
1548 lexer::Number resNum;
1549 switch (typeKind) {
1550 case TypeFlag::BYTE: {
1551 resNum = lexer::Number(indexType->AsByteType()->GetValue());
1552 break;
1553 }
1554 case TypeFlag::SHORT: {
1555 resNum = lexer::Number(indexType->AsShortType()->GetValue());
1556 break;
1557 }
1558 case TypeFlag::INT: {
1559 resNum = lexer::Number(indexType->AsIntType()->GetValue());
1560 break;
1561 }
1562 case TypeFlag::FLOAT: {
1563 resNum = lexer::Number(indexType->AsFloatType()->GetValue());
1564 break;
1565 }
1566 case TypeFlag::DOUBLE: {
1567 resNum = lexer::Number(indexType->AsDoubleType()->GetValue());
1568 break;
1569 }
1570 default:
1571 break;
1572 }
1573 return resNum;
1574 }
1575
ValidateArrayIndex(ir::Expression * const expr,bool relaxed)1576 bool ETSChecker::ValidateArrayIndex(ir::Expression *const expr, bool relaxed)
1577 {
1578 auto const expressionType = expr->Check(this);
1579 if (expressionType->IsTypeError()) {
1580 return false;
1581 }
1582
1583 Type const *const unboxedExpressionType = MaybeUnboxInRelation(expressionType);
1584 if (expressionType->IsETSObjectType() && (unboxedExpressionType != nullptr)) {
1585 expr->AddBoxingUnboxingFlags(GetUnboxingFlag(unboxedExpressionType));
1586 }
1587
1588 Type const *const indexType = ApplyUnaryOperatorPromotion(expressionType);
1589
1590 if (relaxed && indexType != nullptr) {
1591 lexer::Number resNum = ExtractNumericValue(indexType);
1592 double value = resNum.GetDouble();
1593 double intpart;
1594 if (std::modf(value, &intpart) != 0.0) {
1595 LogError(diagnostic::INDEX_NONINTEGRAL_FLOAT, {}, expr->Start());
1596 return false;
1597 }
1598 bool tildeFlag = false;
1599 if (expr->IsUnaryExpression() &&
1600 expr->AsUnaryExpression()->OperatorType() == lexer::TokenType::PUNCTUATOR_TILDE) {
1601 tildeFlag = true;
1602 }
1603 if ((tildeFlag && value > 0) || (!tildeFlag && value < 0)) {
1604 LogError(diagnostic::NEGATIVE_INDEX, {}, expr->Start());
1605 return false;
1606 }
1607 }
1608
1609 if (indexType == nullptr ||
1610 (!indexType->HasTypeFlag(relaxed ? (TypeFlag::ETS_ARRAY_INDEX | TypeFlag::ETS_FLOATING_POINT)
1611 : TypeFlag::ETS_ARRAY_INDEX))) {
1612 std::stringstream message("");
1613 expressionType->ToString(message);
1614
1615 LogError(diagnostic::INVALID_INDEX_TYPE, {message.str()}, expr->Start());
1616 return false;
1617 }
1618
1619 return true;
1620 }
1621
GetTupleElementAccessValue(const Type * const type)1622 std::optional<std::size_t> ETSChecker::GetTupleElementAccessValue(const Type *const type)
1623 {
1624 ES2PANDA_ASSERT(type->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC));
1625
1626 switch (ETSType(type)) {
1627 case TypeFlag::BYTE: {
1628 return type->AsByteType()->GetValue();
1629 }
1630 case TypeFlag::SHORT: {
1631 return type->AsShortType()->GetValue();
1632 }
1633 case TypeFlag::INT: {
1634 return type->AsIntType()->GetValue();
1635 }
1636 case TypeFlag::LONG: {
1637 if (auto val = type->AsLongType()->GetValue();
1638 val <= std::numeric_limits<int32_t>::max() && val >= std::numeric_limits<int32_t>::min()) {
1639 return static_cast<std::size_t>(val);
1640 }
1641 return std::nullopt;
1642 }
1643 default: {
1644 ES2PANDA_UNREACHABLE();
1645 }
1646 }
1647 }
1648
ValidateTupleIndex(const ETSTupleType * const tuple,ir::MemberExpression * const expr,const bool reportError)1649 bool ETSChecker::ValidateTupleIndex(const ETSTupleType *const tuple, ir::MemberExpression *const expr,
1650 const bool reportError)
1651 {
1652 auto const expressionType = expr->Property()->Check(this);
1653 auto const *const unboxedExpressionType = MaybeUnboxInRelation(expressionType);
1654
1655 if (expressionType->IsETSObjectType() && (unboxedExpressionType != nullptr)) {
1656 expr->Property()->AddBoxingUnboxingFlags(GetUnboxingFlag(unboxedExpressionType));
1657 }
1658
1659 const auto *const exprType = expr->Property()->TsType();
1660 ES2PANDA_ASSERT(exprType != nullptr);
1661
1662 if (!exprType->HasTypeFlag(TypeFlag::CONSTANT)) {
1663 if (exprType->IsETSObjectType() && (unboxedExpressionType != nullptr)) {
1664 return ValidateTupleIndexFromEtsObject(tuple, expr);
1665 }
1666 if (reportError) {
1667 LogError(diagnostic::TUPLE_INDEX_NONCONST, {}, expr->Property()->Start());
1668 }
1669 return false;
1670 }
1671
1672 if (!exprType->HasTypeFlag(TypeFlag::ETS_ARRAY_INDEX | TypeFlag::LONG)) {
1673 if (reportError) {
1674 LogError(diagnostic::TUPLE_INDEX_NOT_INT, {}, expr->Property()->Start());
1675 }
1676 return false;
1677 }
1678
1679 auto exprValue = GetTupleElementAccessValue(exprType);
1680 if (!exprValue.has_value() || (*exprValue >= tuple->GetTupleSize())) {
1681 if (reportError) {
1682 LogError(diagnostic::TUPLE_INDEX_OOB, {}, expr->Property()->Start());
1683 }
1684 return false;
1685 }
1686
1687 return true;
1688 }
1689
ValidateTupleIndexFromEtsObject(const ETSTupleType * const tuple,ir::MemberExpression * const expr)1690 bool ETSChecker::ValidateTupleIndexFromEtsObject(const ETSTupleType *const tuple, ir::MemberExpression *const expr)
1691 {
1692 auto *value = expr->Property()->Variable()->Declaration()->Node()->AsClassElement()->Value();
1693 if (value == nullptr) {
1694 LogError(diagnostic::TUPLE_INDEX_NONCONST, {}, expr->Property()->Start());
1695 return false;
1696 }
1697 auto *exprType = value->TsType();
1698 ES2PANDA_ASSERT(exprType != nullptr);
1699 if (!exprType->HasTypeFlag(TypeFlag::CONSTANT)) {
1700 LogError(diagnostic::TUPLE_INDEX_NONCONST, {}, expr->Property()->Start());
1701 return false;
1702 }
1703
1704 if (!exprType->HasTypeFlag(TypeFlag::ETS_ARRAY_INDEX | TypeFlag::LONG)) {
1705 LogError(diagnostic::TUPLE_INDEX_NOT_INT, {}, expr->Property()->Start());
1706 return false;
1707 }
1708
1709 auto exprValue = GetTupleElementAccessValue(exprType);
1710 if (!exprValue.has_value() || (*exprValue >= tuple->GetTupleSize())) {
1711 LogError(diagnostic::TUPLE_INDEX_OOB, {}, expr->Property()->Start());
1712 return false;
1713 }
1714
1715 return true;
1716 }
1717
CheckThisOrSuperAccess(ir::Expression * node,ETSObjectType * classType,std::string_view msg)1718 ETSObjectType *ETSChecker::CheckThisOrSuperAccess(ir::Expression *node, ETSObjectType *classType, std::string_view msg)
1719 {
1720 if ((Context().Status() & CheckerStatus::IGNORE_VISIBILITY) != 0U) {
1721 return classType;
1722 }
1723
1724 if (node->Parent()->IsCallExpression() && (node->Parent()->AsCallExpression()->Callee() == node) &&
1725 !node->Parent()->HasAstNodeFlags(ir::AstNodeFlags::RESIZABLE_REST)) {
1726 if (Context().ContainingSignature() == nullptr) {
1727 LogError(diagnostic::CTOR_CLASS_NOT_FIRST, {msg}, node->Start());
1728 return classType;
1729 }
1730
1731 auto *sig = Context().ContainingSignature();
1732 ES2PANDA_ASSERT(sig->Function()->Body() && sig->Function()->Body()->IsBlockStatement());
1733
1734 if (!sig->HasSignatureFlag(checker::SignatureFlags::CONSTRUCT)) {
1735 LogError(diagnostic::CTOR_CLASS_NOT_FIRST, {msg}, node->Start());
1736 return classType;
1737 }
1738
1739 if (sig->Function()->Body()->AsBlockStatement()->Statements().front() != node->Parent()->Parent()) {
1740 LogError(diagnostic::CTOR_CLASS_NOT_FIRST, {msg}, node->Start());
1741 return classType;
1742 }
1743 }
1744
1745 if (HasStatus(checker::CheckerStatus::IN_STATIC_CONTEXT)) {
1746 LogError(diagnostic::CTOR_REF_IN_STATIC_CTX, {msg}, node->Start());
1747 return classType;
1748 }
1749
1750 if (classType->GetDeclNode()->IsClassDefinition() &&
1751 (classType->GetDeclNode()->AsClassDefinition()->IsGlobal() ||
1752 classType->GetDeclNode()->AsClassDefinition()->IsNamespaceTransformed())) {
1753 LogError(diagnostic::CTOR_REF_INVALID_CTX_GLOBAL, {msg}, node->Start());
1754 return GlobalBuiltinErrorType();
1755 }
1756
1757 return classType;
1758 }
1759
CheckCyclicConstructorCall(Signature * signature)1760 void ETSChecker::CheckCyclicConstructorCall(Signature *signature)
1761 {
1762 ES2PANDA_ASSERT(signature->Function());
1763
1764 if (signature->Function()->IsExternal()) {
1765 return;
1766 }
1767
1768 // This is a condition set up to handle error scenarios.
1769 if (signature->Function()->Body() == nullptr) {
1770 return;
1771 }
1772
1773 auto *funcBody = signature->Function()->Body()->AsBlockStatement();
1774
1775 TypeStackElement tse(this, signature, {{diagnostic::RECURSIVE_CTOR}}, signature->Function()->Start());
1776 if (tse.HasTypeError()) {
1777 return;
1778 }
1779
1780 if (!funcBody->Statements().empty() && funcBody->Statements()[0]->IsExpressionStatement() &&
1781 funcBody->Statements()[0]->AsExpressionStatement()->GetExpression()->IsCallExpression() &&
1782 funcBody->Statements()[0]
1783 ->AsExpressionStatement() // CC-OFF(G.FMT.06-CPP,G.FMT.02-CPP) project code style
1784 ->GetExpression()
1785 ->AsCallExpression()
1786 ->Callee()
1787 ->IsThisExpression()) {
1788 auto *constructorCall = funcBody->Statements()[0]->AsExpressionStatement()->GetExpression()->AsCallExpression();
1789 if (constructorCall->TsType() == nullptr || constructorCall->TsType()->HasTypeFlag(TypeFlag::TYPE_ERROR)) {
1790 LogError(diagnostic::NO_SUCH_CTOR_SIG, {}, constructorCall->Start());
1791 return;
1792 }
1793 ES2PANDA_ASSERT(constructorCall->Signature());
1794 CheckCyclicConstructorCall(constructorCall->Signature());
1795 }
1796 }
1797
CheckExceptionOrErrorType(checker::Type * type,const lexer::SourcePosition pos)1798 ETSObjectType *ETSChecker::CheckExceptionOrErrorType(checker::Type *type, const lexer::SourcePosition pos)
1799 {
1800 ES2PANDA_ASSERT(type != nullptr);
1801 if (!type->IsETSObjectType() || (!Relation()->IsAssignableTo(type, GlobalBuiltinExceptionType()) &&
1802 !Relation()->IsAssignableTo(type, GlobalBuiltinErrorType()))) {
1803 LogError(diagnostic::CATCH_OR_THROW_OF_INVALID_TYPE,
1804 {compiler::Signatures::BUILTIN_EXCEPTION_CLASS, compiler::Signatures::BUILTIN_ERROR_CLASS}, pos);
1805 return GlobalETSObjectType();
1806 }
1807
1808 return type->AsETSObjectType();
1809 }
1810
TryToInstantiate(Type * const type,ArenaAllocator * const allocator,TypeRelation * const relation,GlobalTypesHolder * const globalTypes)1811 Type *ETSChecker::TryToInstantiate(Type *const type, ArenaAllocator *const allocator, TypeRelation *const relation,
1812 GlobalTypesHolder *const globalTypes)
1813 {
1814 // NOTE: Handle generic functions
1815 auto *returnType = type;
1816 const bool isIncomplete =
1817 type->IsETSObjectType() && type->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::INCOMPLETE_INSTANTIATION);
1818 if (const bool isFunctionType = type->IsETSFunctionType(); isFunctionType || isIncomplete) {
1819 returnType = type->Instantiate(allocator, relation, globalTypes);
1820 }
1821
1822 return returnType;
1823 }
1824
ValidateNamespaceProperty(varbinder::Variable * property,const ETSObjectType * target,const ir::Identifier * ident)1825 void ETSChecker::ValidateNamespaceProperty(varbinder::Variable *property, const ETSObjectType *target,
1826 const ir::Identifier *ident)
1827 {
1828 ir::AstNode *parent = nullptr;
1829 if (property->TsType() != nullptr && !property->TsType()->IsTypeError()) {
1830 if (property->TsType()->IsETSMethodType()) {
1831 auto funcType = property->TsType()->AsETSFunctionType();
1832 property = funcType->CallSignatures()[0]->OwnerVar();
1833 ES2PANDA_ASSERT(property != nullptr);
1834 } else {
1835 if (ident->Parent()->IsMemberExpression() &&
1836 ident->Parent()->AsMemberExpression()->Object()->IsSuperExpression()) {
1837 LogError(diagnostic::SUPER_NOT_ACCESSIBLE, {ident->Name()}, ident->Start());
1838 }
1839 }
1840 }
1841
1842 if (property->Declaration() == nullptr) {
1843 return;
1844 }
1845
1846 auto node = property->Declaration()->Node();
1847 if (node == nullptr) {
1848 return;
1849 }
1850
1851 if (node->IsClassDefinition()) {
1852 parent = node->Parent()->Parent();
1853 } else if (node->Parent() != nullptr) {
1854 parent = node->Parent();
1855 }
1856
1857 bool isExported = node->IsExported() || node->IsDefaultExported();
1858 if (parent != nullptr && parent->IsClassDefinition() && parent->AsClassDefinition()->IsNamespaceTransformed() &&
1859 !parent->AsClassDefinition()->IsDeclare() && !isExported) {
1860 LogError(diagnostic::NOT_EXPORTED, {ident->Name(), target->Name()}, ident->Start());
1861 }
1862 }
1863
ValidateResolvedProperty(varbinder::LocalVariable ** property,const ETSObjectType * const target,const ir::Identifier * const ident,const PropertySearchFlags flags)1864 void ETSChecker::ValidateResolvedProperty(varbinder::LocalVariable **property, const ETSObjectType *const target,
1865 const ir::Identifier *const ident, const PropertySearchFlags flags)
1866 {
1867 if (*property != nullptr) {
1868 ValidateNamespaceProperty(*property, target, ident);
1869 return;
1870 }
1871
1872 if (ident->Name().Is(ERROR_LITERAL)) {
1873 return;
1874 }
1875
1876 using Utype = std::underlying_type_t<PropertySearchFlags>;
1877 static constexpr uint32_t CORRECT_PROPERTY_SEARCH_ORDER_INSTANCE = 7U;
1878 static_assert(static_cast<Utype>(PropertySearchFlags::SEARCH_INSTANCE) == CORRECT_PROPERTY_SEARCH_ORDER_INSTANCE,
1879 "PropertySearchFlags order changed");
1880 static constexpr uint32_t CORRECT_PROPERTY_SEARCH_ORDER_STATIC = 56U;
1881 static_assert(static_cast<Utype>(PropertySearchFlags::SEARCH_STATIC) == CORRECT_PROPERTY_SEARCH_ORDER_STATIC,
1882 "PropertySearchFlags order changed");
1883 const auto flagsNum = static_cast<Utype>(flags);
1884 // This algorithm swaps the first 3 bits of a number with it's consecutive 3 bits, example: 0b110001 -> 0b001110
1885 // Effectively it changes PropertySearchFlags to search for the appropriate declarations
1886 const Utype x = (flagsNum ^ (flagsNum >> 3U)) & 7U;
1887 const auto newFlags = PropertySearchFlags {flagsNum ^ (x | (x << 3U))};
1888
1889 auto *newProp = target->GetProperty(ident->Name(), newFlags);
1890 if (newProp == nullptr) {
1891 LogError(diagnostic::PROPERTY_NONEXISTENT, {ident->Name(), target->Name()}, ident->Start());
1892 return;
1893 }
1894
1895 *property = newProp; // trying to recover as much as possible; log the error but treat the property as legal
1896
1897 if (IsVariableStatic(newProp)) {
1898 LogError(diagnostic::PROP_IS_STATIC, {ident->Name(), target->Name()}, ident->Start());
1899 return;
1900 }
1901
1902 LogError(diagnostic::PROP_NOT_STATIC, {ident->Name(), target->Name()}, ident->Start());
1903 }
1904
1905 using VO = varbinder::ResolveBindingOptions;
GetExtensionFuncVarInGlobalFunction(const ir::MemberExpression * const memberExpr)1906 varbinder::Variable *ETSChecker::GetExtensionFuncVarInGlobalFunction(const ir::MemberExpression *const memberExpr)
1907 {
1908 auto propertyName = memberExpr->Property()->AsIdentifier()->Name();
1909 auto *globalFunctionVar = Scope()->FindInGlobal(propertyName, VO::STATIC_METHODS).variable;
1910 if (globalFunctionVar == nullptr) {
1911 return nullptr;
1912 }
1913
1914 if (!IsExtensionETSFunctionType(GetTypeOfVariable(globalFunctionVar))) {
1915 return nullptr;
1916 }
1917
1918 return globalFunctionVar;
1919 }
1920
GetExtensionFuncVarInGlobalField(const ir::MemberExpression * const memberExpr)1921 varbinder::Variable *ETSChecker::GetExtensionFuncVarInGlobalField(const ir::MemberExpression *const memberExpr)
1922 {
1923 auto propertyName = memberExpr->Property()->AsIdentifier()->Name();
1924 auto *globalFieldVar = Scope()->FindInGlobal(propertyName, VO::STATIC_VARIABLES).variable;
1925 if (globalFieldVar == nullptr || !IsExtensionETSFunctionType(globalFieldVar->TsType())) {
1926 return nullptr;
1927 }
1928
1929 return globalFieldVar;
1930 }
1931
GetExtensionFuncVarInFunctionScope(const ir::MemberExpression * const memberExpr)1932 varbinder::Variable *ETSChecker::GetExtensionFuncVarInFunctionScope(const ir::MemberExpression *const memberExpr)
1933 {
1934 auto propertyName = memberExpr->Property()->AsIdentifier()->Name();
1935 auto *funcScopeVar = Scope()->FindInFunctionScope(propertyName, VO::ALL).variable;
1936 if (funcScopeVar == nullptr || !IsExtensionETSFunctionType(funcScopeVar->TsType())) {
1937 return nullptr;
1938 }
1939 return funcScopeVar;
1940 }
1941
ResolveInstanceExtension(const ir::MemberExpression * const memberExpr)1942 varbinder::Variable *ETSChecker::ResolveInstanceExtension(const ir::MemberExpression *const memberExpr)
1943 {
1944 auto *globalFunctionVar = GetExtensionFuncVarInGlobalFunction(memberExpr);
1945 if (globalFunctionVar != nullptr) {
1946 return globalFunctionVar;
1947 }
1948
1949 auto *globalFieldVar = GetExtensionFuncVarInGlobalField(memberExpr);
1950 if (globalFieldVar != nullptr) {
1951 return globalFieldVar;
1952 }
1953
1954 // extension function maybe a parameter, or some lambda function defined in function.
1955 return GetExtensionFuncVarInFunctionScope(memberExpr);
1956 }
1957
GetInitialSearchFlags(const ir::MemberExpression * const memberExpr)1958 PropertySearchFlags ETSChecker::GetInitialSearchFlags(const ir::MemberExpression *const memberExpr)
1959 {
1960 constexpr auto FUNCTIONAL_FLAGS = PropertySearchFlags::SEARCH_METHOD | PropertySearchFlags::SEARCH_FIELD;
1961 constexpr auto GETTER_FLAGS = PropertySearchFlags::SEARCH_METHOD | PropertySearchFlags::IS_GETTER;
1962 constexpr auto SETTER_FLAGS = PropertySearchFlags::SEARCH_METHOD | PropertySearchFlags::IS_SETTER;
1963
1964 switch (memberExpr->Parent()->Type()) {
1965 case ir::AstNodeType::CALL_EXPRESSION: {
1966 if (memberExpr->Parent()->AsCallExpression()->Callee() == memberExpr) {
1967 return FUNCTIONAL_FLAGS;
1968 }
1969 break;
1970 }
1971 case ir::AstNodeType::ETS_NEW_CLASS_INSTANCE_EXPRESSION: {
1972 if (memberExpr->Parent()->AsETSNewClassInstanceExpression()->GetTypeRef() == memberExpr) {
1973 return PropertySearchFlags::SEARCH_DECL;
1974 }
1975 break;
1976 }
1977 case ir::AstNodeType::MEMBER_EXPRESSION: {
1978 return PropertySearchFlags::SEARCH_FIELD | PropertySearchFlags::SEARCH_DECL | GETTER_FLAGS;
1979 }
1980 case ir::AstNodeType::UPDATE_EXPRESSION:
1981 case ir::AstNodeType::UNARY_EXPRESSION:
1982 case ir::AstNodeType::BINARY_EXPRESSION: {
1983 return PropertySearchFlags::SEARCH_FIELD | GETTER_FLAGS;
1984 }
1985 case ir::AstNodeType::ASSIGNMENT_EXPRESSION: {
1986 const auto *const assignmentExpr = memberExpr->Parent()->AsAssignmentExpression();
1987
1988 if (assignmentExpr->Left() == memberExpr) {
1989 if (assignmentExpr->OperatorType() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) {
1990 return PropertySearchFlags::SEARCH_FIELD | SETTER_FLAGS;
1991 }
1992 return PropertySearchFlags::SEARCH_FIELD | GETTER_FLAGS | SETTER_FLAGS;
1993 }
1994
1995 return PropertySearchFlags::SEARCH_FIELD | GETTER_FLAGS;
1996 }
1997 default: {
1998 break;
1999 }
2000 }
2001
2002 return PropertySearchFlags::SEARCH_FIELD | FUNCTIONAL_FLAGS | GETTER_FLAGS;
2003 }
2004
ShouldRemoveStaticSearchFlag(const ir::MemberExpression * const memberExpr,const varbinder::Variable * targetRef)2005 static bool ShouldRemoveStaticSearchFlag(const ir::MemberExpression *const memberExpr,
2006 const varbinder::Variable *targetRef)
2007 {
2008 if ((targetRef != nullptr && targetRef->Declaration() != nullptr && targetRef->Declaration()->IsLetOrConstDecl()) ||
2009 !memberExpr->Object()->TsType()->IsETSEnumType()) {
2010 auto object = memberExpr->Object();
2011 if (object->IsMemberExpression()) {
2012 object = object->AsMemberExpression()->Property();
2013 }
2014 if (!object->IsIdentifier() || (object->AsIdentifier()->Variable() == nullptr) ||
2015 object->AsIdentifier()->Variable()->HasFlag(varbinder::VariableFlags::INITIALIZED)) {
2016 return true;
2017 }
2018 }
2019 return false;
2020 }
2021
GetSearchFlags(const ir::MemberExpression * const memberExpr,const varbinder::Variable * targetRef)2022 PropertySearchFlags ETSChecker::GetSearchFlags(const ir::MemberExpression *const memberExpr,
2023 const varbinder::Variable *targetRef)
2024 {
2025 auto searchFlag = GetInitialSearchFlags(memberExpr);
2026 searchFlag |= PropertySearchFlags::SEARCH_IN_BASE | PropertySearchFlags::SEARCH_IN_INTERFACES;
2027 if (targetRef != nullptr && targetRef->Declaration() != nullptr &&
2028 targetRef->Declaration()->Node()->IsClassDefinition() &&
2029 targetRef->Declaration()->Node()->AsClassDefinition()->IsNamespaceTransformed()) {
2030 return searchFlag;
2031 }
2032
2033 if (targetRef != nullptr &&
2034 (targetRef->HasFlag(varbinder::VariableFlags::CLASS_OR_INTERFACE_OR_ENUM) ||
2035 // NOTE (DZ): need to investigate when and why `targetRef->TsType()->Variable()` can be `nullptr`
2036 // (see ast/parser/ets/union_static_method.ets)
2037 (targetRef->HasFlag(varbinder::VariableFlags::TYPE_ALIAS) && targetRef->TsType()->Variable() != nullptr &&
2038 targetRef->TsType()->Variable()->HasFlag(varbinder::VariableFlags::CLASS_OR_INTERFACE)))) {
2039 searchFlag &= ~PropertySearchFlags::SEARCH_INSTANCE;
2040 } else if (ShouldRemoveStaticSearchFlag(memberExpr, targetRef)) {
2041 searchFlag &= ~PropertySearchFlags::SEARCH_STATIC;
2042 }
2043 return searchFlag;
2044 }
2045
GetTargetRef(const ir::MemberExpression * const memberExpr)2046 const varbinder::Variable *ETSChecker::GetTargetRef(const ir::MemberExpression *const memberExpr)
2047 {
2048 if (memberExpr->Object()->IsIdentifier()) {
2049 return memberExpr->Object()->AsIdentifier()->Variable();
2050 }
2051 if (memberExpr->Object()->IsMemberExpression()) {
2052 return memberExpr->Object()->AsMemberExpression()->PropVar();
2053 }
2054 return nullptr;
2055 }
2056
ValidateReadonlyProperty(const ir::MemberExpression * const memberExpr,const ETSFunctionType * propType,const lexer::SourcePosition sourcePos)2057 void ETSChecker::ValidateReadonlyProperty(const ir::MemberExpression *const memberExpr, const ETSFunctionType *propType,
2058 const lexer::SourcePosition sourcePos)
2059 {
2060 ir::ClassProperty *classProp = nullptr;
2061 ETSObjectType *currentObj = memberExpr->ObjType();
2062 bool foundInThis = false;
2063 while (classProp == nullptr && currentObj != nullptr) {
2064 classProp = FindClassProperty(currentObj, propType);
2065 if (classProp != nullptr && currentObj == memberExpr->ObjType()) {
2066 foundInThis = true;
2067 }
2068
2069 currentObj = currentObj->SuperType();
2070 }
2071
2072 if (classProp != nullptr && this->Context().ContainingSignature() != nullptr && classProp->IsReadonly()) {
2073 if (!foundInThis || (!this->Context().ContainingSignature()->Function()->IsConstructor())) {
2074 LogError(diagnostic::ASSIGN_TO_READONLY_PROP, {}, sourcePos);
2075 return;
2076 }
2077
2078 if (IsInitializedProperty(memberExpr->ObjType()->GetDeclNode()->AsClassDefinition(), classProp)) {
2079 LogError(diagnostic::READONLY_FIELD_MULTIPLE_INIT, {}, sourcePos);
2080 }
2081 }
2082 }
2083
ResolveAccessorTypeByFlag(ir::MemberExpression * const memberExpr,ETSFunctionType * propType,ETSFunctionType * funcType,PropertySearchFlags searchFlag)2084 ETSFunctionType *ETSChecker::ResolveAccessorTypeByFlag(ir::MemberExpression *const memberExpr,
2085 ETSFunctionType *propType, ETSFunctionType *funcType,
2086 PropertySearchFlags searchFlag)
2087 {
2088 ETSFunctionType *finalRes = nullptr;
2089 auto const &sourcePos = memberExpr->Property()->Start();
2090 if ((searchFlag & PropertySearchFlags::IS_GETTER) != 0) {
2091 if (propType != nullptr && propType->HasTypeFlag(TypeFlag::GETTER)) {
2092 ValidateSignatureAccessibility(memberExpr->ObjType(), propType->FindGetter(), sourcePos);
2093 finalRes = propType;
2094 }
2095
2096 if (funcType != nullptr && funcType->IsExtensionAccessorType() &&
2097 // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
2098 FindRelativeExtensionGetter(memberExpr, funcType) != nullptr) {
2099 finalRes = funcType;
2100 }
2101
2102 if (finalRes == nullptr) {
2103 LogError(diagnostic::READ_FROM_WRITEONLY_PROP, {}, sourcePos);
2104 return finalRes;
2105 }
2106 }
2107
2108 if ((searchFlag & PropertySearchFlags::IS_SETTER) != 0) {
2109 finalRes = nullptr;
2110 if (propType != nullptr) {
2111 ValidateReadonlyProperty(memberExpr, propType, sourcePos);
2112 if (propType->FindSetter() != nullptr) {
2113 ValidateSignatureAccessibility(memberExpr->ObjType(), propType->FindSetter(), sourcePos);
2114 finalRes = propType;
2115 }
2116 }
2117
2118 if (funcType != nullptr && funcType->IsExtensionAccessorType() &&
2119 // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
2120 FindRelativeExtensionSetter(memberExpr, funcType) != nullptr) {
2121 finalRes = funcType;
2122 }
2123
2124 if (finalRes == nullptr) {
2125 LogError(diagnostic::ASSIGN_TO_READONLY_PROP, {}, sourcePos);
2126 }
2127 }
2128
2129 return finalRes;
2130 }
2131
2132 // Note: Need to validate extension Accessor and original Accessor.
ValidateAccessor(ir::MemberExpression * const memberExpr,varbinder::LocalVariable * const oAcc,varbinder::Variable * const eAcc,PropertySearchFlags searchFlag)2133 std::vector<ResolveResult *> ETSChecker::ValidateAccessor(ir::MemberExpression *const memberExpr,
2134 varbinder::LocalVariable *const oAcc,
2135 varbinder::Variable *const eAcc,
2136 PropertySearchFlags searchFlag)
2137 {
2138 auto *funcType = eAcc != nullptr ? eAcc->TsType()->AsETSFunctionType() : nullptr;
2139 auto *propType = oAcc != nullptr ? oAcc->TsType()->AsETSFunctionType() : nullptr;
2140 searchFlag = memberExpr->Parent()->IsUpdateExpression() ? searchFlag | PropertySearchFlags::IS_SETTER : searchFlag;
2141 // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
2142 ETSFunctionType *finalRes = ResolveAccessorTypeByFlag(memberExpr, propType, funcType, searchFlag);
2143 std::vector<ResolveResult *> resolveRes = {};
2144 if (finalRes == nullptr) {
2145 return resolveRes;
2146 }
2147
2148 if (finalRes == propType) {
2149 resolveRes.emplace_back(ProgramAllocator()->New<ResolveResult>(oAcc, ResolvedKind::PROPERTY));
2150 return resolveRes;
2151 }
2152 resolveRes.emplace_back(ProgramAllocator()->New<ResolveResult>(eAcc, ResolvedKind::EXTENSION_ACCESSOR));
2153 return resolveRes;
2154 }
2155
FindClassProperty(const ETSObjectType * const objectType,const ETSFunctionType * propType)2156 ir::ClassProperty *ETSChecker::FindClassProperty(const ETSObjectType *const objectType, const ETSFunctionType *propType)
2157 {
2158 auto propName =
2159 util::UString(std::string(compiler::Signatures::PROPERTY) + propType->Name().Mutf8(), ProgramAllocator())
2160 .View();
2161
2162 ir::ClassProperty *classProp = nullptr;
2163 if (objectType->GetDeclNode()->IsClassDefinition()) {
2164 auto body = objectType->GetDeclNode()->AsClassDefinition()->Body();
2165 auto foundValue = std::find_if(body.begin(), body.end(), [propName](ir::AstNode *node) {
2166 return node->IsClassProperty() && node->AsClassProperty()->Key()->AsIdentifier()->Name() == propName;
2167 });
2168 if (foundValue != body.end()) {
2169 classProp = (*foundValue)->AsClassProperty();
2170 }
2171 }
2172
2173 return classProp;
2174 }
2175
IsInitializedProperty(const ir::ClassDefinition * classDefinition,const ir::ClassProperty * prop)2176 bool ETSChecker::IsInitializedProperty(const ir::ClassDefinition *classDefinition, const ir::ClassProperty *prop)
2177 {
2178 std::string targetName = prop->Key()->AsIdentifier()->Name().Mutf8();
2179 if (targetName.find(compiler::Signatures::PROPERTY) == 0) {
2180 targetName = targetName.substr(compiler::Signatures::PROPERTY.size());
2181 }
2182
2183 for (auto *it : classDefinition->Body()) {
2184 if (it->IsClassProperty() && it->AsClassProperty()->Value() != nullptr) {
2185 return FindPropertyInAssignment(it, targetName);
2186 }
2187 }
2188
2189 return false;
2190 }
2191
FindPropertyInAssignment(const ir::AstNode * it,const std::string & targetName)2192 bool ETSChecker::FindPropertyInAssignment(const ir::AstNode *it, const std::string &targetName)
2193 {
2194 return it->AsClassProperty()->Value()->FindChild([&targetName](ir::AstNode *node) {
2195 return node->IsIdentifier() && node->AsIdentifier()->Name().Is(targetName) && node->Parent() != nullptr &&
2196 node->Parent()->IsMemberExpression();
2197 }) != nullptr;
2198 }
2199
IsExtensionAccessorCallUse(checker::ETSChecker * checker,const ir::MemberExpression * const memberExpr,ResolvedKind resolvedKind)2200 static bool IsExtensionAccessorCallUse(checker::ETSChecker *checker, const ir::MemberExpression *const memberExpr,
2201 ResolvedKind resolvedKind)
2202 {
2203 return resolvedKind == ResolvedKind::EXTENSION_ACCESSOR &&
2204 !checker->HasStatus(CheckerStatus::IN_EXTENSION_ACCESSOR_CHECK) &&
2205 memberExpr->Parent()->IsCallExpression() && memberExpr->Parent()->AsCallExpression()->Callee() == memberExpr;
2206 }
2207
DecideResolvedKind(Type * typeOfGlobalFunctionVar)2208 static ResolvedKind DecideResolvedKind(Type *typeOfGlobalFunctionVar)
2209 {
2210 ES2PANDA_ASSERT(typeOfGlobalFunctionVar != nullptr);
2211 ES2PANDA_ASSERT(typeOfGlobalFunctionVar->IsETSObjectType() || typeOfGlobalFunctionVar->IsETSFunctionType());
2212 if (typeOfGlobalFunctionVar->IsETSObjectType()) {
2213 return ResolvedKind::EXTENSION_FUNCTION;
2214 }
2215
2216 if (typeOfGlobalFunctionVar->AsETSFunctionType()->IsExtensionAccessorType()) {
2217 return ResolvedKind::EXTENSION_ACCESSOR;
2218 }
2219
2220 return ResolvedKind::EXTENSION_FUNCTION;
2221 }
2222
2223 // NOLINTNEXTLINE(readability-function-size)
ResolveMemberReference(const ir::MemberExpression * const memberExpr,const ETSObjectType * const target)2224 std::vector<ResolveResult *> ETSChecker::ResolveMemberReference(const ir::MemberExpression *const memberExpr,
2225 const ETSObjectType *const target)
2226 {
2227 std::vector<ResolveResult *> resolveRes {};
2228
2229 if (target->IsETSDynamicType() && !target->AsETSDynamicType()->HasDecl()) {
2230 auto propName = memberExpr->Property()->AsIdentifier()->Name();
2231 varbinder::LocalVariable *propVar = target->AsETSDynamicType()->GetPropertyDynamic(propName, this);
2232 resolveRes.emplace_back(ProgramAllocator()->New<ResolveResult>(propVar, ResolvedKind::PROPERTY));
2233 return resolveRes;
2234 }
2235
2236 if (target->GetDeclNode() != nullptr && target->GetDeclNode()->IsClassDefinition() &&
2237 !target->GetDeclNode()->AsClassDefinition()->IsClassDefinitionChecked()) {
2238 // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
2239 this->CheckClassDefinition(target->GetDeclNode()->AsClassDefinition());
2240 }
2241 const auto *const targetRef = GetTargetRef(memberExpr);
2242 auto searchFlag = GetSearchFlags(memberExpr, targetRef);
2243 auto searchName = target->GetReExportAliasValue(memberExpr->Property()->AsIdentifier()->Name());
2244 auto *prop = target->GetProperty(searchName, searchFlag);
2245 varbinder::Variable *const globalFunctionVar = ResolveInstanceExtension(memberExpr);
2246 if (targetRef != nullptr && targetRef->HasFlag(varbinder::VariableFlags::CLASS_OR_INTERFACE)) {
2247 // Note: extension function only for instance.
2248 ValidateResolvedProperty(&prop, target, memberExpr->Property()->AsIdentifier(), searchFlag);
2249 if (prop != nullptr) {
2250 resolveRes.emplace_back(ProgramAllocator()->New<ResolveResult>(prop, ResolvedKind::PROPERTY));
2251 }
2252 return resolveRes;
2253 }
2254
2255 if (HasStatus(CheckerStatus::IN_GETTER)) {
2256 WarnForEndlessLoopInGetterSetter(memberExpr);
2257 }
2258
2259 // Note: validate originalAccessor and extensionAccessor.
2260 if ((IsVariableGetterSetter(prop) || IsVariableExtensionAccessor(globalFunctionVar)) &&
2261 ((searchFlag & PropertySearchFlags::IS_GETTER) != 0 || (searchFlag & PropertySearchFlags::IS_SETTER) != 0)) {
2262 // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
2263 return ValidateAccessor(const_cast<ir::MemberExpression *>(memberExpr), prop, globalFunctionVar, searchFlag);
2264 }
2265
2266 if (globalFunctionVar != nullptr) {
2267 ResolvedKind resolvedKind = DecideResolvedKind(globalFunctionVar->TsType());
2268 if (IsExtensionAccessorCallUse(this, memberExpr, resolvedKind)) {
2269 LogError(diagnostic::EXTENSION_ACCESSOR_INVALID_CALL, {}, memberExpr->Start());
2270 return resolveRes;
2271 }
2272 resolveRes.emplace_back(ProgramAllocator()->New<ResolveResult>(globalFunctionVar, resolvedKind));
2273 } else {
2274 ValidateResolvedProperty(&prop, target, memberExpr->Property()->AsIdentifier(), searchFlag);
2275 }
2276
2277 if (prop != nullptr) {
2278 resolveRes.emplace_back(ProgramAllocator()->New<ResolveResult>(prop, ResolvedKind::PROPERTY));
2279 }
2280 return resolveRes;
2281 }
2282
WarnForEndlessLoopInGetterSetter(const ir::MemberExpression * const memberExpr)2283 void ETSChecker::WarnForEndlessLoopInGetterSetter(const ir::MemberExpression *const memberExpr)
2284 {
2285 if (!memberExpr->Object()->IsThisExpression() || memberExpr->Property() == nullptr ||
2286 !memberExpr->Property()->IsIdentifier()) {
2287 return;
2288 }
2289 auto ident = memberExpr->Property()->AsIdentifier();
2290 auto parent = memberExpr->Parent();
2291 while (parent != nullptr && (!parent->IsMethodDefinition() || parent->AsMethodDefinition()->Function() == nullptr ||
2292 (!parent->AsMethodDefinition()->Function()->IsGetter() &&
2293 !parent->AsMethodDefinition()->Function()->IsSetter()))) {
2294 parent = parent->Parent();
2295 }
2296 if (parent != nullptr && parent->AsMethodDefinition()->Function() != nullptr &&
2297 ident->Name() == parent->AsMethodDefinition()->Function()->Id()->Name()) {
2298 if (parent->AsMethodDefinition()->Function()->IsGetter()) {
2299 LogDiagnostic(diagnostic::GETTER_LOOP, memberExpr->Property()->AsIdentifier()->Start());
2300 } else {
2301 LogDiagnostic(diagnostic::SETTER_LOOP, memberExpr->Property()->AsIdentifier()->Start());
2302 }
2303 }
2304 }
2305
CheckValidInheritance(ETSObjectType * classType,ir::ClassDefinition * classDef)2306 void ETSChecker::CheckValidInheritance(ETSObjectType *classType, ir::ClassDefinition *classDef)
2307 {
2308 if (classType->SuperType() == nullptr) {
2309 return;
2310 }
2311 if (classType->SuperType()->IsETSDynamicType()) {
2312 LogError(diagnostic::EXTEND_DYNAMIC, {classDef->Ident()->Name()}, classDef->Start());
2313 }
2314
2315 const auto &allProps = classType->GetAllProperties();
2316
2317 for (auto *it : allProps) {
2318 auto *node = it->Declaration()->Node();
2319 if (node->IsClassProperty() && node->AsClassProperty()->TsType() != nullptr &&
2320 node->AsClassProperty()->TsType()->IsTypeError()) {
2321 continue;
2322 }
2323
2324 const auto searchFlag = PropertySearchFlags::SEARCH_ALL | PropertySearchFlags::SEARCH_IN_BASE |
2325 PropertySearchFlags::SEARCH_IN_INTERFACES |
2326 PropertySearchFlags::DISALLOW_SYNTHETIC_METHOD_CREATION;
2327 auto *foundInSuper = classType->SuperType()->GetProperty(it->Name(), searchFlag);
2328
2329 ETSObjectType *interfaceFound = nullptr;
2330 if (foundInSuper != nullptr) {
2331 CheckProperties(classType, classDef, it, foundInSuper, interfaceFound);
2332 }
2333
2334 auto interfaceList = GetInterfaces(classType);
2335 varbinder::LocalVariable *foundInInterface = nullptr;
2336 for (auto *interface : interfaceList) {
2337 auto *propertyFound = interface->GetProperty(it->Name(), searchFlag);
2338 if (propertyFound == nullptr) {
2339 continue;
2340 }
2341 foundInInterface = propertyFound;
2342 interfaceFound = interface;
2343 break;
2344 }
2345 if (foundInInterface == nullptr) {
2346 continue;
2347 }
2348
2349 CheckProperties(classType, classDef, it, foundInInterface, interfaceFound);
2350 }
2351 }
2352
CheckProperties(ETSObjectType * classType,ir::ClassDefinition * classDef,varbinder::LocalVariable * it,varbinder::LocalVariable * found,ETSObjectType * interfaceFound)2353 void ETSChecker::CheckProperties(ETSObjectType *classType, ir::ClassDefinition *classDef, varbinder::LocalVariable *it,
2354 varbinder::LocalVariable *found, ETSObjectType *interfaceFound)
2355 {
2356 if (found->TsType() == nullptr) {
2357 GetTypeOfVariable(found);
2358 }
2359
2360 if (IsVariableStatic(it) != IsVariableStatic(found)) {
2361 return;
2362 }
2363
2364 if (!IsSameDeclarationType(it, found)) {
2365 if (it->Declaration()->Type() == varbinder::DeclType::LET &&
2366 found->Declaration()->Type() == varbinder::DeclType::READONLY) {
2367 return;
2368 }
2369
2370 if (CheckGetterSetterDecl(it, found)) {
2371 return;
2372 }
2373 } else if (CheckFunctionDecl(it, found)) {
2374 return;
2375 }
2376
2377 const char *targetType {};
2378
2379 if (it->HasFlag(varbinder::VariableFlags::PROPERTY)) {
2380 targetType = "field";
2381 } else if (it->HasFlag(varbinder::VariableFlags::METHOD)) {
2382 targetType = "method";
2383 } else if (it->HasFlag(varbinder::VariableFlags::CLASS)) {
2384 targetType = "class";
2385 } else if (it->HasFlag(varbinder::VariableFlags::INTERFACE)) {
2386 targetType = "interface";
2387 } else if (it->HasFlag(varbinder::VariableFlags::NAMESPACE)) {
2388 targetType = "namespace";
2389 } else if (it->HasFlag(varbinder::VariableFlags::ENUM_LITERAL)) {
2390 targetType = "enum";
2391 } else {
2392 ES2PANDA_UNREACHABLE();
2393 }
2394
2395 if (interfaceFound != nullptr) {
2396 LogError(diagnostic::INHERITED_INTERFACE_TYPE_MISMATCH, {interfaceFound->Name(), targetType, it->Name()},
2397 interfaceFound->GetDeclNode()->Start());
2398 return;
2399 }
2400 auto pos = classDef->Super() == nullptr ? classDef->Ident()->Start() : classDef->Super()->Start();
2401 LogError(diagnostic::INHERITED_CLASS_TYPE_MISMATCH, {classType->SuperType()->Name(), targetType, it->Name()}, pos);
2402 }
2403
CheckReadonlyClassPropertyInImplementedInterface(ETSObjectType * classType,varbinder::LocalVariable * field)2404 void ETSChecker::CheckReadonlyClassPropertyInImplementedInterface(ETSObjectType *classType,
2405 varbinder::LocalVariable *field)
2406 {
2407 const auto searchFlag = PropertySearchFlags::SEARCH_ALL | PropertySearchFlags::SEARCH_IN_BASE |
2408 PropertySearchFlags::SEARCH_IN_INTERFACES |
2409 PropertySearchFlags::DISALLOW_SYNTHETIC_METHOD_CREATION;
2410 const auto &interfaceList = GetInterfaces(classType);
2411 if (field == nullptr || field->Declaration() == nullptr || field->Declaration()->Node() == nullptr ||
2412 !field->Declaration()->Node()->IsClassProperty() ||
2413 !field->Declaration()->Node()->AsClassProperty()->IsReadonly()) {
2414 return;
2415 }
2416
2417 for (auto *interface : interfaceList) {
2418 ES2PANDA_ASSERT(interface != nullptr);
2419 auto *propertyFound = interface->GetProperty(field->Name(), searchFlag);
2420 if (propertyFound == nullptr) {
2421 continue;
2422 }
2423
2424 ES2PANDA_ASSERT(propertyFound->TsType() != nullptr);
2425 if (!propertyFound->TsType()->IsETSFunctionType()) {
2426 continue;
2427 }
2428
2429 auto setter = propertyFound->TsType()->AsETSFunctionType()->FindSetter();
2430 if (setter != nullptr) {
2431 LogError(diagnostic::INTERFACE_PROPERTY_REQUIRES_SETTER, {interface->Name(), field->Name()},
2432 field->Declaration()->Node()->Start());
2433 }
2434 }
2435 }
2436
TransformProperties(ETSObjectType * classType)2437 void ETSChecker::TransformProperties(ETSObjectType *classType)
2438 {
2439 auto propertyList = classType->Fields();
2440 auto *const classDef = classType->GetDeclNode()->AsClassDefinition();
2441
2442 for (auto *const field : propertyList) {
2443 ES2PANDA_ASSERT(field->Declaration()->Node()->IsClassProperty());
2444 auto *const originalProp = field->Declaration()->Node()->AsClassProperty();
2445
2446 if ((originalProp->Modifiers() & ir::ModifierFlags::GETTER_SETTER) == 0U) {
2447 continue;
2448 }
2449
2450 if (!field->HasFlag(varbinder::VariableFlags::PUBLIC)) {
2451 LogError(diagnostic::INTERFACE_PROP_NOT_PUBLIC, {}, field->Declaration()->Node()->Start());
2452 }
2453 CheckReadonlyClassPropertyInImplementedInterface(classType, field);
2454 classType->RemoveProperty<checker::PropertyType::INSTANCE_FIELD>(field);
2455 // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
2456 GenerateGetterSetterPropertyAndMethod(originalProp, classType);
2457 }
2458
2459 auto it = classDef->Body().begin();
2460 while (it != classDef->Body().end()) {
2461 if ((*it)->IsClassProperty() && ((*it)->Modifiers() & ir::ModifierFlags::GETTER_SETTER) != 0U) {
2462 it = classDef->Body().erase(it);
2463 } else {
2464 ++it;
2465 }
2466 }
2467 }
2468
CheckGetterSetterProperties(ETSObjectType * classType)2469 void ETSChecker::CheckGetterSetterProperties(ETSObjectType *classType)
2470 {
2471 auto const checkGetterSetter = [this](varbinder::LocalVariable *var, util::StringView name) {
2472 auto const *type = var->TsType()->AsETSFunctionType();
2473 auto const *sigGetter = type->FindGetter();
2474 auto const *sigSetter = type->FindSetter();
2475
2476 for (auto const *sig : type->CallSignatures()) {
2477 if (!sig->Function()->IsGetter() && !sig->Function()->IsSetter()) {
2478 LogError(diagnostic::METHOD_ACCESSOR_COLLISION, {name}, sig->Function()->Start());
2479 return;
2480 }
2481 if (sig != sigGetter && sig != sigSetter) {
2482 LogError(diagnostic::DUPLICATE_ACCESSOR, {}, sig->Function()->Start());
2483 return;
2484 }
2485 }
2486 if ((sigSetter != nullptr && sigGetter != nullptr) &&
2487 ((sigGetter->Function()->Modifiers() ^ sigSetter->Function()->Modifiers()) &
2488 ir::ModifierFlags::ACCESSOR_MODIFIERS) != 0) {
2489 LogError(diagnostic::ACCESSORS_MOD_MISMATCH, {}, sigGetter->Function()->Start());
2490 }
2491 };
2492
2493 for (const auto &[name, var] : classType->InstanceMethods()) {
2494 if (IsVariableGetterSetter(var)) {
2495 checkGetterSetter(var, name);
2496 }
2497 }
2498
2499 for (const auto &[name, var] : classType->StaticMethods()) {
2500 if (IsVariableGetterSetter(var)) {
2501 checkGetterSetter(var, name);
2502 }
2503 }
2504 }
2505
AddElementsToModuleObject(ETSObjectType * moduleObj,const util::StringView & str)2506 void ETSChecker::AddElementsToModuleObject(ETSObjectType *moduleObj, const util::StringView &str)
2507 {
2508 for (const auto &[name, var] : VarBinder()->GetScope()->Bindings()) {
2509 if (name.Is(str.Mutf8()) || util::Helpers::IsGlobalVar(var)) {
2510 continue;
2511 }
2512
2513 if (var->HasFlag(varbinder::VariableFlags::METHOD)) {
2514 moduleObj->AddProperty<checker::PropertyType::STATIC_METHOD>(var->AsLocalVariable());
2515 } else if (var->HasFlag(varbinder::VariableFlags::PROPERTY)) {
2516 moduleObj->AddProperty<checker::PropertyType::STATIC_FIELD>(var->AsLocalVariable());
2517 } else {
2518 moduleObj->AddProperty<checker::PropertyType::STATIC_DECL>(var->AsLocalVariable());
2519 }
2520 }
2521 }
2522
2523 // This function computes effective runtime view of type
GetApparentType(Type * type)2524 Type *ETSChecker::GetApparentType(Type *type)
2525 {
2526 if (auto it = apparentTypes_.find(type); LIKELY(it != apparentTypes_.end())) {
2527 return it->second;
2528 }
2529 auto cached = [this, type](Type *res) {
2530 if (type != res) {
2531 apparentTypes_.insert({type, res});
2532 }
2533 apparentTypes_.insert({res, res});
2534 return res;
2535 };
2536 ES2PANDA_ASSERT(type != nullptr);
2537 if (type->IsETSTypeParameter()) {
2538 // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
2539 return cached(GetApparentType(type->AsETSTypeParameter()->GetConstraintType()));
2540 }
2541 if (type->IsETSNonNullishType()) {
2542 // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
2543 return cached(
2544 // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
2545 GetNonNullishType(GetApparentType(type->AsETSNonNullishType()->GetUnderlying()->GetConstraintType())));
2546 }
2547 if (type->IsETSPartialTypeParameter()) {
2548 // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
2549 return cached(CreatePartialType(
2550 // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
2551 GetApparentType(type->AsETSPartialTypeParameter()->GetUnderlying()->GetConstraintType())));
2552 }
2553 if (type->IsETSArrayType()) {
2554 return cached(type);
2555 }
2556 if (type->IsETSStringType()) {
2557 return GlobalBuiltinETSStringType();
2558 }
2559 if (type->IsETSUnionType()) {
2560 bool differ = false;
2561 ArenaVector<checker::Type *> newConstituent(ProgramAllocator()->Adapter());
2562 for (auto const &ct : type->AsETSUnionType()->ConstituentTypes()) {
2563 // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
2564 newConstituent.push_back(GetApparentType(ct));
2565 differ |= (newConstituent.back() != ct);
2566 }
2567 return cached(differ ? CreateETSUnionType(std::move(newConstituent)) : type);
2568 }
2569 return cached(type);
2570 }
2571
GetApparentType(Type const * type) const2572 Type const *ETSChecker::GetApparentType(Type const *type) const
2573 {
2574 if (auto it = apparentTypes_.find(type); LIKELY(it != apparentTypes_.end())) {
2575 return it->second;
2576 }
2577 ES2PANDA_ASSERT(type != nullptr);
2578 // Relaxed for some types
2579 if (type->IsETSTypeParameter()) {
2580 // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
2581 return GetApparentType(type->AsETSTypeParameter()->GetConstraintType());
2582 }
2583 if (type->IsETSArrayType()) {
2584 return type;
2585 }
2586 if (type->IsETSStringType()) {
2587 return GlobalBuiltinETSStringType();
2588 }
2589 if (type->IsETSUnionType() || type->IsETSNonNullishType() || type->IsETSPartialTypeParameter()) {
2590 ASSERT_PRINT(false, std::string("Type ") + type->ToString() + " was not found in apparent_types_");
2591 }
2592 return type;
2593 }
2594
GetClosestCommonAncestor(ETSObjectType * source,ETSObjectType * target)2595 ETSObjectType *ETSChecker::GetClosestCommonAncestor(ETSObjectType *source, ETSObjectType *target)
2596 {
2597 if (source->AsETSObjectType()->GetDeclNode() == target->AsETSObjectType()->GetDeclNode()) {
2598 return source;
2599 }
2600 if (target->SuperType() == nullptr) {
2601 return GlobalETSObjectType();
2602 }
2603
2604 auto *targetBase = GetOriginalBaseType(target->SuperType());
2605 auto *targetType = targetBase == nullptr ? target->SuperType() : targetBase;
2606
2607 auto *sourceBase = GetOriginalBaseType(source);
2608 auto *sourceType = sourceBase == nullptr ? source : sourceBase;
2609
2610 if (Relation()->IsSupertypeOf(targetType, sourceType)) {
2611 // NOTE: TorokG. Extending the search to find intersection types
2612 return targetType;
2613 }
2614
2615 return GetClosestCommonAncestor(sourceType, targetType);
2616 }
2617
CheckInvokeMethodsLegitimacy(ETSObjectType * const classType)2618 void ETSChecker::CheckInvokeMethodsLegitimacy(ETSObjectType *const classType)
2619 {
2620 if (classType->HasObjectFlag(ETSObjectFlags::CHECKED_INVOKE_LEGITIMACY)) {
2621 return;
2622 }
2623
2624 auto searchFlag = PropertySearchFlags::SEARCH_IN_INTERFACES | PropertySearchFlags::SEARCH_IN_BASE |
2625 PropertySearchFlags::SEARCH_STATIC_METHOD;
2626
2627 auto *const invokeMethod = classType->GetProperty(compiler::Signatures::STATIC_INVOKE_METHOD, searchFlag);
2628 if (invokeMethod == nullptr) {
2629 classType->AddObjectFlag(ETSObjectFlags::CHECKED_INVOKE_LEGITIMACY);
2630 return;
2631 }
2632
2633 auto *const instantiateMethod = classType->GetProperty(compiler::Signatures::STATIC_INSTANTIATE_METHOD, searchFlag);
2634 if (instantiateMethod != nullptr) {
2635 LogError(diagnostic::STATIC_METH_IN_CLASS_AND_INTERFACE,
2636 {compiler::Signatures::STATIC_INVOKE_METHOD, compiler::Signatures::STATIC_INSTANTIATE_METHOD,
2637 classType->Name()},
2638 classType->GetDeclNode()->Start());
2639 }
2640 classType->AddObjectFlag(ETSObjectFlags::CHECKED_INVOKE_LEGITIMACY);
2641 }
2642
2643 } // namespace ark::es2panda::checker
2644