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