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