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