• 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_IR_EXPRESSION_MEMBER_EXPRESSION_H
17 #define ES2PANDA_IR_EXPRESSION_MEMBER_EXPRESSION_H
18 
19 #include "checker/checkerContext.h"
20 #include "checker/types/ets/etsObjectType.h"
21 #include "ir/expression.h"
22 
23 namespace ark::es2panda::compiler {
24 class JSCompiler;
25 class ETSCompiler;
26 }  // namespace ark::es2panda::compiler
27 
28 namespace ark::es2panda::checker {
29 class ETSObjectType;
30 class ETSAnalyzer;
31 }  // namespace ark::es2panda::checker
32 
33 namespace ark::es2panda::ir {
34 
35 // NOLINTBEGIN(modernize-avoid-c-arrays)
36 inline constexpr char const PREDEFINED_METHOD[] = "The special predefined method '";
37 // NOLINTEND(modernize-avoid-c-arrays)
38 
39 using ENUMBITOPS_OPERATORS;
40 
41 enum class MemberExpressionKind : uint32_t {
42     NONE = 0,
43     ELEMENT_ACCESS = 1U << 0U,
44     PROPERTY_ACCESS = 1U << 1U,
45     GETTER = 1U << 2U,
46     SETTER = 1U << 3U,
47     EXTENSION_ACCESSOR = 1U << 4U,
48 };
49 
50 }  // namespace ark::es2panda::ir
51 
52 template <>
53 struct enumbitops::IsAllowedType<ark::es2panda::ir::MemberExpressionKind> : std::true_type {
54 };
55 
56 namespace ark::es2panda::ir {
57 
58 class MemberExpression : public MaybeOptionalExpression {
59     friend class checker::ETSAnalyzer;
60 
61 private:
62     struct Tag {};
63 
64 public:
65     MemberExpression() = delete;
66     ~MemberExpression() override = default;
67 
68     MemberExpression &operator=(const MemberExpression &) = delete;
69     NO_MOVE_SEMANTIC(MemberExpression);
70 
71     explicit MemberExpression(Expression *object, Expression *property, MemberExpressionKind kind, bool computed,
72                               bool optional)
73         : MaybeOptionalExpression(AstNodeType::MEMBER_EXPRESSION, optional),
74           object_(object),
75           property_(property),
76           kind_(kind),
77           computed_(computed)
78     {
79     }
80 
81     explicit MemberExpression(Tag tag, MemberExpression const &other, ArenaAllocator *allocator);
82 
83     // NOTE (csabahurton): these friend relationships can be removed once there are getters for private fields
84     friend class compiler::JSCompiler;
85     friend class compiler::ETSCompiler;
86 
87     [[nodiscard]] Expression *Object() noexcept
88     {
89         return object_;
90     }
91 
92     [[nodiscard]] const Expression *Object() const noexcept
93     {
94         return object_;
95     }
96 
97     void SetObject(Expression *object) noexcept
98     {
99         object_ = object;
100         object_->SetParent(this);
101     }
102 
103     void SetProperty(Expression *prop) noexcept
104     {
105         property_ = prop;
106         property_->SetParent(this);
107     }
108 
109     [[nodiscard]] Expression *Property() noexcept
110     {
111         return property_;
112     }
113 
114     [[nodiscard]] const Expression *Property() const noexcept
115     {
116         return property_;
117     }
118 
119     [[nodiscard]] varbinder::LocalVariable *PropVar() noexcept
120     {
121         if (Kind() == MemberExpressionKind::ELEMENT_ACCESS) {
122             return nullptr;
123         }
124         return Property()->Variable() != nullptr ? Property()->Variable()->AsLocalVariable() : nullptr;
125     }
126 
127     [[nodiscard]] const varbinder::LocalVariable *PropVar() const noexcept
128     {
129         if (Kind() == MemberExpressionKind::ELEMENT_ACCESS) {
130             return nullptr;
131         }
132         return Property()->Variable() != nullptr ? Property()->Variable()->AsLocalVariable() : nullptr;
133     }
134 
135     [[nodiscard]] bool IsComputed() const noexcept
136     {
137         return computed_;
138     }
139 
140     [[nodiscard]] MemberExpressionKind Kind() const noexcept
141     {
142         return kind_;
143     }
144 
145     void AddMemberKind(MemberExpressionKind kind) noexcept
146     {
147         kind_ |= kind;
148     }
149 
150     [[nodiscard]] bool HasMemberKind(MemberExpressionKind kind) const noexcept
151     {
152         return (kind_ & kind) != 0;
153     }
154 
155     void RemoveMemberKind(MemberExpressionKind const kind) noexcept
156     {
157         kind_ &= ~kind;
158     }
159 
160     [[nodiscard]] checker::ETSObjectType *ObjType() const noexcept
161     {
162         return objType_;
163     }
164 
165     [[nodiscard]] checker::ETSFunctionType *ExtensionAccessorType() const
166     {
167         return extensionAccessorType_;
168     }
169 
170     void SetExtensionAccessorType(checker::ETSFunctionType *eAccessorType)
171     {
172         ES2PANDA_ASSERT(HasMemberKind(ir::MemberExpressionKind::EXTENSION_ACCESSOR));
173         extensionAccessorType_ = eAccessorType;
174     }
175 
176     void SetPropVar(varbinder::LocalVariable *propVar) noexcept
177     {
178         ES2PANDA_ASSERT(Property());
179         Property()->SetVariable(propVar);
180     }
181 
182     void SetObjectType(checker::ETSObjectType *objType) noexcept
183     {
184         objType_ = objType;
185     }
186 
187     [[nodiscard]] bool IsIgnoreBox() const noexcept
188     {
189         return ignoreBox_;
190     }
191 
192     void SetIgnoreBox() noexcept
193     {
194         ignoreBox_ = true;
195     }
196 
197     [[nodiscard]] checker::Type *UncheckedType() const noexcept
198     {
199         return uncheckedType_;
200     }
201 
202     [[nodiscard]] bool IsPrivateReference() const noexcept;
203 
204     [[nodiscard]] MemberExpression *Clone(ArenaAllocator *allocator, AstNode *parent) override;
205     std::optional<std::size_t> GetTupleIndexValue() const;
206     checker::Type *GetTypeOfTupleElement(checker::ETSChecker *checker, checker::Type *baseType);
207 
208     void TransformChildren(const NodeTransformer &cb, std::string_view transformationName) override;
209     void Iterate(const NodeTraverser &cb) const override;
210     void Dump(ir::AstDumper *dumper) const override;
211     void Dump(ir::SrcDumper *dumper) const override;
212     void Compile(compiler::PandaGen *pg) const override;
213     void Compile(compiler::ETSGen *etsg) const override;
214     void CompileToReg(compiler::PandaGen *pg, compiler::VReg objReg) const;
215     void CompileToRegs(compiler::PandaGen *pg, compiler::VReg object, compiler::VReg property) const;
216     checker::Type *Check(checker::TSChecker *checker) override;
217     checker::VerifiedType Check(checker::ETSChecker *checker) override;
218 
219     std::string ToString() const override;
220 
221     void Accept(ASTVisitorT *v) override
222     {
223         v->Accept(this);
224     }
225 
226     void CleanUp() override
227     {
228         AstNode::CleanUp();
229         uncheckedType_ = nullptr;
230         objType_ = nullptr;
231         extensionAccessorType_ = nullptr;
232     }
233 
234 protected:
235     MemberExpression(MemberExpression const &other) : MaybeOptionalExpression(other)
236     {
237         kind_ = other.kind_;
238         computed_ = other.computed_;
239         ignoreBox_ = other.ignoreBox_;
240         // Note! Probably, we need to do 'Instantiate(...)' but we haven't access to 'Relation()' here...
241         uncheckedType_ = other.uncheckedType_;
242         objType_ = other.objType_;
243     }
244 
245 private:
246     std::pair<checker::Type *, varbinder::LocalVariable *> ResolveObjectMember(checker::ETSChecker *checker) const;
247     checker::Type *AdjustType(checker::ETSChecker *checker, checker::Type *type);
248     checker::Type *SetAndAdjustType(checker::ETSChecker *checker, checker::ETSObjectType *objectType);
249     checker::Type *CheckComputed(checker::ETSChecker *checker, checker::Type *baseType);
250     checker::Type *CheckUnionMember(checker::ETSChecker *checker, checker::Type *baseType);
251     checker::Type *TraverseUnionMember(checker::ETSChecker *checker, checker::ETSUnionType *unionType);
252 
253     bool CheckArrayIndexValue(checker::ETSChecker *checker) const;
254     checker::Type *CheckIndexAccessMethod(checker::ETSChecker *checker);
255     checker::Type *ResolveReturnTypeFromSignature(checker::ETSChecker *checker, bool isSetter,
256                                                   ArenaVector<ir::Expression *> &arguments,
257                                                   ArenaVector<checker::Signature *> &signatures,
258                                                   std::string_view const methodName);
259 
260     void LoadRhs(compiler::PandaGen *pg) const;
261 
262     Expression *object_ = nullptr;
263     Expression *property_ = nullptr;
264     MemberExpressionKind kind_;
265     bool computed_;
266     bool ignoreBox_ {false};
267     checker::Type *uncheckedType_ {};
268     checker::ETSObjectType *objType_ {};
269     checker::ETSFunctionType *extensionAccessorType_ {};
270 };
271 }  // namespace ark::es2panda::ir
272 
273 #endif
274