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