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