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