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 66namespace ark::es2panda::checker { 67 68static constexpr NodeId INVALID_ID = -1; 69static constexpr bool CHECK_ALL_PROPERTIES = true; 70// NOTE(pantos) generic field initialization issue, skip them for now 71static constexpr bool CHECK_GENERIC_NON_READONLY_PROPERTIES = false; 72static constexpr bool WARN_NO_INIT_ONCE_PER_VARIABLE = false; 73static constexpr int LOOP_PHASES = 2; 74 75template <typename... Ts> 76struct 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 82 explicit ScopeGuard(Ts &...ts) : values(ts...), refs(ts...) {} 83 ~ScopeGuard() 84 { 85 refs = values; 86 } 87 88 DEFAULT_COPY_SEMANTIC(ScopeGuard); 89 DEFAULT_MOVE_SEMANTIC(ScopeGuard); 90}; 91 92static 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 102void Set::Reset() 103{ 104 reset_ = true; 105} 106 107bool Set::IsReset() 108{ 109 return reset_; 110} 111 112void Set::Incl(const int id) 113{ 114 nodes_.insert(id); 115} 116 117void Set::InclRange(const int start, const int limit) 118{ 119 for (int x = start; x < limit; x++) { 120 nodes_.insert(x); 121 } 122} 123 124void Set::Excl(const int id) 125{ 126 nodes_.erase(id); 127} 128 129void Set::ExcludeFrom(const int start) 130{ 131 auto it = nodes_.lower_bound(start); 132 nodes_.erase(nodes_.begin(), it); 133} 134 135bool Set::IsMember(const int id) const 136{ 137 return nodes_.find(id) != nodes_.end(); 138} 139 140Set &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 149Set &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 157Set &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 166int 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 175AssignAnalyzer::AssignAnalyzer(ETSChecker *checker) 176 : checker_(checker), 177 varDecls_(checker->Allocator()->Adapter()), 178 nodeIdMap_(checker->Allocator()->Adapter()), 179 foundErrors_(checker->Allocator()->Adapter()) 180{ 181} 182 183void 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 201void AssignAnalyzer::Warning(const std::string_view message, const lexer::SourcePosition &pos) 202{ 203 ++numErrors_; 204 checker_->Warning(message, pos); 205} 206 207void AssignAnalyzer::Warning(std::initializer_list<TypeErrorMessageElement> list, const lexer::SourcePosition &pos) 208{ 209 ++numErrors_; 210 checker_->ReportWarning(list, pos); 211} 212 213void AssignAnalyzer::AnalyzeNodes(const ir::AstNode *node) 214{ 215 node->Iterate([this](auto *childNode) { AnalyzeNode(childNode); }); 216} 217 218void 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 262bool 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 300bool 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 342bool 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 376bool 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 402void AssignAnalyzer::AnalyzeStat(const ir::AstNode *node) 403{ 404 if (node == nullptr) { 405 return; 406 } 407 408 AnalyzeNode(node); 409} 410 411void AssignAnalyzer::AnalyzeStats(const ArenaVector<ir::Statement *> &stats) 412{ 413 for (const auto it : stats) { 414 AnalyzeStat(it); 415 } 416} 417 418void AssignAnalyzer::AnalyzeBlock(const ir::BlockStatement *blockStmt) 419{ 420 ScopeGuard save(nextAdr_); 421 422 AnalyzeStats(blockStmt->Statements()); 423} 424 425void AssignAnalyzer::AnalyzeStructDecl(const ir::ETSStructDeclaration *structDecl) 426{ 427 AnalyzeNode(structDecl->Definition()); 428} 429 430void AssignAnalyzer::AnalyzeClassDecl(const ir::ClassDeclaration *classDecl) 431{ 432 AnalyzeNode(classDecl->Definition()); 433} 434 435void 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... 490void 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 524void 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 550static 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 573void 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 608void 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 620void 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 658void 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 697void 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 749void 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 791void 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 818void AssignAnalyzer::AnalyzeLabelled(const ir::LabelledStatement *labelledStmt) 819{ 820 SetOldPendingExits(PendingExits()); 821 822 AnalyzeStat(labelledStmt->Body()); 823 824 ResolveBreaks(labelledStmt); 825} 826 827void 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 882void 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 947void AssignAnalyzer::AnalyzeBreak(const ir::BreakStatement *breakStmt) 948{ 949 RecordExit(AssignPendingExit(breakStmt, inits_, uninits_)); 950} 951 952void AssignAnalyzer::AnalyzeContinue(const ir::ContinueStatement *contStmt) 953{ 954 RecordExit(AssignPendingExit(contStmt, inits_, uninits_)); 955} 956 957void AssignAnalyzer::AnalyzeReturn(const ir::ReturnStatement *retStmt) 958{ 959 AnalyzeNode(retStmt->Argument()); 960 RecordExit(AssignPendingExit(retStmt, inits_, uninits_)); 961} 962 963void AssignAnalyzer::AnalyzeThrow(const ir::ThrowStatement *throwStmt) 964{ 965 AnalyzeNode(throwStmt->Argument()); 966 MarkDead(); 967} 968 969void 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 988void AssignAnalyzer::AnalyzeExpr(const ir::AstNode *node) 989{ 990 if (node != nullptr) { 991 AnalyzeNode(node); 992 if (inits_.IsReset()) { 993 Merge(); 994 } 995 } 996} 997 998void AssignAnalyzer::AnalyzeExprs(const ArenaVector<ir::Expression *> &exprs) 999{ 1000 for (const auto it : exprs) { 1001 AnalyzeExpr(it); 1002 } 1003} 1004 1005void 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 1042void 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 1076static bool IsIdentOrThisDotIdent(const ir::AstNode *node) 1077{ 1078 return node->IsIdentifier() || 1079 (node->IsMemberExpression() && node->AsMemberExpression()->Object()->IsThisExpression()); 1080} 1081 1082void 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 1097void 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 1139void AssignAnalyzer::AnalyzeCallExpr(const ir::CallExpression *callExpr) 1140{ 1141 AnalyzeExpr(callExpr->Callee()); 1142 AnalyzeExprs(callExpr->Arguments()); 1143} 1144 1145void 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 1155void AssignAnalyzer::AnalyzeNewClass(const ir::ETSNewClassInstanceExpression *newClass) 1156{ 1157 AnalyzeExpr(newClass->GetTypeRef()); 1158 AnalyzeExprs(newClass->GetArguments()); 1159 AnalyzeNode(newClass->ClassDefinition()); 1160} 1161 1162void 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 1183void 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 1216void AssignAnalyzer::AnalyzeUpdateExpr(const ir::UpdateExpression *updateExpr) 1217{ 1218 AnalyzeExpr(updateExpr->Argument()); 1219 LetInit(updateExpr->Argument()); 1220} 1221 1222void AssignAnalyzer::AnalyzeArrowFunctionExpr(const ir::ArrowFunctionExpression *arrowFuncExpr) 1223{ 1224 // NOTE (pantos) handle lamdas correctly 1225 (void)arrowFuncExpr; 1226} 1227 1228util::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 1244util::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 1256const 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 1267NodeId 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 1276bool 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 1287bool AssignAnalyzer::IsConstUninitializedField(const ir::AstNode *node) const 1288{ 1289 return node->IsClassProperty() && node->IsConst(); 1290} 1291 1292bool AssignAnalyzer::IsConstUninitializedStaticField(const ir::AstNode *node) const 1293{ 1294 return IsConstUninitializedField(node) && node->IsStatic(); 1295} 1296 1297void 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 1315varbinder::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 1330const 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 1364bool 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 1389void 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 1429void 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 1486void 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 1498void AssignAnalyzer::Merge() 1499{ 1500 inits_ = initsWhenFalse_.AndSet(initsWhenTrue_); 1501 uninits_ = uninitsWhenFalse_.AndSet(uninitsWhenTrue_); 1502} 1503 1504void 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 1526void 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