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 #include "ETSchecker.h"
17
18 #include "es2panda.h"
19 #include "ir/base/classDefinition.h"
20 #include "ir/expression.h"
21 #include "ir/expressions/callExpression.h"
22 #include "ir/ts/tsInterfaceDeclaration.h"
23 #include "ir/statements/blockStatement.h"
24 #include "varbinder/ETSBinder.h"
25 #include "parser/program/program.h"
26 #include "checker/ets/aliveAnalyzer.h"
27 #include "checker/ets/assignAnalyzer.h"
28 #include "checker/ets/etsWarningAnalyzer.h"
29 #include "checker/types/globalTypesHolder.h"
30 #include "ir/base/scriptFunction.h"
31 #include "util/helpers.h"
32
33 namespace ark::es2panda::checker {
34
InitBuiltin(ETSChecker * checker,std::string_view signature)35 static util::StringView InitBuiltin(ETSChecker *checker, std::string_view signature)
36 {
37 const auto varMap = checker->VarBinder()->TopScope()->Bindings();
38 const auto iterator = varMap.find(signature);
39 ASSERT(iterator != varMap.end());
40 auto *var = iterator->second;
41 Type *type {nullptr};
42 if (var->Declaration()->Node()->IsClassDefinition()) {
43 type = checker->BuildBasicClassProperties(var->Declaration()->Node()->AsClassDefinition());
44 } else {
45 ASSERT(var->Declaration()->Node()->IsTSInterfaceDeclaration());
46 type = checker->BuildBasicInterfaceProperties(var->Declaration()->Node()->AsTSInterfaceDeclaration());
47 }
48 checker->GetGlobalTypesHolder()->InitializeBuiltin(iterator->first, type);
49 return iterator->first;
50 }
51
SetupFunctionalInterface(ETSObjectType * type)52 static void SetupFunctionalInterface(ETSObjectType *type)
53 {
54 type->AddObjectFlag(ETSObjectFlags::FUNCTIONAL);
55 auto *invoke = type->GetOwnProperty<PropertyType::INSTANCE_METHOD>(FUNCTIONAL_INTERFACE_INVOKE_METHOD_NAME);
56 auto *invokeType = invoke->TsType()->AsETSFunctionType();
57 ASSERT(invokeType->CallSignatures().size() == 1);
58 auto *signature = invokeType->CallSignatures()[0];
59 signature->AddSignatureFlag(SignatureFlags::FUNCTIONAL_INTERFACE_SIGNATURE);
60 }
61
SetupBuiltinMember(varbinder::Variable * var)62 static void SetupBuiltinMember(varbinder::Variable *var)
63 {
64 auto *type = var->TsType();
65 if (type == nullptr || !type->IsETSObjectType()) {
66 return;
67 }
68 }
69
70 // NOLINTNEXTLINE(modernize-avoid-c-arrays)
71 static constexpr std::string_view BUILTINS_TO_INIT[] = {
72 compiler::Signatures::BUILTIN_BOOLEAN_CLASS, compiler::Signatures::BUILTIN_BYTE_CLASS,
73 compiler::Signatures::BUILTIN_CHAR_CLASS, compiler::Signatures::BUILTIN_SHORT_CLASS,
74 compiler::Signatures::BUILTIN_INT_CLASS, compiler::Signatures::BUILTIN_LONG_CLASS,
75 compiler::Signatures::BUILTIN_FLOAT_CLASS, compiler::Signatures::BUILTIN_DOUBLE_CLASS,
76 compiler::Signatures::BUILTIN_FUNCTION0_CLASS, compiler::Signatures::BUILTIN_FUNCTION1_CLASS,
77 compiler::Signatures::BUILTIN_FUNCTION2_CLASS, compiler::Signatures::BUILTIN_FUNCTION3_CLASS,
78 compiler::Signatures::BUILTIN_FUNCTION4_CLASS, compiler::Signatures::BUILTIN_FUNCTION5_CLASS,
79 compiler::Signatures::BUILTIN_FUNCTION6_CLASS, compiler::Signatures::BUILTIN_FUNCTION7_CLASS,
80 compiler::Signatures::BUILTIN_FUNCTION8_CLASS, compiler::Signatures::BUILTIN_FUNCTION9_CLASS,
81 compiler::Signatures::BUILTIN_FUNCTION10_CLASS, compiler::Signatures::BUILTIN_FUNCTION11_CLASS,
82 compiler::Signatures::BUILTIN_FUNCTION12_CLASS, compiler::Signatures::BUILTIN_FUNCTION13_CLASS,
83 compiler::Signatures::BUILTIN_FUNCTION14_CLASS, compiler::Signatures::BUILTIN_FUNCTION15_CLASS,
84 compiler::Signatures::BUILTIN_FUNCTION16_CLASS, compiler::Signatures::BUILTIN_FUNCTIONN_CLASS,
85 };
86
InitializeBuiltins(varbinder::ETSBinder * varbinder)87 void ETSChecker::InitializeBuiltins(varbinder::ETSBinder *varbinder)
88 {
89 if (HasStatus(CheckerStatus::BUILTINS_INITIALIZED)) {
90 return;
91 }
92
93 const auto varMap = varbinder->TopScope()->Bindings();
94
95 auto const objectName = InitBuiltin(this, compiler::Signatures::BUILTIN_OBJECT_CLASS);
96
97 for (auto sig : BUILTINS_TO_INIT) {
98 InitBuiltin(this, sig);
99 }
100
101 for (size_t id = static_cast<size_t>(GlobalTypeId::ETS_FUNCTION0_CLASS), nargs = 0;
102 id <= static_cast<size_t>(GlobalTypeId::ETS_FUNCTIONN_CLASS); id++, nargs++) {
103 auto *type = GetGlobalTypesHolder()->GlobalFunctionBuiltinType(nargs)->AsETSObjectType();
104 SetupFunctionalInterface(type);
105 }
106
107 for (const auto &[name, var] : varMap) {
108 (void)name;
109 SetupBuiltinMember(var);
110 }
111
112 for (const auto &[name, var] : varMap) {
113 if (name == objectName) {
114 continue;
115 }
116
117 if (var->HasFlag(varbinder::VariableFlags::BUILTIN_TYPE)) {
118 if (var->TsType() == nullptr) {
119 InitializeBuiltin(var, name);
120 } else {
121 GetGlobalTypesHolder()->InitializeBuiltin(name, var->TsType());
122 }
123 }
124 }
125
126 AddStatus(CheckerStatus::BUILTINS_INITIALIZED);
127 }
128
InitializeBuiltin(varbinder::Variable * var,const util::StringView & name)129 void ETSChecker::InitializeBuiltin(varbinder::Variable *var, const util::StringView &name)
130 {
131 Type *type {nullptr};
132 if (var->Declaration()->Node()->IsClassDefinition()) {
133 type = BuildBasicClassProperties(var->Declaration()->Node()->AsClassDefinition());
134 } else {
135 ASSERT(var->Declaration()->Node()->IsTSInterfaceDeclaration());
136 type = BuildBasicInterfaceProperties(var->Declaration()->Node()->AsTSInterfaceDeclaration());
137 }
138 GetGlobalTypesHolder()->InitializeBuiltin(name, type);
139 }
140
StartChecker(varbinder::VarBinder * varbinder,const CompilerOptions & options)141 bool ETSChecker::StartChecker(varbinder::VarBinder *varbinder, const CompilerOptions &options)
142 {
143 Initialize(varbinder);
144
145 if (options.parseOnly) {
146 return false;
147 }
148
149 auto *etsBinder = varbinder->AsETSBinder();
150 InitializeBuiltins(etsBinder);
151
152 for (auto &entry : etsBinder->DynamicImportVars()) {
153 auto &data = entry.second;
154 if (data.import->IsPureDynamic()) {
155 data.variable->SetTsType(GlobalBuiltinDynamicType(data.import->Language()));
156 }
157 }
158
159 CheckProgram(Program(), true);
160 BuildDynamicImportClass();
161
162 #ifndef NDEBUG
163 for (auto *func : varbinder->Functions()) {
164 ASSERT(!func->Node()->AsScriptFunction()->Scope()->InternalName().Empty());
165 }
166 #endif
167
168 if (options.dumpCheckedAst) {
169 std::cout << Program()->Dump() << std::endl;
170 }
171
172 if (options.etsHasWarnings) {
173 CheckWarnings(Program(), options);
174 }
175
176 return !ErrorLogger()->IsAnyError();
177 }
178
CheckProgram(parser::Program * program,bool runAnalysis)179 void ETSChecker::CheckProgram(parser::Program *program, bool runAnalysis)
180 {
181 auto *savedProgram = Program();
182 SetProgram(program);
183
184 for (auto &[_, extPrograms] : program->ExternalSources()) {
185 (void)_;
186 for (auto *extProg : extPrograms) {
187 checker::SavedCheckerContext savedContext(this, Context().Status(), Context().ContainingClass());
188 AddStatus(checker::CheckerStatus::IN_EXTERNAL);
189 CheckProgram(extProg, VarBinder()->IsGenStdLib());
190 }
191 }
192
193 ASSERT(Program()->Ast()->IsProgram());
194 Program()->Ast()->Check(this);
195
196 if (ErrorLogger()->IsAnyError()) {
197 return;
198 }
199
200 if (runAnalysis) {
201 AliveAnalyzer aliveAnalyzer(Program()->Ast(), this);
202 AssignAnalyzer(this).Analyze(Program()->Ast());
203 }
204
205 ASSERT(VarBinder()->AsETSBinder()->GetExternalRecordTable().find(program)->second);
206
207 SetProgram(savedProgram);
208 }
209
CheckWarnings(parser::Program * program,const CompilerOptions & options)210 void ETSChecker::CheckWarnings(parser::Program *program, const CompilerOptions &options)
211 {
212 const auto etsWarningCollection = options.etsWarningCollection;
213 for (const auto warning : etsWarningCollection) {
214 ETSWarningAnalyzer(Program()->Ast(), program, warning, options.etsWerror);
215 }
216 }
217
CheckTypeCached(ir::Expression * expr)218 Type *ETSChecker::CheckTypeCached(ir::Expression *expr)
219 {
220 if (expr->TsType() == nullptr) {
221 expr->SetTsType(expr->Check(this));
222 }
223
224 return expr->TsType();
225 }
226
227 template <typename... Args>
AsETSObjectType(Type * (GlobalTypesHolder::* typeFunctor)(Args...),Args...args) const228 ETSObjectType *ETSChecker::AsETSObjectType(Type *(GlobalTypesHolder::*typeFunctor)(Args...), Args... args) const
229 {
230 auto *ret = (GetGlobalTypesHolder()->*typeFunctor)(args...);
231 return ret != nullptr ? ret->AsETSObjectType() : nullptr;
232 }
233
GlobalByteType() const234 Type *ETSChecker::GlobalByteType() const
235 {
236 return GetGlobalTypesHolder()->GlobalByteType();
237 }
238
GlobalShortType() const239 Type *ETSChecker::GlobalShortType() const
240 {
241 return GetGlobalTypesHolder()->GlobalShortType();
242 }
243
GlobalIntType() const244 Type *ETSChecker::GlobalIntType() const
245 {
246 return GetGlobalTypesHolder()->GlobalIntType();
247 }
248
GlobalLongType() const249 Type *ETSChecker::GlobalLongType() const
250 {
251 return GetGlobalTypesHolder()->GlobalLongType();
252 }
253
GlobalFloatType() const254 Type *ETSChecker::GlobalFloatType() const
255 {
256 return GetGlobalTypesHolder()->GlobalFloatType();
257 }
258
GlobalDoubleType() const259 Type *ETSChecker::GlobalDoubleType() const
260 {
261 return GetGlobalTypesHolder()->GlobalDoubleType();
262 }
263
GlobalCharType() const264 Type *ETSChecker::GlobalCharType() const
265 {
266 return GetGlobalTypesHolder()->GlobalCharType();
267 }
268
GlobalETSBooleanType() const269 Type *ETSChecker::GlobalETSBooleanType() const
270 {
271 return GetGlobalTypesHolder()->GlobalETSBooleanType();
272 }
273
GlobalVoidType() const274 Type *ETSChecker::GlobalVoidType() const
275 {
276 return GetGlobalTypesHolder()->GlobalETSVoidType();
277 }
278
GlobalETSNullType() const279 Type *ETSChecker::GlobalETSNullType() const
280 {
281 return GetGlobalTypesHolder()->GlobalETSNullType();
282 }
283
GlobalETSUndefinedType() const284 Type *ETSChecker::GlobalETSUndefinedType() const
285 {
286 return GetGlobalTypesHolder()->GlobalETSUndefinedType();
287 }
288
GlobalETSStringLiteralType() const289 Type *ETSChecker::GlobalETSStringLiteralType() const
290 {
291 return GetGlobalTypesHolder()->GlobalETSStringLiteralType();
292 }
293
GlobalETSBigIntType() const294 Type *ETSChecker::GlobalETSBigIntType() const
295 {
296 return GetGlobalTypesHolder()->GlobalETSBigIntBuiltinType();
297 }
298
GlobalWildcardType() const299 Type *ETSChecker::GlobalWildcardType() const
300 {
301 return GetGlobalTypesHolder()->GlobalWildcardType();
302 }
303
GlobalETSObjectType() const304 ETSObjectType *ETSChecker::GlobalETSObjectType() const
305 {
306 return AsETSObjectType(&GlobalTypesHolder::GlobalETSObjectType);
307 }
308
GlobalETSNullishType() const309 ETSUnionType *ETSChecker::GlobalETSNullishType() const
310 {
311 auto *ret = (GetGlobalTypesHolder()->*&GlobalTypesHolder::GlobalETSNullishType)();
312 return ret != nullptr ? ret->AsETSUnionType() : nullptr;
313 }
314
GlobalETSNullishObjectType() const315 ETSUnionType *ETSChecker::GlobalETSNullishObjectType() const
316 {
317 auto *ret = (GetGlobalTypesHolder()->*&GlobalTypesHolder::GlobalETSNullishObjectType)();
318 return ret != nullptr ? ret->AsETSUnionType() : nullptr;
319 }
320
GlobalBuiltinETSStringType() const321 ETSObjectType *ETSChecker::GlobalBuiltinETSStringType() const
322 {
323 return AsETSObjectType(&GlobalTypesHolder::GlobalETSStringBuiltinType);
324 }
325
GlobalBuiltinETSBigIntType() const326 ETSObjectType *ETSChecker::GlobalBuiltinETSBigIntType() const
327 {
328 return AsETSObjectType(&GlobalTypesHolder::GlobalETSBigIntBuiltinType);
329 }
330
GlobalBuiltinTypeType() const331 ETSObjectType *ETSChecker::GlobalBuiltinTypeType() const
332 {
333 return AsETSObjectType(&GlobalTypesHolder::GlobalTypeBuiltinType);
334 }
335
GlobalBuiltinExceptionType() const336 ETSObjectType *ETSChecker::GlobalBuiltinExceptionType() const
337 {
338 return AsETSObjectType(&GlobalTypesHolder::GlobalExceptionBuiltinType);
339 }
340
GlobalBuiltinErrorType() const341 ETSObjectType *ETSChecker::GlobalBuiltinErrorType() const
342 {
343 return AsETSObjectType(&GlobalTypesHolder::GlobalErrorBuiltinType);
344 }
345
GlobalStringBuilderBuiltinType() const346 ETSObjectType *ETSChecker::GlobalStringBuilderBuiltinType() const
347 {
348 return AsETSObjectType(&GlobalTypesHolder::GlobalStringBuilderBuiltinType);
349 }
350
GlobalBuiltinPromiseType() const351 ETSObjectType *ETSChecker::GlobalBuiltinPromiseType() const
352 {
353 return AsETSObjectType(&GlobalTypesHolder::GlobalPromiseBuiltinType);
354 }
355
GlobalBuiltinJSRuntimeType() const356 ETSObjectType *ETSChecker::GlobalBuiltinJSRuntimeType() const
357 {
358 return AsETSObjectType(&GlobalTypesHolder::GlobalJSRuntimeBuiltinType);
359 }
360
GlobalBuiltinJSValueType() const361 ETSObjectType *ETSChecker::GlobalBuiltinJSValueType() const
362 {
363 return AsETSObjectType(&GlobalTypesHolder::GlobalJSValueBuiltinType);
364 }
365
GlobalBuiltinFunctionType(size_t nargs) const366 ETSObjectType *ETSChecker::GlobalBuiltinFunctionType(size_t nargs) const
367 {
368 return AsETSObjectType(&GlobalTypesHolder::GlobalFunctionBuiltinType, nargs);
369 }
370
GlobalBuiltinFunctionTypeVariadicThreshold() const371 size_t ETSChecker::GlobalBuiltinFunctionTypeVariadicThreshold() const
372 {
373 return GetGlobalTypesHolder()->VariadicFunctionTypeThreshold();
374 }
375
GlobalBuiltinDynamicType(Language lang) const376 ETSObjectType *ETSChecker::GlobalBuiltinDynamicType(Language lang) const
377 {
378 if (lang.GetId() == Language::Id::JS) {
379 return GlobalBuiltinJSValueType();
380 }
381 return nullptr;
382 }
383
GlobalBuiltinBoxType(Type * contents)384 ETSObjectType *ETSChecker::GlobalBuiltinBoxType(Type *contents)
385 {
386 switch (TypeKind(contents)) {
387 case TypeFlag::ETS_BOOLEAN:
388 return AsETSObjectType(&GlobalTypesHolder::GlobalBooleanBoxBuiltinType);
389 case TypeFlag::BYTE:
390 return AsETSObjectType(&GlobalTypesHolder::GlobalByteBoxBuiltinType);
391 case TypeFlag::CHAR:
392 return AsETSObjectType(&GlobalTypesHolder::GlobalCharBoxBuiltinType);
393 case TypeFlag::SHORT:
394 return AsETSObjectType(&GlobalTypesHolder::GlobalShortBoxBuiltinType);
395 case TypeFlag::INT:
396 return AsETSObjectType(&GlobalTypesHolder::GlobalIntBoxBuiltinType);
397 case TypeFlag::LONG:
398 return AsETSObjectType(&GlobalTypesHolder::GlobalLongBoxBuiltinType);
399 case TypeFlag::FLOAT:
400 return AsETSObjectType(&GlobalTypesHolder::GlobalFloatBoxBuiltinType);
401 case TypeFlag::DOUBLE:
402 return AsETSObjectType(&GlobalTypesHolder::GlobalDoubleBoxBuiltinType);
403 default: {
404 auto *base = AsETSObjectType(&GlobalTypesHolder::GlobalBoxBuiltinType);
405 auto *substitution = NewSubstitution();
406 substitution->emplace(base->TypeArguments()[0]->AsETSTypeParameter(), contents);
407 return base->Substitute(Relation(), substitution);
408 }
409 }
410 }
411
PrimitiveWrapper() const412 const checker::WrapperDesc &ETSChecker::PrimitiveWrapper() const
413 {
414 return primitiveWrappers_.Wrappers();
415 }
416
GlobalArrayTypes()417 GlobalArraySignatureMap &ETSChecker::GlobalArrayTypes()
418 {
419 return globalArraySignatures_;
420 }
421
GlobalArrayTypes() const422 const GlobalArraySignatureMap &ETSChecker::GlobalArrayTypes() const
423 {
424 return globalArraySignatures_;
425 }
426
GlobalTypeError() const427 Type *ETSChecker::GlobalTypeError() const
428 {
429 return GetGlobalTypesHolder()->GlobalTypeError();
430 }
431
HandleUpdatedCallExpressionNode(ir::CallExpression * callExpr)432 void ETSChecker::HandleUpdatedCallExpressionNode(ir::CallExpression *callExpr)
433 {
434 VarBinder()->AsETSBinder()->HandleCustomNodes(callExpr);
435 }
436
SelectGlobalIntegerTypeForNumeric(Type * type)437 Type *ETSChecker::SelectGlobalIntegerTypeForNumeric(Type *type)
438 {
439 switch (ETSType(type)) {
440 case checker::TypeFlag::FLOAT: {
441 return GlobalIntType();
442 }
443 case checker::TypeFlag::DOUBLE: {
444 return GlobalLongType();
445 }
446 default: {
447 return type;
448 }
449 }
450 }
451
452 } // namespace ark::es2panda::checker
453