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 
69     [[nodiscard]] ArenaAllocator *Allocator() noexcept
70     {
71         return &allocator_;
72     }
73 
74     [[nodiscard]] varbinder::Scope *Scope() const noexcept
75     {
76         return scope_;
77     }
78 
79     [[nodiscard]] CheckerContext &Context() noexcept
80     {
81         return context_;
82     }
83 
84     [[nodiscard]] bool HasStatus(CheckerStatus status) noexcept
85     {
86         return (context_.Status() & status) != 0;
87     }
88 
89     void RemoveStatus(CheckerStatus status) noexcept
90     {
91         context_.Status() &= ~status;
92     }
93 
94     void AddStatus(CheckerStatus status) noexcept
95     {
96         context_.Status() |= status;
97     }
98 
99     [[nodiscard]] TypeRelation *Relation() const noexcept
100     {
101         return relation_;
102     }
103 
104     [[nodiscard]] GlobalTypesHolder *GetGlobalTypesHolder() const noexcept
105     {
106         return globalTypes_;
107     }
108 
109     [[nodiscard]] RelationHolder &IdenticalResults() noexcept
110     {
111         return identicalResults_;
112     }
113 
114     [[nodiscard]] RelationHolder &AssignableResults() noexcept
115     {
116         return assignableResults_;
117     }
118 
119     [[nodiscard]] RelationHolder &ComparableResults() noexcept
120     {
121         return comparableResults_;
122     }
123 
124     [[nodiscard]] RelationHolder &UncheckedCastableResult() noexcept
125     {
126         return uncheckedCastableResults_;
127     }
128 
129     [[nodiscard]] RelationHolder &SupertypeResults() noexcept
130     {
131         return supertypeResults_;
132     }
133 
134     [[nodiscard]] std::unordered_set<const void *> &TypeStack() noexcept
135     {
136         return typeStack_;
137     }
138 
139     [[nodiscard]] std::unordered_set<Type *> &NamedTypeStack() noexcept
140     {
141         return namedTypeStack_;
142     }
143 
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() const155     [[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     // NOTE: required only for evaluate.
207     void Initialize(varbinder::VarBinder *varbinder);
208 
209 protected:
210     parser::Program *Program() const;
211     void SetProgram(parser::Program *program);
212 
213 private:
214     ArenaAllocator allocator_;
215     CheckerContext context_;
216     GlobalTypesHolder *globalTypes_;
217     TypeRelation *relation_;
218     SemanticAnalyzer *analyzer_ {};
219     varbinder::VarBinder *varbinder_ {};
220     parser::Program *program_ {};
221     varbinder::Scope *scope_ {};
222     util::ErrorLogger errorLogger_;
223 
224     RelationHolder identicalResults_ {{}, RelationType::IDENTICAL};
225     RelationHolder assignableResults_ {{}, RelationType::ASSIGNABLE};
226     RelationHolder comparableResults_ {{}, RelationType::COMPARABLE};
227     RelationHolder uncheckedCastableResults_ {{}, RelationType::UNCHECKED_CASTABLE};
228     RelationHolder supertypeResults_ {{}, RelationType::SUPERTYPE};
229 
230     std::unordered_set<const void *> typeStack_;
231     std::unordered_set<Type *> namedTypeStack_;
232 };
233 
234 class NamedTypeStackElement {
235 public:
NamedTypeStackElement(Checker *checker, Type *element)236     explicit NamedTypeStackElement(Checker *checker, Type *element) : checker_(checker), element_(element)
237     {
238         checker_->namedTypeStack_.insert(element);
239     }
240 
~NamedTypeStackElement()241     ~NamedTypeStackElement()
242     {
243         checker_->namedTypeStack_.erase(element_);
244     }
245     NO_COPY_SEMANTIC(NamedTypeStackElement);
246     NO_MOVE_SEMANTIC(NamedTypeStackElement);
247 
248 private:
249     Checker *checker_;
250     Type *element_;
251 };
252 
253 class TypeStackElement {
254 public:
TypeStackElement(Checker *checker, void *element, std::initializer_list<TypeErrorMessageElement> list, const lexer::SourcePosition &pos)255     explicit TypeStackElement(Checker *checker, void *element, std::initializer_list<TypeErrorMessageElement> list,
256                               const lexer::SourcePosition &pos)
257         : checker_(checker), element_(element), hasErrorChecker_(false)
258     {
259         if (!checker->typeStack_.insert(element).second) {
260             checker_->LogTypeError(list, pos);
261             element_ = nullptr;
262         }
263     }
264 
TypeStackElement(Checker *checker, void *element, std::string_view err, const lexer::SourcePosition &pos)265     explicit TypeStackElement(Checker *checker, void *element, std::string_view err, const lexer::SourcePosition &pos)
266         : checker_(checker), element_(element), hasErrorChecker_(false)
267     {
268         if (!checker->typeStack_.insert(element).second) {
269             checker_->LogTypeError(err, pos);
270             element_ = nullptr;
271         }
272     }
273 
HasTypeError()274     bool HasTypeError()
275     {
276         hasErrorChecker_ = true;
277         return element_ == nullptr;
278     }
279 
~TypeStackElement()280     ~TypeStackElement()
281     {
282         ASSERT(hasErrorChecker_);
283         if (element_ != nullptr) {
284             checker_->typeStack_.erase(element_);
285         }
286     }
287 
288     NO_COPY_SEMANTIC(TypeStackElement);
289     NO_MOVE_SEMANTIC(TypeStackElement);
290 
291 private:
292     Checker *checker_;
293     void *element_;
294     bool hasErrorChecker_;
295 };
296 
297 class ScopeContext {
298 public:
ScopeContext(Checker *checker, varbinder::Scope *newScope)299     explicit ScopeContext(Checker *checker, varbinder::Scope *newScope)
300         : checker_(checker), prevScope_(checker_->scope_)
301     {
302         checker_->scope_ = newScope;
303     }
304 
~ScopeContext()305     ~ScopeContext()
306     {
307         checker_->scope_ = prevScope_;
308     }
309 
310     NO_COPY_SEMANTIC(ScopeContext);
311     NO_MOVE_SEMANTIC(ScopeContext);
312 
313 private:
314     Checker *checker_;
315     varbinder::Scope *prevScope_;
316 };
317 
318 class SavedCheckerContext {
319 public:
SavedCheckerContext(Checker *checker, CheckerStatus newStatus)320     explicit SavedCheckerContext(Checker *checker, CheckerStatus newStatus)
321         : SavedCheckerContext(checker, newStatus, nullptr)
322     {
323     }
324 
SavedCheckerContext(Checker *checker, CheckerStatus newStatus, const ETSObjectType *containingClass)325     explicit SavedCheckerContext(Checker *checker, CheckerStatus newStatus, const ETSObjectType *containingClass)
326         : SavedCheckerContext(checker, newStatus, containingClass, nullptr)
327     {
328     }
329 
SavedCheckerContext(Checker *checker, CheckerStatus newStatus, const ETSObjectType *containingClass, Signature *containingSignature)330     explicit SavedCheckerContext(Checker *checker, CheckerStatus newStatus, const ETSObjectType *containingClass,
331                                  Signature *containingSignature)
332         : checker_(checker), prev_(checker->context_)
333     {
334         const bool inExternal = checker->HasStatus(CheckerStatus::IN_EXTERNAL);
335         checker_->context_ = CheckerContext(checker, newStatus, containingClass, containingSignature);
336         if (inExternal) {
337             // handled here instead of at call sites to make things more foolproof
338             checker_->context_.Status() |= CheckerStatus::IN_EXTERNAL;
339         }
340     }
341 
342     NO_COPY_SEMANTIC(SavedCheckerContext);
343     DEFAULT_MOVE_SEMANTIC(SavedCheckerContext);
344 
~SavedCheckerContext()345     ~SavedCheckerContext()
346     {
347         checker_->context_ = prev_;
348     }
349 
350 private:
351     Checker *checker_;
352     CheckerContext prev_;
353 };
354 
355 }  // namespace ark::es2panda::checker
356 
357 #endif /* CHECKER_H */
358