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 "importExportAccessValid.h" 17#include "helpers.h" 18#include "ir/expressions/callExpression.h" 19#include "checker/types/ets/etsObjectType.h" 20#include "ir/module/importSpecifier.h" 21#include "ir/module/importNamespaceSpecifier.h" 22#include "ir/module/importDefaultSpecifier.h" 23#include "ir/expressions/identifier.h" 24#include "ir/ets/etsImportDeclaration.h" 25#include "checker/types/signature.h" 26 27namespace ark::es2panda::compiler::ast_verifier { 28 29[[nodiscard]] CheckResult ImportExportAccessValid::operator()(CheckContext &ctx, const ir::AstNode *ast) 30{ 31 std::unordered_set<std::string> importedVariables {}; 32 if (ast->IsETSImportDeclaration()) { 33 const auto importDecl = ast->AsETSImportDeclaration()->Specifiers(); 34 const auto name = [](ir::AstNode *const specifier) { 35 if (specifier->IsImportNamespaceSpecifier()) { 36 return specifier->AsImportNamespaceSpecifier()->Local()->Name(); 37 } 38 if (specifier->IsImportSpecifier()) { 39 return specifier->AsImportSpecifier()->Local()->Name(); 40 } 41 return specifier->AsImportDefaultSpecifier()->Local()->Name(); 42 }; 43 for (const auto import : importDecl) { 44 importedVariables.emplace(name(import)); 45 } 46 } 47 if (ast->IsCallExpression()) { 48 const auto *callExpr = ast->AsCallExpression(); 49 const auto *callee = callExpr->Callee(); 50 if (callee != nullptr && callee->IsIdentifier() && 51 !HandleImportExportIdentifier(importedVariables, callee->AsIdentifier(), callExpr)) { 52 ctx.AddCheckMessage("PROPERTY_NOT_VISIBLE_HERE(NOT_EXPORTED)", *callee, callee->Start()); 53 return {CheckDecision::INCORRECT, CheckAction::CONTINUE}; 54 } 55 } 56 if (ast->IsIdentifier() && !HandleImportExportIdentifier(importedVariables, ast->AsIdentifier(), nullptr)) { 57 ctx.AddCheckMessage("PROPERTY_NOT_VISIBLE_HERE(NOT_EXPORTED)", *ast, ast->Start()); 58 return {CheckDecision::INCORRECT, CheckAction::CONTINUE}; 59 } 60 return {CheckDecision::CORRECT, CheckAction::CONTINUE}; 61} 62 63bool ImportExportAccessValid::ValidateExport(const varbinder::Variable *var) 64{ 65 const auto *decl = var->Declaration(); 66 if (decl == nullptr) { 67 return false; 68 } 69 const auto *node = decl->Node(); 70 if (node == nullptr) { 71 return false; 72 } 73 return node->IsExported() || node->IsExportedType(); 74} 75 76bool ImportExportAccessValid::InvariantImportExportMethod(const std::unordered_set<std::string> &importedVariables, 77 const varbinder::Variable *varCallee, 78 const ir::AstNode *callExpr, util::StringView name) 79{ 80 auto *signature = callExpr->AsCallExpression()->Signature(); 81 if (signature == nullptr || signature->Owner() == nullptr) { 82 // NOTE(vpukhov): Add a synthetic owner for dynamic signatures 83 ASSERT(callExpr->AsCallExpression()->Callee()->TsType()->HasTypeFlag(checker::TypeFlag::ETS_DYNAMIC_FLAG)); 84 return true; 85 } 86 87 if (signature != nullptr && varCallee->Declaration() != nullptr && varCallee->Declaration()->Node() != nullptr && 88 !IsContainedIn(varCallee->Declaration()->Node(), signature->Owner()->GetDeclNode()) && 89 varCallee->Declaration()->Node() != signature->Owner()->GetDeclNode()) { 90 if (importedVariables.find(name.Mutf8()) != importedVariables.end() || 91 importedVariables.find("") != importedVariables.end()) { 92 return ValidateExport(varCallee); 93 } 94 return false; 95 } 96 return true; 97} 98 99bool ImportExportAccessValid::InvariantImportExportVariable(const std::unordered_set<std::string> &importedVariables, 100 const varbinder::Variable *var, const ir::Identifier *ident, 101 util::StringView name) 102{ 103 if (!var->HasFlag(varbinder::VariableFlags::LOCAL) && !var->HasFlag(varbinder::VariableFlags::VAR) && 104 var->HasFlag(varbinder::VariableFlags::INITIALIZED) && var->Declaration() != nullptr && 105 var->Declaration()->Node() != nullptr && !var->Declaration()->Node()->IsMethodDefinition() && 106 !var->Declaration()->Node()->IsClassProperty()) { 107 auto varParent = var->Declaration()->Node()->Parent(); 108 if (varParent != nullptr && !IsContainedIn(ident->Parent(), varParent) && ident->Parent() != varParent) { 109 if (var->GetScope() != nullptr && var->GetScope()->Parent() != nullptr && 110 var->GetScope()->Parent()->IsGlobalScope() && 111 ident->GetTopStatement() == varParent->GetTopStatement()) { 112 return true; 113 } 114 if (importedVariables.find(name.Mutf8()) != importedVariables.end() || 115 importedVariables.find("") != importedVariables.end()) { 116 return ValidateExport(var); 117 } 118 return false; 119 } 120 } 121 return true; 122} 123 124bool ImportExportAccessValid::HandleImportExportIdentifier(std::unordered_set<std::string> &importedVariables, 125 const ir::Identifier *ident, const ir::AstNode *callExpr) 126{ 127 if (ident->IsReference()) { 128 const auto *var = ident->Variable(); 129 if (var != nullptr) { 130 if (var->HasFlag(varbinder::VariableFlags::METHOD) && callExpr != nullptr) { 131 return InvariantImportExportMethod(importedVariables, var, callExpr, ident->Name()); 132 } 133 return InvariantImportExportVariable(importedVariables, var, ident, ident->Name()); 134 } 135 } 136 return true; 137} 138 139} // namespace ark::es2panda::compiler::ast_verifier 140