• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &currentInterfaceChild : 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