• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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