From 775d0e3b3ee4d60e57a79b312468ed3311592cee Mon Sep 17 00:00:00 2001 From: daizihan Date: Mon, 26 May 2025 17:49:17 +0800 Subject: [PATCH] Add module to re-export Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICAMO0?from=project-issue Signed-off-by: daizihan Change-Id: If5c1b3f4bed502a4707c9e1049c2f9e349c3b54c --- .../compiler/lowering/ets/enumLowering.cpp | 1 + .../ets/topLevelStmts/globalClassHandler.cpp | 88 +++++++++++++++++-- .../ets/topLevelStmts/globalClassHandler.h | 8 +- ets2panda/ir/base/classDefinition.h | 9 +- .../unit/lowerings/top_level_statements.cpp | 26 ++++++ 5 files changed, 123 insertions(+), 9 deletions(-) diff --git a/ets2panda/compiler/lowering/ets/enumLowering.cpp b/ets2panda/compiler/lowering/ets/enumLowering.cpp index ffe2201556..3d5b82941f 100644 --- a/ets2panda/compiler/lowering/ets/enumLowering.cpp +++ b/ets2panda/compiler/lowering/ets/enumLowering.cpp @@ -278,6 +278,7 @@ ir::ClassDeclaration *EnumLoweringPhase::CreateClass(ir::TSEnumDeclaration *cons if (enumDecl->IsExported()) { classDecl->AddModifier(ir::ModifierFlags::EXPORT); + program_->GlobalClass()->AddToExportedClasses(classDecl); } else if (enumDecl->IsDefaultExported()) { classDecl->AddModifier(ir::ModifierFlags::DEFAULT_EXPORT); } diff --git a/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp b/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp index 1aaced464c..b9f60c91ac 100644 --- a/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp +++ b/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp @@ -14,6 +14,7 @@ */ #include "compiler/lowering/ets/topLevelStmts/globalClassHandler.h" +#include #include "compiler/lowering/util.h" #include "ir/statements/classDeclaration.h" @@ -59,13 +60,69 @@ std::string AddToNamespaceChain(std::string chain, std::string name) return chain + "." + name; } -void GlobalClassHandler::CollectNamespaceExportedClasses(ir::ClassDefinition *classDef) +void GlobalClassHandler::CollectNamespaceExportedClasses(parser::Program *program, ir::ClassDefinition *classDef) { - CollectExportedClasses(classDef, classDef->Body()); + CollectExportedClasses(program, classDef, classDef->Body()); +} + +void GlobalClassHandler::CollectReExportedClasses(parser::Program *program, ir::ClassDefinition *classDef, + const ir::ETSReExportDeclaration *reExport) +{ + auto importDecl = reExport->GetETSImportDeclarations(); + const auto importPath = reExport->GetETSImportDeclarations()->ImportMetadata().resolvedSource; + parser::Program *extProg = nullptr; + // Search Correct external program by comparing importPath and absolutePath + for (auto &[_, progs] : program->DirectExternalSources()) { + auto it = std::find_if(progs.begin(), progs.end(), + [&](const auto *prog) { return prog->AbsoluteName() == importPath; }); + if (it != progs.end()) { + extProg = *it; + break; + } + } + if (extProg == nullptr) { + return; + } + auto &externalExportedClasses = extProg->GlobalClass()->ExportedClasses(); + const auto &specifiers = importDecl->Specifiers(); + bool needAddETSGlobal = false; + for (const auto *specifier : specifiers) { + if (specifier->IsImportNamespaceSpecifier()) { + classDef->BatchAddToExportedClasses(externalExportedClasses); + break; + } + auto found = std::find_if(externalExportedClasses.begin(), externalExportedClasses.end(), + [&specifier](const ir::ClassDeclaration *classDecl) { + return specifier->IsImportSpecifier() && + specifier->AsImportSpecifier()->Imported()->Name() == + // CC-OFFNXT(G.FMT.02-CPP) solid logic + classDecl->Definition()->Ident()->Name(); + // CC-OFFNXT(G.FMT.02-CPP) solid logic + }); + if (found == externalExportedClasses.end()) { + needAddETSGlobal = true; + continue; + } + classDef->AddToExportedClasses(*found); + } + + /* + * a.ets: b.ets: + * export let ident = 10 export {ident, A, B} from './a' + * export class A {} + * export class B {} + * Note: (`a.ets` exported classes: A, B and ETSGLOBAL) + * + * In this re-export declaration, we need manually add ETSGLOBAL to exportedClasses. + */ + if (needAddETSGlobal) { + classDef->AddToExportedClasses(extProg->GlobalClass()->Parent()->AsClassDeclaration()); + } } template -void GlobalClassHandler::CollectExportedClasses(ir::ClassDefinition *classDef, const ArenaVector &statements) +void GlobalClassHandler::CollectExportedClasses(parser::Program *program, ir::ClassDefinition *classDef, + const ArenaVector &statements) { for (const auto *statement : statements) { if (!statement->IsExported()) { @@ -73,7 +130,26 @@ void GlobalClassHandler::CollectExportedClasses(ir::ClassDefinition *classDef, c } if (statement->IsClassDeclaration()) { classDef->AddToExportedClasses(statement->AsClassDeclaration()); + continue; + } + if (statement->IsETSReExportDeclaration()) { + CollectReExportedClasses(program, classDef, statement->AsETSReExportDeclaration()); + } + } + auto globalClass = program->GlobalClass(); + bool foundExport = false; + // Add ETSGLOBAL to Module in case of export let a = 10 + std::function findExportInGlobal = [&findExportInGlobal, &foundExport](ir::AstNode *node) { + if (node->IsExported()) { + foundExport = true; + return; } + node->Iterate(findExportInGlobal); + }; + globalClass->Iterate(findExportInGlobal); + if (foundExport) { + auto globalClassDecl = globalClass->Parent()->AsClassDeclaration(); + classDef->AddToExportedClasses(globalClassDecl); } } @@ -238,7 +314,7 @@ ir::ClassDeclaration *GlobalClassHandler::TransformNamespace(ir::ETSModule *ns) for (auto *cls : globalClasses) { globalClass->EmplaceBody(cls); cls->SetParent(globalClass); - CollectNamespaceExportedClasses(cls->AsClassDeclaration()->Definition()); + CollectNamespaceExportedClasses(globalProgram_, cls->AsClassDeclaration()->Definition()); } // Add rest statement, such as type declaration @@ -256,7 +332,7 @@ void GlobalClassHandler::CollectProgramGlobalClasses(ArenaVectorAst()->AddStatements(classDecls); for (auto cls : classDecls) { cls->SetParent(globalProgram_->Ast()); - CollectNamespaceExportedClasses(cls->AsClassDeclaration()->Definition()); + CollectNamespaceExportedClasses(globalProgram_, cls->AsClassDeclaration()->Definition()); } } @@ -324,7 +400,7 @@ void GlobalClassHandler::SetupGlobalClass(const ArenaVector & TransformBrokenNamespace(); auto initializerBlockStmts = FormInitStaticBlockMethodStatements(moduleDependencies, std::move(initializerBlock)); - CollectExportedClasses(globalClass, globalProgram_->Ast()->Statements()); + CollectExportedClasses(globalProgram_, globalClass, globalProgram_->Ast()->Statements()); // NOTE(vpukhov): stdlib checks are to be removed - do not extend the existing logic if (globalProgram_->Kind() != parser::ScriptKind::STDLIB) { diff --git a/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.h b/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.h index 0a861be7a7..542f132c09 100644 --- a/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.h +++ b/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.h @@ -17,6 +17,7 @@ #define PANDA_GLOBALCLASSHANDLER_H #include "compiler/lowering/ets/topLevelStmts/globalDeclTransformer.h" +#include "ir/ets/etsReExportDeclaration.h" #include "parser/program/program.h" #include "public/public.h" #include "ir/astNode.h" @@ -65,8 +66,11 @@ private: ir::ClassDeclaration *TransformNamespace(ir::ETSModule *ns); ir::ClassDeclaration *CreateTransformedClass(ir::ETSModule *ns); template - void CollectExportedClasses(ir::ClassDefinition *classDef, const ArenaVector &statements); - void CollectNamespaceExportedClasses(ir::ClassDefinition *classDef); + void CollectExportedClasses(parser::Program *program, ir::ClassDefinition *classDef, + const ArenaVector &statements); + void CollectReExportedClasses(parser::Program *program, ir::ClassDefinition *classDef, + const ir::ETSReExportDeclaration *reExport); + void CollectNamespaceExportedClasses(parser::Program *program, ir::ClassDefinition *classDef); void SetupGlobalMethods(ArenaVector &&initStatements, ir::ClassDefinition *globalClass, bool isDeclare); void SetupInitializerBlock(ArenaVector> &&initializerBlock, diff --git a/ets2panda/ir/base/classDefinition.h b/ets2panda/ir/base/classDefinition.h index fd71f32cd3..042d101ee7 100644 --- a/ets2panda/ir/base/classDefinition.h +++ b/ets2panda/ir/base/classDefinition.h @@ -477,11 +477,18 @@ public: void AddToExportedClasses(const ir::ClassDeclaration *cls) { - ES2PANDA_ASSERT(cls->IsExported()); + ES2PANDA_ASSERT(cls->IsExported() || cls->Definition()->IsGlobal()); auto newNode = reinterpret_cast(this->GetOrCreateHistoryNode()); newNode->exportedClasses_.emplace_back(cls); } + void BatchAddToExportedClasses(const ArenaVector &classes) + { + for (const auto cls : classes) { + AddToExportedClasses(cls); + } + } + [[nodiscard]] const ArenaVector &ExportedClasses() const noexcept { return GetHistoryNodeAs()->exportedClasses_; diff --git a/ets2panda/test/unit/lowerings/top_level_statements.cpp b/ets2panda/test/unit/lowerings/top_level_statements.cpp index 88ef617443..c7fedb4621 100644 --- a/ets2panda/test/unit/lowerings/top_level_statements.cpp +++ b/ets2panda/test/unit/lowerings/top_level_statements.cpp @@ -128,4 +128,30 @@ TEST_F(LoweringTest, TestTopLevelStmtsExportedNamespaceNested) } } +TEST_F(LoweringTest, TestTopLevelStmtsExportedEnum) +{ + char const *text = R"( + export let a = 10; + export enum Color { + Red = 1 + } + )"; + + CONTEXT(ES2PANDA_STATE_LOWERED, text) + { + const auto *const ast = GetAst(); + auto *classDef = ast->FindChild([](ir::AstNode *child) { + return child->IsClassDefinition() && child->AsClassDefinition()->IsGlobalInitialized(); + }); + ASSERT(classDef != nullptr); + + const auto &exportedClasses = classDef->AsClassDefinition()->ExportedClasses(); + constexpr uint32_t EXPORTED_CLASSES_NUM = 2; + ASSERT_EQ(exportedClasses.size(), EXPORTED_CLASSES_NUM); + ASSERT_TRUE(exportedClasses[1]->IsExported()); + ASSERT_EQ(exportedClasses[0]->Definition()->InternalName().Mutf8(), "dummy.ETSGLOBAL"); + ASSERT_EQ(exportedClasses[1]->Definition()->InternalName().Mutf8(), "dummy.Color"); + } +} + } // namespace ark::es2panda -- Gitee