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());
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
264 const auto *node = scope->Node();
265
266 if (scope->IsLoopScope()) {
267 iter = scope->Parent();
268 continue;
269 }
270
271 if (!node->IsScriptFunction()) {
272 break;
273 }
274
275 if (!node->AsScriptFunction()->IsArrow()) {
276 auto *argumentsVariable =
277 scope->AddDecl<ConstDecl, LocalVariable>(Allocator(), FUNCTION_ARGUMENTS, VariableFlags::INITIALIZED);
278
279 if (iter->IsFunctionParamScope()) {
280 if (!argumentsVariable) {
281 break;
282 }
283
284 scope = iter->AsFunctionParamScope()->GetFunctionScope();
285 scope->Bindings().insert({argumentsVariable->Name(), argumentsVariable});
286 }
287
288 scope->AsVariableScope()->AddFlag(VariableScopeFlags::USE_ARGS);
289
290 break;
291 }
292
293 iter = scope->Parent();
294 }
295 }
296
LookupIdentReference(ir::Identifier * ident)297 void Binder::LookupIdentReference(ir::Identifier *ident)
298 {
299 if (ident->Name().Is(FUNCTION_ARGUMENTS)) {
300 InstantiateArguments();
301 }
302
303 ScopeFindResult res;
304 if (bindingFlags_ & ResolveBindingFlags::TS_BEFORE_TRANSFORM) {
305 ident->SetTSVariables(FindIdentifierTSVariables(ident, scope_, res));
306 } else {
307 if (ident->Parent()->IsTSTypeReference()) {
308 res = scope_->Find(ident->Name(), ResolveBindingOptions::ALL);
309 } else {
310 res = scope_->Find(ident->Name(), ResolveBindingOptions::BINDINGS);
311 }
312 }
313
314 if (res.level != 0) {
315 ASSERT(res.variable);
316 if (!res.variable->Declaration()->IsDeclare() && !ident->Parent()->IsTSTypeReference() &&
317 !ident->Parent()->IsTSTypeQuery()) {
318 util::Concurrent::ProcessConcurrent(Program()->GetLineIndex(), ident, res, program_);
319 res.variable->SetLexical(res.scope, program_->PatchFixHelper());
320 }
321 }
322
323 if (res.variable == nullptr) {
324 return;
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
356 ASSERT(program_->PatchFixHelper()->IsColdFix() || program_->PatchFixHelper()->IsHotReload());
357 }
358 }
359
BuildFunction(FunctionScope * funcScope,util::StringView name,const ir::ScriptFunction * func)360 void Binder::BuildFunction(FunctionScope *funcScope, util::StringView name, const ir::ScriptFunction *func)
361 {
362 if (funcScope->InFunctionScopes()) {
363 return;
364 }
365 functionScopes_.push_back(funcScope);
366 funcScope->SetInFunctionScopes();
367
368 bool funcNameWithoutDot = (name.Find(".") == std::string::npos);
369 bool funcNameWithoutBackslash = (name.Find("\\") == std::string::npos);
370 if (name != ANONYMOUS_FUNC_NAME && funcNameWithoutDot && funcNameWithoutBackslash && !functionNames_.count(name)) {
371 // function with normal name, and hasn't been recorded
372 auto internalName = std::string(program_->FormatedRecordName()) + std::string(name);
373 functionNames_.insert(name);
374 funcScope->BindName(name, util::UString(internalName, Allocator()).View());
375 return;
376 }
377
378 std::stringstream ss;
379 ss << std::string(program_->FormatedRecordName());
380
381 ASSERT(func != nullptr);
382
383 // For anonymous, special-name and duplicate function, get its source and name, make hash code,
384 // and make #hash_duplicateHashTime#name as its name;
385 auto funcContentNameStr = func->SourceCode(this).Mutf8() + name.Mutf8();
386 ss << ANONYMOUS_SPECIAL_DUPLICATE_FUNCTION_SPECIFIER << util::Helpers::GetHashString(funcContentNameStr);
387
388 auto res = functionHashNames_.find(funcContentNameStr);
389 if (res != functionHashNames_.end()) {
390 ss << "_" << res->second++;
391 } else {
392 functionHashNames_.insert({funcContentNameStr, 1});
393 }
394 ss << ANONYMOUS_SPECIAL_DUPLICATE_FUNCTION_SPECIFIER;
395
396 if (name == ANONYMOUS_FUNC_NAME) {
397 anonymousFunctionNames_[func] = util::UString(ss.str(), Allocator()).View();
398 }
399 if (funcNameWithoutDot && funcNameWithoutBackslash) {
400 ss << name;
401 }
402 std::string internalNameStr = ss.str();
403 StoreAndCheckSpecialFunctionName(internalNameStr, program_->RecordName().Mutf8());
404 funcScope->BindName(name, util::UString(internalNameStr, Allocator()).View());
405 }
406
BuildScriptFunction(Scope * outerScope,const ir::ScriptFunction * scriptFunc)407 void Binder::BuildScriptFunction(Scope *outerScope, const ir::ScriptFunction *scriptFunc)
408 {
409 if (bindingFlags_ & ResolveBindingFlags::TS_BEFORE_TRANSFORM) {
410 return;
411 }
412
413 if (scriptFunc->IsArrow()) {
414 VariableScope *outerVarScope = outerScope->EnclosingVariableScope();
415 outerVarScope->AddFlag(VariableScopeFlags::INNER_ARROW);
416 }
417
418 ASSERT(scope_->IsFunctionScope() || scope_->IsTSModuleScope() || scope_->IsTSEnumScope());
419 BuildFunction(scope_->AsFunctionVariableScope(), util::Helpers::FunctionName(Allocator(), scriptFunc), scriptFunc);
420 }
421
BuildVarDeclaratorId(const ir::AstNode * parent,ir::AstNode * childNode)422 void Binder::BuildVarDeclaratorId(const ir::AstNode *parent, ir::AstNode *childNode)
423 {
424 childNode->SetParent(parent);
425
426 switch (childNode->Type()) {
427 case ir::AstNodeType::IDENTIFIER: {
428 auto *ident = childNode->AsIdentifier();
429 const auto &name = ident->Name();
430 if (name.Is(FUNCTION_ARGUMENTS)) {
431 CheckMandatoryArguments(ident);
432 }
433
434 if (util::Helpers::IsGlobalIdentifier(name)) {
435 break;
436 }
437
438 auto *variable = scope_->FindLocal(name, ResolveBindingOptions::BINDINGS);
439
440 if (Program()->Extension() == ScriptExtension::TS) {
441 ident->SetVariable(variable);
442 BuildTSSignatureDeclarationBaseParamsWithParent(ident, ident->TypeAnnotation());
443 }
444
445 variable->AddFlag(VariableFlags::INITIALIZED);
446 break;
447 }
448 case ir::AstNodeType::OBJECT_PATTERN: {
449 auto *objPattern = childNode->AsObjectPattern();
450
451 for (auto *prop : objPattern->Properties()) {
452 BuildVarDeclaratorId(childNode, prop);
453 }
454
455 BuildTSSignatureDeclarationBaseParamsWithParent(objPattern, objPattern->TypeAnnotation());
456 break;
457 }
458 case ir::AstNodeType::ARRAY_PATTERN: {
459 auto *arrayPattern = childNode->AsArrayPattern();
460
461 for (auto *element : childNode->AsArrayPattern()->Elements()) {
462 BuildVarDeclaratorId(childNode, element);
463 }
464
465 BuildTSSignatureDeclarationBaseParamsWithParent(arrayPattern, arrayPattern->TypeAnnotation());
466 break;
467 }
468 case ir::AstNodeType::ASSIGNMENT_PATTERN: {
469 ResolveReference(childNode, childNode->AsAssignmentPattern()->Right());
470 BuildVarDeclaratorId(childNode, childNode->AsAssignmentPattern()->Left());
471 break;
472 }
473 case ir::AstNodeType::PROPERTY: {
474 ResolveReference(childNode, childNode->AsProperty()->Key());
475 BuildVarDeclaratorId(childNode, childNode->AsProperty()->Value());
476 break;
477 }
478 case ir::AstNodeType::REST_ELEMENT: {
479 BuildVarDeclaratorId(childNode, childNode->AsRestElement()->Argument());
480 break;
481 }
482 default:
483 break;
484 }
485 }
486
BuildTSSignatureDeclarationBaseParamsWithParent(const ir::AstNode * parent,ir::AstNode * typeNode)487 void Binder::BuildTSSignatureDeclarationBaseParamsWithParent(const ir::AstNode *parent, ir::AstNode *typeNode)
488 {
489 if (!typeNode) {
490 return;
491 }
492 typeNode->SetParent(parent);
493 BuildTSSignatureDeclarationBaseParams(typeNode);
494 }
495
BuildTSSignatureDeclarationBaseParams(const ir::AstNode * typeNode)496 void Binder::BuildTSSignatureDeclarationBaseParams(const ir::AstNode *typeNode)
497 {
498 ASSERT(typeNode != nullptr);
499
500 Scope *scope = nullptr;
501
502 switch (typeNode->Type()) {
503 case ir::AstNodeType::TS_FUNCTION_TYPE: {
504 scope = typeNode->AsTSFunctionType()->Scope();
505 break;
506 }
507 case ir::AstNodeType::TS_CONSTRUCTOR_TYPE: {
508 scope = typeNode->AsTSConstructorType()->Scope();
509 break;
510 }
511 case ir::AstNodeType::TS_SIGNATURE_DECLARATION: {
512 scope = typeNode->AsTSSignatureDeclaration()->Scope();
513 break;
514 }
515 case ir::AstNodeType::TS_METHOD_SIGNATURE: {
516 scope = typeNode->AsTSMethodSignature()->Scope();
517 break;
518 }
519 default: {
520 ResolveReferences(typeNode);
521 return;
522 }
523 }
524
525 ASSERT(scope && scope->IsFunctionParamScope());
526
527 auto scopeCtx = LexicalScope<FunctionParamScope>::Enter(this, scope->AsFunctionParamScope());
528 ResolveReferences(typeNode);
529 }
530
BuildVarDeclarator(ir::VariableDeclarator * varDecl)531 void Binder::BuildVarDeclarator(ir::VariableDeclarator *varDecl)
532 {
533 if (varDecl->Parent()->AsVariableDeclaration()->Kind() == ir::VariableDeclaration::VariableDeclarationKind::VAR) {
534 ResolveReferences(varDecl);
535 return;
536 }
537
538 if (varDecl->Init()) {
539 ResolveReference(varDecl, varDecl->Init());
540 }
541
542 BuildVarDeclaratorId(varDecl, varDecl->Id());
543 }
544
BuildClassDefinition(ir::ClassDefinition * classDef)545 void Binder::BuildClassDefinition(ir::ClassDefinition *classDef)
546 {
547 if (classDef->Parent()->IsClassDeclaration()) {
548 util::StringView className = classDef->GetName();
549 ASSERT(!className.Empty());
550 ScopeFindResult res = scope_->Find(className);
551
552 ASSERT(res.variable && (res.variable->Declaration()->IsClassDecl() ||
553 (res.variable->Declaration()->IsFunctionDecl() &&
554 res.variable->Declaration()->AsFunctionDecl()->GetDeclClass() != nullptr)));
555 res.variable->AddFlag(VariableFlags::INITIALIZED);
556 }
557
558 auto scopeCtx = LexicalScope<ClassScope>::Enter(this, classDef->Scope());
559
560 if (classDef->TypeParams()) {
561 ResolveReference(classDef, classDef->TypeParams());
562 }
563
564 if (classDef->Super()) {
565 ResolveReference(classDef, classDef->Super());
566 }
567
568 if (classDef->SuperTypeParams()) {
569 ResolveReference(classDef, classDef->SuperTypeParams());
570 }
571
572 for (auto *iter : classDef->Implements()) {
573 ResolveReference(classDef, iter);
574 }
575
576 // new class features in ecma2022 are only supported for api11 and above
577 if (Program()->TargetApiVersion() > 10 && !(bindingFlags_ & ResolveBindingFlags::TS_BEFORE_TRANSFORM)) {
578 classDef->BuildClassEnvironment(program_->UseDefineSemantic());
579 }
580
581 if (classDef->Ident()) {
582 ScopeFindResult res = scope_->Find(classDef->Ident()->Name());
583
584 ASSERT(res.variable && res.variable->Declaration()->IsConstDecl());
585 res.variable->AddFlag(VariableFlags::INITIALIZED);
586
587 classDef->Ident()->SetParent(classDef);
588 }
589
590 ResolveReference(classDef, classDef->Ctor());
591
592 if (classDef->NeedStaticInitializer()) {
593 ResolveReference(classDef, classDef->StaticInitializer());
594 }
595
596 if (classDef->NeedInstanceInitializer()) {
597 ResolveReference(classDef, classDef->InstanceInitializer());
598 }
599
600 for (auto *stmt : classDef->Body()) {
601 ResolveReference(classDef, stmt);
602 }
603
604 for (auto *iter : classDef->IndexSignatures()) {
605 ResolveReference(classDef, iter);
606 }
607 }
608
BuildForUpdateLoop(ir::ForUpdateStatement * forUpdateStmt)609 void Binder::BuildForUpdateLoop(ir::ForUpdateStatement *forUpdateStmt)
610 {
611 auto *loopScope = forUpdateStmt->Scope();
612
613 auto loopCtx = LexicalScope<LoopScope>::Enter(this, loopScope);
614
615 if (forUpdateStmt->Init()) {
616 ResolveReference(forUpdateStmt, forUpdateStmt->Init());
617 }
618
619 if (forUpdateStmt->Update()) {
620 ResolveReference(forUpdateStmt, forUpdateStmt->Update());
621 }
622
623 if (forUpdateStmt->Test()) {
624 ResolveReference(forUpdateStmt, forUpdateStmt->Test());
625 }
626
627 ResolveReference(forUpdateStmt, forUpdateStmt->Body());
628
629 loopCtx.GetScope()->InitVariable();
630 }
631
BuildForInOfLoop(const ir::Statement * parent,binder::LoopScope * loopScope,ir::AstNode * left,ir::Expression * right,ir::Statement * body)632 void Binder::BuildForInOfLoop(const ir::Statement *parent, binder::LoopScope *loopScope, ir::AstNode *left,
633 ir::Expression *right, ir::Statement *body)
634 {
635 auto loopCtx = LexicalScope<LoopScope>::Enter(this, loopScope);
636
637 ResolveReference(parent, right);
638 ResolveReference(parent, left);
639
640 ResolveReference(parent, body);
641 loopCtx.GetScope()->InitVariable();
642 }
643
BuildCatchClause(ir::CatchClause * catchClauseStmt)644 void Binder::BuildCatchClause(ir::CatchClause *catchClauseStmt)
645 {
646 if (catchClauseStmt->Param()) {
647 auto paramScopeCtx = LexicalScope<CatchParamScope>::Enter(this, catchClauseStmt->Scope()->ParamScope());
648 ResolveReference(catchClauseStmt, catchClauseStmt->Param());
649 }
650
651 auto scopeCtx = LexicalScope<CatchScope>::Enter(this, catchClauseStmt->Scope());
652 ResolveReference(catchClauseStmt, catchClauseStmt->Body());
653 }
654
ResolveReference(const ir::AstNode * parent,ir::AstNode * childNode)655 void Binder::ResolveReference(const ir::AstNode *parent, ir::AstNode *childNode)
656 {
657 childNode->SetParent(parent);
658
659 ClassTdz classTdz(parent, childNode, scope_);
660
661 switch (childNode->Type()) {
662 case ir::AstNodeType::IDENTIFIER: {
663 auto *ident = childNode->AsIdentifier();
664
665 if (ident->Name().Is(FUNCTION_ARGUMENTS)) {
666 CheckMandatoryArguments(ident);
667 }
668
669 if (ident->IsReference()) {
670 LookupIdentReference(ident);
671 }
672
673 ResolveReferences(childNode);
674 break;
675 }
676 case ir::AstNodeType::PRIVATE_IDENTIFIER: {
677 if (Program()->Extension() == ScriptExtension::JS) {
678 CheckPrivateDeclaration(childNode->AsPrivateIdentifier());
679 } else if (Program()->Extension() == ScriptExtension::TS &&
680 bindingFlags_ == ResolveBindingFlags::TS_AFTER_TRANSFORM) {
681 CheckPrivateDeclaration(childNode->AsPrivateIdentifier());
682 }
683 break;
684 }
685 case ir::AstNodeType::SUPER_EXPRESSION: {
686 VariableScope *varScope = scope_->EnclosingVariableScope();
687 varScope->AddFlag(VariableScopeFlags::USE_SUPER);
688
689 ResolveReferences(childNode);
690 break;
691 }
692 case ir::AstNodeType::SCRIPT_FUNCTION: {
693 auto *scriptFunc = childNode->AsScriptFunction();
694 util::Helpers::ScanDirectives(const_cast<ir::ScriptFunction *>(scriptFunc),
695 Program()->GetLineIndex());
696 auto *funcScope = scriptFunc->Scope();
697
698 auto *outerScope = scope_;
699
700 if (scriptFunc->Id() != nullptr) {
701 scriptFunc->Id()->SetParent(scriptFunc);
702 }
703
704 {
705 auto paramScopeCtx = LexicalScope<FunctionParamScope>::Enter(this, funcScope->ParamScope());
706
707 if (Program()->Extension() == ScriptExtension::TS) {
708 if (scriptFunc->TypeParams() != nullptr) {
709 ResolveReference(scriptFunc, scriptFunc->TypeParams());
710 }
711 if (scriptFunc->ThisParams() != nullptr) {
712 ResolveReference(scriptFunc, scriptFunc->ThisParams());
713 }
714 }
715
716 for (auto *param : scriptFunc->Params()) {
717 ResolveReference(scriptFunc, param);
718 }
719 }
720
721 if (Program()->Extension() == ScriptExtension::TS) {
722 if (scriptFunc->ReturnTypeAnnotation()) {
723 ResolveReference(scriptFunc, scriptFunc->ReturnTypeAnnotation());
724 }
725
726 if (scriptFunc->IsOverload() || scriptFunc->Declare()) {
727 break;
728 }
729 }
730
731 auto scopeCtx = LexicalScope<FunctionScope>::Enter(this, funcScope);
732
733 BuildScriptFunction(outerScope, scriptFunc);
734
735 ResolveReference(scriptFunc, scriptFunc->Body());
736 break;
737 }
738 case ir::AstNodeType::VARIABLE_DECLARATOR: {
739 BuildVarDeclarator(childNode->AsVariableDeclarator());
740
741 break;
742 }
743 case ir::AstNodeType::CLASS_DEFINITION: {
744 BuildClassDefinition(childNode->AsClassDefinition());
745
746 break;
747 }
748 case ir::AstNodeType::CLASS_PROPERTY: {
749 /* for ts tranformer cases, all class properties are implemented by transformer in api10 and
750 * only public instance class properties are implemented by transformer in api11*/
751 auto *prop = childNode->AsClassProperty();
752 if (Program()->Extension() == ScriptExtension::TS && (Program()->TargetApiVersion() < 11 ||
753 (!prop->IsStatic() && !prop->IsPrivate()))) {
754 const ir::ScriptFunction *ctor = util::Helpers::GetContainingConstructor(prop);
755 auto scopeCtx = LexicalScope<FunctionScope>::Enter(this, ctor->Scope());
756 ResolveReferences(childNode);
757 break;
758 }
759
760 ResolveReference(prop, prop->Key());
761 if (prop->Value() != nullptr) {
762 ASSERT(parent->IsClassDefinition());
763 const auto *classDef = parent->AsClassDefinition();
764 const ir::MethodDefinition *method = prop->IsStatic() ? classDef->StaticInitializer() :
765 classDef->InstanceInitializer();
766 auto scopeCtx = LexicalScope<FunctionScope>::Enter(this, method->Function()->Scope());
767 ResolveReference(prop, prop->Value());
768 }
769 break;
770 }
771 case ir::AstNodeType::BLOCK_STATEMENT: {
772 auto scope = childNode->AsBlockStatement()->Scope();
773 auto scopeCtx = scope != nullptr ?
774 LexicalScope<Scope>::Enter(this, scope) :
775 LexicalScope<Scope>::Enter(this, GetScope());
776
777 ResolveReferences(childNode);
778 break;
779 }
780 case ir::AstNodeType::SWITCH_STATEMENT: {
781 auto *switchStatement = childNode->AsSwitchStatement();
782 ResolveReference(switchStatement, switchStatement->Discriminant());
783
784 auto scopeCtx = LexicalScope<LocalScope>::Enter(this, childNode->AsSwitchStatement()->Scope());
785 for (auto *it : switchStatement->Cases()) {
786 ResolveReference(switchStatement, it);
787 }
788 break;
789 }
790 case ir::AstNodeType::DO_WHILE_STATEMENT: {
791 auto *doWhileStatement = childNode->AsDoWhileStatement();
792
793 {
794 auto loopScopeCtx = LexicalScope<LoopScope>::Enter(this, doWhileStatement->Scope());
795 ResolveReference(doWhileStatement, doWhileStatement->Body());
796 loopScopeCtx.GetScope()->InitVariable();
797 }
798
799 ResolveReference(doWhileStatement, doWhileStatement->Test());
800 break;
801 }
802 case ir::AstNodeType::WHILE_STATEMENT: {
803 auto *whileStatement = childNode->AsWhileStatement();
804 ResolveReference(whileStatement, whileStatement->Test());
805
806 auto loopScopeCtx = LexicalScope<LoopScope>::Enter(this, whileStatement->Scope());
807 ResolveReference(whileStatement, whileStatement->Body());
808 loopScopeCtx.GetScope()->InitVariable();
809 break;
810 }
811 case ir::AstNodeType::FOR_UPDATE_STATEMENT: {
812 BuildForUpdateLoop(childNode->AsForUpdateStatement());
813 break;
814 }
815 case ir::AstNodeType::FOR_IN_STATEMENT: {
816 auto *forInStmt = childNode->AsForInStatement();
817 BuildForInOfLoop(forInStmt, forInStmt->Scope(), forInStmt->Left(), forInStmt->Right(), forInStmt->Body());
818
819 break;
820 }
821 case ir::AstNodeType::FOR_OF_STATEMENT: {
822 auto *forOfStmt = childNode->AsForOfStatement();
823 BuildForInOfLoop(forOfStmt, forOfStmt->Scope(), forOfStmt->Left(), forOfStmt->Right(), forOfStmt->Body());
824 break;
825 }
826 case ir::AstNodeType::CATCH_CLAUSE: {
827 BuildCatchClause(childNode->AsCatchClause());
828 break;
829 }
830 case ir::AstNodeType::EXPORT_NAMED_DECLARATION: {
831 ValidateExportDecl(childNode->AsExportNamedDeclaration());
832
833 ResolveReferences(childNode);
834 break;
835 }
836 // TypeScript specific part
837 case ir::AstNodeType::TS_FUNCTION_TYPE:
838 case ir::AstNodeType::TS_CONSTRUCTOR_TYPE:
839 case ir::AstNodeType::TS_METHOD_SIGNATURE:
840 case ir::AstNodeType::TS_SIGNATURE_DECLARATION: {
841 BuildTSSignatureDeclarationBaseParams(childNode);
842 break;
843 }
844 case ir::AstNodeType::TS_MODULE_DECLARATION: {
845 auto scopeCtx = LexicalScope<Scope>::Enter(this, childNode->AsTSModuleDeclaration()->Scope());
846 ResolveReferences(childNode);
847 break;
848 }
849 case ir::AstNodeType::TS_ENUM_DECLARATION: {
850 auto scopeCtx = LexicalScope<Scope>::Enter(this, childNode->AsTSEnumDeclaration()->Scope());
851 ResolveReferences(childNode);
852 break;
853 }
854 default: {
855 ResolveReferences(childNode);
856 break;
857 }
858 }
859 }
ResolveReferences(const ir::AstNode * parent)860 void Binder::ResolveReferences(const ir::AstNode *parent)
861 {
862 parent->Iterate([this, parent](auto *childNode) { ResolveReference(parent, childNode); });
863 }
864
AddMandatoryParam(const std::string_view & name)865 void Binder::AddMandatoryParam(const std::string_view &name)
866 {
867 ASSERT(scope_->IsFunctionVariableScope());
868
869 auto *decl = Allocator()->New<ParameterDecl>(name);
870 auto *param = Allocator()->New<LocalVariable>(decl, VariableFlags::VAR);
871
872 auto &funcParams = scope_->AsFunctionVariableScope()->ParamScope()->Params();
873 funcParams.insert(funcParams.begin(), param);
874 scope_->AsFunctionVariableScope()->ParamScope()->Bindings().insert({decl->Name(), param});
875 scope_->AsFunctionVariableScope()->Bindings().insert({decl->Name(), param});
876 }
877
AddMandatoryParams()878 void Binder::AddMandatoryParams()
879 {
880 ASSERT(scope_ == topScope_);
881 ASSERT(!functionScopes_.empty());
882 auto iter = functionScopes_.begin();
883 [[maybe_unused]] auto *funcScope = *iter++;
884
885 ASSERT(funcScope->IsGlobalScope() || funcScope->IsModuleScope());
886
887 if (program_->Kind() == parser::ScriptKind::COMMONJS) {
888 AddMandatoryParams(CJS_MAINFUNC_MANDATORY_PARAMS);
889 } else {
890 AddMandatoryParams(FUNCTION_MANDATORY_PARAMS);
891 }
892
893 for (; iter != functionScopes_.end(); iter++) {
894 funcScope = *iter;
895 const auto *scriptFunc = funcScope->Node()->AsScriptFunction();
896
897 auto scopeCtx = LexicalScope<FunctionScope>::Enter(this, funcScope);
898
899 if (!scriptFunc->IsArrow()) {
900 AddMandatoryParams(FUNCTION_MANDATORY_PARAMS);
901 continue;
902 }
903
904 const ir::ScriptFunction *ctor = util::Helpers::GetContainingConstructor(scriptFunc);
905 bool lexicalFunctionObject {};
906
907 if (ctor && util::Helpers::GetClassDefiniton(ctor)->Super() &&
908 funcScope->HasFlag(VariableScopeFlags::USE_SUPER)) {
909 ASSERT(ctor->Scope()->HasFlag(VariableScopeFlags::INNER_ARROW));
910 ctor->Scope()->AddFlag(VariableScopeFlags::SET_LEXICAL_FUNCTION);
911 lexicalFunctionObject = true;
912 AddMandatoryParams(CTOR_ARROW_MANDATORY_PARAMS);
913 } else {
914 AddMandatoryParams(ARROW_MANDATORY_PARAMS);
915 }
916
917 LookupReference(MANDATORY_PARAM_NEW_TARGET);
918 LookupReference(MANDATORY_PARAM_THIS);
919
920 if (funcScope->HasFlag(VariableScopeFlags::USE_ARGS)) {
921 LookupReference(FUNCTION_ARGUMENTS);
922 }
923
924 if (lexicalFunctionObject) {
925 LookupReference(MANDATORY_PARAM_FUNC);
926 }
927 }
928 }
929
AddDeclarationName(const util::StringView & name,DeclType type)930 void Binder::AddDeclarationName(const util::StringView &name, DeclType type)
931 {
932 if (extension_ != ScriptExtension::TS) {
933 return;
934 }
935 variableNames_.insert(name);
936
937 if (type == DeclType::ENUM) {
938 return;
939 }
940 auto *scope = GetScope();
941 while (scope != nullptr) {
942 if (scope->IsTSModuleScope()) {
943 scope->AsTSModuleScope()->AddDeclarationName(name);
944 }
945 if (scope->IsTSEnumScope()) {
946 scope->AsTSEnumScope()->AddDeclarationName(name);
947 }
948 scope = scope->Parent();
949 }
950 }
951
HasVariableName(const util::StringView & name) const952 bool Binder::HasVariableName(const util::StringView &name) const
953 {
954 return variableNames_.find(name) != variableNames_.end();
955 }
956
FindIdentifierTSVariables(const ir::Identifier * identifier,Scope * scope,ScopeFindResult & res)957 std::vector<Variable *> Binder::FindIdentifierTSVariables(const ir::Identifier *identifier, Scope *scope,
958 ScopeFindResult &res)
959 {
960 const auto &name = identifier->Name();
961 std::vector<binder::Variable *> findRes;
962
963 auto currentScope = scope;
964 while (currentScope != nullptr) {
965 // Find ts variables
966 auto fn = [&findRes](Variable *variable) {
967 if (variable != nullptr) {
968 findRes.emplace_back(variable);
969 }
970 };
971
972 fn(currentScope->FindLocalTSVariable<binder::TSBindingType::NAMESPACE>(name));
973 fn(currentScope->FindLocalTSVariable<binder::TSBindingType::ENUMLITERAL>(name));
974 fn(currentScope->FindLocalTSVariable<binder::TSBindingType::IMPORT_EQUALS>(name));
975 if (currentScope->IsTSModuleScope()) {
976 fn(currentScope->AsTSModuleScope()->FindExportTSVariable<binder::TSBindingType::NAMESPACE>(name));
977 fn(currentScope->AsTSModuleScope()->FindExportTSVariable<binder::TSBindingType::ENUMLITERAL>(name));
978 fn(currentScope->AsTSModuleScope()->FindExportTSVariable<binder::TSBindingType::IMPORT_EQUALS>(name));
979 }
980
981 // Find js variable
982 if (currentScope->FindLocal(name, bindingOptions_) != nullptr) {
983 res = scope->Find(name, bindingOptions_);
984 break;
985 }
986
987 if (!findRes.empty()) {
988 break;
989 }
990
991 currentScope = currentScope->Parent();
992 }
993
994 return findRes;
995 }
996
ReplaceConstReferenceWithInitialization(const ir::Identifier * ident,const Decl * decl)997 void Binder::ReplaceConstReferenceWithInitialization(const ir::Identifier *ident, const Decl *decl)
998 {
999 bool isValidAssignmentExpr = ident->Parent()->IsAssignmentExpression() &&
1000 ident->Parent()->AsAssignmentExpression()->Right() == ident;
1001 bool isBinaryExpr = ident->Parent()->IsBinaryExpression();
1002 bool isVariableDecl = ident->Parent()->IsVariableDeclarator() &&
1003 ident->Parent()->AsVariableDeclarator()->Init() == ident;
1004 if (!isValidAssignmentExpr && !isBinaryExpr && !isVariableDecl) {
1005 return;
1006 }
1007
1008 if (decl->Node() == nullptr || decl->Node()->Parent() == nullptr ||
1009 !decl->Node()->Parent()->IsVariableDeclarator()) {
1010 return;
1011 }
1012
1013 const ir::AstNode *initialization = static_cast<const ir::AstNode *>(
1014 decl->Node()->Parent()->AsVariableDeclarator()->Init());
1015 if (initialization == nullptr || !initialization->IsNumberLiteral()) {
1016 return;
1017 }
1018
1019 auto newNode = Allocator()->New<ir::NumberLiteral>(initialization->AsNumberLiteral()->Number());
1020 if (newNode == nullptr) {
1021 throw Error(ErrorType::GENERIC, "Unsuccessful allocation during replacing const reference node");
1022 }
1023 // Make sure the new node get the correct line number
1024 // Column number may be incorrect, but it doesn't matter in release mode
1025 newNode->SetRange(ident->Range());
1026
1027 auto *parentNode = const_cast<panda::es2panda::ir::AstNode *>(ident->Parent());
1028 // update the reference node with initialization node
1029 parentNode->UpdateSelf([=](auto *childNode) {
1030 if (childNode == ident) {
1031 return static_cast<ir::AstNode *>(newNode);
1032 }
1033 return childNode;
1034 }, this);
1035 }
1036
CheckPrivateDeclaration(const ir::PrivateIdentifier * privateIdent)1037 void Binder::CheckPrivateDeclaration(const ir::PrivateIdentifier *privateIdent)
1038 {
1039 auto name = privateIdent->Name();
1040 auto scope = scope_;
1041 while (scope != nullptr) {
1042 if (scope->Type() == ScopeType::CLASS) {
1043 const auto *classScope = scope->AsClassScope();
1044 if (classScope->HasPrivateName(name)) {
1045 return;
1046 }
1047 }
1048 scope = scope->Parent();
1049 }
1050
1051 auto pos = privateIdent->Start();
1052 lexer::LineIndex index(program_->SourceCode());
1053 lexer::SourceLocation loc = index.GetLocation(pos);
1054
1055 throw Error{ErrorType::SYNTAX, "Use private property before declaration", loc.line, loc.col};
1056 }
1057
ClassTdz(const ir::AstNode * parent,const ir::AstNode * childNode,Scope * scope)1058 ClassTdz::ClassTdz(const ir::AstNode *parent, const ir::AstNode *childNode, Scope *scope)
1059 {
1060 /* In ES2022, class element name's evaluation is before class's initialization.
1061 * So a computed property name can not access class object which leads to a reference error.
1062 * For example:
1063 * class A {
1064 * [A]
1065 * }
1066 */
1067 bool isClassTdz = (parent->IsClassProperty() && childNode == parent->AsClassProperty()->Key()) ||
1068 (parent->IsMethodDefinition() && childNode == parent->AsMethodDefinition()->Key());
1069 if (!isClassTdz) {
1070 return;
1071 }
1072
1073 ASSERT(parent->Parent()->IsClassDefinition());
1074 auto classDef = parent->Parent()->AsClassDefinition();
1075 if (!classDef->Ident()) {
1076 return;
1077 }
1078
1079 ScopeFindResult res = scope->Find(classDef->Ident()->Name());
1080 ASSERT(res.variable && res.variable->Declaration()->IsConstDecl());
1081 variable_ = res.variable;
1082 variable_->RemoveFlag(VariableFlags::INITIALIZED);
1083 }
1084
1085 } // namespace panda::es2panda::binder
1086