• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "helpers.h"
17 
18 #include "checker/types/typeFlag.h"
19 #include "checker/types/type.h"
20 #include "checker/types/ets/etsObjectType.h"
21 #include "ir/statements/blockStatement.h"
22 #include "ir/ets/etsScript.h"
23 #include "parser/program/program.h"
24 #include "ir/expressions/memberExpression.h"
25 #include "ir/expressions/callExpression.h"
26 
27 namespace ark::es2panda::compiler::ast_verifier {
28 
IsImportLike(const ir::AstNode * ast)29 bool IsImportLike(const ir::AstNode *ast)
30 {
31     return (ast->IsETSImportDeclaration() || ast->IsETSReExportDeclaration() || ast->IsImportExpression() ||
32             ast->IsImportSpecifier() || ast->IsImportDefaultSpecifier() || ast->IsImportNamespaceSpecifier());
33 }
34 
IsExportLike(const ir::AstNode * ast)35 bool IsExportLike(const ir::AstNode *ast)
36 {
37     return (ast->IsExportDefaultDeclaration() || ast->IsExportSpecifier() || ast->IsExportAllDeclaration() ||
38             ast->IsExportNamedDeclaration() || ast->IsETSReExportDeclaration());
39 }
40 
IsBooleanType(const ir::AstNode * ast)41 bool IsBooleanType(const ir::AstNode *ast)
42 {
43     if (ast == nullptr) {
44         return false;
45     }
46 
47     if (!ast->IsTyped()) {
48         return false;
49     }
50 
51     auto typedAst = static_cast<const ir::TypedAstNode *>(ast);
52 
53     if (typedAst->TsType() == nullptr) {
54         return false;
55     }
56 
57     if (typedAst->TsType()->HasTypeFlag(checker::TypeFlag::ETS_OBJECT) &&
58         ast->HasBoxingUnboxingFlags(ir::BoxingUnboxingFlags::UNBOXING_FLAG)) {
59         return typedAst->TsType()->AsETSObjectType()->HasObjectFlag(checker::ETSObjectFlags::BUILTIN_BOOLEAN);
60     }
61 
62     return typedAst->TsType()->HasTypeFlag(checker::TypeFlag::ETS_BOOLEAN) ||
63            typedAst->TsType()->HasTypeFlag(checker::TypeFlag::BOOLEAN_LIKE);
64 }
65 
IsValidTypeForBinaryOp(const ir::AstNode * ast,bool isBitwise)66 bool IsValidTypeForBinaryOp(const ir::AstNode *ast, bool isBitwise)
67 {
68     if (ast == nullptr) {
69         std::cout << __LINE__ << std::endl;
70         return false;
71     }
72 
73     if (!ast->IsTyped()) {
74         std::cout << __LINE__ << std::endl;
75         return false;
76     }
77 
78     auto typedAst = static_cast<const ir::TypedAstNode *>(ast);
79 
80     if (typedAst->TsType() == nullptr) {
81         // std::cout << typedAst
82         std::cout << __LINE__ << std::endl;
83         return false;
84     }
85 
86     if (IsBooleanType(ast)) {
87         return isBitwise;
88     }
89 
90     if (typedAst->TsType()->HasTypeFlag(checker::TypeFlag::ETS_OBJECT) &&
91         typedAst->TsType()->AsETSObjectType()->HasObjectFlag(checker::ETSObjectFlags::BUILTIN_BIGINT)) {
92         return true;
93     }
94 
95     if (typedAst->TsType()->HasTypeFlag(checker::TypeFlag::ETS_OBJECT) &&
96         ast->HasBoxingUnboxingFlags(ir::BoxingUnboxingFlags::UNBOXING_FLAG)) {
97         return typedAst->TsType()->AsETSObjectType()->HasObjectFlag(checker::ETSObjectFlags::BUILTIN_TYPE) &&
98                !typedAst->TsType()->AsETSObjectType()->HasObjectFlag(checker::ETSObjectFlags::BUILTIN_BOOLEAN);
99     }
100 
101     return typedAst->TsType()->HasTypeFlag(checker::TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC) ||
102            typedAst->TsType()->HasTypeFlag(checker::TypeFlag::NUMBER_LITERAL) ||
103            typedAst->TsType()->HasTypeFlag(checker::TypeFlag::BIGINT) ||
104            typedAst->TsType()->HasTypeFlag(checker::TypeFlag::BIGINT_LITERAL);
105 }
106 
IsStringType(const ir::AstNode * ast)107 bool IsStringType(const ir::AstNode *ast)
108 {
109     if (ast == nullptr) {
110         return false;
111     }
112 
113     if (!ast->IsTyped()) {
114         return false;
115     }
116 
117     auto typedAst = static_cast<const ir::TypedAstNode *>(ast);
118 
119     if (typedAst->TsType() == nullptr) {
120         return false;
121     }
122 
123     if (typedAst->TsType()->HasTypeFlag(checker::TypeFlag::ETS_OBJECT)) {
124         return typedAst->TsType()->AsETSObjectType()->HasObjectFlag(checker::ETSObjectFlags::STRING) ||
125                typedAst->TsType()->AsETSObjectType()->HasObjectFlag(checker::ETSObjectFlags::BUILTIN_STRING);
126     }
127 
128     return typedAst->TsType()->HasTypeFlag(checker::TypeFlag::STRING_LIKE);
129 }
130 
IsVisibleInternalNode(const ir::AstNode * ast,const ir::AstNode * objTypeDeclNode)131 bool IsVisibleInternalNode(const ir::AstNode *ast, const ir::AstNode *objTypeDeclNode)
132 {
133     // NOTE(orlovskymaxim) This relies on the fact, that GetTopStatement has no bugs, that is not the case for now
134     if (!ast->GetTopStatement()->IsETSScript()) {
135         return false;
136     }
137     auto *currentTopStatement = (static_cast<const ir::ETSScript *>(ast->GetTopStatement()));
138     auto *currentProgram = currentTopStatement->Program();
139     if (currentProgram == nullptr) {
140         return false;
141     }
142     util::StringView moduleNameCurrent = currentProgram->ModuleName();
143     // NOTE(orlovskymaxim) This relies on the fact, that GetTopStatement has no bugs, that is not the case for now
144     if (!objTypeDeclNode->GetTopStatement()->IsETSScript()) {
145         return false;
146     }
147     auto *objectTopStatement = (static_cast<const ir::ETSScript *>(objTypeDeclNode->GetTopStatement()));
148     auto *objectProgram = objectTopStatement->Program();
149     if (objectProgram == nullptr) {
150         return false;
151     }
152     util::StringView moduleNameObject = objectProgram->ModuleName();
153     return currentTopStatement == objectTopStatement || moduleNameCurrent == moduleNameObject;
154 }
155 
GetClassDefinitionType(const ir::AstNode * ast)156 const checker::Type *GetClassDefinitionType(const ir::AstNode *ast)
157 {
158     const ir::AstNode *tmpNode = ast;
159     while (tmpNode->Parent() != nullptr && !tmpNode->IsClassDefinition()) {
160         tmpNode = tmpNode->Parent();
161     }
162     if (!tmpNode->IsClassDefinition()) {
163         return nullptr;
164     }
165     auto *classDefinition = tmpNode->AsClassDefinition();
166     return classDefinition->TsType();
167 }
168 
GetTSInterfaceDeclarationType(const ir::AstNode * ast)169 const checker::Type *GetTSInterfaceDeclarationType(const ir::AstNode *ast)
170 {
171     const ir::AstNode *tmpNode = ast;
172     while (tmpNode->Parent() != nullptr && !tmpNode->IsTSInterfaceDeclaration()) {
173         tmpNode = tmpNode->Parent();
174     }
175     if (!tmpNode->IsTSInterfaceDeclaration()) {
176         return nullptr;
177     }
178     auto *tsInterfaceDeclaration = tmpNode->AsTSInterfaceDeclaration();
179     return tsInterfaceDeclaration->TsType();
180 }
181 
ValidateMethodAccessForClass(const ir::AstNode * ast,const ir::AstNode * ownerSignDeclNode,checker::Signature * signature,const ir::AstNode * memberObjTypeDeclNode)182 bool ValidateMethodAccessForClass(const ir::AstNode *ast, const ir::AstNode *ownerSignDeclNode,
183                                   checker::Signature *signature, const ir::AstNode *memberObjTypeDeclNode)
184 {
185     // Check if the method is used where it is declared
186     if (IsContainedIn<const ir::AstNode>(ast, ownerSignDeclNode)) {
187         return true;
188     }
189     if (signature->HasSignatureFlag(checker::SignatureFlags::PRIVATE)) {
190         return false;
191     }
192     if (signature->HasSignatureFlag(checker::SignatureFlags::PROTECTED)) {
193         // Check if the method is inherited and is used in class in which it is inherited
194         auto *classDefinitionType = GetClassDefinitionType(ast);
195         if (classDefinitionType == nullptr || !classDefinitionType->IsETSObjectType()) {
196             return false;
197         }
198         auto *classObjectType = classDefinitionType->AsETSObjectType();
199         return classObjectType->IsDescendantOf(signature->Owner());
200     }
201     if (signature->HasSignatureFlag(checker::SignatureFlags::INTERNAL)) {
202         return IsVisibleInternalNode(ast, memberObjTypeDeclNode);
203     }
204     return true;
205 }
206 
ValidateMethodAccessForTSInterface(const ir::AstNode * ast,const ir::AstNode * ownerSignDeclNode,checker::Signature * signature,const ir::AstNode * memberObjTypeDeclNode)207 bool ValidateMethodAccessForTSInterface(const ir::AstNode *ast, const ir::AstNode *ownerSignDeclNode,
208                                         checker::Signature *signature, const ir::AstNode *memberObjTypeDeclNode)
209 {
210     // Check if the method is used where it is declared
211     if (IsContainedIn<const ir::AstNode>(ast, ownerSignDeclNode)) {
212         return true;
213     }
214     if (signature->HasSignatureFlag(checker::SignatureFlags::PRIVATE)) {
215         return false;
216     }
217     if (signature->HasSignatureFlag(checker::SignatureFlags::PROTECTED)) {
218         // Check if the method is inherited and is used in class in which it is inherited
219         auto *tsInterfaceDeclarationType = GetTSInterfaceDeclarationType(ast);
220         if (tsInterfaceDeclarationType == nullptr || !tsInterfaceDeclarationType->IsETSObjectType()) {
221             return false;
222         }
223         auto *tsInterfaceObjectType = tsInterfaceDeclarationType->AsETSObjectType();
224         return tsInterfaceObjectType->IsDescendantOf(signature->Owner());
225     }
226     if (signature->HasSignatureFlag(checker::SignatureFlags::INTERNAL)) {
227         return IsVisibleInternalNode(ast, memberObjTypeDeclNode);
228     }
229     return true;
230 }
231 
ValidatePropertyAccessForClass(const ir::AstNode * ast,const ir::AstNode * propVarDeclNode,const ir::AstNode * propVarDeclNodeParent,const varbinder::LocalVariable * propVar,const ir::AstNode * objTypeDeclNode)232 bool ValidatePropertyAccessForClass(const ir::AstNode *ast, const ir::AstNode *propVarDeclNode,
233                                     const ir::AstNode *propVarDeclNodeParent, const varbinder::LocalVariable *propVar,
234                                     const ir::AstNode *objTypeDeclNode)
235 {
236     // Check if the variable is used where it is declared
237     if (IsContainedIn<const ir::AstNode>(ast, propVarDeclNodeParent)) {
238         return true;
239     }
240     if (propVarDeclNode->IsPrivate()) {
241         return false;
242     }
243     if (propVarDeclNode->IsProtected()) {
244         auto *classDefinitionType = GetClassDefinitionType(ast);
245         if (classDefinitionType != nullptr && classDefinitionType->IsETSObjectType()) {
246             auto *classObjectType = classDefinitionType->AsETSObjectType();
247             return classObjectType->IsPropertyOfAscendant(propVar);
248         }
249         auto *interfaceDefType = GetTSInterfaceDeclarationType(ast);
250         if (interfaceDefType != nullptr && interfaceDefType->IsETSObjectType()) {
251             auto *interfaceObjectType = interfaceDefType->AsETSObjectType();
252             return interfaceObjectType->IsPropertyOfAscendant(propVar);
253         }
254         return false;
255     }
256     if (propVarDeclNode->IsInternal()) {
257         return IsVisibleInternalNode(ast, objTypeDeclNode);
258     }
259     return true;
260 }
261 
ValidateVariableAccess(const varbinder::LocalVariable * propVar,const ir::MemberExpression * ast)262 bool ValidateVariableAccess(const varbinder::LocalVariable *propVar, const ir::MemberExpression *ast)
263 {
264     const auto *propVarDecl = propVar->Declaration();
265     if (propVarDecl == nullptr) {
266         return false;
267     }
268     const auto *propVarDeclNode = propVarDecl->Node();
269     if (propVarDeclNode == nullptr) {
270         return false;
271     }
272     auto *objType = ast->ObjType();
273     if (objType == nullptr) {
274         return false;
275     }
276     const auto *objTypeDeclNode = objType->GetDeclNode();
277     if (objTypeDeclNode == nullptr) {
278         return false;
279     }
280     if (objTypeDeclNode->Parent() != nullptr && objTypeDeclNode->Parent()->IsImportNamespaceSpecifier()) {
281         return true;
282     }
283     const auto *propVarDeclNodeParent = propVarDeclNode->Parent();
284     if (propVarDeclNodeParent == nullptr) {
285         return false;
286     }
287     if ((propVarDeclNodeParent->IsClassDefinition() && objTypeDeclNode->IsClassDefinition()) ||
288         (propVarDeclNodeParent->IsTSInterfaceDeclaration() && objTypeDeclNode->IsTSInterfaceDeclaration())) {
289         return ValidatePropertyAccessForClass(ast, propVarDeclNode, propVarDeclNodeParent, propVar, objTypeDeclNode);
290     }
291     return false;
292 }
293 
ValidateMethodAccess(const ir::MemberExpression * memberExpression,const ir::CallExpression * ast)294 bool ValidateMethodAccess(const ir::MemberExpression *memberExpression, const ir::CallExpression *ast)
295 {
296     if (memberExpression->Object()->TsType() != nullptr) {
297         // When calling enum methods member expression
298         // object has ETSEnumType instead of ETSObjectType.
299         const auto *const type = memberExpression->Object()->TsType();
300         if (type->IsETSEnumType()) {
301             return true;
302         }
303     }
304 
305     auto *memberObjType = memberExpression->ObjType();
306     if (memberObjType == nullptr) {
307         return false;
308     }
309     if (memberObjType->HasObjectFlag(checker::ETSObjectFlags::RESOLVED_SUPER) &&
310         memberObjType->SuperType() != nullptr &&
311         memberObjType->SuperType()->HasObjectFlag(checker::ETSObjectFlags::BUILTIN_TYPE |
312                                                   checker::ETSObjectFlags::GLOBAL)) {
313         return true;
314     }
315     const auto *memberObjTypeDeclNode = memberObjType->GetDeclNode();
316     if (memberObjTypeDeclNode == nullptr) {
317         return false;
318     }
319     if (memberObjTypeDeclNode->Parent() != nullptr && memberObjTypeDeclNode->Parent()->IsImportNamespaceSpecifier()) {
320         return true;
321     }
322     auto *signature = ast->Signature();
323     if (signature == nullptr) {
324         return false;
325     }
326     auto *ownerSign = signature->Owner();
327     if (ownerSign == nullptr) {
328         return false;
329     }
330     auto *ownerSignDeclNode = ownerSign->GetDeclNode();
331     if (ownerSignDeclNode == nullptr) {
332         return false;
333     }
334     if (!ownerSignDeclNode->IsClassDefinition() && !ownerSignDeclNode->IsTSInterfaceDeclaration()) {
335         return false;
336     }
337     bool ret = false;
338     if (memberObjTypeDeclNode->IsClassDefinition()) {
339         ret = ValidateMethodAccessForClass(ast, ownerSignDeclNode, signature, memberObjTypeDeclNode);
340     } else if (memberObjTypeDeclNode->IsTSInterfaceDeclaration()) {
341         ret = ValidateMethodAccessForTSInterface(ast, ownerSignDeclNode, signature, memberObjTypeDeclNode);
342     }
343     return ret;
344 }
345 
346 }  // namespace ark::es2panda::compiler::ast_verifier
347