38 |
38 |
39 import com.sun.tools.javac.code.Symbol.*; |
39 import com.sun.tools.javac.code.Symbol.*; |
40 import com.sun.tools.javac.tree.JCTree.*; |
40 import com.sun.tools.javac.tree.JCTree.*; |
41 |
41 |
42 import static com.sun.tools.javac.code.Flags.*; |
42 import static com.sun.tools.javac.code.Flags.*; |
|
43 import static com.sun.tools.javac.code.Flags.BLOCK; |
43 import static com.sun.tools.javac.code.Kinds.*; |
44 import static com.sun.tools.javac.code.Kinds.*; |
44 import static com.sun.tools.javac.code.TypeTags.*; |
45 import static com.sun.tools.javac.code.TypeTags.*; |
|
46 import static com.sun.tools.javac.tree.JCTree.Tag.*; |
45 |
47 |
46 /** This pass implements dataflow analysis for Java programs. |
48 /** This pass implements dataflow analysis for Java programs. |
47 * Liveness analysis checks that every statement is reachable. |
49 * Liveness analysis checks that every statement is reachable. |
48 * Exception analysis ensures that every checked exception that is |
50 * Exception analysis ensures that every checked exception that is |
49 * thrown is declared or caught. Definite assignment analysis |
51 * thrown is declared or caught. Definite assignment analysis |
319 if (classDef != null && |
321 if (classDef != null && |
320 classDef.pos == exit.tree.pos) { |
322 classDef.pos == exit.tree.pos) { |
321 log.error(exit.tree.pos(), |
323 log.error(exit.tree.pos(), |
322 "unreported.exception.default.constructor", |
324 "unreported.exception.default.constructor", |
323 exit.thrown); |
325 exit.thrown); |
324 } else if (exit.tree.getTag() == JCTree.VARDEF && |
326 } else if (exit.tree.hasTag(VARDEF) && |
325 ((JCVariableDecl)exit.tree).sym.isResourceVariable()) { |
327 ((JCVariableDecl)exit.tree).sym.isResourceVariable()) { |
326 log.error(exit.tree.pos(), |
328 log.error(exit.tree.pos(), |
327 "unreported.exception.implicit.close", |
329 "unreported.exception.implicit.close", |
328 exit.thrown, |
330 exit.thrown, |
329 ((JCVariableDecl)exit.tree).sym.name); |
331 ((JCVariableDecl)exit.tree).sym.name); |
414 * C.this.name, and tree represents a trackable variable, |
416 * C.this.name, and tree represents a trackable variable, |
415 * record an initialization of the variable. |
417 * record an initialization of the variable. |
416 */ |
418 */ |
417 void letInit(JCTree tree) { |
419 void letInit(JCTree tree) { |
418 tree = TreeInfo.skipParens(tree); |
420 tree = TreeInfo.skipParens(tree); |
419 if (tree.getTag() == JCTree.IDENT || tree.getTag() == JCTree.SELECT) { |
421 if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) { |
420 Symbol sym = TreeInfo.symbol(tree); |
422 Symbol sym = TreeInfo.symbol(tree); |
421 if (sym.kind == VAR) { |
423 if (sym.kind == VAR) { |
422 letInit(tree.pos(), (VarSymbol)sym); |
424 letInit(tree.pos(), (VarSymbol)sym); |
423 } |
425 } |
424 } |
426 } |
450 boolean result = false; |
452 boolean result = false; |
451 List<PendingExit> exits = pendingExits.toList(); |
453 List<PendingExit> exits = pendingExits.toList(); |
452 pendingExits = oldPendingExits; |
454 pendingExits = oldPendingExits; |
453 for (; exits.nonEmpty(); exits = exits.tail) { |
455 for (; exits.nonEmpty(); exits = exits.tail) { |
454 PendingExit exit = exits.head; |
456 PendingExit exit = exits.head; |
455 if (exit.tree.getTag() == JCTree.BREAK && |
457 if (exit.tree.hasTag(BREAK) && |
456 ((JCBreak) exit.tree).target == tree) { |
458 ((JCBreak) exit.tree).target == tree) { |
457 inits.andSet(exit.inits); |
459 inits.andSet(exit.inits); |
458 uninits.andSet(exit.uninits); |
460 uninits.andSet(exit.uninits); |
459 result = true; |
461 result = true; |
460 } else { |
462 } else { |
469 boolean result = false; |
471 boolean result = false; |
470 List<PendingExit> exits = pendingExits.toList(); |
472 List<PendingExit> exits = pendingExits.toList(); |
471 pendingExits = new ListBuffer<PendingExit>(); |
473 pendingExits = new ListBuffer<PendingExit>(); |
472 for (; exits.nonEmpty(); exits = exits.tail) { |
474 for (; exits.nonEmpty(); exits = exits.tail) { |
473 PendingExit exit = exits.head; |
475 PendingExit exit = exits.head; |
474 if (exit.tree.getTag() == JCTree.CONTINUE && |
476 if (exit.tree.hasTag(CONTINUE) && |
475 ((JCContinue) exit.tree).target == tree) { |
477 ((JCContinue) exit.tree).target == tree) { |
476 inits.andSet(exit.inits); |
478 inits.andSet(exit.inits); |
477 uninits.andSet(exit.uninits); |
479 uninits.andSet(exit.uninits); |
478 result = true; |
480 result = true; |
479 } else { |
481 } else { |
515 |
517 |
516 /** Analyze a definition. |
518 /** Analyze a definition. |
517 */ |
519 */ |
518 void scanDef(JCTree tree) { |
520 void scanDef(JCTree tree) { |
519 scanStat(tree); |
521 scanStat(tree); |
520 if (tree != null && tree.getTag() == JCTree.BLOCK && !alive) { |
522 if (tree != null && tree.hasTag(JCTree.Tag.BLOCK) && !alive) { |
521 log.error(tree.pos(), |
523 log.error(tree.pos(), |
522 "initializer.must.be.able.to.complete.normally"); |
524 "initializer.must.be.able.to.complete.normally"); |
523 } |
525 } |
524 } |
526 } |
525 |
527 |
526 /** Analyze a statement. Check that statement is reachable. |
528 /** Analyze a statement. Check that statement is reachable. |
527 */ |
529 */ |
528 void scanStat(JCTree tree) { |
530 void scanStat(JCTree tree) { |
529 if (!alive && tree != null) { |
531 if (!alive && tree != null) { |
530 log.error(tree.pos(), "unreachable.stmt"); |
532 log.error(tree.pos(), "unreachable.stmt"); |
531 if (tree.getTag() != JCTree.SKIP) alive = true; |
533 if (!tree.hasTag(SKIP)) alive = true; |
532 } |
534 } |
533 scan(tree); |
535 scan(tree); |
534 } |
536 } |
535 |
537 |
536 /** Analyze list of statements. |
538 /** Analyze list of statements. |
612 lint = lint.augment(tree.sym.attributes_field); |
614 lint = lint.augment(tree.sym.attributes_field); |
613 |
615 |
614 try { |
616 try { |
615 // define all the static fields |
617 // define all the static fields |
616 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { |
618 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { |
617 if (l.head.getTag() == JCTree.VARDEF) { |
619 if (l.head.hasTag(VARDEF)) { |
618 JCVariableDecl def = (JCVariableDecl)l.head; |
620 JCVariableDecl def = (JCVariableDecl)l.head; |
619 if ((def.mods.flags & STATIC) != 0) { |
621 if ((def.mods.flags & STATIC) != 0) { |
620 VarSymbol sym = def.sym; |
622 VarSymbol sym = def.sym; |
621 if (trackable(sym)) |
623 if (trackable(sym)) |
622 newVar(sym); |
624 newVar(sym); |
651 } |
653 } |
652 } |
654 } |
653 |
655 |
654 // define all the instance fields |
656 // define all the instance fields |
655 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { |
657 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { |
656 if (l.head.getTag() == JCTree.VARDEF) { |
658 if (l.head.hasTag(VARDEF)) { |
657 JCVariableDecl def = (JCVariableDecl)l.head; |
659 JCVariableDecl def = (JCVariableDecl)l.head; |
658 if ((def.mods.flags & STATIC) == 0) { |
660 if ((def.mods.flags & STATIC) == 0) { |
659 VarSymbol sym = def.sym; |
661 VarSymbol sym = def.sym; |
660 if (trackable(sym)) |
662 if (trackable(sym)) |
661 newVar(sym); |
663 newVar(sym); |
758 pendingExits = new ListBuffer<PendingExit>(); |
760 pendingExits = new ListBuffer<PendingExit>(); |
759 while (exits.nonEmpty()) { |
761 while (exits.nonEmpty()) { |
760 PendingExit exit = exits.head; |
762 PendingExit exit = exits.head; |
761 exits = exits.tail; |
763 exits = exits.tail; |
762 if (exit.thrown == null) { |
764 if (exit.thrown == null) { |
763 Assert.check(exit.tree.getTag() == JCTree.RETURN); |
765 Assert.check(exit.tree.hasTag(RETURN)); |
764 if (isInitialConstructor) { |
766 if (isInitialConstructor) { |
765 inits = exit.inits; |
767 inits = exit.inits; |
766 for (int i = firstadr; i < nextadr; i++) |
768 for (int i = firstadr; i < nextadr; i++) |
767 checkInit(exit.tree.pos(), vars[i]); |
769 checkInit(exit.tree.pos(), vars[i]); |
768 } |
770 } |
987 /** Add any variables defined in stats to inits and uninits. */ |
989 /** Add any variables defined in stats to inits and uninits. */ |
988 private static void addVars(List<JCStatement> stats, Bits inits, |
990 private static void addVars(List<JCStatement> stats, Bits inits, |
989 Bits uninits) { |
991 Bits uninits) { |
990 for (;stats.nonEmpty(); stats = stats.tail) { |
992 for (;stats.nonEmpty(); stats = stats.tail) { |
991 JCTree stat = stats.head; |
993 JCTree stat = stats.head; |
992 if (stat.getTag() == JCTree.VARDEF) { |
994 if (stat.hasTag(VARDEF)) { |
993 int adr = ((JCVariableDecl) stat).sym.adr; |
995 int adr = ((JCVariableDecl) stat).sym.adr; |
994 inits.excl(adr); |
996 inits.excl(adr); |
995 uninits.incl(adr); |
997 uninits.incl(adr); |
996 } |
998 } |
997 } |
999 } |
1344 letInit(tree.lhs); |
1346 letInit(tree.lhs); |
1345 } |
1347 } |
1346 |
1348 |
1347 public void visitUnary(JCUnary tree) { |
1349 public void visitUnary(JCUnary tree) { |
1348 switch (tree.getTag()) { |
1350 switch (tree.getTag()) { |
1349 case JCTree.NOT: |
1351 case NOT: |
1350 scanCond(tree.arg); |
1352 scanCond(tree.arg); |
1351 Bits t = initsWhenFalse; |
1353 Bits t = initsWhenFalse; |
1352 initsWhenFalse = initsWhenTrue; |
1354 initsWhenFalse = initsWhenTrue; |
1353 initsWhenTrue = t; |
1355 initsWhenTrue = t; |
1354 t = uninitsWhenFalse; |
1356 t = uninitsWhenFalse; |
1355 uninitsWhenFalse = uninitsWhenTrue; |
1357 uninitsWhenFalse = uninitsWhenTrue; |
1356 uninitsWhenTrue = t; |
1358 uninitsWhenTrue = t; |
1357 break; |
1359 break; |
1358 case JCTree.PREINC: case JCTree.POSTINC: |
1360 case PREINC: case POSTINC: |
1359 case JCTree.PREDEC: case JCTree.POSTDEC: |
1361 case PREDEC: case POSTDEC: |
1360 scanExpr(tree.arg); |
1362 scanExpr(tree.arg); |
1361 letInit(tree.arg); |
1363 letInit(tree.arg); |
1362 break; |
1364 break; |
1363 default: |
1365 default: |
1364 scanExpr(tree.arg); |
1366 scanExpr(tree.arg); |
1365 } |
1367 } |
1366 } |
1368 } |
1367 |
1369 |
1368 public void visitBinary(JCBinary tree) { |
1370 public void visitBinary(JCBinary tree) { |
1369 switch (tree.getTag()) { |
1371 switch (tree.getTag()) { |
1370 case JCTree.AND: |
1372 case AND: |
1371 scanCond(tree.lhs); |
1373 scanCond(tree.lhs); |
1372 Bits initsWhenFalseLeft = initsWhenFalse; |
1374 Bits initsWhenFalseLeft = initsWhenFalse; |
1373 Bits uninitsWhenFalseLeft = uninitsWhenFalse; |
1375 Bits uninitsWhenFalseLeft = uninitsWhenFalse; |
1374 inits = initsWhenTrue; |
1376 inits = initsWhenTrue; |
1375 uninits = uninitsWhenTrue; |
1377 uninits = uninitsWhenTrue; |
1376 scanCond(tree.rhs); |
1378 scanCond(tree.rhs); |
1377 initsWhenFalse.andSet(initsWhenFalseLeft); |
1379 initsWhenFalse.andSet(initsWhenFalseLeft); |
1378 uninitsWhenFalse.andSet(uninitsWhenFalseLeft); |
1380 uninitsWhenFalse.andSet(uninitsWhenFalseLeft); |
1379 break; |
1381 break; |
1380 case JCTree.OR: |
1382 case OR: |
1381 scanCond(tree.lhs); |
1383 scanCond(tree.lhs); |
1382 Bits initsWhenTrueLeft = initsWhenTrue; |
1384 Bits initsWhenTrueLeft = initsWhenTrue; |
1383 Bits uninitsWhenTrueLeft = uninitsWhenTrue; |
1385 Bits uninitsWhenTrueLeft = uninitsWhenTrue; |
1384 inits = initsWhenFalse; |
1386 inits = initsWhenFalse; |
1385 uninits = uninitsWhenFalse; |
1387 uninits = uninitsWhenFalse; |
1416 } |
1418 } |
1417 //where |
1419 //where |
1418 private boolean is292targetTypeCast(JCTypeCast tree) { |
1420 private boolean is292targetTypeCast(JCTypeCast tree) { |
1419 boolean is292targetTypeCast = false; |
1421 boolean is292targetTypeCast = false; |
1420 JCExpression expr = TreeInfo.skipParens(tree.expr); |
1422 JCExpression expr = TreeInfo.skipParens(tree.expr); |
1421 if (expr.getTag() == JCTree.APPLY) { |
1423 if (expr.hasTag(APPLY)) { |
1422 JCMethodInvocation apply = (JCMethodInvocation)expr; |
1424 JCMethodInvocation apply = (JCMethodInvocation)expr; |
1423 Symbol sym = TreeInfo.symbol(apply.meth); |
1425 Symbol sym = TreeInfo.symbol(apply.meth); |
1424 is292targetTypeCast = sym != null && |
1426 is292targetTypeCast = sym != null && |
1425 sym.kind == MTH && |
1427 sym.kind == MTH && |
1426 (sym.flags() & POLYMORPHIC_SIGNATURE) != 0; |
1428 (sym.flags() & POLYMORPHIC_SIGNATURE) != 0; |