• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifndef ES2PANDA_CHECKER_CHECKER_CONTEXT_H
17 #define ES2PANDA_CHECKER_CHECKER_CONTEXT_H
18 
19 #include "checker/types/type.h"
20 #include "ir/statements/loopStatement.h"
21 #include "varbinder/variable.h"
22 
23 namespace ark::es2panda::checker {
24 
25 class ETSObjectType;
26 class Signature;
27 
28 using ENUMBITOPS_OPERATORS;
29 
30 enum class CheckerStatus : uint32_t {
31     NO_OPTS = 0U,
32     FORCE_TUPLE = 1U << 0U,
33     IN_CONST_CONTEXT = 1U << 1U,
34     KEEP_LITERAL_TYPE = 1U << 2U,
35     IN_PARAMETER = 1U << 3U,
36     IN_CLASS = 1U << 4U,
37     IN_INTERFACE = 1U << 5U,
38     IN_ABSTRACT = 1U << 6U,
39     IN_STATIC_CONTEXT = 1U << 7U,
40     IN_CONSTRUCTOR = 1U << 8U,
41     IN_STATIC_BLOCK = 1U << 9U,
42     INNER_CLASS = 1U << 10U,
43     IN_ENUM = 1U << 11U,
44     BUILTINS_INITIALIZED = 1U << 12U,
45     IN_LAMBDA = 1U << 13U,
46     IGNORE_VISIBILITY = 1U << 14U,
47     IN_INSTANCE_EXTENSION_METHOD = 1U << 15U,
48     IN_LOCAL_CLASS = 1U << 16U,
49     IN_INSTANCEOF_CONTEXT = 1U << 17U,
50     IN_TEST_EXPRESSION = 1U << 18U,
51     IN_LOOP = 1U << 19U,
52     MEET_RETURN = 1U << 20U,
53     MEET_BREAK = 1U << 21U,
54     MEET_CONTINUE = 1U << 22U,
55     MEET_THROW = 1U << 23U,
56     IN_EXTERNAL = 1U << 24U,
57 };
58 
59 }  // namespace ark::es2panda::checker
60 
61 template <>
62 struct enumbitops::IsAllowedType<ark::es2panda::checker::CheckerStatus> : std::true_type {
63 };
64 
65 namespace ark::es2panda::checker {
66 
67 using CapturedVarsMap = ArenaUnorderedMap<varbinder::Variable *, lexer::SourcePosition>;
68 using SmartCastMap = ArenaMap<varbinder::Variable const *, checker::Type *>;
69 using SmartCastArray = std::vector<std::pair<varbinder::Variable const *, checker::Type *>>;
70 using SmartCastTestMap = ArenaMap<varbinder::Variable const *, std::pair<checker::Type *, checker::Type *>>;
71 using SmartCastTuple = std::tuple<varbinder::Variable const *, checker::Type *, checker::Type *>;
72 using SmartCastTestArray = std::vector<SmartCastTuple>;
73 using PreservedSmartCastsMap = ArenaMultiMap<ir::AstNode const *, SmartCastArray>;
74 using SmartVariables = std::unordered_set<varbinder::Variable const *>;
75 
76 struct SmartCastCondition final {
77     SmartCastCondition() = default;
78     ~SmartCastCondition() = default;
79 
80     DEFAULT_COPY_SEMANTIC(SmartCastCondition);
81     DEFAULT_MOVE_SEMANTIC(SmartCastCondition);
82 
83     // NOLINTBEGIN(misc-non-private-member-variables-in-classes)
84     varbinder::Variable const *variable = nullptr;
85     checker::Type *testedType = nullptr;
86     bool negate = false;
87     bool strict = true;
88     // NOLINTEND(misc-non-private-member-variables-in-classes)
89 };
90 
91 using SmartCastTypes = std::optional<SmartCastTestArray>;
92 
93 class CheckerContext final {
94 public:
95     explicit CheckerContext(Checker *checker, CheckerStatus newStatus) : CheckerContext(checker, newStatus, nullptr) {}
96 
97     explicit CheckerContext(Checker *checker, CheckerStatus newStatus, const ETSObjectType *containingClass)
98         : CheckerContext(checker, newStatus, containingClass, nullptr)
99     {
100     }
101 
102     explicit CheckerContext(Checker *checker, CheckerStatus newStatus, const ETSObjectType *containingClass,
103                             Signature *containingSignature);
104 
105     CheckerContext() = delete;
106     ~CheckerContext() = default;
107 
108     DEFAULT_COPY_SEMANTIC(CheckerContext);
109     DEFAULT_MOVE_SEMANTIC(CheckerContext);
110 
111     [[nodiscard]] const CapturedVarsMap &CapturedVars() const noexcept
112     {
113         return capturedVars_;
114     }
115 
116     [[nodiscard]] CapturedVarsMap &CapturedVars() noexcept
117     {
118         return capturedVars_;
119     }
120 
121     [[nodiscard]] const CheckerStatus &Status() const noexcept
122     {
123         return status_;
124     }
125 
126     [[nodiscard]] ETSObjectType *ContainingClass() const noexcept
127     {
128         return const_cast<ETSObjectType *>(containingClass_);
129     }
130 
131     [[nodiscard]] Signature *ContainingSignature() const noexcept
132     {
133         return containingSignature_;
134     }
135 
136     [[nodiscard]] CheckerStatus &Status() noexcept
137     {
138         return status_;
139     }
140 
141     void SetContainingSignature(Signature *containingSignature) noexcept
142     {
143         containingSignature_ = containingSignature;
144     }
145 
146     void SetContainingClass(ETSObjectType *containingClass) noexcept
147     {
148         containingClass_ = containingClass;
149     }
150 
151     void AddCapturedVar(varbinder::Variable *var, const lexer::SourcePosition &pos)
152     {
153         capturedVars_.emplace(var, pos);
154     }
155     [[nodiscard]] ir::ArrowFunctionExpression *ContainingLambda() const noexcept
156     {
157         return containingLambda_;
158     }
159 
160     void SetContainingLambda(ir::ArrowFunctionExpression *containingLambda) noexcept
161     {
162         containingLambda_ = containingLambda;
163     }
164 
165     void ClearSmartCasts() noexcept
166     {
167         smartCasts_.clear();
168     }
169 
170     void RemoveSmartCast(varbinder::Variable const *const variable) noexcept
171     {
172         smartCasts_.erase(variable);
173     }
174 
175     void SetSmartCast(varbinder::Variable const *const variable, checker::Type *const smartType) noexcept
176     {
177         smartCasts_.insert_or_assign(variable, smartType);
178     }
179 
180     [[nodiscard]] checker::Type *GetSmartCast(varbinder::Variable const *const variable) const noexcept;
181     [[nodiscard]] SmartCastArray CloneSmartCasts(bool clearData = false) noexcept;
182     void RestoreSmartCasts(SmartCastArray const &otherSmartCasts);
183     void CombineSmartCasts(SmartCastArray const &otherSmartCasts);
184 
185     [[nodiscard]] SmartCastArray EnterTestExpression() noexcept
186     {
187         status_ |= CheckerStatus::IN_TEST_EXPRESSION;
188         ClearTestSmartCasts();
189         return CloneSmartCasts(false);
190     }
191 
192     [[nodiscard]] bool IsInTestExpression() const noexcept
193     {
194         return (status_ & CheckerStatus::IN_TEST_EXPRESSION) != 0;
195     }
196 
197     SmartCastTypes ExitTestExpression()
198     {
199         status_ &= ~CheckerStatus::IN_TEST_EXPRESSION;
200         CheckTestSmartCastCondition(lexer::TokenType::EOS);
201         return CloneTestSmartCasts(true);
202     }
203 
204     [[nodiscard]] std::pair<SmartCastArray, bool> EnterLoop(ir::LoopStatement const &loop) noexcept;
205 
206     [[nodiscard]] bool IsInLoop() const noexcept
207     {
208         return (status_ & CheckerStatus::IN_LOOP) != 0;
209     }
210 
211     void ExitLoop(SmartCastArray &prevSmartCasts, bool clearFlag, ir::LoopStatement *loopStatement) noexcept;
212 
213     void EnterPath() noexcept
214     {
215         status_ &= ~(CheckerStatus::MEET_RETURN | CheckerStatus::MEET_BREAK | CheckerStatus::MEET_CONTINUE |
216                      CheckerStatus::MEET_THROW);
217     }
218 
219     [[nodiscard]] bool ExitPath() noexcept
220     {
221         auto const rc = (status_ & (CheckerStatus::MEET_RETURN | CheckerStatus::MEET_BREAK |
222                                     CheckerStatus::MEET_CONTINUE | CheckerStatus::MEET_THROW)) != 0;
223         status_ &= ~(CheckerStatus::MEET_RETURN | CheckerStatus::MEET_BREAK | CheckerStatus::MEET_CONTINUE |
224                      CheckerStatus::MEET_THROW);
225         return rc;
226     }
227 
228     [[nodiscard]] SmartCastArray CheckTryBlock(ir::BlockStatement const &tryBlock) noexcept;
229 
230     void CheckTestSmartCastCondition(lexer::TokenType operatorType);
231     void CheckIdentifierSmartCastCondition(ir::Identifier const *identifier) noexcept;
232     void CheckUnarySmartCastCondition(ir::UnaryExpression const *unaryExpression) noexcept;
233     void CheckBinarySmartCastCondition(ir::BinaryExpression *binaryExpression) noexcept;
234 
235     void OnBreakStatement(ir::BreakStatement const *breakStatement);
236     void AddBreakSmartCasts(ir::Statement const *targetStatement, SmartCastArray &&smartCasts);
237     void CombineBreakSmartCasts(ir::Statement const *targetStatement);
238 
239 private:
240     Checker *parent_;
241     CheckerStatus status_;
242     CapturedVarsMap capturedVars_;
243     SmartCastMap smartCasts_;
244     const ETSObjectType *containingClass_ {nullptr};
245     ir::ArrowFunctionExpression *containingLambda_ {nullptr};
246     Signature *containingSignature_ {nullptr};
247 
248     lexer::TokenType operatorType_ = lexer::TokenType::EOS;
249     SmartCastCondition testCondition_ {};
250     SmartCastTestMap testSmartCasts_;
251 
252     PreservedSmartCastsMap breakSmartCasts_;
253 
254     void RemoveSmartCasts(SmartCastArray const &otherSmartCasts) noexcept;
255     [[nodiscard]] checker::Type *CombineTypes(checker::Type *typeOne, checker::Type *typeTwo) const noexcept;
256     [[nodiscard]] static bool IsInValidChain(ir::AstNode const *parent) noexcept;
257     void CheckSmartCastEqualityCondition(ir::BinaryExpression *binaryExpression) noexcept;
258     [[nodiscard]] SmartCastTypes CloneTestSmartCasts(bool clearData = true) noexcept;
259     void ClearTestSmartCasts() noexcept;
260     [[nodiscard]] std::optional<SmartCastTuple> ResolveSmartCastTypes();
261     [[nodiscard]] bool CheckTestOrSmartCastCondition(SmartCastTuple const &types);
262     void CheckAssignments(ir::AstNode const *node, SmartVariables &changedVariables) noexcept;
263 };
264 }  // namespace ark::es2panda::checker
265 
266 #endif
267