1 /** 2 * Copyright (c) 2021-2025 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_H 17 #define ES2PANDA_CHECKER_CHECKER_H 18 19 #include "checker/checkerContext.h" 20 #include "checker/SemanticAnalyzer.h" 21 #include "checker/types/globalTypesHolder.h" 22 #include "util/diagnosticEngine.h" 23 24 namespace ark::es2panda::util { 25 class Options; 26 } // namespace ark::es2panda::util 27 28 namespace ark::es2panda::parser { 29 class Program; 30 } // namespace ark::es2panda::parser 31 32 namespace ark::es2panda::ir { 33 class AstNode; 34 class Expression; 35 class BlockStatement; 36 enum class AstNodeType; 37 } // namespace ark::es2panda::ir 38 39 namespace ark::es2panda::varbinder { 40 class VarBinder; 41 class Decl; 42 class EnumVariable; 43 class FunctionDecl; 44 class LocalVariable; 45 class Scope; 46 class Variable; 47 } // namespace ark::es2panda::varbinder 48 49 namespace ark::es2panda::checker { 50 class ETSChecker; 51 class InterfaceType; 52 class GlobalTypesHolder; 53 54 using StringLiteralPool = std::unordered_map<util::StringView, Type *>; 55 using NumberLiteralPool = std::unordered_map<double, Type *>; 56 using FunctionParamsResolveResult = std::variant<std::vector<varbinder::LocalVariable *> &, bool>; 57 using InterfacePropertyMap = 58 std::unordered_map<util::StringView, std::pair<varbinder::LocalVariable *, InterfaceType *>>; 59 using TypeOrNode = std::variant<Type *, ir::AstNode *>; 60 using IndexInfoTypePair = std::pair<Type *, Type *>; 61 using PropertyMap = std::unordered_map<util::StringView, varbinder::LocalVariable *>; 62 using ArgRange = std::pair<uint32_t, uint32_t>; 63 64 class Checker { 65 public: 66 explicit Checker(util::DiagnosticEngine &diagnosticEngine, ArenaAllocator *programAllocator = nullptr); 67 virtual ~Checker() = default; 68 69 NO_COPY_SEMANTIC(Checker); 70 NO_MOVE_SEMANTIC(Checker); 71 Allocator()72 [[nodiscard]] ArenaAllocator *Allocator() noexcept 73 { 74 return &allocator_; 75 } 76 Scope()77 [[nodiscard]] varbinder::Scope *Scope() const noexcept 78 { 79 return scope_; 80 } 81 Context()82 [[nodiscard]] CheckerContext &Context() noexcept 83 { 84 return context_; 85 } 86 HasStatus(CheckerStatus status)87 [[nodiscard]] bool HasStatus(CheckerStatus status) noexcept 88 { 89 return (context_.Status() & status) != 0; 90 } 91 RemoveStatus(CheckerStatus status)92 void RemoveStatus(CheckerStatus status) noexcept 93 { 94 context_.Status() &= ~status; 95 } 96 AddStatus(CheckerStatus status)97 void AddStatus(CheckerStatus status) noexcept 98 { 99 context_.Status() |= status; 100 } 101 Relation()102 [[nodiscard]] TypeRelation *Relation() const noexcept 103 { 104 return relation_; 105 } 106 InitGlobalTypes()107 void InitGlobalTypes() 108 { 109 globalTypes_ = ProgramAllocator()->New<GlobalTypesHolder>(ProgramAllocator()); 110 } 111 GetGlobalTypesHolder()112 [[nodiscard]] GlobalTypesHolder *GetGlobalTypesHolder() const noexcept 113 { 114 return globalTypes_; 115 } 116 SetGlobalTypes(GlobalTypesHolder * globalTypes)117 void SetGlobalTypes(GlobalTypesHolder *globalTypes) noexcept 118 { 119 globalTypes_ = globalTypes; 120 } 121 IdenticalResults()122 [[nodiscard]] RelationHolder &IdenticalResults() noexcept 123 { 124 return identicalResults_; 125 } 126 AssignableResults()127 [[nodiscard]] RelationHolder &AssignableResults() noexcept 128 { 129 return assignableResults_; 130 } 131 ComparableResults()132 [[nodiscard]] RelationHolder &ComparableResults() noexcept 133 { 134 return comparableResults_; 135 } 136 UncheckedCastableResult()137 [[nodiscard]] RelationHolder &UncheckedCastableResult() noexcept 138 { 139 return uncheckedCastableResults_; 140 } 141 SupertypeResults()142 [[nodiscard]] RelationHolder &SupertypeResults() noexcept 143 { 144 return supertypeResults_; 145 } 146 TypeStack()147 [[nodiscard]] std::unordered_map<const void *, Type *> &TypeStack() noexcept 148 { 149 return typeStack_; 150 } 151 NamedTypeStack()152 [[nodiscard]] std::unordered_set<Type *> &NamedTypeStack() noexcept 153 { 154 return namedTypeStack_; 155 } 156 IsETSChecker()157 [[nodiscard]] virtual bool IsETSChecker() const noexcept 158 { 159 return false; 160 } 161 AsETSChecker()162 [[nodiscard]] ETSChecker *AsETSChecker() 163 { 164 ES2PANDA_ASSERT(IsETSChecker()); 165 return reinterpret_cast<ETSChecker *>(this); 166 } 167 AsETSChecker()168 [[nodiscard]] const ETSChecker *AsETSChecker() const 169 { 170 ES2PANDA_ASSERT(IsETSChecker()); 171 return reinterpret_cast<const ETSChecker *>(this); 172 } 173 174 virtual bool StartChecker([[maybe_unused]] varbinder::VarBinder *varbinder, const util::Options &options) = 0; 175 virtual Type *CheckTypeCached(ir::Expression *expr) = 0; 176 virtual Type *GetTypeOfVariable(varbinder::Variable *var) = 0; 177 virtual void ResolveStructuredTypeMembers(Type *type) = 0; 178 179 void LogError(const diagnostic::DiagnosticKind &diagnostic, 180 const util::DiagnosticMessageParams &diagnosticParams = {}); 181 void LogError(const diagnostic::DiagnosticKind &diagnostic, const util::DiagnosticMessageParams &diagnosticParams, 182 const lexer::SourcePosition &pos); 183 void LogError(const diagnostic::DiagnosticKind &diagnostic, const lexer::SourcePosition &pos); 184 void LogTypeError(std::string_view message, const lexer::SourcePosition &pos); 185 void LogTypeError(const util::DiagnosticMessageParams &list, const lexer::SourcePosition &pos); 186 void LogDiagnostic(const diagnostic::DiagnosticKind &kind, const util::DiagnosticMessageParams &list, 187 const lexer::SourcePosition &pos); LogDiagnostic(const diagnostic::DiagnosticKind & kind,const lexer::SourcePosition & pos)188 void LogDiagnostic(const diagnostic::DiagnosticKind &kind, const lexer::SourcePosition &pos) 189 { 190 LogDiagnostic(kind, {}, pos); 191 } 192 193 bool IsTypeIdenticalTo(Type *source, Type *target); 194 bool IsTypeIdenticalTo(Type *source, Type *target, const diagnostic::DiagnosticKind &diagKind, 195 const util::DiagnosticMessageParams &diagParams, const lexer::SourcePosition &errPos); 196 bool IsTypeIdenticalTo(Type *source, Type *target, const diagnostic::DiagnosticKind &diagKind, 197 const lexer::SourcePosition &errPos); 198 bool IsTypeAssignableTo(Type *source, Type *target); 199 bool IsTypeAssignableTo(Type *source, Type *target, const diagnostic::DiagnosticKind &diagKind, 200 const util::DiagnosticMessageParams &list, const lexer::SourcePosition &errPos); 201 bool IsTypeComparableTo(Type *source, Type *target); 202 bool IsTypeComparableTo(Type *source, Type *target, const diagnostic::DiagnosticKind &diagKind, 203 const util::DiagnosticMessageParams &list, const lexer::SourcePosition &errPos); 204 bool AreTypesComparable(Type *source, Type *target); 205 bool IsTypeEqualityComparableTo(Type *source, Type *target); 206 bool IsAllTypesAssignableTo(Type *source, Type *target); 207 void SetAnalyzer(SemanticAnalyzer *analyzer); 208 checker::SemanticAnalyzer *GetAnalyzer() const; 209 210 friend class ScopeContext; 211 friend class TypeStackElement; 212 friend class NamedTypeStackElement; 213 friend class SavedCheckerContext; 214 friend class NamedTypeStackElement; 215 216 varbinder::VarBinder *VarBinder() const; 217 DiagnosticEngine()218 util::DiagnosticEngine &DiagnosticEngine() 219 { 220 return diagnosticEngine_; 221 } 222 GetPositionForDiagnostic()223 lexer::SourcePosition GetPositionForDiagnostic() const 224 { 225 return lexer::SourcePosition {Program()}; 226 } 227 228 // NOTE: required only for evaluate. 229 void Initialize(varbinder::VarBinder *varbinder); 230 231 [[nodiscard]] bool IsAnyError(); 232 233 virtual void CleanUp(); 234 ProgramAllocator()235 [[nodiscard]] ArenaAllocator *ProgramAllocator() 236 { 237 return programAllocator_ == nullptr ? &allocator_ : programAllocator_; 238 } 239 240 protected: 241 parser::Program *Program() const; 242 void SetProgram(parser::Program *program); 243 244 private: 245 ArenaAllocator allocator_; 246 ArenaAllocator *programAllocator_ {nullptr}; 247 CheckerContext context_; 248 GlobalTypesHolder *globalTypes_ {nullptr}; 249 TypeRelation *relation_; 250 SemanticAnalyzer *analyzer_ {}; 251 varbinder::VarBinder *varbinder_ {}; 252 parser::Program *program_ {}; 253 varbinder::Scope *scope_ {}; 254 util::DiagnosticEngine &diagnosticEngine_; 255 256 RelationHolder identicalResults_ {{}, RelationType::IDENTICAL}; 257 RelationHolder assignableResults_ {{}, RelationType::ASSIGNABLE}; 258 RelationHolder comparableResults_ {{}, RelationType::COMPARABLE}; 259 RelationHolder uncheckedCastableResults_ {{}, RelationType::UNCHECKED_CASTABLE}; 260 RelationHolder supertypeResults_ {{}, RelationType::SUPERTYPE}; 261 262 std::unordered_map<const void *, Type *> typeStack_; 263 std::unordered_set<Type *> namedTypeStack_; 264 }; 265 266 class NamedTypeStackElement { 267 public: NamedTypeStackElement(Checker * checker,Type * element)268 explicit NamedTypeStackElement(Checker *checker, Type *element) : checker_(checker), element_(element) 269 { 270 checker_->namedTypeStack_.insert(element); 271 } 272 ~NamedTypeStackElement()273 ~NamedTypeStackElement() 274 { 275 checker_->namedTypeStack_.erase(element_); 276 } 277 NO_COPY_SEMANTIC(NamedTypeStackElement); 278 NO_MOVE_SEMANTIC(NamedTypeStackElement); 279 280 private: 281 Checker *checker_; 282 Type *element_; 283 }; 284 285 class TypeStackElement { 286 public: 287 explicit TypeStackElement(Checker *checker, void *element, const std::optional<util::DiagnosticWithParams> &diag, 288 const lexer::SourcePosition &pos, bool isRecursive = false) checker_(checker)289 : checker_(checker), element_(element), isRecursive_(isRecursive) 290 { 291 if (!checker->typeStack_.insert({element, nullptr}).second) { 292 if (isRecursive_) { 293 cleanup_ = false; 294 } else { 295 checker_->LogError(diag->kind, diag->params, pos); 296 element_ = nullptr; 297 } 298 } 299 } 300 HasTypeError()301 bool HasTypeError() 302 { 303 hasErrorChecker_ = true; 304 return element_ == nullptr; 305 } 306 GetElementType()307 Type *GetElementType() 308 { 309 auto recursiveType = checker_->typeStack_.find(element_); 310 if (recursiveType != checker_->typeStack_.end()) { 311 return recursiveType->second; 312 } 313 return nullptr; 314 } 315 SetElementType(Type * type)316 void SetElementType(Type *type) 317 { 318 checker_->typeStack_[element_] = type; 319 } 320 ~TypeStackElement()321 ~TypeStackElement() 322 { 323 ES2PANDA_ASSERT(hasErrorChecker_); 324 if (element_ != nullptr && cleanup_) { 325 checker_->typeStack_.erase(element_); 326 } 327 } 328 329 NO_COPY_SEMANTIC(TypeStackElement); 330 NO_MOVE_SEMANTIC(TypeStackElement); 331 332 private: 333 Checker *checker_; 334 void *element_; 335 bool hasErrorChecker_ {false}; 336 bool isRecursive_; 337 bool cleanup_ {true}; 338 }; 339 340 template <typename T> 341 class RecursionPreserver { 342 public: RecursionPreserver(std::unordered_set<T * > & elementStack,T * element)343 explicit RecursionPreserver(std::unordered_set<T *> &elementStack, T *element) 344 : elementStack_(elementStack), element_(element) 345 { 346 recursion_ = !elementStack_.insert(element_).second; 347 } 348 349 bool &operator*() 350 { 351 return recursion_; 352 } 353 ~RecursionPreserver()354 ~RecursionPreserver() 355 { 356 if (!recursion_) { 357 elementStack_.erase(element_); 358 } 359 } 360 361 NO_COPY_SEMANTIC(RecursionPreserver); 362 NO_MOVE_SEMANTIC(RecursionPreserver); 363 364 private: 365 std::unordered_set<T *> &elementStack_; 366 T *element_; 367 bool recursion_; 368 }; 369 370 class ScopeContext { 371 public: 372 explicit ScopeContext(Checker *checker, varbinder::Scope *newScope); 373 ~ScopeContext()374 ~ScopeContext() 375 { 376 checker_->scope_ = prevScope_; 377 checker_->SetProgram(prevProgram_); 378 } 379 380 NO_COPY_SEMANTIC(ScopeContext); 381 NO_MOVE_SEMANTIC(ScopeContext); 382 383 private: 384 Checker *checker_; 385 varbinder::Scope *prevScope_; 386 parser::Program *prevProgram_; 387 }; 388 389 class SavedCheckerContext { 390 public: SavedCheckerContext(Checker * checker,CheckerStatus newStatus)391 explicit SavedCheckerContext(Checker *checker, CheckerStatus newStatus) 392 : SavedCheckerContext(checker, newStatus, nullptr) 393 { 394 } 395 SavedCheckerContext(Checker * checker,CheckerStatus newStatus,const ETSObjectType * containingClass)396 explicit SavedCheckerContext(Checker *checker, CheckerStatus newStatus, const ETSObjectType *containingClass) 397 : SavedCheckerContext(checker, newStatus, containingClass, nullptr) 398 { 399 } 400 SavedCheckerContext(Checker * checker,CheckerStatus newStatus,const ETSObjectType * containingClass,Signature * containingSignature)401 explicit SavedCheckerContext(Checker *checker, CheckerStatus newStatus, const ETSObjectType *containingClass, 402 Signature *containingSignature) 403 : checker_(checker), prev_(checker->context_) 404 { 405 const bool inExternal = checker->HasStatus(CheckerStatus::IN_EXTERNAL); 406 checker_->context_ = CheckerContext(checker, newStatus, containingClass, containingSignature); 407 if (inExternal) { 408 // handled here instead of at call sites to make things more foolproof 409 checker_->context_.Status() |= CheckerStatus::IN_EXTERNAL; 410 } 411 } 412 413 NO_COPY_SEMANTIC(SavedCheckerContext); 414 DEFAULT_MOVE_SEMANTIC(SavedCheckerContext); 415 ~SavedCheckerContext()416 ~SavedCheckerContext() 417 { 418 checker_->context_ = prev_; 419 } 420 421 private: 422 Checker *checker_; 423 CheckerContext prev_; 424 }; 425 426 // VerifiedType is used to check return type from Expresssion not equal nullptr 427 class VerifiedType { 428 public: 429 VerifiedType() = delete; 430 ~VerifiedType() = default; 431 432 DEFAULT_MOVE_SEMANTIC(VerifiedType); 433 DEFAULT_COPY_SEMANTIC(VerifiedType); 434 VerifiedType(const ir::AstNode * const node,Type * type)435 VerifiedType([[maybe_unused]] const ir::AstNode *const node, Type *type) : type_(type) 436 { 437 ES2PANDA_ASSERT(type != nullptr || !node->IsExpression()); 438 }; 439 440 Type *operator*() const 441 { 442 return type_; 443 } 444 445 // NOLINTNEXTLINE(*-explicit-constructor) 446 operator Type *() const 447 { 448 return type_; 449 } 450 451 Type *operator->() const 452 { 453 return type_; 454 } 455 456 friend bool operator==(const VerifiedType &l, const std::nullptr_t &r) 457 { 458 return l.type_ == r; 459 } 460 461 friend bool operator==(const VerifiedType &l, const VerifiedType &r) 462 { 463 return l.type_ == r.type_; 464 } 465 466 friend bool operator!=(const VerifiedType &l, const std::nullptr_t &r) 467 { 468 return !(l == r); 469 } 470 471 friend bool operator!=(const VerifiedType &l, const VerifiedType &r) 472 { 473 return !(l == r); 474 } 475 476 // Other conparison is should't used with VerificationType 477 478 private: 479 Type *type_ {}; 480 }; 481 482 } // namespace ark::es2panda::checker 483 484 #endif /* CHECKER_H */ 485