1/**
2 * Copyright (c) 2021-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 "ir/expressions/assignmentExpression.h"
17#include "ir/expressions/binaryExpression.h"
18#include "ir/expressions/memberExpression.h"
19#include "ir/expressions/templateLiteral.h"
20#include "ir/ts/tsQualifiedName.h"
21
22#include "checker/TSchecker.h"
23
24namespace ark::es2panda::checker {
25ir::MemberExpression *TSChecker::ResolveLeftMostMemberExpression(ir::MemberExpression *expr)
26{
27    ir::MemberExpression *iter = expr;
28
29    while (iter->Object()->IsMemberExpression()) {
30        iter = iter->Object()->AsMemberExpression();
31    }
32
33    return iter;
34}
35
36bool TSChecker::InAssignment(ir::AstNode *node)
37{
38    ir::AstNode *parent = node;
39
40    while (parent->Parent() != nullptr) {
41        if (parent->Parent()->IsAssignmentExpression()) {
42            return parent->Parent()->AsAssignmentExpression()->Left() == parent;
43        }
44
45        if (parent->Parent()->IsBinaryExpression()) {
46            ir::BinaryExpression *binaryExpr = parent->Parent()->AsBinaryExpression();
47            return IsAssignmentOperator(binaryExpr->OperatorType()) && binaryExpr->Left() == parent;
48        }
49
50        if (parent->Parent()->IsUpdateExpression()) {
51            return true;
52        }
53
54        parent = parent->Parent();
55    }
56    return false;
57}
58
59bool TSChecker::IsAssignmentOperator(lexer::TokenType op)
60{
61    switch (op) {
62        case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL:
63        case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL:
64        case lexer::TokenType::PUNCTUATOR_MULTIPLY_EQUAL:
65        case lexer::TokenType::PUNCTUATOR_EXPONENTIATION_EQUAL:
66        case lexer::TokenType::PUNCTUATOR_DIVIDE_EQUAL:
67        case lexer::TokenType::PUNCTUATOR_MOD_EQUAL:
68        case lexer::TokenType::PUNCTUATOR_MINUS_EQUAL:
69        case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT_EQUAL:
70        case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT_EQUAL:
71        case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT_EQUAL:
72        case lexer::TokenType::PUNCTUATOR_BITWISE_AND_EQUAL:
73        case lexer::TokenType::PUNCTUATOR_BITWISE_OR_EQUAL:
74        case lexer::TokenType::PUNCTUATOR_BITWISE_XOR_EQUAL:
75        case lexer::TokenType::PUNCTUATOR_PLUS_EQUAL:
76        case lexer::TokenType::PUNCTUATOR_SUBSTITUTION:
77            return true;
78        default:
79            return false;
80    }
81}
82
83bool TSChecker::IsLiteralType(const Type *type)
84{
85    if (type->IsBooleanType()) {
86        return true;
87    }
88
89    if (type->IsUnionType()) {
90        auto &constituentTypes = type->AsUnionType()->ConstituentTypes();
91        bool result = true;
92        for (auto *it : constituentTypes) {
93            result &= it->HasTypeFlag(TypeFlag::UNIT);
94        }
95        return result;
96    }
97
98    return type->HasTypeFlag(TypeFlag::UNIT);
99}
100
101ir::AstNode *TSChecker::FindAncestorUntilGivenType(ir::AstNode *node, ir::AstNodeType stop)
102{
103    while (node->Parent()->Type() != stop) {
104        if (node->Parent() != nullptr) {
105            node = node->Parent();
106            continue;
107        }
108
109        return nullptr;
110    }
111
112    return node;
113}
114
115bool TSChecker::MaybeTypeOfKind(const Type *type, TypeFlag flags)
116{
117    if (type->HasTypeFlag(flags)) {
118        return true;
119    }
120
121    if (type->HasTypeFlag(TypeFlag::UNION_OR_INTERSECTION) && type->IsUnionType()) {
122        const auto &constituentTypes = type->AsUnionType()->ConstituentTypes();
123        for (auto *it : constituentTypes) {
124            if (MaybeTypeOfKind(it, flags)) {
125                return true;
126            }
127        }
128    }
129
130    return false;
131}
132
133bool TSChecker::MaybeTypeOfKind(const Type *type, ObjectType::ObjectTypeKind kind)
134{
135    if (type->IsObjectType() && type->AsObjectType()->Kind() == kind) {
136        return true;
137    }
138
139    if (type->HasTypeFlag(TypeFlag::UNION_OR_INTERSECTION) && type->IsUnionType()) {
140        const auto &constituentTypes = type->AsUnionType()->ConstituentTypes();
141        for (auto *it : constituentTypes) {
142            if (MaybeTypeOfKind(it, kind)) {
143                return true;
144            }
145        }
146    }
147
148    return false;
149}
150
151bool TSChecker::IsConstantMemberAccess(ir::Expression *expr)
152{
153    switch (expr->Type()) {
154        case ir::AstNodeType::IDENTIFIER: {
155            return true;
156        }
157        case ir::AstNodeType::MEMBER_EXPRESSION: {
158            bool res = IsConstantMemberAccess(expr->AsMemberExpression()->Object());
159            return !expr->AsMemberExpression()->IsComputed()
160                       ? res
161                       : (res && IsStringLike(expr->AsMemberExpression()->Property()));
162        }
163        default:
164            return false;
165    }
166}
167
168bool TSChecker::IsStringLike(ir::Expression *expr)
169{
170    if (expr->IsStringLiteral()) {
171        return true;
172    }
173
174    if (expr->IsTemplateLiteral() && expr->AsTemplateLiteral()->Quasis().empty()) {
175        return true;
176    }
177
178    return false;
179}
180}  // namespace ark::es2panda::checker
181