• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2025 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 "ETSBinder.h"
17 
18 #include "evaluate/scopedDebugInfoPlugin.h"
19 #include "public/public.h"
20 #include "compiler/lowering/util.h"
21 #include "util/helpers.h"
22 
23 namespace ark::es2panda::varbinder {
24 
IdentifierAnalysis()25 void ETSBinder::IdentifierAnalysis()
26 {
27     ES2PANDA_ASSERT(Program()->Ast());
28     ES2PANDA_ASSERT(GetScope() == TopScope());
29     ES2PANDA_ASSERT(VarScope() == TopScope());
30 
31     recordTable_->SetProgram(Program());
32     globalRecordTable_.SetClassDefinition(Program()->GlobalClass());
33 
34     BuildProgram();
35 
36     ES2PANDA_ASSERT(globalRecordTable_.ClassDefinition() == Program()->GlobalClass());
37 }
38 
LookupTypeArgumentReferences(ir::ETSTypeReference * typeRef)39 void ETSBinder::LookupTypeArgumentReferences(ir::ETSTypeReference *typeRef)
40 {
41     auto *iter = typeRef->Part();
42     for (auto *anno : typeRef->Annotations()) {
43         ResolveReference(anno);
44     }
45 
46     while (iter != nullptr) {
47         if (iter->TypeParams() == nullptr) {
48             iter = iter->Previous();
49             continue;
50         }
51 
52         ResolveReferences(iter->TypeParams());
53         iter = iter->Previous();
54     }
55 }
56 
IsSpecialName(const util::StringView & name)57 bool ETSBinder::IsSpecialName(const util::StringView &name)
58 {
59     return name == compiler::Signatures::ANY_TYPE_NAME || name == compiler::Signatures::UNDEFINED ||
60            name == compiler::Signatures::NULL_LITERAL || name == compiler::Signatures::READONLY_TYPE_NAME ||
61            name == compiler::Signatures::PARTIAL_TYPE_NAME || name == compiler::Signatures::REQUIRED_TYPE_NAME ||
62            name == compiler::Signatures::FIXED_ARRAY_TYPE_NAME;
63 }
64 
HandleDynamicVariables(ir::Identifier * ident,Variable * variable,bool allowDynamicNamespaces)65 bool ETSBinder::HandleDynamicVariables(ir::Identifier *ident, Variable *variable, bool allowDynamicNamespaces)
66 {
67     if (IsDynamicModuleVariable(variable)) {
68         ident->SetVariable(variable);
69         return true;
70     }
71 
72     if (allowDynamicNamespaces && IsDynamicNamespaceVariable(variable)) {
73         ident->SetVariable(variable);
74         return true;
75     }
76     return false;
77 }
78 
LookupInDebugInfoPlugin(ir::Identifier * ident)79 bool ETSBinder::LookupInDebugInfoPlugin(ir::Identifier *ident)
80 {
81     auto *checker = GetContext()->checker->AsETSChecker();
82     auto *debugInfoPlugin = checker->GetDebugInfoPlugin();
83     if (UNLIKELY(debugInfoPlugin)) {
84         auto *var = debugInfoPlugin->FindClass(ident);
85         if (var != nullptr) {
86             ident->SetVariable(var);
87             return true;
88         }
89     }
90     // NOTE: search an imported module's name in case of 'import "file" as xxx'.
91     return false;
92 }
93 
94 //  Auxiliary method extracted from LookupTypeReference(...) to avoid too large size
CreateDummyVariable(ETSBinder * varBinder,ir::Identifier * ident)95 static void CreateDummyVariable(ETSBinder *varBinder, ir::Identifier *ident)
96 {
97     auto expressionCtx = varbinder::LexicalScope<varbinder::Scope>::Enter(varBinder, varBinder->VarScope());
98     auto [decl, var] =
99         varBinder->NewVarDecl<varbinder::LetDecl>(ident->Start(), compiler::GenName(varBinder->Allocator()).View());
100     var->SetScope(varBinder->GetScope());
101     ident->SetVariable(var);
102     ident->SetTsType(var->SetTsType(varBinder->GetContext()->checker->AsETSChecker()->GlobalTypeError()));
103     decl->BindNode(ident);
104 }
105 
LookupTypeReference(ir::Identifier * ident,bool allowDynamicNamespaces)106 void ETSBinder::LookupTypeReference(ir::Identifier *ident, bool allowDynamicNamespaces)
107 {
108     ES2PANDA_ASSERT(ident != nullptr);
109     if (ident->Variable() != nullptr && ident->Variable()->Declaration()->Node() == ident) {
110         return;
111     }
112 
113     auto const &name = ident->Name();
114     if (IsSpecialName(name)) {
115         return;
116     }
117 
118     if (ident->IsErrorPlaceHolder()) {
119         CreateDummyVariable(this, ident);
120         return;
121     }
122 
123     auto *scope = GetScope();
124     while (scope != nullptr) {
125         auto options = ResolveBindingOptions::DECLARATION | ResolveBindingOptions::TYPE_ALIASES |
126                        ResolveBindingOptions::STATIC_DECLARATION;
127         auto res = scope->Find(name, options);
128         if (res.variable == nullptr) {
129             break;
130         }
131 
132         if (HandleDynamicVariables(ident, res.variable, allowDynamicNamespaces)) {
133             return;
134         }
135 
136         switch (res.variable->Declaration()->Node()->Type()) {
137             case ir::AstNodeType::CLASS_DECLARATION:
138             case ir::AstNodeType::CLASS_DEFINITION:
139             case ir::AstNodeType::STRUCT_DECLARATION:
140             case ir::AstNodeType::TS_ENUM_DECLARATION:
141             case ir::AstNodeType::TS_INTERFACE_DECLARATION:
142             case ir::AstNodeType::TS_TYPE_PARAMETER:
143             case ir::AstNodeType::TS_TYPE_ALIAS_DECLARATION:
144             case ir::AstNodeType::ANNOTATION_DECLARATION:
145             case ir::AstNodeType::IMPORT_NAMESPACE_SPECIFIER: {
146                 ident->SetVariable(res.variable);
147                 return;
148             }
149             default: {
150                 scope = scope->Parent();
151             }
152         }
153     }
154 
155     if (LookupInDebugInfoPlugin(ident)) {
156         return;
157     }
158 
159     if (!GetContext()->config->options->IsGenerateDeclEnableIsolated()) {
160         ThrowUnresolvableType(ident->Start(), name);
161     }
162 
163     CreateDummyVariable(this, ident);
164 }
165 
ResolveReferencesForScope(ir::AstNode const * const parent,Scope * const scope)166 void ETSBinder::ResolveReferencesForScope(ir::AstNode const *const parent, Scope *const scope)
167 {
168     parent->Iterate([this, scope](auto *node) { ResolveReferenceForScope(node, scope); });
169 }
170 
ResolveReferenceForScope(ir::AstNode * const node,Scope * const scope)171 void ETSBinder::ResolveReferenceForScope(ir::AstNode *const node, Scope *const scope)
172 {
173     switch (node->Type()) {
174         case ir::AstNodeType::IDENTIFIER: {
175             auto *ident = node->AsIdentifier();
176             if (ident->Variable() != nullptr) {
177                 break;
178             }
179             if (auto const res = scope->Find(ident->Name(), ResolveBindingOptions::ALL); res.variable != nullptr) {
180                 ident->SetVariable(res.variable);
181             }
182             break;
183         }
184         case ir::AstNodeType::VARIABLE_DECLARATOR: {
185             auto scopeCtx = LexicalScope<Scope>::Enter(this, scope);
186             BuildVarDeclarator(node->AsVariableDeclarator());
187             break;
188         }
189         /* Maybe will be used
190         case ir::AstNodeType::BLOCK_STATEMENT: {
191             auto scope_ctx = LexicalScope<Scope>::Enter(this, node->AsBlockStatement()->Scope());
192             ResolveReferences(node);
193             break;
194         }
195         */
196         case ir::AstNodeType::BLOCK_EXPRESSION: {
197             auto scopeCtx = LexicalScope<Scope>::Enter(this, node->AsBlockExpression()->Scope());
198             ResolveReferences(node);
199             break;
200         }
201         default: {
202             ResolveReferencesForScope(node, scope);
203             break;
204         }
205     }
206 }
207 
ResolveReferencesForScopeWithContext(ir::AstNode * node,Scope * scope)208 void ETSBinder::ResolveReferencesForScopeWithContext(ir::AstNode *node, Scope *scope)
209 {
210     auto lexScope = LexicalScope<Scope>::Enter(this, scope);
211     ResolveReference(node);
212 }
213 
214 // export { a as b } value => a, key => b
215 // value == value and key == key => Warning, value == value and key != key => Ok, value != value and key == key => CTE
AddSelectiveExportAlias(parser::ETSParser * parser,util::StringView const & path,util::StringView const & key,util::StringView const & value,ir::AstNode const * decl)216 bool ETSBinder::AddSelectiveExportAlias(parser::ETSParser *parser, util::StringView const &path,
217                                         util::StringView const &key, util::StringView const &value,
218                                         ir::AstNode const *decl) noexcept
219 {
220     if (auto foundMap = selectiveExportAliasMultimap_.find(path); foundMap != selectiveExportAliasMultimap_.end()) {
221         auto inserted = foundMap->second.insert({key, std::make_pair(value, decl)}).second;
222         if (UNLIKELY(!inserted && foundMap->second.find(key)->second.first == value)) {
223             parser->DiagnosticEngine().Log(
224                 {util::DiagnosticType::WARNING, diagnostic::DUPLICATE_EXPORT_ALIASES, {key}, decl->Start()});
225             return true;
226         }
227         return inserted;
228     }
229 
230     ArenaMap<util::StringView, std::pair<util::StringView, ir::AstNode const *>> map(Allocator()->Adapter());
231     bool insertResult = map.insert({key, std::make_pair(value, decl)}).second;
232     selectiveExportAliasMultimap_.insert({path, map});
233     return insertResult;
234 }
235 
FindNameInAliasMap(const util::StringView & pathAsKey,const util::StringView & aliasName)236 util::StringView ETSBinder::FindNameInAliasMap(const util::StringView &pathAsKey, const util::StringView &aliasName)
237 {
238     if (auto relatedMap = selectiveExportAliasMultimap_.find(pathAsKey);
239         relatedMap != selectiveExportAliasMultimap_.end()) {
240         if (auto item = relatedMap->second.find(aliasName); item != relatedMap->second.end()) {
241             return item->second.first;
242         }
243     }
244 
245     return "";
246 }
247 
FindNodeInAliasMap(const util::StringView & pathAsKey,const util::StringView & aliasName)248 const ir::AstNode *ETSBinder::FindNodeInAliasMap(const util::StringView &pathAsKey, const util::StringView &aliasName)
249 {
250     if (auto relatedMap = selectiveExportAliasMultimap_.find(pathAsKey);
251         relatedMap != selectiveExportAliasMultimap_.end()) {
252         if (auto item = relatedMap->second.find(aliasName); item != relatedMap->second.end()) {
253             return item->second.second;
254         }
255     }
256 
257     return nullptr;
258 }
259 
LookupIdentReference(ir::Identifier * ident)260 void ETSBinder::LookupIdentReference(ir::Identifier *ident)
261 {
262     if (ident->IsErrorPlaceHolder()) {
263         return;
264     }
265 
266     const auto &name = ident->Name();
267     auto res = GetScope()->Find(name, ResolveBindingOptions::ALL);
268     if (res.level != 0) {
269         ES2PANDA_ASSERT(res.variable != nullptr);
270 
271         ES2PANDA_ASSERT(GetScope()->EnclosingVariableScope() != nullptr);
272         auto *outerFunction = GetScope()->EnclosingVariableScope()->Node();
273 
274         if ((!outerFunction->IsScriptFunction() || !outerFunction->AsScriptFunction()->IsArrow()) &&
275             !res.variable->IsGlobalVariable() && res.variable->HasFlag(VariableFlags::LOCAL) && res.level > 1) {
276             ThrowInvalidCapture(ident->Start(), name);
277         }
278     }
279 
280     if (res.variable == nullptr) {
281         return;
282     }
283 
284     if (ident->IsReference(Extension()) && res.variable->Declaration()->IsLetOrConstDecl() &&
285         !res.variable->HasFlag(VariableFlags::INITIALIZED) &&
286         !res.variable->HasFlag(VariableFlags::INIT_IN_STATIC_BLOCK)) {
287         ThrowTDZ(ident->Start(), name);
288     }
289 }
290 
BuildClassProperty(const ir::ClassProperty * prop)291 void ETSBinder::BuildClassProperty(const ir::ClassProperty *prop)
292 {
293     ResolveReferences(prop);
294 }
295 
BuildETSTypeReference(ir::ETSTypeReference * typeRef)296 void ETSBinder::BuildETSTypeReference(ir::ETSTypeReference *typeRef)
297 {
298     auto *baseName = typeRef->BaseName();
299     ES2PANDA_ASSERT(baseName->IsReference(Extension()));
300 
301     // We allow to resolve following types in pure dynamic mode:
302     // import * as I from "@dynamic"
303     // let x : I.X.Y
304     bool allowDynamicNamespaces = typeRef->Part()->Name() != baseName;
305     LookupTypeReference(baseName, allowDynamicNamespaces);
306     LookupTypeArgumentReferences(typeRef);
307 }
308 
BuildObjectExpression(ir::ObjectExpression * obj)309 void ETSBinder::BuildObjectExpression(ir::ObjectExpression *obj)
310 {
311     for (auto *it : obj->Decorators()) {
312         ResolveReference(it);
313     }
314 
315     // NOTE: when we try to resolve references for Object Expression
316     // we visit properties, example:
317     // class C { x : boolean }
318     // let x: C = { x: true }
319     //
320     // However we visit Object Expression with _outer_ scope, not class scope.
321     // That means that varbinder will try to resolve `x` as `x` from outer scope, _not from the class scope_.
322     // The following code will skip resolving LHS of the property.
323     // We can do it because currently LHS is still checked in the `ETSAnalyzer::CheckObjectExprProps` function.
324     for (auto expr : obj->Properties()) {
325         if (expr->IsProperty()) {
326             auto *prop = expr->AsProperty();
327             ResolveReference(prop->Value());
328         }
329     }
330 
331     if (obj->TypeAnnotation() != nullptr) {
332         ResolveReference(obj->TypeAnnotation());
333     }
334 }
335 
InitializeInterfaceIdent(ir::TSInterfaceDeclaration * decl)336 void ETSBinder::InitializeInterfaceIdent(ir::TSInterfaceDeclaration *decl)
337 {
338     auto res = GetScope()->Find(decl->Id()->Name());
339 
340     ES2PANDA_ASSERT(res.variable && res.variable->Declaration()->IsInterfaceDecl());
341     res.variable->AddFlag(VariableFlags::INITIALIZED);
342     decl->Id()->SetVariable(res.variable);
343 }
344 
ResolveEnumDeclaration(ir::TSEnumDeclaration * enumDecl)345 void ETSBinder::ResolveEnumDeclaration(ir::TSEnumDeclaration *enumDecl)
346 {
347     auto enumScopeCtx = LexicalScope<LocalScope>::Enter(this, enumDecl->Scope());
348 
349     for (auto *member : enumDecl->Members()) {
350         ResolveReference(member);
351     }
352 }
353 
ResolveInterfaceDeclaration(ir::TSInterfaceDeclaration * decl)354 void ETSBinder::ResolveInterfaceDeclaration(ir::TSInterfaceDeclaration *decl)
355 {
356     auto boundCtx = BoundContext(recordTable_, decl);
357 
358     for (auto *extend : decl->Extends()) {
359         ResolveReference(extend);
360     }
361 
362     for (auto *anno : decl->Annotations()) {
363         ResolveReference(anno);
364     }
365 
366     auto scopeCtx = LexicalScope<ClassScope>::Enter(this, decl->Scope()->AsClassScope());
367 
368     for (auto *stmt : decl->Body()->Body()) {
369         if (!stmt->IsClassProperty()) {
370             continue;
371         }
372 
373         ResolveReference(stmt);
374 
375         ES2PANDA_ASSERT(stmt->AsClassProperty()->Id() != nullptr);
376         auto fieldVar =
377             ResolvePropertyReference(stmt->AsClassProperty(), decl->Scope()->AsClassScope())
378                 ->FindLocal(stmt->AsClassProperty()->Id()->Name(), varbinder::ResolveBindingOptions::BINDINGS);
379         fieldVar->AddFlag(VariableFlags::INITIALIZED);
380     }
381 
382     for (auto *stmt : decl->Body()->Body()) {
383         if (stmt->IsClassProperty()) {
384             continue;
385         }
386         ResolveReference(stmt);
387     }
388 }
389 
BuildInterfaceDeclaration(ir::TSInterfaceDeclaration * decl)390 void ETSBinder::BuildInterfaceDeclaration(ir::TSInterfaceDeclaration *decl)
391 {
392     if (decl->TypeParams() != nullptr) {
393         auto typeParamScopeCtx = LexicalScope<LocalScope>::Enter(this, decl->TypeParams()->Scope());
394         ResolveReferences(decl->TypeParams());
395         ResolveInterfaceDeclaration(decl);
396         return;
397     }
398 
399     ResolveInterfaceDeclaration(decl);
400 }
401 
BuildMethodDefinition(ir::MethodDefinition * methodDef)402 void ETSBinder::BuildMethodDefinition(ir::MethodDefinition *methodDef)
403 {
404     if (methodDef->BaseOverloadMethod() != nullptr &&
405         methodDef->GetTopStatement()->AsETSModule()->Program() != Program() &&
406         methodDef->BaseOverloadMethod()->GetTopStatement() != methodDef->GetTopStatement()) {
407         return;
408     }
409     ES2PANDA_ASSERT(methodDef->Function() != nullptr);
410     if (methodDef->Function()->TypeParams() != nullptr) {
411         auto scopeCtx = LexicalScope<LocalScope>::Enter(this, methodDef->Function()->TypeParams()->Scope());
412         ResolveReferences(methodDef->Function()->TypeParams());
413     }
414     ResolveMethodDefinition(methodDef);
415 }
416 
BuildAnnotationDeclaration(ir::AnnotationDeclaration * annoDecl)417 void ETSBinder::BuildAnnotationDeclaration(ir::AnnotationDeclaration *annoDecl)
418 {
419     auto boundCtx = BoundContext(recordTable_, annoDecl);
420     if (annoDecl->Expr()->IsIdentifier()) {
421         LookupTypeReference(annoDecl->AsAnnotationDeclaration()->Expr()->AsIdentifier(), false);
422     } else {
423         ResolveReference(annoDecl->Expr());
424     }
425     auto scopeCtx = LexicalScope<LocalScope>::Enter(this, annoDecl->Scope());
426     for (auto *property : annoDecl->Properties()) {
427         ResolveReference(property);
428     }
429     for (auto *anno : annoDecl->Annotations()) {
430         ResolveReference(anno);
431     }
432 }
433 
BuildAnnotationUsage(ir::AnnotationUsage * annoUsage)434 void ETSBinder::BuildAnnotationUsage(ir::AnnotationUsage *annoUsage)
435 {
436     if (annoUsage->Expr()->IsIdentifier()) {
437         LookupTypeReference(annoUsage->AsAnnotationUsage()->Expr()->AsIdentifier(), false);
438     } else {
439         ResolveReference(annoUsage->Expr());
440     }
441 
442     for (auto *property : annoUsage->Properties()) {
443         ResolveReference(property);
444     }
445 }
446 
ResolveMethodDefinition(ir::MethodDefinition * methodDef)447 void ETSBinder::ResolveMethodDefinition(ir::MethodDefinition *methodDef)
448 {
449     methodDef->ResolveReferences([this](auto *childNode) { ResolveReference(childNode); });
450 
451     auto *func = methodDef->Function();
452     for (auto *anno : func->Annotations()) {
453         ResolveReference(anno);
454     }
455     if (methodDef->IsStatic() || func->IsStaticBlock()) {
456         return;
457     }
458 
459     auto paramScopeCtx = LexicalScope<FunctionParamScope>::Enter(this, func->Scope()->ParamScope());
460 
461     auto params = func->Scope()->ParamScope()->Params();
462     if (!params.empty() && params.front()->Name() == MANDATORY_PARAM_THIS && !func->HasReceiver()) {
463         return;  // Implicit this parameter is already inserted by ResolveReferences(), don't insert it twice.
464     }
465 
466     auto *thisParam = AddMandatoryParam(MANDATORY_PARAM_THIS);
467     ES2PANDA_ASSERT(thisParam != nullptr);
468     thisParam->Declaration()->BindNode(thisParam_);
469 }
470 
BuildMemberExpression(ir::MemberExpression * memberExpr)471 void ETSBinder::BuildMemberExpression(ir::MemberExpression *memberExpr)
472 {
473     ResolveReference(memberExpr->Object());
474 
475     if (memberExpr->Kind() == ir::MemberExpressionKind::ELEMENT_ACCESS) {
476         ResolveReference(memberExpr->Property());
477     }
478 }
479 
BuildClassDefinition(ir::ClassDefinition * classDef)480 void ETSBinder::BuildClassDefinition(ir::ClassDefinition *classDef)
481 {
482     auto boundCtx = BoundContext(recordTable_, classDef);
483 
484     if (classDef->TypeParams() != nullptr) {
485         auto scopeCtx = LexicalScope<LocalScope>::Enter(this, classDef->TypeParams()->Scope());
486         ResolveReferences(classDef->TypeParams());
487         BuildClassDefinitionImpl(classDef);
488         return;
489     }
490 
491     BuildClassDefinitionImpl(classDef);
492 }
493 
ResolvePropertyReference(ir::ClassProperty * prop,ClassScope * scope)494 LocalScope *ETSBinder::ResolvePropertyReference(ir::ClassProperty *prop, ClassScope *scope)
495 {
496     ResolveReferences(prop);
497 
498     if (prop->IsStatic()) {
499         return scope->StaticFieldScope();
500     }
501 
502     return scope->InstanceFieldScope();
503 }
504 
BuildClassDefinitionImpl(ir::ClassDefinition * classDef)505 void ETSBinder::BuildClassDefinitionImpl(ir::ClassDefinition *classDef)
506 {
507     auto classCtx = LexicalScope<ClassScope>::Enter(this, classDef->Scope()->AsClassScope());
508 
509     if (classDef->Super() != nullptr) {
510         ResolveReference(classDef->Super());
511     }
512 
513     for (auto *impl : classDef->Implements()) {
514         ResolveReference(impl);
515     }
516     for (auto *anno : classDef->Annotations()) {
517         ResolveReference(anno);
518     }
519 
520     for (auto *stmt : classDef->Body()) {
521         if (!stmt->IsClassProperty()) {
522             continue;
523         }
524         auto *const prop = stmt->AsClassProperty();
525 
526         auto fieldScope = ResolvePropertyReference(prop, classDef->Scope()->AsClassScope());
527         ES2PANDA_ASSERT(prop->Id() != nullptr);
528         auto fieldName = prop->Id()->Name();
529         if (auto fieldVar = fieldScope->FindLocal(fieldName, varbinder::ResolveBindingOptions::BINDINGS);
530             fieldVar != nullptr) {
531             if (fieldVar->Declaration()->Node()->IsClassProperty() &&
532                 fieldVar->Declaration()->Node()->AsClassProperty()->NeedInitInStaticBlock()) {
533                 fieldVar->AddFlag(VariableFlags::INIT_IN_STATIC_BLOCK);
534             } else if (!fieldVar->Declaration()->Node()->IsDefinite()) {
535                 fieldVar->AddFlag(VariableFlags::INITIALIZED);
536             }
537 
538             if ((fieldVar->Declaration()->IsConstDecl() || fieldVar->Declaration()->IsReadonlyDecl()) &&
539                 prop->Value() == nullptr) {
540                 fieldVar->AddFlag(VariableFlags::EXPLICIT_INIT_REQUIRED);
541             }
542         } else {
543             ES2PANDA_ASSERT(GetContext()->diagnosticEngine->IsAnyError());
544             auto *checker = GetContext()->checker->AsETSChecker();
545             prop->SetTsType(checker->GlobalTypeError());
546             prop->Id()->SetTsType(checker->GlobalTypeError());
547         }
548     }
549 
550     for (auto *stmt : classDef->Body()) {
551         if (stmt->IsClassProperty()) {
552             continue;
553         }
554         ResolveReference(stmt);
555     }
556 }
557 
AddFunctionThisParam(ir::ScriptFunction * func)558 void ETSBinder::AddFunctionThisParam(ir::ScriptFunction *func)
559 {
560     auto paramScopeCtx = LexicalScope<FunctionParamScope>::Enter(this, func->Scope()->ParamScope());
561     auto *thisParam = AddMandatoryParam(MANDATORY_PARAM_THIS);
562     ES2PANDA_ASSERT(thisParam != nullptr);
563     thisParam->Declaration()->BindNode(thisParam_);
564 }
565 
AddDynamicImport(ir::ETSImportDeclaration * import)566 void ETSBinder::AddDynamicImport(ir::ETSImportDeclaration *import)
567 {
568     ES2PANDA_ASSERT(import->Language().IsDynamic());
569     dynamicImports_.push_back(import);
570 }
571 
BuildProxyMethod(ir::ScriptFunction * func,const util::StringView & containingClassName,bool isExternal)572 void ETSBinder::BuildProxyMethod(ir::ScriptFunction *func, const util::StringView &containingClassName, bool isExternal)
573 {
574     ES2PANDA_ASSERT(!containingClassName.Empty() && func != nullptr);
575     func->Scope()->BindName(containingClassName);
576 
577     if (!func->IsAsyncFunc() && !isExternal) {
578         Functions().push_back(func->Scope());
579     }
580 }
581 
AddDynamicSpecifiersToTopBindings(ir::AstNode * const specifier,const ir::ETSImportDeclaration * const import)582 void ETSBinder::AddDynamicSpecifiersToTopBindings(ir::AstNode *const specifier,
583                                                   const ir::ETSImportDeclaration *const import)
584 {
585     // NOTE issue #23214: enable it after fix default import in dynamic import
586     if (specifier->IsImportDefaultSpecifier()) {
587         ThrowError(specifier->Start(), diagnostic::DEFAULT_DYNAMIC_IMPORT);
588         return;
589     }
590     const auto name = [specifier]() {
591         if (specifier->IsImportNamespaceSpecifier()) {
592             return specifier->AsImportNamespaceSpecifier()->Local()->Name();
593         }
594 
595         return specifier->AsImportSpecifier()->Local()->Name();
596     }();
597 
598     auto specDecl = GetScope()->Find(name, ResolveBindingOptions::DECLARATION);
599     ES2PANDA_ASSERT(specDecl.variable != nullptr);
600     dynamicImportVars_.emplace(specDecl.variable, DynamicImportData {import, specifier, specDecl.variable});
601 
602     if (specifier->IsImportSpecifier()) {
603         auto importSpecifier = specifier->AsImportSpecifier();
604         importSpecifier->Imported()->SetVariable(specDecl.variable);
605         importSpecifier->Local()->SetVariable(specDecl.variable);
606     }
607 }
608 
InsertForeignBinding(ir::AstNode * const specifier,const ir::ETSImportDeclaration * const import,const util::StringView & name,Variable * var)609 void ETSBinder::InsertForeignBinding(ir::AstNode *const specifier, const ir::ETSImportDeclaration *const import,
610                                      const util::StringView &name, Variable *var)
611 {
612     if (import->Language().IsDynamic()) {
613         dynamicImportVars_.emplace(var, DynamicImportData {import, specifier, var});
614     }
615 
616     TopScope()->InsertForeignBinding(name, var);
617 }
618 
InsertOrAssignForeignBinding(ir::AstNode * const specifier,const ir::ETSImportDeclaration * const import,const util::StringView & name,Variable * var)619 void ETSBinder::InsertOrAssignForeignBinding(ir::AstNode *const specifier, const ir::ETSImportDeclaration *const import,
620                                              const util::StringView &name, Variable *var)
621 {
622     if (import->Language().IsDynamic()) {
623         dynamicImportVars_.insert_or_assign(var, DynamicImportData {import, specifier, var});
624     }
625 
626     TopScope()->InsertOrAssignForeignBinding(name, var);
627 }
628 
ThrowRedeclarationError(const lexer::SourcePosition & pos,const Variable * const var,const Variable * const variable,util::StringView localName)629 void ETSBinder::ThrowRedeclarationError(const lexer::SourcePosition &pos, const Variable *const var,
630                                         const Variable *const variable, util::StringView localName)
631 {
632     const bool isNamespace = var->Declaration()->Node()->IsClassDefinition() &&
633                              var->Declaration()->Node()->AsClassDefinition()->IsNamespaceTransformed();
634     const auto type = isNamespace                                       ? "Namespace"
635                       : var->Declaration()->Node()->IsClassDefinition() ? "Class"
636                       : var->Declaration()->IsFunctionDecl()            ? "Function"
637                                                                         : "Variable";
638 
639     if (variable->Declaration()->Type() == var->Declaration()->Type()) {
640         ThrowError(pos, diagnostic::REDEFINITION, {type, localName});
641     } else {
642         ThrowError(pos, diagnostic::REDEFINITION_DIFF_TYPE, {type, localName});
643     }
644 }
645 
AddOverloadFlag(ArenaAllocator * allocator,bool isStdLib,varbinder::Variable * importedVar,varbinder::Variable * variable)646 void AddOverloadFlag(ArenaAllocator *allocator, bool isStdLib, varbinder::Variable *importedVar,
647                      varbinder::Variable *variable)
648 {
649     auto *const currentNode = variable->Declaration()->Node()->AsMethodDefinition();
650     auto *const method = importedVar->Declaration()->Node()->AsMethodDefinition();
651 
652     // Necessary because stdlib and escompat handled as same package, it can be removed after fixing package handling
653     auto const getPackageName = [](Variable *var) {
654         return var->GetScope()->Node()->GetTopStatement()->AsETSModule()->Program()->ModuleName();
655     };
656     if (isStdLib && (getPackageName(importedVar) != getPackageName(variable))) {
657         return;
658     }
659 
660     ES2PANDA_ASSERT(method->Function() != nullptr);
661     if (!method->Overloads().empty() && !method->HasOverload(currentNode)) {
662         method->AddOverload(currentNode);
663         currentNode->Function()->Id()->SetVariable(importedVar);
664         currentNode->Function()->AddFlag(ir::ScriptFunctionFlags::OVERLOAD);
665         currentNode->Function()->AddFlag(ir::ScriptFunctionFlags::EXTERNAL_OVERLOAD);
666         util::UString newInternalName(currentNode->Function()->Scope()->Name(), allocator);
667         currentNode->Function()->Scope()->BindInternalName(newInternalName.View());
668         return;
669     }
670 
671     if (!currentNode->HasOverload(method)) {
672         currentNode->AddOverload(method);
673         method->Function()->Id()->SetVariable(variable);
674         method->Function()->AddFlag(ir::ScriptFunctionFlags::OVERLOAD);
675         method->Function()->AddFlag(ir::ScriptFunctionFlags::EXTERNAL_OVERLOAD);
676         util::UString newInternalName(method->Function()->Scope()->Name(), allocator);
677         method->Function()->Scope()->BindInternalName(newInternalName.View());
678     }
679 }
680 
ImportAllForeignBindings(ir::AstNode * const specifier,const varbinder::Scope::VariableMap & globalBindings,const parser::Program * const importProgram,const varbinder::GlobalScope * const importGlobalScope,const ir::ETSImportDeclaration * const import)681 void ETSBinder::ImportAllForeignBindings(ir::AstNode *const specifier,
682                                          const varbinder::Scope::VariableMap &globalBindings,
683                                          const parser::Program *const importProgram,
684                                          const varbinder::GlobalScope *const importGlobalScope,
685                                          const ir::ETSImportDeclaration *const import)
686 {
687     bool const isStdLib = util::Helpers::IsStdLib(Program());
688 
689     for (const auto [bindingName, var] : globalBindings) {
690         if (util::Helpers::IsGlobalVar(var)) {
691             const auto *const classDef = var->Declaration()->Node()->AsClassDeclaration()->Definition();
692             ImportGlobalProperties(classDef);
693             continue;
694         }
695         if (!importGlobalScope->IsForeignBinding(bindingName) && !var->Declaration()->Node()->IsDefaultExported() &&
696             (var->AsLocalVariable()->Declaration()->Node()->IsExported())) {
697             auto variable = Program()->GlobalClassScope()->FindLocal(bindingName, ResolveBindingOptions::ALL);
698             if (variable == nullptr || var == variable) {
699                 InsertForeignBinding(specifier, import, bindingName, var);
700                 continue;
701             }
702 
703             if (variable->Declaration()->IsFunctionDecl() && var->Declaration()->IsFunctionDecl()) {
704                 AddOverloadFlag(Allocator(), isStdLib, var, variable);
705                 continue;
706             }
707 
708             // It will be a redeclaration error, but the imported element has not been placed among the bindings yet
709             if (TopScope()->FindLocal(bindingName, ResolveBindingOptions::ALL) == nullptr) {
710                 InsertForeignBinding(specifier, import, bindingName, var);
711             }
712 
713             // redeclaration for builtin type,
714             // need to erase the redeclaration one and make sure the builtin types initialized successfully.
715             if (var->HasFlag(varbinder::VariableFlags::BUILTIN_TYPE)) {
716                 TopScope()->CorrectForeignBinding(bindingName, var, variable);
717             }
718 
719             ThrowRedeclarationError(import->Source()->Start(), var, variable, bindingName);
720         }
721     }
722 
723     for (const auto [bindingName, var] : importProgram->GlobalClassScope()->StaticMethodScope()->Bindings()) {
724         if (!var->Declaration()->Node()->IsDefaultExported()) {
725             InsertForeignBinding(specifier, import, bindingName, var);
726         }
727     }
728 
729     for (const auto [bindingName, var] : importProgram->GlobalClassScope()->StaticFieldScope()->Bindings()) {
730         if (!var->Declaration()->Node()->IsDefaultExported()) {
731             InsertForeignBinding(specifier, import, bindingName, var);
732         }
733     }
734 }
735 
ReexportPathMatchesImportPath(const ir::ETSReExportDeclaration * const reexport,const ir::ETSImportDeclaration * const import) const736 bool ETSBinder::ReexportPathMatchesImportPath(const ir::ETSReExportDeclaration *const reexport,
737                                               const ir::ETSImportDeclaration *const import) const
738 {
739     // NOTE(dkofanov): Related to #23877. Probably this should be resolved by 'import->ResolvedSource()'.
740     // For static import `ResolvedSource` is realpath, while in case of dynamic it module-relative.
741     auto importSource = import->ImportMetadata().HasSpecifiedDeclPath() ? import->DeclPath() : import->ResolvedSource();
742     auto reexportSource = reexport->GetProgramPath();
743     return reexportSource == importSource;
744 }
745 
GetExternalProgram(ETSBinder * binder,const ir::ETSImportDeclaration * const import)746 static auto GetExternalProgram(ETSBinder *binder, const ir::ETSImportDeclaration *const import)
747 {
748     if (!import->DeclPath().empty() && (import->DeclPath() != util::ImportPathManager::DUMMY_PATH)) {
749         return binder->GetExternalProgram(std::string_view {import->DeclPath()}, import->Source());
750     }
751     return binder->GetExternalProgram(import->ResolvedSource(), import->Source());
752 }
753 
AddImportNamespaceSpecifiersToTopBindings(Span<parser::Program * const> records,ir::ImportNamespaceSpecifier * const namespaceSpecifier,const ir::ETSImportDeclaration * const import)754 void ETSBinder::AddImportNamespaceSpecifiersToTopBindings(Span<parser::Program *const> records,
755                                                           ir::ImportNamespaceSpecifier *const namespaceSpecifier,
756                                                           const ir::ETSImportDeclaration *const import)
757 {
758     const parser::Program *const importProgram = records[0];
759     const auto *const importGlobalScope = importProgram->GlobalScope();
760     const auto &globalBindings = importGlobalScope->Bindings();
761 
762     if (namespaceSpecifier->Local()->Name().Empty()) {
763         ImportAllForeignBindings(namespaceSpecifier, globalBindings, importProgram, importGlobalScope, import);
764     }
765 
766     for (auto item : ReExportImports()) {
767         // NOTE(rsipka): this should be refactored or eliminated
768         if (!ReexportPathMatchesImportPath(item, import)) {
769             continue;
770         }
771 
772         for (auto it : item->GetETSImportDeclarations()->Specifiers()) {
773             if (it->IsImportNamespaceSpecifier() && !namespaceSpecifier->Local()->Name().Empty()) {
774                 continue;
775             }
776 
777             AddSpecifiersToTopBindings(it, item->GetETSImportDeclarations());
778         }
779     }
780 }
781 
FindImportSpecifiersVariable(const util::StringView & imported,const varbinder::Scope::VariableMap & globalBindings,Span<parser::Program * const> records)782 Variable *ETSBinder::FindImportSpecifiersVariable(const util::StringView &imported,
783                                                   const varbinder::Scope::VariableMap &globalBindings,
784                                                   Span<parser::Program *const> records)
785 {
786     auto foundVar = globalBindings.find(imported);
787     if (foundVar == globalBindings.end()) {
788         const auto &staticMethodBindings = records[0]->GlobalClassScope()->StaticMethodScope()->Bindings();
789         foundVar = staticMethodBindings.find(imported);
790         if (foundVar != staticMethodBindings.end()) {
791             return foundVar->second;
792         }
793         bool found = false;
794         for (auto res : records) {
795             const auto &staticFieldBindings = res->GlobalClassScope()->StaticFieldScope()->Bindings();
796             foundVar = staticFieldBindings.find(imported);
797             if (foundVar != staticFieldBindings.end()) {
798                 found = true;
799                 foundVar->second->AsLocalVariable()->AddFlag(VariableFlags::INITIALIZED);
800                 break;
801             }
802         }
803         if (!found) {
804             return nullptr;
805         }
806     }
807 
808     return foundVar->second;
809 }
810 
IsExportedVariable(varbinder::Variable * const var)811 static bool IsExportedVariable(varbinder::Variable *const var)
812 {
813     return var != nullptr &&
814            (var->Declaration()->Node()->IsExported() || var->Declaration()->Node()->IsDefaultExported() ||
815             var->Declaration()->Node()->HasExportAlias());
816 }
817 
FindImportDeclInExports(const ir::ETSImportDeclaration * const import,const util::StringView & imported,const ir::StringLiteral * const importPath)818 std::pair<ir::ETSImportDeclaration *, ir::AstNode *> ETSBinder::FindImportDeclInExports(
819     const ir::ETSImportDeclaration *const import, const util::StringView &imported,
820     const ir::StringLiteral *const importPath)
821 {
822     ir::ETSImportDeclaration *implDecl = nullptr;
823     ir::AstNode *specifier = nullptr;
824     std::tie(implDecl, specifier) = FindImportDeclInReExports(import, imported, importPath);
825     if (implDecl != nullptr) {
826         return std::make_pair(implDecl, specifier);
827     }
828     std::tie(implDecl, specifier) = FindImportDeclInNamedExports(import, imported, importPath);
829     return std::make_pair(implDecl, specifier);
830 }
831 
FindImportDeclInProgram(parser::Program * program,const util::StringView & imported)832 static std::pair<ir::ETSImportDeclaration *, ir::AstNode *> FindImportDeclInProgram(parser::Program *program,
833                                                                                     const util::StringView &imported)
834 {
835     for (auto stmt : program->Ast()->AsETSModule()->Statements()) {
836         if (!stmt->IsETSImportDeclaration()) {
837             continue;
838         }
839         for (auto specifier : stmt->AsETSImportDeclaration()->Specifiers()) {
840             if (specifier->IsImportSpecifier() && specifier->AsImportSpecifier()->Local()->Name() == imported) {
841                 return std::make_pair(stmt->AsETSImportDeclaration(), specifier);
842             }
843             if (specifier->IsImportDefaultSpecifier() &&
844                 specifier->AsImportDefaultSpecifier()->Local()->Name() == imported) {
845                 return std::make_pair(stmt->AsETSImportDeclaration(), specifier);
846             }
847         }
848     }
849     return std::make_pair(nullptr, nullptr);
850 }
851 
FindImportDeclInNamedExports(const ir::ETSImportDeclaration * const import,const util::StringView & imported,const ir::StringLiteral * const importPath)852 std::pair<ir::ETSImportDeclaration *, ir::AstNode *> ETSBinder::FindImportDeclInNamedExports(
853     const ir::ETSImportDeclaration *const import, [[maybe_unused]] const util::StringView &imported,
854     const ir::StringLiteral *const importPath)
855 {
856     auto importMapIter = selectiveExportAliasMultimap_.find(import->ImportMetadata().resolvedSource);
857     if (importMapIter == selectiveExportAliasMultimap_.end()) {
858         return std::make_pair(nullptr, nullptr);
859     }
860     auto pairIter = importMapIter->second.find(imported);
861     if (pairIter == importMapIter->second.end()) {
862         return std::make_pair(nullptr, nullptr);
863     }
864     auto [localName, declNode] = pairIter->second;
865     const auto records = GetExternalProgram(import->ImportMetadata().resolvedSource, importPath);
866     if (records.empty()) {
867         return std::make_pair(nullptr, nullptr);
868     }
869     auto currProgram = records[0];
870     if (currProgram == nullptr) {
871         return std::make_pair(nullptr, nullptr);
872     }
873     auto [newImportDecl, specfier] = FindImportDeclInProgram(currProgram, localName);
874     if (newImportDecl == nullptr) {
875         return std::make_pair(nullptr, nullptr);
876     }
877     return std::make_pair(newImportDecl->AsETSImportDeclaration(), specfier);
878 }
879 
GetSpecifier(const util::StringView & importedLocal,ir::ETSImportDeclaration * decl)880 static ir::AstNode *GetSpecifier(const util::StringView &importedLocal, ir::ETSImportDeclaration *decl)
881 {
882     for (auto localSpecfier : decl->Specifiers()) {
883         util::StringView name;
884         if (localSpecfier->IsImportSpecifier()) {
885             name = localSpecfier->AsImportSpecifier()->Local()->Name();
886         } else if (localSpecfier->IsImportNamespaceSpecifier()) {
887             name = localSpecfier->AsImportNamespaceSpecifier()->Local()->Name();
888         } else {
889             name = localSpecfier->AsImportDefaultSpecifier()->Local()->Name();
890         }
891         if (name == importedLocal) {
892             return localSpecfier;
893         }
894     }
895     if (decl->Specifiers().size() == 1 && decl->Specifiers()[0]->IsImportNamespaceSpecifier()) {
896         return decl->Specifiers()[0];
897     }
898     ES2PANDA_UNREACHABLE();
899 }
900 
FindImportDeclInReExports(const ir::ETSImportDeclaration * const import,const util::StringView & imported,const ir::StringLiteral * const importPath)901 std::pair<ir::ETSImportDeclaration *, ir::AstNode *> ETSBinder::FindImportDeclInReExports(
902     const ir::ETSImportDeclaration *const import, const util::StringView &imported,
903     const ir::StringLiteral *const importPath)
904 {
905     ir::ETSImportDeclaration *implDecl = nullptr;
906     ir::AstNode *specifier = nullptr;
907 
908     for (auto item : ReExportImports()) {
909         if (!ReexportPathMatchesImportPath(item, import)) {
910             continue;
911         }
912 
913         auto specifiers = item->GetETSImportDeclarations()->Specifiers();
914         if (specifiers[0]->IsImportSpecifier()) {
915             if (!std::any_of(specifiers.begin(), specifiers.end(), [&imported](auto it) {
916                     return it->AsImportSpecifier()->Local()->Name().Is(imported.Mutf8());
917                 })) {
918                 continue;
919             }
920             implDecl = item->GetETSImportDeclarations();
921             specifier = GetSpecifier(imported, implDecl);
922         } else {
923             const auto records = GetExternalProgram(item->GetETSImportDeclarations()->ResolvedSource(), importPath);
924             if (records.empty()) {
925                 continue;
926             }
927             auto *const var =
928                 FindImportSpecifiersVariable(imported, records[0]->GlobalScope()->Bindings(), Span {records});
929             if (IsExportedVariable(var)) {
930                 implDecl = item->GetETSImportDeclarations();
931                 specifier = GetSpecifier(imported, implDecl);
932                 continue;
933             }
934             auto reExportImport = item->GetETSImportDeclarations();
935             auto reExportImportPath = reExportImport->Source();
936             auto [implDeclOrNullptr, localSpecifier] =
937                 FindImportDeclInExports(reExportImport, imported, reExportImportPath);
938             if (implDeclOrNullptr != nullptr) {
939                 implDecl = implDeclOrNullptr;
940                 specifier = GetSpecifier(imported, implDecl);
941             }
942         }
943     }
944     return std::make_pair(implDecl, specifier);
945 }
946 
ValidateImportVariable(const ir::AstNode * node,const util::StringView & imported,const ir::StringLiteral * const importPath)947 void ETSBinder::ValidateImportVariable(const ir::AstNode *node, const util::StringView &imported,
948                                        const ir::StringLiteral *const importPath)
949 {
950     if (node->IsDefaultExported()) {
951         ThrowError(importPath->Start(), diagnostic::DEFAULT_EXPORT_DIRECT_IMPORTED);
952     } else if (!node->IsExported() && !node->IsDefaultExported() && !node->HasExportAlias()) {
953         ThrowError(importPath->Start(), diagnostic::IMPORTED_NOT_EXPORTED, {imported});
954     }
955 }
956 
DetectNameConflict(const util::StringView localName,Variable * const var,Variable * const otherVar,const ir::StringLiteral * const importPath)957 bool ETSBinder::DetectNameConflict(const util::StringView localName, Variable *const var, Variable *const otherVar,
958                                    const ir::StringLiteral *const importPath)
959 {
960     if (otherVar == nullptr || var == otherVar) {
961         return false;
962     }
963 
964     if (var->Declaration()->IsFunctionDecl() && otherVar->Declaration()->IsFunctionDecl()) {
965         AddOverloadFlag(Allocator(), util::Helpers::IsStdLib(Program()), var, otherVar);
966         return true;
967     }
968 
969     bool isAmbient = var->Declaration()->Node()->IsDeclare() && !otherVar->Declaration()->Node()->IsDeclare();
970     if (isAmbient) {
971         return false;
972     }
973 
974     ThrowRedeclarationError(importPath->Start(), var, otherVar, localName);
975     return true;
976 }
977 
AddImportSpecifierFromReExport(ir::AstNode * importSpecifier,const ir::ETSImportDeclaration * const import,const util::StringView & imported,const ir::StringLiteral * const importPath)978 Variable *ETSBinder::AddImportSpecifierFromReExport(ir::AstNode *importSpecifier,
979                                                     const ir::ETSImportDeclaration *const import,
980                                                     const util::StringView &imported,
981                                                     const ir::StringLiteral *const importPath)
982 {
983     auto [implDecl, localSpecifier] = FindImportDeclInExports(import, imported, importPath);
984     Variable *localVar = nullptr;
985     auto insertBinding = [this, importSpecifier, import](Variable *var) {
986         if (importSpecifier->IsImportSpecifier()) {
987             this->InsertOrAssignForeignBinding(importSpecifier, import,
988                                                importSpecifier->AsImportSpecifier()->Local()->Name(), var);
989             importSpecifier->AsImportSpecifier()->Local()->SetVariable(var);
990             importSpecifier->AsImportSpecifier()->Imported()->SetVariable(var);
991         } else if (importSpecifier->IsImportDefaultSpecifier()) {
992             this->InsertOrAssignForeignBinding(importSpecifier, import,
993                                                importSpecifier->AsImportDefaultSpecifier()->Local()->Name(), var);
994             importSpecifier->AsImportDefaultSpecifier()->Local()->SetVariable(var);
995         }
996     };
997     if (implDecl != nullptr) {
998         if (localSpecifier->IsImportSpecifier() || localSpecifier->IsImportDefaultSpecifier()) {
999             AddSpecifiersToTopBindings(localSpecifier, implDecl);
1000             if (localSpecifier->IsImportSpecifier()) {
1001                 localVar = localSpecifier->AsImportSpecifier()->Imported()->Variable();
1002                 insertBinding(localVar);
1003             } else if (localSpecifier->IsImportDefaultSpecifier()) {
1004                 localVar = localSpecifier->AsImportDefaultSpecifier()->Local()->Variable();
1005                 insertBinding(localVar);
1006             }
1007         } else {
1008             AddSpecifiersToTopBindings(importSpecifier, implDecl);
1009         }
1010 
1011         return localVar;
1012     }
1013 
1014     ThrowError(importPath->Start(), diagnostic::IMPORT_NOT_FOUND, {imported});
1015     return nullptr;
1016 }
1017 
1018 // CC-OFFNXT(huge_method, G.FUN.01-CPP) solid logic
AddImportSpecifiersToTopBindings(Span<parser::Program * const> records,ir::ImportSpecifier * const importSpecifier,const ir::ETSImportDeclaration * const import)1019 bool ETSBinder::AddImportSpecifiersToTopBindings(Span<parser::Program *const> records,
1020                                                  ir::ImportSpecifier *const importSpecifier,
1021                                                  const ir::ETSImportDeclaration *const import)
1022 {
1023     const auto &globalBindings = records[0]->GlobalScope()->Bindings();
1024     const ir::StringLiteral *const importPath = import->Source();
1025 
1026     if (!importSpecifier->Imported()->IsIdentifier()) {
1027         return true;
1028     }
1029 
1030     auto imported = importSpecifier->Imported()->Name();
1031 
1032     for (auto const item : import->Specifiers()) {
1033         if (item->IsImportSpecifier() && item->AsImportSpecifier()->Local()->Name().Is(imported.Mutf8()) &&
1034             !item->AsImportSpecifier()->Local()->Name().Is(item->AsImportSpecifier()->Imported()->Name().Mutf8())) {
1035             imported = item->AsImportSpecifier()->Imported()->Name();
1036         }
1037     }
1038 
1039     util::StringView nameToSearchFor = FindNameInAliasMap(import->ResolvedSource(), imported);
1040     if (nameToSearchFor.Empty()) {
1041         nameToSearchFor = imported;
1042     }
1043 
1044     auto *var = FindImportSpecifiersVariable(nameToSearchFor, globalBindings, records);
1045     importSpecifier->Imported()->SetVariable(var);
1046     importSpecifier->Local()->SetVariable(var);
1047 
1048     if (var == nullptr) {
1049         var = AddImportSpecifierFromReExport(importSpecifier, import, imported, importPath);
1050     }
1051     if (var == nullptr) {
1052         return false;
1053     }
1054 
1055     auto *node = FindNodeInAliasMap(import->ResolvedSource(), imported);
1056 
1057     ValidateImportVariable(node != nullptr ? node : var->Declaration()->Node(), imported, importPath);
1058 
1059     const auto localName = importSpecifier->Local()->Name();
1060     auto varInGlobalClassScope = Program()->GlobalClassScope()->FindLocal(localName, ResolveBindingOptions::ALL);
1061     auto previouslyImportedVariable = TopScope()->FindLocal(localName, ResolveBindingOptions::ALL);
1062     if (DetectNameConflict(localName, var, varInGlobalClassScope, importPath) ||
1063         DetectNameConflict(localName, var, previouslyImportedVariable, importPath)) {
1064         return true;
1065     }
1066 
1067     if (var->Declaration()->Node()->IsAnnotationDeclaration() &&
1068         var->Declaration()->Node()->AsAnnotationDeclaration()->GetBaseName()->Name() != localName) {
1069         ThrowError(importPath->Start(), diagnostic::IMPORT_RENAMES_ANNOTATION, {var->Declaration()->Name()});
1070         return false;
1071     }
1072 
1073     // The first part of the condition will be true, if something was given an alias when exported, but we try
1074     // to import it using its original name and if original name is not exported.
1075     if (nameToSearchFor == imported && var->Declaration()->Node()->HasExportAlias() &&
1076         !var->Declaration()->Node()->IsExported()) {
1077         ThrowError(importSpecifier->Start(), diagnostic::IMPORT_NOT_FOUND, {imported});
1078         return false;
1079     }
1080 
1081     InsertOrAssignForeignBinding(importSpecifier, import, localName, var);
1082     return true;
1083 }
1084 
AddImportDefaultSpecifiersToTopBindings(Span<parser::Program * const> records,ir::ImportDefaultSpecifier * const importDefaultSpecifier,const ir::ETSImportDeclaration * const import)1085 void ETSBinder::AddImportDefaultSpecifiersToTopBindings(Span<parser::Program *const> records,
1086                                                         ir::ImportDefaultSpecifier *const importDefaultSpecifier,
1087                                                         const ir::ETSImportDeclaration *const import)
1088 {
1089     auto importProgram = records[0];
1090     const auto &globalBindings = importProgram->GlobalScope()->Bindings();
1091     auto isDefaultExpored = [](const auto &item) { return item.second.second->IsDefaultExported(); };
1092     auto selectMap = importProgram->VarBinder()->AsETSBinder()->GetSelectiveExportAliasMultimap();
1093     auto selectMap2 = selectMap.find(import->ResolvedSource());
1094     if (selectMap2 != selectMap.end()) {
1095         auto item1 = std::find_if(selectMap2->second.begin(), selectMap2->second.end(), isDefaultExpored);
1096         if (item1 != selectMap2->second.end()) {
1097             auto var = FindImportSpecifiersVariable(item1->first, globalBindings, records);
1098             if (var == nullptr) {
1099                 var = AddImportSpecifierFromReExport(importDefaultSpecifier, import, item1->first, import->Source());
1100             }
1101             if (var == nullptr) {
1102                 return;
1103             }
1104             importDefaultSpecifier->Local()->SetVariable(var);
1105             InsertOrAssignForeignBinding(importDefaultSpecifier, import, importDefaultSpecifier->Local()->Name(), var);
1106             return;
1107         }
1108     }
1109 
1110     if (auto var = FindStaticBinding(records, import->Source()); var != nullptr) {
1111         importDefaultSpecifier->Local()->SetVariable(var);
1112         InsertForeignBinding(importDefaultSpecifier, import, importDefaultSpecifier->Local()->Name(), var);
1113         return;
1114     }
1115 }
1116 
FindInStatic(parser::Program * program)1117 static Variable *FindInStatic(parser::Program *program)
1118 {
1119     auto predicateFunc = [](const auto &item) { return item.second->Declaration()->Node()->IsDefaultExported(); };
1120     const auto &staticMethodBindings = program->GlobalClassScope()->StaticMethodScope()->Bindings();
1121     auto result = std::find_if(staticMethodBindings.begin(), staticMethodBindings.end(), predicateFunc);
1122     if (result == staticMethodBindings.end()) {
1123         const auto &staticFieldBindings = program->GlobalClassScope()->StaticFieldScope()->Bindings();
1124         result = std::find_if(staticFieldBindings.begin(), staticFieldBindings.end(), predicateFunc);
1125         if (result == staticFieldBindings.end()) {
1126             const auto &staticDeclBindings = program->GlobalClassScope()->StaticDeclScope()->Bindings();
1127             result = std::find_if(staticDeclBindings.begin(), staticDeclBindings.end(), predicateFunc);
1128             if (result == staticDeclBindings.end()) {
1129                 return nullptr;
1130             }
1131         }
1132     }
1133     return result->second;
1134 }
1135 
FindInInstance(parser::Program * program)1136 static Variable *FindInInstance(parser::Program *program)
1137 {
1138     auto predicateFunc = [](const auto &item) { return item.second->Declaration()->Node()->IsDefaultExported(); };
1139     const auto &instanceMethodBindings = program->GlobalClassScope()->InstanceMethodScope()->Bindings();
1140     auto result = std::find_if(instanceMethodBindings.begin(), instanceMethodBindings.end(), predicateFunc);
1141     if (result == instanceMethodBindings.end()) {
1142         const auto &instanceFieldBindings = program->GlobalClassScope()->InstanceFieldScope()->Bindings();
1143         result = std::find_if(instanceFieldBindings.begin(), instanceFieldBindings.end(), predicateFunc);
1144         if (result == instanceFieldBindings.end()) {
1145             const auto &instanceDeclBindings = program->GlobalClassScope()->InstanceDeclScope()->Bindings();
1146             result = std::find_if(instanceDeclBindings.begin(), instanceDeclBindings.end(), predicateFunc);
1147             if (result == instanceDeclBindings.end()) {
1148                 return nullptr;
1149             }
1150         }
1151     }
1152     return result->second;
1153 }
1154 
FindStaticBinding(Span<parser::Program * const> records,const ir::StringLiteral * const importPath)1155 varbinder::Variable *ETSBinder::FindStaticBinding(Span<parser::Program *const> records,
1156                                                   const ir::StringLiteral *const importPath)
1157 {
1158     auto result = FindInInstance(records[0]);
1159     if (result != nullptr) {
1160         return result;
1161     }
1162     result = FindInStatic(records[0]);
1163     if (result != nullptr) {
1164         return result;
1165     }
1166     if (!GetContext()->config->options->IsGenerateDeclEnableIsolated()) {
1167         ThrowError(importPath->Start(), diagnostic::DEFAULT_IMPORT_NOT_FOUND);
1168     }
1169 
1170     return nullptr;
1171 }
1172 
GetExternalProgram(util::StringView sourceName,const ir::StringLiteral * importPath)1173 ArenaVector<parser::Program *> ETSBinder::GetExternalProgram(util::StringView sourceName,
1174                                                              const ir::StringLiteral *importPath)
1175 {
1176     if (sourceName == ERROR_LITERAL) {
1177         // avoid logging rediculus messages, there must be a syntax error
1178         ES2PANDA_ASSERT(GetContext()->diagnosticEngine->IsAnyError());
1179         return ArenaVector<parser::Program *>(Allocator()->Adapter());
1180     }
1181     // NOTE: quick fix to make sure not to look for the global program among the external sources
1182     if (sourceName.Compare(globalRecordTable_.Program()->AbsoluteName()) == 0) {
1183         ArenaVector<parser::Program *> mainModule(Allocator()->Adapter());
1184         mainModule.emplace_back(globalRecordTable_.Program());
1185         return mainModule;
1186     }
1187 
1188     auto programList = GetProgramList(sourceName);
1189     if (programList.empty()) {
1190         if (ark::os::file::File::IsDirectory(sourceName.Mutf8())) {
1191             ThrowError(importPath->Start(), diagnostic::MODULE_INDEX_MISSING, {importPath->Str()});
1192         } else {
1193             ThrowError(importPath->Start(), diagnostic::IMPORT_NOT_FOUND_2, {importPath->Str()});
1194         }
1195     }
1196 
1197     return programList;
1198 }
1199 
AddSpecifiersToTopBindings(ir::AstNode * const specifier,const ir::ETSImportDeclaration * const import)1200 void ETSBinder::AddSpecifiersToTopBindings(ir::AstNode *const specifier, const ir::ETSImportDeclaration *const import)
1201 {
1202     if (import->IsPureDynamic()) {
1203         AddDynamicSpecifiersToTopBindings(specifier, import);
1204         return;
1205     }
1206     const auto records = varbinder::GetExternalProgram(this, import);
1207     if (records.empty()) {
1208         return;
1209     }
1210 
1211     if (specifier->IsImportNamespaceSpecifier()) {
1212         AddImportNamespaceSpecifiersToTopBindings(Span {records}, specifier->AsImportNamespaceSpecifier(), import);
1213     } else if (specifier->IsImportSpecifier()) {
1214         AddImportSpecifiersToTopBindings(Span {records}, specifier->AsImportSpecifier(), import);
1215     } else if (specifier->IsImportDefaultSpecifier()) {
1216         AddImportDefaultSpecifiersToTopBindings(Span {records}, specifier->AsImportDefaultSpecifier(), import);
1217     }
1218 }
1219 
HandleCustomNodes(ir::AstNode * childNode)1220 void ETSBinder::HandleCustomNodes(ir::AstNode *childNode)
1221 {
1222     switch (childNode->Type()) {
1223         case ir::AstNodeType::ETS_TYPE_REFERENCE: {
1224             return BuildETSTypeReference(childNode->AsETSTypeReference());
1225         }
1226         case ir::AstNodeType::TS_INTERFACE_DECLARATION: {
1227             return BuildInterfaceDeclaration(childNode->AsTSInterfaceDeclaration());
1228         }
1229         case ir::AstNodeType::TS_ENUM_DECLARATION: {
1230             return ResolveEnumDeclaration(childNode->AsTSEnumDeclaration());
1231         }
1232         case ir::AstNodeType::EXPORT_NAMED_DECLARATION: {
1233             break;
1234         }
1235         case ir::AstNodeType::ETS_IMPORT_DECLARATION: {
1236             return BuildImportDeclaration(childNode->AsETSImportDeclaration());
1237         }
1238         case ir::AstNodeType::MEMBER_EXPRESSION: {
1239             return BuildMemberExpression(childNode->AsMemberExpression());
1240         }
1241         case ir::AstNodeType::METHOD_DEFINITION: {
1242             return BuildMethodDefinition(childNode->AsMethodDefinition());
1243         }
1244         case ir::AstNodeType::ETS_NEW_CLASS_INSTANCE_EXPRESSION: {
1245             return BuildETSNewClassInstanceExpression(childNode->AsETSNewClassInstanceExpression());
1246         }
1247         case ir::AstNodeType::ETS_FUNCTION_TYPE: {
1248             return BuildSignatureDeclarationBaseParams(childNode);
1249         }
1250         case ir::AstNodeType::OBJECT_EXPRESSION: {
1251             return BuildObjectExpression(childNode->AsObjectExpression());
1252         }
1253         case ir::AstNodeType::ANNOTATION_USAGE: {
1254             return BuildAnnotationUsage(childNode->AsAnnotationUsage());
1255         }
1256         case ir::AstNodeType::ANNOTATION_DECLARATION: {
1257             BuildAnnotationDeclaration(childNode->AsAnnotationDeclaration());
1258             break;
1259         }
1260         default: {
1261             return ResolveReferences(childNode);
1262         }
1263     }
1264 }
1265 
BuildInternalName(ir::ScriptFunction * scriptFunc)1266 bool ETSBinder::BuildInternalName(ir::ScriptFunction *scriptFunc)
1267 {
1268     const bool isExternal = recordTable_->IsExternal();
1269     if (isExternal) {
1270         scriptFunc->AddFlag(ir::ScriptFunctionFlags::EXTERNAL);
1271     }
1272 
1273     if (scriptFunc->IsArrow()) {
1274         return true;
1275     }
1276 
1277     auto *funcScope = scriptFunc->Scope();
1278     funcScope->BindName(recordTable_->RecordName());
1279 
1280     bool compilable = scriptFunc->Body() != nullptr && !isExternal;
1281     if (!compilable) {
1282         recordTable_->Signatures().push_back(funcScope);
1283     }
1284 
1285     return compilable;
1286 }
1287 
BuildInternalNameWithCustomRecordTable(ir::ScriptFunction * const scriptFunc,RecordTable * const recordTable)1288 bool ETSBinder::BuildInternalNameWithCustomRecordTable(ir::ScriptFunction *const scriptFunc,
1289                                                        RecordTable *const recordTable)
1290 {
1291     const bool isExternal = recordTable->IsExternal();
1292     if (isExternal) {
1293         scriptFunc->AddFlag(ir::ScriptFunctionFlags::EXTERNAL);
1294     }
1295 
1296     if (scriptFunc->IsArrow()) {
1297         return true;
1298     }
1299 
1300     auto *const funcScope = scriptFunc->Scope();
1301     funcScope->BindName(recordTable->RecordName());
1302 
1303     const bool compilable = scriptFunc->Body() != nullptr && !isExternal;
1304     if (!compilable) {
1305         recordTable->Signatures().push_back(funcScope);
1306     }
1307 
1308     return compilable;
1309 }
1310 
AddCompilableFunction(ir::ScriptFunction * func)1311 void ETSBinder::AddCompilableFunction(ir::ScriptFunction *func)
1312 {
1313     if (func->IsArrow() || func->IsAsyncFunc()) {
1314         return;
1315     }
1316 
1317     AddCompilableFunctionScope(func->Scope());
1318 }
1319 
BuildFunctionName(const ir::ScriptFunction * func) const1320 void ETSBinder::BuildFunctionName(const ir::ScriptFunction *func) const
1321 {
1322     auto *funcScope = func->Scope();
1323 
1324     std::stringstream ss;
1325     ES2PANDA_ASSERT(func->IsArrow() || !funcScope->Name().Empty());
1326     ss << (func->IsExternalOverload() ? funcScope->InternalName() : funcScope->Name())
1327        << compiler::Signatures::METHOD_SEPARATOR;
1328 
1329     const auto *signature = func->Signature();
1330 
1331     if (func->IsStaticBlock()) {
1332         ss << compiler::Signatures::CCTOR;
1333     } else if (func->IsConstructor()) {
1334         ss << compiler::Signatures::CTOR;
1335     } else {
1336         if (func->IsGetter()) {
1337             ss << compiler::Signatures::GETTER_BEGIN;
1338         } else if (func->IsSetter()) {
1339             ss << compiler::Signatures::SETTER_BEGIN;
1340         }
1341         ss << util::Helpers::FunctionName(Allocator(), func);
1342     }
1343 
1344     signature->ToAssemblerType(ss);
1345 
1346     util::UString internalName(ss.str(), Allocator());
1347     funcScope->BindInternalName(internalName.View());
1348 }
1349 
InitImplicitThisParam()1350 void ETSBinder::InitImplicitThisParam()
1351 {
1352     thisParam_ = Allocator()->New<ir::Identifier>("this", Allocator());
1353 }
1354 
BuildProgram()1355 void ETSBinder::BuildProgram()
1356 {
1357     // A tmp solution caused by #23877, needs to check stdlib first to avoid a bug in std/math/math.ets
1358     // After the bug fixed, we can merge these 2 loop.
1359     static const std::string STD_SUFFIX = "std.";
1360     for (auto &[_, extPrograms] : Program()->ExternalSources()) {
1361         if (_.Utf8().substr(0, STD_SUFFIX.length()) == STD_SUFFIX) {
1362             for (auto *extProg : extPrograms) {
1363                 BuildExternalProgram(extProg);
1364             }
1365         }
1366     }
1367     for (auto &[_, extPrograms] : Program()->ExternalSources()) {
1368         (void)_;
1369         if (_.Utf8().substr(0, STD_SUFFIX.length()) != STD_SUFFIX) {
1370             for (auto *extProg : extPrograms) {
1371                 BuildExternalProgram(extProg);
1372             }
1373         }
1374     }
1375 
1376     for (auto *defaultImport : defaultImports_) {
1377         BuildImportDeclaration(defaultImport);
1378     }
1379 
1380     ValidateReexports();
1381 
1382     auto &stmts = Program()->Ast()->Statements();
1383     const auto etsGlobal = std::find_if(stmts.begin(), stmts.end(), [](const ir::Statement *stmt) {
1384         return stmt->IsClassDeclaration() && stmt->AsClassDeclaration()->Definition()->IsGlobal();
1385     });
1386     if (etsGlobal != stmts.end()) {
1387         const auto begin = std::find_if(stmts.rbegin(), stmts.rend(), [](const ir::Statement *stmt) {
1388                                return stmt->IsETSImportDeclaration() || stmt->IsETSPackageDeclaration();
1389                            }).base();
1390 
1391         const auto index = std::distance(begin, etsGlobal);
1392         std::rotate(begin, begin + index, begin + index + 1);
1393     }
1394 
1395     for (auto *stmt : stmts) {
1396         ResolveReference(stmt);
1397     }
1398 }
1399 
BuildExternalProgram(parser::Program * extProgram)1400 void ETSBinder::BuildExternalProgram(parser::Program *extProgram)
1401 {
1402     auto *savedProgram = Program();
1403     auto *savedRecordTable = recordTable_;
1404     auto *savedTopScope = TopScope();
1405 
1406     auto flags = Program()->VarBinder()->IsGenStdLib() || (extProgram->IsGenAbcForExternal())
1407                      ? RecordTableFlags::NONE
1408                      : RecordTableFlags::EXTERNAL;
1409     auto *extRecordTable = Allocator()->New<RecordTable>(Allocator(), extProgram, flags);
1410     externalRecordTable_.insert({extProgram, extRecordTable});
1411 
1412     ResetTopScope(extProgram->GlobalScope());
1413     recordTable_ = extRecordTable;
1414     SetProgram(extProgram);
1415 
1416     BuildProgram();
1417 
1418     SetProgram(savedProgram);
1419     recordTable_ = savedRecordTable;
1420     ResetTopScope(savedTopScope);
1421 }
1422 
BuildETSNewClassInstanceExpression(ir::ETSNewClassInstanceExpression * classInstance)1423 void ETSBinder::BuildETSNewClassInstanceExpression(ir::ETSNewClassInstanceExpression *classInstance)
1424 {
1425     ResolveReference(classInstance->GetTypeRef());
1426 
1427     for (auto *arg : classInstance->GetArguments()) {
1428         ResolveReference(arg);
1429     }
1430 }
1431 
BuildImportDeclaration(ir::ETSImportDeclaration * decl)1432 void ETSBinder::BuildImportDeclaration(ir::ETSImportDeclaration *decl)
1433 {
1434     if (!decl->IsValid()) {
1435         return;
1436     }
1437 
1438     if (decl->Source()->Str() == Program()->SourceFile().GetAbsolutePath()) {
1439         return;
1440     }
1441 
1442     const auto &specifiers = decl->Specifiers();
1443 
1444     for (auto specifier : specifiers) {
1445         AddSpecifiersToTopBindings(specifier, decl);
1446     }
1447 }
1448 
ValidateImportSpecifier(const ir::ImportSpecifier * const specifier,const ir::ETSImportDeclaration * const import)1449 Variable *ETSBinder::ValidateImportSpecifier(const ir::ImportSpecifier *const specifier,
1450                                              const ir::ETSImportDeclaration *const import)
1451 {
1452     const auto records = varbinder::GetExternalProgram(this, import);
1453     if (records.empty()) {
1454         return nullptr;
1455     }
1456 
1457     const auto *const importProgram = records.front();
1458     const auto *const importGlobalScope = importProgram->GlobalScope();
1459     const auto &globalBindings = importGlobalScope->Bindings();
1460 
1461     auto imported = specifier->Imported()->Name();
1462     for (const auto *const item : import->Specifiers()) {
1463         // Handle alias
1464         // export {foo as FOO}
1465         if (item->IsImportSpecifier() && item->AsImportSpecifier()->Local()->Name().Is(imported.Mutf8()) &&
1466             !item->AsImportSpecifier()->Local()->Name().Is(item->AsImportSpecifier()->Imported()->Name().Mutf8())) {
1467             imported = item->AsImportSpecifier()->Imported()->Name();
1468         }
1469     }
1470 
1471     auto *const var = FindImportSpecifiersVariable(imported, globalBindings, Span {records});
1472     if (var != nullptr) {
1473         return var;
1474     }
1475 
1476     // Failed to find variable, go through reexports
1477     auto [implDecl, localSpecifier] = FindImportDeclInExports(import, imported, import->Source());
1478     if (implDecl != nullptr) {
1479         return ValidateImportSpecifier(specifier, implDecl);
1480     }
1481 
1482     return nullptr;
1483 }
1484 
ValidateReexports()1485 void ETSBinder::ValidateReexports()
1486 {
1487     // This will throw syntax error if the reexport is incorrect
1488     // This will also set variables and check for ambiguous reexports
1489     for (auto *reexport : reExportImports_) {
1490         ValidateReexportDeclaration(reexport);
1491     }
1492 
1493     reexportedNames_.clear();
1494 }
1495 
ValidateReexportDeclaration(ir::ETSReExportDeclaration * decl)1496 void ETSBinder::ValidateReexportDeclaration(ir::ETSReExportDeclaration *decl)
1497 {
1498     // Reexport declarations are available in all files, see ReExportImports()
1499     // Check that reexport declaration is in this file
1500     const auto program = Program()->SourceFile().GetAbsolutePath();
1501     const auto reexportSource = os::GetAbsolutePath(decl->GetProgramPath().Utf8());
1502     if (program.Utf8() != reexportSource) {
1503         return;
1504     }
1505 
1506     const auto *const import = decl->GetETSImportDeclarations();
1507     const auto &specifiers = import->Specifiers();
1508     for (auto specifier : specifiers) {
1509         // Example: export {foo} from "./A"
1510         if (specifier->IsImportSpecifier()) {
1511             auto importSpecifier = specifier->AsImportSpecifier();
1512             const auto reexported = importSpecifier->Imported()->Name();
1513             auto *const var = ValidateImportSpecifier(importSpecifier, import);
1514             if (var == nullptr) {
1515                 ThrowError(import->Start(), diagnostic::EXPORT_INCORRECT, {reexported});
1516                 continue;
1517             }
1518 
1519             importSpecifier->Imported()->SetVariable(var);
1520             importSpecifier->Local()->SetVariable(var);
1521 
1522             // Remember reexported name to check for ambiguous reexports
1523             if (!reexportedNames_.insert(reexported).second) {
1524                 ThrowError(import->Start(), diagnostic::AMBIGUOUS_EXPORT, {reexported});
1525                 continue;
1526             }
1527         }
1528 
1529         if (specifier->IsImportNamespaceSpecifier()) {
1530             // NOTE(kkonkuznetsov): See #20658
1531             // How to validate ambiguous exports with namespace specifiers?
1532             // Example:
1533             // export * from "./A"
1534             // export * from "./B"
1535         }
1536     }
1537 }
1538 
ImportGlobalPropertiesForNotDefaultedExports(varbinder::Variable * var,const util::StringView & name,const ir::ClassElement * classElement)1539 bool ETSBinder::ImportGlobalPropertiesForNotDefaultedExports(varbinder::Variable *var, const util::StringView &name,
1540                                                              const ir::ClassElement *classElement)
1541 {
1542     ES2PANDA_ASSERT(var != nullptr);
1543     if (var->Declaration()->Node()->IsDefaultExported()) {
1544         return false;
1545     }
1546 
1547     auto variable = Program()->GlobalClassScope()->FindLocal(name, ResolveBindingOptions::ALL);
1548 
1549     bool isStdLib = util::Helpers::IsStdLib(Program());
1550     if (variable != nullptr && var != variable) {
1551         if (variable->Declaration()->IsFunctionDecl() && var->Declaration()->IsFunctionDecl()) {
1552             AddOverloadFlag(Allocator(), isStdLib, var, variable);
1553             return true;
1554         }
1555 
1556         ThrowRedeclarationError(classElement->Id()->Start(), var, variable, name.Utf8());
1557     }
1558 
1559     const auto insRes = TopScope()->InsertForeignBinding(name, var);
1560     if (!(!insRes.second && insRes.first != TopScope()->Bindings().end()) || !(insRes.first->second != var)) {
1561         return true;
1562     }
1563     if (insRes.first->second->Declaration()->IsFunctionDecl() && var->Declaration()->IsFunctionDecl()) {
1564         AddOverloadFlag(Allocator(), isStdLib, var, insRes.first->second);
1565         return true;
1566     }
1567 
1568     ThrowRedeclarationError(classElement->Id()->Start(), var, insRes.first->second, name.Utf8());
1569     return false;
1570 }
1571 
ImportGlobalProperties(const ir::ClassDefinition * const classDef)1572 void ETSBinder::ImportGlobalProperties(const ir::ClassDefinition *const classDef)
1573 {
1574     const auto scopeCtx = LexicalScope<ClassScope>::Enter(this, classDef->Scope()->AsClassScope());
1575 
1576     for (const auto *const prop : classDef->Body()) {
1577         const auto *const classElement = prop->AsClassElement();
1578 
1579         if (classElement->IsClassStaticBlock()) {
1580             continue;
1581         }
1582 
1583         ES2PANDA_ASSERT(classElement->IsStatic() && classElement->Id() != nullptr);
1584         const auto &name = classElement->Id()->Name();
1585         auto *const var = scopeCtx.GetScope()->FindLocal(name, ResolveBindingOptions::ALL);
1586         ES2PANDA_ASSERT(var != nullptr);
1587 
1588         if (ImportGlobalPropertiesForNotDefaultedExports(var, name, classElement)) {
1589             return;
1590         }
1591     }
1592 }
1593 
DynamicImportDataForVar(const Variable * var) const1594 const DynamicImportData *ETSBinder::DynamicImportDataForVar(const Variable *var) const noexcept
1595 {
1596     auto it = dynamicImportVars_.find(var);
1597     if (it == dynamicImportVars_.cend()) {
1598         return nullptr;
1599     }
1600 
1601     return &it->second;
1602 }
1603 
GetProgramList(const util::StringView & oldPath) const1604 ArenaVector<parser::Program *> ETSBinder::GetProgramList(const util::StringView &oldPath) const noexcept
1605 {
1606     auto const *globalProgram = globalRecordTable_.Program();
1607     util::StringView newPath = oldPath;
1608     if (auto it = GetContext()->dupPrograms.find(oldPath); it != GetContext()->dupPrograms.end()) {
1609         newPath = it->second->AbsoluteName();
1610     }
1611 
1612     for (const auto &extRecords : globalProgram->ExternalSources()) {
1613         for (const auto &program : extRecords.second) {
1614             if (program->AbsoluteName() == newPath) {
1615                 return extRecords.second;
1616             }
1617 
1618             // in case of importing a package folder, the path could not be resolved to a specific file
1619             if (program->IsPackage() && program->SourceFileFolder() == newPath) {
1620                 return extRecords.second;
1621             }
1622         }
1623     }
1624 
1625     if (globalProgram->IsPackage() && newPath.Compare(globalProgram->SourceFileFolder()) == 0) {
1626         return ArenaVector<parser::Program *>({GetContext()->parserProgram}, Allocator()->Adapter());
1627     }
1628 
1629     return ArenaVector<parser::Program *>(Allocator()->Adapter());
1630 }
1631 
IsDynamicModuleVariable(const Variable * var) const1632 bool ETSBinder::IsDynamicModuleVariable(const Variable *var) const noexcept
1633 {
1634     auto *data = DynamicImportDataForVar(var);
1635     if (data == nullptr) {
1636         return false;
1637     }
1638 
1639     return data->specifier->IsImportSpecifier();
1640 }
1641 
IsDynamicNamespaceVariable(const Variable * var) const1642 bool ETSBinder::IsDynamicNamespaceVariable(const Variable *var) const noexcept
1643 {
1644     auto *data = DynamicImportDataForVar(var);
1645     if (data == nullptr) {
1646         return false;
1647     }
1648 
1649     return data->specifier->IsImportNamespaceSpecifier();
1650 }
1651 
ThrowError(const lexer::SourcePosition & pos,const diagnostic::DiagnosticKind & kind,const util::DiagnosticMessageParams & params) const1652 void ETSBinder::ThrowError(const lexer::SourcePosition &pos, const diagnostic::DiagnosticKind &kind,
1653                            const util::DiagnosticMessageParams &params) const
1654 {
1655     GetContext()->diagnosticEngine->LogDiagnostic(kind, params, pos);
1656 }
1657 
IsGlobalIdentifier(const util::StringView & str) const1658 bool ETSBinder::IsGlobalIdentifier([[maybe_unused]] const util::StringView &str) const
1659 {
1660     return false;
1661 }
1662 
1663 }  // namespace ark::es2panda::varbinder
1664