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_set<const void *> &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 [[noreturn]] void ThrowTypeError(std::string_view message, const lexer::SourcePosition &pos); 168 [[noreturn]] void ThrowTypeError(std::initializer_list<TypeErrorMessageElement> list, 169 const lexer::SourcePosition &pos); 170 void LogTypeError(std::string_view message, const lexer::SourcePosition &pos); 171 void LogTypeError(std::initializer_list<TypeErrorMessageElement> list, const lexer::SourcePosition &pos); 172 void Warning(std::string_view message, const lexer::SourcePosition &pos) const; 173 void ReportWarning(std::initializer_list<TypeErrorMessageElement> list, const lexer::SourcePosition &pos); 174 175 bool IsTypeIdenticalTo(Type *source, Type *target); 176 bool IsTypeIdenticalTo(Type *source, Type *target, const std::string &errMsg, const lexer::SourcePosition &errPos); 177 bool IsTypeIdenticalTo(Type *source, Type *target, std::initializer_list<TypeErrorMessageElement> list, 178 const lexer::SourcePosition &errPos); 179 bool IsTypeAssignableTo(Type *source, Type *target); 180 bool IsTypeAssignableTo(Type *source, Type *target, const std::string &errMsg, const lexer::SourcePosition &errPos); 181 bool IsTypeAssignableTo(Type *source, Type *target, std::initializer_list<TypeErrorMessageElement> list, 182 const lexer::SourcePosition &errPos); 183 bool IsTypeComparableTo(Type *source, Type *target); 184 bool IsTypeComparableTo(Type *source, Type *target, const std::string &errMsg, const lexer::SourcePosition &errPos); 185 bool IsTypeComparableTo(Type *source, Type *target, std::initializer_list<TypeErrorMessageElement> list, 186 const lexer::SourcePosition &errPos); 187 bool AreTypesComparable(Type *source, Type *target); 188 bool IsTypeEqualityComparableTo(Type *source, Type *target); 189 bool IsAllTypesAssignableTo(Type *source, Type *target); 190 void SetAnalyzer(SemanticAnalyzer *analyzer); 191 checker::SemanticAnalyzer *GetAnalyzer() const; 192 193 friend class ScopeContext; 194 friend class TypeStackElement; 195 friend class NamedTypeStackElement; 196 friend class SavedCheckerContext; 197 friend class NamedTypeStackElement; 198 199 varbinder::VarBinder *VarBinder() const; 200 ErrorLogger()201 util::ErrorLogger *ErrorLogger() 202 { 203 return &errorLogger_; 204 } 205 206 protected: 207 void Initialize(varbinder::VarBinder *varbinder); 208 parser::Program *Program() const; 209 void SetProgram(parser::Program *program); 210 211 private: 212 ArenaAllocator allocator_; 213 CheckerContext context_; 214 GlobalTypesHolder *globalTypes_; 215 TypeRelation *relation_; 216 SemanticAnalyzer *analyzer_ {}; 217 varbinder::VarBinder *varbinder_ {}; 218 parser::Program *program_ {}; 219 varbinder::Scope *scope_ {}; 220 util::ErrorLogger errorLogger_; 221 222 RelationHolder identicalResults_ {{}, RelationType::IDENTICAL}; 223 RelationHolder assignableResults_ {{}, RelationType::ASSIGNABLE}; 224 RelationHolder comparableResults_ {{}, RelationType::COMPARABLE}; 225 RelationHolder uncheckedCastableResults_ {{}, RelationType::UNCHECKED_CASTABLE}; 226 RelationHolder supertypeResults_ {{}, RelationType::SUPERTYPE}; 227 228 std::unordered_set<const void *> typeStack_; 229 std::unordered_set<Type *> namedTypeStack_; 230 }; 231 232 class NamedTypeStackElement { 233 public: NamedTypeStackElement(Checker * checker,Type * element)234 explicit NamedTypeStackElement(Checker *checker, Type *element) : checker_(checker), element_(element) 235 { 236 checker_->namedTypeStack_.insert(element); 237 } 238 ~NamedTypeStackElement()239 ~NamedTypeStackElement() 240 { 241 checker_->namedTypeStack_.erase(element_); 242 } 243 NO_COPY_SEMANTIC(NamedTypeStackElement); 244 NO_MOVE_SEMANTIC(NamedTypeStackElement); 245 246 private: 247 Checker *checker_; 248 Type *element_; 249 }; 250 251 class TypeStackElement { 252 public: TypeStackElement(Checker * checker,void * element,std::initializer_list<TypeErrorMessageElement> list,const lexer::SourcePosition & pos)253 explicit TypeStackElement(Checker *checker, void *element, std::initializer_list<TypeErrorMessageElement> list, 254 const lexer::SourcePosition &pos) 255 : checker_(checker), element_(element) 256 { 257 if (!checker->typeStack_.insert(element).second) { 258 checker_->ThrowTypeError(list, pos); 259 } 260 } 261 TypeStackElement(Checker * checker,void * element,std::string_view err,const lexer::SourcePosition & pos)262 explicit TypeStackElement(Checker *checker, void *element, std::string_view err, const lexer::SourcePosition &pos) 263 : checker_(checker), element_(element) 264 { 265 if (!checker->typeStack_.insert(element).second) { 266 checker_->ThrowTypeError(err, pos); 267 } 268 } 269 ~TypeStackElement()270 ~TypeStackElement() 271 { 272 checker_->typeStack_.erase(element_); 273 } 274 275 NO_COPY_SEMANTIC(TypeStackElement); 276 NO_MOVE_SEMANTIC(TypeStackElement); 277 278 private: 279 Checker *checker_; 280 void *element_; 281 }; 282 283 class ScopeContext { 284 public: ScopeContext(Checker * checker,varbinder::Scope * newScope)285 explicit ScopeContext(Checker *checker, varbinder::Scope *newScope) 286 : checker_(checker), prevScope_(checker_->scope_) 287 { 288 checker_->scope_ = newScope; 289 } 290 ~ScopeContext()291 ~ScopeContext() 292 { 293 checker_->scope_ = prevScope_; 294 } 295 296 NO_COPY_SEMANTIC(ScopeContext); 297 NO_MOVE_SEMANTIC(ScopeContext); 298 299 private: 300 Checker *checker_; 301 varbinder::Scope *prevScope_; 302 }; 303 304 class SavedCheckerContext { 305 public: SavedCheckerContext(Checker * checker,CheckerStatus newStatus)306 explicit SavedCheckerContext(Checker *checker, CheckerStatus newStatus) 307 : SavedCheckerContext(checker, newStatus, nullptr) 308 { 309 } 310 SavedCheckerContext(Checker * checker,CheckerStatus newStatus,const ETSObjectType * containingClass)311 explicit SavedCheckerContext(Checker *checker, CheckerStatus newStatus, const ETSObjectType *containingClass) 312 : SavedCheckerContext(checker, newStatus, containingClass, nullptr) 313 { 314 } 315 SavedCheckerContext(Checker * checker,CheckerStatus newStatus,const ETSObjectType * containingClass,Signature * containingSignature)316 explicit SavedCheckerContext(Checker *checker, CheckerStatus newStatus, const ETSObjectType *containingClass, 317 Signature *containingSignature) 318 : checker_(checker), prev_(checker->context_) 319 { 320 const bool inExternal = checker->HasStatus(CheckerStatus::IN_EXTERNAL); 321 checker_->context_ = CheckerContext(checker, newStatus, containingClass, containingSignature); 322 if (inExternal) { 323 // handled here instead of at call sites to make things more foolproof 324 checker_->context_.Status() |= CheckerStatus::IN_EXTERNAL; 325 } 326 } 327 328 NO_COPY_SEMANTIC(SavedCheckerContext); 329 DEFAULT_MOVE_SEMANTIC(SavedCheckerContext); 330 ~SavedCheckerContext()331 ~SavedCheckerContext() 332 { 333 checker_->context_ = prev_; 334 } 335 336 private: 337 Checker *checker_; 338 CheckerContext prev_; 339 }; 340 341 } // namespace ark::es2panda::checker 342 343 #endif /* CHECKER_H */ 344