< prev index next >

src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java

Print this page
rev 52490 : imported patch 8212982b2


 340             JCTree tree;
 341 
 342             PendingExit(JCTree tree) {
 343                 this.tree = tree;
 344             }
 345 
 346             void resolveJump() {
 347                 //do nothing
 348             }
 349         }
 350 
 351         abstract void markDead();
 352 
 353         /** Record an outward transfer of control. */
 354         void recordExit(P pe) {
 355             pendingExits.append(pe);
 356             markDead();
 357         }
 358 
 359         /** Resolve all jumps of this statement. */
 360         private boolean resolveJump(JCTree tree,
 361                         ListBuffer<P> oldPendingExits,
 362                         JumpKind jk) {
 363             boolean resolved = false;
 364             List<P> exits = pendingExits.toList();
 365             pendingExits = oldPendingExits;
 366             for (; exits.nonEmpty(); exits = exits.tail) {
 367                 P exit = exits.head;
 368                 if (exit.tree.hasTag(jk.treeTag) &&
 369                         jk.getTarget(exit.tree) == tree) {
 370                     exit.resolveJump();
 371                     resolved = true;
 372                 } else {
 373                     pendingExits.append(exit);
 374                 }
 375             }
 376             return resolved;
 377         }
 378 
 379         /** Resolve all continues of this statement. */
 380         boolean resolveContinues(JCTree tree) {
 381             return resolveJump(tree, new ListBuffer<P>(), JumpKind.CONTINUE);
 382         }
 383 
 384         /** Resolve all breaks of this statement. */
 385         boolean resolveBreaks(JCTree tree, ListBuffer<P> oldPendingExits) {
 386             return resolveJump(tree, oldPendingExits, JumpKind.BREAK);
 387         }
 388 
 389         @Override
 390         public void scan(JCTree tree) {
 391             if (tree != null && (
 392                     tree.type == null ||
 393                     tree.type != Type.stuckType)) {
 394                 super.scan(tree);
 395             }
 396         }
 397 
 398         public void visitPackageDef(JCPackageDecl tree) {
 399             // Do nothing for PackageDecl
 400         }
 401 
 402         protected void scanSyntheticBreak(TreeMaker make, JCTree swtch) {
 403             JCBreak brk = make.at(Position.NOPOS).Break(null);
 404             brk.target = swtch;
 405             scan(brk);
 406         }
 407     }
 408 
 409     /**
 410      * This pass implements the first step of the dataflow analysis, namely
 411      * the liveness analysis check. This checks that every statement is reachable.
 412      * The output of this analysis pass are used by other analyzers. This analyzer
 413      * sets the 'finallyCanCompleteNormally' field in the JCTry class.
 414      */
 415     class AliveAnalyzer extends BaseAnalyzer<BaseAnalyzer.PendingExit> {
 416 
 417         /** A flag that indicates whether the last statement could
 418          *  complete normally.
 419          */
 420         private boolean alive;
 421 
 422         @Override
 423         void markDead() {
 424             alive = false;
 425         }
 426 
 427     /*************************************************************************
 428      * Visitor methods for statements and definitions
 429      *************************************************************************/
 430 
 431         /** Analyze a definition.
 432          */
 433         void scanDef(JCTree tree) {
 434             scanStat(tree);
 435             if (tree != null && tree.hasTag(JCTree.Tag.BLOCK) && !alive) {
 436                 log.error(tree.pos(),
 437                           Errors.InitializerMustBeAbleToCompleteNormally);
 438             }
 439         }
 440 
 441         /** Analyze a statement. Check that statement is reachable.
 442          */
 443         void scanStat(JCTree tree) {
 444             if (!alive && tree != null) {
 445                 log.error(tree.pos(), Errors.UnreachableStmt);
 446                 if (!tree.hasTag(SKIP)) alive = true;
 447             }
 448             scan(tree);
 449         }
 450 
 451         /** Analyze list of statements.
 452          */
 453         void scanStats(List<? extends JCStatement> trees) {
 454             if (trees != null)
 455                 for (List<? extends JCStatement> l = trees; l.nonEmpty(); l = l.tail)
 456                     scanStat(l.head);
 457         }
 458 
 459         /* ------------ Visitor methods for various sorts of trees -------------*/
 460 
 461         public void visitClassDef(JCClassDecl tree) {
 462             if (tree.sym == null) return;
 463             boolean alivePrev = alive;
 464             ListBuffer<PendingExit> pendingExitsPrev = pendingExits;
 465             Lint lintPrev = lint;
 466 
 467             pendingExits = new ListBuffer<>();
 468             lint = lint.augment(tree.sym);
 469 
 470             try {
 471                 // process all the static initializers
 472                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
 473                     if (!l.head.hasTag(METHODDEF) &&
 474                         (TreeInfo.flags(l.head) & STATIC) != 0) {
 475                         scanDef(l.head);
 476                     }
 477                 }
 478 
 479                 // process all the instance initializers
 480                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
 481                     if (!l.head.hasTag(METHODDEF) &&
 482                         (TreeInfo.flags(l.head) & STATIC) == 0) {
 483                         scanDef(l.head);


 489                     if (l.head.hasTag(METHODDEF)) {
 490                         scan(l.head);
 491                     }
 492                 }
 493             } finally {
 494                 pendingExits = pendingExitsPrev;
 495                 alive = alivePrev;
 496                 lint = lintPrev;
 497             }
 498         }
 499 
 500         public void visitMethodDef(JCMethodDecl tree) {
 501             if (tree.body == null) return;
 502             Lint lintPrev = lint;
 503 
 504             lint = lint.augment(tree.sym);
 505 
 506             Assert.check(pendingExits.isEmpty());
 507 
 508             try {
 509                 alive = true;
 510                 scanStat(tree.body);
 511 
 512                 if (alive && !tree.sym.type.getReturnType().hasTag(VOID))
 513                     log.error(TreeInfo.diagEndPos(tree.body), Errors.MissingRetStmt);
 514 
 515                 List<PendingExit> exits = pendingExits.toList();
 516                 pendingExits = new ListBuffer<>();
 517                 while (exits.nonEmpty()) {
 518                     PendingExit exit = exits.head;
 519                     exits = exits.tail;
 520                     Assert.check(exit.tree.hasTag(RETURN));
 521                 }
 522             } finally {
 523                 lint = lintPrev;
 524             }
 525         }
 526 
 527         public void visitVarDef(JCVariableDecl tree) {
 528             if (tree.init != null) {
 529                 Lint lintPrev = lint;
 530                 lint = lint.augment(tree.sym);
 531                 try{
 532                     scan(tree.init);
 533                 } finally {
 534                     lint = lintPrev;
 535                 }
 536             }
 537         }
 538 
 539         public void visitBlock(JCBlock tree) {
 540             scanStats(tree.stats);
 541         }
 542 
 543         public void visitDoLoop(JCDoWhileLoop tree) {
 544             ListBuffer<PendingExit> prevPendingExits = pendingExits;
 545             pendingExits = new ListBuffer<>();
 546             scanStat(tree.body);
 547             alive |= resolveContinues(tree);
 548             scan(tree.cond);
 549             alive = alive && !tree.cond.type.isTrue();
 550             alive |= resolveBreaks(tree, prevPendingExits);
 551         }
 552 
 553         public void visitWhileLoop(JCWhileLoop tree) {
 554             ListBuffer<PendingExit> prevPendingExits = pendingExits;
 555             pendingExits = new ListBuffer<>();
 556             scan(tree.cond);
 557             alive = !tree.cond.type.isFalse();
 558             scanStat(tree.body);
 559             alive |= resolveContinues(tree);
 560             alive = resolveBreaks(tree, prevPendingExits) ||
 561                 !tree.cond.type.isTrue();
 562         }
 563 
 564         public void visitForLoop(JCForLoop tree) {
 565             ListBuffer<PendingExit> prevPendingExits = pendingExits;
 566             scanStats(tree.init);
 567             pendingExits = new ListBuffer<>();
 568             if (tree.cond != null) {
 569                 scan(tree.cond);
 570                 alive = !tree.cond.type.isFalse();
 571             } else {
 572                 alive = true;
 573             }
 574             scanStat(tree.body);
 575             alive |= resolveContinues(tree);
 576             scan(tree.step);
 577             alive = resolveBreaks(tree, prevPendingExits) ||
 578                 tree.cond != null && !tree.cond.type.isTrue();
 579         }
 580 
 581         public void visitForeachLoop(JCEnhancedForLoop tree) {
 582             visitVarDef(tree.var);
 583             ListBuffer<PendingExit> prevPendingExits = pendingExits;
 584             scan(tree.expr);
 585             pendingExits = new ListBuffer<>();
 586             scanStat(tree.body);
 587             alive |= resolveContinues(tree);
 588             resolveBreaks(tree, prevPendingExits);
 589             alive = true;
 590         }
 591 
 592         public void visitLabelled(JCLabeledStatement tree) {
 593             ListBuffer<PendingExit> prevPendingExits = pendingExits;
 594             pendingExits = new ListBuffer<>();
 595             scanStat(tree.body);
 596             alive |= resolveBreaks(tree, prevPendingExits);
 597         }
 598 
 599         public void visitSwitch(JCSwitch tree) {
 600             ListBuffer<PendingExit> prevPendingExits = pendingExits;
 601             pendingExits = new ListBuffer<>();
 602             scan(tree.selector);
 603             boolean hasDefault = false;
 604             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
 605                 alive = true;
 606                 JCCase c = l.head;
 607                 if (c.pats.isEmpty())
 608                     hasDefault = true;
 609                 else {
 610                     for (JCExpression pat : c.pats) {
 611                         scan(pat);
 612                     }
 613                 }
 614                 scanStats(c.stats);
 615                 c.completesNormally = alive;
 616                 if (alive && c.caseKind == JCCase.RULE) {
 617                     scanSyntheticBreak(make, tree);
 618                     alive = false;
 619                 }
 620                 // Warn about fall-through if lint switch fallthrough enabled.
 621                 if (alive &&
 622                     lint.isEnabled(Lint.LintCategory.FALLTHROUGH) &&
 623                     c.stats.nonEmpty() && l.tail.nonEmpty())
 624                     log.warning(Lint.LintCategory.FALLTHROUGH,
 625                                 l.tail.head.pos(),
 626                                 Warnings.PossibleFallThroughIntoCase);
 627             }
 628             if (!hasDefault) {
 629                 alive = true;
 630             }
 631             alive |= resolveBreaks(tree, prevPendingExits);
 632         }
 633 
 634         @Override
 635         public void visitSwitchExpression(JCSwitchExpression tree) {
 636             ListBuffer<PendingExit> prevPendingExits = pendingExits;
 637             pendingExits = new ListBuffer<>();
 638             scan(tree.selector);
 639             Set<Object> constants = null;
 640             if ((tree.selector.type.tsym.flags() & ENUM) != 0) {
 641                 constants = new HashSet<>();
 642                 for (Symbol s : tree.selector.type.tsym.members().getSymbols(s -> (s.flags() & ENUM) != 0)) {
 643                     constants.add(s.name);
 644                 }
 645             }
 646             boolean hasDefault = false;
 647             boolean prevAlive = alive;
 648             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
 649                 alive = true;
 650                 JCCase c = l.head;
 651                 if (c.pats.isEmpty())
 652                     hasDefault = true;
 653                 else {
 654                     for (JCExpression pat : c.pats) {
 655                         scan(pat);
 656                         if (constants != null) {
 657                             if (pat.hasTag(IDENT))
 658                                 constants.remove(((JCIdent) pat).name);
 659                             if (pat.type != null)
 660                                 constants.remove(pat.type.constValue());
 661                         }
 662                     }
 663                 }
 664                 scanStats(c.stats);
 665                 c.completesNormally = alive;









 666             }
 667             if ((constants == null || !constants.isEmpty()) && !hasDefault) {
 668                 log.error(tree, Errors.NotExhaustive);
 669             }
 670             alive = prevAlive;
 671             alive |= resolveBreaks(tree, prevPendingExits);
 672         }
 673 
 674         public void visitTry(JCTry tree) {
 675             ListBuffer<PendingExit> prevPendingExits = pendingExits;
 676             pendingExits = new ListBuffer<>();
 677             for (JCTree resource : tree.resources) {
 678                 if (resource instanceof JCVariableDecl) {
 679                     JCVariableDecl vdecl = (JCVariableDecl) resource;
 680                     visitVarDef(vdecl);
 681                 } else if (resource instanceof JCExpression) {
 682                     scan((JCExpression) resource);
 683                 } else {
 684                     throw new AssertionError(tree);  // parser error
 685                 }
 686             }
 687 
 688             scanStat(tree.body);
 689             boolean aliveEnd = alive;
 690 
 691             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
 692                 alive = true;
 693                 JCVariableDecl param = l.head.param;
 694                 scan(param);
 695                 scanStat(l.head.body);
 696                 aliveEnd |= alive;
 697             }
 698             if (tree.finalizer != null) {
 699                 ListBuffer<PendingExit> exits = pendingExits;
 700                 pendingExits = prevPendingExits;
 701                 alive = true;
 702                 scanStat(tree.finalizer);
 703                 tree.finallyCanCompleteNormally = alive;
 704                 if (!alive) {
 705                     if (lint.isEnabled(Lint.LintCategory.FINALLY)) {
 706                         log.warning(Lint.LintCategory.FINALLY,
 707                                 TreeInfo.diagEndPos(tree.finalizer),
 708                                 Warnings.FinallyCannotComplete);
 709                     }
 710                 } else {
 711                     while (exits.nonEmpty()) {
 712                         pendingExits.append(exits.next());
 713                     }
 714                     alive = aliveEnd;
 715                 }
 716             } else {
 717                 alive = aliveEnd;
 718                 ListBuffer<PendingExit> exits = pendingExits;
 719                 pendingExits = prevPendingExits;
 720                 while (exits.nonEmpty()) pendingExits.append(exits.next());
 721             }
 722         }
 723 
 724         @Override
 725         public void visitIf(JCIf tree) {
 726             scan(tree.cond);
 727             scanStat(tree.thenpart);
 728             if (tree.elsepart != null) {
 729                 boolean aliveAfterThen = alive;
 730                 alive = true;
 731                 scanStat(tree.elsepart);
 732                 alive = alive | aliveAfterThen;
 733             } else {
 734                 alive = true;
 735             }
 736         }
 737 
 738         public void visitBreak(JCBreak tree) {
 739             if (tree.isValueBreak())
 740                 scan(tree.value);
 741             recordExit(new PendingExit(tree));
 742         }
 743 
 744         public void visitContinue(JCContinue tree) {
 745             recordExit(new PendingExit(tree));
 746         }
 747 
 748         public void visitReturn(JCReturn tree) {
 749             scan(tree.expr);
 750             recordExit(new PendingExit(tree));
 751         }
 752 
 753         public void visitThrow(JCThrow tree) {
 754             scan(tree.expr);


 759             scan(tree.meth);
 760             scan(tree.args);
 761         }
 762 
 763         public void visitNewClass(JCNewClass tree) {
 764             scan(tree.encl);
 765             scan(tree.args);
 766             if (tree.def != null) {
 767                 scan(tree.def);
 768             }
 769         }
 770 
 771         @Override
 772         public void visitLambda(JCLambda tree) {
 773             if (tree.type != null &&
 774                     tree.type.isErroneous()) {
 775                 return;
 776             }
 777 
 778             ListBuffer<PendingExit> prevPending = pendingExits;
 779             boolean prevAlive = alive;
 780             try {
 781                 pendingExits = new ListBuffer<>();
 782                 alive = true;
 783                 scanStat(tree.body);
 784                 tree.canCompleteNormally = alive;
 785             }
 786             finally {
 787                 pendingExits = prevPending;
 788                 alive = prevAlive;
 789             }
 790         }
 791 
 792         public void visitModuleDef(JCModuleDecl tree) {
 793             // Do nothing for modules
 794         }
 795 
 796     /**************************************************************************
 797      * main method
 798      *************************************************************************/
 799 
 800         /** Perform definite assignment/unassignment analysis on a tree.
 801          */
 802         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
 803             analyzeTree(env, env.tree, make);
 804         }
 805         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
 806             try {
 807                 attrEnv = env;
 808                 Flow.this.make = make;
 809                 pendingExits = new ListBuffer<>();
 810                 alive = true;
 811                 scan(tree);
 812             } finally {
 813                 pendingExits = null;
 814                 Flow.this.make = null;
 815             }
 816         }
 817     }
 818 
 819     /**
 820      * This pass implements the second step of the dataflow analysis, namely
 821      * the exception analysis. This is to ensure that every checked exception that is
 822      * thrown is declared or caught. The analyzer uses some info that has been set by
 823      * the liveliness analyzer.
 824      */
 825     class FlowAnalyzer extends BaseAnalyzer<FlowAnalyzer.FlowPendingExit> {
 826 
 827         /** A flag that indicates whether the last statement could
 828          *  complete normally.
 829          */
 830         HashMap<Symbol, List<Type>> preciseRethrowTypes;


2759      * main method
2760      *************************************************************************/
2761 
2762         /** Perform definite assignment/unassignment analysis on a tree.
2763          */
2764         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
2765             analyzeTree(env, env.tree, make);
2766         }
2767         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
2768             try {
2769                 attrEnv = env;
2770                 Flow.this.make = make;
2771                 pendingExits = new ListBuffer<>();
2772                 scan(tree);
2773             } finally {
2774                 pendingExits = null;
2775                 Flow.this.make = null;
2776             }
2777         }
2778     }




























































