13af6ab5fSopenharmony_ci/**
23af6ab5fSopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd.
33af6ab5fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
43af6ab5fSopenharmony_ci * you may not use this file except in compliance with the License.
53af6ab5fSopenharmony_ci * You may obtain a copy of the License at
63af6ab5fSopenharmony_ci *
73af6ab5fSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
83af6ab5fSopenharmony_ci *
93af6ab5fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
103af6ab5fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
113af6ab5fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
123af6ab5fSopenharmony_ci * See the License for the specific language governing permissions and
133af6ab5fSopenharmony_ci * limitations under the License.
143af6ab5fSopenharmony_ci */
153af6ab5fSopenharmony_ci
163af6ab5fSopenharmony_ci#include "checker/ETSchecker.h"
173af6ab5fSopenharmony_ci#include "evaluate/helpers.h"
183af6ab5fSopenharmony_ci
193af6ab5fSopenharmony_ci#include "evaluate/debugInfoDeserialization/debugInfoDeserializer.h"
203af6ab5fSopenharmony_ci#include "evaluate/scopedDebugInfoPlugin.h"
213af6ab5fSopenharmony_ci#include "evaluate/debugInfoStorage.h"
223af6ab5fSopenharmony_ci#include "evaluate/proxyProgramsCache.h"
233af6ab5fSopenharmony_ci#include "evaluate/entityDeclarator-inl.h"
243af6ab5fSopenharmony_ci
253af6ab5fSopenharmony_ci#include "libpandafile/class_data_accessor.h"
263af6ab5fSopenharmony_ci#include "libpandafile/file-inl.h"
273af6ab5fSopenharmony_ci
283af6ab5fSopenharmony_cinamespace ark::es2panda::evaluate {
293af6ab5fSopenharmony_ci
303af6ab5fSopenharmony_cinamespace {
313af6ab5fSopenharmony_ci
323af6ab5fSopenharmony_ciconstexpr std::string_view OBJECT_NAME = "std.core.Object";
333af6ab5fSopenharmony_ci
343af6ab5fSopenharmony_cistd::string GetFullSuperClassName(panda_file::ClassDataAccessor &cda)
353af6ab5fSopenharmony_ci{
363af6ab5fSopenharmony_ci    return panda_file::ClassDataAccessor::DemangledName(cda.GetPandaFile().GetStringData(cda.GetSuperClassId()));
373af6ab5fSopenharmony_ci}
383af6ab5fSopenharmony_ci
393af6ab5fSopenharmony_cistd::optional<std::pair<util::StringView, FileDebugInfo *>> GetSuperClassModuleAndClassName(
403af6ab5fSopenharmony_ci    panda_file::ClassDataAccessor &cda, DebugInfoStorage *debugInfoStorage)
413af6ab5fSopenharmony_ci{
423af6ab5fSopenharmony_ci    ASSERT(debugInfoStorage);
433af6ab5fSopenharmony_ci
443af6ab5fSopenharmony_ci    auto fullSuperClassName = GetFullSuperClassName(cda);
453af6ab5fSopenharmony_ci    if (fullSuperClassName == OBJECT_NAME) {
463af6ab5fSopenharmony_ci        // Must stop iterating upon reaching std.core.Object.
473af6ab5fSopenharmony_ci        return {};
483af6ab5fSopenharmony_ci    }
493af6ab5fSopenharmony_ci
503af6ab5fSopenharmony_ci    auto [moduleName, recordName] = helpers::SplitRecordName(fullSuperClassName);
513af6ab5fSopenharmony_ci    auto *debugInfo = debugInfoStorage->GetDebugInfoByModuleName(moduleName);
523af6ab5fSopenharmony_ci    if (UNLIKELY(debugInfo == nullptr)) {
533af6ab5fSopenharmony_ci        LOG(FATAL, ES2PANDA) << "Failed to find debug info for module '" << moduleName << "'";
543af6ab5fSopenharmony_ci    }
553af6ab5fSopenharmony_ci    // Allocate record name for later usage in compilation.
563af6ab5fSopenharmony_ci    return std::make_pair(util::UString(recordName, debugInfoStorage->Allocator()).View(), debugInfo);
573af6ab5fSopenharmony_ci}
583af6ab5fSopenharmony_ci
593af6ab5fSopenharmony_ci}  // namespace
603af6ab5fSopenharmony_ci
613af6ab5fSopenharmony_cistruct ChainEntryInfo final {
623af6ab5fSopenharmony_ci    explicit ChainEntryInfo(std::string_view filePath, std::string_view declName,
633af6ab5fSopenharmony_ci                            panda_file::ClassDataAccessor *accessor, parser::Program *prog)
643af6ab5fSopenharmony_ci        : sourceFilePath(filePath), entityDeclarationName(declName), cda(accessor), program(prog)
653af6ab5fSopenharmony_ci    {
663af6ab5fSopenharmony_ci        ASSERT(cda != nullptr);
673af6ab5fSopenharmony_ci    }
683af6ab5fSopenharmony_ci
693af6ab5fSopenharmony_ci    DEFAULT_MOVE_SEMANTIC(ChainEntryInfo);
703af6ab5fSopenharmony_ci    DEFAULT_COPY_SEMANTIC(ChainEntryInfo);
713af6ab5fSopenharmony_ci
723af6ab5fSopenharmony_ci    ~ChainEntryInfo() = default;
733af6ab5fSopenharmony_ci
743af6ab5fSopenharmony_ci    // NOLINTBEGIN(misc-non-private-member-variables-in-classes)
753af6ab5fSopenharmony_ci    std::string_view sourceFilePath;
763af6ab5fSopenharmony_ci    std::string_view entityDeclarationName;
773af6ab5fSopenharmony_ci    // Pointer is required for move semantics.
783af6ab5fSopenharmony_ci    panda_file::ClassDataAccessor *cda {nullptr};
793af6ab5fSopenharmony_ci    parser::Program *program {nullptr};
803af6ab5fSopenharmony_ci    // NOLINTEND(misc-non-private-member-variables-in-classes)
813af6ab5fSopenharmony_ci};
823af6ab5fSopenharmony_ci
833af6ab5fSopenharmony_ciir::ETSTypeReference *DebugInfoDeserializer::GetSuperClass(panda_file::ClassDataAccessor &cda)
843af6ab5fSopenharmony_ci{
853af6ab5fSopenharmony_ci    auto optClassInfo = GetSuperClassModuleAndClassName(cda, debugInfoPlugin_.GetDebugInfoStorage());
863af6ab5fSopenharmony_ci    if (!optClassInfo) {
873af6ab5fSopenharmony_ci        return nullptr;
883af6ab5fSopenharmony_ci    }
893af6ab5fSopenharmony_ci    auto [superClassName, debugInfo] = *optClassInfo;
903af6ab5fSopenharmony_ci    return ResolveInheritanceChain(superClassName, debugInfo);
913af6ab5fSopenharmony_ci}
923af6ab5fSopenharmony_ci
933af6ab5fSopenharmony_ciir::ETSTypeReference *DebugInfoDeserializer::ResolveInheritanceChain(util::StringView abcSuperName,
943af6ab5fSopenharmony_ci                                                                     FileDebugInfo *debugInfo)
953af6ab5fSopenharmony_ci{
963af6ab5fSopenharmony_ci    ASSERT(debugInfo);
973af6ab5fSopenharmony_ci
983af6ab5fSopenharmony_ci    auto *program = debugInfoPlugin_.GetProxyProgramsCache()->GetProgram(debugInfo->sourceFilePath);
993af6ab5fSopenharmony_ci    if (debugInfoPlugin_.GetEntityDeclarator()->IsEntityDeclared(program, abcSuperName)) {
1003af6ab5fSopenharmony_ci        // If a superclass has already been declared, then we just need to create the TypeReference of it.
1013af6ab5fSopenharmony_ci        // Note that a TypeReference is created for each of usage of the super class.
1023af6ab5fSopenharmony_ci        return helpers::CreateETSTypeReference(debugInfoPlugin_.GetIrCheckHelper()->GetChecker(), abcSuperName);
1033af6ab5fSopenharmony_ci    }
1043af6ab5fSopenharmony_ci    return ResolveInheritanceChainImpl(abcSuperName, debugInfo);
1053af6ab5fSopenharmony_ci}
1063af6ab5fSopenharmony_ci
1073af6ab5fSopenharmony_ciir::ETSTypeReference *DebugInfoDeserializer::ResolveInheritanceChainImpl(util::StringView abcSuperName,
1083af6ab5fSopenharmony_ci                                                                         FileDebugInfo *debugInfo)
1093af6ab5fSopenharmony_ci{
1103af6ab5fSopenharmony_ci    auto *checker = debugInfoPlugin_.GetIrCheckHelper()->GetChecker();
1113af6ab5fSopenharmony_ci
1123af6ab5fSopenharmony_ci    // List starting from the most derived to the base class.
1133af6ab5fSopenharmony_ci    ArenaVector<ChainEntryInfo> chainEntryList(checker->Allocator()->Adapter());
1143af6ab5fSopenharmony_ci    auto alreadyCreatedSuperClassName = CollectChainInfo(chainEntryList, abcSuperName, debugInfo);
1153af6ab5fSopenharmony_ci
1163af6ab5fSopenharmony_ci    ir::ETSTypeReference *superClass = nullptr;
1173af6ab5fSopenharmony_ci    if (!alreadyCreatedSuperClassName.Empty()) {
1183af6ab5fSopenharmony_ci        superClass = helpers::CreateETSTypeReference(checker, util::StringView(alreadyCreatedSuperClassName));
1193af6ab5fSopenharmony_ci    }
1203af6ab5fSopenharmony_ci
1213af6ab5fSopenharmony_ci    auto *entityDeclarator = debugInfoPlugin_.GetEntityDeclarator();
1223af6ab5fSopenharmony_ci    for (auto it = chainEntryList.rbegin(); it != chainEntryList.rend(); ++it) {
1233af6ab5fSopenharmony_ci        // Create entity in the same file in that it destinded to be declared, so import declaration should not be
1243af6ab5fSopenharmony_ci        // inserted in AST.
1253af6ab5fSopenharmony_ci        std::string_view declarationName = it->entityDeclarationName;
1263af6ab5fSopenharmony_ci        auto *cda = it->cda;
1273af6ab5fSopenharmony_ci        ASSERT(cda != nullptr);
1283af6ab5fSopenharmony_ci        // clang-format off
1293af6ab5fSopenharmony_ci        entityDeclarator->ImportGlobalEntity(it->sourceFilePath, declarationName, it->program, declarationName,
1303af6ab5fSopenharmony_ci            [this, superClass, cda](auto, auto *program, auto, auto name) {
1313af6ab5fSopenharmony_ci                auto *classDecl = CreateClassDeclaration(name, *cda, superClass, program);
1323af6ab5fSopenharmony_ci                return classDecl->Definition()->Ident()->Variable();
1333af6ab5fSopenharmony_ci            });
1343af6ab5fSopenharmony_ci        // clang-format on
1353af6ab5fSopenharmony_ci        superClass = helpers::CreateETSTypeReference(checker, declarationName);
1363af6ab5fSopenharmony_ci    }
1373af6ab5fSopenharmony_ci
1383af6ab5fSopenharmony_ci    return superClass;
1393af6ab5fSopenharmony_ci}
1403af6ab5fSopenharmony_ci
1413af6ab5fSopenharmony_ciutil::StringView DebugInfoDeserializer::CollectChainInfo(ArenaVector<ChainEntryInfo> &chainEntryList,
1423af6ab5fSopenharmony_ci                                                         util::StringView abcSuperName, FileDebugInfo *debugInfo)
1433af6ab5fSopenharmony_ci{
1443af6ab5fSopenharmony_ci    ASSERT(debugInfo != nullptr);
1453af6ab5fSopenharmony_ci
1463af6ab5fSopenharmony_ci    auto *proxyProgramsCache = debugInfoPlugin_.GetProxyProgramsCache();
1473af6ab5fSopenharmony_ci    auto *debugInfoStorage = debugInfoPlugin_.GetDebugInfoStorage();
1483af6ab5fSopenharmony_ci    auto *entityDeclarator = debugInfoPlugin_.GetEntityDeclarator();
1493af6ab5fSopenharmony_ci    auto *allocator = debugInfoPlugin_.GetIrCheckHelper()->GetChecker()->Allocator();
1503af6ab5fSopenharmony_ci
1513af6ab5fSopenharmony_ci    // CC-OFFNXT(G.CTL.03) false positive
1523af6ab5fSopenharmony_ci    while (true) {
1533af6ab5fSopenharmony_ci        auto *program = proxyProgramsCache->GetProgram(debugInfo->sourceFilePath);
1543af6ab5fSopenharmony_ci        ASSERT(program != nullptr);
1553af6ab5fSopenharmony_ci        if (entityDeclarator->IsEntityDeclared(program, abcSuperName)) {
1563af6ab5fSopenharmony_ci            // Go until reach A_i, which has already been declared.
1573af6ab5fSopenharmony_ci            // Object <-- A_1 <-- ... <-- A_i <-- ... <-- A_n
1583af6ab5fSopenharmony_ci            //    |                        |
1593af6ab5fSopenharmony_ci            //    +------------------------+
1603af6ab5fSopenharmony_ci            //                |
1613af6ab5fSopenharmony_ci            //             Declared
1623af6ab5fSopenharmony_ci            return abcSuperName;
1633af6ab5fSopenharmony_ci        }
1643af6ab5fSopenharmony_ci
1653af6ab5fSopenharmony_ci        // Class must be created - save necessary information about it.
1663af6ab5fSopenharmony_ci        auto classId = debugInfoStorage->FindClass(debugInfo->sourceFilePath, abcSuperName.Utf8());
1673af6ab5fSopenharmony_ci        if (!classId.IsValid()) {
1683af6ab5fSopenharmony_ci            LOG(FATAL, ES2PANDA) << "Can't find classId for " << abcSuperName;
1693af6ab5fSopenharmony_ci        }
1703af6ab5fSopenharmony_ci        auto *cda = allocator->New<panda_file::ClassDataAccessor>(*debugInfo->pf, classId);
1713af6ab5fSopenharmony_ci        chainEntryList.emplace_back(debugInfo->sourceFilePath, abcSuperName.Utf8(), cda, program);
1723af6ab5fSopenharmony_ci
1733af6ab5fSopenharmony_ci        // Update information for the next iteration.
1743af6ab5fSopenharmony_ci        auto optClassInfo = GetSuperClassModuleAndClassName(*cda, debugInfoStorage);
1753af6ab5fSopenharmony_ci        if (!optClassInfo) {
1763af6ab5fSopenharmony_ci            // Go until reach Object:
1773af6ab5fSopenharmony_ci            // std.core.Object <-- A1 <-- A2 <-- ... <-- An
1783af6ab5fSopenharmony_ci            return "";
1793af6ab5fSopenharmony_ci        }
1803af6ab5fSopenharmony_ci        std::tie(abcSuperName, debugInfo) = *optClassInfo;
1813af6ab5fSopenharmony_ci    }
1823af6ab5fSopenharmony_ci}
1833af6ab5fSopenharmony_ci
1843af6ab5fSopenharmony_ci}  // namespace ark::es2panda::evaluate
185