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 ¶ms) 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