• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-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 "compiler/lowering/ets/topLevelStmts/importExportDecls.h"
17 #include "generated/diagnostic.h"
18 
19 namespace ark::es2panda::compiler {
20 
ProgramFileNameLessThan(const parser::Program * a,const parser::Program * b)21 static bool ProgramFileNameLessThan(const parser::Program *a, const parser::Program *b)
22 {
23     return a->FileName().Mutf8() < b->FileName().Mutf8();
24 }
25 
ParseDefaultSources()26 void ImportExportDecls::ParseDefaultSources()
27 {
28     auto imports = parser_->ParseDefaultSources(DEFAULT_IMPORT_SOURCE_FILE, defaultImportSource_);
29     varbinder_->SetDefaultImports(std::move(imports));
30 }
31 
ProcessProgramStatements(parser::Program * program,const ArenaVector<ir::Statement * > & statements,GlobalClassHandler::ModuleDependencies & moduleDependencies)32 void ImportExportDecls::ProcessProgramStatements(parser::Program *program,
33                                                  const ArenaVector<ir::Statement *> &statements,
34                                                  GlobalClassHandler::ModuleDependencies &moduleDependencies)
35 {
36     for (auto stmt : statements) {
37         if (stmt->IsETSModule()) {
38             SavedImportExportDeclsContext savedContext(this, program);
39             ProcessProgramStatements(program, stmt->AsETSModule()->Statements(), moduleDependencies);
40             VerifyCollectedExportName(program);
41             savedContext.RecoverExportAliasMultimap();
42         }
43         stmt->Accept(this);
44         if (stmt->IsExportNamedDeclaration()) {
45             PopulateAliasMap(stmt->AsExportNamedDeclaration(), program->SourceFilePath());
46         }
47         if (stmt->IsTSTypeAliasDeclaration() && (stmt->IsExported() || stmt->IsDefaultExported())) {
48             PopulateAliasMap(stmt->AsTSTypeAliasDeclaration(), program->SourceFilePath());
49         }
50     }
51 }
52 
HandleGlobalStmts(ArenaVector<parser::Program * > & programs)53 GlobalClassHandler::ModuleDependencies ImportExportDecls::HandleGlobalStmts(ArenaVector<parser::Program *> &programs)
54 {
55     VerifySingleExportDefault(programs);
56     VerifyTypeExports(programs);
57     GlobalClassHandler::ModuleDependencies moduleDependencies {programs.front()->Allocator()->Adapter()};
58     if (!programs.empty()) {
59         std::sort(programs.begin(), programs.end(), ProgramFileNameLessThan);
60     }
61     for (const auto &program : programs) {
62         PreMergeNamespaces(program);
63         SavedImportExportDeclsContext savedContext(this, program);
64         ProcessProgramStatements(program, program->Ast()->Statements(), moduleDependencies);
65         VerifyCollectedExportName(program);
66     }
67     return moduleDependencies;
68 }
69 
PopulateAliasMap(const ir::ExportNamedDeclaration * decl,const util::StringView & path)70 void ImportExportDecls::PopulateAliasMap(const ir::ExportNamedDeclaration *decl, const util::StringView &path)
71 {
72     for (auto spec : decl->Specifiers()) {
73         if (!varbinder_->AddSelectiveExportAlias(parser_, path, spec->Local()->Name(), spec->Exported()->Name(),
74                                                  decl)) {
75             parser_->LogError(diagnostic::AMBIGUOUS_EXPORT, {spec->Local()->Name().Mutf8()}, spec->Exported()->Start());
76             lastExportErrorPos_ = lexer::SourcePosition();
77         }
78     }
79 }
80 
AddExportFlags(ir::AstNode * node,util::StringView originalFieldName,bool exportedWithAlias)81 void ImportExportDecls::AddExportFlags(ir::AstNode *node, util::StringView originalFieldName, bool exportedWithAlias)
82 {
83     if (exportedWithAlias) {
84         node->AddAstNodeFlags(ir::AstNodeFlags::HAS_EXPORT_ALIAS);
85     } else if (originalFieldName == exportDefaultName_) {
86         node->AddModifier(ir::ModifierFlags::DEFAULT_EXPORT);
87     } else {
88         node->AddModifier(ir::ModifierFlags::EXPORT);
89     }
90 }
PopulateAliasMap(const ir::TSTypeAliasDeclaration * decl,const util::StringView & path)91 void ImportExportDecls::PopulateAliasMap(const ir::TSTypeAliasDeclaration *decl, const util::StringView &path)
92 {
93     if (!varbinder_->AddSelectiveExportAlias(parser_, path, decl->Id()->AsIdentifier()->Name(),
94                                              decl->Id()->AsIdentifier()->Name(), decl)) {
95         parser_->LogError(diagnostic::AMBIGUOUS_EXPORT, {decl->Id()->AsIdentifier()->Name().Mutf8()},
96                           lastExportErrorPos_);
97         lastExportErrorPos_ = lexer::SourcePosition();
98     }
99 }
100 
HandleSelectiveExportWithAlias(util::StringView originalFieldName,util::StringView exportName,lexer::SourcePosition startLoc)101 void ImportExportDecls::HandleSelectiveExportWithAlias(util::StringView originalFieldName, util::StringView exportName,
102                                                        lexer::SourcePosition startLoc)
103 {
104     bool exportedWithAlias = exportName != originalFieldName;
105 
106     auto fieldItem = fieldMap_.find(originalFieldName);
107     ir::VariableDeclarator *variableDeclarator = nullptr;
108     if (fieldItem != fieldMap_.end()) {
109         ir::AstNode *field = fieldItem->second;
110         if (field->IsVariableDeclaration()) {
111             variableDeclarator = field->AsVariableDeclaration()->GetDeclaratorByName(originalFieldName);
112             ES2PANDA_ASSERT(variableDeclarator != nullptr);
113         }
114 
115         if (variableDeclarator != nullptr) {
116             AddExportFlags(variableDeclarator, originalFieldName, exportedWithAlias);
117         } else {
118             AddExportFlags(field, originalFieldName, exportedWithAlias);
119         }
120     }
121 
122     if (exportedWithAlias) {
123         if (auto declItem = fieldMap_.find(exportName); declItem != fieldMap_.end()) {
124             // Checking for the alias might be unnecessary, because explicit exports cannot
125             // have an alias yet.
126             bool alreadyExported = ((declItem->second->Modifiers() & ir::ModifierFlags::EXPORTED) != 0) &&
127                                    !declItem->second->HasExportAlias();
128             if (!alreadyExported && declItem->second->IsVariableDeclaration()) {
129                 auto declarator = declItem->second->AsVariableDeclaration()->GetDeclaratorByName(exportName);
130                 ES2PANDA_ASSERT(declarator != nullptr);
131                 alreadyExported |=
132                     ((declarator->Modifiers() & ir::ModifierFlags::EXPORTED) != 0) && !declarator->HasExportAlias();
133             }
134             if (alreadyExported) {
135                 parser_->LogError(diagnostic::DUPLICATE_EXPORT_NAME, {exportName.Mutf8()}, startLoc);
136             }
137         }
138     }
139 }
140 
VisitFunctionDeclaration(ir::FunctionDeclaration * funcDecl)141 void ImportExportDecls::VisitFunctionDeclaration(ir::FunctionDeclaration *funcDecl)
142 {
143     fieldMap_.emplace(funcDecl->Function()->Id()->Name(), funcDecl->Function());
144 }
145 
VisitVariableDeclaration(ir::VariableDeclaration * varDecl)146 void ImportExportDecls::VisitVariableDeclaration(ir::VariableDeclaration *varDecl)
147 {
148     for (const auto &decl : varDecl->Declarators()) {
149         fieldMap_.emplace(decl->Id()->AsIdentifier()->Name(), varDecl);
150     }
151 }
152 
VisitClassDeclaration(ir::ClassDeclaration * classDecl)153 void ImportExportDecls::VisitClassDeclaration(ir::ClassDeclaration *classDecl)
154 {
155     fieldMap_.emplace(classDecl->Definition()->Ident()->Name(), classDecl);
156 }
157 
VisitTSEnumDeclaration(ir::TSEnumDeclaration * enumDecl)158 void ImportExportDecls::VisitTSEnumDeclaration(ir::TSEnumDeclaration *enumDecl)
159 {
160     fieldMap_.emplace(enumDecl->Key()->Name(), enumDecl);
161 }
162 
VisitTSTypeAliasDeclaration(ir::TSTypeAliasDeclaration * typeAliasDecl)163 void ImportExportDecls::VisitTSTypeAliasDeclaration(ir::TSTypeAliasDeclaration *typeAliasDecl)
164 {
165     fieldMap_.emplace(typeAliasDecl->Id()->Name(), typeAliasDecl);
166 }
167 
VisitTSInterfaceDeclaration(ir::TSInterfaceDeclaration * interfaceDecl)168 void ImportExportDecls::VisitTSInterfaceDeclaration(ir::TSInterfaceDeclaration *interfaceDecl)
169 {
170     fieldMap_.emplace(interfaceDecl->Id()->Name(), interfaceDecl);
171 }
172 
VisitAnnotationDeclaration(ir::AnnotationDeclaration * annotationDecl)173 void ImportExportDecls::VisitAnnotationDeclaration(ir::AnnotationDeclaration *annotationDecl)
174 {
175     fieldMap_.emplace(annotationDecl->GetBaseName()->Name(), annotationDecl);
176 }
177 
VisitETSModule(ir::ETSModule * etsModule)178 void ImportExportDecls::VisitETSModule(ir::ETSModule *etsModule)
179 {
180     if (etsModule->IsETSScript()) {
181         return;
182     }
183     fieldMap_.emplace(etsModule->Ident()->Name(), etsModule);
184 }
185 
VisitExportNamedDeclaration(ir::ExportNamedDeclaration * exportDecl)186 void ImportExportDecls::VisitExportNamedDeclaration(ir::ExportNamedDeclaration *exportDecl)
187 {
188     for (auto spec : exportDecl->Specifiers()) {
189         auto local = spec->Local();
190         // If this was enterred more than once, CTE must has been logged in parser.
191         if ((exportDecl->Modifiers() & ir::ModifierFlags::DEFAULT_EXPORT) != 0) {
192             if (exportDefaultName_ != nullptr) {
193                 parser_->LogError(diagnostic::EXPORT_DEFAULT_WITH_MUPLTIPLE_SPECIFIER, {}, local->Start());
194                 continue;
195             }
196             exportDefaultName_ = local->Name();
197         }
198         exportNameMap_.emplace(local->Name(), local->Start());
199     }
200 }
201 
VisitETSImportDeclaration(ir::ETSImportDeclaration * importDecl)202 void ImportExportDecls::VisitETSImportDeclaration(ir::ETSImportDeclaration *importDecl)
203 {
204     for (ir::AstNode *spec : importDecl->AsETSImportDeclaration()->Specifiers()) {
205         if (spec->IsImportSpecifier()) {
206             importedSpecifiersForExportCheck_.emplace(spec->AsImportSpecifier()->Local()->Name(),
207                                                       spec->AsImportSpecifier()->Imported()->Name());
208         }
209         if (spec->IsImportDefaultSpecifier()) {
210             importedSpecifiersForExportCheck_.emplace(spec->AsImportDefaultSpecifier()->Local()->Name(),
211                                                       spec->AsImportDefaultSpecifier()->Local()->Name());
212         }
213     }
214 }
215 
HandleSimpleType(std::set<util::StringView> & exportedStatements,ir::Statement * stmt,util::StringView name)216 void ImportExportDecls::HandleSimpleType(std::set<util::StringView> &exportedStatements, ir::Statement *stmt,
217                                          util::StringView name)
218 {
219     if (stmt->IsExported()) {
220         exportedStatements.insert(name);
221     }
222 }
223 
VerifyTypeExports(const ArenaVector<parser::Program * > & programs)224 void ImportExportDecls::VerifyTypeExports(const ArenaVector<parser::Program *> &programs)
225 {
226     std::set<util::StringView> exportedStatements;
227     std::map<util::StringView, ir::AstNode *> typesMap;
228 
229     for (const auto &program : programs) {
230         for (auto stmt : program->Ast()->Statements()) {
231             VerifyType(stmt, exportedStatements, typesMap);
232         }
233     }
234 }
235 
VerifyType(ir::Statement * stmt,std::set<util::StringView> & exportedStatements,std::map<util::StringView,ir::AstNode * > & typesMap)236 void ImportExportDecls::VerifyType(ir::Statement *stmt, std::set<util::StringView> &exportedStatements,
237                                    std::map<util::StringView, ir::AstNode *> &typesMap)
238 {
239     if (stmt->IsClassDeclaration()) {
240         if (!stmt->IsDeclare() && stmt->AsClassDeclaration()->Definition()->Language().IsDynamic()) {
241             parser_->LogError(diagnostic::EXPORT_WITHOUT_DECLARE_IN_DECL_MODULE, {}, stmt->Start());
242         }
243         typesMap.insert({stmt->AsClassDeclaration()->Definition()->Ident()->Name(), stmt});
244         return HandleSimpleType(exportedStatements, stmt, stmt->AsClassDeclaration()->Definition()->Ident()->Name());
245     }
246 
247     if (stmt->IsTSInterfaceDeclaration()) {
248         if (!stmt->IsDeclare() && stmt->AsTSInterfaceDeclaration()->Language().IsDynamic()) {
249             parser_->LogError(diagnostic::EXPORT_WITHOUT_DECLARE_IN_DECL_MODULE, {}, stmt->Start());
250         }
251         typesMap.insert({stmt->AsTSInterfaceDeclaration()->Id()->Name(), stmt});
252         return HandleSimpleType(exportedStatements, stmt, stmt->AsTSInterfaceDeclaration()->Id()->Name());
253     }
254 
255     if (stmt->IsTSTypeAliasDeclaration()) {
256         typesMap.insert({stmt->AsTSTypeAliasDeclaration()->Id()->Name(), stmt});
257         return HandleSimpleType(exportedStatements, stmt, stmt->AsTSTypeAliasDeclaration()->Id()->Name());
258     }
259 }
260 
VerifySingleExportDefault(const ArenaVector<parser::Program * > & programs)261 void ImportExportDecls::VerifySingleExportDefault(const ArenaVector<parser::Program *> &programs)
262 {
263     bool metDefaultExport = false;
264     auto &logger = parser_->DiagnosticEngine();
265     auto verifyDefault = [&metDefaultExport, &logger](ir::Statement *stmt) {
266         if ((stmt->Modifiers() & ir::ModifierFlags::DEFAULT_EXPORT) == 0) {
267             return;
268         }
269         if (metDefaultExport) {
270             logger.LogDiagnostic(diagnostic::MULTIPLE_DEFAULT_EXPORTS, util::DiagnosticMessageParams {}, stmt->Start());
271         }
272         metDefaultExport = true;
273     };
274     for (const auto &program : programs) {
275         for (auto stmt : program->Ast()->Statements()) {
276             verifyDefault(stmt);
277         }
278         metDefaultExport = false;
279     }
280 }
281 
VerifyCollectedExportName(const parser::Program * program)282 void ImportExportDecls::VerifyCollectedExportName(const parser::Program *program)
283 {
284     for (auto const &[exportName, startLoc] : exportNameMap_) {
285         const bool isType = exportedTypes_.find(exportName) != exportedTypes_.end();
286         util::StringView middleName = varbinder_->FindNameInAliasMap(program->SourceFilePath(), exportName);
287         ES2PANDA_ASSERT(!middleName.Empty());
288         auto originNameIt = importedSpecifiersForExportCheck_.find(middleName);
289         auto originalName = originNameIt != importedSpecifiersForExportCheck_.end() ? originNameIt->second : middleName;
290         auto result = fieldMap_.find(originalName);
291         if (result == fieldMap_.end() && !isType && originNameIt == importedSpecifiersForExportCheck_.end()) {
292             parser_->LogError(diagnostic::CAN_NOT_FIND_NAME_TO_EXPORT, {originalName}, startLoc);
293         }
294         if (result != fieldMap_.end() && result->second->IsAnnotationDeclaration() && exportName != originalName) {
295             parser_->LogError(diagnostic::CAN_NOT_RENAME_ANNOTATION, {originalName}, startLoc);
296         }
297         if (!isType) {
298             HandleSelectiveExportWithAlias(originalName, exportName, startLoc);
299         }
300     }
301 }
302 
PreMergeNamespaces(parser::Program * program)303 void ImportExportDecls::PreMergeNamespaces(parser::Program *program)
304 {
305     bool isChanged = false;
306     auto mergeNameSpace = [&program, &isChanged](ir::AstNode *ast) {
307         if (!ast->IsETSModule()) {
308             return;
309         }
310 
311         ArenaVector<ir::ETSModule *> namespaces(program->Allocator()->Adapter());
312         auto &body = ast->AsETSModule()->Statements();
313         auto originalSize = body.size();
314         auto end = std::remove_if(body.begin(), body.end(), [&namespaces](ir::AstNode *node) {
315             if (node->IsETSModule() && node->AsETSModule()->IsNamespace()) {
316                 namespaces.emplace_back(node->AsETSModule());
317                 return true;
318             }
319             return false;
320         });
321         body.erase(end, body.end());
322 
323         GlobalClassHandler::MergeNamespace(namespaces, program);
324 
325         for (auto ns : namespaces) {
326             body.emplace_back(ns);
327         }
328 
329         isChanged |= (originalSize != body.size());
330     };
331 
332     do {
333         isChanged = false;
334         mergeNameSpace(program->Ast());
335         program->Ast()->IterateRecursivelyPreorder(mergeNameSpace);
336     } while (isChanged);
337 }
338 }  // namespace ark::es2panda::compiler
339