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 }
|