• 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 "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::MethodDefinitionKind;
27 
28 namespace {
TEST_F(ASTVerifierTest,ValidateGetterReturnTypeAnnotation)29 TEST_F(ASTVerifierTest, ValidateGetterReturnTypeAnnotation)
30 {
31     ETSChecker checker {};
32     ASTVerifier verifier {Allocator()};
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): void {
43                 this._value = v
44             }
45         }
46     )";
47 
48     es2panda_Context *ctx = impl_->CreateContextFromString(cfg_, text, "dummy.sts");
49     impl_->ProceedToState(ctx, ES2PANDA_STATE_CHECKED);
50     ASSERT_EQ(impl_->ContextState(ctx), ES2PANDA_STATE_CHECKED);
51 
52     auto *ast = reinterpret_cast<AstNode *>(impl_->ProgramAst(impl_->ContextProgram(ctx)));
53 
54     // Change annotation return type to void
55     ast->IterateRecursively([&checker](ark::es2panda::ir::AstNode *child) {
56         if (child->IsMethodDefinition()) {
57             auto *const method = child->AsMethodDefinition();
58             if (method->Kind() == MethodDefinitionKind::GET && method->Value()->IsFunctionExpression()) {
59                 auto *const function = method->Value()->AsFunctionExpression()->Function();
60                 ASSERT_NE(function->ReturnTypeAnnotation(), nullptr);
61                 function->ReturnTypeAnnotation()->SetTsType(checker.GlobalVoidType());
62             }
63         }
64     });
65 
66     InvariantNameSet checks;
67     checks.insert("GetterSetterValidationForAll");
68     const auto &messages = verifier.Verify(ast, checks);
69 
70     ASSERT_EQ(messages.size(), 1);
71     ASSERT_EQ(messages[0].Cause(), "GETTER METHOD HAS VOID RETURN TYPE IN RETURN TYPE ANNOTATION");
72 
73     impl_->DestroyContext(ctx);
74 }
75 
TEST_F(ASTVerifierTest,ValidateGetterHasReturnStatement)76 TEST_F(ASTVerifierTest, ValidateGetterHasReturnStatement)
77 {
78     ASTVerifier verifier {Allocator()};
79 
80     // Program with no type annotation for getter
81     char const *text =
82         R"(
83         class A {
84             private _value: number = 0;
85             get value() {
86                 return this._value
87             }
88 
89             set value(v: number): void {
90                 this._value = v
91             }
92         }
93     )";
94 
95     es2panda_Context *ctx = impl_->CreateContextFromString(cfg_, text, "dummy.sts");
96     impl_->ProceedToState(ctx, ES2PANDA_STATE_CHECKED);
97     ASSERT_EQ(impl_->ContextState(ctx), ES2PANDA_STATE_CHECKED);
98 
99     auto *ast = reinterpret_cast<AstNode *>(impl_->ProgramAst(impl_->ContextProgram(ctx)));
100 
101     // Remove return statements from getter
102     ast->IterateRecursively([](ark::es2panda::ir::AstNode *child) {
103         if (child->IsMethodDefinition()) {
104             auto *const method = child->AsMethodDefinition();
105             if (method->Kind() == MethodDefinitionKind::GET && method->Value()->IsFunctionExpression()) {
106                 auto *const function = method->Value()->AsFunctionExpression()->Function();
107                 auto &returns = function->ReturnStatements();
108                 returns.clear();
109             }
110         }
111     });
112 
113     InvariantNameSet checks;
114     checks.insert("GetterSetterValidationForAll");
115     const auto &messages = verifier.Verify(ast, checks);
116 
117     ASSERT_EQ(messages.size(), 1);
118     ASSERT_EQ(messages[0].Cause(), "MISSING RETURN TYPE ANNOTATION AND RETURN STATEMENT IN GETTER METHOD");
119 
120     impl_->DestroyContext(ctx);
121 }
122 
TEST_F(ASTVerifierTest,ValidateGetterVoidReturnStatement)123 TEST_F(ASTVerifierTest, ValidateGetterVoidReturnStatement)
124 {
125     ETSChecker checker {};
126     ASTVerifier verifier {Allocator()};
127 
128     char const *text =
129         R"(
130         class A {
131             private _value: number = 0;
132             get value() {
133                 return this._value
134             }
135 
136             set value(v: number): void {
137                 this._value = v
138             }
139         }
140     )";
141 
142     es2panda_Context *ctx = impl_->CreateContextFromString(cfg_, text, "dummy.sts");
143     impl_->ProceedToState(ctx, ES2PANDA_STATE_CHECKED);
144     ASSERT_EQ(impl_->ContextState(ctx), ES2PANDA_STATE_CHECKED);
145 
146     auto *ast = reinterpret_cast<AstNode *>(impl_->ProgramAst(impl_->ContextProgram(ctx)));
147 
148     // Change return statement type to void
149     ast->IterateRecursively([&checker](ark::es2panda::ir::AstNode *child) {
150         if (child->IsMethodDefinition()) {
151             auto *const method = child->AsMethodDefinition();
152             if (method->Kind() == MethodDefinitionKind::GET && method->Value()->IsFunctionExpression()) {
153                 auto *const function = method->Value()->AsFunctionExpression()->Function();
154                 auto &returns = function->ReturnStatements();
155                 ASSERT_EQ(returns.size(), 1);
156 
157                 returns[0]->SetArgument(nullptr);
158                 returns[0]->SetReturnType(&checker, checker.GlobalVoidType());
159             }
160         }
161     });
162 
163     InvariantNameSet checks;
164     checks.insert("GetterSetterValidationForAll");
165     const auto &messages = verifier.Verify(ast, checks);
166 
167     ASSERT_EQ(messages.size(), 1);
168     ASSERT_EQ(messages[0].Cause(), "GETTER METHOD HAS VOID RETURN TYPE");
169 
170     impl_->DestroyContext(ctx);
171 }
172 
173 }  // anonymous namespace
174