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 "evaluate/pathResolver.h" 17#include "evaluate/debugInfoStorage.h" 18 19#include "parser/program/program.h" 20 21namespace ark::es2panda::evaluate { 22 23void PathResolver::FindImportedFunctions(ArenaVector<EntityInfo> &overloadSet, std::string_view filePath, 24 std::string_view entityName) 25{ 26 // NOTE: cache all the resolved paths. 27 auto *table = debugInfoStorage_.GetImportExportTable(filePath); 28 if (table == nullptr) { 29 LOG(WARNING, ES2PANDA) << "Failed to find import/export table for " << filePath; 30 return; 31 } 32 33 // `import * as B from "C"` should not be searched, as it handled differently in compiler. 34 const auto &imports = table->GetImports(); 35 auto optOverloadSet = imports.find(entityName); 36 if (optOverloadSet == imports.end()) { 37 return; 38 } 39 40 ASSERT(!optOverloadSet->second.empty()); 41 for (const auto &[path, entity] : optOverloadSet->second) { 42 // `import {A as B} from "C"` 43 FindExportedFunctions(overloadSet, path, entity); 44 } 45} 46 47void PathResolver::FindExportedFunctions(ArenaVector<EntityInfo> &overloadSet, std::string_view filePath, 48 std::string_view entityName) 49{ 50 // NOTE: cache all the resolved paths. 51 auto *table = debugInfoStorage_.GetImportExportTable(filePath); 52 if (table == nullptr) { 53 LOG(WARNING, ES2PANDA) << "Failed to find import/export table for " << filePath; 54 return; 55 } 56 57 const auto &exports = table->GetExports(); 58 const auto optOverloadSet = exports.find(entityName); 59 if (optOverloadSet != exports.end()) { 60 ASSERT(!optOverloadSet->second.empty()); 61 for (const auto &[path, entity] : optOverloadSet->second) { 62 // `export {A as B} from "C"` 63 if (path.empty()) { 64 overloadSet.push_back(EntityInfo(filePath, entity)); 65 } else { 66 FindExportedFunctions(overloadSet, path, entity); 67 } 68 } 69 } 70 71 // Still need to traverse re-export-all statements to fill the complete overload set. 72 const auto optReExportAll = exports.find(STAR_IMPORT); 73 if (optReExportAll != exports.end()) { 74 ASSERT(!optReExportAll->second.empty()); 75 for (const auto &[path, entity] : optReExportAll->second) { 76 // export * from "C" 77 (void)entity; 78 ASSERT(entity == STAR_IMPORT); 79 80 FindExportedFunctions(overloadSet, path, entityName); 81 } 82 } 83} 84 85std::string_view PathResolver::FindNamedImportAll(std::string_view filePath, std::string_view bindingName) 86{ 87 auto *table = debugInfoStorage_.GetImportExportTable(filePath); 88 if (table == nullptr) { 89 LOG(WARNING, ES2PANDA) << "Failed to find import/export table for " << filePath; 90 return {}; 91 } 92 93 const auto &imports = table->GetImports(); 94 auto optEntity = imports.find(bindingName); 95 if (optEntity == imports.end()) { 96 return {}; 97 } 98 99 ASSERT(!optEntity->second.empty()); 100 for (const auto &[path, entity] : optEntity->second) { 101 if (entity == STAR_IMPORT) { 102 return path; 103 } 104 } 105 return {}; 106} 107 108std::optional<EntityInfo> PathResolver::FindImportedEntity(std::string_view filePath, std::string_view entityName) 109{ 110 // NOTE: cache all the resolved paths. 111 auto *table = debugInfoStorage_.GetImportExportTable(filePath); 112 if (table == nullptr) { 113 LOG(WARNING, ES2PANDA) << "Failed to find import/export table for " << filePath; 114 return {}; 115 } 116 117 // `import * as B from "C"` should not be searched, as it handled differently in compiler. 118 const auto &imports = table->GetImports(); 119 auto optEntity = imports.find(entityName); 120 if (optEntity == imports.end()) { 121 return {}; 122 } 123 124 ASSERT(!optEntity->second.empty()); 125 if (optEntity->second.size() > 1) { 126 // Have more than one imports for the given name - it could not be a variable. 127 return {}; 128 } 129 // `import {A as B} from "C"` 130 auto [path, entity] = optEntity->second[0]; 131 return FindExportedEntity(path, entity); 132} 133 134// Note that the current implementation does not guarantee that the found entity is indeed a variable, 135// so users must check it manually by traversing the found file's ETSGLOBAL fields. 136std::optional<EntityInfo> PathResolver::FindExportedEntity(std::string_view filePath, std::string_view entityName) 137{ 138 // NOTE: cache all the resolved paths. 139 auto *table = debugInfoStorage_.GetImportExportTable(filePath); 140 if (table == nullptr) { 141 LOG(WARNING, ES2PANDA) << "Failed to find import/export table for " << filePath; 142 return {}; 143 } 144 145 const auto &exports = table->GetExports(); 146 const auto optOverloadSet = exports.find(entityName); 147 if (optOverloadSet != exports.end()) { 148 ASSERT(!optOverloadSet->second.empty()); 149 if (optOverloadSet->second.size() > 1) { 150 // Have more than one imports for the given name, but we search for the single one - variable or class. 151 return {}; 152 } 153 // export {A as B} from "C" 154 const auto &[path, entity] = optOverloadSet->second[0]; 155 if (path.empty()) { 156 return EntityInfo(filePath, entity); 157 } 158 return FindExportedEntity(path, entity); 159 } 160 161 const auto optReExportAll = exports.find(STAR_IMPORT); 162 if (optReExportAll != exports.end()) { 163 ASSERT(!optReExportAll->second.empty()); 164 for (const auto &[path, entity] : optReExportAll->second) { 165 // export * from "C" 166 (void)entity; 167 ASSERT(entity == STAR_IMPORT); 168 169 auto optResult = FindExportedEntity(path, entityName); 170 if (optResult) { 171 return optResult; 172 } 173 } 174 } 175 176 return {}; 177} 178 179} // namespace ark::es2panda::evaluate 180