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 "ast_verifier_test.h"
17 #include "checker/ETSchecker.h"
18 #include "ir/astNode.h"
19
20 #include <gtest/gtest.h>
21
22 using ark::es2panda::checker::ETSChecker;
23 using ark::es2panda::compiler::ast_verifier::ASTVerifier;
24 using ark::es2panda::compiler::ast_verifier::InvariantNameSet;
25 using ark::es2panda::ir::AstNode;
26 using ark::es2panda::ir::ETSParameterExpression;
27 using ark::es2panda::ir::Identifier;
28 using ark::es2panda::ir::MethodDefinitionKind;
29
30 namespace {
31
TEST_F(ASTVerifierTest,ValidateGetterArguments)32 TEST_F(ASTVerifierTest, ValidateGetterArguments)
33 {
34 ETSChecker checker {};
35 ASTVerifier verifier {Allocator()};
36
37 char const *text =
38 R"(
39 class A {
40 private _value: number = 0;
41 get value(): number {
42 return this._value
43 }
44
45 set value(v: number): void {
46 this._value = v
47 }
48 }
49 )";
50
51 es2panda_Context *ctx = impl_->CreateContextFromString(cfg_, text, "dummy.ets");
52 impl_->ProceedToState(ctx, ES2PANDA_STATE_CHECKED);
53 ASSERT_EQ(impl_->ContextState(ctx), ES2PANDA_STATE_CHECKED);
54
55 auto *ast = reinterpret_cast<AstNode *>(impl_->ProgramAst(impl_->ContextProgram(ctx)));
56
57 // Create argument
58 auto *ident = checker.AllocNode<Identifier>("ident", Allocator());
59 auto *param = checker.AllocNode<ETSParameterExpression>(ident, nullptr);
60
61 // Add argument to getter
62 ast->IterateRecursively([param](ark::es2panda::ir::AstNode *child) {
63 if (child->IsMethodDefinition()) {
64 auto *const method = child->AsMethodDefinition();
65 if (method->Kind() == MethodDefinitionKind::GET && method->Value()->IsFunctionExpression()) {
66 auto *const function = method->Value()->AsFunctionExpression()->Function();
67 auto ¶ms = function->Params();
68 ASSERT_EQ(params.size(), 0);
69 params.push_back(param);
70 }
71 }
72 });
73
74 InvariantNameSet checks;
75 checks.insert("GetterSetterValidationForAll");
76 const auto &messages = verifier.Verify(ast, checks);
77
78 // Expecting warning
79 ASSERT_EQ(messages.size(), 1);
80 ASSERT_EQ(messages[0].Cause(), "GETTER METHOD HAS INCORRECT NUMBER OF ARGUMENTS");
81
82 impl_->DestroyContext(ctx);
83 }
84
TEST_F(ASTVerifierTest,ValidateSetterReturnType)85 TEST_F(ASTVerifierTest, ValidateSetterReturnType)
86 {
87 ETSChecker checker {};
88 ASTVerifier verifier {Allocator()};
89
90 char const *text =
91 R"(
92 class A {
93 private _value: number = 0;
94 set value(v: number): void {
95 this._value = v
96 }
97
98 get value(): number {
99 return this._value
100 }
101 }
102 )";
103
104 es2panda_Context *ctx = impl_->CreateContextFromString(cfg_, text, "dummy.ets");
105 impl_->ProceedToState(ctx, ES2PANDA_STATE_CHECKED);
106 ASSERT_EQ(impl_->ContextState(ctx), ES2PANDA_STATE_CHECKED);
107
108 auto *ast = reinterpret_cast<AstNode *>(impl_->ProgramAst(impl_->ContextProgram(ctx)));
109
110 // Change setter return type
111 ast->IterateRecursively([&checker](ark::es2panda::ir::AstNode *child) {
112 if (child->IsMethodDefinition()) {
113 auto *const method = child->AsMethodDefinition();
114 if (method->Kind() == MethodDefinitionKind::SET && method->Value()->IsFunctionExpression()) {
115 auto *const function = method->Value()->AsFunctionExpression()->Function();
116 ASSERT_NE(function->ReturnTypeAnnotation(), nullptr);
117 function->ReturnTypeAnnotation()->SetTsType(checker.GlobalIntType());
118 }
119 }
120 });
121
122 InvariantNameSet checks;
123 checks.insert("GetterSetterValidationForAll");
124 const auto &messages = verifier.Verify(ast, checks);
125
126 // Expecting warning
127 ASSERT_EQ(messages.size(), 1);
128 ASSERT_EQ(messages[0].Cause(), "SETTER METHOD HAS NON-VOID RETURN TYPE");
129
130 impl_->DestroyContext(ctx);
131 }
132
TEST_F(ASTVerifierTest,ValidateSetterArguments)133 TEST_F(ASTVerifierTest, ValidateSetterArguments)
134 {
135 ETSChecker checker {};
136 ASTVerifier verifier {Allocator()};
137
138 char const *text =
139 R"(
140 class A {
141 private _value: number = 0;
142 set value(v: number): void {
143 this._value = v
144 }
145
146 get value(): number {
147 return this._value
148 }
149 }
150 )";
151
152 es2panda_Context *ctx = impl_->CreateContextFromString(cfg_, text, "dummy.ets");
153 impl_->ProceedToState(ctx, ES2PANDA_STATE_CHECKED);
154 ASSERT_EQ(impl_->ContextState(ctx), ES2PANDA_STATE_CHECKED);
155
156 auto *ast = reinterpret_cast<AstNode *>(impl_->ProgramAst(impl_->ContextProgram(ctx)));
157
158 // Change setter arguments
159 ast->IterateRecursively([](ark::es2panda::ir::AstNode *child) {
160 if (child->IsMethodDefinition()) {
161 auto *const method = child->AsMethodDefinition();
162 if (method->Kind() == MethodDefinitionKind::SET && method->Value()->IsFunctionExpression()) {
163 auto *const function = method->Value()->AsFunctionExpression()->Function();
164 auto ¶ms = function->Params();
165 ASSERT_EQ(params.size(), 1);
166 params.clear();
167 }
168 }
169 });
170
171 InvariantNameSet checks;
172 checks.insert("GetterSetterValidationForAll");
173 const auto &messages = verifier.Verify(ast, checks);
174
175 // Expecting warning
176 ASSERT_EQ(messages.size(), 1);
177 ASSERT_EQ(messages[0].Cause(), "SETTER METHOD HAS INCORRECT NUMBER OF ARGUMENTS");
178
179 impl_->DestroyContext(ctx);
180 }
181 } // anonymous namespace
182