23 * questions.
24 */
25
26 //todo: one might eliminate uninits.andSets when monotonic
27
28 package com.sun.tools.javac.comp;
29
30 import java.util.HashMap;
31 import java.util.Map;
32 import java.util.LinkedHashMap;
33
34 import com.sun.tools.javac.code.*;
35 import com.sun.tools.javac.tree.*;
36 import com.sun.tools.javac.util.*;
37 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
38
39 import com.sun.tools.javac.code.Symbol.*;
40 import com.sun.tools.javac.tree.JCTree.*;
41
42 import static com.sun.tools.javac.code.Flags.*;
43 import static com.sun.tools.javac.code.Kinds.*;
44 import static com.sun.tools.javac.code.TypeTags.*;
45
46 /** This pass implements dataflow analysis for Java programs.
47 * Liveness analysis checks that every statement is reachable.
48 * Exception analysis ensures that every checked exception that is
49 * thrown is declared or caught. Definite assignment analysis
50 * ensures that each variable is assigned when used. Definite
51 * unassignment analysis ensures that no final variable is assigned
52 * more than once.
53 *
54 * <p>The JLS has a number of problems in the
55 * specification of these flow analysis problems. This implementation
56 * attempts to address those issues.
57 *
58 * <p>First, there is no accommodation for a finally clause that cannot
59 * complete normally. For liveness analysis, an intervening finally
60 * clause can cause a break, continue, or return not to reach its
61 * target. For exception analysis, an intervening finally clause can
62 * cause any exception to be "caught". For DA/DU analysis, the finally
63 * clause can prevent a transfer of control from propagating DA/DU
64 * state to the target. In addition, code in the finally clause can
304 }
305
306 /** The currently pending exits that go from current inner blocks
307 * to an enclosing block, in source order.
308 */
309 ListBuffer<PendingExit> pendingExits;
310
311 /*-------------------- Exceptions ----------------------*/
312
313 /** Complain that pending exceptions are not caught.
314 */
315 void errorUncaught() {
316 for (PendingExit exit = pendingExits.next();
317 exit != null;
318 exit = pendingExits.next()) {
319 if (classDef != null &&
320 classDef.pos == exit.tree.pos) {
321 log.error(exit.tree.pos(),
322 "unreported.exception.default.constructor",
323 exit.thrown);
324 } else if (exit.tree.getTag() == JCTree.VARDEF &&
325 ((JCVariableDecl)exit.tree).sym.isResourceVariable()) {
326 log.error(exit.tree.pos(),
327 "unreported.exception.implicit.close",
328 exit.thrown,
329 ((JCVariableDecl)exit.tree).sym.name);
330 } else {
331 log.error(exit.tree.pos(),
332 "unreported.exception.need.to.catch.or.throw",
333 exit.thrown);
334 }
335 }
336 }
337
338 /** Record that exception is potentially thrown and check that it
339 * is caught.
340 */
341 void markThrown(JCTree tree, Type exc) {
342 if (!chk.isUnchecked(tree.pos(), exc)) {
343 if (!chk.isHandled(exc, caught))
344 pendingExits.append(new PendingExit(tree, exc));
399 // reachable assignment
400 uninits.excl(sym.adr);
401 uninitsTry.excl(sym.adr);
402 } else {
403 //log.rawWarning(pos, "unreachable assignment");//DEBUG
404 uninits.excl(sym.adr);
405 }
406 }
407 inits.incl(sym.adr);
408 } else if ((sym.flags() & FINAL) != 0) {
409 log.error(pos, "var.might.already.be.assigned", sym);
410 }
411 }
412
413 /** If tree is either a simple name or of the form this.name or
414 * C.this.name, and tree represents a trackable variable,
415 * record an initialization of the variable.
416 */
417 void letInit(JCTree tree) {
418 tree = TreeInfo.skipParens(tree);
419 if (tree.getTag() == JCTree.IDENT || tree.getTag() == JCTree.SELECT) {
420 Symbol sym = TreeInfo.symbol(tree);
421 if (sym.kind == VAR) {
422 letInit(tree.pos(), (VarSymbol)sym);
423 }
424 }
425 }
426
427 /** Check that trackable variable is initialized.
428 */
429 void checkInit(DiagnosticPosition pos, VarSymbol sym) {
430 if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
431 trackable(sym) &&
432 !inits.isMember(sym.adr)) {
433 log.error(pos, "var.might.not.have.been.initialized",
434 sym);
435 inits.incl(sym.adr);
436 }
437 }
438
439 /*-------------------- Handling jumps ----------------------*/
440
441 /** Record an outward transfer of control. */
442 void recordExit(JCTree tree) {
443 pendingExits.append(new PendingExit(tree, inits, uninits));
444 markDead();
445 }
446
447 /** Resolve all breaks of this statement. */
448 boolean resolveBreaks(JCTree tree,
449 ListBuffer<PendingExit> oldPendingExits) {
450 boolean result = false;
451 List<PendingExit> exits = pendingExits.toList();
452 pendingExits = oldPendingExits;
453 for (; exits.nonEmpty(); exits = exits.tail) {
454 PendingExit exit = exits.head;
455 if (exit.tree.getTag() == JCTree.BREAK &&
456 ((JCBreak) exit.tree).target == tree) {
457 inits.andSet(exit.inits);
458 uninits.andSet(exit.uninits);
459 result = true;
460 } else {
461 pendingExits.append(exit);
462 }
463 }
464 return result;
465 }
466
467 /** Resolve all continues of this statement. */
468 boolean resolveContinues(JCTree tree) {
469 boolean result = false;
470 List<PendingExit> exits = pendingExits.toList();
471 pendingExits = new ListBuffer<PendingExit>();
472 for (; exits.nonEmpty(); exits = exits.tail) {
473 PendingExit exit = exits.head;
474 if (exit.tree.getTag() == JCTree.CONTINUE &&
475 ((JCContinue) exit.tree).target == tree) {
476 inits.andSet(exit.inits);
477 uninits.andSet(exit.uninits);
478 result = true;
479 } else {
480 pendingExits.append(exit);
481 }
482 }
483 return result;
484 }
485
486 /** Record that statement is unreachable.
487 */
488 void markDead() {
489 inits.inclRange(firstadr, nextadr);
490 uninits.inclRange(firstadr, nextadr);
491 alive = false;
492 }
493
494 /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
500 uninitsWhenTrue = uninits;
501 if (setToNull)
502 inits = uninits = null;
503 }
504
505 /** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets.
506 */
507 void merge() {
508 inits = initsWhenFalse.andSet(initsWhenTrue);
509 uninits = uninitsWhenFalse.andSet(uninitsWhenTrue);
510 }
511
512 /* ************************************************************************
513 * Visitor methods for statements and definitions
514 *************************************************************************/
515
516 /** Analyze a definition.
517 */
518 void scanDef(JCTree tree) {
519 scanStat(tree);
520 if (tree != null && tree.getTag() == JCTree.BLOCK && !alive) {
521 log.error(tree.pos(),
522 "initializer.must.be.able.to.complete.normally");
523 }
524 }
525
526 /** Analyze a statement. Check that statement is reachable.
527 */
528 void scanStat(JCTree tree) {
529 if (!alive && tree != null) {
530 log.error(tree.pos(), "unreachable.stmt");
531 if (tree.getTag() != JCTree.SKIP) alive = true;
532 }
533 scan(tree);
534 }
535
536 /** Analyze list of statements.
537 */
538 void scanStats(List<? extends JCStatement> trees) {
539 if (trees != null)
540 for (List<? extends JCStatement> l = trees; l.nonEmpty(); l = l.tail)
541 scanStat(l.head);
542 }
543
544 /** Analyze an expression. Make sure to set (un)inits rather than
545 * (un)initsWhenTrue(WhenFalse) on exit.
546 */
547 void scanExpr(JCTree tree) {
548 if (tree != null) {
549 scan(tree);
550 if (inits == null) merge();
551 }
597 List<Type> thrownPrev = thrown;
598 List<Type> caughtPrev = caught;
599 boolean alivePrev = alive;
600 int firstadrPrev = firstadr;
601 int nextadrPrev = nextadr;
602 ListBuffer<PendingExit> pendingExitsPrev = pendingExits;
603 Lint lintPrev = lint;
604
605 pendingExits = new ListBuffer<PendingExit>();
606 if (tree.name != names.empty) {
607 caught = List.nil();
608 firstadr = nextadr;
609 }
610 classDef = tree;
611 thrown = List.nil();
612 lint = lint.augment(tree.sym.attributes_field);
613
614 try {
615 // define all the static fields
616 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
617 if (l.head.getTag() == JCTree.VARDEF) {
618 JCVariableDecl def = (JCVariableDecl)l.head;
619 if ((def.mods.flags & STATIC) != 0) {
620 VarSymbol sym = def.sym;
621 if (trackable(sym))
622 newVar(sym);
623 }
624 }
625 }
626
627 // process all the static initializers
628 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
629 if (l.head.getTag() != JCTree.METHODDEF &&
630 (TreeInfo.flags(l.head) & STATIC) != 0) {
631 scanDef(l.head);
632 errorUncaught();
633 }
634 }
635
636 // add intersection of all thrown clauses of initial constructors
637 // to set of caught exceptions, unless class is anonymous.
638 if (tree.name != names.empty) {
639 boolean firstConstructor = true;
640 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
641 if (TreeInfo.isInitialConstructor(l.head)) {
642 List<Type> mthrown =
643 ((JCMethodDecl) l.head).sym.type.getThrownTypes();
644 if (firstConstructor) {
645 caught = mthrown;
646 firstConstructor = false;
647 } else {
648 caught = chk.intersect(mthrown, caught);
649 }
650 }
651 }
652 }
653
654 // define all the instance fields
655 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
656 if (l.head.getTag() == JCTree.VARDEF) {
657 JCVariableDecl def = (JCVariableDecl)l.head;
658 if ((def.mods.flags & STATIC) == 0) {
659 VarSymbol sym = def.sym;
660 if (trackable(sym))
661 newVar(sym);
662 }
663 }
664 }
665
666 // process all the instance initializers
667 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
668 if (l.head.getTag() != JCTree.METHODDEF &&
669 (TreeInfo.flags(l.head) & STATIC) == 0) {
670 scanDef(l.head);
671 errorUncaught();
672 }
673 }
674
675 // in an anonymous class, add the set of thrown exceptions to
676 // the throws clause of the synthetic constructor and propagate
677 // outwards.
678 // Changing the throws clause on the fly is okay here because
679 // the anonymous constructor can't be invoked anywhere else,
680 // and its type hasn't been cached.
681 if (tree.name == names.empty) {
682 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
683 if (TreeInfo.isInitialConstructor(l.head)) {
684 JCMethodDecl mdef = (JCMethodDecl)l.head;
685 mdef.thrown = make.Types(thrown);
686 mdef.sym.type = types.createMethodTypeWithThrown(mdef.sym.type, thrown);
687 }
688 }
689 thrownPrev = chk.union(thrown, thrownPrev);
690 }
691
692 // process all the methods
693 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
694 if (l.head.getTag() == JCTree.METHODDEF) {
695 scan(l.head);
696 errorUncaught();
697 }
698 }
699
700 thrown = thrownPrev;
701 } finally {
702 pendingExits = pendingExitsPrev;
703 alive = alivePrev;
704 nextadr = nextadrPrev;
705 firstadr = firstadrPrev;
706 caught = caughtPrev;
707 classDef = classDefPrev;
708 lint = lintPrev;
709 }
710 }
711
712 public void visitMethodDef(JCMethodDecl tree) {
713 if (tree.body == null) return;
714
743 // else we are in an instance initializer block;
744 // leave caught unchanged.
745
746 alive = true;
747 scanStat(tree.body);
748
749 if (alive && tree.sym.type.getReturnType().tag != VOID)
750 log.error(TreeInfo.diagEndPos(tree.body), "missing.ret.stmt");
751
752 if (isInitialConstructor) {
753 for (int i = firstadr; i < nextadr; i++)
754 if (vars[i].owner == classDef.sym)
755 checkInit(TreeInfo.diagEndPos(tree.body), vars[i]);
756 }
757 List<PendingExit> exits = pendingExits.toList();
758 pendingExits = new ListBuffer<PendingExit>();
759 while (exits.nonEmpty()) {
760 PendingExit exit = exits.head;
761 exits = exits.tail;
762 if (exit.thrown == null) {
763 Assert.check(exit.tree.getTag() == JCTree.RETURN);
764 if (isInitialConstructor) {
765 inits = exit.inits;
766 for (int i = firstadr; i < nextadr; i++)
767 checkInit(exit.tree.pos(), vars[i]);
768 }
769 } else {
770 // uncaught throws will be reported later
771 pendingExits.append(exit);
772 }
773 }
774 } finally {
775 inits = initsPrev;
776 uninits = uninitsPrev;
777 nextadr = nextadrPrev;
778 firstadr = firstadrPrev;
779 caught = caughtPrev;
780 lint = lintPrev;
781 }
782 }
783
972 alive &&
973 lint.isEnabled(Lint.LintCategory.FALLTHROUGH) &&
974 c.stats.nonEmpty() && l.tail.nonEmpty())
975 log.warning(Lint.LintCategory.FALLTHROUGH,
976 l.tail.head.pos(),
977 "possible.fall-through.into.case");
978 }
979 if (!hasDefault) {
980 inits.andSet(initsSwitch);
981 alive = true;
982 }
983 alive |= resolveBreaks(tree, prevPendingExits);
984 nextadr = nextadrPrev;
985 }
986 // where
987 /** Add any variables defined in stats to inits and uninits. */
988 private static void addVars(List<JCStatement> stats, Bits inits,
989 Bits uninits) {
990 for (;stats.nonEmpty(); stats = stats.tail) {
991 JCTree stat = stats.head;
992 if (stat.getTag() == JCTree.VARDEF) {
993 int adr = ((JCVariableDecl) stat).sym.adr;
994 inits.excl(adr);
995 uninits.incl(adr);
996 }
997 }
998 }
999
1000 public void visitTry(JCTry tree) {
1001 List<Type> caughtPrev = caught;
1002 List<Type> thrownPrev = thrown;
1003 thrown = List.nil();
1004 for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
1005 List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
1006 ((JCTypeUnion)l.head.param.vartype).alternatives :
1007 List.of(l.head.param.vartype);
1008 for (JCExpression ct : subClauses) {
1009 caught = chk.incl(ct.type, caught);
1010 }
1011 }
1012 ListBuffer<JCVariableDecl> resourceVarDecls = ListBuffer.lb();
1329 }
1330 inits = initsExit;
1331 uninits = uninitsExit;
1332 }
1333
1334 public void visitAssign(JCAssign tree) {
1335 JCTree lhs = TreeInfo.skipParens(tree.lhs);
1336 if (!(lhs instanceof JCIdent)) scanExpr(lhs);
1337 scanExpr(tree.rhs);
1338 letInit(lhs);
1339 }
1340
1341 public void visitAssignop(JCAssignOp tree) {
1342 scanExpr(tree.lhs);
1343 scanExpr(tree.rhs);
1344 letInit(tree.lhs);
1345 }
1346
1347 public void visitUnary(JCUnary tree) {
1348 switch (tree.getTag()) {
1349 case JCTree.NOT:
1350 scanCond(tree.arg);
1351 Bits t = initsWhenFalse;
1352 initsWhenFalse = initsWhenTrue;
1353 initsWhenTrue = t;
1354 t = uninitsWhenFalse;
1355 uninitsWhenFalse = uninitsWhenTrue;
1356 uninitsWhenTrue = t;
1357 break;
1358 case JCTree.PREINC: case JCTree.POSTINC:
1359 case JCTree.PREDEC: case JCTree.POSTDEC:
1360 scanExpr(tree.arg);
1361 letInit(tree.arg);
1362 break;
1363 default:
1364 scanExpr(tree.arg);
1365 }
1366 }
1367
1368 public void visitBinary(JCBinary tree) {
1369 switch (tree.getTag()) {
1370 case JCTree.AND:
1371 scanCond(tree.lhs);
1372 Bits initsWhenFalseLeft = initsWhenFalse;
1373 Bits uninitsWhenFalseLeft = uninitsWhenFalse;
1374 inits = initsWhenTrue;
1375 uninits = uninitsWhenTrue;
1376 scanCond(tree.rhs);
1377 initsWhenFalse.andSet(initsWhenFalseLeft);
1378 uninitsWhenFalse.andSet(uninitsWhenFalseLeft);
1379 break;
1380 case JCTree.OR:
1381 scanCond(tree.lhs);
1382 Bits initsWhenTrueLeft = initsWhenTrue;
1383 Bits uninitsWhenTrueLeft = uninitsWhenTrue;
1384 inits = initsWhenFalse;
1385 uninits = uninitsWhenFalse;
1386 scanCond(tree.rhs);
1387 initsWhenTrue.andSet(initsWhenTrueLeft);
1388 uninitsWhenTrue.andSet(uninitsWhenTrueLeft);
1389 break;
1390 default:
1391 scanExpr(tree.lhs);
1392 scanExpr(tree.rhs);
1393 }
1394 }
1395
1396 public void visitIdent(JCIdent tree) {
1397 if (tree.sym.kind == VAR) {
1398 checkInit(tree.pos(), (VarSymbol)tree.sym);
1399 referenced(tree.sym);
1400 }
1401 }
1402
1403 void referenced(Symbol sym) {
1404 unrefdResources.remove(sym);
1405 }
1406
1407 public void visitTypeCast(JCTypeCast tree) {
1408 super.visitTypeCast(tree);
1409 if (!tree.type.isErroneous()
1410 && lint.isEnabled(Lint.LintCategory.CAST)
1411 && types.isSameType(tree.expr.type, tree.clazz.type)
1412 && !is292targetTypeCast(tree)) {
1413 log.warning(Lint.LintCategory.CAST,
1414 tree.pos(), "redundant.cast", tree.expr.type);
1415 }
1416 }
1417 //where
1418 private boolean is292targetTypeCast(JCTypeCast tree) {
1419 boolean is292targetTypeCast = false;
1420 JCExpression expr = TreeInfo.skipParens(tree.expr);
1421 if (expr.getTag() == JCTree.APPLY) {
1422 JCMethodInvocation apply = (JCMethodInvocation)expr;
1423 Symbol sym = TreeInfo.symbol(apply.meth);
1424 is292targetTypeCast = sym != null &&
1425 sym.kind == MTH &&
1426 (sym.flags() & POLYMORPHIC_SIGNATURE) != 0;
1427 }
1428 return is292targetTypeCast;
1429 }
1430
1431 public void visitTopLevel(JCCompilationUnit tree) {
1432 // Do nothing for TopLevel since each class is visited individually
1433 }
1434
1435 /**************************************************************************
1436 * main method
1437 *************************************************************************/
1438
1439 /** Perform definite assignment/unassignment analysis on a tree.
1440 */
1441 public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
|
23 * questions.
24 */
25
26 //todo: one might eliminate uninits.andSets when monotonic
27
28 package com.sun.tools.javac.comp;
29
30 import java.util.HashMap;
31 import java.util.Map;
32 import java.util.LinkedHashMap;
33
34 import com.sun.tools.javac.code.*;
35 import com.sun.tools.javac.tree.*;
36 import com.sun.tools.javac.util.*;
37 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
38
39 import com.sun.tools.javac.code.Symbol.*;
40 import com.sun.tools.javac.tree.JCTree.*;
41
42 import static com.sun.tools.javac.code.Flags.*;
43 import static com.sun.tools.javac.code.Flags.BLOCK;
44 import static com.sun.tools.javac.code.Kinds.*;
45 import static com.sun.tools.javac.code.TypeTags.*;
46 import static com.sun.tools.javac.tree.JCTree.Tag.*;
47
48 /** This pass implements dataflow analysis for Java programs.
49 * Liveness analysis checks that every statement is reachable.
50 * Exception analysis ensures that every checked exception that is
51 * thrown is declared or caught. Definite assignment analysis
52 * ensures that each variable is assigned when used. Definite
53 * unassignment analysis ensures that no final variable is assigned
54 * more than once.
55 *
56 * <p>The JLS has a number of problems in the
57 * specification of these flow analysis problems. This implementation
58 * attempts to address those issues.
59 *
60 * <p>First, there is no accommodation for a finally clause that cannot
61 * complete normally. For liveness analysis, an intervening finally
62 * clause can cause a break, continue, or return not to reach its
63 * target. For exception analysis, an intervening finally clause can
64 * cause any exception to be "caught". For DA/DU analysis, the finally
65 * clause can prevent a transfer of control from propagating DA/DU
66 * state to the target. In addition, code in the finally clause can
306 }
307
308 /** The currently pending exits that go from current inner blocks
309 * to an enclosing block, in source order.
310 */
311 ListBuffer<PendingExit> pendingExits;
312
313 /*-------------------- Exceptions ----------------------*/
314
315 /** Complain that pending exceptions are not caught.
316 */
317 void errorUncaught() {
318 for (PendingExit exit = pendingExits.next();
319 exit != null;
320 exit = pendingExits.next()) {
321 if (classDef != null &&
322 classDef.pos == exit.tree.pos) {
323 log.error(exit.tree.pos(),
324 "unreported.exception.default.constructor",
325 exit.thrown);
326 } else if (exit.tree.hasTag(VARDEF) &&
327 ((JCVariableDecl)exit.tree).sym.isResourceVariable()) {
328 log.error(exit.tree.pos(),
329 "unreported.exception.implicit.close",
330 exit.thrown,
331 ((JCVariableDecl)exit.tree).sym.name);
332 } else {
333 log.error(exit.tree.pos(),
334 "unreported.exception.need.to.catch.or.throw",
335 exit.thrown);
336 }
337 }
338 }
339
340 /** Record that exception is potentially thrown and check that it
341 * is caught.
342 */
343 void markThrown(JCTree tree, Type exc) {
344 if (!chk.isUnchecked(tree.pos(), exc)) {
345 if (!chk.isHandled(exc, caught))
346 pendingExits.append(new PendingExit(tree, exc));
401 // reachable assignment
402 uninits.excl(sym.adr);
403 uninitsTry.excl(sym.adr);
404 } else {
405 //log.rawWarning(pos, "unreachable assignment");//DEBUG
406 uninits.excl(sym.adr);
407 }
408 }
409 inits.incl(sym.adr);
410 } else if ((sym.flags() & FINAL) != 0) {
411 log.error(pos, "var.might.already.be.assigned", sym);
412 }
413 }
414
415 /** If tree is either a simple name or of the form this.name or
416 * C.this.name, and tree represents a trackable variable,
417 * record an initialization of the variable.
418 */
419 void letInit(JCTree tree) {
420 tree = TreeInfo.skipParens(tree);
421 if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
422 Symbol sym = TreeInfo.symbol(tree);
423 if (sym.kind == VAR) {
424 letInit(tree.pos(), (VarSymbol)sym);
425 }
426 }
427 }
428
429 /** Check that trackable variable is initialized.
430 */
431 void checkInit(DiagnosticPosition pos, VarSymbol sym) {
432 if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
433 trackable(sym) &&
434 !inits.isMember(sym.adr)) {
435 log.error(pos, "var.might.not.have.been.initialized",
436 sym);
437 inits.incl(sym.adr);
438 }
439 }
440
441 /*-------------------- Handling jumps ----------------------*/
442
443 /** Record an outward transfer of control. */
444 void recordExit(JCTree tree) {
445 pendingExits.append(new PendingExit(tree, inits, uninits));
446 markDead();
447 }
448
449 /** Resolve all breaks of this statement. */
450 boolean resolveBreaks(JCTree tree,
451 ListBuffer<PendingExit> oldPendingExits) {
452 boolean result = false;
453 List<PendingExit> exits = pendingExits.toList();
454 pendingExits = oldPendingExits;
455 for (; exits.nonEmpty(); exits = exits.tail) {
456 PendingExit exit = exits.head;
457 if (exit.tree.hasTag(BREAK) &&
458 ((JCBreak) exit.tree).target == tree) {
459 inits.andSet(exit.inits);
460 uninits.andSet(exit.uninits);
461 result = true;
462 } else {
463 pendingExits.append(exit);
464 }
465 }
466 return result;
467 }
468
469 /** Resolve all continues of this statement. */
470 boolean resolveContinues(JCTree tree) {
471 boolean result = false;
472 List<PendingExit> exits = pendingExits.toList();
473 pendingExits = new ListBuffer<PendingExit>();
474 for (; exits.nonEmpty(); exits = exits.tail) {
475 PendingExit exit = exits.head;
476 if (exit.tree.hasTag(CONTINUE) &&
477 ((JCContinue) exit.tree).target == tree) {
478 inits.andSet(exit.inits);
479 uninits.andSet(exit.uninits);
480 result = true;
481 } else {
482 pendingExits.append(exit);
483 }
484 }
485 return result;
486 }
487
488 /** Record that statement is unreachable.
489 */
490 void markDead() {
491 inits.inclRange(firstadr, nextadr);
492 uninits.inclRange(firstadr, nextadr);
493 alive = false;
494 }
495
496 /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
502 uninitsWhenTrue = uninits;
503 if (setToNull)
504 inits = uninits = null;
505 }
506
507 /** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets.
508 */
509 void merge() {
510 inits = initsWhenFalse.andSet(initsWhenTrue);
511 uninits = uninitsWhenFalse.andSet(uninitsWhenTrue);
512 }
513
514 /* ************************************************************************
515 * Visitor methods for statements and definitions
516 *************************************************************************/
517
518 /** Analyze a definition.
519 */
520 void scanDef(JCTree tree) {
521 scanStat(tree);
522 if (tree != null && tree.hasTag(JCTree.Tag.BLOCK) && !alive) {
523 log.error(tree.pos(),
524 "initializer.must.be.able.to.complete.normally");
525 }
526 }
527
528 /** Analyze a statement. Check that statement is reachable.
529 */
530 void scanStat(JCTree tree) {
531 if (!alive && tree != null) {
532 log.error(tree.pos(), "unreachable.stmt");
533 if (!tree.hasTag(SKIP)) alive = true;
534 }
535 scan(tree);
536 }
537
538 /** Analyze list of statements.
539 */
540 void scanStats(List<? extends JCStatement> trees) {
541 if (trees != null)
542 for (List<? extends JCStatement> l = trees; l.nonEmpty(); l = l.tail)
543 scanStat(l.head);
544 }
545
546 /** Analyze an expression. Make sure to set (un)inits rather than
547 * (un)initsWhenTrue(WhenFalse) on exit.
548 */
549 void scanExpr(JCTree tree) {
550 if (tree != null) {
551 scan(tree);
552 if (inits == null) merge();
553 }
599 List<Type> thrownPrev = thrown;
600 List<Type> caughtPrev = caught;
601 boolean alivePrev = alive;
602 int firstadrPrev = firstadr;
603 int nextadrPrev = nextadr;
604 ListBuffer<PendingExit> pendingExitsPrev = pendingExits;
605 Lint lintPrev = lint;
606
607 pendingExits = new ListBuffer<PendingExit>();
608 if (tree.name != names.empty) {
609 caught = List.nil();
610 firstadr = nextadr;
611 }
612 classDef = tree;
613 thrown = List.nil();
614 lint = lint.augment(tree.sym.attributes_field);
615
616 try {
617 // define all the static fields
618 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
619 if (l.head.hasTag(VARDEF)) {
620 JCVariableDecl def = (JCVariableDecl)l.head;
621 if ((def.mods.flags & STATIC) != 0) {
622 VarSymbol sym = def.sym;
623 if (trackable(sym))
624 newVar(sym);
625 }
626 }
627 }
628
629 // process all the static initializers
630 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
631 if (!l.head.hasTag(METHODDEF) &&
632 (TreeInfo.flags(l.head) & STATIC) != 0) {
633 scanDef(l.head);
634 errorUncaught();
635 }
636 }
637
638 // add intersection of all thrown clauses of initial constructors
639 // to set of caught exceptions, unless class is anonymous.
640 if (tree.name != names.empty) {
641 boolean firstConstructor = true;
642 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
643 if (TreeInfo.isInitialConstructor(l.head)) {
644 List<Type> mthrown =
645 ((JCMethodDecl) l.head).sym.type.getThrownTypes();
646 if (firstConstructor) {
647 caught = mthrown;
648 firstConstructor = false;
649 } else {
650 caught = chk.intersect(mthrown, caught);
651 }
652 }
653 }
654 }
655
656 // define all the instance fields
657 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
658 if (l.head.hasTag(VARDEF)) {
659 JCVariableDecl def = (JCVariableDecl)l.head;
660 if ((def.mods.flags & STATIC) == 0) {
661 VarSymbol sym = def.sym;
662 if (trackable(sym))
663 newVar(sym);
664 }
665 }
666 }
667
668 // process all the instance initializers
669 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
670 if (!l.head.hasTag(METHODDEF) &&
671 (TreeInfo.flags(l.head) & STATIC) == 0) {
672 scanDef(l.head);
673 errorUncaught();
674 }
675 }
676
677 // in an anonymous class, add the set of thrown exceptions to
678 // the throws clause of the synthetic constructor and propagate
679 // outwards.
680 // Changing the throws clause on the fly is okay here because
681 // the anonymous constructor can't be invoked anywhere else,
682 // and its type hasn't been cached.
683 if (tree.name == names.empty) {
684 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
685 if (TreeInfo.isInitialConstructor(l.head)) {
686 JCMethodDecl mdef = (JCMethodDecl)l.head;
687 mdef.thrown = make.Types(thrown);
688 mdef.sym.type = types.createMethodTypeWithThrown(mdef.sym.type, thrown);
689 }
690 }
691 thrownPrev = chk.union(thrown, thrownPrev);
692 }
693
694 // process all the methods
695 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
696 if (l.head.hasTag(METHODDEF)) {
697 scan(l.head);
698 errorUncaught();
699 }
700 }
701
702 thrown = thrownPrev;
703 } finally {
704 pendingExits = pendingExitsPrev;
705 alive = alivePrev;
706 nextadr = nextadrPrev;
707 firstadr = firstadrPrev;
708 caught = caughtPrev;
709 classDef = classDefPrev;
710 lint = lintPrev;
711 }
712 }
713
714 public void visitMethodDef(JCMethodDecl tree) {
715 if (tree.body == null) return;
716
745 // else we are in an instance initializer block;
746 // leave caught unchanged.
747
748 alive = true;
749 scanStat(tree.body);
750
751 if (alive && tree.sym.type.getReturnType().tag != VOID)
752 log.error(TreeInfo.diagEndPos(tree.body), "missing.ret.stmt");
753
754 if (isInitialConstructor) {
755 for (int i = firstadr; i < nextadr; i++)
756 if (vars[i].owner == classDef.sym)
757 checkInit(TreeInfo.diagEndPos(tree.body), vars[i]);
758 }
759 List<PendingExit> exits = pendingExits.toList();
760 pendingExits = new ListBuffer<PendingExit>();
761 while (exits.nonEmpty()) {
762 PendingExit exit = exits.head;
763 exits = exits.tail;
764 if (exit.thrown == null) {
765 Assert.check(exit.tree.hasTag(RETURN));
766 if (isInitialConstructor) {
767 inits = exit.inits;
768 for (int i = firstadr; i < nextadr; i++)
769 checkInit(exit.tree.pos(), vars[i]);
770 }
771 } else {
772 // uncaught throws will be reported later
773 pendingExits.append(exit);
774 }
775 }
776 } finally {
777 inits = initsPrev;
778 uninits = uninitsPrev;
779 nextadr = nextadrPrev;
780 firstadr = firstadrPrev;
781 caught = caughtPrev;
782 lint = lintPrev;
783 }
784 }
785
974 alive &&
975 lint.isEnabled(Lint.LintCategory.FALLTHROUGH) &&
976 c.stats.nonEmpty() && l.tail.nonEmpty())
977 log.warning(Lint.LintCategory.FALLTHROUGH,
978 l.tail.head.pos(),
979 "possible.fall-through.into.case");
980 }
981 if (!hasDefault) {
982 inits.andSet(initsSwitch);
983 alive = true;
984 }
985 alive |= resolveBreaks(tree, prevPendingExits);
986 nextadr = nextadrPrev;
987 }
988 // where
989 /** Add any variables defined in stats to inits and uninits. */
990 private static void addVars(List<JCStatement> stats, Bits inits,
991 Bits uninits) {
992 for (;stats.nonEmpty(); stats = stats.tail) {
993 JCTree stat = stats.head;
994 if (stat.hasTag(VARDEF)) {
995 int adr = ((JCVariableDecl) stat).sym.adr;
996 inits.excl(adr);
997 uninits.incl(adr);
998 }
999 }
1000 }
1001
1002 public void visitTry(JCTry tree) {
1003 List<Type> caughtPrev = caught;
1004 List<Type> thrownPrev = thrown;
1005 thrown = List.nil();
1006 for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
1007 List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
1008 ((JCTypeUnion)l.head.param.vartype).alternatives :
1009 List.of(l.head.param.vartype);
1010 for (JCExpression ct : subClauses) {
1011 caught = chk.incl(ct.type, caught);
1012 }
1013 }
1014 ListBuffer<JCVariableDecl> resourceVarDecls = ListBuffer.lb();
1331 }
1332 inits = initsExit;
1333 uninits = uninitsExit;
1334 }
1335
1336 public void visitAssign(JCAssign tree) {
1337 JCTree lhs = TreeInfo.skipParens(tree.lhs);
1338 if (!(lhs instanceof JCIdent)) scanExpr(lhs);
1339 scanExpr(tree.rhs);
1340 letInit(lhs);
1341 }
1342
1343 public void visitAssignop(JCAssignOp tree) {
1344 scanExpr(tree.lhs);
1345 scanExpr(tree.rhs);
1346 letInit(tree.lhs);
1347 }
1348
1349 public void visitUnary(JCUnary tree) {
1350 switch (tree.getTag()) {
1351 case NOT:
1352 scanCond(tree.arg);
1353 Bits t = initsWhenFalse;
1354 initsWhenFalse = initsWhenTrue;
1355 initsWhenTrue = t;
1356 t = uninitsWhenFalse;
1357 uninitsWhenFalse = uninitsWhenTrue;
1358 uninitsWhenTrue = t;
1359 break;
1360 case PREINC: case POSTINC:
1361 case PREDEC: case POSTDEC:
1362 scanExpr(tree.arg);
1363 letInit(tree.arg);
1364 break;
1365 default:
1366 scanExpr(tree.arg);
1367 }
1368 }
1369
1370 public void visitBinary(JCBinary tree) {
1371 switch (tree.getTag()) {
1372 case AND:
1373 scanCond(tree.lhs);
1374 Bits initsWhenFalseLeft = initsWhenFalse;
1375 Bits uninitsWhenFalseLeft = uninitsWhenFalse;
1376 inits = initsWhenTrue;
1377 uninits = uninitsWhenTrue;
1378 scanCond(tree.rhs);
1379 initsWhenFalse.andSet(initsWhenFalseLeft);
1380 uninitsWhenFalse.andSet(uninitsWhenFalseLeft);
1381 break;
1382 case OR:
1383 scanCond(tree.lhs);
1384 Bits initsWhenTrueLeft = initsWhenTrue;
1385 Bits uninitsWhenTrueLeft = uninitsWhenTrue;
1386 inits = initsWhenFalse;
1387 uninits = uninitsWhenFalse;
1388 scanCond(tree.rhs);
1389 initsWhenTrue.andSet(initsWhenTrueLeft);
1390 uninitsWhenTrue.andSet(uninitsWhenTrueLeft);
1391 break;
1392 default:
1393 scanExpr(tree.lhs);
1394 scanExpr(tree.rhs);
1395 }
1396 }
1397
1398 public void visitIdent(JCIdent tree) {
1399 if (tree.sym.kind == VAR) {
1400 checkInit(tree.pos(), (VarSymbol)tree.sym);
1401 referenced(tree.sym);
1402 }
1403 }
1404
1405 void referenced(Symbol sym) {
1406 unrefdResources.remove(sym);
1407 }
1408
1409 public void visitTypeCast(JCTypeCast tree) {
1410 super.visitTypeCast(tree);
1411 if (!tree.type.isErroneous()
1412 && lint.isEnabled(Lint.LintCategory.CAST)
1413 && types.isSameType(tree.expr.type, tree.clazz.type)
1414 && !is292targetTypeCast(tree)) {
1415 log.warning(Lint.LintCategory.CAST,
1416 tree.pos(), "redundant.cast", tree.expr.type);
1417 }
1418 }
1419 //where
1420 private boolean is292targetTypeCast(JCTypeCast tree) {
1421 boolean is292targetTypeCast = false;
1422 JCExpression expr = TreeInfo.skipParens(tree.expr);
1423 if (expr.hasTag(APPLY)) {
1424 JCMethodInvocation apply = (JCMethodInvocation)expr;
1425 Symbol sym = TreeInfo.symbol(apply.meth);
1426 is292targetTypeCast = sym != null &&
1427 sym.kind == MTH &&
1428 (sym.flags() & POLYMORPHIC_SIGNATURE) != 0;
1429 }
1430 return is292targetTypeCast;
1431 }
1432
1433 public void visitTopLevel(JCCompilationUnit tree) {
1434 // Do nothing for TopLevel since each class is visited individually
1435 }
1436
1437 /**************************************************************************
1438 * main method
1439 *************************************************************************/
1440
1441 /** Perform definite assignment/unassignment analysis on a tree.
1442 */
1443 public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
|