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