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