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