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