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 #include "assignAnalyzer.h"
17 #include <cstddef>
18
19 #include "ir/base/classDefinition.h"
20 #include "ir/base/classProperty.h"
21 #include "ir/base/classStaticBlock.h"
22 #include "ir/base/methodDefinition.h"
23 #include "ir/base/scriptFunction.h"
24 #include "ir/statements/classDeclaration.h"
25 #include "ir/statements/variableDeclaration.h"
26 #include "ir/statements/doWhileStatement.h"
27 #include "ir/statements/expressionStatement.h"
28 #include "ir/statements/whileStatement.h"
29 #include "ir/statements/forUpdateStatement.h"
30 #include "ir/statements/labelledStatement.h"
31 #include "ir/statements/forOfStatement.h"
32 #include "ir/statements/blockStatement.h"
33 #include "ir/statements/ifStatement.h"
34 #include "ir/statements/switchStatement.h"
35 #include "ir/statements/variableDeclarator.h"
36 #include "ir/statements/throwStatement.h"
37 #include "ir/statements/switchCaseStatement.h"
38 #include "ir/statements/breakStatement.h"
39 #include "ir/statements/continueStatement.h"
40 #include "ir/statements/returnStatement.h"
41 #include "ir/statements/tryStatement.h"
42 #include "ir/expressions/callExpression.h"
43 #include "ir/expressions/identifier.h"
44 #include "ir/expressions/arrowFunctionExpression.h"
45 #include "ir/expressions/assignmentExpression.h"
46 #include "ir/expressions/binaryExpression.h"
47 #include "ir/expressions/conditionalExpression.h"
48 #include "ir/expressions/memberExpression.h"
49 #include "ir/expressions/objectExpression.h"
50 #include "ir/expressions/unaryExpression.h"
51 #include "ir/expressions/updateExpression.h"
52 #include "ir/expressions/typeofExpression.h"
53 #include "ir/ets/etsNewClassInstanceExpression.h"
54 #include "ir/ets/etsStructDeclaration.h"
55 #include "ir/ts/tsInterfaceDeclaration.h"
56 #include "varbinder/ETSBinder.h"
57 #include "varbinder/variable.h"
58 #include "varbinder/scope.h"
59 #include "varbinder/declaration.h"
60 #include "checker/ETSchecker.h"
61 #include "ir/base/catchClause.h"
62 #include "parser/program/program.h"
63 #include "checker/types/ts/objectType.h"
64
65 namespace ark::es2panda::checker {
66
67 static constexpr NodeId INVALID_ID = -1;
68 static constexpr bool CHECK_ALL_PROPERTIES = true;
69 // NOTE(pantos) generic field initialization issue, skip them for now
70 static constexpr bool CHECK_GENERIC_NON_READONLY_PROPERTIES = false;
71 static constexpr bool WARN_NO_INIT_ONCE_PER_VARIABLE = false;
72 static constexpr int LOOP_PHASES = 2;
73
74 template <typename... Ts>
75 struct ScopeGuard {
76 // NOLINTBEGIN(misc-non-private-member-variables-in-classes)
77 std::tuple<Ts...> values;
78 std::tuple<Ts &...> refs;
79 // NOLINTEND(misc-non-private-member-variables-in-classes)
80
ScopeGuardark::es2panda::checker::ScopeGuard81 explicit ScopeGuard(Ts &...ts) : values(ts...), refs(ts...) {}
~ScopeGuardark::es2panda::checker::ScopeGuard82 ~ScopeGuard()
83 {
84 refs = values;
85 }
86
87 DEFAULT_COPY_SEMANTIC(ScopeGuard);
88 DEFAULT_MOVE_SEMANTIC(ScopeGuard);
89 };
90
Capitalize(const util::StringView & str)91 static std::string Capitalize(const util::StringView &str)
92 {
93 if (str.Empty()) {
94 return "";
95 }
96 std::string ret(str.Utf8());
97 ret[0] = std::toupper(ret[0]);
98 return ret;
99 }
100
Reset()101 void Set::Reset()
102 {
103 reset_ = true;
104 }
105
IsReset()106 bool Set::IsReset()
107 {
108 return reset_;
109 }
110
Incl(const int id)111 void Set::Incl(const int id)
112 {
113 nodes_.insert(id);
114 }
115
InclRange(const int start,const int limit)116 void Set::InclRange(const int start, const int limit)
117 {
118 for (int x = start; x < limit; x++) {
119 nodes_.insert(x);
120 }
121 }
122
Excl(const int id)123 void Set::Excl(const int id)
124 {
125 nodes_.erase(id);
126 }
127
ExcludeFrom(const int start)128 void Set::ExcludeFrom(const int start)
129 {
130 auto it = nodes_.lower_bound(start);
131 nodes_.erase(nodes_.begin(), it);
132 }
133
IsMember(const int id) const134 bool Set::IsMember(const int id) const
135 {
136 return nodes_.find(id) != nodes_.end();
137 }
138
AndSet(const Set & xs)139 Set &Set::AndSet(const Set &xs)
140 {
141 std::set<int> res;
142 std::set_intersection(nodes_.begin(), nodes_.end(), xs.nodes_.begin(), xs.nodes_.end(),
143 std::inserter(res, res.begin()));
144 nodes_ = std::move(res);
145 return *this;
146 }
147
OrSet(const Set & xs)148 Set &Set::OrSet(const Set &xs)
149 {
150 std::set<int> res;
151 std::set_union(nodes_.begin(), nodes_.end(), xs.nodes_.begin(), xs.nodes_.end(), std::inserter(res, res.begin()));
152 nodes_ = std::move(res);
153 return *this;
154 }
155
DiffSet(const Set & xs)156 Set &Set::DiffSet(const Set &xs)
157 {
158 std::set<int> res;
159 std::set_difference(nodes_.begin(), nodes_.end(), xs.nodes_.begin(), xs.nodes_.end(),
160 std::inserter(res, res.begin()));
161 nodes_ = std::move(res);
162 return *this;
163 }
164
Next(const int id)165 int Set::Next(const int id)
166 {
167 auto it = nodes_.upper_bound(id);
168 if (it != nodes_.end()) {
169 return *it;
170 }
171 return -1;
172 }
173
AssignAnalyzer(ETSChecker * checker)174 AssignAnalyzer::AssignAnalyzer(ETSChecker *checker)
175 : checker_(checker),
176 varDecls_(checker->Allocator()->Adapter()),
177 nodeIdMap_(checker->Allocator()->Adapter()),
178 foundErrors_(checker->Allocator()->Adapter())
179 {
180 }
181
Analyze(const ir::AstNode * node)182 void AssignAnalyzer::Analyze(const ir::AstNode *node)
183 {
184 const auto program = checker_->VarBinder()->Program();
185 globalClass_ = program->GlobalClass();
186
187 AnalyzeClassDef(globalClass_);
188
189 firstNonGlobalAdr_ = nextAdr_;
190 AnalyzeNodes(node);
191 }
192
Warning(const diagnostic::DiagnosticKind & kind,const util::DiagnosticMessageParams & list,const lexer::SourcePosition & pos)193 void AssignAnalyzer::Warning(const diagnostic::DiagnosticKind &kind, const util::DiagnosticMessageParams &list,
194 const lexer::SourcePosition &pos)
195 {
196 ++numErrors_;
197 checker_->LogDiagnostic(kind, list, pos);
198 }
199
AnalyzeNodes(const ir::AstNode * node)200 void AssignAnalyzer::AnalyzeNodes(const ir::AstNode *node)
201 {
202 node->Iterate([this](auto *childNode) { AnalyzeNode(childNode); });
203 }
204
AnalyzeNode(const ir::AstNode * node)205 void AssignAnalyzer::AnalyzeNode(const ir::AstNode *node)
206 {
207 ES2PANDA_ASSERT(node != nullptr);
208
209 // NOTE(pantos) these are dummy methods to conform the CI's method size and complexity requirements
210 if (AnalyzeStmtNode1(node) || AnalyzeStmtNode2(node) || AnalyzeExprNode1(node) || AnalyzeExprNode2(node)) {
211 return;
212 }
213
214 switch (node->Type()) {
215 case ir::AstNodeType::STRUCT_DECLARATION: {
216 AnalyzeStructDecl(node->AsETSStructDeclaration());
217 break;
218 }
219 case ir::AstNodeType::CLASS_DECLARATION: {
220 AnalyzeClassDecl(node->AsClassDeclaration());
221 break;
222 }
223 case ir::AstNodeType::CLASS_DEFINITION: {
224 if (node->AsClassDefinition() != globalClass_) {
225 AnalyzeClassDef(node->AsClassDefinition());
226 }
227 break;
228 }
229 case ir::AstNodeType::METHOD_DEFINITION: {
230 AnalyzeMethodDef(node->AsMethodDefinition());
231 break;
232 }
233 case ir::AstNodeType::VARIABLE_DECLARATION: {
234 AnalyzeVarDef(node->AsVariableDeclaration());
235 break;
236 }
237 default: {
238 AnalyzeNodes(node);
239 if (node->IsExpression()) {
240 if (inits_.IsReset()) {
241 Merge();
242 }
243 }
244 break;
245 }
246 }
247 }
248
AnalyzeStmtNode1(const ir::AstNode * node)249 bool AssignAnalyzer::AnalyzeStmtNode1(const ir::AstNode *node)
250 {
251 switch (node->Type()) {
252 case ir::AstNodeType::EXPRESSION_STATEMENT: {
253 AnalyzeNode(node->AsExpressionStatement()->GetExpression());
254 break;
255 }
256 case ir::AstNodeType::BLOCK_STATEMENT: {
257 AnalyzeBlock(node->AsBlockStatement());
258 break;
259 }
260 case ir::AstNodeType::DO_WHILE_STATEMENT: {
261 AnalyzeDoLoop(node->AsDoWhileStatement());
262 break;
263 }
264 case ir::AstNodeType::WHILE_STATEMENT: {
265 AnalyzeWhileLoop(node->AsWhileStatement());
266 break;
267 }
268 case ir::AstNodeType::FOR_UPDATE_STATEMENT: {
269 AnalyzeForLoop(node->AsForUpdateStatement());
270 break;
271 }
272 case ir::AstNodeType::FOR_OF_STATEMENT: {
273 AnalyzeForOfLoop(node->AsForOfStatement());
274 break;
275 }
276 case ir::AstNodeType::IF_STATEMENT: {
277 AnalyzeIf(node->AsIfStatement());
278 break;
279 }
280 default:
281 return false;
282 }
283
284 return true;
285 }
286
AnalyzeStmtNode2(const ir::AstNode * node)287 bool AssignAnalyzer::AnalyzeStmtNode2(const ir::AstNode *node)
288 {
289 switch (node->Type()) {
290 case ir::AstNodeType::LABELLED_STATEMENT: {
291 AnalyzeLabelled(node->AsLabelledStatement());
292 break;
293 }
294 case ir::AstNodeType::SWITCH_STATEMENT: {
295 AnalyzeSwitch(node->AsSwitchStatement());
296 break;
297 }
298 case ir::AstNodeType::TRY_STATEMENT: {
299 AnalyzeTry(node->AsTryStatement());
300 break;
301 }
302 case ir::AstNodeType::BREAK_STATEMENT: {
303 AnalyzeBreak(node->AsBreakStatement());
304 break;
305 }
306 case ir::AstNodeType::CONTINUE_STATEMENT: {
307 AnalyzeContinue(node->AsContinueStatement());
308 break;
309 }
310 case ir::AstNodeType::RETURN_STATEMENT: {
311 AnalyzeReturn(node->AsReturnStatement());
312 break;
313 }
314 case ir::AstNodeType::THROW_STATEMENT: {
315 AnalyzeThrow(node->AsThrowStatement());
316 break;
317 }
318 default:
319 return false;
320 }
321
322 return true;
323 }
324
AnalyzeExprNode1(const ir::AstNode * node)325 bool AssignAnalyzer::AnalyzeExprNode1(const ir::AstNode *node)
326 {
327 switch (node->Type()) {
328 case ir::AstNodeType::ETS_NEW_CLASS_INSTANCE_EXPRESSION: {
329 AnalyzeNewClass(node->AsETSNewClassInstanceExpression());
330 break;
331 }
332 case ir::AstNodeType::CALL_EXPRESSION: {
333 AnalyzeCallExpr(node->AsCallExpression());
334 break;
335 }
336 case ir::AstNodeType::IDENTIFIER: {
337 AnalyzeId(node->AsIdentifier());
338 break;
339 }
340 case ir::AstNodeType::ASSIGNMENT_EXPRESSION: {
341 AnalyzeAssignExpr(node->AsAssignmentExpression());
342 break;
343 }
344 case ir::AstNodeType::CONDITIONAL_EXPRESSION: {
345 AnalyzeCondExpr(node->AsConditionalExpression());
346 break;
347 }
348 case ir::AstNodeType::MEMBER_EXPRESSION: {
349 AnalyzeMemberExpr(node->AsMemberExpression());
350 break;
351 }
352 default:
353 return false;
354 }
355
356 return true;
357 }
358
AnalyzeExprNode2(const ir::AstNode * node)359 bool AssignAnalyzer::AnalyzeExprNode2(const ir::AstNode *node)
360 {
361 switch (node->Type()) {
362 case ir::AstNodeType::BINARY_EXPRESSION: {
363 AnalyzeBinaryExpr(node->AsBinaryExpression());
364 break;
365 }
366 case ir::AstNodeType::UNARY_EXPRESSION: {
367 AnalyzeUnaryExpr(node->AsUnaryExpression());
368 break;
369 }
370 case ir::AstNodeType::UPDATE_EXPRESSION: {
371 AnalyzeUpdateExpr(node->AsUpdateExpression());
372 break;
373 }
374 case ir::AstNodeType::ARROW_FUNCTION_EXPRESSION: {
375 AnalyzeArrowFunctionExpr(node->AsArrowFunctionExpression());
376 break;
377 }
378 default:
379 return false;
380 }
381
382 return true;
383 }
384
AnalyzeStat(const ir::AstNode * node)385 void AssignAnalyzer::AnalyzeStat(const ir::AstNode *node)
386 {
387 ES2PANDA_ASSERT(node != nullptr);
388 AnalyzeNode(node);
389 }
390
AnalyzeStats(const ArenaVector<ir::Statement * > & stats)391 void AssignAnalyzer::AnalyzeStats(const ArenaVector<ir::Statement *> &stats)
392 {
393 for (const auto it : stats) {
394 AnalyzeStat(it);
395 }
396 }
397
AnalyzeBlock(const ir::BlockStatement * blockStmt)398 void AssignAnalyzer::AnalyzeBlock(const ir::BlockStatement *blockStmt)
399 {
400 ScopeGuard save(nextAdr_);
401
402 AnalyzeStats(blockStmt->Statements());
403 }
404
AnalyzeStructDecl(const ir::ETSStructDeclaration * structDecl)405 void AssignAnalyzer::AnalyzeStructDecl(const ir::ETSStructDeclaration *structDecl)
406 {
407 AnalyzeNode(structDecl->Definition());
408 }
409
AnalyzeClassDecl(const ir::ClassDeclaration * classDecl)410 void AssignAnalyzer::AnalyzeClassDecl(const ir::ClassDeclaration *classDecl)
411 {
412 AnalyzeNode(classDecl->Definition());
413 }
414
AnalyzeClassDef(const ir::ClassDefinition * classDef)415 void AssignAnalyzer::AnalyzeClassDef(const ir::ClassDefinition *classDef)
416 {
417 SetOldPendingExits(PendingExits());
418
419 ScopeGuard save(firstAdr_, nextAdr_, classDef_, classFirstAdr_);
420
421 classDef_ = classDef;
422 firstAdr_ = nextAdr_;
423 classFirstAdr_ = nextAdr_;
424
425 ProcessClassDefStaticFields(classDef_);
426
427 // define all the instance fields
428 for (const auto it : classDef->Body()) {
429 if (it->IsClassProperty() && !it->IsStatic()) {
430 const auto prop = it->AsClassProperty();
431 NewVar(prop);
432 if (prop->Value() != nullptr) {
433 LetInit(prop);
434 }
435 }
436 }
437
438 CheckAnonymousClassCtor(classDef_);
439
440 // process all the methods
441 std::vector<const ir::AstNode *> methods;
442 for (const auto it : classDef->Body()) {
443 if (it->IsMethodDefinition()) {
444 const auto methodDef = it->AsMethodDefinition();
445 if (methodDef->Key()->AsIdentifier()->Name().Is(compiler::Signatures::INIT_METHOD)) {
446 // skip the special init method as we have already checked it
447 continue;
448 }
449
450 methods.push_back(methodDef);
451
452 for (const auto it2 : methodDef->Overloads()) {
453 methods.push_back(it2);
454 }
455 }
456 }
457
458 for (const auto it : methods) {
459 AnalyzeNode(it);
460 }
461
462 SetPendingExits(OldPendingExits());
463 }
464
465 // NOTE (pantos) awkward methods to conform method length/complexity requirements of CI...
ProcessClassDefStaticFields(const ir::ClassDefinition * classDef)466 void AssignAnalyzer::ProcessClassDefStaticFields(const ir::ClassDefinition *classDef)
467 {
468 // define all the static fields
469 for (const auto it : classDef->Body()) {
470 if (it->IsClassProperty() && it->IsStatic()) {
471 const auto prop = it->AsClassProperty();
472 NewVar(prop);
473 if (prop->Value() != nullptr) {
474 LetInit(prop);
475 }
476 }
477 }
478
479 // process all the static initializers
480 for (const auto it : classDef->Body()) {
481 if (it->IsClassStaticBlock() ||
482 (it->IsStatic() && it->IsMethodDefinition() &&
483 (it->AsMethodDefinition()->Key()->AsIdentifier()->Name().Is(compiler::Signatures::INIT_METHOD) ||
484 it->AsMethodDefinition()->Key()->AsIdentifier()->Name().StartsWith(
485 compiler::Signatures::INITIALIZER_BLOCK_INIT)))) {
486 AnalyzeNodes(it);
487 ClearPendingExits();
488 }
489 }
490
491 // verify all static const fields got initailized
492 if (!classDef->IsModule()) {
493 for (int i = firstAdr_; i < nextAdr_; i++) {
494 const ir::AstNode *var = varDecls_[i];
495 if (var->IsStatic() && (var->IsConst() || CHECK_ALL_PROPERTIES)) {
496 CheckInit(var);
497 }
498 }
499 }
500 }
501
CheckAnonymousClassCtor(const ir::ClassDefinition * classDef)502 void AssignAnalyzer::CheckAnonymousClassCtor(const ir::ClassDefinition *classDef)
503 {
504 if (classDef == globalClass_) {
505 return;
506 }
507
508 // NOTE(pantos) anonymous classes of new expressions has no default ctor right now
509 // but this feature might be completely removed from the spec...
510 bool hasCtor = false;
511 for (const auto it : classDef->Body()) {
512 if (it->IsMethodDefinition() && it->AsMethodDefinition()->IsConstructor()) {
513 hasCtor = true;
514 break;
515 }
516 }
517 if (!hasCtor) {
518 for (int i = firstAdr_; i < nextAdr_; i++) {
519 const ir::AstNode *var = varDecls_[i];
520 if (!var->IsStatic() && (var->IsConst() || CHECK_ALL_PROPERTIES)) {
521 CheckInit(var);
522 }
523 }
524 }
525 }
526
527 // NOTE(pantos) modified version of ETSChecker::CheckCyclicConstructorCall
IsInitialConstructor(const ir::AstNode * node)528 static bool IsInitialConstructor(const ir::AstNode *node)
529 {
530 if (!node->IsMethodDefinition() || !node->AsMethodDefinition()->IsConstructor()) {
531 return false;
532 }
533
534 const auto methodDef = node->AsMethodDefinition();
535 ES2PANDA_ASSERT(methodDef != nullptr);
536 if (methodDef->Function()->Body() == nullptr || methodDef->Function()->IsExternal()) {
537 return false;
538 }
539
540 const auto *func = node->AsMethodDefinition()->Function();
541 ES2PANDA_ASSERT(func != nullptr);
542 const auto funcBody = func->Body()->AsBlockStatement();
543
544 return !(!funcBody->Statements().empty() && funcBody->Statements()[0]->IsExpressionStatement() &&
545 funcBody->Statements()[0]->AsExpressionStatement()->GetExpression()->IsCallExpression() &&
546 funcBody->Statements()[0]
547 ->AsExpressionStatement()
548 ->GetExpression()
549 ->AsCallExpression()
550 ->Callee()
551 ->IsThisExpression());
552 }
553
AnalyzeMethodDef(const ir::MethodDefinition * methodDef)554 void AssignAnalyzer::AnalyzeMethodDef(const ir::MethodDefinition *methodDef)
555 {
556 auto *func = methodDef->Function();
557 ES2PANDA_ASSERT(func != nullptr);
558 if (func->Body() == nullptr || func->IsProxy()) {
559 return;
560 }
561
562 Set initsPrev = inits_;
563 Set uninitsPrev = uninits_;
564
565 ScopeGuard save(firstAdr_, nextAdr_, returnAdr_, isInitialConstructor_);
566
567 hasTryFinallyBlock_ = func->IsAnyChild([](ir::AstNode *ast) {
568 return (ast->Type() == ir::AstNodeType::TRY_STATEMENT && ast->AsTryStatement()->FinallyBlock() != nullptr);
569 });
570 isInitialConstructor_ = IsInitialConstructor(methodDef);
571 if (!isInitialConstructor_) {
572 firstAdr_ = nextAdr_;
573 }
574
575 AnalyzeStat(func->Body());
576
577 if (isInitialConstructor_) {
578 for (int i = firstAdr_; i < nextAdr_; i++) {
579 const ir::AstNode *var = varDecls_[i];
580 if (!var->IsStatic() && (var->IsConst() || CHECK_ALL_PROPERTIES)) {
581 CheckInit(var);
582 }
583 }
584 }
585
586 CheckPendingExits();
587
588 inits_ = std::move(initsPrev);
589 uninits_ = std::move(uninitsPrev);
590 }
591
AnalyzeVarDef(const ir::VariableDeclaration * varDef)592 void AssignAnalyzer::AnalyzeVarDef(const ir::VariableDeclaration *varDef)
593 {
594 for (auto *var : varDef->Declarators()) {
595 NewVar(var);
596
597 if (var->Init() != nullptr) {
598 AnalyzeExpr(var->Init());
599 LetInit(var);
600 }
601 }
602 }
603
AnalyzeDoLoop(const ir::DoWhileStatement * doWhileStmt)604 void AssignAnalyzer::AnalyzeDoLoop(const ir::DoWhileStatement *doWhileStmt)
605 {
606 SetOldPendingExits(PendingExits());
607
608 Set initsSkip {};
609 Set uninitsSkip {};
610 int prevErrors = numErrors_;
611
612 for (int phase = 1; phase <= LOOP_PHASES; phase++) {
613 Set uninitsEntry = uninits_;
614 uninitsEntry.ExcludeFrom(nextAdr_);
615
616 AnalyzeStat(doWhileStmt->Body());
617
618 ResolveContinues(doWhileStmt);
619
620 AnalyzeCond(doWhileStmt->Test());
621
622 if (phase == 1) {
623 initsSkip = initsWhenFalse_;
624 uninitsSkip = uninitsWhenFalse_;
625 }
626
627 if (prevErrors != numErrors_ || phase == LOOP_PHASES ||
628 uninitsEntry.DiffSet(uninitsWhenTrue_).Next(firstAdr_) == -1) {
629 break;
630 }
631
632 inits_ = initsWhenTrue_;
633 uninits_ = uninitsEntry.AndSet(uninitsWhenTrue_);
634 }
635
636 inits_ = std::move(initsSkip);
637 uninits_ = std::move(uninitsSkip);
638
639 ResolveBreaks(doWhileStmt);
640 }
641
AnalyzeWhileLoop(const ir::WhileStatement * whileStmt)642 void AssignAnalyzer::AnalyzeWhileLoop(const ir::WhileStatement *whileStmt)
643 {
644 SetOldPendingExits(PendingExits());
645
646 Set initsSkip {};
647 Set uninitsSkip {};
648 int prevErrors = numErrors_;
649
650 Set uninitsEntry = uninits_;
651 uninitsEntry.ExcludeFrom(nextAdr_);
652
653 for (int phase = 1; phase <= LOOP_PHASES; phase++) {
654 AnalyzeCond(whileStmt->Test());
655
656 if (phase == 1) {
657 initsSkip = initsWhenFalse_;
658 uninitsSkip = uninitsWhenFalse_;
659 }
660
661 inits_ = initsWhenTrue_;
662 uninits_ = uninitsWhenTrue_;
663
664 AnalyzeStat(whileStmt->Body());
665
666 ResolveContinues(whileStmt);
667
668 if (prevErrors != numErrors_ || phase == LOOP_PHASES || uninitsEntry.DiffSet(uninits_).Next(firstAdr_) == -1) {
669 break;
670 }
671
672 uninits_ = uninitsEntry.AndSet(uninits_);
673 }
674
675 inits_ = std::move(initsSkip);
676 uninits_ = std::move(uninitsSkip);
677
678 ResolveBreaks(whileStmt);
679 }
680
AnalyzeForLoop(const ir::ForUpdateStatement * forStmt)681 void AssignAnalyzer::AnalyzeForLoop(const ir::ForUpdateStatement *forStmt)
682 {
683 ScopeGuard save(nextAdr_);
684
685 if (forStmt->Init() != nullptr) {
686 AnalyzeNode(forStmt->Init());
687 }
688
689 Set initsSkip {};
690 Set uninitsSkip {};
691 int prevErrors = numErrors_;
692
693 SetOldPendingExits(PendingExits());
694
695 for (int phase = 1; phase <= LOOP_PHASES; phase++) {
696 Set uninitsEntry = uninits_;
697 uninitsEntry.ExcludeFrom(nextAdr_);
698
699 if (forStmt->Test() != nullptr) {
700 AnalyzeCond(forStmt->Test());
701
702 if (phase == 1) {
703 initsSkip = initsWhenFalse_;
704 uninitsSkip = uninitsWhenFalse_;
705 }
706
707 inits_ = initsWhenTrue_;
708 uninits_ = uninitsWhenTrue_;
709 } else if (phase == 1) {
710 initsSkip = inits_;
711 initsSkip.InclRange(firstAdr_, nextAdr_);
712 uninitsSkip = uninits_;
713 uninitsSkip.InclRange(firstAdr_, nextAdr_);
714 }
715
716 AnalyzeStat(forStmt->Body());
717
718 ResolveContinues(forStmt);
719
720 if (forStmt->Update() != nullptr) {
721 AnalyzeNode(forStmt->Update());
722 }
723
724 if (prevErrors != numErrors_ || phase == LOOP_PHASES || uninitsEntry.DiffSet(uninits_).Next(firstAdr_) == -1) {
725 break;
726 }
727
728 uninits_ = uninitsEntry.AndSet(uninits_);
729 }
730
731 inits_ = std::move(initsSkip);
732 uninits_ = std::move(uninitsSkip);
733
734 ResolveBreaks(forStmt);
735 }
736
AnalyzeForOfLoop(const ir::ForOfStatement * forOfStmt)737 void AssignAnalyzer::AnalyzeForOfLoop(const ir::ForOfStatement *forOfStmt)
738 {
739 ScopeGuard save(nextAdr_);
740
741 if (forOfStmt->Left()->IsVariableDeclaration()) {
742 AnalyzeVarDef(forOfStmt->Left()->AsVariableDeclaration());
743 for (auto *var : forOfStmt->Left()->AsVariableDeclaration()->Declarators()) {
744 LetInit(var);
745 }
746 } else {
747 LetInit(forOfStmt->Left());
748 }
749
750 AnalyzeNode(forOfStmt->Right());
751
752 Set initsStart = inits_;
753 Set uninitsStart = uninits_;
754 int prevErrors = numErrors_;
755
756 SetOldPendingExits(PendingExits());
757
758 for (int phase = 1; phase <= LOOP_PHASES; phase++) {
759 Set uninitsEntry = uninits_;
760 uninitsEntry.ExcludeFrom(nextAdr_);
761
762 AnalyzeStat(forOfStmt->Body());
763
764 ResolveContinues(forOfStmt);
765
766 if (prevErrors != numErrors_ || phase == LOOP_PHASES || uninitsEntry.DiffSet(uninits_).Next(firstAdr_) == -1) {
767 break;
768 }
769
770 uninits_ = uninitsEntry.AndSet(uninits_);
771 }
772
773 inits_ = initsStart;
774 uninits_ = std::move(uninitsStart.AndSet(uninits_));
775
776 ResolveBreaks(forOfStmt);
777 }
778
AnalyzeIf(const ir::IfStatement * ifStmt)779 void AssignAnalyzer::AnalyzeIf(const ir::IfStatement *ifStmt)
780 {
781 AnalyzeCond(ifStmt->Test());
782
783 Set initsBeforeElse = initsWhenFalse_;
784 Set uninitsBeforeElse = uninitsWhenFalse_;
785 inits_ = initsWhenTrue_;
786 uninits_ = uninitsWhenTrue_;
787
788 AnalyzeStat(ifStmt->Consequent());
789
790 if (ifStmt->Alternate() != nullptr) {
791 Set initsAfterThen = std::move(inits_);
792 Set uninitsAfterThen = std::move(uninits_);
793 inits_ = std::move(initsBeforeElse);
794 uninits_ = std::move(uninitsBeforeElse);
795
796 AnalyzeStat(ifStmt->Alternate());
797
798 inits_.AndSet(initsAfterThen);
799 uninits_.AndSet(uninitsAfterThen);
800 } else {
801 inits_.AndSet(initsBeforeElse);
802 uninits_.AndSet(uninitsBeforeElse);
803 }
804 }
805
AnalyzeLabelled(const ir::LabelledStatement * labelledStmt)806 void AssignAnalyzer::AnalyzeLabelled(const ir::LabelledStatement *labelledStmt)
807 {
808 SetOldPendingExits(PendingExits());
809
810 AnalyzeStat(labelledStmt->Body());
811
812 ResolveBreaks(labelledStmt);
813 }
814
AnalyzeSwitch(const ir::SwitchStatement * switchStmt)815 void AssignAnalyzer::AnalyzeSwitch(const ir::SwitchStatement *switchStmt)
816 {
817 SetOldPendingExits(PendingExits());
818
819 ScopeGuard save(nextAdr_);
820
821 AnalyzeNode(switchStmt->Discriminant());
822
823 Set initsSwitch = inits_;
824 Set uninitsSwitch = uninits_;
825
826 bool hasDefault = false;
827
828 for (const auto caseClause : switchStmt->Cases()) {
829 inits_ = initsSwitch;
830 uninits_ = uninits_.AndSet(uninitsSwitch);
831
832 if (caseClause->Test() == nullptr) {
833 hasDefault = true;
834 } else {
835 AnalyzeNode(caseClause->Test());
836 }
837
838 if (hasDefault) {
839 inits_ = initsSwitch;
840 uninits_ = uninits_.AndSet(uninitsSwitch);
841 }
842
843 AnalyzeStats(caseClause->Consequent());
844
845 for (const auto stmt : caseClause->Consequent()) {
846 if (!stmt->IsVariableDeclaration()) {
847 continue;
848 }
849 for (auto *var : stmt->AsVariableDeclaration()->Declarators()) {
850 NodeId adr = GetNodeId(var);
851 ES2PANDA_ASSERT(adr >= 0);
852 initsSwitch.Excl(adr);
853 uninitsSwitch.Incl(adr);
854 }
855 }
856
857 if (!hasDefault) {
858 inits_ = initsSwitch;
859 uninits_ = uninits_.AndSet(uninitsSwitch);
860 }
861 }
862
863 if (!hasDefault) {
864 inits_.AndSet(initsSwitch);
865 }
866
867 ResolveBreaks(switchStmt);
868 }
869
AnalyzeTry(const ir::TryStatement * tryStmt)870 void AssignAnalyzer::AnalyzeTry(const ir::TryStatement *tryStmt)
871 {
872 Set uninitsTryPrev = uninitsTry_;
873
874 PendingExitsVector prevPendingExits = PendingExits();
875 SetOldPendingExits(prevPendingExits);
876
877 Set initsTry = inits_;
878 uninitsTry_ = uninits_;
879
880 AnalyzeNode(tryStmt->Block());
881
882 uninitsTry_.AndSet(uninits_);
883
884 Set initsEnd = inits_;
885 Set uninitsEnd = uninits_;
886 int nextAdrCatch = nextAdr_;
887
888 Set initsCatchPrev = initsTry; // NOLINT(performance-unnecessary-copy-initialization)
889 Set uninitsCatchPrev = uninitsTry_;
890
891 for (const auto catchClause : tryStmt->CatchClauses()) {
892 inits_ = initsCatchPrev;
893 uninits_ = uninitsCatchPrev;
894
895 AnalyzeNode(catchClause->Body());
896
897 initsEnd.AndSet(inits_);
898 uninitsEnd.AndSet(uninits_);
899 nextAdr_ = nextAdrCatch;
900 }
901
902 if (tryStmt->FinallyBlock() != nullptr) {
903 inits_ = std::move(initsTry);
904 uninits_ = uninitsTry_;
905
906 PendingExitsVector exits = PendingExits();
907 SetPendingExits(prevPendingExits);
908
909 AnalyzeNode(tryStmt->FinallyBlock());
910
911 if (tryStmt->FinallyCanCompleteNormally()) {
912 uninits_.AndSet(uninitsEnd);
913 for (auto exit : exits) {
914 exit.exitInits_.OrSet(inits_);
915 exit.exitUninits_.AndSet(uninits_);
916 PendingExits().push_back(exit);
917 }
918 inits_.OrSet(initsEnd);
919 }
920 } else {
921 inits_ = std::move(initsEnd);
922 uninits_ = std::move(uninitsEnd);
923
924 PendingExitsVector exits = PendingExits();
925 SetPendingExits(prevPendingExits);
926
927 for (const auto &exit : exits) {
928 PendingExits().push_back(exit);
929 }
930 }
931
932 uninitsTry_.AndSet(uninitsTryPrev).AndSet(uninits_);
933 }
934
AnalyzeBreak(const ir::BreakStatement * breakStmt)935 void AssignAnalyzer::AnalyzeBreak(const ir::BreakStatement *breakStmt)
936 {
937 RecordExit(AssignPendingExit(breakStmt, inits_, uninits_, isInitialConstructor_, hasTryFinallyBlock_));
938 }
939
AnalyzeContinue(const ir::ContinueStatement * contStmt)940 void AssignAnalyzer::AnalyzeContinue(const ir::ContinueStatement *contStmt)
941 {
942 RecordExit(AssignPendingExit(contStmt, inits_, uninits_, isInitialConstructor_, hasTryFinallyBlock_));
943 }
944
AnalyzeReturn(const ir::ReturnStatement * retStmt)945 void AssignAnalyzer::AnalyzeReturn(const ir::ReturnStatement *retStmt)
946 {
947 if (retStmt->Argument() != nullptr) {
948 AnalyzeNode(retStmt->Argument());
949 }
950 RecordExit(AssignPendingExit(retStmt, inits_, uninits_, isInitialConstructor_, hasTryFinallyBlock_));
951 }
952
AnalyzeThrow(const ir::ThrowStatement * throwStmt)953 void AssignAnalyzer::AnalyzeThrow(const ir::ThrowStatement *throwStmt)
954 {
955 AnalyzeNode(throwStmt->Argument());
956 MarkDead();
957 }
958
AnalyzeExpr(const ir::AstNode * node)959 void AssignAnalyzer::AnalyzeExpr(const ir::AstNode *node)
960 {
961 ES2PANDA_ASSERT(node != nullptr);
962 AnalyzeNode(node);
963 if (inits_.IsReset()) {
964 Merge();
965 }
966 }
967
AnalyzeExprs(const ArenaVector<ir::Expression * > & exprs)968 void AssignAnalyzer::AnalyzeExprs(const ArenaVector<ir::Expression *> &exprs)
969 {
970 for (const auto it : exprs) {
971 AnalyzeExpr(it);
972 }
973 }
974
AnalyzeCond(const ir::AstNode * node)975 void AssignAnalyzer::AnalyzeCond(const ir::AstNode *node)
976 {
977 ES2PANDA_ASSERT(node->IsExpression());
978 const ir::Expression *expr = node->AsExpression();
979
980 if (auto etype = expr->TsType();
981 etype != nullptr && etype->IsETSBooleanType() && etype->HasTypeFlag(TypeFlag::CONSTANT)) {
982 const ETSBooleanType *condType = etype->AsETSBooleanType();
983 if (inits_.IsReset()) {
984 Merge();
985 }
986 if (condType->GetValue()) {
987 initsWhenFalse_ = inits_;
988 initsWhenFalse_.InclRange(firstAdr_, nextAdr_);
989 uninitsWhenFalse_ = uninits_;
990 uninitsWhenFalse_.InclRange(firstAdr_, nextAdr_);
991 initsWhenTrue_ = inits_;
992 uninitsWhenTrue_ = uninits_;
993 } else {
994 initsWhenTrue_ = inits_;
995 initsWhenTrue_.InclRange(firstAdr_, nextAdr_);
996 uninitsWhenTrue_ = uninits_;
997 uninitsWhenTrue_.InclRange(firstAdr_, nextAdr_);
998 initsWhenFalse_ = inits_;
999 uninitsWhenFalse_ = uninits_;
1000 }
1001 } else {
1002 AnalyzeNode(node);
1003 if (!inits_.IsReset()) {
1004 Split(true);
1005 }
1006 }
1007
1008 inits_.Reset();
1009 uninits_.Reset();
1010 }
1011
AnalyzeId(const ir::Identifier * id)1012 void AssignAnalyzer::AnalyzeId(const ir::Identifier *id)
1013 {
1014 if (id->Parent()->IsProperty() && id->Parent()->AsProperty()->Key() == id &&
1015 id->Parent()->Parent()->IsObjectExpression()) {
1016 return; // inside ObjectExpression
1017 }
1018
1019 if (id->Parent()->IsBinaryExpression()) {
1020 const ir::BinaryExpression *binExpr = id->Parent()->AsBinaryExpression();
1021 if ((binExpr->OperatorType() == lexer::TokenType::PUNCTUATOR_EQUAL ||
1022 binExpr->OperatorType() == lexer::TokenType::PUNCTUATOR_NOT_EQUAL) &&
1023 (binExpr->Left()->IsNullLiteral() || binExpr->Right()->IsNullLiteral() ||
1024 binExpr->Left()->IsUndefinedLiteral() || binExpr->Right()->IsUndefinedLiteral())) {
1025 return; // null/undefined comparison with == or != operators (e.g. in assert statement)
1026 }
1027 }
1028
1029 if (id->Parent()->IsMemberExpression()) {
1030 const ir::MemberExpression *membExpr = id->Parent()->AsMemberExpression();
1031 if (id == membExpr->Property() && !membExpr->Object()->IsThisExpression() &&
1032 membExpr->HasMemberKind(ir::MemberExpressionKind::PROPERTY_ACCESS)) {
1033 return; // something.property
1034 }
1035 }
1036
1037 CheckInit(id);
1038 }
1039
IsIdentOrThisDotIdent(const ir::AstNode * node)1040 static bool IsIdentOrThisDotIdent(const ir::AstNode *node)
1041 {
1042 return node->IsIdentifier() ||
1043 (node->IsMemberExpression() && node->AsMemberExpression()->Object()->IsThisExpression());
1044 }
1045
AnalyzeAssignExpr(const ir::AssignmentExpression * assignExpr)1046 void AssignAnalyzer::AnalyzeAssignExpr(const ir::AssignmentExpression *assignExpr)
1047 {
1048 if (!IsIdentOrThisDotIdent(assignExpr->Left())) {
1049 AnalyzeExpr(assignExpr->Left());
1050 }
1051
1052 AnalyzeExpr(assignExpr->Right());
1053
1054 if (assignExpr->OperatorType() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) {
1055 LetInit(assignExpr->Left());
1056 } else {
1057 CheckInit(assignExpr->Left());
1058 }
1059 }
1060
AnalyzeCondExpr(const ir::ConditionalExpression * condExpr)1061 void AssignAnalyzer::AnalyzeCondExpr(const ir::ConditionalExpression *condExpr)
1062 {
1063 AnalyzeCond(condExpr->Test());
1064
1065 Set initsBeforeElse = initsWhenFalse_;
1066 Set uninitsBeforeElse = uninitsWhenFalse_;
1067 inits_ = initsWhenTrue_;
1068 uninits_ = uninitsWhenTrue_;
1069
1070 ES2PANDA_ASSERT(condExpr->Consequent()->TsType() && condExpr->Alternate()->TsType());
1071
1072 if (condExpr->Consequent()->TsType()->IsETSBooleanType() && condExpr->Alternate()->TsType()->IsETSBooleanType()) {
1073 AnalyzeCond(condExpr->Consequent());
1074
1075 Set initsAfterThenWhenTrue = initsWhenTrue_;
1076 Set initsAfterThenWhenFalse = initsWhenFalse_;
1077 Set uninitsAfterThenWhenTrue = uninitsWhenTrue_;
1078 Set uninitsAfterThenWhenFalse = uninitsWhenFalse_;
1079 inits_ = std::move(initsBeforeElse);
1080 uninits_ = std::move(uninitsBeforeElse);
1081
1082 AnalyzeCond(condExpr->Alternate());
1083
1084 initsWhenTrue_.AndSet(initsAfterThenWhenTrue);
1085 initsWhenFalse_.AndSet(initsAfterThenWhenFalse);
1086 uninitsWhenTrue_.AndSet(uninitsAfterThenWhenTrue);
1087 uninitsWhenFalse_.AndSet(uninitsAfterThenWhenFalse);
1088 } else {
1089 AnalyzeExpr(condExpr->Consequent());
1090
1091 Set initsAfterThen = inits_;
1092 Set uninitsAfterThen = uninits_;
1093 inits_ = std::move(initsBeforeElse);
1094 uninits_ = std::move(uninitsBeforeElse);
1095
1096 AnalyzeExpr(condExpr->Alternate());
1097
1098 inits_.AndSet(initsAfterThen);
1099 uninits_.AndSet(uninitsAfterThen);
1100 }
1101 }
1102
AnalyzeCallExpr(const ir::CallExpression * callExpr)1103 void AssignAnalyzer::AnalyzeCallExpr(const ir::CallExpression *callExpr)
1104 {
1105 AnalyzeExpr(callExpr->Callee());
1106 AnalyzeExprs(callExpr->Arguments());
1107 }
1108
AnalyzeMemberExpr(const ir::MemberExpression * membExpr)1109 void AssignAnalyzer::AnalyzeMemberExpr(const ir::MemberExpression *membExpr)
1110 {
1111 if (membExpr->Object()->IsThisExpression() && membExpr->HasMemberKind(ir::MemberExpressionKind::PROPERTY_ACCESS)) {
1112 CheckInit(membExpr);
1113 } else {
1114 AnalyzeNode(membExpr->Object());
1115 AnalyzeNode(membExpr->Property());
1116 }
1117 }
1118
AnalyzeNewClass(const ir::ETSNewClassInstanceExpression * newClass)1119 void AssignAnalyzer::AnalyzeNewClass(const ir::ETSNewClassInstanceExpression *newClass)
1120 {
1121 AnalyzeExpr(newClass->GetTypeRef());
1122 AnalyzeExprs(newClass->GetArguments());
1123 }
1124
AnalyzeUnaryExpr(const ir::UnaryExpression * unaryExpr)1125 void AssignAnalyzer::AnalyzeUnaryExpr(const ir::UnaryExpression *unaryExpr)
1126 {
1127 AnalyzeCond(unaryExpr->Argument());
1128
1129 switch (unaryExpr->OperatorType()) {
1130 case lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK: {
1131 Set ti = std::move(initsWhenFalse_);
1132 initsWhenFalse_ = std::move(initsWhenTrue_);
1133 initsWhenTrue_ = std::move(ti);
1134 Set tu = std::move(uninitsWhenFalse_);
1135 uninitsWhenFalse_ = std::move(uninitsWhenTrue_);
1136 uninitsWhenTrue_ = std::move(tu);
1137 break;
1138 }
1139 default: {
1140 AnalyzeExpr(unaryExpr->Argument());
1141 break;
1142 }
1143 }
1144 }
1145
AnalyzeBinaryExpr(const ir::BinaryExpression * binExpr)1146 void AssignAnalyzer::AnalyzeBinaryExpr(const ir::BinaryExpression *binExpr)
1147 {
1148 switch (binExpr->OperatorType()) {
1149 case lexer::TokenType::PUNCTUATOR_LOGICAL_AND: {
1150 AnalyzeCond(binExpr->Left());
1151 Set initsWhenFalseLeft = initsWhenFalse_;
1152 Set uninitsWhenFalseLeft = uninitsWhenFalse_;
1153 inits_ = initsWhenTrue_;
1154 uninits_ = uninitsWhenTrue_;
1155 AnalyzeCond(binExpr->Right());
1156 initsWhenFalse_.AndSet(initsWhenFalseLeft);
1157 uninitsWhenFalse_.AndSet(uninitsWhenFalseLeft);
1158 break;
1159 }
1160 case lexer::TokenType::PUNCTUATOR_LOGICAL_OR: {
1161 AnalyzeCond(binExpr->Left());
1162 Set initsWhenTrueLeft = initsWhenTrue_;
1163 Set uninitsWhenTrueLeft = uninitsWhenTrue_;
1164 inits_ = initsWhenFalse_;
1165 uninits_ = uninitsWhenFalse_;
1166 AnalyzeCond(binExpr->Right());
1167 initsWhenTrue_.AndSet(initsWhenTrueLeft);
1168 uninitsWhenTrue_.AndSet(uninitsWhenTrueLeft);
1169 break;
1170 }
1171 default: {
1172 AnalyzeExpr(binExpr->Left());
1173 AnalyzeExpr(binExpr->Right());
1174 break;
1175 }
1176 }
1177 }
1178
AnalyzeUpdateExpr(const ir::UpdateExpression * updateExpr)1179 void AssignAnalyzer::AnalyzeUpdateExpr(const ir::UpdateExpression *updateExpr)
1180 {
1181 AnalyzeExpr(updateExpr->Argument());
1182 LetInit(updateExpr->Argument());
1183 }
1184
AnalyzeArrowFunctionExpr(const ir::ArrowFunctionExpression * arrowFuncExpr)1185 void AssignAnalyzer::AnalyzeArrowFunctionExpr(const ir::ArrowFunctionExpression *arrowFuncExpr)
1186 {
1187 // NOTE (pantos) handle lamdas correctly
1188 (void)arrowFuncExpr;
1189 }
1190
GetVariableType(const ir::AstNode * node) const1191 util::StringView AssignAnalyzer::GetVariableType(const ir::AstNode *node) const
1192 {
1193 switch (node->Type()) {
1194 case ir::AstNodeType::CLASS_PROPERTY:
1195 if (node->AsClassProperty()->Parent() == globalClass_) {
1196 return "variable";
1197 } else {
1198 return "property";
1199 }
1200 case ir::AstNodeType::VARIABLE_DECLARATOR:
1201 return "variable";
1202 default:
1203 ES2PANDA_UNREACHABLE();
1204 }
1205 }
1206
GetVariableName(const ir::AstNode * node) const1207 util::StringView AssignAnalyzer::GetVariableName(const ir::AstNode *node) const
1208 {
1209 switch (node->Type()) {
1210 case ir::AstNodeType::CLASS_PROPERTY: {
1211 const ir::Identifier *identifier = node->AsClassProperty()->Id();
1212 ES2PANDA_ASSERT(identifier != nullptr);
1213 return identifier->Name();
1214 }
1215 case ir::AstNodeType::VARIABLE_DECLARATOR:
1216 return node->AsVariableDeclarator()->Id()->AsIdentifier()->Name();
1217 default:
1218 ES2PANDA_UNREACHABLE();
1219 }
1220 }
1221
GetVariablePosition(const ir::AstNode * node) const1222 const lexer::SourcePosition &AssignAnalyzer::GetVariablePosition(const ir::AstNode *node) const
1223 {
1224 switch (node->Type()) {
1225 case ir::AstNodeType::CLASS_PROPERTY:
1226 return node->AsClassProperty()->Key()->Start();
1227 case ir::AstNodeType::VARIABLE_DECLARATOR:
1228 default:
1229 return node->Start();
1230 }
1231 }
1232
GetNodeId(const ir::AstNode * node) const1233 NodeId AssignAnalyzer::GetNodeId(const ir::AstNode *node) const
1234 {
1235 auto res = nodeIdMap_.find(node);
1236 if (res != nodeIdMap_.end()) {
1237 return res->second;
1238 }
1239 return INVALID_ID;
1240 }
1241
Trackable(const ir::AstNode * node) const1242 bool AssignAnalyzer::Trackable(const ir::AstNode *node) const
1243 {
1244 switch (node->Type()) {
1245 case ir::AstNodeType::CLASS_PROPERTY:
1246 case ir::AstNodeType::VARIABLE_DECLARATOR:
1247 return true;
1248 default:
1249 return false;
1250 }
1251 }
1252
IsConstUninitializedField(const ir::AstNode * node) const1253 bool AssignAnalyzer::IsConstUninitializedField(const ir::AstNode *node) const
1254 {
1255 return node->IsClassProperty() && node->IsConst();
1256 }
1257
IsConstUninitializedStaticField(const ir::AstNode * node) const1258 bool AssignAnalyzer::IsConstUninitializedStaticField(const ir::AstNode *node) const
1259 {
1260 return IsConstUninitializedField(node) && node->IsStatic();
1261 }
1262
NewVar(const ir::AstNode * node)1263 void AssignAnalyzer::NewVar(const ir::AstNode *node)
1264 {
1265 if (!Trackable(node)) {
1266 return;
1267 }
1268
1269 if (GetNodeId(node) != INVALID_ID) {
1270 return;
1271 }
1272
1273 nodeIdMap_[node] = nextAdr_;
1274 varDecls_.reserve(nextAdr_ + 1);
1275 varDecls_.insert(varDecls_.begin() + nextAdr_, node);
1276 inits_.Excl(nextAdr_);
1277 uninits_.Incl(nextAdr_);
1278 ++nextAdr_;
1279 }
1280
GetBoundVariable(const ir::AstNode * node)1281 varbinder::Variable *AssignAnalyzer::GetBoundVariable(const ir::AstNode *node)
1282 {
1283 varbinder::Variable *ret = nullptr;
1284
1285 if (node->IsClassProperty()) {
1286 const ir::Identifier *identifier = node->AsClassProperty()->Id();
1287 ES2PANDA_ASSERT(identifier != nullptr);
1288 ret = identifier->Variable();
1289 } else if (node->IsVariableDeclarator()) {
1290 ret = node->AsVariableDeclarator()->Id()->AsIdentifier()->Variable();
1291 } else {
1292 ES2PANDA_UNREACHABLE();
1293 }
1294
1295 return ret;
1296 }
1297
CheckInterfaceProp(const ark::es2panda::ir::AstNode * const node,const ir::ClassDefinition * classDef)1298 static const ir::AstNode *CheckInterfaceProp(const ark::es2panda::ir::AstNode *const node,
1299 const ir::ClassDefinition *classDef)
1300 {
1301 util::StringView methodName = node->AsMethodDefinition()->Key()->AsIdentifier()->Name();
1302 // the property from interface should start with <property> to distinguish from its getter/setter.
1303 std::string interfaceProp = std::string("<property>") + std::string(methodName.Utf8());
1304 for (const auto it : classDef->Body()) {
1305 // Check if there is corresponding class property in the same class.
1306 if (it->IsClassProperty() && !it->IsStatic()) {
1307 const auto *prop = it->AsClassProperty();
1308 auto *propIdentifier = prop->Key()->AsIdentifier();
1309 if (propIdentifier->Name().Is(interfaceProp)) {
1310 // Use property node as declNode to ensure obtaining NodeId and add it to inits.
1311 return prop;
1312 }
1313 }
1314 }
1315 return nullptr;
1316 }
1317
GetDeclaringNode(const ir::AstNode * node)1318 const ir::AstNode *AssignAnalyzer::GetDeclaringNode(const ir::AstNode *node)
1319 {
1320 if (node->IsClassProperty() || node->IsVariableDeclarator()) {
1321 return node;
1322 }
1323
1324 const ir::AstNode *ret = nullptr;
1325
1326 if (node->IsMemberExpression()) {
1327 const ir::MemberExpression *membExpr = node->AsMemberExpression();
1328 if (membExpr->PropVar() != nullptr) {
1329 if (membExpr->PropVar()->Declaration() != nullptr) {
1330 ret = membExpr->PropVar()->Declaration()->Node();
1331 }
1332 }
1333 } else if (node->IsIdentifier()) {
1334 if (auto *const variable = node->Variable(); variable != nullptr) {
1335 ret = variable->Declaration()->Node();
1336 }
1337 }
1338
1339 if (ret != nullptr) {
1340 if (ret->IsIdentifier() && ret->Parent()->IsVariableDeclarator() &&
1341 ret == ret->Parent()->AsVariableDeclarator()->Id()) {
1342 ret = ret->Parent();
1343 }
1344 }
1345
1346 if (ret != nullptr) {
1347 // if declNode is a getter/setter method, actual node initialized should be a class proterty node.
1348 if ((ret->Modifiers() & ir::ModifierFlags::GETTER_SETTER) != 0U) {
1349 if (const auto *interfaceProp = CheckInterfaceProp(ret, classDef_); interfaceProp != nullptr) {
1350 ret = interfaceProp;
1351 }
1352 }
1353 }
1354
1355 return ret;
1356 }
1357
IsDefaultValueType(const Type * type,bool isNonReadonlyField)1358 static bool IsDefaultValueType(const Type *type, bool isNonReadonlyField)
1359 {
1360 if (type == nullptr) {
1361 return false;
1362 }
1363 return (type->IsETSPrimitiveType() || type->IsETSNeverType() || type->IsETSUndefinedType() ||
1364 type->IsETSNullType() ||
1365 (type->PossiblyETSUndefined() && (!type->HasTypeFlag(checker::TypeFlag::GENERIC) ||
1366 (isNonReadonlyField && !CHECK_GENERIC_NON_READONLY_PROPERTIES))));
1367 }
1368
VariableHasDefaultValue(const ir::AstNode * node)1369 bool AssignAnalyzer::VariableHasDefaultValue(const ir::AstNode *node)
1370 {
1371 ES2PANDA_ASSERT(node != nullptr);
1372
1373 const checker::Type *type = nullptr;
1374 bool isNonReadonlyField = false;
1375
1376 if (node->IsClassProperty()) {
1377 type = node->AsClassProperty()->TsType();
1378 isNonReadonlyField = !node->IsReadonly(); // NOTE(pantos) readonly is true, const is not set?
1379 } else if (node->IsVariableDeclarator()) {
1380 varbinder::Variable *variable = GetBoundVariable(node);
1381 ES2PANDA_ASSERT(variable != nullptr);
1382 type = variable->TsType();
1383 } else {
1384 ES2PANDA_UNREACHABLE();
1385 }
1386 return IsDefaultValueType(type, isNonReadonlyField);
1387 }
1388
LetInit(const ir::AstNode * node)1389 void AssignAnalyzer::LetInit(const ir::AstNode *node)
1390 {
1391 const ir::AstNode *declNode = GetDeclaringNode(node);
1392
1393 if (declNode == nullptr || declNode->IsDeclare()) {
1394 return;
1395 }
1396
1397 NodeId adr = GetNodeId(declNode);
1398 if (adr == INVALID_ID) {
1399 return;
1400 }
1401
1402 if (node != declNode && declNode->IsConst()) {
1403 // check reassignment of readonly properties
1404 util::StringView type = GetVariableType(declNode);
1405 util::StringView name = GetVariableName(declNode);
1406 const lexer::SourcePosition &pos = GetVariablePosition(node);
1407
1408 auto uninit = [this](NodeId a) {
1409 uninits_.Excl(a);
1410 if (!inits_.IsMember(a)) {
1411 uninitsTry_.Excl(a);
1412 }
1413 };
1414
1415 if (classDef_ == globalClass_ || (adr < classFirstAdr_ || adr >= firstAdr_)) {
1416 if (declNode->IsClassProperty() && classDef_ != declNode->Parent()) {
1417 Warning(diagnostic::ASSIGN_TO_READONLY, {name}, pos);
1418 } else if (!uninits_.IsMember(adr)) {
1419 Warning(diagnostic::MAYBE_REASSIGNED, {Capitalize(type).c_str(), name}, pos);
1420 } else {
1421 uninit(adr);
1422 }
1423 }
1424 }
1425
1426 inits_.Incl(adr);
1427 }
1428
CheckInit(const ir::AstNode * node)1429 void AssignAnalyzer::CheckInit(const ir::AstNode *node)
1430 {
1431 const ir::AstNode *declNode = GetDeclaringNode(node);
1432
1433 if (declNode == nullptr || declNode->IsDeclare()) {
1434 return;
1435 }
1436
1437 NodeId adr = GetNodeId(declNode);
1438 if (adr == INVALID_ID) {
1439 return;
1440 }
1441
1442 if (VariableHasDefaultValue(declNode)) {
1443 // no explicit init is required (primitive, nullish)
1444 return;
1445 }
1446
1447 if (declNode->IsClassProperty()) {
1448 if (!CHECK_ALL_PROPERTIES && !declNode->IsConst()) {
1449 // non readonly property
1450 return;
1451 }
1452
1453 if (declNode->Parent() != classDef_) {
1454 // property of an other class
1455 return;
1456 }
1457
1458 if (node->IsDefinite()) {
1459 return;
1460 }
1461 }
1462
1463 if (classDef_ == globalClass_ || (adr < classFirstAdr_ || adr >= firstAdr_)) {
1464 if (!inits_.IsMember(adr)) {
1465 if (WARN_NO_INIT_ONCE_PER_VARIABLE && !foundErrors_.insert(declNode).second) {
1466 return;
1467 }
1468
1469 util::StringView type = GetVariableType(declNode);
1470 util::StringView name = GetVariableName(declNode);
1471 const lexer::SourcePosition &pos = GetVariablePosition(node);
1472
1473 std::stringstream ss;
1474 if (node->IsClassProperty()) {
1475 checker_->LogError(diagnostic::PROPERTY_MAYBE_MISSING_INIT, {name}, pos);
1476 } else {
1477 checker_->LogError(diagnostic::USE_BEFORE_INIT, {Capitalize(type), name}, pos);
1478 }
1479 }
1480 }
1481 }
1482
Split(const bool setToNull)1483 void AssignAnalyzer::Split(const bool setToNull)
1484 {
1485 initsWhenFalse_ = inits_;
1486 uninitsWhenFalse_ = uninits_;
1487 initsWhenTrue_ = inits_;
1488 uninitsWhenTrue_ = uninits_;
1489 if (setToNull) {
1490 inits_.Reset();
1491 uninits_.Reset();
1492 }
1493 }
1494
Merge()1495 void AssignAnalyzer::Merge()
1496 {
1497 inits_ = initsWhenFalse_.AndSet(initsWhenTrue_);
1498 uninits_ = uninitsWhenFalse_.AndSet(uninitsWhenTrue_);
1499 }
1500
CheckPendingExits()1501 void AssignAnalyzer::CheckPendingExits()
1502 {
1503 for (const auto &it : PendingExits()) {
1504 if (!it.Node()->IsReturnStatement()) {
1505 continue;
1506 }
1507 if (isInitialConstructor_) {
1508 inits_ = it.exitInits_;
1509
1510 for (int i = firstAdr_; i < nextAdr_; i++) {
1511 CheckInit(varDecls_[i]);
1512 }
1513 }
1514 }
1515 ClearPendingExits();
1516 }
1517
MarkDead()1518 void AssignAnalyzer::MarkDead()
1519 {
1520 if (!isInitialConstructor_) {
1521 inits_.InclRange(returnAdr_, nextAdr_);
1522 } else {
1523 for (int address = returnAdr_; address < nextAdr_; address++) {
1524 if (!IsConstUninitializedStaticField(varDecls_[address])) {
1525 inits_.Incl(address);
1526 }
1527 }
1528 }
1529 uninits_.InclRange(returnAdr_, nextAdr_);
1530 }
1531
1532 } // namespace ark::es2panda::checker
1533