• 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_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