• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2024-2025 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 #include "util/diagnosticEngine.h"
20 #include <gtest/gtest.h>
21 #include <cstddef>
22 
23 using ark::es2panda::checker::ETSChecker;
24 using ark::es2panda::compiler::ast_verifier::GetterSetterValidation;
25 using ark::es2panda::ir::ETSParameterExpression;
26 using ark::es2panda::ir::Identifier;
27 using ark::es2panda::util::DiagnosticEngine;
28 namespace {
TEST_F(ASTVerifierTest,ValidateGetterReturnTypeAnnotation)29 TEST_F(ASTVerifierTest, ValidateGetterReturnTypeAnnotation)
30 {
31     DiagnosticEngine de {};
32     ETSChecker checker {de};
33 
34     char const *text =
35         R"(
36         class A {
37             private _value: number = 0;
38             get value(): number {
39                 return this._value
40             }
41 
42             set value(v: number) {
43                 this._value = v
44             }
45         }
46     )";
47 
48     auto cb = [&checker](ark::es2panda::ir::AstNode *child) {
49         if (child->IsMethodDefinition()) {
50             auto *const method = child->AsMethodDefinition();
51             if (method->IsGetter() && method->Value()->IsFunctionExpression()) {
52                 auto *const function = method->Value()->AsFunctionExpression()->Function();
53                 ASSERT_NE(function->ReturnTypeAnnotation(), nullptr);
54                 function->ReturnTypeAnnotation()->SetTsType(checker.GlobalVoidType());
55             }
56         }
57     };
58 
59     CONTEXT(ES2PANDA_STATE_CHECKED, text)
60     {
61         // Change annotation return type to void
62         GetAst()->IterateRecursively(cb);
63         EXPECT_TRUE(Verify<GetterSetterValidation>(
64             ExpectVerifierMessage {"GETTER METHOD HAS VOID RETURN TYPE IN RETURN TYPE ANNOTATION"}));
65     }
66 }
67 
TEST_F(ASTVerifierTest,ValidateGetterHasReturnStatement)68 TEST_F(ASTVerifierTest, ValidateGetterHasReturnStatement)
69 {
70     // Program with no type annotation for getter
71     char const *text =
72         R"(
73         class A {
74             private _value: number = 0;
75             get value() {
76                 return this._value
77             }
78 
79             set value(v: number) {
80                 this._value = v
81             }
82         }
83     )";
84 
85     auto cb = [](ark::es2panda::ir::AstNode *child) {
86         if (child->IsMethodDefinition()) {
87             auto *const method = child->AsMethodDefinition();
88             if (method->IsGetter() && method->Value()->IsFunctionExpression()) {
89                 auto *const function = method->Value()->AsFunctionExpression()->Function();
90                 auto &returns = function->ReturnStatements();
91                 returns.clear();
92             }
93         }
94     };
95     CONTEXT(ES2PANDA_STATE_CHECKED, text)
96     {
97         // Remove return statements from getter
98         GetAst()->IterateRecursively(cb);
99         EXPECT_TRUE(Verify<GetterSetterValidation>(
100             ExpectVerifierMessage {"MISSING RETURN TYPE ANNOTATION AND RETURN STATEMENT IN GETTER METHOD"}));
101     }
102 }
103 
TEST_F(ASTVerifierTest,ValidateGetterVoidReturnStatement)104 TEST_F(ASTVerifierTest, ValidateGetterVoidReturnStatement)
105 {
106     DiagnosticEngine de {};
107     ETSChecker checker {de};
108 
109     char const *text =
110         R"(
111         class A {
112             private _value: number = 0;
113             get value() {
114                 return this._value
115             }
116 
117             set value(v: number) {
118                 this._value = v
119             }
120         }
121     )";
122     auto cb = [&checker](ark::es2panda::ir::AstNode *child) {
123         if (child->IsMethodDefinition()) {
124             auto *const method = child->AsMethodDefinition();
125             if (method->IsGetter() && method->Value()->IsFunctionExpression()) {
126                 auto *const function = method->Value()->AsFunctionExpression()->Function();
127                 auto &returns = function->ReturnStatements();
128                 ASSERT_EQ(returns.size(), 1);
129                 returns[0]->SetArgument(nullptr);
130                 returns[0]->SetReturnType(&checker, checker.GlobalVoidType());
131             }
132         }
133     };
134     CONTEXT(ES2PANDA_STATE_CHECKED, text)
135     {
136         // Change return statement type to void
137         GetAst()->IterateRecursively(cb);
138         EXPECT_TRUE(Verify<GetterSetterValidation>(ExpectVerifierMessage {"GETTER METHOD HAS VOID RETURN TYPE"}));
139     }
140 }
141 
TEST_F(ASTVerifierTest,ValidateGetterArguments)142 TEST_F(ASTVerifierTest, ValidateGetterArguments)
143 {
144     DiagnosticEngine de {};
145     ETSChecker checker {de};
146 
147     char const *text =
148         R"(
149         class A {
150             private _value: number = 0;
151             get value(): number {
152                 return this._value
153             }
154 
155             set value(v: number) {
156                 this._value = v
157             }
158         }
159     )";
160 
161     // Create argument
162     auto *ident = checker.AllocNode<Identifier>("ident", Allocator());
163     auto *param = checker.AllocNode<ETSParameterExpression>(ident, nullptr, Allocator());
164     auto cb = [param](ark::es2panda::ir::AstNode *child) {
165         if (child->IsMethodDefinition()) {
166             auto *const method = child->AsMethodDefinition();
167             if (method->IsGetter() && method->Value()->IsFunctionExpression()) {
168                 auto *const function = method->Value()->AsFunctionExpression()->Function();
169                 auto &params = function->Params();
170                 ASSERT_EQ(params.size(), 0);
171                 params.push_back(param);
172             }
173         }
174     };
175     CONTEXT(ES2PANDA_STATE_CHECKED, text)
176     {
177         // Add argument to getter
178         GetAst()->IterateRecursively(cb);
179         EXPECT_TRUE(
180             Verify<GetterSetterValidation>(ExpectVerifierMessage {"GETTER METHOD HAS INCORRECT NUMBER OF ARGUMENTS"}));
181     }
182 }
183 
TEST_F(ASTVerifierTest,ValidateSetterReturnType)184 TEST_F(ASTVerifierTest, ValidateSetterReturnType)
185 {
186     DiagnosticEngine de {};
187     ETSChecker checker {de};
188 
189     char const *text =
190         R"(
191         class A {
192             private _value: number = 0;
193             set value(v: number) {
194                 this._value = v
195             }
196 
197             get value(): number {
198                 return this._value
199             }
200         }
201     )";
202     auto cb = [&checker](ark::es2panda::ir::AstNode *child) {
203         if (child->IsMethodDefinition()) {
204             auto *const method = child->AsMethodDefinition();
205             if (method->IsSetter() && method->Value()->IsFunctionExpression()) {
206                 auto *const function = method->Value()->AsFunctionExpression()->Function();
207                 ASSERT_EQ(function->ReturnTypeAnnotation(), nullptr);
208                 auto *const thisType = function->Signature()->Params()[0]->TsType();
209                 auto *const thisTypeAnnotation =
210                     function->Params()[0]->AsETSParameterExpression()->Ident()->TypeAnnotation();
211                 function->Signature()->SetReturnType(thisType);
212                 function->SetReturnTypeAnnotation(thisTypeAnnotation->Clone(checker.Allocator(), function));
213             }
214         }
215     };
216 
217     CONTEXT(ES2PANDA_STATE_CHECKED, text)
218     {
219         // Change setter return type
220         GetAst()->IterateRecursively(cb);
221         EXPECT_TRUE(Verify<GetterSetterValidation>(ExpectVerifierMessage {"SETTER METHOD MUST NOT HAVE RETURN TYPE"}));
222     }
223 }
224 
TEST_F(ASTVerifierTest,ValidateSetterArguments)225 TEST_F(ASTVerifierTest, ValidateSetterArguments)
226 {
227     DiagnosticEngine de {};
228     ETSChecker checker {de};
229 
230     char const *text =
231         R"(
232         class A {
233             private _value: number = 0;
234             set value(v: number) {
235                 this._value = v
236             }
237 
238             get value(): number {
239                 return this._value
240             }
241         }
242     )";
243     auto cb = [](ark::es2panda::ir::AstNode *child) {
244         if (child->IsMethodDefinition()) {
245             auto *const method = child->AsMethodDefinition();
246             if (method->IsSetter() && method->Value()->IsFunctionExpression()) {
247                 auto *const function = method->Value()->AsFunctionExpression()->Function();
248                 auto &params = function->Params();
249                 ASSERT_EQ(params.size(), 1);
250                 params.clear();
251             }
252         }
253     };
254     CONTEXT(ES2PANDA_STATE_CHECKED, text)
255     {
256         // Change setter arguments
257         GetAst()->IterateRecursively(cb);
258         EXPECT_TRUE(
259             Verify<GetterSetterValidation>(ExpectVerifierMessage {"SETTER METHOD HAS INCORRECT NUMBER OF ARGUMENTS"}));
260     }
261 }
262 
263 }  // anonymous namespace
264