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