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 27namespace ark::es2panda::compiler::ast_verifier { 28 29bool IsImportLike(const ir::AstNode *ast) 30{ 31 return (ast->IsETSImportDeclaration() || ast->IsETSReExportDeclaration() || ast->IsImportExpression() || 32 ast->IsImportSpecifier() || ast->IsImportDefaultSpecifier() || ast->IsImportNamespaceSpecifier()); 33} 34 35bool IsExportLike(const ir::AstNode *ast) 36{ 37 return (ast->IsExportDefaultDeclaration() || ast->IsExportSpecifier() || ast->IsExportAllDeclaration() || 38 ast->IsExportNamedDeclaration() || ast->IsETSReExportDeclaration()); 39} 40 41bool 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 66bool 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 107bool 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 131bool 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 156const 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 169const 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 182bool 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 207bool 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 232bool 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 return false; 247 } 248 auto *classObjectType = classDefinitionType->AsETSObjectType(); 249 return classObjectType->IsPropertyOfAscendant(propVar); 250 } 251 if (propVarDeclNode->IsInternal()) { 252 return IsVisibleInternalNode(ast, objTypeDeclNode); 253 } 254 return true; 255} 256 257bool ValidateVariableAccess(const varbinder::LocalVariable *propVar, const ir::MemberExpression *ast) 258{ 259 const auto *propVarDecl = propVar->Declaration(); 260 if (propVarDecl == nullptr) { 261 return false; 262 } 263 const auto *propVarDeclNode = propVarDecl->Node(); 264 if (propVarDeclNode == nullptr) { 265 return false; 266 } 267 auto *objType = ast->ObjType(); 268 if (objType == nullptr) { 269 return false; 270 } 271 const auto *objTypeDeclNode = objType->GetDeclNode(); 272 if (objTypeDeclNode == nullptr) { 273 return false; 274 } 275 if (objTypeDeclNode->Parent() != nullptr && objTypeDeclNode->Parent()->IsImportNamespaceSpecifier()) { 276 return true; 277 } 278 const auto *propVarDeclNodeParent = propVarDeclNode->Parent(); 279 if (propVarDeclNodeParent == nullptr) { 280 return false; 281 } 282 if (propVarDeclNodeParent->IsClassDefinition() && objTypeDeclNode->IsClassDefinition()) { 283 return ValidatePropertyAccessForClass(ast, propVarDeclNode, propVarDeclNodeParent, propVar, objTypeDeclNode); 284 } 285 return false; 286} 287 288bool ValidateMethodAccess(const ir::MemberExpression *memberExpression, const ir::CallExpression *ast) 289{ 290 auto *memberObjType = memberExpression->ObjType(); 291 if (memberObjType == nullptr) { 292 return false; 293 } 294 if (memberObjType->HasObjectFlag(checker::ETSObjectFlags::RESOLVED_SUPER) && 295 memberObjType->SuperType() != nullptr && 296 memberObjType->SuperType()->HasObjectFlag(checker::ETSObjectFlags::BUILTIN_TYPE | 297 checker::ETSObjectFlags::GLOBAL)) { 298 return true; 299 } 300 const auto *memberObjTypeDeclNode = memberObjType->GetDeclNode(); 301 if (memberObjTypeDeclNode == nullptr) { 302 return false; 303 } 304 if (memberObjTypeDeclNode->Parent() != nullptr && memberObjTypeDeclNode->Parent()->IsImportNamespaceSpecifier()) { 305 return true; 306 } 307 auto *signature = ast->Signature(); 308 if (signature == nullptr) { 309 return false; 310 } 311 auto *ownerSign = signature->Owner(); 312 if (ownerSign == nullptr) { 313 return false; 314 } 315 auto *ownerSignDeclNode = ownerSign->GetDeclNode(); 316 if (ownerSignDeclNode == nullptr) { 317 return false; 318 } 319 if (!ownerSignDeclNode->IsClassDefinition() && !ownerSignDeclNode->IsTSInterfaceDeclaration()) { 320 return false; 321 } 322 bool ret = false; 323 if (memberObjTypeDeclNode->IsClassDefinition()) { 324 ret = ValidateMethodAccessForClass(ast, ownerSignDeclNode, signature, memberObjTypeDeclNode); 325 } else if (memberObjTypeDeclNode->IsTSInterfaceDeclaration()) { 326 ret = ValidateMethodAccessForTSInterface(ast, ownerSignDeclNode, signature, memberObjTypeDeclNode); 327 } 328 return ret; 329} 330 331} // namespace ark::es2panda::compiler::ast_verifier 332