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
27 namespace ark::es2panda::compiler::ast_verifier {
28
operator ()(CheckContext &ctx, const ir::AstNode *ast)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
ValidateExport(const varbinder::Variable *var)63 bool 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
InvariantImportExportMethod(const std::unordered_set<std::string> &importedVariables, const varbinder::Variable *varCallee, const ir::AstNode *callExpr, util::StringView name)76 bool 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
InvariantImportExportVariable(const std::unordered_set<std::string> &importedVariables, const varbinder::Variable *var, const ir::Identifier *ident, util::StringView name)99 bool 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
HandleImportExportIdentifier(std::unordered_set<std::string> &importedVariables, const ir::Identifier *ident, const ir::AstNode *callExpr)124 bool 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