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