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 "scope.h"
17 
18 #include <binder/declaration.h>
19 #include <util/helpers.h>
20 #include <binder/tsBinding.h>
21 #include <binder/variable.h>
22 #include <binder/variableFlags.h>
23 #include <ir/astNode.h>
24 #include <ir/base/scriptFunction.h>
25 #include <ir/base/classDefinition.h>
26 #include <ir/expressions/identifier.h>
27 #include <ir/expressions/literals/stringLiteral.h>
28 #include <ir/expressions/privateIdentifier.h>
29 #include <ir/module/exportAllDeclaration.h>
30 #include <ir/module/exportNamedDeclaration.h>
31 #include <ir/module/exportSpecifier.h>
32 #include <ir/module/importDeclaration.h>
33 #include <ir/ts/tsModuleDeclaration.h>
34 #include <ir/ts/tsEnumDeclaration.h>
35 #include <macros.h>
36 #include <util/concurrent.h>
37 #include <util/ustring.h>
38 
39 #include <algorithm>
40 #include <sstream>
41 
42 namespace panda::es2panda::binder {
43 
EnclosingVariableScope()44 VariableScope *Scope::EnclosingVariableScope()
45 {
46     Scope *iter = this;
47 
48     while (iter) {
49         if (iter->IsVariableScope()) {
50             return iter->AsVariableScope();
51         }
52 
53         iter = iter->Parent();
54     }
55 
56     return nullptr;
57 }
58 
EnclosingFunctionVariableScope()59 FunctionScope *Scope::EnclosingFunctionVariableScope()
60 {
61     Scope *iter = this;
62     while (iter) {
63         if (iter->IsFunctionVariableScope()) {
64             return iter->AsFunctionVariableScope();
65         }
66 
67         iter = iter->Parent();
68     }
69 
70     return nullptr;
71 }
72 
FindLocal(const util::StringView &name, ResolveBindingOptions options) const73 Variable *Scope::FindLocal(const util::StringView &name, ResolveBindingOptions options) const
74 {
75     if (options & ResolveBindingOptions::INTERFACES) {
76         const std::string &interfaceName = binder::TSBinding::ToTSBinding(name);
77 
78         auto res = bindings_.find(util::StringView{interfaceName});
79         if (res != bindings_.end()) {
80             return res->second;
81         }
82 
83         if (!(options & ResolveBindingOptions::BINDINGS)) {
84             return nullptr;
85         }
86     }
87 
88     auto res = bindings_.find(name);
89     if (res == bindings_.end()) {
90         return nullptr;
91     }
92 
93     return res->second;
94 }
95 
CalculateLevelInCorrespondingFunctionScope(const FunctionParamScope *scope, uint32_t &lexLevel, uint32_t &sendableLevel) const96 void Scope::CalculateLevelInCorrespondingFunctionScope(const FunctionParamScope *scope, uint32_t &lexLevel,
97                                                        uint32_t &sendableLevel) const
98 {
99     auto *funcVariableScope = scope->GetFunctionScope();
100     // we may only have function param scope without function scope in TS here
101     if (funcVariableScope == nullptr) {
102         return;
103     }
104 
105     if (funcVariableScope->NeedLexEnv()) {
106         lexLevel++;
107     }
108 
109     if (funcVariableScope->NeedSendableEnv()) {
110         sendableLevel++;
111     }
112 }
113 
Find(const util::StringView &name, ResolveBindingOptions options) const114 ScopeFindResult Scope::Find(const util::StringView &name, ResolveBindingOptions options) const
115 {
116     uint32_t level = 0;
117     uint32_t lexLevel = 0;
118     uint32_t sendableLevel = 0;
119     const auto *iter = this;
120     ir::ScriptFunction *concurrentFunc = nullptr;
121     // If the first scope is functionParamScope, it means its corresponding functionScope is not
122     // iterated. so by default we set prevScopeNotFunctionScope as true so under such case,
123     // functionScopeNotIterated will be true.
124     bool prevScopeNotFunctionScope = true;
125     bool lexical = false;
126 
127     while (iter != nullptr) {
128         bool functionScopeNotIterated = iter->IsFunctionParamScope() && prevScopeNotFunctionScope;
129         Variable *v = iter->FindLocal(name, options);
130 
131         if (v != nullptr) {
132             return {name, const_cast<Scope *>(iter), level, lexLevel, sendableLevel, v, concurrentFunc};
133         }
134 
135         if (iter->IsFunctionVariableScope() && !lexical) {
136             lexical = true;
137         }
138 
139         if (iter->IsFunctionScope() && !concurrentFunc) {
140             if (iter->Node()->AsScriptFunction()->IsConcurrent()) {
141                 concurrentFunc = const_cast<ir::ScriptFunction *>(iter->Node()->AsScriptFunction());
142             }
143         }
144 
145         if (iter->IsVariableScope()) {
146             if (lexical) {
147                 level++;
148             }
149 
150             if (iter->AsVariableScope()->NeedLexEnv()) {
151                 lexLevel++;
152             }
153 
154             if (iter->AsVariableScope()->NeedSendableEnv()) {
155                 sendableLevel++;
156             }
157         } else if (functionScopeNotIterated) {
158             level++;
159             CalculateLevelInCorrespondingFunctionScope(iter->AsFunctionParamScope(), lexLevel, sendableLevel);
160         }
161 
162         prevScopeNotFunctionScope = !iter->IsFunctionVariableScope();
163         iter = iter->Parent();
164     }
165 
166     return {name, nullptr, 0, 0, 0, nullptr, concurrentFunc};
167 }
168 
Find(const ir::Expression *expr, bool onlyLevel) const169 std::pair<uint32_t, uint32_t> Scope::Find(const ir::Expression *expr, bool onlyLevel) const
170 {
171     uint32_t lexLevel = 0;
172     const auto *iter = this;
173 
174     while (iter != nullptr) {
175         if (iter->Type() == ScopeType::CLASS) {
176             if (onlyLevel) {
177                 return {lexLevel, 0};
178             }
179             return {lexLevel, iter->AsClassScope()->GetSlot(expr)};
180         }
181 
182         if (iter->IsVariableScope()) {
183             if (iter->AsVariableScope()->NeedLexEnv()) {
184                 lexLevel++;
185             }
186         }
187         iter = iter->Parent();
188     }
189 
190     UNREACHABLE();
191 }
192 
IsVariableScope() const193 bool ClassScope::IsVariableScope() const
194 {
195     // sendable class does not need a lexical env, handle it's scope as a non-variable scope
196     return !node_->AsClassDefinition()->IsSendable();
197 }
198 
GetPrivateProperty(const util::StringView &name, bool isSetter) const199 Result ClassScope::GetPrivateProperty(const util::StringView &name, bool isSetter) const
200 {
201     if (name.Is("#method")) {
202         return {instanceMethodValidation_, false, false, false, false, 0};
203     }
204 
205     uint32_t slot{0};
206     bool setter{false};
207     bool getter{false};
208 
209     if (privateNames_.find(name) != privateNames_.end()) {
210         slot = privateNames_.find(name)->second;
211     } else {
212         auto accessor = isSetter ? privateSetters_ : privateGetters_;
213         auto unexpectedAccessor = isSetter ? privateGetters_ : privateSetters_;
214 
215         if (accessor.find(name) != accessor.end()) {
216             setter = isSetter;
217             getter = !setter;
218             slot = accessor.find(name)->second;
219         } else {
220             getter = isSetter;
221             setter = !getter;
222             slot = unexpectedAccessor.find(name)->second;
223         }
224     }
225 
226     uint32_t validateMethodSlot{0};
227 
228     if (IsMethod(slot)) {
229         validateMethodSlot = IsStaticMethod(slot) ? staticMethodValidation_ : instanceMethodValidation_;
230     }
231 
232     return {slot, IsMethod(slot), IsStaticMethod(slot), getter, setter, validateMethodSlot};
233 }
234 
AddPrivateName(std::vector<const ir::Statement *> privateProperties, uint32_t privateFieldCnt, uint32_t instancePrivateMethodCnt, uint32_t staticPrivateMethodCnt)235 void ClassScope::AddPrivateName(std::vector<const ir::Statement *> privateProperties, uint32_t privateFieldCnt,
236                                 uint32_t instancePrivateMethodCnt, uint32_t staticPrivateMethodCnt)
237 {
238     privateFieldCnt_ = privateFieldCnt;
239     instancePrivateMethodStartSlot_ = slotIndex_ + privateFieldCnt_;
240     staticPrivateMethodStartSlot_ = instancePrivateMethodStartSlot_ + instancePrivateMethodCnt;
241     uint32_t instancePrivateMethodSlot = instancePrivateMethodStartSlot_;
242     uint32_t staticPrivateMethodSlot = staticPrivateMethodStartSlot_;
243     for (const auto *stmt : privateProperties) {
244         if (stmt->IsClassProperty()) {
245             privateNames_[stmt->AsClassProperty()->Key()->AsPrivateIdentifier()->Name()] = slotIndex_++;
246             continue;
247         }
248         ASSERT(stmt->IsMethodDefinition());
249         auto *methodDef = stmt->AsMethodDefinition();
250         uint32_t *start = methodDef->IsStatic() ? &staticPrivateMethodSlot : &instancePrivateMethodSlot;
251         auto name = methodDef->Key()->AsPrivateIdentifier()->Name();
252         switch (methodDef->Kind()) {
253             case ir::MethodDefinitionKind::GET: {
254                 privateGetters_[name] =  (*start)++;
255                 continue;
256             }
257             case ir::MethodDefinitionKind::SET: {
258                 privateSetters_[name] =  (*start)++;
259                 continue;
260             }
261             default: {
262                 privateNames_[name]=  (*start)++;
263                 continue;
264             }
265         }
266     }
267     slotIndex_ = staticPrivateMethodSlot;
268     privateMethodEndSlot_ = slotIndex_;
269     if (instancePrivateMethodCnt != 0) {
270         instanceMethodValidation_ = slotIndex_++;
271     }
272 
273     if (staticPrivateMethodCnt != 0) {
274         staticMethodValidation_ = slotIndex_++;
275     }
276 }
277 
GetSelfScopeName()278 util::StringView ClassScope::GetSelfScopeName()
279 {
280     if (hasSelfScopeNameSet_) {
281         return selfScopeName_;
282     }
283 
284     std::stringstream scopeName;
285 
286     if (node_ && node_->IsClassDefinition() && node_->AsClassDefinition()->Ident()) {
287         util::StringView selfName = node_->AsClassDefinition()->Ident()->Name();
288         scopeName << selfName;
289         return util::UString(scopeName.str(), allocator_).View();
290     }
291     // To get the name for anonymous class
292     if (node_ && node_->Parent() && node_->Parent()->Parent()) {
293         scopeName << util::Helpers::GetName(allocator_, node_->Parent()->Parent());
294         return util::UString(scopeName.str(), allocator_).View();
295     }
296 
297     return util::UString(scopeName.str(), allocator_).View();
298 }
299 
GetScopeTag()300 util::StringView ClassScope::GetScopeTag()
301 {
302     return util::UString(util::Helpers::CLASS_SCOPE_TAG.data(), allocator_).View();
303 }
304 
FindPrivateName(const util::StringView &name, bool isSetter) const305 PrivateNameFindResult Scope::FindPrivateName(const util::StringView &name, bool isSetter) const
306 {
307     uint32_t lexLevel = 0;
308     const auto *iter = this;
309 
310     while (iter != nullptr) {
311         if (iter->Type() == ScopeType::CLASS) {
312             const auto *classScope = iter->AsClassScope();
313             if (name.Is("#method") || classScope->HasPrivateName(name)) {
314                 return {lexLevel, classScope->GetPrivateProperty(name, isSetter)};
315             }
316         }
317 
318         if (iter->IsVariableScope()) {
319             if (iter->AsVariableScope()->NeedLexEnv()) {
320                 lexLevel++;
321             }
322         }
323         iter = iter->Parent();
324     }
325 
326     UNREACHABLE();
327 }
328 
FindDecl(const util::StringView &name) const329 Decl *Scope::FindDecl(const util::StringView &name) const
330 {
331     for (auto *it : decls_) {
332         if (it->Name() == name) {
333             return it;
334         }
335     }
336 
337     return nullptr;
338 }
339 
HasVarDecl(const util::StringView &name) const340 bool Scope::HasVarDecl(const util::StringView &name) const
341 {
342     for (auto *it : decls_) {
343         if (it->Name() == name && it->IsVarDecl()) {
344             return true;
345         }
346     }
347 
348     return false;
349 }
350 
IterateShadowedVariables(const util::StringView &name, const VariableVisitior &visitor)351 std::tuple<Scope *, bool> Scope::IterateShadowedVariables(const util::StringView &name, const VariableVisitior &visitor)
352 {
353     auto *iter = this;
354 
355     while (true) {
356         auto *v = iter->FindLocal(name);
357 
358         if (v && visitor(v)) {
359             return {iter, true};
360         }
361 
362         if (iter->IsFunctionVariableScope()) {
363             break;
364         }
365 
366         iter = iter->Parent();
367     }
368 
369     return {iter, false};
370 }
371 
SetFullScopeNames()372 void Scope::SetFullScopeNames()
373 {
374     if (hasFullScopeNameSet_) {
375         return;
376     }
377     hasFullScopeNameSet_ = true;
378     if (!hasSelfScopeNameSet_) {
379         SetSelfScopeName(GetSelfScopeName());
380     }
381 
382     std::stringstream selfScopeStream;
383     OptimizeSelfScopeName(selfScopeStream);
384     std::stringstream fullScopeName;
385     Scope *parent = GetParentWithScopeName();
386     if (parent) {
387         fullScopeName << parent->GetFullScopeName() <<
388                          GetScopeTag() <<
389                          selfScopeStream.str();
390         if (scopeDuplicateIndex_ > 0) {
391             fullScopeName << util::Helpers::DUPLICATED_SEPERATOR <<
392                              std::hex << scopeDuplicateIndex_;
393         }
394     }
395 
396     fullScopeName_ = util::UString(fullScopeName.str(), allocator_).View();
397 }
398 
OptimizeSelfScopeName(std::stringstream &selfScopeStream)399 void Scope::OptimizeSelfScopeName(std::stringstream &selfScopeStream)
400 {
401     bool useIndex = false;
402     auto it = topScope_->scopeNames_.find(selfScopeName_);
403     if (it == topScope_->scopeNames_.end()) {
404         std::stringstream indexScopeName;
405         indexScopeName << util::Helpers::INDEX_NAME_SPICIFIER << std::hex << topScope_->scopeNames_.size();
406         if (selfScopeName_.Length() > indexScopeName.str().length()) {
407             topScope_->scopeNames_.insert(
408                 {selfScopeName_, (int32_t)topScope_->scopeNames_.size()}
409             );
410             selfScopeStream << indexScopeName.str();
411             useIndex = true;
412         }
413     } else {
414         selfScopeStream << util::Helpers::INDEX_NAME_SPICIFIER << std::hex << it->second;
415         useIndex = true;
416     }
417 
418     if (!useIndex) {
419         selfScopeStream << selfScopeName_;
420     }
421 }
422 
AddLocal(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, [[maybe_unused]] ScriptExtension extension)423 bool Scope::AddLocal(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
424                      [[maybe_unused]] ScriptExtension extension)
425 {
426     VariableFlags flags = VariableFlags::NONE;
427     switch (newDecl->Type()) {
428         case DeclType::VAR: {
429             auto [scope, shadowed] = IterateShadowedVariables(
430                 newDecl->Name(), [](const Variable *v) { return !v->HasFlag(VariableFlags::VAR); });
431 
432             if (shadowed) {
433                 return false;
434             }
435 
436             VariableFlags varFlags = VariableFlags::HOIST_VAR;
437             if (scope->IsGlobalScope()) {
438                 scope->Bindings().insert({newDecl->Name(), allocator->New<GlobalVariable>(newDecl, varFlags)});
439             } else {
440                 scope->PropagateBinding<LocalVariable>(allocator, newDecl->Name(), newDecl, varFlags);
441             }
442 
443             return true;
444         }
445         case DeclType::ENUM_LITERAL: {
446             return tsBindings_.AddTSVariable<TSBindingType::ENUMLITERAL>(
447                 newDecl->Name(), allocator->New<EnumLiteralVariable>(newDecl, VariableFlags::ENUM_LITERAL));
448         }
449         case DeclType::INTERFACE: {
450             bindings_.insert({newDecl->Name(), allocator->New<LocalVariable>(newDecl, VariableFlags::INTERFACE)});
451             return true;
452         }
453         case DeclType::FUNC: {
454             flags = VariableFlags::HOIST;
455             [[fallthrough]];
456         }
457         default: {
458             if (currentVariable) {
459                 return false;
460             }
461 
462             if (HasVarDecl(newDecl->Name())) {
463                 return false;
464             }
465 
466             bindings_.insert({newDecl->Name(), allocator->New<LocalVariable>(newDecl, flags)});
467             return true;
468         }
469     }
470 }
471 
AddParam(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, VariableFlags flags)472 bool ParamScope::AddParam(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, VariableFlags flags)
473 {
474     CHECK_NOT_NULL(newDecl);
475     ASSERT(newDecl->IsParameterDecl());
476 
477     if (currentVariable) {
478         return false;
479     }
480 
481     auto *param = allocator->New<LocalVariable>(newDecl, flags);
482 
483     params_.push_back(param);
484     bindings_.insert({newDecl->Name(), param});
485     return true;
486 }
487 
AddParamDecl(ArenaAllocator *allocator, const ir::AstNode *param)488 std::tuple<ParameterDecl *, const ir::AstNode *> ParamScope::AddParamDecl(ArenaAllocator *allocator,
489                                                                           const ir::AstNode *param)
490 {
491     const auto [name, pattern] = util::Helpers::ParamName(allocator, param, params_.size());
492 
493     auto *decl = NewDecl<ParameterDecl>(allocator, name);
494     CHECK_NOT_NULL(decl);
495 
496     if (!AddParam(allocator, FindLocal(name), decl, VariableFlags::VAR)) {
497         return {decl, param};
498     }
499 
500     if (!pattern) {
501         decl->BindNode(param);
502         return {decl, nullptr};
503     }
504 
505     std::vector<const ir::Identifier *> bindings = util::Helpers::CollectBindingNames(param);
506 
507     for (const auto *binding : bindings) {
508         auto *varDecl = NewDecl<VarDecl>(allocator, binding->Name());
509         CHECK_NOT_NULL(varDecl);
510         varDecl->BindNode(binding);
511 
512         if (FindLocal(varDecl->Name())) {
513             return {decl, binding};
514         }
515 
516         auto *paramVar = allocator->New<LocalVariable>(varDecl, VariableFlags::VAR);
517         bindings_.insert({varDecl->Name(), paramVar});
518     }
519 
520     return {decl, nullptr};
521 }
522 
BindName(ArenaAllocator *allocator, util::StringView name)523 void FunctionParamScope::BindName(ArenaAllocator *allocator, util::StringView name)
524 {
525     nameVar_ = AddDecl<ConstDecl, LocalVariable>(allocator, name, VariableFlags::INITIALIZED);
526     functionScope_->Bindings().insert({name, nameVar_});
527 }
528 
AddBinding([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] Variable *currentVariable, [[maybe_unused]] Decl *newDecl, [[maybe_unused]] ScriptExtension extension)529 bool FunctionParamScope::AddBinding([[maybe_unused]] ArenaAllocator *allocator,
530                                     [[maybe_unused]] Variable *currentVariable, [[maybe_unused]] Decl *newDecl,
531                                     [[maybe_unused]] ScriptExtension extension)
532 {
533     UNREACHABLE();
534 }
535 
GetFullScopeName()536 const util::StringView &FunctionParamScope::GetFullScopeName()
537 {
538     if (functionScope_) {
539         return functionScope_->GetFullScopeName();
540     }
541 
542     // FunctionParam should have the same name with FunctionScope
543     // Get scope name from parent in case the functionScope_ is nullptr
544     if (parent_) {
545         return parent_->GetFullScopeName();
546     }
547 
548     return fullScopeName_;
549 }
550 
GetDuplicateScopeIndex(const util::StringView &childScopeName)551 uint32_t FunctionParamScope::GetDuplicateScopeIndex(const util::StringView &childScopeName)
552 {
553     if (functionScope_) {
554         return functionScope_->GetDuplicateScopeIndex(childScopeName);
555     }
556 
557     if (parent_) {
558         return parent_->GetDuplicateScopeIndex(childScopeName);
559     }
560 
561     return 0;
562 }
563 
BindNameWithScopeInfo(util::StringView name, util::StringView recordName)564 void FunctionScope::BindNameWithScopeInfo(util::StringView name, util::StringView recordName)
565 {
566     name_ = name;
567     std::stringstream internalName;
568     internalName << recordName << util::Helpers::FUNC_NAME_SEPARATOR;
569 
570     Scope *parent = GetParentWithScopeName();
571     if (parent != nullptr) {
572         internalName << parent->GetFullScopeName();
573     }
574     internalName << GetScopeTag() << util::Helpers::FUNC_NAME_SEPARATOR << GetSelfScopeName();
575     if (scopeDuplicateIndex_ > 0) {
576         internalName << util::Helpers::DUPLICATED_SEPERATOR <<
577                         std::hex << scopeDuplicateIndex_;
578     }
579     internalName_ = util::UString(internalName.str(), allocator_).View();
580 }
581 
AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, [[maybe_unused]] ScriptExtension extension)582 bool FunctionScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
583                                [[maybe_unused]] ScriptExtension extension)
584 {
585     switch (newDecl->Type()) {
586         case DeclType::VAR: {
587             return AddVar<LocalVariable>(allocator, currentVariable, newDecl);
588         }
589         case DeclType::FUNC: {
590             return AddFunction<LocalVariable>(allocator, currentVariable, newDecl, extension);
591         }
592         case DeclType::CLASS: {
593             return AddClass<LocalVariable>(allocator, currentVariable, newDecl);
594         }
595         case DeclType::ENUM_LITERAL: {
596             return AddTSBinding<EnumLiteralVariable>(allocator, newDecl, VariableFlags::ENUM_LITERAL);
597         }
598         case DeclType::NAMESPACE: {
599             return AddTSBinding<NamespaceVariable>(allocator, newDecl, VariableFlags::NAMESPACE);
600         }
601         case DeclType::IMPORT_EQUALS: {
602             return AddTSBinding<ImportEqualsVariable>(allocator, newDecl, VariableFlags::IMPORT_EQUALS);
603         }
604         case DeclType::INTERFACE: {
605             return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::INTERFACE);
606         }
607         default: {
608             return AddLexical<LocalVariable>(allocator, currentVariable, newDecl);
609         }
610     }
611 }
612 
SetSelfScopeName(const util::StringView &ident)613 void FunctionScope::SetSelfScopeName(const util::StringView &ident)
614 {
615     Scope::SetSelfScopeName(ident);
616     paramScope_->selfScopeName_ = selfScopeName_;
617     paramScope_->hasSelfScopeNameSet_ = true;
618     hasSelfScopeNameSet_ = true;
619 }
620 
GetScopeTag()621 util::StringView FunctionScope::GetScopeTag()
622 {
623     if (IsFunctionScope() && (node_->IsScriptFunction() && node_->AsScriptFunction()->IsConstructor())) {
624         return util::UString(util::Helpers::CTOR_TAG.data(), allocator_).View();
625     }
626     if (parent_ && parent_->Parent() && parent_->Parent()->IsClassScope()) {
627         bool hasNodeParent = node_ && node_->Parent() && node_->Parent()->Parent();
628         const ir::AstNode *nodeParent = hasNodeParent ? node_->Parent()->Parent() : nullptr;
629         if (nodeParent && nodeParent->IsMethodDefinition() && nodeParent->AsMethodDefinition()->IsStatic()) {
630             return util::UString(util::Helpers::STATIC_METHOD_TAG.data(), allocator_).View();
631         }
632         return util::UString(util::Helpers::METHOD_TAG.data(), allocator_).View();
633     }
634     return util::UString(util::Helpers::FUNCTION_TAG.data(), allocator_).View();
635 }
636 
GetSelfScopeName()637 util::StringView FunctionScope::GetSelfScopeName()
638 {
639     if (hasSelfScopeNameSet_) {
640         return selfScopeName_;
641     }
642 
643     if (node_ && node_->IsScriptFunction()) {
644         auto selfName = util::Helpers::FunctionName(allocator_, node_->AsScriptFunction());
645         if (!util::Helpers::IsSpecialScopeName(selfName)) {
646             return selfName;
647         }
648     }
649     return util::UString(util::Helpers::STRING_EMPTY.data(), allocator_).View();
650 }
651 
GetSelfScopeName()652 util::StringView TSModuleScope::GetSelfScopeName()
653 {
654     if (hasSelfScopeNameSet_) {
655         return selfScopeName_;
656     }
657     throw Error(ErrorType::GENERIC, "namespace or module name should be set in Binder::ResolveReference()");
658 }
659 
GetScopeTag()660 util::StringView TSModuleScope::GetScopeTag()
661 {
662     return util::UString(util::Helpers::NAMESPACE_TAG.data(), allocator_).View();
663 }
664 
AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, [[maybe_unused]] ScriptExtension extension)665 bool TSEnumScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
666                              [[maybe_unused]] ScriptExtension extension)
667 {
668     ASSERT(newDecl->Type() == DeclType::ENUM);
669     return enumMemberBindings_->insert({newDecl->Name(), allocator->New<EnumVariable>(newDecl, false)}).second;
670 }
671 
SetSelfScopeName(const util::StringView &ident)672 void TSEnumScope::SetSelfScopeName(const util::StringView &ident)
673 {
674     if (!hasSelfScopeNameSet_) {
675         FunctionScope::SetSelfScopeName(GetSelfScopeName());
676     }
677 }
678 
GetSelfScopeName()679 util::StringView TSEnumScope::GetSelfScopeName()
680 {
681     if (hasSelfScopeNameSet_) {
682         return selfScopeName_;
683     }
684 
685     std::stringstream scopeName;
686     if (node_ && node_->IsScriptFunction()) {
687         auto scriptFunction = node_->AsScriptFunction();
688         if (scriptFunction->Params().size() > 0 && scriptFunction->Params()[0]->IsIdentifier()) {
689             scopeName << scriptFunction->Params()[0]->AsIdentifier()->Name();
690         }
691     }
692     return util::UString(scopeName.str(), allocator_).View();
693 }
694 
GetScopeTag()695 util::StringView TSEnumScope::GetScopeTag()
696 {
697     return util::UString(util::Helpers::ENUM_TAG.data(), allocator_).View();
698 }
699 
AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, [[maybe_unused]] ScriptExtension extension)700 bool GlobalScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
701                              [[maybe_unused]] ScriptExtension extension)
702 {
703     switch (newDecl->Type()) {
704         case DeclType::VAR: {
705             return AddVar<GlobalVariable>(allocator, currentVariable, newDecl);
706         }
707         case DeclType::FUNC: {
708             return AddFunction<GlobalVariable>(allocator, currentVariable, newDecl, extension);
709         }
710         case DeclType::CLASS: {
711             return AddClass<LocalVariable>(allocator, currentVariable, newDecl);
712         }
713         case DeclType::ENUM_LITERAL: {
714             return AddTSBinding<EnumLiteralVariable>(allocator, newDecl, VariableFlags::ENUM_LITERAL);
715         }
716         case DeclType::NAMESPACE: {
717             return AddTSBinding<NamespaceVariable>(allocator, newDecl, VariableFlags::NAMESPACE);
718         }
719         case DeclType::IMPORT_EQUALS: {
720             return AddTSBinding<ImportEqualsVariable>(allocator, newDecl, VariableFlags::IMPORT_EQUALS);
721         }
722         case DeclType::INTERFACE: {
723             return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::INTERFACE);
724         }
725         default: {
726             return AddLexical<LocalVariable>(allocator, currentVariable, newDecl);
727         }
728     }
729 
730     return true;
731 }
732 
SetSelfScopeName([[maybe_unused]] const util::StringView &ident)733 void GlobalScope::SetSelfScopeName([[maybe_unused]] const util::StringView &ident)
734 {
735     hasSelfScopeNameSet_ = true;
736 }
737 
738 // ModuleScope
739 
ConvertLocalVariableToModuleVariable(ArenaAllocator *allocator, util::StringView localName)740 void ModuleScope::ConvertLocalVariableToModuleVariable(ArenaAllocator *allocator, util::StringView localName)
741 {
742     auto res = bindings_.find(localName);
743     // Since the module's exported [localName] has been validated before,
744     // [localName] must have a binding now.
745     ASSERT(res != bindings_.end());
746     if (!res->second->IsModuleVariable()) {
747         auto *decl = res->second->Declaration();
748         decl->AddFlag(DeclarationFlags::EXPORT);
749         VariableFlags flags = res->second->Flags();
750         res->second = allocator->New<ModuleVariable>(decl, flags | VariableFlags::LOCAL_EXPORT);
751     }
752 }
753 
AssignIndexToModuleVariable(util::StringView name, uint32_t index)754 void ModuleScope::AssignIndexToModuleVariable(util::StringView name, uint32_t index)
755 {
756     auto *moduleVar = FindLocal(name);
757     CHECK_NOT_NULL(moduleVar);
758     ASSERT(moduleVar->IsModuleVariable());
759     moduleVar->AsModuleVariable()->AssignIndex(index);
760 }
761 
AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, [[maybe_unused]] ScriptExtension extension)762 bool ModuleScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
763                              [[maybe_unused]] ScriptExtension extension)
764 {
765     switch (newDecl->Type()) {
766         case DeclType::VAR: {
767             auto [scope, shadowed] = IterateShadowedVariables(
768                 newDecl->Name(), [](const Variable *v) { return !v->HasFlag(VariableFlags::VAR); });
769 
770             if (shadowed) {
771                 return false;
772             }
773             return newDecl->IsImportOrExportDecl() ?
774                    AddVar<ModuleVariable>(allocator, currentVariable, newDecl) :
775                    AddVar<LocalVariable>(allocator, currentVariable, newDecl);
776         }
777         case DeclType::FUNC: {
778             if (currentVariable) {
779                 auto decl = currentVariable->Declaration();
780                 if (!decl->IsClassDecl() || !decl->AsClassDecl()->IsDeclare()) {
781                     return false;
782                 }
783             }
784             return newDecl->IsImportOrExportDecl() ?
785                    AddFunction<ModuleVariable>(allocator, currentVariable, newDecl, extension) :
786                    AddFunction<LocalVariable>(allocator, currentVariable, newDecl, extension);
787         }
788         case DeclType::CLASS: {
789             return newDecl->IsImportOrExportDecl() ?
790                    AddClass<ModuleVariable>(allocator, currentVariable, newDecl) :
791                    AddClass<LocalVariable>(allocator, currentVariable, newDecl);
792         }
793         case DeclType::ENUM_LITERAL: {
794             return AddTSBinding<EnumLiteralVariable>(allocator, newDecl, VariableFlags::ENUM_LITERAL);
795         }
796         case DeclType::NAMESPACE: {
797             return AddTSBinding<NamespaceVariable>(allocator, newDecl, VariableFlags::NAMESPACE);
798         }
799         case DeclType::IMPORT_EQUALS: {
800             return AddTSBinding<ImportEqualsVariable>(allocator, newDecl, VariableFlags::IMPORT_EQUALS);
801         }
802         case DeclType::INTERFACE: {
803             return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::INTERFACE);
804         }
805         default: {
806             if (currentVariable) {
807                 return false;
808             }
809             return newDecl->IsImportOrExportDecl() ?
810                    AddLexical<ModuleVariable>(allocator, currentVariable, newDecl) :
811                    AddLexical<LocalVariable>(allocator, currentVariable, newDecl);
812         }
813     }
814 }
815 
SetSelfScopeName([[maybe_unused]] const util::StringView &ident)816 void ModuleScope::SetSelfScopeName([[maybe_unused]] const util::StringView &ident)
817 {
818     hasSelfScopeNameSet_ = true;
819 }
820 
821 // LocalScope
822 
AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, [[maybe_unused]] ScriptExtension extension)823 bool LocalScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
824                             [[maybe_unused]] ScriptExtension extension)
825 {
826     return AddLocal(allocator, currentVariable, newDecl, extension);
827 }
828 
InitVariable()829 void LoopScope::InitVariable()
830 {
831     for (const auto &[name, var] : bindings_) {
832         if (!var->Declaration()->IsLetOrConstOrClassDecl()) {
833             continue;
834         }
835 
836         var->AddFlag(VariableFlags::INITIALIZED);
837         if (var->LexicalBound()) {
838             var->AddFlag(VariableFlags::PER_ITERATION);
839         }
840     }
841 }
842 
AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, [[maybe_unused]] ScriptExtension extension)843 bool CatchParamScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
844                                  [[maybe_unused]] ScriptExtension extension)
845 {
846     return AddParam(allocator, currentVariable, newDecl, VariableFlags::INITIALIZED);
847 }
848 
AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, [[maybe_unused]] ScriptExtension extension)849 bool CatchScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
850                             [[maybe_unused]] ScriptExtension extension)
851 {
852     if (!newDecl->IsVarDecl() && paramScope_->FindLocal(newDecl->Name())) {
853         return false;
854     }
855 
856     return AddLocal(allocator, currentVariable, newDecl, extension);
857 }
858 }  // namespace panda::es2panda::binder
859