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