• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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