2779 }


 340             JCTree tree;
 341 
 342             PendingExit(JCTree tree) {
 343                 this.tree = tree;
 344             }
 345 
 346             void resolveJump() {
 347                 //do nothing
 348             }
 349         }
 350 
 351         abstract void markDead();
 352 
 353         /** Record an outward transfer of control. */
 354         void recordExit(P pe) {
 355             pendingExits.append(pe);
 356             markDead();
 357         }
 358 
 359         /** Resolve all jumps of this statement. */
 360         private Liveness resolveJump(JCTree tree,
 361                          ListBuffer<P> oldPendingExits,
 362                          JumpKind jk) {
 363             boolean resolved = false;
 364             List<P> exits = pendingExits.toList();
 365             pendingExits = oldPendingExits;
 366             for (; exits.nonEmpty(); exits = exits.tail) {
 367                 P exit = exits.head;
 368                 if (exit.tree.hasTag(jk.treeTag) &&
 369                         jk.getTarget(exit.tree) == tree) {
 370                     exit.resolveJump();
 371                     resolved = true;
 372                 } else {
 373                     pendingExits.append(exit);
 374                 }
 375             }
 376             return Liveness.from(resolved);
 377         }
 378 
 379         /** Resolve all continues of this statement. */
 380         Liveness resolveContinues(JCTree tree) {
 381             return resolveJump(tree, new ListBuffer<P>(), JumpKind.CONTINUE);
 382         }
 383 
 384         /** Resolve all breaks of this statement. */
 385         Liveness resolveBreaks(JCTree tree, ListBuffer<P> oldPendingExits) {
 386             return resolveJump(tree, oldPendingExits, JumpKind.BREAK);
 387         }
 388 
 389         @Override
 390         public void scan(JCTree tree) {
 391             if (tree != null && (
 392                     tree.type == null ||
 393                     tree.type != Type.stuckType)) {
 394                 super.scan(tree);
 395             }
 396         }
 397 
 398         public void visitPackageDef(JCPackageDecl tree) {
 399             // Do nothing for PackageDecl
 400         }
 401 
 402         protected void scanSyntheticBreak(TreeMaker make, JCTree swtch) {
 403             JCBreak brk = make.at(Position.NOPOS).Break(null);
 404             brk.target = swtch;
 405             scan(brk);
 406         }
 407     }
 408 
 409     /**
 410      * This pass implements the first step of the dataflow analysis, namely
 411      * the liveness analysis check. This checks that every statement is reachable.
 412      * The output of this analysis pass are used by other analyzers. This analyzer
 413      * sets the 'finallyCanCompleteNormally' field in the JCTry class.
 414      */
 415     class AliveAnalyzer extends BaseAnalyzer<BaseAnalyzer.PendingExit> {
 416 
 417         /** A flag that indicates whether the last statement could
 418          *  complete normally.
 419          */
 420         private Liveness alive;
 421 
 422         @Override
 423         void markDead() {
 424             alive = Liveness.NOT_ALIVE;
 425         }
 426 
 427     /*************************************************************************
 428      * Visitor methods for statements and definitions
 429      *************************************************************************/
 430 
 431         /** Analyze a definition.
 432          */
 433         void scanDef(JCTree tree) {
 434             scanStat(tree);
 435             if (tree != null && tree.hasTag(JCTree.Tag.BLOCK) && !alive.alive) {
 436                 log.error(tree.pos(),
 437                           Errors.InitializerMustBeAbleToCompleteNormally);
 438             }
 439         }
 440 
 441         /** Analyze a statement. Check that statement is reachable.
 442          */
 443         void scanStat(JCTree tree) {
 444             if (!alive.alive && tree != null) {
 445                 log.error(tree.pos(), Errors.UnreachableStmt);
 446                 if (!tree.hasTag(SKIP)) alive = Liveness.RECOVERY;
 447             }
 448             scan(tree);
 449         }
 450 
 451         /** Analyze list of statements.
 452          */
 453         void scanStats(List<? extends JCStatement> trees) {
 454             if (trees != null)
 455                 for (List<? extends JCStatement> l = trees; l.nonEmpty(); l = l.tail)
 456                     scanStat(l.head);
 457         }
 458 
 459         /* ------------ Visitor methods for various sorts of trees -------------*/
 460 
 461         public void visitClassDef(JCClassDecl tree) {
 462             if (tree.sym == null) return;
 463             Liveness alivePrev = alive;
 464             ListBuffer<PendingExit> pendingExitsPrev = pendingExits;
 465             Lint lintPrev = lint;
 466 
 467             pendingExits = new ListBuffer<>();
 468             lint = lint.augment(tree.sym);
 469 
 470             try {
 471                 // process all the static initializers
 472                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
 473                     if (!l.head.hasTag(METHODDEF) &&
 474                         (TreeInfo.flags(l.head) & STATIC) != 0) {
 475                         scanDef(l.head);
 476                     }
 477                 }
 478 
 479                 // process all the instance initializers
 480                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
 481                     if (!l.head.hasTag(METHODDEF) &&
 482                         (TreeInfo.flags(l.head) & STATIC) == 0) {
 483                         scanDef(l.head);


 489                     if (l.head.hasTag(METHODDEF)) {
 490                         scan(l.head);
 491                     }
 492                 }
 493             } finally {
 494                 pendingExits = pendingExitsPrev;
 495                 alive = alivePrev;
 496                 lint = lintPrev;
 497             }
 498         }
 499 
 500         public void visitMethodDef(JCMethodDecl tree) {
 501             if (tree.body == null) return;
 502             Lint lintPrev = lint;
 503 
 504             lint = lint.augment(tree.sym);
 505 
 506             Assert.check(pendingExits.isEmpty());
 507 
 508             try {
 509                 alive = Liveness.ALIVE;
 510                 scanStat(tree.body);
 511 
 512                 if (alive.alive && !tree.sym.type.getReturnType().hasTag(VOID))
 513                     log.error(TreeInfo.diagEndPos(tree.body), Errors.MissingRetStmt);
 514 
 515                 List<PendingExit> exits = pendingExits.toList();
 516                 pendingExits = new ListBuffer<>();
 517                 while (exits.nonEmpty()) {
 518                     PendingExit exit = exits.head;
 519                     exits = exits.tail;
 520                     Assert.check(exit.tree.hasTag(RETURN));
 521                 }
 522             } finally {
 523                 lint = lintPrev;
 524             }
 525         }
 526 
 527         public void visitVarDef(JCVariableDecl tree) {
 528             if (tree.init != null) {
 529                 Lint lintPrev = lint;
 530                 lint = lint.augment(tree.sym);
 531                 try{
 532                     scan(tree.init);
 533                 } finally {
 534                     lint = lintPrev;
 535                 }
 536             }
 537         }
 538 
 539         public void visitBlock(JCBlock tree) {
 540             scanStats(tree.stats);
 541         }
 542 
 543         public void visitDoLoop(JCDoWhileLoop tree) {
 544             ListBuffer<PendingExit> prevPendingExits = pendingExits;
 545             pendingExits = new ListBuffer<>();
 546             scanStat(tree.body);
 547             alive = alive.or(resolveContinues(tree));
 548             scan(tree.cond);
 549             alive = alive.and(!tree.cond.type.isTrue());
 550             alive = alive.or(resolveBreaks(tree, prevPendingExits));
 551         }
 552 
 553         public void visitWhileLoop(JCWhileLoop tree) {
 554             ListBuffer<PendingExit> prevPendingExits = pendingExits;
 555             pendingExits = new ListBuffer<>();
 556             scan(tree.cond);
 557             alive = Liveness.from(!tree.cond.type.isFalse());
 558             scanStat(tree.body);
 559             alive = alive.or(resolveContinues(tree));
 560             alive = resolveBreaks(tree, prevPendingExits).or(
 561                 !tree.cond.type.isTrue());
 562         }
 563 
 564         public void visitForLoop(JCForLoop tree) {
 565             ListBuffer<PendingExit> prevPendingExits = pendingExits;
 566             scanStats(tree.init);
 567             pendingExits = new ListBuffer<>();
 568             if (tree.cond != null) {
 569                 scan(tree.cond);
 570                 alive = Liveness.from(!tree.cond.type.isFalse());
 571             } else {
 572                 alive = Liveness.ALIVE;
 573             }
 574             scanStat(tree.body);
 575             alive = alive.or(resolveContinues(tree));
 576             scan(tree.step);
 577             alive = resolveBreaks(tree, prevPendingExits).or(
 578                 tree.cond != null && !tree.cond.type.isTrue());
 579         }
 580 
 581         public void visitForeachLoop(JCEnhancedForLoop tree) {
 582             visitVarDef(tree.var);
 583             ListBuffer<PendingExit> prevPendingExits = pendingExits;
 584             scan(tree.expr);
 585             pendingExits = new ListBuffer<>();
 586             scanStat(tree.body);
 587             alive = alive.or(resolveContinues(tree));
 588             resolveBreaks(tree, prevPendingExits);
 589             alive = Liveness.ALIVE;
 590         }
 591 
 592         public void visitLabelled(JCLabeledStatement tree) {
 593             ListBuffer<PendingExit> prevPendingExits = pendingExits;
 594             pendingExits = new ListBuffer<>();
 595             scanStat(tree.body);
 596             alive = alive.or(resolveBreaks(tree, prevPendingExits));
 597         }
 598 
 599         public void visitSwitch(JCSwitch tree) {
 600             ListBuffer<PendingExit> prevPendingExits = pendingExits;
 601             pendingExits = new ListBuffer<>();
 602             scan(tree.selector);
 603             boolean hasDefault = false;
 604             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
 605                 alive = Liveness.ALIVE;
 606                 JCCase c = l.head;
 607                 if (c.pats.isEmpty())
 608                     hasDefault = true;
 609                 else {
 610                     for (JCExpression pat : c.pats) {
 611                         scan(pat);
 612                     }
 613                 }
 614                 scanStats(c.stats);
 615                 c.completesNormally = alive.alive;
 616                 if (alive.alive && c.caseKind == JCCase.RULE) {
 617                     scanSyntheticBreak(make, tree);
 618                     alive = Liveness.NOT_ALIVE;
 619                 }
 620                 // Warn about fall-through if lint switch fallthrough enabled.
 621                 if (alive == Liveness.ALIVE &&
 622                     lint.isEnabled(Lint.LintCategory.FALLTHROUGH) &&
 623                     c.stats.nonEmpty() && l.tail.nonEmpty())
 624                     log.warning(Lint.LintCategory.FALLTHROUGH,
 625                                 l.tail.head.pos(),
 626                                 Warnings.PossibleFallThroughIntoCase);
 627             }
 628             if (!hasDefault) {
 629                 alive = Liveness.ALIVE;
 630             }
 631             alive = alive.or(resolveBreaks(tree, prevPendingExits));
 632         }
 633 
 634         @Override
 635         public void visitSwitchExpression(JCSwitchExpression tree) {
 636             ListBuffer<PendingExit> prevPendingExits = pendingExits;
 637             pendingExits = new ListBuffer<>();
 638             scan(tree.selector);
 639             Set<Object> constants = null;
 640             if ((tree.selector.type.tsym.flags() & ENUM) != 0) {
 641                 constants = new HashSet<>();
 642                 for (Symbol s : tree.selector.type.tsym.members().getSymbols(s -> (s.flags() & ENUM) != 0)) {
 643                     constants.add(s.name);
 644                 }
 645             }
 646             boolean hasDefault = false;
 647             Liveness prevAlive = alive;
 648             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
 649                 alive = Liveness.ALIVE;
 650                 JCCase c = l.head;
 651                 if (c.pats.isEmpty())
 652                     hasDefault = true;
 653                 else {
 654                     for (JCExpression pat : c.pats) {
 655                         scan(pat);
 656                         if (constants != null) {
 657                             if (pat.hasTag(IDENT))
 658                                 constants.remove(((JCIdent) pat).name);
 659                             if (pat.type != null)
 660                                 constants.remove(pat.type.constValue());
 661                         }
 662                     }
 663                 }
 664                 scanStats(c.stats);
 665                 if (alive == Liveness.ALIVE) {
 666                     if (c.caseKind == JCCase.RULE) {
 667                         log.error(TreeInfo.diagEndPos(c.body),
 668                                   Errors.RuleCompletesNormally);
 669                     } else if (l.tail.isEmpty()) {
 670                         log.error(TreeInfo.diagEndPos(tree),
 671                                   Errors.SwitchExpressionCompletesNormally);
 672                     }
 673                 }
 674                 c.completesNormally = alive.alive;
 675             }
 676             if ((constants == null || !constants.isEmpty()) && !hasDefault) {
 677                 log.error(tree, Errors.NotExhaustive);
 678             }
 679             alive = prevAlive;
 680             alive = alive.or(resolveBreaks(tree, prevPendingExits));
 681         }
 682 
 683         public void visitTry(JCTry tree) {
 684             ListBuffer<PendingExit> prevPendingExits = pendingExits;
 685             pendingExits = new ListBuffer<>();
 686             for (JCTree resource : tree.resources) {
 687                 if (resource instanceof JCVariableDecl) {
 688                     JCVariableDecl vdecl = (JCVariableDecl) resource;
 689                     visitVarDef(vdecl);
 690                 } else if (resource instanceof JCExpression) {
 691                     scan((JCExpression) resource);
 692                 } else {
 693                     throw new AssertionError(tree);  // parser error
 694                 }
 695             }
 696 
 697             scanStat(tree.body);
 698             Liveness aliveEnd = alive;
 699 
 700             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
 701                 alive = Liveness.ALIVE;
 702                 JCVariableDecl param = l.head.param;
 703                 scan(param);
 704                 scanStat(l.head.body);
 705                 aliveEnd = aliveEnd.or(alive);
 706             }
 707             if (tree.finalizer != null) {
 708                 ListBuffer<PendingExit> exits = pendingExits;
 709                 pendingExits = prevPendingExits;
 710                 alive = Liveness.ALIVE;
 711                 scanStat(tree.finalizer);
 712                 tree.finallyCanCompleteNormally = alive.alive;
 713                 if (!alive.alive) {
 714                     if (lint.isEnabled(Lint.LintCategory.FINALLY)) {
 715                         log.warning(Lint.LintCategory.FINALLY,
 716                                 TreeInfo.diagEndPos(tree.finalizer),
 717                                 Warnings.FinallyCannotComplete);
 718                     }
 719                 } else {
 720                     while (exits.nonEmpty()) {
 721                         pendingExits.append(exits.next());
 722                     }
 723                     alive = aliveEnd;
 724                 }
 725             } else {
 726                 alive = aliveEnd;
 727                 ListBuffer<PendingExit> exits = pendingExits;
 728                 pendingExits = prevPendingExits;
 729                 while (exits.nonEmpty()) pendingExits.append(exits.next());
 730             }
 731         }
 732 
 733         @Override
 734         public void visitIf(JCIf tree) {
 735             scan(tree.cond);
 736             scanStat(tree.thenpart);
 737             if (tree.elsepart != null) {
 738                 Liveness aliveAfterThen = alive;
 739                 alive = Liveness.ALIVE;
 740                 scanStat(tree.elsepart);
 741                 alive = alive.or(aliveAfterThen);
 742             } else {
 743                 alive = Liveness.ALIVE;
 744             }
 745         }
 746 
 747         public void visitBreak(JCBreak tree) {
 748             if (tree.isValueBreak())
 749                 scan(tree.value);
 750             recordExit(new PendingExit(tree));
 751         }
 752 
 753         public void visitContinue(JCContinue tree) {
 754             recordExit(new PendingExit(tree));
 755         }
 756 
 757         public void visitReturn(JCReturn tree) {
 758             scan(tree.expr);
 759             recordExit(new PendingExit(tree));
 760         }
 761 
 762         public void visitThrow(JCThrow tree) {
 763             scan(tree.expr);


 768             scan(tree.meth);
 769             scan(tree.args);
 770         }
 771 
 772         public void visitNewClass(JCNewClass tree) {
 773             scan(tree.encl);
 774             scan(tree.args);
 775             if (tree.def != null) {
 776                 scan(tree.def);
 777             }
 778         }
 779 
 780         @Override
 781         public void visitLambda(JCLambda tree) {
 782             if (tree.type != null &&
 783                     tree.type.isErroneous()) {
 784                 return;
 785             }
 786 
 787             ListBuffer<PendingExit> prevPending = pendingExits;
 788             Liveness prevAlive = alive;
 789             try {
 790                 pendingExits = new ListBuffer<>();
 791                 alive = Liveness.ALIVE;
 792                 scanStat(tree.body);
 793                 tree.canCompleteNormally = alive.alive;
 794             }
 795             finally {
 796                 pendingExits = prevPending;
 797                 alive = prevAlive;
 798             }
 799         }
 800 
 801         public void visitModuleDef(JCModuleDecl tree) {
 802             // Do nothing for modules
 803         }
 804 
 805     /**************************************************************************
 806      * main method
 807      *************************************************************************/
 808 
 809         /** Perform definite assignment/unassignment analysis on a tree.
 810          */
 811         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
 812             analyzeTree(env, env.tree, make);
 813         }
 814         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
 815             try {
 816                 attrEnv = env;
 817                 Flow.this.make = make;
 818                 pendingExits = new ListBuffer<>();
 819                 alive = Liveness.ALIVE;
 820                 scan(tree);
 821             } finally {
 822                 pendingExits = null;
 823                 Flow.this.make = null;
 824             }
 825         }
 826     }
 827 
 828     /**
 829      * This pass implements the second step of the dataflow analysis, namely
 830      * the exception analysis. This is to ensure that every checked exception that is
 831      * thrown is declared or caught. The analyzer uses some info that has been set by
 832      * the liveliness analyzer.
 833      */
 834     class FlowAnalyzer extends BaseAnalyzer<FlowAnalyzer.FlowPendingExit> {
 835 
 836         /** A flag that indicates whether the last statement could
 837          *  complete normally.
 838          */
 839         HashMap<Symbol, List<Type>> preciseRethrowTypes;


2768      * main method
2769      *************************************************************************/
2770 
2771         /** Perform definite assignment/unassignment analysis on a tree.
2772          */
2773         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
2774             analyzeTree(env, env.tree, make);
2775         }
2776         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
2777             try {
2778                 attrEnv = env;
2779                 Flow.this.make = make;
2780                 pendingExits = new ListBuffer<>();
2781                 scan(tree);
2782             } finally {
2783                 pendingExits = null;
2784                 Flow.this.make = null;
2785             }
2786         }
2787     }
2788 
2789     enum Liveness {
2790         ALIVE(true) {
2791             @Override
2792             public Liveness or(Liveness other) {
2793                 return this;
2794             }
2795             @Override
2796             public Liveness and(Liveness other) {
2797                 return other;
2798             }
2799         },
2800         NOT_ALIVE(false) {
2801             @Override
2802             public Liveness or(Liveness other) {
2803                 return other;
2804             }
2805             @Override
2806             public Liveness and(Liveness other) {
2807                 return this;
2808             }
2809         },
2810         RECOVERY(true) {
2811             @Override
2812             public Liveness or(Liveness other) {
2813                 if (other == ALIVE) {
2814                     return ALIVE;
2815                 } else {
2816                     return this;
2817                 }
2818             }
2819             @Override
2820             public Liveness and(Liveness other) {
2821                 if (other == NOT_ALIVE) {
2822                     return NOT_ALIVE;
2823                 } else {
2824                     return this;
2825                 }
2826             }
2827         };
2828 
2829         public final boolean alive;
2830 
2831         private Liveness(boolean alive) {
2832             this.alive = alive;
2833         }
2834         
2835         public abstract Liveness or(Liveness other);
2836         public abstract Liveness and(Liveness other);
2837         public Liveness or(boolean value) {
2838             return or(from(value));
2839         }
2840         public Liveness and(boolean value) {
2841             return and(from(value));
2842         }
2843         public static Liveness from(boolean value) {
2844             return value ? ALIVE : NOT_ALIVE;
2845         }
2846     }
2847 
2848 }
< prev index next >