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