• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 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 "ir/expressions/blockExpression.h"
19 #include "ir/expressions/identifier.h"
20 #include "ir/expressions/objectExpression.h"
21 #include "ir/expressions/thisExpression.h"
22 #include "ir/expressions/typeofExpression.h"
23 #include "ir/expressions/memberExpression.h"
24 #include "ir/expressions/callExpression.h"
25 #include "ir/expressions/functionExpression.h"
26 #include "ir/base/methodDefinition.h"
27 #include "ir/base/scriptFunction.h"
28 #include "ir/base/classElement.h"
29 #include "ir/base/classDefinition.h"
30 #include "ir/base/classProperty.h"
31 #include "ir/base/classStaticBlock.h"
32 #include "ir/base/decorator.h"
33 #include "ir/statements/annotationDeclaration.h"
34 #include "ir/statements/blockStatement.h"
35 #include "ir/statements/classDeclaration.h"
36 #include "ir/statements/variableDeclarator.h"
37 #include "ir/statements/functionDeclaration.h"
38 #include "ir/statements/returnStatement.h"
39 #include "ir/ets/etsPrimitiveType.h"
40 #include "ir/ets/etsTypeReferencePart.h"
41 #include "ir/ets/etsNewClassInstanceExpression.h"
42 #include "ir/ets/etsTypeReference.h"
43 #include "ir/ets/etsFunctionType.h"
44 #include "ir/ets/etsNeverType.h"
45 #include "ir/ets/etsScript.h"
46 #include "ir/ets/etsImportDeclaration.h"
47 #include "ir/ts/tsInterfaceDeclaration.h"
48 #include "ir/ts/tsTypeParameterDeclaration.h"
49 #include "ir/ts/tsTypeParameterInstantiation.h"
50 #include "ir/ts/tsClassImplements.h"
51 #include "ir/ts/tsEnumDeclaration.h"
52 #include "ir/ts/tsEnumMember.h"
53 #include "ir/ts/tsInterfaceHeritage.h"
54 #include "ir/ts/tsInterfaceBody.h"
55 #include "ir/ts/tsFunctionType.h"
56 #include "ir/ts/tsQualifiedName.h"
57 #include "ir/module/importDefaultSpecifier.h"
58 #include "ir/module/importNamespaceSpecifier.h"
59 #include "ir/module/importDeclaration.h"
60 #include "ir/module/importSpecifier.h"
61 #include "ir/expressions/literals/stringLiteral.h"
62 #include "mem/arena_allocator.h"
63 #include "os/filesystem.h"
64 #include "recordTable.h"
65 #include "util/helpers.h"
66 #include "util/ustring.h"
67 #include "checker/ETSchecker.h"
68 #include "checker/types/type.h"
69 #include "checker/types/ets/types.h"
70 #include "evaluate/scopedDebugInfoPlugin.h"
71 #include "public/public.h"
72 
73 namespace ark::es2panda::varbinder {
74 
IdentifierAnalysis()75 void ETSBinder::IdentifierAnalysis()
76 {
77     ASSERT(Program()->Ast());
78     ASSERT(GetScope() == TopScope());
79     ASSERT(VarScope() == TopScope());
80 
81     recordTable_->SetProgram(Program());
82     globalRecordTable_.SetClassDefinition(Program()->GlobalClass());
83     BuildProgram();
84 
85     ASSERT(globalRecordTable_.ClassDefinition() == Program()->GlobalClass());
86 }
87 
LookupTypeArgumentReferences(ir::ETSTypeReference * typeRef)88 void ETSBinder::LookupTypeArgumentReferences(ir::ETSTypeReference *typeRef)
89 {
90     auto *iter = typeRef->Part();
91 
92     while (iter != nullptr) {
93         if (iter->TypeParams() == nullptr) {
94             iter = iter->Previous();
95             continue;
96         }
97 
98         ResolveReferences(iter->TypeParams());
99         iter = iter->Previous();
100     }
101 }
102 
LookupTypeReference(ir::Identifier * ident,bool allowDynamicNamespaces)103 void ETSBinder::LookupTypeReference(ir::Identifier *ident, bool allowDynamicNamespaces)
104 {
105     const auto &name = ident->Name();
106     if (name == compiler::Signatures::UNDEFINED || name == compiler::Signatures::NULL_LITERAL ||
107         name == compiler::Signatures::READONLY_TYPE_NAME || name == compiler::Signatures::PARTIAL_TYPE_NAME ||
108         name == compiler::Signatures::REQUIRED_TYPE_NAME) {
109         return;
110     }
111     auto *iter = GetScope();
112 
113     while (iter != nullptr) {
114         auto res = iter->Find(name, ResolveBindingOptions::DECLARATION | ResolveBindingOptions::TYPE_ALIASES);
115         if (res.variable == nullptr) {
116             break;
117         }
118 
119         if (IsDynamicModuleVariable(res.variable)) {
120             ident->SetVariable(res.variable);
121             return;
122         }
123 
124         if (allowDynamicNamespaces && IsDynamicNamespaceVariable(res.variable)) {
125             ident->SetVariable(res.variable);
126             return;
127         }
128 
129         switch (res.variable->Declaration()->Node()->Type()) {
130             case ir::AstNodeType::CLASS_DECLARATION:
131             case ir::AstNodeType::CLASS_DEFINITION:
132             case ir::AstNodeType::STRUCT_DECLARATION:
133             case ir::AstNodeType::TS_ENUM_DECLARATION:
134             case ir::AstNodeType::TS_INTERFACE_DECLARATION:
135             case ir::AstNodeType::TS_TYPE_PARAMETER:
136             case ir::AstNodeType::TS_TYPE_ALIAS_DECLARATION:
137             case ir::AstNodeType::ANNOTATION_DECLARATION:
138             case ir::AstNodeType::IMPORT_NAMESPACE_SPECIFIER: {
139                 ident->SetVariable(res.variable);
140                 return;
141             }
142             default: {
143                 iter = iter->Parent();
144             }
145         }
146     }
147 
148     auto *checker = GetContext()->checker->AsETSChecker();
149     auto *debugInfoPlugin = checker->GetDebugInfoPlugin();
150     if (UNLIKELY(debugInfoPlugin)) {
151         auto *var = debugInfoPlugin->FindClass(ident);
152         if (var != nullptr) {
153             ident->SetVariable(var);
154             return;
155         }
156         // NOTE: search an imported module's name in case of 'import "file" as xxx'.
157     }
158 
159     ThrowUnresolvableType(ident->Start(), name);
160 }
161 
ResolveReferencesForScope(ir::AstNode const * const parent,Scope * const scope)162 void ETSBinder::ResolveReferencesForScope(ir::AstNode const *const parent, Scope *const scope)
163 {
164     parent->Iterate([this, scope](auto *node) { ResolveReferenceForScope(node, scope); });
165 }
166 
ResolveReferenceForScope(ir::AstNode * const node,Scope * const scope)167 void ETSBinder::ResolveReferenceForScope(ir::AstNode *const node, Scope *const scope)
168 {
169     switch (node->Type()) {
170         case ir::AstNodeType::IDENTIFIER: {
171             auto *ident = node->AsIdentifier();
172             if (ident->Variable() != nullptr) {
173                 break;
174             }
175             if (auto const res = scope->Find(ident->Name(), ResolveBindingOptions::ALL); res.variable != nullptr) {
176                 ident->SetVariable(res.variable);
177             }
178             break;
179         }
180         case ir::AstNodeType::VARIABLE_DECLARATOR: {
181             auto scopeCtx = LexicalScope<Scope>::Enter(this, scope);
182             BuildVarDeclarator(node->AsVariableDeclarator());
183             break;
184         }
185         /* Maybe will be used
186         case ir::AstNodeType::BLOCK_STATEMENT: {
187             auto scope_ctx = LexicalScope<Scope>::Enter(this, node->AsBlockStatement()->Scope());
188             ResolveReferences(node);
189             break;
190         }
191         */
192         case ir::AstNodeType::BLOCK_EXPRESSION: {
193             auto scopeCtx = LexicalScope<Scope>::Enter(this, node->AsBlockExpression()->Scope());
194             ResolveReferences(node);
195             break;
196         }
197         default: {
198             ResolveReferencesForScope(node, scope);
199             break;
200         }
201     }
202 }
203 
ResolveReferencesForScopeWithContext(ir::AstNode * node,Scope * scope)204 void ETSBinder::ResolveReferencesForScopeWithContext(ir::AstNode *node, Scope *scope)
205 {
206     auto lexScope = LexicalScope<Scope>::Enter(this, scope);
207     ResolveReference(node);
208 }
209 
LookupIdentReference(ir::Identifier * ident)210 void ETSBinder::LookupIdentReference(ir::Identifier *ident)
211 {
212     const auto &name = ident->Name();
213     auto res = GetScope()->Find(name, ResolveBindingOptions::ALL);
214     if (res.level != 0) {
215         ASSERT(res.variable != nullptr);
216 
217         auto *outerFunction = GetScope()->EnclosingVariableScope()->Node();
218 
219         if ((!outerFunction->IsScriptFunction() || !outerFunction->AsScriptFunction()->IsArrow()) &&
220             !res.variable->IsGlobalVariable() && res.variable->HasFlag(VariableFlags::LOCAL) && res.level > 1) {
221             ThrowInvalidCapture(ident->Start(), name);
222         }
223     }
224 
225     if (res.variable == nullptr) {
226         return;
227     }
228 
229     if (ident->IsReference(Extension()) && res.variable->Declaration()->IsLetOrConstDecl() &&
230         !res.variable->HasFlag(VariableFlags::INITIALIZED)) {
231         ThrowTDZ(ident->Start(), name);
232     }
233 }
234 
BuildClassProperty(const ir::ClassProperty * prop)235 void ETSBinder::BuildClassProperty(const ir::ClassProperty *prop)
236 {
237     ResolveReferences(prop);
238 }
239 
BuildETSTypeReference(ir::ETSTypeReference * typeRef)240 void ETSBinder::BuildETSTypeReference(ir::ETSTypeReference *typeRef)
241 {
242     auto *baseName = typeRef->BaseName();
243     ASSERT(baseName->IsReference(Extension()));
244 
245     // We allow to resolve following types in pure dynamic mode:
246     // import * as I from "@dynamic"
247     // let x : I.X.Y
248     bool allowDynamicNamespaces = typeRef->Part()->Name() != baseName;
249     LookupTypeReference(baseName, allowDynamicNamespaces);
250     LookupTypeArgumentReferences(typeRef);
251 }
252 
BuildObjectExpression(ir::ObjectExpression * obj)253 void ETSBinder::BuildObjectExpression(ir::ObjectExpression *obj)
254 {
255     for (auto *it : obj->Decorators()) {
256         ResolveReference(it);
257     }
258 
259     // NOTE: when we try to resolve references for Object Expression
260     // we visit properties, example:
261     // class C { x : boolean }
262     // let x: C = { x: true }
263     //
264     // However we visit Object Expression with _outer_ scope, not class scope.
265     // That means that varbinder will try to resolve `x` as `x` from outer scope, _not from the class scope_.
266     // The following code will skip resolving LHS of the property.
267     // We can do it because currently LHS is still checked in the `ETSAnalyzer::CheckObjectExprProps` function.
268     for (auto expr : obj->Properties()) {
269         if (expr->IsProperty()) {
270             auto *prop = expr->AsProperty();
271             ResolveReference(prop->Value());
272         }
273     }
274 
275     if (obj->TypeAnnotation() != nullptr) {
276         ResolveReference(obj->TypeAnnotation());
277     }
278 }
279 
InitializeInterfaceIdent(ir::TSInterfaceDeclaration * decl)280 void ETSBinder::InitializeInterfaceIdent(ir::TSInterfaceDeclaration *decl)
281 {
282     auto res = GetScope()->Find(decl->Id()->Name());
283 
284     ASSERT(res.variable && res.variable->Declaration()->IsInterfaceDecl());
285     res.variable->AddFlag(VariableFlags::INITIALIZED);
286     decl->Id()->SetVariable(res.variable);
287 }
288 
ResolveEnumDeclaration(ir::TSEnumDeclaration * enumDecl)289 void ETSBinder::ResolveEnumDeclaration(ir::TSEnumDeclaration *enumDecl)
290 {
291     auto enumScopeCtx = LexicalScope<LocalScope>::Enter(this, enumDecl->Scope());
292 
293     for (auto *member : enumDecl->Members()) {
294         ResolveReference(member);
295     }
296 }
297 
ResolveInterfaceDeclaration(ir::TSInterfaceDeclaration * decl)298 void ETSBinder::ResolveInterfaceDeclaration(ir::TSInterfaceDeclaration *decl)
299 {
300     auto boundCtx = BoundContext(recordTable_, decl);
301 
302     for (auto *extend : decl->Extends()) {
303         ResolveReference(extend);
304     }
305 
306     auto scopeCtx = LexicalScope<ClassScope>::Enter(this, decl->Scope()->AsClassScope());
307 
308     for (auto *stmt : decl->Body()->Body()) {
309         if (!stmt->IsClassProperty()) {
310             continue;
311         }
312 
313         ResolveReference(stmt);
314 
315         auto fieldVar =
316             ResolvePropertyReference(stmt->AsClassProperty(), decl->Scope()->AsClassScope())
317                 ->FindLocal(stmt->AsClassProperty()->Id()->Name(), varbinder::ResolveBindingOptions::BINDINGS);
318         fieldVar->AddFlag(VariableFlags::INITIALIZED);
319     }
320 
321     for (auto *stmt : decl->Body()->Body()) {
322         if (stmt->IsClassProperty()) {
323             continue;
324         }
325         ResolveReference(stmt);
326     }
327 }
328 
BuildInterfaceDeclaration(ir::TSInterfaceDeclaration * decl)329 void ETSBinder::BuildInterfaceDeclaration(ir::TSInterfaceDeclaration *decl)
330 {
331     if (decl->TypeParams() != nullptr) {
332         auto typeParamScopeCtx = LexicalScope<LocalScope>::Enter(this, decl->TypeParams()->Scope());
333         ResolveReferences(decl->TypeParams());
334         ResolveInterfaceDeclaration(decl);
335         return;
336     }
337 
338     ResolveInterfaceDeclaration(decl);
339 }
340 
BuildMethodDefinition(ir::MethodDefinition * methodDef)341 void ETSBinder::BuildMethodDefinition(ir::MethodDefinition *methodDef)
342 {
343     if (methodDef->Function()->TypeParams() != nullptr) {
344         auto scopeCtx = LexicalScope<LocalScope>::Enter(this, methodDef->Function()->TypeParams()->Scope());
345         ResolveReferences(methodDef->Function()->TypeParams());
346     }
347     ResolveMethodDefinition(methodDef);
348 }
349 
BuildAnnotationDeclaration(ir::AnnotationDeclaration * annoDecl)350 void ETSBinder::BuildAnnotationDeclaration(ir::AnnotationDeclaration *annoDecl)
351 {
352     auto boundCtx = BoundContext(recordTable_, annoDecl);
353     if (annoDecl->Expr()->IsIdentifier()) {
354         LookupTypeReference(annoDecl->AsAnnotationDeclaration()->Expr()->AsIdentifier(), false);
355     } else {
356         ResolveReference(annoDecl->Expr());
357     }
358     auto scopeCtx = LexicalScope<LocalScope>::Enter(this, annoDecl->Scope());
359     for (auto *property : annoDecl->Properties()) {
360         ResolveReference(property);
361     }
362 }
363 
BuildAnnotationUsage(ir::AnnotationUsage * annoUsage)364 void ETSBinder::BuildAnnotationUsage(ir::AnnotationUsage *annoUsage)
365 {
366     if (annoUsage->Expr()->IsIdentifier()) {
367         LookupTypeReference(annoUsage->AsAnnotationUsage()->Expr()->AsIdentifier(), false);
368     } else {
369         ResolveReference(annoUsage->Expr());
370     }
371 
372     for (auto *property : annoUsage->Properties()) {
373         ResolveReference(property);
374     }
375 }
376 
ResolveMethodDefinition(ir::MethodDefinition * methodDef)377 void ETSBinder::ResolveMethodDefinition(ir::MethodDefinition *methodDef)
378 {
379     methodDef->ResolveReferences([this](auto *childNode) { ResolveReference(childNode); });
380 
381     auto *func = methodDef->Function();
382     for (auto *anno : func->Annotations()) {
383         ResolveReference(anno);
384     }
385     if (methodDef->IsStatic() || func->IsStaticBlock()) {
386         return;
387     }
388 
389     auto paramScopeCtx = LexicalScope<FunctionParamScope>::Enter(this, func->Scope()->ParamScope());
390 
391     auto params = func->Scope()->ParamScope()->Params();
392     if (!params.empty() && params.front()->Name() == MANDATORY_PARAM_THIS) {
393         return;  // Implicit this parameter is already inserted by ResolveReferences(), don't insert it twice.
394     }
395 
396     auto *thisParam = AddMandatoryParam(MANDATORY_PARAM_THIS);
397     thisParam->Declaration()->BindNode(thisParam_);
398 }
399 
BuildMemberExpression(ir::MemberExpression * memberExpr)400 void ETSBinder::BuildMemberExpression(ir::MemberExpression *memberExpr)
401 {
402     ResolveReference(memberExpr->Object());
403 
404     if (memberExpr->Kind() == ir::MemberExpressionKind::ELEMENT_ACCESS) {
405         ResolveReference(memberExpr->Property());
406     }
407 }
408 
BuildClassDefinition(ir::ClassDefinition * classDef)409 void ETSBinder::BuildClassDefinition(ir::ClassDefinition *classDef)
410 {
411     auto boundCtx = BoundContext(recordTable_, classDef);
412 
413     if (classDef->TypeParams() != nullptr) {
414         auto scopeCtx = LexicalScope<LocalScope>::Enter(this, classDef->TypeParams()->Scope());
415         ResolveReferences(classDef->TypeParams());
416         BuildClassDefinitionImpl(classDef);
417         return;
418     }
419 
420     BuildClassDefinitionImpl(classDef);
421 }
422 
ResolvePropertyReference(ir::ClassProperty * prop,ClassScope * scope)423 LocalScope *ETSBinder::ResolvePropertyReference(ir::ClassProperty *prop, ClassScope *scope)
424 {
425     ResolveReferences(prop);
426 
427     if (prop->IsStatic()) {
428         return scope->StaticFieldScope();
429     }
430 
431     return scope->InstanceFieldScope();
432 }
433 
BuildClassDefinitionImpl(ir::ClassDefinition * classDef)434 void ETSBinder::BuildClassDefinitionImpl(ir::ClassDefinition *classDef)
435 {
436     auto classCtx = LexicalScope<ClassScope>::Enter(this, classDef->Scope()->AsClassScope());
437 
438     if (classDef->Super() != nullptr) {
439         ResolveReference(classDef->Super());
440     }
441 
442     for (auto *impl : classDef->Implements()) {
443         ResolveReference(impl);
444     }
445     for (auto *anno : classDef->Annotations()) {
446         ResolveReference(anno);
447     }
448 
449     for (auto *stmt : classDef->Body()) {
450         if (!stmt->IsClassProperty()) {
451             continue;
452         }
453 
454         auto fieldScope = ResolvePropertyReference(stmt->AsClassProperty(), classDef->Scope()->AsClassScope());
455         auto fieldName = stmt->AsClassProperty()->Id()->Name();
456         auto fieldVar = fieldScope->FindLocal(fieldName, varbinder::ResolveBindingOptions::BINDINGS);
457         fieldVar->AddFlag(VariableFlags::INITIALIZED);
458         if ((fieldVar->Declaration()->IsConstDecl() || fieldVar->Declaration()->IsReadonlyDecl()) &&
459             stmt->AsClassProperty()->Value() == nullptr) {
460             fieldVar->AddFlag(VariableFlags::EXPLICIT_INIT_REQUIRED);
461         }
462     }
463 
464     for (auto *stmt : classDef->Body()) {
465         if (stmt->IsClassProperty()) {
466             continue;
467         }
468         ResolveReference(stmt);
469     }
470 }
471 
AddFunctionThisParam(ir::ScriptFunction * func)472 void ETSBinder::AddFunctionThisParam(ir::ScriptFunction *func)
473 {
474     auto paramScopeCtx = LexicalScope<FunctionParamScope>::Enter(this, func->Scope()->ParamScope());
475     auto *thisParam = AddMandatoryParam(MANDATORY_PARAM_THIS);
476     thisParam->Declaration()->BindNode(thisParam_);
477 }
478 
BuildProxyMethod(ir::ScriptFunction * func,const util::StringView & containingClassName,bool isExternal)479 void ETSBinder::BuildProxyMethod(ir::ScriptFunction *func, const util::StringView &containingClassName, bool isExternal)
480 {
481     ASSERT(!containingClassName.Empty());
482     func->Scope()->BindName(containingClassName);
483 
484     if (!func->IsAsyncFunc() && !isExternal) {
485         Functions().push_back(func->Scope());
486     }
487 }
488 
AddDynamicSpecifiersToTopBindings(ir::AstNode * const specifier,const ir::ETSImportDeclaration * const import)489 void ETSBinder::AddDynamicSpecifiersToTopBindings(ir::AstNode *const specifier,
490                                                   const ir::ETSImportDeclaration *const import)
491 {
492     const auto name = [specifier]() {
493         if (specifier->IsImportNamespaceSpecifier()) {
494             return specifier->AsImportNamespaceSpecifier()->Local()->Name();
495         }
496 
497         return specifier->AsImportSpecifier()->Local()->Name();
498     }();
499 
500     ASSERT(GetScope()->Find(name, ResolveBindingOptions::DECLARATION).variable != nullptr);
501     auto specDecl = GetScope()->Find(name, ResolveBindingOptions::DECLARATION);
502     dynamicImportVars_.emplace(specDecl.variable, DynamicImportData {import, specifier, specDecl.variable});
503 
504     if (specifier->IsImportSpecifier()) {
505         auto importSpecifier = specifier->AsImportSpecifier();
506         importSpecifier->Imported()->SetVariable(specDecl.variable);
507         importSpecifier->Local()->SetVariable(specDecl.variable);
508     }
509 }
510 
InsertForeignBinding(ir::AstNode * const specifier,const ir::ETSImportDeclaration * const import,const util::StringView & name,Variable * var)511 void ETSBinder::InsertForeignBinding(ir::AstNode *const specifier, const ir::ETSImportDeclaration *const import,
512                                      const util::StringView &name, Variable *var)
513 {
514     if (import->Language().IsDynamic()) {
515         dynamicImportVars_.emplace(var, DynamicImportData {import, specifier, var});
516     }
517 
518     TopScope()->InsertForeignBinding(name, var);
519 }
520 
RedeclarationErrorMessageAssembler(const Variable * const var,const Variable * const variable,util::StringView localName)521 std::string RedeclarationErrorMessageAssembler(const Variable *const var, const Variable *const variable,
522                                                util::StringView localName)
523 {
524     auto type = var->Declaration()->Node()->IsClassDefinition() ? "Class '"
525                 : var->Declaration()->IsFunctionDecl()          ? "Function '"
526                                                                 : "Variable '";
527     auto str = util::Helpers::AppendAll(type, localName.Utf8(), "'");
528     str += variable->Declaration()->Type() == var->Declaration()->Type() ? " is already defined."
529                                                                          : " is already defined with different type.";
530 
531     return str;
532 }
533 
GetPackageName(varbinder::Variable * var)534 static const util::StringView &GetPackageName(varbinder::Variable *var)
535 {
536     Scope *scope = var->GetScope();
537 
538     while (scope->Parent() != nullptr) {
539         scope = scope->Parent();
540     }
541 
542     ASSERT(scope->Node()->IsETSScript());
543 
544     return scope->Node()->AsETSScript()->Program()->ModuleName();
545 }
546 
AddOverloadFlag(ArenaAllocator * allocator,bool isStdLib,varbinder::Variable * importedVar,varbinder::Variable * variable)547 void AddOverloadFlag(ArenaAllocator *allocator, bool isStdLib, varbinder::Variable *importedVar,
548                      varbinder::Variable *variable)
549 {
550     auto *const currentNode = variable->Declaration()->Node()->AsMethodDefinition();
551     auto *const method = importedVar->Declaration()->Node()->AsMethodDefinition();
552 
553     // Necessary because stdlib and escompat handled as same package, it can be removed after fixing package handling
554     if (isStdLib && (GetPackageName(importedVar) != GetPackageName(variable))) {
555         return;
556     }
557 
558     if (!method->Overloads().empty() && !method->HasOverload(currentNode)) {
559         method->AddOverload(currentNode);
560         currentNode->Function()->Id()->SetVariable(importedVar);
561         currentNode->Function()->AddFlag(ir::ScriptFunctionFlags::OVERLOAD);
562         currentNode->Function()->AddFlag(ir::ScriptFunctionFlags::EXTERNAL_OVERLOAD);
563         util::UString newInternalName(currentNode->Function()->Scope()->Name(), allocator);
564         currentNode->Function()->Scope()->BindInternalName(newInternalName.View());
565         return;
566     }
567 
568     if (!currentNode->HasOverload(method)) {
569         currentNode->AddOverload(method);
570         method->Function()->Id()->SetVariable(variable);
571         method->Function()->AddFlag(ir::ScriptFunctionFlags::OVERLOAD);
572         method->Function()->AddFlag(ir::ScriptFunctionFlags::EXTERNAL_OVERLOAD);
573         util::UString newInternalName(method->Function()->Scope()->Name(), allocator);
574         method->Function()->Scope()->BindInternalName(newInternalName.View());
575     }
576 }
577 
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)578 void ETSBinder::ImportAllForeignBindings(ir::AstNode *const specifier,
579                                          const varbinder::Scope::VariableMap &globalBindings,
580                                          const parser::Program *const importProgram,
581                                          const varbinder::GlobalScope *const importGlobalScope,
582                                          const ir::ETSImportDeclaration *const import)
583 {
584     for (const auto [bindingName, var] : globalBindings) {
585         if (bindingName.Is(compiler::Signatures::ETS_GLOBAL)) {
586             const auto *const classDef = var->Declaration()->Node()->AsClassDeclaration()->Definition();
587             ImportGlobalProperties(classDef);
588             continue;
589         }
590 
591         if (!importGlobalScope->IsForeignBinding(bindingName) && !var->Declaration()->Node()->IsDefaultExported() &&
592             (var->AsLocalVariable()->Declaration()->Node()->IsExported() ||
593              var->AsLocalVariable()->Declaration()->Node()->IsExportedType())) {
594             auto variable = Program()->GlobalClassScope()->FindLocal(bindingName, ResolveBindingOptions::ALL);
595             if (variable != nullptr && var != variable && variable->Declaration()->IsFunctionDecl() &&
596                 var->Declaration()->IsFunctionDecl()) {
597                 bool isStdLib = util::Helpers::IsStdLib(Program());
598                 AddOverloadFlag(Allocator(), isStdLib, var, variable);
599                 continue;
600             }
601             if (variable != nullptr && var != variable) {
602                 ThrowError(import->Source()->Start(), RedeclarationErrorMessageAssembler(var, variable, bindingName));
603             }
604             InsertForeignBinding(specifier, import, bindingName, var);
605         }
606     }
607 
608     for (const auto [bindingName, var] : importProgram->GlobalClassScope()->StaticMethodScope()->Bindings()) {
609         if (!var->Declaration()->Node()->IsDefaultExported()) {
610             InsertForeignBinding(specifier, import, bindingName, var);
611         }
612     }
613 
614     for (const auto [bindingName, var] : importProgram->GlobalClassScope()->StaticFieldScope()->Bindings()) {
615         if (!var->Declaration()->Node()->IsDefaultExported()) {
616             InsertForeignBinding(specifier, import, bindingName, var);
617         }
618     }
619 }
620 
ReexportPathMatchesImportPath(const ir::ETSReExportDeclaration * const reexport,const ir::ETSImportDeclaration * const import) const621 bool ETSBinder::ReexportPathMatchesImportPath(const ir::ETSReExportDeclaration *const reexport,
622                                               const ir::ETSImportDeclaration *const import) const
623 {
624     auto importSource = import->ResolvedSource()->Str();
625     auto reexportSource = reexport->GetProgramPath();
626     return importSource == reexportSource;
627 }
628 
AddImportNamespaceSpecifiersToTopBindings(ir::AstNode * const specifier,const varbinder::Scope::VariableMap & globalBindings,const parser::Program * const importProgram,const varbinder::GlobalScope * const importGlobalScope,const ir::ETSImportDeclaration * const import)629 bool ETSBinder::AddImportNamespaceSpecifiersToTopBindings(ir::AstNode *const specifier,
630                                                           const varbinder::Scope::VariableMap &globalBindings,
631                                                           const parser::Program *const importProgram,
632                                                           const varbinder::GlobalScope *const importGlobalScope,
633                                                           const ir::ETSImportDeclaration *const import)
634 {
635     if (!specifier->IsImportNamespaceSpecifier()) {
636         return false;
637     }
638     const auto *const namespaceSpecifier = specifier->AsImportNamespaceSpecifier();
639 
640     if (namespaceSpecifier->Local()->Name().Empty()) {
641         ImportAllForeignBindings(specifier, globalBindings, importProgram, importGlobalScope, import);
642     }
643 
644     for (auto item : ReExportImports()) {
645         // NOTE(rsipka): this should be refactored or eliminated
646         if (!ReexportPathMatchesImportPath(item, import)) {
647             continue;
648         }
649 
650         for (auto it : item->GetETSImportDeclarations()->Specifiers()) {
651             if (it->IsImportNamespaceSpecifier() && !namespaceSpecifier->Local()->Name().Empty()) {
652                 continue;
653             }
654 
655             AddSpecifiersToTopBindings(it, item->GetETSImportDeclarations(),
656                                        item->GetETSImportDeclarations()->Source());
657         }
658     }
659 
660     return true;
661 }
662 
FindImportSpecifiersVariable(const util::StringView & imported,const varbinder::Scope::VariableMap & globalBindings,const ArenaVector<parser::Program * > & recordRes)663 Variable *ETSBinder::FindImportSpecifiersVariable(const util::StringView &imported,
664                                                   const varbinder::Scope::VariableMap &globalBindings,
665                                                   const ArenaVector<parser::Program *> &recordRes)
666 {
667     auto foundVar = globalBindings.find(imported);
668     if (foundVar == globalBindings.end()) {
669         const auto &staticMethodBindings = recordRes.front()->GlobalClassScope()->StaticMethodScope()->Bindings();
670         foundVar = staticMethodBindings.find(imported);
671         if (foundVar != staticMethodBindings.end()) {
672             return foundVar->second;
673         }
674         bool found = false;
675         for (auto res : recordRes) {
676             const auto &staticFieldBindings = res->GlobalClassScope()->StaticFieldScope()->Bindings();
677             foundVar = staticFieldBindings.find(imported);
678             if (foundVar != staticFieldBindings.end()) {
679                 found = true;
680                 foundVar->second->AsLocalVariable()->AddFlag(VariableFlags::INITIALIZED);
681                 break;
682             }
683         }
684         if (!found) {
685             return nullptr;
686         }
687     }
688 
689     return foundVar->second;
690 }
691 
FindImportDeclInReExports(const ir::ETSImportDeclaration * const import,std::vector<ir::ETSImportDeclaration * > & viewedReExport,const util::StringView & imported,const ir::StringLiteral * const importPath)692 ir::ETSImportDeclaration *ETSBinder::FindImportDeclInReExports(const ir::ETSImportDeclaration *const import,
693                                                                std::vector<ir::ETSImportDeclaration *> &viewedReExport,
694                                                                const util::StringView &imported,
695                                                                const ir::StringLiteral *const importPath)
696 {
697     ir::ETSImportDeclaration *implDecl = nullptr;
698     for (auto item : ReExportImports()) {
699         if (!ReexportPathMatchesImportPath(item, import)) {
700             continue;
701         }
702 
703         viewedReExport.push_back(item->GetETSImportDeclarations());
704 
705         auto specifiers = item->GetETSImportDeclarations()->Specifiers();
706         if (specifiers[0]->IsImportSpecifier()) {
707             if (!std::any_of(specifiers.begin(), specifiers.end(), [&imported](auto it) {
708                     return it->AsImportSpecifier()->Local()->Name().Is(imported.Mutf8());
709                 })) {
710                 continue;
711             }
712             implDecl = item->GetETSImportDeclarations();
713         } else {
714             ArenaVector<parser::Program *> record =
715                 GetExternalProgram(item->GetETSImportDeclarations()->ResolvedSource()->Str(), importPath);
716             auto *const var = FindImportSpecifiersVariable(imported, record.front()->GlobalScope()->Bindings(), record);
717             if (var != nullptr) {
718                 implDecl = item->GetETSImportDeclarations();
719                 continue;
720             }
721             auto reExportImport = item->GetETSImportDeclarations();
722             auto reExportImportPath = reExportImport->Source();
723             auto implDeclOrNullptr =
724                 FindImportDeclInReExports(reExportImport, viewedReExport, imported, reExportImportPath);
725             if (implDeclOrNullptr != nullptr) {
726                 implDecl = implDeclOrNullptr;
727             }
728         }
729     }
730     return implDecl;
731 }
732 
ValidateImportVariable(varbinder::Variable * const var,const ir::ETSImportDeclaration * const import,const util::StringView & imported,const ir::StringLiteral * const importPath)733 void ETSBinder::ValidateImportVariable(varbinder::Variable *const var, const ir::ETSImportDeclaration *const import,
734                                        const util::StringView &imported, const ir::StringLiteral *const importPath)
735 {
736     if (var->Declaration()->Node()->IsDefaultExported()) {
737         ThrowError(importPath->Start(), "Use the default import syntax to import a default exported element");
738     }
739 
740     if (import->IsTypeKind() && !var->Declaration()->Node()->IsExportedType()) {
741         ThrowError(importPath->Start(),
742                    "Cannot import '" + imported.Mutf8() + "', imported type imports only exported types.");
743     }
744 
745     if (!var->Declaration()->Node()->IsExported() && !var->Declaration()->Node()->IsExportedType()) {
746         ThrowError(importPath->Start(), "Imported element not exported '" + var->Declaration()->Name().Mutf8() + "'");
747     }
748 }
749 
ImportLocalName(const ir::ImportSpecifier * importSpecifier,const ir::StringLiteral * importPath,util::StringView imported,ArenaVector<std::pair<util::StringView,util::StringView>> & importSpecifiers,GlobalScope * topScope)750 static util::StringView ImportLocalName(const ir::ImportSpecifier *importSpecifier, const ir::StringLiteral *importPath,
751                                         util::StringView imported,
752                                         ArenaVector<std::pair<util::StringView, util::StringView>> &importSpecifiers,
753                                         GlobalScope *topScope)
754 {
755     if (importSpecifier->Local() != nullptr) {
756         auto fnc = [&importPath, &imported](const auto &savedSpecifier) {
757             return importPath->Str() != savedSpecifier.first && imported == savedSpecifier.second;
758         };
759         if (!std::any_of(importSpecifiers.begin(), importSpecifiers.end(), fnc)) {
760             topScope->EraseBinding(imported);
761         }
762 
763         importSpecifiers.push_back(std::make_pair(importPath->Str(), imported));
764 
765         return importSpecifier->Local()->Name();
766     }
767 
768     return imported;
769 }
770 
DetectNameConflict(const util::StringView localName,Variable * const var,Variable * const otherVar,const ir::StringLiteral * const importPath,bool overloadAllowed)771 bool ETSBinder::DetectNameConflict(const util::StringView localName, Variable *const var, Variable *const otherVar,
772                                    const ir::StringLiteral *const importPath, bool overloadAllowed)
773 {
774     if (otherVar == nullptr || var == otherVar) {
775         return false;
776     }
777 
778     if (overloadAllowed && var->Declaration()->IsFunctionDecl() && otherVar->Declaration()->IsFunctionDecl()) {
779         AddOverloadFlag(Allocator(), util::Helpers::IsStdLib(Program()), var, otherVar);
780         return true;
781     }
782 
783     bool isAmbient = var->Declaration()->Node()->IsDeclare() && !otherVar->Declaration()->Node()->IsDeclare();
784     if (isAmbient) {
785         return false;
786     }
787 
788     ThrowError(importPath->Start(), RedeclarationErrorMessageAssembler(var, otherVar, localName));
789 }
790 
AddImportSpecifiersToTopBindings(ir::AstNode * const specifier,const varbinder::Scope::VariableMap & globalBindings,const ir::ETSImportDeclaration * const import,const ArenaVector<parser::Program * > & recordRes,std::vector<ir::ETSImportDeclaration * > viewedReExport)791 bool ETSBinder::AddImportSpecifiersToTopBindings(ir::AstNode *const specifier,
792                                                  const varbinder::Scope::VariableMap &globalBindings,
793                                                  const ir::ETSImportDeclaration *const import,
794                                                  const ArenaVector<parser::Program *> &recordRes,
795                                                  std::vector<ir::ETSImportDeclaration *> viewedReExport)
796 {
797     if (!specifier->IsImportSpecifier()) {
798         return false;
799     }
800     const ir::StringLiteral *const importPath = import->Source();
801 
802     auto importSpecifier = specifier->AsImportSpecifier();
803     if (!importSpecifier->Imported()->IsIdentifier()) {
804         return true;
805     }
806 
807     auto imported = importSpecifier->Imported()->Name();
808 
809     for (auto const item : import->Specifiers()) {
810         if (item->IsImportSpecifier() && item->AsImportSpecifier()->Local()->Name().Is(imported.Mutf8()) &&
811             !item->AsImportSpecifier()->Local()->Name().Is(item->AsImportSpecifier()->Imported()->Name().Mutf8())) {
812             imported = item->AsImportSpecifier()->Imported()->Name();
813         }
814     }
815 
816     util::StringView nameToSearchFor = FindNameInAliasMap(import->ResolvedSource()->Str(), imported);
817     if (nameToSearchFor.Empty()) {
818         nameToSearchFor = imported;
819     }
820 
821     auto *const var = FindImportSpecifiersVariable(nameToSearchFor, globalBindings, recordRes);
822     importSpecifier->Imported()->SetVariable(var);
823     importSpecifier->Local()->SetVariable(var);
824 
825     const auto localName = ImportLocalName(importSpecifier, importPath, imported, importSpecifiers_, TopScope());
826 
827     if (var == nullptr) {
828         ir::ETSImportDeclaration *implDecl = FindImportDeclInReExports(import, viewedReExport, imported, importPath);
829         if (implDecl != nullptr) {
830             AddSpecifiersToTopBindings(specifier, implDecl, implDecl->Source(), viewedReExport);
831             return true;
832         }
833 
834         ThrowError(importPath->Start(), "Cannot find imported element '" + imported.Mutf8() + "'");
835     }
836 
837     ValidateImportVariable(var, import, imported, importPath);
838 
839     auto varInGlobalClassScope = Program()->GlobalClassScope()->FindLocal(localName, ResolveBindingOptions::ALL);
840     auto previouslyImportedVariable = TopScope()->FindLocal(localName, ResolveBindingOptions::ALL);
841     if (DetectNameConflict(localName, var, varInGlobalClassScope, importPath, true) ||
842         DetectNameConflict(localName, var, previouslyImportedVariable, importPath, false)) {
843         return true;
844     }
845 
846     if (var->Declaration()->Node()->IsAnnotationDeclaration() &&
847         var->Declaration()->Node()->AsAnnotationDeclaration()->GetBaseName()->Name() != localName) {
848         ThrowError(importPath->Start(), "Can not rename annotation '" + var->Declaration()->Name().Mutf8() +
849                                             "' in export or import statements.");
850     }
851 
852     // The first part of the condition will be true, if something was given an alias when exported, but we try
853     // to import it using its original name.
854     if (nameToSearchFor == imported && var->Declaration()->Node()->HasExportAlias()) {
855         ThrowError(specifier->Start(), "Cannot find imported element '" + imported.Mutf8() + "'");
856     }
857 
858     InsertForeignBinding(specifier, import, localName, var);
859     return true;
860 }
861 
FindStaticBinding(const ArenaVector<parser::Program * > & recordRes,const ir::StringLiteral * const importPath)862 varbinder::Variable *ETSBinder::FindStaticBinding(const ArenaVector<parser::Program *> &recordRes,
863                                                   const ir::StringLiteral *const importPath)
864 {
865     auto predicateFunc = [](const auto &item) { return item.second->Declaration()->Node()->IsDefaultExported(); };
866     const auto &staticMethodBindings = recordRes.front()->GlobalClassScope()->StaticMethodScope()->Bindings();
867     auto result = std::find_if(staticMethodBindings.begin(), staticMethodBindings.end(), predicateFunc);
868     if (result == staticMethodBindings.end()) {
869         const auto &staticFieldBindings = recordRes.front()->GlobalClassScope()->StaticFieldScope()->Bindings();
870         result = std::find_if(staticFieldBindings.begin(), staticFieldBindings.end(), predicateFunc);
871         if (result == staticFieldBindings.end()) {
872             ThrowError(importPath->Start(), "Cannot find default imported element in the target");
873         }
874     }
875     return result->second;
876 }
877 
GetExternalProgram(const util::StringView & sourceName,const ir::StringLiteral * importPath)878 ArenaVector<parser::Program *> ETSBinder::GetExternalProgram(const util::StringView &sourceName,
879                                                              const ir::StringLiteral *importPath)
880 {
881     // NOTE: quick fix to make sure not to look for the global program among the external sources
882     if (sourceName.Compare(globalRecordTable_.Program()->AbsoluteName()) == 0) {
883         ArenaVector<parser::Program *> mainModule(Allocator()->Adapter());
884         mainModule.emplace_back(globalRecordTable_.Program());
885         return mainModule;
886     }
887 
888     auto programList = GetProgramList(sourceName);
889     if (programList.empty()) {
890         // NOTE(rsipka): it is not clear that an error should be thrown in these cases
891         if (ark::os::file::File::IsDirectory(sourceName.Mutf8())) {
892             ThrowError(importPath->Start(),
893                        "Cannot find index.[sts|ts] or package module in folder: " + importPath->Str().Mutf8());
894         }
895 
896         ThrowError(importPath->Start(), "Cannot find import: " + importPath->Str().Mutf8());
897     }
898 
899     return programList;
900 }
901 
AddSpecifiersToTopBindings(ir::AstNode * const specifier,const ir::ETSImportDeclaration * const import,ir::StringLiteral * path,std::vector<ir::ETSImportDeclaration * > viewedReExport)902 void ETSBinder::AddSpecifiersToTopBindings(ir::AstNode *const specifier, const ir::ETSImportDeclaration *const import,
903                                            ir::StringLiteral *path,
904                                            std::vector<ir::ETSImportDeclaration *> viewedReExport)
905 {
906     const ir::StringLiteral *const importPath = path;
907 
908     if (import->IsPureDynamic()) {
909         AddDynamicSpecifiersToTopBindings(specifier, import);
910         return;
911     }
912 
913     const util::StringView sourceName = import->ResolvedSource()->Str();
914 
915     auto record = GetExternalProgram(sourceName, importPath);
916     const auto *const importProgram = record.front();
917     const auto *const importGlobalScope = importProgram->GlobalScope();
918     const auto &globalBindings = importGlobalScope->Bindings();
919 
920     if (AddImportNamespaceSpecifiersToTopBindings(specifier, globalBindings, importProgram, importGlobalScope,
921                                                   import) ||
922         AddImportSpecifiersToTopBindings(specifier, globalBindings, import, record, std::move(viewedReExport))) {
923         return;
924     }
925 
926     ASSERT(specifier->IsImportDefaultSpecifier());
927     auto predicateFunc = [](const auto &item) { return item.second->Declaration()->Node()->IsDefaultExported(); };
928 
929     auto item = std::find_if(globalBindings.begin(), globalBindings.end(), predicateFunc);
930     if (item == globalBindings.end()) {
931         auto var = FindStaticBinding(record, importPath);
932         specifier->AsImportDefaultSpecifier()->Local()->SetVariable(var);
933         InsertForeignBinding(specifier, import, specifier->AsImportDefaultSpecifier()->Local()->Name(), var);
934         return;
935     }
936 
937     specifier->AsImportDefaultSpecifier()->Local()->SetVariable(item->second);
938     InsertForeignBinding(specifier, import, specifier->AsImportDefaultSpecifier()->Local()->Name(), item->second);
939 }
940 
HandleCustomNodes(ir::AstNode * childNode)941 void ETSBinder::HandleCustomNodes(ir::AstNode *childNode)
942 {
943     switch (childNode->Type()) {
944         case ir::AstNodeType::ETS_TYPE_REFERENCE: {
945             return BuildETSTypeReference(childNode->AsETSTypeReference());
946         }
947         case ir::AstNodeType::TS_INTERFACE_DECLARATION: {
948             return BuildInterfaceDeclaration(childNode->AsTSInterfaceDeclaration());
949         }
950         case ir::AstNodeType::TS_ENUM_DECLARATION: {
951             return ResolveEnumDeclaration(childNode->AsTSEnumDeclaration());
952         }
953         case ir::AstNodeType::EXPORT_NAMED_DECLARATION: {
954             break;
955         }
956         case ir::AstNodeType::ETS_IMPORT_DECLARATION: {
957             return BuildImportDeclaration(childNode->AsETSImportDeclaration());
958         }
959         case ir::AstNodeType::MEMBER_EXPRESSION: {
960             return BuildMemberExpression(childNode->AsMemberExpression());
961         }
962         case ir::AstNodeType::METHOD_DEFINITION: {
963             return BuildMethodDefinition(childNode->AsMethodDefinition());
964         }
965         case ir::AstNodeType::ETS_NEW_CLASS_INSTANCE_EXPRESSION: {
966             return BuildETSNewClassInstanceExpression(childNode->AsETSNewClassInstanceExpression());
967         }
968         case ir::AstNodeType::ETS_FUNCTION_TYPE: {
969             return BuildSignatureDeclarationBaseParams(childNode);
970         }
971         case ir::AstNodeType::OBJECT_EXPRESSION: {
972             return BuildObjectExpression(childNode->AsObjectExpression());
973         }
974         case ir::AstNodeType::ANNOTATION_USAGE: {
975             return BuildAnnotationUsage(childNode->AsAnnotationUsage());
976         }
977         case ir::AstNodeType::ANNOTATION_DECLARATION: {
978             BuildAnnotationDeclaration(childNode->AsAnnotationDeclaration());
979             break;
980         }
981         default: {
982             return ResolveReferences(childNode);
983         }
984     }
985 }
986 
BuildInternalName(ir::ScriptFunction * scriptFunc)987 bool ETSBinder::BuildInternalName(ir::ScriptFunction *scriptFunc)
988 {
989     const bool isExternal = recordTable_->IsExternal();
990     if (isExternal) {
991         scriptFunc->AddFlag(ir::ScriptFunctionFlags::EXTERNAL);
992     }
993 
994     if (scriptFunc->IsArrow()) {
995         return true;
996     }
997 
998     auto *funcScope = scriptFunc->Scope();
999     funcScope->BindName(recordTable_->RecordName());
1000 
1001     bool compilable = scriptFunc->Body() != nullptr && !isExternal;
1002     if (!compilable) {
1003         recordTable_->Signatures().push_back(funcScope);
1004     }
1005 
1006     return compilable;
1007 }
1008 
BuildInternalNameWithCustomRecordTable(ir::ScriptFunction * const scriptFunc,RecordTable * const recordTable)1009 bool ETSBinder::BuildInternalNameWithCustomRecordTable(ir::ScriptFunction *const scriptFunc,
1010                                                        RecordTable *const recordTable)
1011 {
1012     const bool isExternal = recordTable->IsExternal();
1013     if (isExternal) {
1014         scriptFunc->AddFlag(ir::ScriptFunctionFlags::EXTERNAL);
1015     }
1016 
1017     if (scriptFunc->IsArrow()) {
1018         return true;
1019     }
1020 
1021     auto *const funcScope = scriptFunc->Scope();
1022     funcScope->BindName(recordTable->RecordName());
1023 
1024     const bool compilable = scriptFunc->Body() != nullptr && !isExternal;
1025     if (!compilable) {
1026         recordTable->Signatures().push_back(funcScope);
1027     }
1028 
1029     return compilable;
1030 }
1031 
AddCompilableFunction(ir::ScriptFunction * func)1032 void ETSBinder::AddCompilableFunction(ir::ScriptFunction *func)
1033 {
1034     if (func->IsArrow() || func->IsAsyncFunc()) {
1035         return;
1036     }
1037 
1038     AddCompilableFunctionScope(func->Scope());
1039 }
1040 
BuildFunctionName(const ir::ScriptFunction * func) const1041 void ETSBinder::BuildFunctionName(const ir::ScriptFunction *func) const
1042 {
1043     auto *funcScope = func->Scope();
1044 
1045     std::stringstream ss;
1046     ASSERT(func->IsArrow() || !funcScope->Name().Empty());
1047     ss << (func->IsExternalOverload() ? funcScope->InternalName() : funcScope->Name())
1048        << compiler::Signatures::METHOD_SEPARATOR;
1049 
1050     const auto *signature = func->Signature();
1051 
1052     if (func->IsStaticBlock()) {
1053         ss << compiler::Signatures::CCTOR;
1054     } else if (func->IsConstructor()) {
1055         ss << compiler::Signatures::CTOR;
1056     } else {
1057         if (func->IsGetter()) {
1058             ss << compiler::Signatures::GETTER_BEGIN;
1059         } else if (func->IsSetter()) {
1060             ss << compiler::Signatures::SETTER_BEGIN;
1061         }
1062         ss << util::Helpers::FunctionName(Allocator(), func);
1063     }
1064 
1065     signature->ToAssemblerType(ss);
1066 
1067     util::UString internalName(ss.str(), Allocator());
1068     funcScope->BindInternalName(internalName.View());
1069 }
1070 
InitImplicitThisParam()1071 void ETSBinder::InitImplicitThisParam()
1072 {
1073     thisParam_ = Allocator()->New<ir::Identifier>("this", Allocator());
1074 }
1075 
BuildProgram()1076 void ETSBinder::BuildProgram()
1077 {
1078     for (auto &[_, extPrograms] : Program()->ExternalSources()) {
1079         (void)_;
1080         for (auto *extProg : extPrograms) {
1081             BuildExternalProgram(extProg);
1082         }
1083     }
1084 
1085     for (auto *defaultImport : defaultImports_) {
1086         BuildImportDeclaration(defaultImport);
1087     }
1088 
1089     ValidateReexports();
1090 
1091     auto &stmts = Program()->Ast()->Statements();
1092     const auto etsGlobal = std::find_if(stmts.begin(), stmts.end(), [](const ir::Statement *stmt) {
1093         return stmt->IsClassDeclaration() &&
1094                stmt->AsClassDeclaration()->Definition()->Ident()->Name().Is(compiler::Signatures::ETS_GLOBAL);
1095     });
1096     if (etsGlobal != stmts.end()) {
1097         const auto begin = std::find_if(stmts.rbegin(), stmts.rend(), [](const ir::Statement *stmt) {
1098                                return stmt->IsETSImportDeclaration() || stmt->IsETSPackageDeclaration();
1099                            }).base();
1100 
1101         const auto index = std::distance(begin, etsGlobal);
1102         std::rotate(begin, begin + index, begin + index + 1);
1103     }
1104 
1105     for (auto *stmt : stmts) {
1106         ResolveReference(stmt);
1107     }
1108 }
1109 
BuildExternalProgram(parser::Program * extProgram)1110 void ETSBinder::BuildExternalProgram(parser::Program *extProgram)
1111 {
1112     auto *savedProgram = Program();
1113     auto *savedRecordTable = recordTable_;
1114     auto *savedTopScope = TopScope();
1115 
1116     auto flags = Program()->VarBinder()->IsGenStdLib() ? RecordTableFlags::NONE : RecordTableFlags::EXTERNAL;
1117     auto *extRecordTable = Allocator()->New<RecordTable>(Allocator(), extProgram, flags);
1118     externalRecordTable_.insert({extProgram, extRecordTable});
1119 
1120     ResetTopScope(extProgram->GlobalScope());
1121     recordTable_ = extRecordTable;
1122     SetProgram(extProgram);
1123 
1124     BuildProgram();
1125 
1126     SetProgram(savedProgram);
1127     recordTable_ = savedRecordTable;
1128     ResetTopScope(savedTopScope);
1129 }
1130 
BuildETSNewClassInstanceExpression(ir::ETSNewClassInstanceExpression * classInstance)1131 void ETSBinder::BuildETSNewClassInstanceExpression(ir::ETSNewClassInstanceExpression *classInstance)
1132 {
1133     BoundContext boundCtx(recordTable_, classInstance->ClassDefinition());
1134     ResolveReference(classInstance->GetTypeRef());
1135 
1136     for (auto *arg : classInstance->GetArguments()) {
1137         ResolveReference(arg);
1138     }
1139 
1140     if (classInstance->ClassDefinition() == nullptr) {
1141         return;
1142     }
1143 
1144     ResolveReference(classInstance->ClassDefinition());
1145 }
1146 
BuildImportDeclaration(ir::ETSImportDeclaration * decl)1147 void ETSBinder::BuildImportDeclaration(ir::ETSImportDeclaration *decl)
1148 {
1149     if (decl->Source()->Str() == Program()->SourceFile().GetAbsolutePath()) {
1150         return;
1151     }
1152 
1153     const auto &specifiers = decl->Specifiers();
1154 
1155     for (auto specifier : specifiers) {
1156         AddSpecifiersToTopBindings(specifier, decl, decl->Source());
1157     }
1158 }
1159 
ValidateImportSpecifier(const ir::ImportSpecifier * const specifier,const ir::ETSImportDeclaration * const import,std::vector<ir::ETSImportDeclaration * > viewedReExport)1160 Variable *ETSBinder::ValidateImportSpecifier(const ir::ImportSpecifier *const specifier,
1161                                              const ir::ETSImportDeclaration *const import,
1162                                              std::vector<ir::ETSImportDeclaration *> viewedReExport)
1163 {
1164     const auto sourceName = import->ResolvedSource()->Str();
1165     const auto &record = GetExternalProgram(sourceName, import->Source());
1166     const auto *const importProgram = record.front();
1167     const auto *const importGlobalScope = importProgram->GlobalScope();
1168     const auto &globalBindings = importGlobalScope->Bindings();
1169 
1170     auto imported = specifier->Imported()->Name();
1171     for (const auto *const item : import->Specifiers()) {
1172         // Handle alias
1173         // export {foo as FOO}
1174         if (item->IsImportSpecifier() && item->AsImportSpecifier()->Local()->Name().Is(imported.Mutf8()) &&
1175             !item->AsImportSpecifier()->Local()->Name().Is(item->AsImportSpecifier()->Imported()->Name().Mutf8())) {
1176             imported = item->AsImportSpecifier()->Imported()->Name();
1177         }
1178     }
1179 
1180     auto *const var = FindImportSpecifiersVariable(imported, globalBindings, record);
1181     if (var != nullptr) {
1182         return var;
1183     }
1184 
1185     // Failed to find variable, go through reexports
1186     const ir::ETSImportDeclaration *const implDecl =
1187         FindImportDeclInReExports(import, viewedReExport, imported, import->Source());
1188     if (implDecl != nullptr) {
1189         return ValidateImportSpecifier(specifier, implDecl, std::move(viewedReExport));
1190     }
1191 
1192     return nullptr;
1193 }
1194 
ValidateReexports()1195 void ETSBinder::ValidateReexports()
1196 {
1197     // This will throw syntax error if the reexport is incorrect
1198     // This will also set variables and check for ambiguous reexports
1199     for (auto *reexport : reExportImports_) {
1200         ValidateReexportDeclaration(reexport);
1201     }
1202 
1203     reexportedNames_.clear();
1204 }
1205 
ValidateReexportDeclaration(ir::ETSReExportDeclaration * decl)1206 void ETSBinder::ValidateReexportDeclaration(ir::ETSReExportDeclaration *decl)
1207 {
1208     // Reexport declarations are available in all files, see ReExportImports()
1209     // Check that reexport declaration is in this file
1210     const auto program = Program()->SourceFile().GetAbsolutePath();
1211     const auto reexportSource = os::GetAbsolutePath(decl->GetProgramPath().Utf8());
1212     if (program.Utf8() != reexportSource) {
1213         return;
1214     }
1215 
1216     const auto *const import = decl->GetETSImportDeclarations();
1217     const auto &specifiers = import->Specifiers();
1218     for (auto specifier : specifiers) {
1219         // Example: export {foo} from "./A"
1220         if (specifier->IsImportSpecifier()) {
1221             auto importSpecifier = specifier->AsImportSpecifier();
1222             const auto reexported = importSpecifier->Imported()->Name();
1223             auto *const var =
1224                 ValidateImportSpecifier(importSpecifier, import, std::vector<ir::ETSImportDeclaration *>());
1225             if (var == nullptr) {
1226                 ThrowError(import->Start(), "Incorrect export \"" + reexported.Mutf8() + "\"");
1227             }
1228 
1229             importSpecifier->Imported()->SetVariable(var);
1230             importSpecifier->Local()->SetVariable(var);
1231 
1232             // Remember reexported name to check for ambiguous reexports
1233             if (!reexportedNames_.insert(reexported).second) {
1234                 ThrowError(import->Start(), "Ambiguous export \"" + reexported.Mutf8() + "\"");
1235             }
1236         }
1237 
1238         if (specifier->IsImportNamespaceSpecifier()) {
1239             // NOTE(kkonkuznetsov): See #20658
1240             // How to validate ambiguous exports with namespace specifiers?
1241             // Example:
1242             // export * from "./A"
1243             // export * from "./B"
1244         }
1245     }
1246 }
1247 
ImportGlobalPropertiesForNotDefaultedExports(varbinder::Variable * var,const util::StringView & name,const ir::ClassElement * classElement)1248 bool ETSBinder::ImportGlobalPropertiesForNotDefaultedExports(varbinder::Variable *var, const util::StringView &name,
1249                                                              const ir::ClassElement *classElement)
1250 {
1251     if (var->Declaration()->Node()->IsDefaultExported()) {
1252         return false;
1253     }
1254 
1255     auto variable = Program()->GlobalClassScope()->FindLocal(name, ResolveBindingOptions::ALL);
1256 
1257     bool isStdLib = util::Helpers::IsStdLib(Program());
1258     if (variable != nullptr && var != variable) {
1259         if (variable->Declaration()->IsFunctionDecl() && var->Declaration()->IsFunctionDecl()) {
1260             AddOverloadFlag(Allocator(), isStdLib, var, variable);
1261             return true;
1262         }
1263 
1264         ThrowError(classElement->Id()->Start(), RedeclarationErrorMessageAssembler(var, variable, name.Utf8()));
1265     }
1266 
1267     const auto insRes = TopScope()->InsertForeignBinding(name, var);
1268     if (!(!insRes.second && insRes.first != TopScope()->Bindings().end()) || !(insRes.first->second != var)) {
1269         return true;
1270     }
1271     if (insRes.first->second->Declaration()->IsFunctionDecl() && var->Declaration()->IsFunctionDecl()) {
1272         AddOverloadFlag(Allocator(), isStdLib, var, insRes.first->second);
1273         return true;
1274     }
1275 
1276     ThrowError(classElement->Id()->Start(), RedeclarationErrorMessageAssembler(var, insRes.first->second, name.Utf8()));
1277 }
1278 
ImportGlobalProperties(const ir::ClassDefinition * const classDef)1279 void ETSBinder::ImportGlobalProperties(const ir::ClassDefinition *const classDef)
1280 {
1281     const auto scopeCtx = LexicalScope<ClassScope>::Enter(this, classDef->Scope()->AsClassScope());
1282 
1283     for (const auto *const prop : classDef->Body()) {
1284         const auto *const classElement = prop->AsClassElement();
1285 
1286         if (classElement->IsClassStaticBlock()) {
1287             continue;
1288         }
1289 
1290         ASSERT(classElement->IsStatic());
1291         const auto &name = classElement->Id()->Name();
1292         auto *const var = scopeCtx.GetScope()->FindLocal(name, ResolveBindingOptions::ALL);
1293         ASSERT(var != nullptr);
1294 
1295         if (ImportGlobalPropertiesForNotDefaultedExports(var, name, classElement)) {
1296             return;
1297         }
1298     }
1299 }
1300 
DynamicImportDataForVar(const Variable * var) const1301 const DynamicImportData *ETSBinder::DynamicImportDataForVar(const Variable *var) const
1302 {
1303     auto it = dynamicImportVars_.find(var);
1304     if (it == dynamicImportVars_.cend()) {
1305         return nullptr;
1306     }
1307 
1308     return &it->second;
1309 }
1310 
GetProgramList(const util::StringView & path) const1311 ArenaVector<parser::Program *> ETSBinder::GetProgramList(const util::StringView &path) const
1312 {
1313     for (const auto &extRecords : globalRecordTable_.Program()->ExternalSources()) {
1314         for (const auto &program : extRecords.second) {
1315             if (program->AbsoluteName() == path) {
1316                 return extRecords.second;
1317             }
1318 
1319             // in case of importing a package folder, the path could not be resolved to a specific file
1320             if (program->IsPackageModule() && program->SourceFileFolder() == path) {
1321                 return extRecords.second;
1322             }
1323         }
1324     }
1325 
1326     bool globalIsPackage = globalRecordTable_.Program()->IsPackageModule();
1327     if (globalIsPackage && path.Compare(globalRecordTable_.Program()->SourceFileFolder()) == 0) {
1328         return ArenaVector<parser::Program *>({GetContext()->parserProgram}, Allocator()->Adapter());
1329     }
1330 
1331     return ArenaVector<parser::Program *>(Allocator()->Adapter());
1332 }
1333 
IsDynamicModuleVariable(const Variable * var) const1334 bool ETSBinder::IsDynamicModuleVariable(const Variable *var) const
1335 {
1336     auto *data = DynamicImportDataForVar(var);
1337     if (data == nullptr) {
1338         return false;
1339     }
1340 
1341     return data->specifier->IsImportSpecifier();
1342 }
1343 
IsDynamicNamespaceVariable(const Variable * var) const1344 bool ETSBinder::IsDynamicNamespaceVariable(const Variable *var) const
1345 {
1346     auto *data = DynamicImportDataForVar(var);
1347     if (data == nullptr) {
1348         return false;
1349     }
1350 
1351     return data->specifier->IsImportNamespaceSpecifier();
1352 }
1353 
1354 }  // namespace ark::es2panda::varbinder
1355