• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 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 "checker/ETSchecker.h"
17 #include "evaluate/helpers.h"
18 
19 #include "evaluate/debugInfoDeserialization/debugInfoDeserializer.h"
20 #include "evaluate/scopedDebugInfoPlugin.h"
21 #include "evaluate/debugInfoStorage.h"
22 #include "evaluate/proxyProgramsCache.h"
23 #include "evaluate/entityDeclarator-inl.h"
24 
25 #include "libpandafile/class_data_accessor.h"
26 #include "libpandafile/file-inl.h"
27 
28 namespace ark::es2panda::evaluate {
29 
30 namespace {
31 
GetFullSuperClassName(panda_file::ClassDataAccessor & cda)32 std::string GetFullSuperClassName(panda_file::ClassDataAccessor &cda)
33 {
34     return panda_file::ClassDataAccessor::DemangledName(cda.GetPandaFile().GetStringData(cda.GetSuperClassId()));
35 }
36 
GetSuperClassModuleAndClassName(panda_file::ClassDataAccessor & cda,DebugInfoStorage * debugInfoStorage)37 std::optional<std::pair<util::StringView, FileDebugInfo *>> GetSuperClassModuleAndClassName(
38     panda_file::ClassDataAccessor &cda, DebugInfoStorage *debugInfoStorage)
39 {
40     ES2PANDA_ASSERT(debugInfoStorage);
41 
42     auto fullSuperClassName = GetFullSuperClassName(cda);
43     if (fullSuperClassName == compiler::Signatures::BUILTIN_OBJECT) {
44         // Must stop iterating upon reaching BUILTIN_OBJECT.
45         return {};
46     }
47 
48     auto [moduleName, recordName] = helpers::SplitRecordName(fullSuperClassName);
49     auto *debugInfo = debugInfoStorage->GetDebugInfoByModuleName(moduleName);
50     if (UNLIKELY(debugInfo == nullptr)) {
51         LOG(FATAL, ES2PANDA) << "Failed to find debug info for module '" << moduleName << "'";
52     }
53     // Allocate record name for later usage in compilation.
54     return std::make_pair(util::UString(recordName, debugInfoStorage->Allocator()).View(), debugInfo);
55 }
56 
57 }  // namespace
58 
59 struct ChainEntryInfo final {
ChainEntryInfoark::es2panda::evaluate::ChainEntryInfo60     explicit ChainEntryInfo(std::string_view filePath, std::string_view declName,
61                             panda_file::ClassDataAccessor *accessor, parser::Program *prog)
62         : sourceFilePath(filePath), entityDeclarationName(declName), cda(accessor), program(prog)
63     {
64         ES2PANDA_ASSERT(cda != nullptr);
65     }
66 
67     DEFAULT_MOVE_SEMANTIC(ChainEntryInfo);
68     DEFAULT_COPY_SEMANTIC(ChainEntryInfo);
69 
70     ~ChainEntryInfo() = default;
71 
72     // NOLINTBEGIN(misc-non-private-member-variables-in-classes)
73     std::string_view sourceFilePath;
74     std::string_view entityDeclarationName;
75     // Pointer is required for move semantics.
76     panda_file::ClassDataAccessor *cda {nullptr};
77     parser::Program *program {nullptr};
78     // NOLINTEND(misc-non-private-member-variables-in-classes)
79 };
80 
GetSuperClass(panda_file::ClassDataAccessor & cda)81 ir::ETSTypeReference *DebugInfoDeserializer::GetSuperClass(panda_file::ClassDataAccessor &cda)
82 {
83     auto optClassInfo = GetSuperClassModuleAndClassName(cda, debugInfoPlugin_.GetDebugInfoStorage());
84     if (!optClassInfo) {
85         return nullptr;
86     }
87     auto [superClassName, debugInfo] = *optClassInfo;
88     return ResolveInheritanceChain(superClassName, debugInfo);
89 }
90 
ResolveInheritanceChain(util::StringView abcSuperName,FileDebugInfo * debugInfo)91 ir::ETSTypeReference *DebugInfoDeserializer::ResolveInheritanceChain(util::StringView abcSuperName,
92                                                                      FileDebugInfo *debugInfo)
93 {
94     ES2PANDA_ASSERT(debugInfo);
95 
96     auto *program = debugInfoPlugin_.GetProxyProgramsCache()->GetProgram(debugInfo->sourceFilePath);
97     if (debugInfoPlugin_.GetEntityDeclarator()->IsEntityDeclared(program, abcSuperName)) {
98         // If a superclass has already been declared, then we just need to create the TypeReference of it.
99         // Note that a TypeReference is created for each of usage of the super class.
100         return helpers::CreateETSTypeReference(debugInfoPlugin_.GetIrCheckHelper()->GetChecker(), abcSuperName);
101     }
102     return ResolveInheritanceChainImpl(abcSuperName, debugInfo);
103 }
104 
ResolveInheritanceChainImpl(util::StringView abcSuperName,FileDebugInfo * debugInfo)105 ir::ETSTypeReference *DebugInfoDeserializer::ResolveInheritanceChainImpl(util::StringView abcSuperName,
106                                                                          FileDebugInfo *debugInfo)
107 {
108     auto *checker = debugInfoPlugin_.GetIrCheckHelper()->GetChecker();
109 
110     // List starting from the most derived to the base class.
111     ArenaVector<ChainEntryInfo> chainEntryList(checker->Allocator()->Adapter());
112     auto alreadyCreatedSuperClassName = CollectChainInfo(chainEntryList, abcSuperName, debugInfo);
113 
114     ir::ETSTypeReference *superClass = nullptr;
115     if (!alreadyCreatedSuperClassName.Empty()) {
116         superClass = helpers::CreateETSTypeReference(checker, util::StringView(alreadyCreatedSuperClassName));
117     }
118 
119     auto *entityDeclarator = debugInfoPlugin_.GetEntityDeclarator();
120     for (auto it = chainEntryList.rbegin(); it != chainEntryList.rend(); ++it) {
121         // Create entity in the same file in that it destinded to be declared, so import declaration should not be
122         // inserted in AST.
123         std::string_view declarationName = it->entityDeclarationName;
124         auto *cda = it->cda;
125         ES2PANDA_ASSERT(cda != nullptr);
126         // clang-format off
127         entityDeclarator->ImportGlobalEntity(it->sourceFilePath, declarationName, it->program, declarationName,
128             [this, superClass, cda](auto, auto *program, auto, auto name) {
129                 auto *classDecl = CreateClassDeclaration(name, *cda, superClass, program);
130                 return classDecl->Definition()->Ident()->Variable();
131             });
132         // clang-format on
133         superClass = helpers::CreateETSTypeReference(checker, declarationName);
134     }
135 
136     return superClass;
137 }
138 
CollectChainInfo(ArenaVector<ChainEntryInfo> & chainEntryList,util::StringView abcSuperName,FileDebugInfo * debugInfo)139 util::StringView DebugInfoDeserializer::CollectChainInfo(ArenaVector<ChainEntryInfo> &chainEntryList,
140                                                          util::StringView abcSuperName, FileDebugInfo *debugInfo)
141 {
142     ES2PANDA_ASSERT(debugInfo != nullptr);
143 
144     auto *proxyProgramsCache = debugInfoPlugin_.GetProxyProgramsCache();
145     auto *debugInfoStorage = debugInfoPlugin_.GetDebugInfoStorage();
146     auto *entityDeclarator = debugInfoPlugin_.GetEntityDeclarator();
147     auto *allocator = debugInfoPlugin_.GetIrCheckHelper()->GetChecker()->Allocator();
148 
149     // CC-OFFNXT(G.CTL.03) false positive
150     while (true) {
151         auto *program = proxyProgramsCache->GetProgram(debugInfo->sourceFilePath);
152         ES2PANDA_ASSERT(program != nullptr);
153         if (entityDeclarator->IsEntityDeclared(program, abcSuperName)) {
154             // Go until reach A_i, which has already been declared.
155             // Object <-- A_1 <-- ... <-- A_i <-- ... <-- A_n
156             //    |                        |
157             //    +------------------------+
158             //                |
159             //             Declared
160             return abcSuperName;
161         }
162 
163         // Class must be created - save necessary information about it.
164         auto classId = debugInfoStorage->FindClass(debugInfo->sourceFilePath, abcSuperName.Utf8());
165         if (!classId.IsValid()) {
166             LOG(FATAL, ES2PANDA) << "Can't find classId for " << abcSuperName;
167         }
168         auto *cda = allocator->New<panda_file::ClassDataAccessor>(*debugInfo->pf, classId);
169         chainEntryList.emplace_back(debugInfo->sourceFilePath, abcSuperName.Utf8(), cda, program);
170 
171         // Update information for the next iteration.
172         auto optClassInfo = GetSuperClassModuleAndClassName(*cda, debugInfoStorage);
173         if (!optClassInfo) {
174             // Go until reach Object:
175             // BUILTIN_OBJECT <-- A1 <-- A2 <-- ... <-- An
176             return "";
177         }
178         std::tie(abcSuperName, debugInfo) = *optClassInfo;
179     }
180 }
181 
182 }  // namespace ark::es2panda::evaluate
183