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