• 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 "binder.h"
17 
18 #include "ir/base/annotation.h"
19 #include "ir/base/catchClause.h"
20 #include "ir/base/classDefinition.h"
21 #include "ir/base/metaProperty.h"
22 #include "ir/base/property.h"
23 #include "ir/base/scriptFunction.h"
24 #include "ir/base/spreadElement.h"
25 #include "ir/expressions/arrayExpression.h"
26 #include "ir/expressions/assignmentExpression.h"
27 #include "ir/expressions/callExpression.h"
28 #include "ir/expressions/objectExpression.h"
29 #include "ir/expressions/literals/numberLiteral.h"
30 #include "ir/module/exportNamedDeclaration.h"
31 #include "ir/module/exportSpecifier.h"
32 #include "ir/statements/blockStatement.h"
33 #include "ir/statements/classDeclaration.h"
34 #include "ir/statements/doWhileStatement.h"
35 #include "ir/statements/forInStatement.h"
36 #include "ir/statements/forOfStatement.h"
37 #include "ir/statements/forUpdateStatement.h"
38 #include "ir/statements/switchCaseStatement.h"
39 #include "ir/statements/switchStatement.h"
40 #include "ir/statements/variableDeclaration.h"
41 #include "ir/statements/variableDeclarator.h"
42 #include "ir/statements/whileStatement.h"
43 #include "ir/ts/tsClassImplements.h"
44 #include "ir/ts/tsConstructorType.h"
45 #include "ir/ts/tsEnumDeclaration.h"
46 #include "ir/ts/tsFunctionType.h"
47 #include "ir/ts/tsIndexSignature.h"
48 #include "ir/ts/tsMethodSignature.h"
49 #include "ir/ts/tsModuleDeclaration.h"
50 #include "ir/ts/tsSignatureDeclaration.h"
51 #include "ir/ts/tsTypeParameterDeclaration.h"
52 #include "ir/ts/tsTypeParameterInstantiation.h"
53 #include "util/concurrent.h"
54 
55 namespace panda::es2panda::binder {
InitTopScope()56 void Binder::InitTopScope()
57 {
58     if (program_->Kind() == parser::ScriptKind::MODULE) {
59         topScope_ = Allocator()->New<ModuleScope>(Allocator(), program_);
60     } else {
61         topScope_ = Allocator()->New<GlobalScope>(Allocator());
62     }
63 
64     scope_ = topScope_;
65 }
66 
AddParamDecl(const ir::AstNode * param)67 ParameterDecl *Binder::AddParamDecl(const ir::AstNode *param)
68 {
69     ASSERT(scope_->IsFunctionParamScope() || scope_->IsCatchParamScope());
70     auto [decl, node] = static_cast<ParamScope *>(scope_)->AddParamDecl(Allocator(), param);
71 
72     if (!node) {
73         return decl;
74     }
75 
76     ThrowRedeclaration(node->Start(), decl->Name());
77 }
78 
ThrowRedeclaration(const lexer::SourcePosition & pos,const util::StringView & name)79 void Binder::ThrowRedeclaration(const lexer::SourcePosition &pos, const util::StringView &name)
80 {
81     lexer::LineIndex index(program_->SourceCode());
82     lexer::SourceLocation loc = index.GetLocation(pos);
83 
84     std::stringstream ss;
85     ss << "Variable '" << name << "' has already been declared.";
86     throw Error(ErrorType::SYNTAX, ss.str(), loc.line, loc.col);
87 }
88 
ThrowUndeclaredExport(const lexer::SourcePosition & pos,const util::StringView & name)89 void Binder::ThrowUndeclaredExport(const lexer::SourcePosition &pos, const util::StringView &name)
90 {
91     lexer::LineIndex index(program_->SourceCode());
92     lexer::SourceLocation loc = index.GetLocation(pos);
93 
94     std::stringstream ss;
95     ss << "Export name '" << name << "' is not defined.";
96     throw Error(ErrorType::SYNTAX, ss.str(), loc.line, loc.col);
97 }
98 
ThrowInvalidDstrTarget(const lexer::SourcePosition & pos,const util::StringView & name)99 void Binder::ThrowInvalidDstrTarget(const lexer::SourcePosition &pos, const util::StringView &name)
100 {
101     lexer::LineIndex index(program_->SourceCode());
102     lexer::SourceLocation loc = index.GetLocation(pos);
103 
104     std::stringstream ss;
105     ss << "Invalid destructuring assignment target: " << name;
106     throw Error(ErrorType::SYNTAX, ss.str(), loc.line, loc.col);
107 }
108 
ThrowInvalidAnnotationDeclaration(const lexer::SourcePosition & pos,const util::StringView & name)109 void Binder::ThrowInvalidAnnotationDeclaration(const lexer::SourcePosition &pos, const util::StringView &name)
110 {
111     lexer::LineIndex index(program_->SourceCode());
112     lexer::SourceLocation loc = index.GetLocation(pos);
113 
114     std::stringstream ss;
115     ss << "Invalid annotation declaration: " << name;
116     throw Error(ErrorType::SYNTAX, ss.str(), loc.line, loc.col);
117 }
118 
CheckMandatoryArguments(const ir::Identifier * ident)119 void Binder::CheckMandatoryArguments(const ir::Identifier *ident)
120 {
121     const auto *iter = static_cast<const ir::AstNode *>(ident);
122     bool isPatternMember = false;
123     while (iter) {
124         if (iter->IsArrayExpression() || iter->IsArrayPattern()) {
125             isPatternMember = true;
126             break;
127         }
128 
129         if (iter->IsObjectExpression() || iter->IsObjectPattern()) {
130             auto &properties = iter->IsObjectExpression() ? iter->AsObjectExpression()->Properties() :
131                                                             iter->AsObjectPattern()->Properties();
132             isPatternMember = util::Helpers::IsObjectPropertyValue(properties, ident);
133             break;
134         }
135         iter = iter->Parent();
136     }
137 
138     if (!isPatternMember) {
139         return;
140     }
141 
142     auto *patternNode = iter;
143 
144     while (iter) {
145         if (iter->IsAssignmentExpression() || iter->IsVariableDeclarator() || iter->IsForInStatement() ||
146             iter->IsForOfStatement()) {
147             break;
148         }
149 
150         iter = iter->Parent();
151     }
152 
153     if (!iter) {
154         return;
155     }
156 
157     const ir::AstNode *potentialParent = iter;
158 
159     if (iter->IsAssignmentExpression()) {
160         potentialParent = iter->AsAssignmentExpression()->Left();
161     } else if (iter->IsVariableDeclarator()) {
162         potentialParent = iter->AsVariableDeclarator()->Id();
163     } else {
164         potentialParent = iter->IsForInStatement() ? iter->AsForInStatement()->Left() :
165                                                      iter->AsForOfStatement()->Left();
166     }
167 
168     if (!util::Helpers::IsChild(potentialParent, patternNode)) {
169         return;
170     }
171 
172     ThrowInvalidDstrTarget(ident->Start(), ident->Name());
173 }
174 
AssignIndexToModuleVariable()175 void Binder::AssignIndexToModuleVariable()
176 {
177     ASSERT(program_->ModuleRecord());
178     program_->ModuleRecord()->AssignIndexToModuleVariable(topScope_->AsModuleScope());
179 }
180 
IdentifierAnalysis(ResolveBindingFlags flags)181 void Binder::IdentifierAnalysis(ResolveBindingFlags flags)
182 {
183     ASSERT(program_->Ast());
184     ASSERT(scope_ == topScope_);
185 
186     bindingFlags_ = flags;
187     // Bind function main0 first to determine whether a lexical variable is in it or not under hot-reload mode
188     if (bindingFlags_ & ResolveBindingFlags::TS_BEFORE_TRANSFORM) {
189         BuildFunction(topScope_, MAIN_FUNC_NAME);
190         ResolveReferences(program_->Ast());
191     } else if (bindingFlags_ & ResolveBindingFlags::TS_AFTER_TRANSFORM) {
192         // Basically same as js, except of function main0 will not be bound after transform
193         ResolveReferences(program_->Ast());
194         AddMandatoryParams();
195         if (topScope_->IsModuleScope()) {
196             AssignIndexToModuleVariable();
197         }
198     } else if (bindingFlags_ & ResolveBindingFlags::ALL) {
199         BuildFunction(topScope_, MAIN_FUNC_NAME);
200         ResolveReferences(program_->Ast());
201         AddMandatoryParams();
202         if (topScope_->IsModuleScope()) {
203             AssignIndexToModuleVariable();
204         }
205     }
206 }
207 
ValidateExportDecl(const ir::ExportNamedDeclaration * exportDecl)208 void Binder::ValidateExportDecl(const ir::ExportNamedDeclaration *exportDecl)
209 {
210     if (exportDecl->Source() != nullptr || exportDecl->Decl() != nullptr || exportDecl->IsType()) {
211         return;
212     }
213 
214     ASSERT(topScope_->IsModuleScope());
215     for (auto *it : exportDecl->Specifiers()) {
216         if (it->AsExportSpecifier()->IsType()) {
217             continue;
218         }
219 
220         auto localName = it->AsExportSpecifier()->Local()->Name();
221         if (scope_->IsTSModuleScope()) {
222             auto currentScope = scope_;
223             while (currentScope != nullptr) {
224                 if (currentScope->FindLocal(localName, ResolveBindingOptions::ALL) != nullptr ||
225                     (currentScope->IsTSModuleScope() && (currentScope->InLocalTSBindings(localName) ||
226                     currentScope->AsTSModuleScope()->InExportBindings(localName)))) {
227                     break;
228                 }
229                 currentScope = currentScope->Parent();
230             }
231             if (currentScope != nullptr) {
232                 continue;
233             }
234             ThrowUndeclaredExport(it->AsExportSpecifier()->Local()->Start(), localName);
235         }
236         ASSERT(topScope_ == scope_);
237         if (scope_->FindLocal(localName) == nullptr) {
238             // The declaration of ts cannot correspond to the variables of ts before transform,
239             // After the transform, they are all js variables. So it can return directly here.
240             if (scope_->InLocalTSBindings(localName) ||
241                 scope_->FindLocal(localName, ResolveBindingOptions::INTERFACES)) {
242                 continue;
243             }
244             ThrowUndeclaredExport(it->AsExportSpecifier()->Local()->Start(), localName);
245         }
246         scope_->AsModuleScope()->ConvertLocalVariableToModuleVariable(Allocator(), localName);
247     }
248 }
249 
LookupReference(const util::StringView & name)250 void Binder::LookupReference(const util::StringView &name)
251 {
252     ScopeFindResult res = scope_->Find(name);
253     if (res.level == 0) {
254         return;
255     }
256 
257     ASSERT(res.variable);
258     res.variable->SetLexical(res.scope, program_->PatchFixHelper());
259 }
260 
InstantiateArguments()261 void Binder::InstantiateArguments()
262 {
263     auto *iter = scope_;
264     while (true) {
265         Scope *scope = iter->IsFunctionParamScope() ? iter : iter->EnclosingVariableScope();
266         CHECK_NOT_NULL(scope);
267 
268         const auto *node = scope->Node();
269 
270         if (scope->IsLoopScope()) {
271             iter = scope->Parent();
272             continue;
273         }
274 
275         if (!node->IsScriptFunction()) {
276             break;
277         }
278 
279         if (!node->AsScriptFunction()->IsArrow()) {
280             auto *argumentsVariable =
281                 scope->AddDecl<ConstDecl, LocalVariable>(Allocator(), FUNCTION_ARGUMENTS, VariableFlags::INITIALIZED);
282 
283             if (iter->IsFunctionParamScope()) {
284                 if (!argumentsVariable) {
285                     break;
286                 }
287 
288                 scope = iter->AsFunctionParamScope()->GetFunctionScope();
289                 scope->Bindings().insert({argumentsVariable->Name(), argumentsVariable});
290             }
291 
292             scope->AsVariableScope()->AddFlag(VariableScopeFlags::USE_ARGS);
293 
294             break;
295         }
296 
297         iter = scope->Parent();
298     }
299 }
300 
LookupIdentReference(ir::Identifier * ident)301 void Binder::LookupIdentReference(ir::Identifier *ident)
302 {
303     if (ident->Name().Is(FUNCTION_ARGUMENTS)) {
304         InstantiateArguments();
305     }
306 
307     ScopeFindResult res;
308     if (bindingFlags_ & ResolveBindingFlags::TS_BEFORE_TRANSFORM) {
309         ident->SetTSVariables(FindIdentifierTSVariables(ident, scope_, res));
310     } else {
311         if (ident->Parent()->IsTSTypeReference()) {
312             res = scope_->Find(ident->Name(), ResolveBindingOptions::ALL);
313         } else {
314             res = scope_->Find(ident->Name(), ResolveBindingOptions::BINDINGS);
315         }
316     }
317 
318     if (res.variable == nullptr) {
319         return;
320     }
321 
322     if (res.level != 0) {
323         if (!res.variable->Declaration()->IsDeclare() && !ident->Parent()->IsTSTypeReference() &&
324             !ident->Parent()->IsTSTypeQuery() && !(bindingFlags_ & ResolveBindingFlags::TS_BEFORE_TRANSFORM)) {
325             util::Concurrent::ProcessConcurrent(Program()->GetLineIndex(), ident, res, program_);
326             res.variable->SetLexical(res.scope, program_->PatchFixHelper());
327         }
328     }
329 
330     auto decl = res.variable->Declaration();
331     if (decl->IsLetOrConstOrClassDecl() && !decl->HasFlag(DeclarationFlags::NAMESPACE_IMPORT) &&
332         !res.variable->HasFlag(VariableFlags::INITIALIZED)) {
333         ident->SetTdz();
334     }
335     // in release mode, replace const reference with its initialization
336     if (!this->Program()->IsDebug() && decl->IsConstDecl()) {
337         ReplaceConstReferenceWithInitialization(ident, decl);
338     }
339 
340     ident->SetVariable(res.variable);
341 }
342 
StoreAndCheckSpecialFunctionName(std::string & internalNameStr,std::string recordName)343 void Binder::StoreAndCheckSpecialFunctionName(std::string &internalNameStr, std::string recordName)
344 {
345     if (program_->PatchFixHelper()) {
346         if (program_->PatchFixHelper()->IsDumpSymbolTable()) {
347             // anonymous, special-name and duplicate function index started from 1
348             specialFuncNameIndexMap_.insert({internalNameStr, std::to_string(++globalIndexForSpecialFunc_)});
349             return;
350         }
351         if (program_->PatchFixHelper()->IsHotFix()) {
352             // Adding/removing anonymous, special or duplicate functions is supported for hotReload and coldFix mode,
353             // but forbidden in hotFix mode
354             program_->PatchFixHelper()->CheckAndRestoreSpecialFunctionName(++globalIndexForSpecialFunc_,
355                 internalNameStr, recordName);
356             return;
357         }
358         // else: must be coldfix or hotreload mode or coldreload mode
359         ASSERT(program_->PatchFixHelper()->IsColdFix() || program_->PatchFixHelper()->IsHotReload() ||
360                program_->PatchFixHelper()->IsColdReload());
361     }
362 }
363 
BuildFunction(FunctionScope * funcScope,util::StringView name,const ir::ScriptFunction * func)364 void Binder::BuildFunction(FunctionScope *funcScope, util::StringView name, const ir::ScriptFunction *func)
365 {
366     if (funcScope->InFunctionScopes()) {
367         return;
368     }
369     functionScopes_.push_back(funcScope);
370     funcScope->SetInFunctionScopes();
371     if (!util::Helpers::IsDefaultApiVersion(Program()->TargetApiVersion(), Program()->GetTargetApiSubVersion())) {
372         funcScope->SetSelfScopeName(name);
373         auto recordName = program_->FormatedRecordName().Mutf8();
374         funcScope->BindNameWithScopeInfo(name, util::UString(recordName, Allocator()).View());
375         if (func && (name == ANONYMOUS_FUNC_NAME)) {
376             anonymousFunctionNames_[func] = util::UString(funcScope->InternalName().Mutf8(), Allocator()).View();
377         }
378     } else {
379         LegacyBuildFunction(funcScope, name, func);
380     }
381 }
382 
LegacyBuildFunction(FunctionScope * funcScope,util::StringView name,const ir::ScriptFunction * func)383 void Binder::LegacyBuildFunction(FunctionScope *funcScope, util::StringView name, const ir::ScriptFunction *func)
384 {
385     bool funcNameWithoutDot = (name.Find(".") == std::string::npos);
386     bool funcNameWithoutBackslash = (name.Find("\\") == std::string::npos);
387     if (name != ANONYMOUS_FUNC_NAME && funcNameWithoutDot &&
388         funcNameWithoutBackslash && !functionNames_.count(name)) {
389         // function with normal name, and hasn't been recorded
390         auto internalName = std::string(program_->FormatedRecordName()) + std::string(name);
391         functionNames_.insert(name);
392         funcScope->BindName(name, util::UString(internalName, Allocator()).View());
393         return;
394     }
395 
396     std::stringstream ss;
397     ss << std::string(program_->FormatedRecordName());
398 
399     ASSERT(func != nullptr);
400 
401     // For anonymous, special-name and duplicate function, get its source and name, make hash code,
402     // and make #hash_duplicateHashTime#name as its name;
403     auto funcContentNameStr = func->SourceCode(this).Mutf8() + name.Mutf8();
404     ss << ANONYMOUS_SPECIAL_DUPLICATE_FUNCTION_SPECIFIER << util::Helpers::GetHashString(funcContentNameStr);
405 
406     auto res = functionHashNames_.find(funcContentNameStr);
407     if (res != functionHashNames_.end()) {
408         ss << "_" << res->second++;
409     } else {
410         functionHashNames_.insert({funcContentNameStr, 1});
411     }
412     ss << ANONYMOUS_SPECIAL_DUPLICATE_FUNCTION_SPECIFIER;
413 
414     if (name == ANONYMOUS_FUNC_NAME) {
415         anonymousFunctionNames_[func] = util::UString(ss.str(), Allocator()).View();
416     }
417     if (funcNameWithoutDot && funcNameWithoutBackslash) {
418         ss << name;
419     }
420     std::string internalNameStr = ss.str();
421     StoreAndCheckSpecialFunctionName(internalNameStr, program_->RecordName().Mutf8());
422     funcScope->BindName(name, util::UString(internalNameStr, Allocator()).View());
423 }
424 
BuildScriptFunction(Scope * outerScope,const ir::ScriptFunction * scriptFunc)425 void Binder::BuildScriptFunction(Scope *outerScope, const ir::ScriptFunction *scriptFunc)
426 {
427     if (bindingFlags_ & ResolveBindingFlags::TS_BEFORE_TRANSFORM) {
428         return;
429     }
430 
431     auto *funcScope = scriptFunc->Scope();
432     funcScope->ParamScope()->SetParent(outerScope);
433 
434     if (scriptFunc->IsArrow()) {
435         const ir::ScriptFunction *ctor = util::Helpers::GetContainingConstructor(scriptFunc);
436         if (ctor) {
437             ctor->Scope()->AddFlag(VariableScopeFlags::INNER_ARROW);
438         }
439     }
440 
441     ASSERT(scope_->IsFunctionScope() || scope_->IsTSModuleScope() || scope_->IsTSEnumScope());
442     BuildFunction(scope_->AsFunctionVariableScope(), util::Helpers::FunctionName(Allocator(), scriptFunc), scriptFunc);
443 }
444 
BuildVarDeclaratorId(const ir::AstNode * parent,ir::AstNode * childNode)445 void Binder::BuildVarDeclaratorId(const ir::AstNode *parent, ir::AstNode *childNode)
446 {
447     childNode->SetParent(parent);
448 
449     switch (childNode->Type()) {
450         case ir::AstNodeType::IDENTIFIER: {
451             auto *ident = childNode->AsIdentifier();
452             const auto &name = ident->Name();
453             if (name.Is(FUNCTION_ARGUMENTS)) {
454                 CheckMandatoryArguments(ident);
455             }
456 
457             if (util::Helpers::IsGlobalIdentifier(name)) {
458                 break;
459             }
460 
461             auto *variable = scope_->FindLocal(name, ResolveBindingOptions::BINDINGS);
462 
463             if (Program()->Extension() == ScriptExtension::TS) {
464                 ident->SetVariable(variable);
465                 BuildTSSignatureDeclarationBaseParamsWithParent(ident, ident->TypeAnnotation());
466             }
467 
468             CHECK_NOT_NULL(variable);
469             variable->AddFlag(VariableFlags::INITIALIZED);
470             break;
471         }
472         case ir::AstNodeType::OBJECT_PATTERN: {
473             auto *objPattern = childNode->AsObjectPattern();
474 
475             for (auto *prop : objPattern->Properties()) {
476                 BuildVarDeclaratorId(childNode, prop);
477             }
478 
479             BuildTSSignatureDeclarationBaseParamsWithParent(objPattern, objPattern->TypeAnnotation());
480             break;
481         }
482         case ir::AstNodeType::ARRAY_PATTERN: {
483             auto *arrayPattern = childNode->AsArrayPattern();
484 
485             for (auto *element : childNode->AsArrayPattern()->Elements()) {
486                 BuildVarDeclaratorId(childNode, element);
487             }
488 
489             BuildTSSignatureDeclarationBaseParamsWithParent(arrayPattern, arrayPattern->TypeAnnotation());
490             break;
491         }
492         case ir::AstNodeType::ASSIGNMENT_PATTERN: {
493             ResolveReference(childNode, childNode->AsAssignmentPattern()->Right());
494             BuildVarDeclaratorId(childNode, childNode->AsAssignmentPattern()->Left());
495             break;
496         }
497         case ir::AstNodeType::PROPERTY: {
498             ResolveReference(childNode, childNode->AsProperty()->Key());
499             BuildVarDeclaratorId(childNode, childNode->AsProperty()->Value());
500             break;
501         }
502         case ir::AstNodeType::REST_ELEMENT: {
503             BuildVarDeclaratorId(childNode, childNode->AsRestElement()->Argument());
504             break;
505         }
506         default:
507             break;
508     }
509 }
510 
BuildTSSignatureDeclarationBaseParamsWithParent(const ir::AstNode * parent,ir::AstNode * typeNode)511 void Binder::BuildTSSignatureDeclarationBaseParamsWithParent(const ir::AstNode *parent, ir::AstNode *typeNode)
512 {
513     if (!typeNode) {
514         return;
515     }
516     typeNode->SetParent(parent);
517     BuildTSSignatureDeclarationBaseParams(typeNode);
518 }
519 
BuildTSSignatureDeclarationBaseParams(const ir::AstNode * typeNode)520 void Binder::BuildTSSignatureDeclarationBaseParams(const ir::AstNode *typeNode)
521 {
522     ASSERT(typeNode != nullptr);
523 
524     Scope *scope = nullptr;
525 
526     switch (typeNode->Type()) {
527         case ir::AstNodeType::TS_FUNCTION_TYPE: {
528             scope = typeNode->AsTSFunctionType()->Scope();
529             break;
530         }
531         case ir::AstNodeType::TS_CONSTRUCTOR_TYPE: {
532             scope = typeNode->AsTSConstructorType()->Scope();
533             break;
534         }
535         case ir::AstNodeType::TS_SIGNATURE_DECLARATION: {
536             scope = typeNode->AsTSSignatureDeclaration()->Scope();
537             break;
538         }
539         case ir::AstNodeType::TS_METHOD_SIGNATURE: {
540             scope = typeNode->AsTSMethodSignature()->Scope();
541             break;
542         }
543         default: {
544             ResolveReferences(typeNode);
545             return;
546         }
547     }
548 
549     ASSERT(scope && scope->IsFunctionParamScope());
550 
551     auto scopeCtx = LexicalScope<FunctionParamScope>::Enter(this, scope->AsFunctionParamScope());
552     ResolveReferences(typeNode);
553 }
554 
BuildVarDeclarator(ir::VariableDeclarator * varDecl)555 void Binder::BuildVarDeclarator(ir::VariableDeclarator *varDecl)
556 {
557     if (varDecl->Parent()->AsVariableDeclaration()->Kind() == ir::VariableDeclaration::VariableDeclarationKind::VAR) {
558         ResolveReferences(varDecl);
559         return;
560     }
561 
562     if (varDecl->Init()) {
563         ResolveReference(varDecl, varDecl->Init());
564     }
565 
566     BuildVarDeclaratorId(varDecl, varDecl->Id());
567 }
568 
ProcessNodeInStaticInitializer(ir::ClassDefinition * classDef)569 void Binder::ProcessNodeInStaticInitializer(ir::ClassDefinition *classDef)
570 {
571     if (classDef->NeedStaticInitializer()) {
572         ResolveReference(classDef, classDef->StaticInitializer());
573     }
574 
575     for (auto *stmt : classDef->Body()) {
576         if (stmt->IsClassStaticBlock() || (stmt->IsClassProperty() && stmt->AsClassProperty()->IsStatic())) {
577             ResolveReference(classDef, stmt);
578         }
579     }
580 }
581 
BuildClassDefinition(ir::ClassDefinition * classDef)582 void Binder::BuildClassDefinition(ir::ClassDefinition *classDef)
583 {
584     if (classDef->Parent()->IsClassDeclaration()) {
585         util::StringView className = classDef->GetName();
586         ASSERT(!className.Empty());
587         ScopeFindResult res = scope_->Find(className);
588 
589         ASSERT(res.variable && (res.variable->Declaration()->IsClassDecl() ||
590                (res.variable->Declaration()->IsFunctionDecl() &&
591                res.variable->Declaration()->AsFunctionDecl()->GetDeclClass() != nullptr)));
592         res.variable->AddFlag(VariableFlags::INITIALIZED);
593     }
594 
595     auto scopeCtx = LexicalScope<ClassScope>::Enter(this, classDef->Scope());
596 
597     if (classDef->TypeParams()) {
598         ResolveReference(classDef, classDef->TypeParams());
599     }
600 
601     if (classDef->Super()) {
602         ResolveReference(classDef, classDef->Super());
603     }
604 
605     if (classDef->SuperTypeParams()) {
606         ResolveReference(classDef, classDef->SuperTypeParams());
607     }
608 
609     for (auto *iter : classDef->Implements()) {
610         ResolveReference(classDef, iter);
611     }
612 
613     // new class features in ecma2022 are only supported for api11 and above
614     if (Program()->TargetApiVersion() > 10 && !(bindingFlags_ & ResolveBindingFlags::TS_BEFORE_TRANSFORM)) {
615         classDef->BuildClassEnvironment(program_->UseDefineSemantic());
616     }
617 
618     if (classDef->Ident()) {
619         ScopeFindResult res = scope_->Find(classDef->Ident()->Name());
620 
621         ASSERT(res.variable && res.variable->Declaration()->IsConstDecl());
622         res.variable->AddFlag(VariableFlags::INITIALIZED);
623 
624         classDef->Ident()->SetParent(classDef);
625     }
626     util::SaveValue<bool> saveInSendableClass {inSendableClass_};
627 
628     // Static initializer in sendable class should not be marked as sendable.
629     // By processing static initializer before constructor, in which class is marked sendable,
630     // the static initializer and functions inside it will not be marked as sendable.
631     ProcessNodeInStaticInitializer(classDef);
632 
633     if (!(classDef->Parent()->IsClassDeclaration() && classDef->Parent()->AsClassDeclaration()->IsAnnotationDecl())) {
634         ResolveReference(classDef, classDef->Ctor());
635     }
636 
637     if (classDef->NeedInstanceInitializer()) {
638         ResolveReference(classDef, classDef->InstanceInitializer());
639     }
640 
641     for (auto *stmt : classDef->Body()) {
642         if (!stmt->IsClassStaticBlock() && !(stmt->IsClassProperty() && stmt->AsClassProperty()->IsStatic())) {
643             ResolveReference(classDef, stmt);
644         }
645     }
646 
647     for (auto *iter : classDef->IndexSignatures()) {
648         ResolveReference(classDef, iter);
649     }
650 }
651 
BuildForUpdateLoop(ir::ForUpdateStatement * forUpdateStmt)652 void Binder::BuildForUpdateLoop(ir::ForUpdateStatement *forUpdateStmt)
653 {
654     auto *loopScope = forUpdateStmt->Scope();
655 
656     auto loopCtx = LexicalScope<LoopScope>::Enter(this, loopScope);
657 
658     if (forUpdateStmt->Init()) {
659         ResolveReference(forUpdateStmt, forUpdateStmt->Init());
660     }
661 
662     if (forUpdateStmt->Update()) {
663         ResolveReference(forUpdateStmt, forUpdateStmt->Update());
664     }
665 
666     if (forUpdateStmt->Test()) {
667         ResolveReference(forUpdateStmt, forUpdateStmt->Test());
668     }
669 
670     ResolveReference(forUpdateStmt, forUpdateStmt->Body());
671 
672     loopCtx.GetScope()->InitVariable();
673 }
674 
BuildForInOfLoop(const ir::Statement * parent,binder::LoopScope * loopScope,ir::AstNode * left,ir::Expression * right,ir::Statement * body)675 void Binder::BuildForInOfLoop(const ir::Statement *parent, binder::LoopScope *loopScope, ir::AstNode *left,
676                               ir::Expression *right, ir::Statement *body)
677 {
678     auto loopCtx = LexicalScope<LoopScope>::Enter(this, loopScope);
679 
680     ResolveReference(parent, right);
681     ResolveReference(parent, left);
682 
683     ResolveReference(parent, body);
684     loopCtx.GetScope()->InitVariable();
685 }
686 
BuildCatchClause(ir::CatchClause * catchClauseStmt)687 void Binder::BuildCatchClause(ir::CatchClause *catchClauseStmt)
688 {
689     if (catchClauseStmt->Param()) {
690         auto paramScopeCtx = LexicalScope<CatchParamScope>::Enter(this, catchClauseStmt->Scope()->ParamScope());
691         ResolveReference(catchClauseStmt, catchClauseStmt->Param());
692     }
693 
694     auto scopeCtx = LexicalScope<CatchScope>::Enter(this, catchClauseStmt->Scope());
695     ResolveReference(catchClauseStmt, catchClauseStmt->Body());
696 }
697 
ResolveReference(const ir::AstNode * parent,ir::AstNode * childNode)698 void Binder::ResolveReference(const ir::AstNode *parent, ir::AstNode *childNode)
699 {
700     childNode->SetParent(parent);
701 
702     ClassTdz classTdz(parent, childNode, scope_);
703 
704     switch (childNode->Type()) {
705         case ir::AstNodeType::IDENTIFIER: {
706             auto *ident = childNode->AsIdentifier();
707 
708             if (ident->Name().Is(FUNCTION_ARGUMENTS)) {
709                 CheckMandatoryArguments(ident);
710             }
711 
712             if (ident->IsReference()) {
713                 LookupIdentReference(ident);
714             }
715 
716             /* During ts to js transformation, a non-empty namespace in ts file will be transformed
717                into a anonymous function while empty namespace will be removed. So the name for the
718                namespace need to be stored before the transformation.*/
719             if (scope_->Type() == ScopeType::TSMODULE) {
720                 scope_->SetSelfScopeName(ident->Name());
721             }
722 
723             ResolveReferences(childNode);
724             break;
725         }
726         case ir::AstNodeType::ANNOTATION: {
727             auto *annotation = childNode->AsAnnotation();
728             std::string annoName{annotation->Name()};
729             ScopeFindResult res = scope_->Find(annotation->Name(), bindingOptions_);
730             if (res.variable != nullptr) {
731                 if (res.variable->Declaration()->Node()->IsImportSpecifier()) {
732                     annotation->SetIsImported();
733                 } else if (!res.variable->Declaration()->Node()->IsClassDefinition()) {
734                     ThrowInvalidAnnotationDeclaration(annotation->Start(), annotation->Name());
735                 }
736             } else if (annoName.find_first_of(".") != std::string::npos) {
737                 auto importName = annoName.substr(0, annoName.find_first_of("."));
738                 ScopeFindResult res = scope_->Find(util::StringView(importName), bindingOptions_);
739                 if (res.variable != nullptr && res.variable->Declaration()->Node()->IsImportNamespaceSpecifier()) {
740                     annotation->SetIsImported();
741                 } else {
742                     ThrowInvalidAnnotationDeclaration(annotation->Start(), annotation->Name());
743                 }
744             } else {
745                 ThrowInvalidAnnotationDeclaration(annotation->Start(), annotation->Name());
746             }
747             ResolveReferences(childNode);
748             break;
749         }
750         case ir::AstNodeType::PRIVATE_IDENTIFIER: {
751             if (Program()->Extension() == ScriptExtension::JS) {
752                 CheckPrivateDeclaration(childNode->AsPrivateIdentifier());
753             } else if (Program()->Extension() == ScriptExtension::TS &&
754                        bindingFlags_ == ResolveBindingFlags::TS_AFTER_TRANSFORM) {
755                 CheckPrivateDeclaration(childNode->AsPrivateIdentifier());
756             }
757             break;
758         }
759         case ir::AstNodeType::SUPER_EXPRESSION: {
760             VariableScope *varScope = scope_->EnclosingFunctionVariableScope();
761             CHECK_NOT_NULL(varScope);
762             varScope->AddFlag(VariableScopeFlags::USE_SUPER);
763 
764             ResolveReferences(childNode);
765             break;
766         }
767         case ir::AstNodeType::SCRIPT_FUNCTION: {
768             util::SaveValue<bool> saveInSendableFunction {inSendableFunction_};
769             auto *scriptFunc = childNode->AsScriptFunction();
770             if (inSendableClass_ || inSendableFunction_) {
771                 scriptFunc->SetInSendable();
772             }
773             util::DirectiveScanConfig scanInfos {
774                 Program()->GetLineIndex(),
775                 program_->TargetApiVersion() >= util::Helpers::SENDABLE_CLASS_MIN_SUPPORTED_API_VERSION,
776                 !util::Helpers::IsDefaultApiVersion(program_->TargetApiVersion(), program_->GetTargetApiSubVersion()),
777                 program_->IsEnableEtsImplements()};
778             util::Helpers::ScanDirectives(const_cast<ir::ScriptFunction *>(scriptFunc), scanInfos);
779 
780             if (scriptFunc->IsConstructor() && util::Helpers::GetClassDefiniton(scriptFunc)->IsSendable()) {
781                 scriptFunc->SetInSendable();
782                 inSendableClass_ = true;
783             } else if (scriptFunc->IsSendable()) {
784                 scriptFunc->SetInSendable();
785                 inSendableFunction_ = true;
786             }
787 
788             auto *funcScope = scriptFunc->Scope();
789 
790             auto *outerScope = scope_;
791 
792             if (scriptFunc->Id() != nullptr) {
793                 scriptFunc->Id()->SetParent(scriptFunc);
794             }
795 
796             {
797                 auto paramScopeCtx = LexicalScope<FunctionParamScope>::Enter(this, funcScope->ParamScope());
798 
799                 if (Program()->Extension() == ScriptExtension::TS) {
800                     if (scriptFunc->TypeParams() != nullptr) {
801                         ResolveReference(scriptFunc, scriptFunc->TypeParams());
802                     }
803                     if (scriptFunc->ThisParams() != nullptr) {
804                         ResolveReference(scriptFunc, scriptFunc->ThisParams());
805                     }
806                 }
807 
808                 for (auto *param : scriptFunc->Params()) {
809                     ResolveReference(scriptFunc, param);
810                 }
811             }
812 
813             if (Program()->Extension() == ScriptExtension::TS) {
814                 if (scriptFunc->ReturnTypeAnnotation()) {
815                     ResolveReference(scriptFunc, scriptFunc->ReturnTypeAnnotation());
816                 }
817 
818                 if (scriptFunc->IsOverload() || scriptFunc->Declare()) {
819                     break;
820                 }
821             }
822 
823             auto scopeCtx = LexicalScope<FunctionScope>::Enter(this, funcScope);
824 
825             BuildScriptFunction(outerScope, scriptFunc);
826 
827             ResolveReference(scriptFunc, scriptFunc->Body());
828             break;
829         }
830         case ir::AstNodeType::VARIABLE_DECLARATOR: {
831             BuildVarDeclarator(childNode->AsVariableDeclarator());
832 
833             break;
834         }
835         case ir::AstNodeType::CLASS_DEFINITION: {
836             auto *classScope = childNode->AsClassDefinition()->Scope();
837             classScope->SetParent(scope_);
838             BuildClassDefinition(childNode->AsClassDefinition());
839 
840             break;
841         }
842         case ir::AstNodeType::CLASS_PROPERTY: {
843             /* for ts tranformer cases, all class properties are implemented by transformer in api10 and
844              * only public instance class properties are implemented by transformer in api11*/
845             auto *prop = childNode->AsClassProperty();
846             if (Program()->Extension() == ScriptExtension::TS && (Program()->TargetApiVersion() < 11 ||
847                 (!prop->IsStatic() && !prop->IsPrivate()))) {
848                 const ir::ScriptFunction *ctor = util::Helpers::GetContainingConstructor(prop);
849                 CHECK_NOT_NULL(ctor);
850                 auto scopeCtx = LexicalScope<FunctionScope>::Enter(this, ctor->Scope());
851                 ResolveReferences(childNode);
852                 break;
853             }
854 
855             ResolveReference(prop, prop->Key());
856             if (prop->TypeAnnotation() != nullptr) {
857                 ResolveReference(prop, prop->TypeAnnotation());
858             }
859             if (prop->Value() != nullptr) {
860                 ASSERT(parent->IsClassDefinition());
861                 const auto *classDef = parent->AsClassDefinition();
862                 const ir::MethodDefinition *method = prop->IsStatic() ? classDef->StaticInitializer() :
863                                                      classDef->InstanceInitializer();
864                 auto scopeCtx = LexicalScope<FunctionScope>::Enter(this, method->Function()->Scope());
865                 ResolveReference(prop, prop->Value());
866             }
867             break;
868         }
869         case ir::AstNodeType::BLOCK_STATEMENT: {
870             auto scope = childNode->AsBlockStatement()->Scope();
871             auto scopeCtx = scope != nullptr ?
872                 LexicalScope<Scope>::Enter(this, scope) :
873                 LexicalScope<Scope>::Enter(this, GetScope());
874 
875             ResolveReferences(childNode);
876             break;
877         }
878         case ir::AstNodeType::SWITCH_STATEMENT: {
879             auto *switchStatement = childNode->AsSwitchStatement();
880             ResolveReference(switchStatement, switchStatement->Discriminant());
881 
882             auto scopeCtx = LexicalScope<LocalScope>::Enter(this, childNode->AsSwitchStatement()->Scope());
883             for (auto *it : switchStatement->Cases()) {
884                 ResolveReference(switchStatement, it);
885             }
886             break;
887         }
888         case ir::AstNodeType::DO_WHILE_STATEMENT: {
889             auto *doWhileStatement = childNode->AsDoWhileStatement();
890 
891             {
892                 auto loopScopeCtx = LexicalScope<LoopScope>::Enter(this, doWhileStatement->Scope());
893                 ResolveReference(doWhileStatement, doWhileStatement->Body());
894                 loopScopeCtx.GetScope()->InitVariable();
895             }
896 
897             ResolveReference(doWhileStatement, doWhileStatement->Test());
898             break;
899         }
900         case ir::AstNodeType::WHILE_STATEMENT: {
901             auto *whileStatement = childNode->AsWhileStatement();
902             ResolveReference(whileStatement, whileStatement->Test());
903 
904             auto loopScopeCtx = LexicalScope<LoopScope>::Enter(this, whileStatement->Scope());
905             ResolveReference(whileStatement, whileStatement->Body());
906             loopScopeCtx.GetScope()->InitVariable();
907             break;
908         }
909         case ir::AstNodeType::FOR_UPDATE_STATEMENT: {
910             BuildForUpdateLoop(childNode->AsForUpdateStatement());
911             break;
912         }
913         case ir::AstNodeType::FOR_IN_STATEMENT: {
914             auto *forInStmt = childNode->AsForInStatement();
915             BuildForInOfLoop(forInStmt, forInStmt->Scope(), forInStmt->Left(), forInStmt->Right(), forInStmt->Body());
916 
917             break;
918         }
919         case ir::AstNodeType::FOR_OF_STATEMENT: {
920             auto *forOfStmt = childNode->AsForOfStatement();
921             BuildForInOfLoop(forOfStmt, forOfStmt->Scope(), forOfStmt->Left(), forOfStmt->Right(), forOfStmt->Body());
922             break;
923         }
924         case ir::AstNodeType::CATCH_CLAUSE: {
925             BuildCatchClause(childNode->AsCatchClause());
926             break;
927         }
928         case ir::AstNodeType::EXPORT_NAMED_DECLARATION: {
929             ValidateExportDecl(childNode->AsExportNamedDeclaration());
930 
931             ResolveReferences(childNode);
932             break;
933         }
934         // TypeScript specific part
935         case ir::AstNodeType::TS_FUNCTION_TYPE:
936         case ir::AstNodeType::TS_CONSTRUCTOR_TYPE:
937         case ir::AstNodeType::TS_METHOD_SIGNATURE:
938         case ir::AstNodeType::TS_SIGNATURE_DECLARATION: {
939             BuildTSSignatureDeclarationBaseParams(childNode);
940             break;
941         }
942         case ir::AstNodeType::TS_MODULE_DECLARATION: {
943             auto scopeCtx = LexicalScope<Scope>::Enter(this, childNode->AsTSModuleDeclaration()->Scope());
944             ResolveReferences(childNode);
945             break;
946         }
947         case ir::AstNodeType::TS_ENUM_DECLARATION: {
948             auto scopeCtx = LexicalScope<Scope>::Enter(this, childNode->AsTSEnumDeclaration()->Scope());
949             ResolveReferences(childNode);
950             break;
951         }
952         case ir::AstNodeType::THIS_EXPRESSION: {
953             VariableScope *varScope = scope_->EnclosingFunctionVariableScope();
954             CHECK_NOT_NULL(varScope);
955             varScope->AddFlag(VariableScopeFlags::USE_THIS);
956             ResolveReferences(childNode);
957             break;
958         }
959         case ir::AstNodeType::META_PROPERTY_EXPRESSION: {
960             if (childNode->AsMetaProperty()->Kind() ==
961                 ir::MetaProperty::MetaPropertyKind::NEW_TARGET) {
962                 VariableScope *varScope = scope_->EnclosingFunctionVariableScope();
963                 CHECK_NOT_NULL(varScope);
964                 varScope->AddFlag(VariableScopeFlags::USE_NEW_TARGET);
965             }
966             ResolveReferences(childNode);
967             break;
968         }
969         default: {
970             ResolveReferences(childNode);
971             break;
972         }
973     }
974 }
ResolveReferences(const ir::AstNode * parent)975 void Binder::ResolveReferences(const ir::AstNode *parent)
976 {
977     parent->Iterate([this, parent](auto *childNode) { ResolveReference(parent, childNode); });
978 }
979 
AddMandatoryParam(const std::string_view & name)980 void Binder::AddMandatoryParam(const std::string_view &name)
981 {
982     ASSERT(scope_->IsFunctionVariableScope());
983 
984     auto *decl = Allocator()->New<ParameterDecl>(name);
985     CHECK_NOT_NULL(decl);
986     auto *param = Allocator()->New<LocalVariable>(decl, VariableFlags::VAR);
987     CHECK_NOT_NULL(param);
988 
989     auto *paramScope = scope_->AsFunctionVariableScope()->ParamScope();
990     CHECK_NOT_NULL(paramScope);
991 
992     auto &funcParams = paramScope->Params();
993     funcParams.insert(funcParams.begin(), param);
994     scope_->AsFunctionVariableScope()->ParamScope()->Bindings().insert({decl->Name(), param});
995     scope_->AsFunctionVariableScope()->Bindings().insert({decl->Name(), param});
996 }
997 
AddMandatoryParams()998 void Binder::AddMandatoryParams()
999 {
1000     ASSERT(scope_ == topScope_);
1001     ASSERT(!functionScopes_.empty());
1002     auto iter = functionScopes_.begin();
1003     [[maybe_unused]] auto *funcScope = *iter++;
1004 
1005     ASSERT(funcScope->IsGlobalScope() || funcScope->IsModuleScope());
1006 
1007     if (program_->Kind() == parser::ScriptKind::COMMONJS) {
1008         AddMandatoryParams(CJS_MAINFUNC_MANDATORY_PARAMS);
1009     } else {
1010         AddMandatoryParams(FUNCTION_MANDATORY_PARAMS);
1011     }
1012 
1013     for (; iter != functionScopes_.end(); iter++) {
1014         funcScope = *iter;
1015         const auto *scriptFunc = funcScope->Node()->AsScriptFunction();
1016 
1017         auto scopeCtx = LexicalScope<FunctionScope>::Enter(this, funcScope);
1018 
1019         if (!scriptFunc->IsArrow()) {
1020             AddMandatoryParams(FUNCTION_MANDATORY_PARAMS);
1021             continue;
1022         }
1023 
1024         const ir::ScriptFunction *ctor = util::Helpers::GetContainingConstructor(scriptFunc);
1025         bool lexicalFunctionObject {};
1026 
1027         if (ctor && util::Helpers::GetClassDefiniton(ctor)->Super() &&
1028             funcScope->HasFlag(VariableScopeFlags::USE_SUPER)) {
1029             ASSERT(ctor->Scope()->HasFlag(VariableScopeFlags::INNER_ARROW));
1030             ctor->Scope()->AddFlag(VariableScopeFlags::SET_LEXICAL_FUNCTION);
1031             lexicalFunctionObject = true;
1032             AddMandatoryParams(CTOR_ARROW_MANDATORY_PARAMS);
1033         } else {
1034             AddMandatoryParams(ARROW_MANDATORY_PARAMS);
1035         }
1036 
1037         if (funcScope->HasFlag(VariableScopeFlags::USE_NEW_TARGET)) {
1038             LookupReference(MANDATORY_PARAM_NEW_TARGET);
1039         }
1040         if (funcScope->HasFlag(VariableScopeFlags::USE_THIS) || funcScope->HasFlag(VariableScopeFlags::USE_SUPER)) {
1041             LookupReference(MANDATORY_PARAM_THIS);
1042         }
1043 
1044         if (funcScope->HasFlag(VariableScopeFlags::USE_ARGS)) {
1045             LookupReference(FUNCTION_ARGUMENTS);
1046         }
1047 
1048         if (lexicalFunctionObject) {
1049             LookupReference(MANDATORY_PARAM_FUNC);
1050         }
1051     }
1052 }
1053 
AddDeclarationName(const util::StringView & name,DeclType type)1054 void Binder::AddDeclarationName(const util::StringView &name, DeclType type)
1055 {
1056     if (extension_ != ScriptExtension::TS) {
1057         return;
1058     }
1059     variableNames_.insert(name);
1060 
1061     if (type == DeclType::ENUM) {
1062         return;
1063     }
1064     auto *scope = GetScope();
1065     while (scope != nullptr) {
1066         if (scope->IsTSModuleScope()) {
1067             scope->AsTSModuleScope()->AddDeclarationName(name);
1068         }
1069         if (scope->IsTSEnumScope()) {
1070             scope->AsTSEnumScope()->AddDeclarationName(name);
1071         }
1072         scope = scope->Parent();
1073     }
1074 }
1075 
HasVariableName(const util::StringView & name) const1076 bool Binder::HasVariableName(const util::StringView &name) const
1077 {
1078     return variableNames_.find(name) != variableNames_.end();
1079 }
1080 
FindIdentifierTSVariables(const ir::Identifier * identifier,Scope * scope,ScopeFindResult & res)1081 std::vector<Variable *> Binder::FindIdentifierTSVariables(const ir::Identifier *identifier, Scope *scope,
1082     ScopeFindResult &res)
1083 {
1084     const auto &name = identifier->Name();
1085     std::vector<binder::Variable *> findRes;
1086 
1087     auto currentScope = scope;
1088     while (currentScope != nullptr) {
1089         // Find ts variables
1090         auto fn = [&findRes](Variable *variable) {
1091             if (variable != nullptr) {
1092                 findRes.emplace_back(variable);
1093             }
1094         };
1095 
1096         fn(currentScope->FindLocalTSVariable<binder::TSBindingType::NAMESPACE>(name));
1097         fn(currentScope->FindLocalTSVariable<binder::TSBindingType::ENUMLITERAL>(name));
1098         fn(currentScope->FindLocalTSVariable<binder::TSBindingType::IMPORT_EQUALS>(name));
1099         if (currentScope->IsTSModuleScope()) {
1100             fn(currentScope->AsTSModuleScope()->FindExportTSVariable<binder::TSBindingType::NAMESPACE>(name));
1101             fn(currentScope->AsTSModuleScope()->FindExportTSVariable<binder::TSBindingType::ENUMLITERAL>(name));
1102             fn(currentScope->AsTSModuleScope()->FindExportTSVariable<binder::TSBindingType::IMPORT_EQUALS>(name));
1103         }
1104 
1105         // Find js variable
1106         if (currentScope->FindLocal(name, bindingOptions_) != nullptr) {
1107             res = scope->Find(name, bindingOptions_);
1108             break;
1109         }
1110 
1111         if (!findRes.empty()) {
1112             break;
1113         }
1114 
1115         currentScope = currentScope->Parent();
1116     }
1117 
1118     return findRes;
1119 }
1120 
ReplaceConstReferenceWithInitialization(const ir::Identifier * ident,const Decl * decl)1121 void Binder::ReplaceConstReferenceWithInitialization(const ir::Identifier *ident, const Decl *decl)
1122 {
1123     bool isValidAssignmentExpr = ident->Parent()->IsAssignmentExpression() &&
1124         ident->Parent()->AsAssignmentExpression()->Right() == ident;
1125     bool isBinaryExpr = ident->Parent()->IsBinaryExpression();
1126     bool isVariableDecl = ident->Parent()->IsVariableDeclarator() &&
1127         ident->Parent()->AsVariableDeclarator()->Init() == ident;
1128     if (!isValidAssignmentExpr && !isBinaryExpr && !isVariableDecl) {
1129         return;
1130     }
1131 
1132     if (decl->Node() == nullptr || decl->Node()->Parent() == nullptr ||
1133         !decl->Node()->Parent()->IsVariableDeclarator()) {
1134         return;
1135     }
1136 
1137     const ir::AstNode *initialization = static_cast<const ir::AstNode *>(
1138         decl->Node()->Parent()->AsVariableDeclarator()->Init());
1139     if (initialization == nullptr || !initialization->IsNumberLiteral()) {
1140         return;
1141     }
1142 
1143     auto newNode = Allocator()->New<ir::NumberLiteral>(initialization->AsNumberLiteral()->Number());
1144     if (newNode == nullptr) {
1145         throw Error(ErrorType::GENERIC, "Unsuccessful allocation during replacing const reference node");
1146     }
1147     // Make sure the new node get the correct line number
1148     // Column number may be incorrect, but it doesn't matter in release mode
1149     newNode->SetRange(ident->Range());
1150 
1151     auto *parentNode = const_cast<panda::es2panda::ir::AstNode *>(ident->Parent());
1152     // update the reference node with initialization node
1153     parentNode->UpdateSelf([=](auto *childNode) {
1154             if (childNode == ident) {
1155                 return static_cast<ir::AstNode *>(newNode);
1156             }
1157             return childNode;
1158         }, this);
1159 }
1160 
CheckPrivateDeclaration(const ir::PrivateIdentifier * privateIdent)1161 void Binder::CheckPrivateDeclaration(const ir::PrivateIdentifier *privateIdent)
1162 {
1163     auto name = privateIdent->Name();
1164     auto scope = scope_;
1165     while (scope != nullptr) {
1166         if (scope->Type() == ScopeType::CLASS) {
1167             const auto *classScope = scope->AsClassScope();
1168             if (classScope->HasPrivateName(name)) {
1169                 return;
1170             }
1171         }
1172         scope = scope->Parent();
1173     }
1174 
1175     auto pos = privateIdent->Start();
1176     lexer::LineIndex index(program_->SourceCode());
1177     lexer::SourceLocation loc = index.GetLocation(pos);
1178 
1179     throw Error{ErrorType::SYNTAX, "Use private property before declaration", loc.line, loc.col};
1180 }
1181 
ClassTdz(const ir::AstNode * parent,const ir::AstNode * childNode,Scope * scope)1182 ClassTdz::ClassTdz(const ir::AstNode *parent, const ir::AstNode *childNode, Scope *scope)
1183 {
1184     /* In ES2022, class element name's evaluation is before class's initialization.
1185      * So a computed property name can not access class object which leads to a reference error.
1186      * For example:
1187      * class A {
1188      *   [A]
1189      * }
1190      */
1191     bool isClassTdz = (parent->IsClassProperty() && childNode == parent->AsClassProperty()->Key()) ||
1192         (parent->IsMethodDefinition() && childNode == parent->AsMethodDefinition()->Key());
1193     if (!isClassTdz) {
1194         return;
1195     }
1196 
1197     ASSERT(parent->Parent()->IsClassDefinition());
1198     auto classDef = parent->Parent()->AsClassDefinition();
1199     if (!classDef->Ident()) {
1200         return;
1201     }
1202 
1203     ScopeFindResult res = scope->Find(classDef->Ident()->Name());
1204     ASSERT(res.variable && res.variable->Declaration()->IsConstDecl());
1205     variable_ = res.variable;
1206     variable_->RemoveFlag(VariableFlags::INITIALIZED);
1207 }
1208 
1209 }  // namespace panda::es2panda::binder
1210