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 "getterSetterValidation.h" 17#include "ir/expression.h" 18#include "ir/expressions/functionExpression.h" 19#include "ir/typeNode.h" 20#include "ir/base/methodDefinition.h" 21#include "ir/base/scriptFunction.h" 22 23namespace ark::es2panda::compiler::ast_verifier { 24 25[[nodiscard]] CheckResult GetterSetterValidation::operator()(CheckContext &ctx, const ir::AstNode *ast) 26{ 27 if (!ast->IsMethodDefinition()) { 28 return {CheckDecision::CORRECT, CheckAction::CONTINUE}; 29 } 30 31 bool errorFound = false; 32 auto const validateMethod = [&ctx, &errorFound, this](ir::MethodDefinition const *const method) { 33 auto const kind = method->Kind(); 34 if (kind == ir::MethodDefinitionKind::GET) { 35 errorFound |= !ValidateGetter(ctx, method); 36 } else if (kind == ir::MethodDefinitionKind::SET) { 37 errorFound |= !ValidateSetter(ctx, method); 38 }; 39 }; 40 41 auto const *const method = ast->AsMethodDefinition(); 42 validateMethod(method); 43 for (auto const *const overload : method->Overloads()) { 44 validateMethod(overload); 45 } 46 47 if (errorFound) { 48 return {CheckDecision::INCORRECT, CheckAction::CONTINUE}; 49 } 50 51 return {CheckDecision::CORRECT, CheckAction::CONTINUE}; 52} 53 54bool GetterSetterValidation::ValidateGetter(CheckContext &ctx, ir::MethodDefinition const *const method) const 55{ 56 if (!method->Value()->IsFunctionExpression()) { 57 return true; 58 } 59 60 bool result = true; 61 auto const report = [&ctx, &result, method](const std::string &msg) { 62 ctx.AddCheckMessage(msg, *method, method->Start()); 63 result = false; 64 }; 65 66 auto const *const function = method->Value()->AsFunctionExpression()->Function(); 67 68 // Check getter flag 69 if (!function->IsGetter()) { 70 report("GETTER METHOD DOES NOT HAVE GETTER FLAG"); 71 } 72 73 // Check return type annotation if it exists 74 if (function->ReturnTypeAnnotation() != nullptr) { 75 auto const *const type = function->ReturnTypeAnnotation()->TsType(); 76 if (type != nullptr && type->IsETSVoidType()) { 77 report("GETTER METHOD HAS VOID RETURN TYPE IN RETURN TYPE ANNOTATION"); 78 } 79 } 80 81 // For non-abstract and non-ambient getters return statement should always exist 82 if (!function->HasReturnStatement() && !function->IsAbstract() && !function->IsDeclare()) { 83 report("MISSING RETURN STATEMENT IN GETTER METHOD"); 84 } 85 86 // Check return statements 87 auto const &returns = function->ReturnStatements(); 88 if (function->ReturnTypeAnnotation() == nullptr) { 89 if (returns.empty()) { 90 report("MISSING RETURN TYPE ANNOTATION AND RETURN STATEMENT IN GETTER METHOD"); 91 } 92 } 93 94 // Check that all return statements are not void 95 for (auto const *const stmt : returns) { 96 if (stmt->ReturnType()->IsETSVoidType()) { 97 // All getters should have non-void return type 98 report("GETTER METHOD HAS VOID RETURN TYPE"); 99 } 100 } 101 102 // Check number of arguments 103 auto const ¶ms = function->Params(); 104 if (!params.empty()) { 105 report("GETTER METHOD HAS INCORRECT NUMBER OF ARGUMENTS"); 106 } 107 108 return result; 109} 110 111bool GetterSetterValidation::ValidateSetter(CheckContext &ctx, ir::MethodDefinition const *const method) const 112{ 113 if (!method->Value()->IsFunctionExpression()) { 114 return true; 115 } 116 117 bool result = true; 118 auto const report = [&ctx, &result, method](const std::string &msg) { 119 ctx.AddCheckMessage(msg, *method, method->Start()); 120 result = false; 121 }; 122 123 auto const *const function = method->Value()->AsFunctionExpression()->Function(); 124 125 // Check setter flag 126 if (!function->IsSetter()) { 127 report("SETTER METHOD DOES NOT HAVE SETTER FLAG"); 128 } 129 130 // Check return type annotation 131 if (function->ReturnTypeAnnotation() != nullptr) { 132 auto const *const type = function->ReturnTypeAnnotation()->TsType(); 133 if (type != nullptr && !type->IsETSVoidType()) { 134 report("SETTER METHOD HAS NON-VOID RETURN TYPE"); 135 } 136 } 137 138 // Check number of arguments 139 auto const ¶ms = function->Params(); 140 if (params.size() != 1) { 141 report("SETTER METHOD HAS INCORRECT NUMBER OF ARGUMENTS"); 142 } 143 144 return result; 145} 146 147} // namespace ark::es2panda::compiler::ast_verifier 148