2817:976523f1d562 | 2820:7f6d6b80a58b |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. | 2 * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * | 4 * |
5 * This code is free software; you can redistribute it and/or modify it | 5 * This code is free software; you can redistribute it and/or modify it |
6 * under the terms of the GNU General Public License version 2 only, as | 6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. Oracle designates this | 7 * published by the Free Software Foundation. Oracle designates this |
351 | 351 |
352 PendingExit(JCTree tree) { | 352 PendingExit(JCTree tree) { |
353 this.tree = tree; | 353 this.tree = tree; |
354 } | 354 } |
355 | 355 |
356 void resolveJump(JCTree tree) { | 356 void resolveJump() { |
357 //do nothing | 357 //do nothing |
358 } | 358 } |
359 } | 359 } |
360 | 360 |
361 abstract void markDead(JCTree tree); | 361 abstract void markDead(); |
362 | 362 |
363 /** Record an outward transfer of control. */ | 363 /** Record an outward transfer of control. */ |
364 void recordExit(JCTree tree, P pe) { | 364 void recordExit(P pe) { |
365 pendingExits.append(pe); | 365 pendingExits.append(pe); |
366 markDead(tree); | 366 markDead(); |
367 } | 367 } |
368 | 368 |
369 /** Resolve all jumps of this statement. */ | 369 /** Resolve all jumps of this statement. */ |
370 private boolean resolveJump(JCTree tree, | 370 private boolean resolveJump(JCTree tree, |
371 ListBuffer<P> oldPendingExits, | 371 ListBuffer<P> oldPendingExits, |
375 pendingExits = oldPendingExits; | 375 pendingExits = oldPendingExits; |
376 for (; exits.nonEmpty(); exits = exits.tail) { | 376 for (; exits.nonEmpty(); exits = exits.tail) { |
377 P exit = exits.head; | 377 P exit = exits.head; |
378 if (exit.tree.hasTag(jk.treeTag) && | 378 if (exit.tree.hasTag(jk.treeTag) && |
379 jk.getTarget(exit.tree) == tree) { | 379 jk.getTarget(exit.tree) == tree) { |
380 exit.resolveJump(tree); | 380 exit.resolveJump(); |
381 resolved = true; | 381 resolved = true; |
382 } else { | 382 } else { |
383 pendingExits.append(exit); | 383 pendingExits.append(exit); |
384 } | 384 } |
385 } | 385 } |
418 * complete normally. | 418 * complete normally. |
419 */ | 419 */ |
420 private boolean alive; | 420 private boolean alive; |
421 | 421 |
422 @Override | 422 @Override |
423 void markDead(JCTree tree) { | 423 void markDead() { |
424 alive = false; | 424 alive = false; |
425 } | 425 } |
426 | 426 |
427 /************************************************************************* | 427 /************************************************************************* |
428 * Visitor methods for statements and definitions | 428 * Visitor methods for statements and definitions |
462 if (tree.sym == null) return; | 462 if (tree.sym == null) return; |
463 boolean alivePrev = alive; | 463 boolean alivePrev = alive; |
464 ListBuffer<PendingExit> pendingExitsPrev = pendingExits; | 464 ListBuffer<PendingExit> pendingExitsPrev = pendingExits; |
465 Lint lintPrev = lint; | 465 Lint lintPrev = lint; |
466 | 466 |
467 pendingExits = new ListBuffer<PendingExit>(); | 467 pendingExits = new ListBuffer<>(); |
468 lint = lint.augment(tree.sym); | 468 lint = lint.augment(tree.sym); |
469 | 469 |
470 try { | 470 try { |
471 // process all the static initializers | 471 // process all the static initializers |
472 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { | 472 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { |
511 | 511 |
512 if (alive && !tree.sym.type.getReturnType().hasTag(VOID)) | 512 if (alive && !tree.sym.type.getReturnType().hasTag(VOID)) |
513 log.error(TreeInfo.diagEndPos(tree.body), "missing.ret.stmt"); | 513 log.error(TreeInfo.diagEndPos(tree.body), "missing.ret.stmt"); |
514 | 514 |
515 List<PendingExit> exits = pendingExits.toList(); | 515 List<PendingExit> exits = pendingExits.toList(); |
516 pendingExits = new ListBuffer<PendingExit>(); | 516 pendingExits = new ListBuffer<>(); |
517 while (exits.nonEmpty()) { | 517 while (exits.nonEmpty()) { |
518 PendingExit exit = exits.head; | 518 PendingExit exit = exits.head; |
519 exits = exits.tail; | 519 exits = exits.tail; |
520 Assert.check(exit.tree.hasTag(RETURN)); | 520 Assert.check(exit.tree.hasTag(RETURN)); |
521 } | 521 } |
540 scanStats(tree.stats); | 540 scanStats(tree.stats); |
541 } | 541 } |
542 | 542 |
543 public void visitDoLoop(JCDoWhileLoop tree) { | 543 public void visitDoLoop(JCDoWhileLoop tree) { |
544 ListBuffer<PendingExit> prevPendingExits = pendingExits; | 544 ListBuffer<PendingExit> prevPendingExits = pendingExits; |
545 pendingExits = new ListBuffer<PendingExit>(); | 545 pendingExits = new ListBuffer<>(); |
546 scanStat(tree.body); | 546 scanStat(tree.body); |
547 alive |= resolveContinues(tree); | 547 alive |= resolveContinues(tree); |
548 scan(tree.cond); | 548 scan(tree.cond); |
549 alive = alive && !tree.cond.type.isTrue(); | 549 alive = alive && !tree.cond.type.isTrue(); |
550 alive |= resolveBreaks(tree, prevPendingExits); | 550 alive |= resolveBreaks(tree, prevPendingExits); |
551 } | 551 } |
552 | 552 |
553 public void visitWhileLoop(JCWhileLoop tree) { | 553 public void visitWhileLoop(JCWhileLoop tree) { |
554 ListBuffer<PendingExit> prevPendingExits = pendingExits; | 554 ListBuffer<PendingExit> prevPendingExits = pendingExits; |
555 pendingExits = new ListBuffer<PendingExit>(); | 555 pendingExits = new ListBuffer<>(); |
556 scan(tree.cond); | 556 scan(tree.cond); |
557 alive = !tree.cond.type.isFalse(); | 557 alive = !tree.cond.type.isFalse(); |
558 scanStat(tree.body); | 558 scanStat(tree.body); |
559 alive |= resolveContinues(tree); | 559 alive |= resolveContinues(tree); |
560 alive = resolveBreaks(tree, prevPendingExits) || | 560 alive = resolveBreaks(tree, prevPendingExits) || |
562 } | 562 } |
563 | 563 |
564 public void visitForLoop(JCForLoop tree) { | 564 public void visitForLoop(JCForLoop tree) { |
565 ListBuffer<PendingExit> prevPendingExits = pendingExits; | 565 ListBuffer<PendingExit> prevPendingExits = pendingExits; |
566 scanStats(tree.init); | 566 scanStats(tree.init); |
567 pendingExits = new ListBuffer<PendingExit>(); | 567 pendingExits = new ListBuffer<>(); |
568 if (tree.cond != null) { | 568 if (tree.cond != null) { |
569 scan(tree.cond); | 569 scan(tree.cond); |
570 alive = !tree.cond.type.isFalse(); | 570 alive = !tree.cond.type.isFalse(); |
571 } else { | 571 } else { |
572 alive = true; | 572 alive = true; |
580 | 580 |
581 public void visitForeachLoop(JCEnhancedForLoop tree) { | 581 public void visitForeachLoop(JCEnhancedForLoop tree) { |
582 visitVarDef(tree.var); | 582 visitVarDef(tree.var); |
583 ListBuffer<PendingExit> prevPendingExits = pendingExits; | 583 ListBuffer<PendingExit> prevPendingExits = pendingExits; |
584 scan(tree.expr); | 584 scan(tree.expr); |
585 pendingExits = new ListBuffer<PendingExit>(); | 585 pendingExits = new ListBuffer<>(); |
586 scanStat(tree.body); | 586 scanStat(tree.body); |
587 alive |= resolveContinues(tree); | 587 alive |= resolveContinues(tree); |
588 resolveBreaks(tree, prevPendingExits); | 588 resolveBreaks(tree, prevPendingExits); |
589 alive = true; | 589 alive = true; |
590 } | 590 } |
591 | 591 |
592 public void visitLabelled(JCLabeledStatement tree) { | 592 public void visitLabelled(JCLabeledStatement tree) { |
593 ListBuffer<PendingExit> prevPendingExits = pendingExits; | 593 ListBuffer<PendingExit> prevPendingExits = pendingExits; |
594 pendingExits = new ListBuffer<PendingExit>(); | 594 pendingExits = new ListBuffer<>(); |
595 scanStat(tree.body); | 595 scanStat(tree.body); |
596 alive |= resolveBreaks(tree, prevPendingExits); | 596 alive |= resolveBreaks(tree, prevPendingExits); |
597 } | 597 } |
598 | 598 |
599 public void visitSwitch(JCSwitch tree) { | 599 public void visitSwitch(JCSwitch tree) { |
600 ListBuffer<PendingExit> prevPendingExits = pendingExits; | 600 ListBuffer<PendingExit> prevPendingExits = pendingExits; |
601 pendingExits = new ListBuffer<PendingExit>(); | 601 pendingExits = new ListBuffer<>(); |
602 scan(tree.selector); | 602 scan(tree.selector); |
603 boolean hasDefault = false; | 603 boolean hasDefault = false; |
604 for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) { | 604 for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) { |
605 alive = true; | 605 alive = true; |
606 JCCase c = l.head; | 606 JCCase c = l.head; |
623 alive |= resolveBreaks(tree, prevPendingExits); | 623 alive |= resolveBreaks(tree, prevPendingExits); |
624 } | 624 } |
625 | 625 |
626 public void visitTry(JCTry tree) { | 626 public void visitTry(JCTry tree) { |
627 ListBuffer<PendingExit> prevPendingExits = pendingExits; | 627 ListBuffer<PendingExit> prevPendingExits = pendingExits; |
628 pendingExits = new ListBuffer<PendingExit>(); | 628 pendingExits = new ListBuffer<>(); |
629 for (JCTree resource : tree.resources) { | 629 for (JCTree resource : tree.resources) { |
630 if (resource instanceof JCVariableDecl) { | 630 if (resource instanceof JCVariableDecl) { |
631 JCVariableDecl vdecl = (JCVariableDecl) resource; | 631 JCVariableDecl vdecl = (JCVariableDecl) resource; |
632 visitVarDef(vdecl); | 632 visitVarDef(vdecl); |
633 } else if (resource instanceof JCExpression) { | 633 } else if (resource instanceof JCExpression) { |
686 alive = true; | 686 alive = true; |
687 } | 687 } |
688 } | 688 } |
689 | 689 |
690 public void visitBreak(JCBreak tree) { | 690 public void visitBreak(JCBreak tree) { |
691 recordExit(tree, new PendingExit(tree)); | 691 recordExit(new PendingExit(tree)); |
692 } | 692 } |
693 | 693 |
694 public void visitContinue(JCContinue tree) { | 694 public void visitContinue(JCContinue tree) { |
695 recordExit(tree, new PendingExit(tree)); | 695 recordExit(new PendingExit(tree)); |
696 } | 696 } |
697 | 697 |
698 public void visitReturn(JCReturn tree) { | 698 public void visitReturn(JCReturn tree) { |
699 scan(tree.expr); | 699 scan(tree.expr); |
700 recordExit(tree, new PendingExit(tree)); | 700 recordExit(new PendingExit(tree)); |
701 } | 701 } |
702 | 702 |
703 public void visitThrow(JCThrow tree) { | 703 public void visitThrow(JCThrow tree) { |
704 scan(tree.expr); | 704 scan(tree.expr); |
705 markDead(tree); | 705 markDead(); |
706 } | 706 } |
707 | 707 |
708 public void visitApply(JCMethodInvocation tree) { | 708 public void visitApply(JCMethodInvocation tree) { |
709 scan(tree.meth); | 709 scan(tree.meth); |
710 scan(tree.args); | 710 scan(tree.args); |
754 } | 754 } |
755 public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) { | 755 public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) { |
756 try { | 756 try { |
757 attrEnv = env; | 757 attrEnv = env; |
758 Flow.this.make = make; | 758 Flow.this.make = make; |
759 pendingExits = new ListBuffer<PendingExit>(); | 759 pendingExits = new ListBuffer<>(); |
760 alive = true; | 760 alive = true; |
761 scan(tree); | 761 scan(tree); |
762 } finally { | 762 } finally { |
763 pendingExits = null; | 763 pendingExits = null; |
764 Flow.this.make = null; | 764 Flow.this.make = null; |
801 this.thrown = thrown; | 801 this.thrown = thrown; |
802 } | 802 } |
803 } | 803 } |
804 | 804 |
805 @Override | 805 @Override |
806 void markDead(JCTree tree) { | 806 void markDead() { |
807 //do nothing | 807 //do nothing |
808 } | 808 } |
809 | 809 |
810 /*-------------------- Exceptions ----------------------*/ | 810 /*-------------------- Exceptions ----------------------*/ |
811 | 811 |
1199 return exc.tsym == syms.throwableType.tsym || | 1199 return exc.tsym == syms.throwableType.tsym || |
1200 exc.tsym == syms.exceptionType.tsym; | 1200 exc.tsym == syms.exceptionType.tsym; |
1201 } | 1201 } |
1202 | 1202 |
1203 public void visitBreak(JCBreak tree) { | 1203 public void visitBreak(JCBreak tree) { |
1204 recordExit(tree, new FlowPendingExit(tree, null)); | 1204 recordExit(new FlowPendingExit(tree, null)); |
1205 } | 1205 } |
1206 | 1206 |
1207 public void visitContinue(JCContinue tree) { | 1207 public void visitContinue(JCContinue tree) { |
1208 recordExit(tree, new FlowPendingExit(tree, null)); | 1208 recordExit(new FlowPendingExit(tree, null)); |
1209 } | 1209 } |
1210 | 1210 |
1211 public void visitReturn(JCReturn tree) { | 1211 public void visitReturn(JCReturn tree) { |
1212 scan(tree.expr); | 1212 scan(tree.expr); |
1213 recordExit(tree, new FlowPendingExit(tree, null)); | 1213 recordExit(new FlowPendingExit(tree, null)); |
1214 } | 1214 } |
1215 | 1215 |
1216 public void visitThrow(JCThrow tree) { | 1216 public void visitThrow(JCThrow tree) { |
1217 scan(tree.expr); | 1217 scan(tree.expr); |
1218 Symbol sym = TreeInfo.symbol(tree.expr); | 1218 Symbol sym = TreeInfo.symbol(tree.expr); |
1226 } | 1226 } |
1227 } | 1227 } |
1228 else { | 1228 else { |
1229 markThrown(tree, tree.expr.type); | 1229 markThrown(tree, tree.expr.type); |
1230 } | 1230 } |
1231 markDead(tree); | 1231 markDead(); |
1232 } | 1232 } |
1233 | 1233 |
1234 public void visitApply(JCMethodInvocation tree) { | 1234 public void visitApply(JCMethodInvocation tree) { |
1235 scan(tree.meth); | 1235 scan(tree.meth); |
1236 scan(tree.args); | 1236 scan(tree.args); |
1377 * which ensures that no final variable is assigned more than once. This visitor | 1377 * which ensures that no final variable is assigned more than once. This visitor |
1378 * depends on the results of the liveliness analyzer. This pass is also used to mark | 1378 * depends on the results of the liveliness analyzer. This pass is also used to mark |
1379 * effectively-final local variables/parameters. | 1379 * effectively-final local variables/parameters. |
1380 */ | 1380 */ |
1381 | 1381 |
1382 public abstract class AbstractAssignAnalyzer<P extends AbstractAssignAnalyzer<P>.AbstractAssignPendingExit> | 1382 public class AssignAnalyzer extends BaseAnalyzer<AssignAnalyzer.AssignPendingExit> { |
1383 extends BaseAnalyzer<P> { | |
1384 | |
1385 /** The set of definitely assigned variables. | 1383 /** The set of definitely assigned variables. |
1386 */ | 1384 */ |
1387 protected Bits inits; | 1385 final Bits inits; |
1388 | 1386 |
1389 /** The set of definitely unassigned variables. | 1387 /** The set of definitely unassigned variables. |
1390 */ | 1388 */ |
1391 final Bits uninits; | 1389 final Bits uninits; |
1392 | 1390 |
1430 | 1428 |
1431 /** The list of unreferenced automatic resources. | 1429 /** The list of unreferenced automatic resources. |
1432 */ | 1430 */ |
1433 Scope unrefdResources; | 1431 Scope unrefdResources; |
1434 | 1432 |
1435 /** Set when processing a loop body the second time for DU analysis. */ | 1433 /** Modified when processing a loop body the second time for DU analysis. */ |
1436 FlowKind flowKind = FlowKind.NORMAL; | 1434 FlowKind flowKind = FlowKind.NORMAL; |
1437 | 1435 |
1438 /** The starting position of the analysed tree */ | 1436 /** The starting position of the analyzed tree */ |
1439 int startPos; | 1437 int startPos; |
1440 | 1438 |
1441 public class AbstractAssignPendingExit extends BaseAnalyzer.PendingExit { | 1439 public class AssignPendingExit extends BaseAnalyzer.PendingExit { |
1442 | 1440 |
1443 final Bits inits; | 1441 final Bits inits; |
1444 final Bits uninits; | 1442 final Bits uninits; |
1445 final Bits exit_inits = new Bits(true); | 1443 final Bits exit_inits = new Bits(true); |
1446 final Bits exit_uninits = new Bits(true); | 1444 final Bits exit_uninits = new Bits(true); |
1447 | 1445 |
1448 public AbstractAssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) { | 1446 public AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) { |
1449 super(tree); | 1447 super(tree); |
1450 this.inits = inits; | 1448 this.inits = inits; |
1451 this.uninits = uninits; | 1449 this.uninits = uninits; |
1452 this.exit_inits.assign(inits); | 1450 this.exit_inits.assign(inits); |
1453 this.exit_uninits.assign(uninits); | 1451 this.exit_uninits.assign(uninits); |
1454 } | 1452 } |
1455 | 1453 |
1456 @Override | 1454 @Override |
1457 public void resolveJump(JCTree tree) { | 1455 void resolveJump() { |
1458 inits.andSet(exit_inits); | 1456 inits.andSet(exit_inits); |
1459 uninits.andSet(exit_uninits); | 1457 uninits.andSet(exit_uninits); |
1460 } | 1458 } |
1461 } | 1459 } |
1462 | 1460 |
1463 public AbstractAssignAnalyzer() { | 1461 public AssignAnalyzer() { |
1464 this.inits = new Bits(); | 1462 this.inits = new Bits(); |
1465 uninits = new Bits(); | 1463 uninits = new Bits(); |
1466 uninitsTry = new Bits(); | 1464 uninitsTry = new Bits(); |
1467 initsWhenTrue = new Bits(true); | 1465 initsWhenTrue = new Bits(true); |
1468 initsWhenFalse = new Bits(true); | 1466 initsWhenFalse = new Bits(true); |
1471 } | 1469 } |
1472 | 1470 |
1473 private boolean isInitialConstructor = false; | 1471 private boolean isInitialConstructor = false; |
1474 | 1472 |
1475 @Override | 1473 @Override |
1476 protected void markDead(JCTree tree) { | 1474 void markDead() { |
1477 if (!isInitialConstructor) { | 1475 if (!isInitialConstructor) { |
1478 inits.inclRange(returnadr, nextadr); | 1476 inits.inclRange(returnadr, nextadr); |
1479 } else { | 1477 } else { |
1480 for (int address = returnadr; address < nextadr; address++) { | 1478 for (int address = returnadr; address < nextadr; address++) { |
1481 if (!(isFinalUninitializedStaticField(vardecls[address].sym))) { | 1479 if (!(isFinalUninitializedStaticField(vardecls[address].sym))) { |
1518 if ((sym.flags() & FINAL) == 0) { | 1516 if ((sym.flags() & FINAL) == 0) { |
1519 sym.flags_field |= EFFECTIVELY_FINAL; | 1517 sym.flags_field |= EFFECTIVELY_FINAL; |
1520 } | 1518 } |
1521 sym.adr = nextadr; | 1519 sym.adr = nextadr; |
1522 vardecls[nextadr] = varDecl; | 1520 vardecls[nextadr] = varDecl; |
1523 exclVarFromInits(varDecl, nextadr); | 1521 inits.excl(nextadr); |
1524 uninits.incl(nextadr); | 1522 uninits.incl(nextadr); |
1525 nextadr++; | 1523 nextadr++; |
1526 } | 1524 } |
1527 | 1525 |
1528 protected void exclVarFromInits(JCTree tree, int adr) { | |
1529 inits.excl(adr); | |
1530 } | |
1531 | |
1532 protected void assignToInits(JCTree tree, Bits bits) { | |
1533 inits.assign(bits); | |
1534 } | |
1535 | |
1536 protected void andSetInits(JCTree tree, Bits bits) { | |
1537 inits.andSet(bits); | |
1538 } | |
1539 | |
1540 protected void orSetInits(JCTree tree, Bits bits) { | |
1541 inits.orSet(bits); | |
1542 } | |
1543 | |
1544 /** Record an initialization of a trackable variable. | 1526 /** Record an initialization of a trackable variable. |
1545 */ | 1527 */ |
1546 void letInit(DiagnosticPosition pos, VarSymbol sym) { | 1528 void letInit(DiagnosticPosition pos, VarSymbol sym) { |
1547 if (sym.adr >= firstadr && trackable(sym)) { | 1529 if (sym.adr >= firstadr && trackable(sym)) { |
1548 if (uninits.isMember(sym.adr)) { | 1530 if ((sym.flags() & EFFECTIVELY_FINAL) != 0) { |
1549 uninit(sym); | 1531 if (!uninits.isMember(sym.adr)) { |
1532 //assignment targeting an effectively final variable | |
1533 //makes the variable lose its status of effectively final | |
1534 //if the variable is _not_ definitively unassigned | |
1535 sym.flags_field &= ~EFFECTIVELY_FINAL; | |
1536 } else { | |
1537 uninit(sym); | |
1538 } | |
1539 } else if ((sym.flags() & FINAL) != 0) { | |
1540 if ((sym.flags() & PARAMETER) != 0) { | |
1541 if ((sym.flags() & UNION) != 0) { //multi-catch parameter | |
1542 log.error(pos, "multicatch.parameter.may.not.be.assigned", sym); | |
1543 } else { | |
1544 log.error(pos, "final.parameter.may.not.be.assigned", | |
1545 sym); | |
1546 } | |
1547 } else if (!uninits.isMember(sym.adr)) { | |
1548 log.error(pos, flowKind.errKey, sym); | |
1549 } else { | |
1550 uninit(sym); | |
1551 } | |
1550 } | 1552 } |
1551 inits.incl(sym.adr); | 1553 inits.incl(sym.adr); |
1554 } else if ((sym.flags() & FINAL) != 0) { | |
1555 log.error(pos, "var.might.already.be.assigned", sym); | |
1552 } | 1556 } |
1553 } | 1557 } |
1554 //where | 1558 //where |
1555 void uninit(VarSymbol sym) { | 1559 void uninit(VarSymbol sym) { |
1556 if (!inits.isMember(sym.adr)) { | 1560 if (!inits.isMember(sym.adr)) { |
1581 */ | 1585 */ |
1582 void checkInit(DiagnosticPosition pos, VarSymbol sym) { | 1586 void checkInit(DiagnosticPosition pos, VarSymbol sym) { |
1583 checkInit(pos, sym, "var.might.not.have.been.initialized"); | 1587 checkInit(pos, sym, "var.might.not.have.been.initialized"); |
1584 } | 1588 } |
1585 | 1589 |
1586 void checkInit(DiagnosticPosition pos, VarSymbol sym, String errkey) {} | 1590 void checkInit(DiagnosticPosition pos, VarSymbol sym, String errkey) { |
1591 if ((sym.adr >= firstadr || sym.owner.kind != TYP) && | |
1592 trackable(sym) && | |
1593 !inits.isMember(sym.adr)) { | |
1594 log.error(pos, errkey, sym); | |
1595 inits.incl(sym.adr); | |
1596 } | |
1597 } | |
1587 | 1598 |
1588 /** Utility method to reset several Bits instances. | 1599 /** Utility method to reset several Bits instances. |
1589 */ | 1600 */ |
1590 private void resetBits(Bits... bits) { | 1601 private void resetBits(Bits... bits) { |
1591 for (Bits b : bits) { | 1602 for (Bits b : bits) { |
1605 } | 1616 } |
1606 } | 1617 } |
1607 | 1618 |
1608 /** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets. | 1619 /** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets. |
1609 */ | 1620 */ |
1610 protected void merge(JCTree tree) { | 1621 protected void merge() { |
1611 inits.assign(initsWhenFalse.andSet(initsWhenTrue)); | 1622 inits.assign(initsWhenFalse.andSet(initsWhenTrue)); |
1612 uninits.assign(uninitsWhenFalse.andSet(uninitsWhenTrue)); | 1623 uninits.assign(uninitsWhenFalse.andSet(uninitsWhenTrue)); |
1613 } | 1624 } |
1614 | 1625 |
1615 /* ************************************************************************ | 1626 /* ************************************************************************ |
1621 */ | 1632 */ |
1622 void scanExpr(JCTree tree) { | 1633 void scanExpr(JCTree tree) { |
1623 if (tree != null) { | 1634 if (tree != null) { |
1624 scan(tree); | 1635 scan(tree); |
1625 if (inits.isReset()) { | 1636 if (inits.isReset()) { |
1626 merge(tree); | 1637 merge(); |
1627 } | 1638 } |
1628 } | 1639 } |
1629 } | 1640 } |
1630 | 1641 |
1631 /** Analyze a list of expressions. | 1642 /** Analyze a list of expressions. |
1639 /** Analyze a condition. Make sure to set (un)initsWhenTrue(WhenFalse) | 1650 /** Analyze a condition. Make sure to set (un)initsWhenTrue(WhenFalse) |
1640 * rather than (un)inits on exit. | 1651 * rather than (un)inits on exit. |
1641 */ | 1652 */ |
1642 void scanCond(JCTree tree) { | 1653 void scanCond(JCTree tree) { |
1643 if (tree.type.isFalse()) { | 1654 if (tree.type.isFalse()) { |
1644 if (inits.isReset()) merge(tree); | 1655 if (inits.isReset()) merge(); |
1645 initsWhenTrue.assign(inits); | 1656 initsWhenTrue.assign(inits); |
1646 initsWhenTrue.inclRange(firstadr, nextadr); | 1657 initsWhenTrue.inclRange(firstadr, nextadr); |
1647 uninitsWhenTrue.assign(uninits); | 1658 uninitsWhenTrue.assign(uninits); |
1648 uninitsWhenTrue.inclRange(firstadr, nextadr); | 1659 uninitsWhenTrue.inclRange(firstadr, nextadr); |
1649 initsWhenFalse.assign(inits); | 1660 initsWhenFalse.assign(inits); |
1650 uninitsWhenFalse.assign(uninits); | 1661 uninitsWhenFalse.assign(uninits); |
1651 } else if (tree.type.isTrue()) { | 1662 } else if (tree.type.isTrue()) { |
1652 if (inits.isReset()) merge(tree); | 1663 if (inits.isReset()) merge(); |
1653 initsWhenFalse.assign(inits); | 1664 initsWhenFalse.assign(inits); |
1654 initsWhenFalse.inclRange(firstadr, nextadr); | 1665 initsWhenFalse.inclRange(firstadr, nextadr); |
1655 uninitsWhenFalse.assign(uninits); | 1666 uninitsWhenFalse.assign(uninits); |
1656 uninitsWhenFalse.inclRange(firstadr, nextadr); | 1667 uninitsWhenFalse.inclRange(firstadr, nextadr); |
1657 initsWhenTrue.assign(inits); | 1668 initsWhenTrue.assign(inits); |
1666 } | 1677 } |
1667 } | 1678 } |
1668 | 1679 |
1669 /* ------------ Visitor methods for various sorts of trees -------------*/ | 1680 /* ------------ Visitor methods for various sorts of trees -------------*/ |
1670 | 1681 |
1671 @Override | |
1672 public void visitClassDef(JCClassDecl tree) { | 1682 public void visitClassDef(JCClassDecl tree) { |
1673 if (tree.sym == null) { | 1683 if (tree.sym == null) { |
1674 return; | 1684 return; |
1675 } | 1685 } |
1676 | 1686 |
1677 JCClassDecl classDefPrev = classDef; | 1687 Lint lintPrev = lint; |
1678 int firstadrPrev = firstadr; | 1688 lint = lint.augment(tree.sym); |
1679 int nextadrPrev = nextadr; | |
1680 ListBuffer<P> pendingExitsPrev = pendingExits; | |
1681 | |
1682 pendingExits = new ListBuffer<P>(); | |
1683 if (tree.name != names.empty) { | |
1684 firstadr = nextadr; | |
1685 } | |
1686 classDef = tree; | |
1687 try { | 1689 try { |
1688 // define all the static fields | 1690 if (tree.sym == null) { |
1689 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { | 1691 return; |
1690 if (l.head.hasTag(VARDEF)) { | 1692 } |
1691 JCVariableDecl def = (JCVariableDecl)l.head; | 1693 |
1692 if ((def.mods.flags & STATIC) != 0) { | 1694 JCClassDecl classDefPrev = classDef; |
1693 VarSymbol sym = def.sym; | 1695 int firstadrPrev = firstadr; |
1694 if (trackable(sym)) { | 1696 int nextadrPrev = nextadr; |
1695 newVar(def); | 1697 ListBuffer<AssignPendingExit> pendingExitsPrev = pendingExits; |
1698 | |
1699 pendingExits = new ListBuffer<>(); | |
1700 if (tree.name != names.empty) { | |
1701 firstadr = nextadr; | |
1702 } | |
1703 classDef = tree; | |
1704 try { | |
1705 // define all the static fields | |
1706 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { | |
1707 if (l.head.hasTag(VARDEF)) { | |
1708 JCVariableDecl def = (JCVariableDecl)l.head; | |
1709 if ((def.mods.flags & STATIC) != 0) { | |
1710 VarSymbol sym = def.sym; | |
1711 if (trackable(sym)) { | |
1712 newVar(def); | |
1713 } | |
1696 } | 1714 } |
1697 } | 1715 } |
1698 } | 1716 } |
1699 } | 1717 |
1700 | 1718 // process all the static initializers |
1701 // process all the static initializers | 1719 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { |
1702 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { | 1720 if (!l.head.hasTag(METHODDEF) && |
1703 if (!l.head.hasTag(METHODDEF) && | 1721 (TreeInfo.flags(l.head) & STATIC) != 0) { |
1704 (TreeInfo.flags(l.head) & STATIC) != 0) { | 1722 scan(l.head); |
1705 scan(l.head); | 1723 } |
1706 } | 1724 } |
1707 } | 1725 |
1708 | 1726 // define all the instance fields |
1709 // define all the instance fields | 1727 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { |
1710 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { | 1728 if (l.head.hasTag(VARDEF)) { |
1711 if (l.head.hasTag(VARDEF)) { | 1729 JCVariableDecl def = (JCVariableDecl)l.head; |
1712 JCVariableDecl def = (JCVariableDecl)l.head; | 1730 if ((def.mods.flags & STATIC) == 0) { |
1713 if ((def.mods.flags & STATIC) == 0) { | 1731 VarSymbol sym = def.sym; |
1714 VarSymbol sym = def.sym; | 1732 if (trackable(sym)) { |
1715 if (trackable(sym)) { | 1733 newVar(def); |
1716 newVar(def); | 1734 } |
1717 } | 1735 } |
1718 } | 1736 } |
1719 } | 1737 } |
1720 } | 1738 // process all the instance initializers |
1721 | 1739 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { |
1722 // process all the instance initializers | 1740 if (!l.head.hasTag(METHODDEF) && |
1723 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { | 1741 (TreeInfo.flags(l.head) & STATIC) == 0) { |
1724 if (!l.head.hasTag(METHODDEF) && | 1742 scan(l.head); |
1725 (TreeInfo.flags(l.head) & STATIC) == 0) { | 1743 } |
1726 scan(l.head); | 1744 } |
1727 } | 1745 |
1728 } | 1746 // process all the methods |
1729 | 1747 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { |
1730 // process all the methods | 1748 if (l.head.hasTag(METHODDEF)) { |
1731 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { | 1749 scan(l.head); |
1732 if (l.head.hasTag(METHODDEF)) { | 1750 } |
1733 scan(l.head); | 1751 } |
1734 } | 1752 } finally { |
1753 pendingExits = pendingExitsPrev; | |
1754 nextadr = nextadrPrev; | |
1755 firstadr = firstadrPrev; | |
1756 classDef = classDefPrev; | |
1735 } | 1757 } |
1736 } finally { | 1758 } finally { |
1737 pendingExits = pendingExitsPrev; | 1759 lint = lintPrev; |
1738 nextadr = nextadrPrev; | 1760 } |
1739 firstadr = firstadrPrev; | 1761 } |
1740 classDef = classDefPrev; | 1762 |
1741 } | |
1742 } | |
1743 | |
1744 @Override | |
1745 public void visitMethodDef(JCMethodDecl tree) { | 1763 public void visitMethodDef(JCMethodDecl tree) { |
1746 if (tree.body == null) { | 1764 if (tree.body == null) { |
1747 return; | 1765 return; |
1748 } | 1766 } |
1749 /* Ignore synthetic methods, except for translated lambda methods. | 1767 |
1768 /* MemberEnter can generate synthetic methods ignore them | |
1750 */ | 1769 */ |
1751 if ((tree.sym.flags() & (SYNTHETIC | LAMBDA_METHOD)) == SYNTHETIC) { | 1770 if ((tree.sym.flags() & SYNTHETIC) != 0) { |
1752 return; | 1771 return; |
1753 } | 1772 } |
1754 | 1773 |
1755 final Bits initsPrev = new Bits(inits); | 1774 Lint lintPrev = lint; |
1756 final Bits uninitsPrev = new Bits(uninits); | 1775 lint = lint.augment(tree.sym); |
1757 int nextadrPrev = nextadr; | |
1758 int firstadrPrev = firstadr; | |
1759 int returnadrPrev = returnadr; | |
1760 | |
1761 Assert.check(pendingExits.isEmpty()); | |
1762 boolean lastInitialConstructor = isInitialConstructor; | |
1763 try { | 1776 try { |
1764 isInitialConstructor = TreeInfo.isInitialConstructor(tree); | 1777 if (tree.body == null) { |
1765 | 1778 return; |
1766 if (!isInitialConstructor) { | 1779 } |
1767 firstadr = nextadr; | 1780 /* Ignore synthetic methods, except for translated lambda methods. |
1768 } | 1781 */ |
1769 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) { | 1782 if ((tree.sym.flags() & (SYNTHETIC | LAMBDA_METHOD)) == SYNTHETIC) { |
1770 JCVariableDecl def = l.head; | 1783 return; |
1771 scan(def); | 1784 } |
1772 Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag"); | 1785 |
1773 /* If we are executing the code from Gen, then there can be | 1786 final Bits initsPrev = new Bits(inits); |
1774 * synthetic or mandated variables, ignore them. | 1787 final Bits uninitsPrev = new Bits(uninits); |
1775 */ | 1788 int nextadrPrev = nextadr; |
1776 initParam(def); | 1789 int firstadrPrev = firstadr; |
1777 } | 1790 int returnadrPrev = returnadr; |
1778 // else we are in an instance initializer block; | 1791 |
1779 // leave caught unchanged. | 1792 Assert.check(pendingExits.isEmpty()); |
1780 scan(tree.body); | 1793 boolean lastInitialConstructor = isInitialConstructor; |
1781 | 1794 try { |
1782 if (isInitialConstructor) { | 1795 isInitialConstructor = TreeInfo.isInitialConstructor(tree); |
1783 boolean isSynthesized = (tree.sym.flags() & | 1796 |
1784 GENERATEDCONSTR) != 0; | 1797 if (!isInitialConstructor) { |
1785 for (int i = firstadr; i < nextadr; i++) { | 1798 firstadr = nextadr; |
1786 JCVariableDecl vardecl = vardecls[i]; | 1799 } |
1787 VarSymbol var = vardecl.sym; | 1800 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) { |
1788 if (var.owner == classDef.sym) { | 1801 JCVariableDecl def = l.head; |
1789 // choose the diagnostic position based on whether | 1802 scan(def); |
1790 // the ctor is default(synthesized) or not | 1803 Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag"); |
1791 if (isSynthesized) { | 1804 /* If we are executing the code from Gen, then there can be |
1792 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), | 1805 * synthetic or mandated variables, ignore them. |
1793 var, "var.not.initialized.in.default.constructor"); | 1806 */ |
1794 } else { | 1807 initParam(def); |
1795 checkInit(TreeInfo.diagEndPos(tree.body), var); | 1808 } |
1809 // else we are in an instance initializer block; | |
1810 // leave caught unchanged. | |
1811 scan(tree.body); | |
1812 | |
1813 if (isInitialConstructor) { | |
1814 boolean isSynthesized = (tree.sym.flags() & | |
1815 GENERATEDCONSTR) != 0; | |
1816 for (int i = firstadr; i < nextadr; i++) { | |
1817 JCVariableDecl vardecl = vardecls[i]; | |
1818 VarSymbol var = vardecl.sym; | |
1819 if (var.owner == classDef.sym) { | |
1820 // choose the diagnostic position based on whether | |
1821 // the ctor is default(synthesized) or not | |
1822 if (isSynthesized) { | |
1823 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), | |
1824 var, "var.not.initialized.in.default.constructor"); | |
1825 } else { | |
1826 checkInit(TreeInfo.diagEndPos(tree.body), var); | |
1827 } | |
1796 } | 1828 } |
1797 } | 1829 } |
1798 } | 1830 } |
1799 } | 1831 List<AssignPendingExit> exits = pendingExits.toList(); |
1800 List<P> exits = pendingExits.toList(); | 1832 pendingExits = new ListBuffer<>(); |
1801 pendingExits = new ListBuffer<>(); | 1833 while (exits.nonEmpty()) { |
1802 while (exits.nonEmpty()) { | 1834 AssignPendingExit exit = exits.head; |
1803 P exit = exits.head; | 1835 exits = exits.tail; |
1804 exits = exits.tail; | 1836 Assert.check(exit.tree.hasTag(RETURN), exit.tree); |
1805 Assert.check(exit.tree.hasTag(RETURN), exit.tree); | 1837 if (isInitialConstructor) { |
1806 if (isInitialConstructor) { | 1838 inits.assign(exit.exit_inits); |
1807 assignToInits(exit.tree, exit.exit_inits); | 1839 for (int i = firstadr; i < nextadr; i++) { |
1808 for (int i = firstadr; i < nextadr; i++) { | 1840 checkInit(exit.tree.pos(), vardecls[i].sym); |
1809 checkInit(exit.tree.pos(), vardecls[i].sym); | 1841 } |
1810 } | 1842 } |
1811 } | 1843 } |
1844 } finally { | |
1845 inits.assign(initsPrev); | |
1846 uninits.assign(uninitsPrev); | |
1847 nextadr = nextadrPrev; | |
1848 firstadr = firstadrPrev; | |
1849 returnadr = returnadrPrev; | |
1850 isInitialConstructor = lastInitialConstructor; | |
1812 } | 1851 } |
1813 } finally { | 1852 } finally { |
1814 assignToInits(tree, initsPrev); | 1853 lint = lintPrev; |
1815 uninits.assign(uninitsPrev); | |
1816 nextadr = nextadrPrev; | |
1817 firstadr = firstadrPrev; | |
1818 returnadr = returnadrPrev; | |
1819 isInitialConstructor = lastInitialConstructor; | |
1820 } | 1854 } |
1821 } | 1855 } |
1822 | 1856 |
1823 protected void initParam(JCVariableDecl def) { | 1857 protected void initParam(JCVariableDecl def) { |
1824 inits.incl(def.sym.adr); | 1858 inits.incl(def.sym.adr); |
1825 uninits.excl(def.sym.adr); | 1859 uninits.excl(def.sym.adr); |
1826 } | 1860 } |
1827 | 1861 |
1828 public void visitVarDef(JCVariableDecl tree) { | 1862 public void visitVarDef(JCVariableDecl tree) { |
1829 boolean track = trackable(tree.sym); | 1863 Lint lintPrev = lint; |
1830 if (track && tree.sym.owner.kind == MTH) { | 1864 lint = lint.augment(tree.sym); |
1831 newVar(tree); | 1865 try{ |
1832 } | 1866 boolean track = trackable(tree.sym); |
1833 if (tree.init != null) { | 1867 if (track && tree.sym.owner.kind == MTH) { |
1834 scanExpr(tree.init); | 1868 newVar(tree); |
1835 if (track) { | 1869 } |
1836 letInit(tree.pos(), tree.sym); | 1870 if (tree.init != null) { |
1837 } | 1871 scanExpr(tree.init); |
1872 if (track) { | |
1873 letInit(tree.pos(), tree.sym); | |
1874 } | |
1875 } | |
1876 } finally { | |
1877 lint = lintPrev; | |
1838 } | 1878 } |
1839 } | 1879 } |
1840 | 1880 |
1841 public void visitBlock(JCBlock tree) { | 1881 public void visitBlock(JCBlock tree) { |
1842 int nextadrPrev = nextadr; | 1882 int nextadrPrev = nextadr; |
1843 scan(tree.stats); | 1883 scan(tree.stats); |
1844 nextadr = nextadrPrev; | 1884 nextadr = nextadrPrev; |
1845 } | 1885 } |
1846 | 1886 |
1847 int getLogNumberOfErrors() { | |
1848 return 0; | |
1849 } | |
1850 | |
1851 public void visitDoLoop(JCDoWhileLoop tree) { | 1887 public void visitDoLoop(JCDoWhileLoop tree) { |
1852 ListBuffer<P> prevPendingExits = pendingExits; | 1888 ListBuffer<AssignPendingExit> prevPendingExits = pendingExits; |
1853 FlowKind prevFlowKind = flowKind; | 1889 FlowKind prevFlowKind = flowKind; |
1854 flowKind = FlowKind.NORMAL; | 1890 flowKind = FlowKind.NORMAL; |
1855 final Bits initsSkip = new Bits(true); | 1891 final Bits initsSkip = new Bits(true); |
1856 final Bits uninitsSkip = new Bits(true); | 1892 final Bits uninitsSkip = new Bits(true); |
1857 pendingExits = new ListBuffer<P>(); | 1893 pendingExits = new ListBuffer<>(); |
1858 int prevErrors = getLogNumberOfErrors(); | 1894 int prevErrors = log.nerrors; |
1859 do { | 1895 do { |
1860 final Bits uninitsEntry = new Bits(uninits); | 1896 final Bits uninitsEntry = new Bits(uninits); |
1861 uninitsEntry.excludeFrom(nextadr); | 1897 uninitsEntry.excludeFrom(nextadr); |
1862 scan(tree.body); | 1898 scan(tree.body); |
1863 resolveContinues(tree); | 1899 resolveContinues(tree); |
1864 scanCond(tree.cond); | 1900 scanCond(tree.cond); |
1865 if (!flowKind.isFinal()) { | 1901 if (!flowKind.isFinal()) { |
1866 initsSkip.assign(initsWhenFalse); | 1902 initsSkip.assign(initsWhenFalse); |
1867 uninitsSkip.assign(uninitsWhenFalse); | 1903 uninitsSkip.assign(uninitsWhenFalse); |
1868 } | 1904 } |
1869 if (getLogNumberOfErrors() != prevErrors || | 1905 if (log.nerrors != prevErrors || |
1870 flowKind.isFinal() || | 1906 flowKind.isFinal() || |
1871 new Bits(uninitsEntry).diffSet(uninitsWhenTrue).nextBit(firstadr)==-1) | 1907 new Bits(uninitsEntry).diffSet(uninitsWhenTrue).nextBit(firstadr)==-1) |
1872 break; | 1908 break; |
1873 assignToInits(tree.cond, initsWhenTrue); | 1909 inits.assign(initsWhenTrue); |
1874 uninits.assign(uninitsEntry.andSet(uninitsWhenTrue)); | 1910 uninits.assign(uninitsEntry.andSet(uninitsWhenTrue)); |
1875 flowKind = FlowKind.SPECULATIVE_LOOP; | 1911 flowKind = FlowKind.SPECULATIVE_LOOP; |
1876 } while (true); | 1912 } while (true); |
1877 flowKind = prevFlowKind; | 1913 flowKind = prevFlowKind; |
1878 assignToInits(tree, initsSkip); | 1914 inits.assign(initsSkip); |
1879 uninits.assign(uninitsSkip); | 1915 uninits.assign(uninitsSkip); |
1880 resolveBreaks(tree, prevPendingExits); | 1916 resolveBreaks(tree, prevPendingExits); |
1881 } | 1917 } |
1882 | 1918 |
1883 public void visitWhileLoop(JCWhileLoop tree) { | 1919 public void visitWhileLoop(JCWhileLoop tree) { |
1884 ListBuffer<P> prevPendingExits = pendingExits; | 1920 ListBuffer<AssignPendingExit> prevPendingExits = pendingExits; |
1885 FlowKind prevFlowKind = flowKind; | 1921 FlowKind prevFlowKind = flowKind; |
1886 flowKind = FlowKind.NORMAL; | 1922 flowKind = FlowKind.NORMAL; |
1887 final Bits initsSkip = new Bits(true); | 1923 final Bits initsSkip = new Bits(true); |
1888 final Bits uninitsSkip = new Bits(true); | 1924 final Bits uninitsSkip = new Bits(true); |
1889 pendingExits = new ListBuffer<>(); | 1925 pendingExits = new ListBuffer<>(); |
1890 int prevErrors = getLogNumberOfErrors(); | 1926 int prevErrors = log.nerrors; |
1891 final Bits uninitsEntry = new Bits(uninits); | 1927 final Bits uninitsEntry = new Bits(uninits); |
1892 uninitsEntry.excludeFrom(nextadr); | 1928 uninitsEntry.excludeFrom(nextadr); |
1893 do { | 1929 do { |
1894 scanCond(tree.cond); | 1930 scanCond(tree.cond); |
1895 if (!flowKind.isFinal()) { | 1931 if (!flowKind.isFinal()) { |
1896 initsSkip.assign(initsWhenFalse) ; | 1932 initsSkip.assign(initsWhenFalse) ; |
1897 uninitsSkip.assign(uninitsWhenFalse); | 1933 uninitsSkip.assign(uninitsWhenFalse); |
1898 } | 1934 } |
1899 assignToInits(tree, initsWhenTrue); | 1935 inits.assign(initsWhenTrue); |
1900 uninits.assign(uninitsWhenTrue); | 1936 uninits.assign(uninitsWhenTrue); |
1901 scan(tree.body); | 1937 scan(tree.body); |
1902 resolveContinues(tree); | 1938 resolveContinues(tree); |
1903 if (getLogNumberOfErrors() != prevErrors || | 1939 if (log.nerrors != prevErrors || |
1904 flowKind.isFinal() || | 1940 flowKind.isFinal() || |
1905 new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1) { | 1941 new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1) { |
1906 break; | 1942 break; |
1907 } | 1943 } |
1908 uninits.assign(uninitsEntry.andSet(uninits)); | 1944 uninits.assign(uninitsEntry.andSet(uninits)); |
1909 flowKind = FlowKind.SPECULATIVE_LOOP; | 1945 flowKind = FlowKind.SPECULATIVE_LOOP; |
1910 } while (true); | 1946 } while (true); |
1911 flowKind = prevFlowKind; | 1947 flowKind = prevFlowKind; |
1912 //a variable is DA/DU after the while statement, if it's DA/DU assuming the | 1948 //a variable is DA/DU after the while statement, if it's DA/DU assuming the |
1913 //branch is not taken AND if it's DA/DU before any break statement | 1949 //branch is not taken AND if it's DA/DU before any break statement |
1914 assignToInits(tree.body, initsSkip); | 1950 inits.assign(initsSkip); |
1915 uninits.assign(uninitsSkip); | 1951 uninits.assign(uninitsSkip); |
1916 resolveBreaks(tree, prevPendingExits); | 1952 resolveBreaks(tree, prevPendingExits); |
1917 } | 1953 } |
1918 | 1954 |
1919 public void visitForLoop(JCForLoop tree) { | 1955 public void visitForLoop(JCForLoop tree) { |
1920 ListBuffer<P> prevPendingExits = pendingExits; | 1956 ListBuffer<AssignPendingExit> prevPendingExits = pendingExits; |
1921 FlowKind prevFlowKind = flowKind; | 1957 FlowKind prevFlowKind = flowKind; |
1922 flowKind = FlowKind.NORMAL; | 1958 flowKind = FlowKind.NORMAL; |
1923 int nextadrPrev = nextadr; | 1959 int nextadrPrev = nextadr; |
1924 scan(tree.init); | 1960 scan(tree.init); |
1925 final Bits initsSkip = new Bits(true); | 1961 final Bits initsSkip = new Bits(true); |
1926 final Bits uninitsSkip = new Bits(true); | 1962 final Bits uninitsSkip = new Bits(true); |
1927 pendingExits = new ListBuffer<P>(); | 1963 pendingExits = new ListBuffer<>(); |
1928 int prevErrors = getLogNumberOfErrors(); | 1964 int prevErrors = log.nerrors; |
1929 do { | 1965 do { |
1930 final Bits uninitsEntry = new Bits(uninits); | 1966 final Bits uninitsEntry = new Bits(uninits); |
1931 uninitsEntry.excludeFrom(nextadr); | 1967 uninitsEntry.excludeFrom(nextadr); |
1932 if (tree.cond != null) { | 1968 if (tree.cond != null) { |
1933 scanCond(tree.cond); | 1969 scanCond(tree.cond); |
1934 if (!flowKind.isFinal()) { | 1970 if (!flowKind.isFinal()) { |
1935 initsSkip.assign(initsWhenFalse); | 1971 initsSkip.assign(initsWhenFalse); |
1936 uninitsSkip.assign(uninitsWhenFalse); | 1972 uninitsSkip.assign(uninitsWhenFalse); |
1937 } | 1973 } |
1938 assignToInits(tree.body, initsWhenTrue); | 1974 inits.assign(initsWhenTrue); |
1939 uninits.assign(uninitsWhenTrue); | 1975 uninits.assign(uninitsWhenTrue); |
1940 } else if (!flowKind.isFinal()) { | 1976 } else if (!flowKind.isFinal()) { |
1941 initsSkip.assign(inits); | 1977 initsSkip.assign(inits); |
1942 initsSkip.inclRange(firstadr, nextadr); | 1978 initsSkip.inclRange(firstadr, nextadr); |
1943 uninitsSkip.assign(uninits); | 1979 uninitsSkip.assign(uninits); |
1944 uninitsSkip.inclRange(firstadr, nextadr); | 1980 uninitsSkip.inclRange(firstadr, nextadr); |
1945 } | 1981 } |
1946 scan(tree.body); | 1982 scan(tree.body); |
1947 resolveContinues(tree); | 1983 resolveContinues(tree); |
1948 scan(tree.step); | 1984 scan(tree.step); |
1949 if (getLogNumberOfErrors() != prevErrors || | 1985 if (log.nerrors != prevErrors || |
1950 flowKind.isFinal() || | 1986 flowKind.isFinal() || |
1951 new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1) | 1987 new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1) |
1952 break; | 1988 break; |
1953 uninits.assign(uninitsEntry.andSet(uninits)); | 1989 uninits.assign(uninitsEntry.andSet(uninits)); |
1954 flowKind = FlowKind.SPECULATIVE_LOOP; | 1990 flowKind = FlowKind.SPECULATIVE_LOOP; |
1955 } while (true); | 1991 } while (true); |
1956 flowKind = prevFlowKind; | 1992 flowKind = prevFlowKind; |
1957 //a variable is DA/DU after a for loop, if it's DA/DU assuming the | 1993 //a variable is DA/DU after a for loop, if it's DA/DU assuming the |
1958 //branch is not taken AND if it's DA/DU before any break statement | 1994 //branch is not taken AND if it's DA/DU before any break statement |
1959 assignToInits(tree.body, initsSkip); | 1995 inits.assign(initsSkip); |
1960 uninits.assign(uninitsSkip); | 1996 uninits.assign(uninitsSkip); |
1961 resolveBreaks(tree, prevPendingExits); | 1997 resolveBreaks(tree, prevPendingExits); |
1962 nextadr = nextadrPrev; | 1998 nextadr = nextadrPrev; |
1963 } | 1999 } |
1964 | 2000 |
1965 public void visitForeachLoop(JCEnhancedForLoop tree) { | 2001 public void visitForeachLoop(JCEnhancedForLoop tree) { |
1966 visitVarDef(tree.var); | 2002 visitVarDef(tree.var); |
1967 | 2003 |
1968 ListBuffer<P> prevPendingExits = pendingExits; | 2004 ListBuffer<AssignPendingExit> prevPendingExits = pendingExits; |
1969 FlowKind prevFlowKind = flowKind; | 2005 FlowKind prevFlowKind = flowKind; |
1970 flowKind = FlowKind.NORMAL; | 2006 flowKind = FlowKind.NORMAL; |
1971 int nextadrPrev = nextadr; | 2007 int nextadrPrev = nextadr; |
1972 scan(tree.expr); | 2008 scan(tree.expr); |
1973 final Bits initsStart = new Bits(inits); | 2009 final Bits initsStart = new Bits(inits); |
1974 final Bits uninitsStart = new Bits(uninits); | 2010 final Bits uninitsStart = new Bits(uninits); |
1975 | 2011 |
1976 letInit(tree.pos(), tree.var.sym); | 2012 letInit(tree.pos(), tree.var.sym); |
1977 pendingExits = new ListBuffer<P>(); | 2013 pendingExits = new ListBuffer<>(); |
1978 int prevErrors = getLogNumberOfErrors(); | 2014 int prevErrors = log.nerrors; |
1979 do { | 2015 do { |
1980 final Bits uninitsEntry = new Bits(uninits); | 2016 final Bits uninitsEntry = new Bits(uninits); |
1981 uninitsEntry.excludeFrom(nextadr); | 2017 uninitsEntry.excludeFrom(nextadr); |
1982 scan(tree.body); | 2018 scan(tree.body); |
1983 resolveContinues(tree); | 2019 resolveContinues(tree); |
1984 if (getLogNumberOfErrors() != prevErrors || | 2020 if (log.nerrors != prevErrors || |
1985 flowKind.isFinal() || | 2021 flowKind.isFinal() || |
1986 new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1) | 2022 new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1) |
1987 break; | 2023 break; |
1988 uninits.assign(uninitsEntry.andSet(uninits)); | 2024 uninits.assign(uninitsEntry.andSet(uninits)); |
1989 flowKind = FlowKind.SPECULATIVE_LOOP; | 2025 flowKind = FlowKind.SPECULATIVE_LOOP; |
1990 } while (true); | 2026 } while (true); |
1991 flowKind = prevFlowKind; | 2027 flowKind = prevFlowKind; |
1992 assignToInits(tree.body, initsStart); | 2028 inits.assign(initsStart); |
1993 uninits.assign(uninitsStart.andSet(uninits)); | 2029 uninits.assign(uninitsStart.andSet(uninits)); |
1994 resolveBreaks(tree, prevPendingExits); | 2030 resolveBreaks(tree, prevPendingExits); |
1995 nextadr = nextadrPrev; | 2031 nextadr = nextadrPrev; |
1996 } | 2032 } |
1997 | 2033 |
1998 public void visitLabelled(JCLabeledStatement tree) { | 2034 public void visitLabelled(JCLabeledStatement tree) { |
1999 ListBuffer<P> prevPendingExits = pendingExits; | 2035 ListBuffer<AssignPendingExit> prevPendingExits = pendingExits; |
2000 pendingExits = new ListBuffer<P>(); | 2036 pendingExits = new ListBuffer<>(); |
2001 scan(tree.body); | 2037 scan(tree.body); |
2002 resolveBreaks(tree, prevPendingExits); | 2038 resolveBreaks(tree, prevPendingExits); |
2003 } | 2039 } |
2004 | 2040 |
2005 public void visitSwitch(JCSwitch tree) { | 2041 public void visitSwitch(JCSwitch tree) { |
2006 ListBuffer<P> prevPendingExits = pendingExits; | 2042 ListBuffer<AssignPendingExit> prevPendingExits = pendingExits; |
2007 pendingExits = new ListBuffer<>(); | 2043 pendingExits = new ListBuffer<>(); |
2008 int nextadrPrev = nextadr; | 2044 int nextadrPrev = nextadr; |
2009 scanExpr(tree.selector); | 2045 scanExpr(tree.selector); |
2010 final Bits initsSwitch = new Bits(inits); | 2046 final Bits initsSwitch = new Bits(inits); |
2011 final Bits uninitsSwitch = new Bits(uninits); | 2047 final Bits uninitsSwitch = new Bits(uninits); |
2012 boolean hasDefault = false; | 2048 boolean hasDefault = false; |
2013 for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) { | 2049 for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) { |
2014 assignToInits(l.head, initsSwitch); | 2050 inits.assign(initsSwitch); |
2015 uninits.assign(uninits.andSet(uninitsSwitch)); | 2051 uninits.assign(uninits.andSet(uninitsSwitch)); |
2016 JCCase c = l.head; | 2052 JCCase c = l.head; |
2017 if (c.pat == null) { | 2053 if (c.pat == null) { |
2018 hasDefault = true; | 2054 hasDefault = true; |
2019 } else { | 2055 } else { |
2020 scanExpr(c.pat); | 2056 scanExpr(c.pat); |
2021 } | 2057 } |
2022 if (hasDefault) { | 2058 if (hasDefault) { |
2023 assignToInits(null, initsSwitch); | 2059 inits.assign(initsSwitch); |
2024 uninits.assign(uninits.andSet(uninitsSwitch)); | 2060 uninits.assign(uninits.andSet(uninitsSwitch)); |
2025 } | 2061 } |
2026 scan(c.stats); | 2062 scan(c.stats); |
2027 addVars(c.stats, initsSwitch, uninitsSwitch); | 2063 addVars(c.stats, initsSwitch, uninitsSwitch); |
2028 if (!hasDefault) { | 2064 if (!hasDefault) { |
2029 assignToInits(l.head.stats.last(), initsSwitch); | 2065 inits.assign(initsSwitch); |
2030 uninits.assign(uninits.andSet(uninitsSwitch)); | 2066 uninits.assign(uninits.andSet(uninitsSwitch)); |
2031 } | 2067 } |
2032 // Warn about fall-through if lint switch fallthrough enabled. | 2068 // Warn about fall-through if lint switch fallthrough enabled. |
2033 } | 2069 } |
2034 if (!hasDefault) { | 2070 if (!hasDefault) { |
2035 andSetInits(null, initsSwitch); | 2071 inits.andSet(initsSwitch); |
2036 } | 2072 } |
2037 resolveBreaks(tree, prevPendingExits); | 2073 resolveBreaks(tree, prevPendingExits); |
2038 nextadr = nextadrPrev; | 2074 nextadr = nextadrPrev; |
2039 } | 2075 } |
2040 // where | 2076 // where |
2049 uninits.incl(adr); | 2085 uninits.incl(adr); |
2050 } | 2086 } |
2051 } | 2087 } |
2052 } | 2088 } |
2053 | 2089 |
2054 boolean isEnabled(Lint.LintCategory lc) { | |
2055 return false; | |
2056 } | |
2057 | |
2058 void reportWarning(Lint.LintCategory lc, DiagnosticPosition pos, String key, Object ... args) {} | |
2059 | |
2060 public void visitTry(JCTry tree) { | 2090 public void visitTry(JCTry tree) { |
2061 ListBuffer<JCVariableDecl> resourceVarDecls = new ListBuffer<>(); | 2091 ListBuffer<JCVariableDecl> resourceVarDecls = new ListBuffer<>(); |
2062 final Bits uninitsTryPrev = new Bits(uninitsTry); | 2092 final Bits uninitsTryPrev = new Bits(uninitsTry); |
2063 ListBuffer<P> prevPendingExits = pendingExits; | 2093 ListBuffer<AssignPendingExit> prevPendingExits = pendingExits; |
2064 pendingExits = new ListBuffer<>(); | 2094 pendingExits = new ListBuffer<>(); |
2065 final Bits initsTry = new Bits(inits); | 2095 final Bits initsTry = new Bits(inits); |
2066 uninitsTry.assign(uninits); | 2096 uninitsTry.assign(uninits); |
2067 for (JCTree resource : tree.resources) { | 2097 for (JCTree resource : tree.resources) { |
2068 if (resource instanceof JCVariableDecl) { | 2098 if (resource instanceof JCVariableDecl) { |
2081 final Bits initsEnd = new Bits(inits); | 2111 final Bits initsEnd = new Bits(inits); |
2082 final Bits uninitsEnd = new Bits(uninits); | 2112 final Bits uninitsEnd = new Bits(uninits); |
2083 int nextadrCatch = nextadr; | 2113 int nextadrCatch = nextadr; |
2084 | 2114 |
2085 if (!resourceVarDecls.isEmpty() && | 2115 if (!resourceVarDecls.isEmpty() && |
2086 isEnabled(Lint.LintCategory.TRY)) { | 2116 lint.isEnabled(Lint.LintCategory.TRY)) { |
2087 for (JCVariableDecl resVar : resourceVarDecls) { | 2117 for (JCVariableDecl resVar : resourceVarDecls) { |
2088 if (unrefdResources.includes(resVar.sym)) { | 2118 if (unrefdResources.includes(resVar.sym)) { |
2089 reportWarning(Lint.LintCategory.TRY, resVar.pos(), | 2119 log.warning(Lint.LintCategory.TRY, resVar.pos(), |
2090 "try.resource.not.referenced", resVar.sym); | 2120 "try.resource.not.referenced", resVar.sym); |
2091 unrefdResources.remove(resVar.sym); | 2121 unrefdResources.remove(resVar.sym); |
2092 } | 2122 } |
2093 } | 2123 } |
2094 } | 2124 } |
2100 final Bits initsCatchPrev = new Bits(initsTry); | 2130 final Bits initsCatchPrev = new Bits(initsTry); |
2101 final Bits uninitsCatchPrev = new Bits(uninitsTry); | 2131 final Bits uninitsCatchPrev = new Bits(uninitsTry); |
2102 | 2132 |
2103 for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) { | 2133 for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) { |
2104 JCVariableDecl param = l.head.param; | 2134 JCVariableDecl param = l.head.param; |
2105 assignToInits(tree.body, initsCatchPrev); | 2135 inits.assign(initsCatchPrev); |
2106 uninits.assign(uninitsCatchPrev); | 2136 uninits.assign(uninitsCatchPrev); |
2107 scan(param); | 2137 scan(param); |
2108 /* If this is a TWR and we are executing the code from Gen, | 2138 /* If this is a TWR and we are executing the code from Gen, |
2109 * then there can be synthetic variables, ignore them. | 2139 * then there can be synthetic variables, ignore them. |
2110 */ | 2140 */ |
2113 initsEnd.andSet(inits); | 2143 initsEnd.andSet(inits); |
2114 uninitsEnd.andSet(uninits); | 2144 uninitsEnd.andSet(uninits); |
2115 nextadr = nextadrCatch; | 2145 nextadr = nextadrCatch; |
2116 } | 2146 } |
2117 if (tree.finalizer != null) { | 2147 if (tree.finalizer != null) { |
2118 assignToInits(tree.finalizer, initsTry); | 2148 inits.assign(initsTry); |
2119 uninits.assign(uninitsTry); | 2149 uninits.assign(uninitsTry); |
2120 ListBuffer<P> exits = pendingExits; | 2150 ListBuffer<AssignPendingExit> exits = pendingExits; |
2121 pendingExits = prevPendingExits; | 2151 pendingExits = prevPendingExits; |
2122 scan(tree.finalizer); | 2152 scan(tree.finalizer); |
2123 if (!tree.finallyCanCompleteNormally) { | 2153 if (!tree.finallyCanCompleteNormally) { |
2124 // discard exits and exceptions from try and finally | 2154 // discard exits and exceptions from try and finally |
2125 } else { | 2155 } else { |
2126 uninits.andSet(uninitsEnd); | 2156 uninits.andSet(uninitsEnd); |
2127 // FIX: this doesn't preserve source order of exits in catch | 2157 // FIX: this doesn't preserve source order of exits in catch |
2128 // versus finally! | 2158 // versus finally! |
2129 while (exits.nonEmpty()) { | 2159 while (exits.nonEmpty()) { |
2130 P exit = exits.next(); | 2160 AssignPendingExit exit = exits.next(); |
2131 if (exit.exit_inits != null) { | 2161 if (exit.exit_inits != null) { |
2132 exit.exit_inits.orSet(inits); | 2162 exit.exit_inits.orSet(inits); |
2133 exit.exit_uninits.andSet(uninits); | 2163 exit.exit_uninits.andSet(uninits); |
2134 } | 2164 } |
2135 pendingExits.append(exit); | 2165 pendingExits.append(exit); |
2136 } | 2166 } |
2137 orSetInits(tree, initsEnd); | 2167 inits.orSet(initsEnd); |
2138 } | 2168 } |
2139 } else { | 2169 } else { |
2140 assignToInits(tree, initsEnd); | 2170 inits.assign(initsEnd); |
2141 uninits.assign(uninitsEnd); | 2171 uninits.assign(uninitsEnd); |
2142 ListBuffer<P> exits = pendingExits; | 2172 ListBuffer<AssignPendingExit> exits = pendingExits; |
2143 pendingExits = prevPendingExits; | 2173 pendingExits = prevPendingExits; |
2144 while (exits.nonEmpty()) pendingExits.append(exits.next()); | 2174 while (exits.nonEmpty()) pendingExits.append(exits.next()); |
2145 } | 2175 } |
2146 uninitsTry.andSet(uninitsTryPrev).andSet(uninits); | 2176 uninitsTry.andSet(uninitsTryPrev).andSet(uninits); |
2147 } | 2177 } |
2148 | 2178 |
2149 public void visitConditional(JCConditional tree) { | 2179 public void visitConditional(JCConditional tree) { |
2150 scanCond(tree.cond); | 2180 scanCond(tree.cond); |
2151 final Bits initsBeforeElse = new Bits(initsWhenFalse); | 2181 final Bits initsBeforeElse = new Bits(initsWhenFalse); |
2152 final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse); | 2182 final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse); |
2153 assignToInits(tree.cond, initsWhenTrue); | 2183 inits.assign(initsWhenTrue); |
2154 uninits.assign(uninitsWhenTrue); | 2184 uninits.assign(uninitsWhenTrue); |
2155 if (tree.truepart.type.hasTag(BOOLEAN) && | 2185 if (tree.truepart.type.hasTag(BOOLEAN) && |
2156 tree.falsepart.type.hasTag(BOOLEAN)) { | 2186 tree.falsepart.type.hasTag(BOOLEAN)) { |
2157 // if b and c are boolean valued, then | 2187 // if b and c are boolean valued, then |
2158 // v is (un)assigned after a?b:c when true iff | 2188 // v is (un)assigned after a?b:c when true iff |
2161 scanCond(tree.truepart); | 2191 scanCond(tree.truepart); |
2162 final Bits initsAfterThenWhenTrue = new Bits(initsWhenTrue); | 2192 final Bits initsAfterThenWhenTrue = new Bits(initsWhenTrue); |
2163 final Bits initsAfterThenWhenFalse = new Bits(initsWhenFalse); | 2193 final Bits initsAfterThenWhenFalse = new Bits(initsWhenFalse); |
2164 final Bits uninitsAfterThenWhenTrue = new Bits(uninitsWhenTrue); | 2194 final Bits uninitsAfterThenWhenTrue = new Bits(uninitsWhenTrue); |
2165 final Bits uninitsAfterThenWhenFalse = new Bits(uninitsWhenFalse); | 2195 final Bits uninitsAfterThenWhenFalse = new Bits(uninitsWhenFalse); |
2166 assignToInits(tree.truepart, initsBeforeElse); | 2196 inits.assign(initsBeforeElse); |
2167 uninits.assign(uninitsBeforeElse); | 2197 uninits.assign(uninitsBeforeElse); |
2168 scanCond(tree.falsepart); | 2198 scanCond(tree.falsepart); |
2169 initsWhenTrue.andSet(initsAfterThenWhenTrue); | 2199 initsWhenTrue.andSet(initsAfterThenWhenTrue); |
2170 initsWhenFalse.andSet(initsAfterThenWhenFalse); | 2200 initsWhenFalse.andSet(initsAfterThenWhenFalse); |
2171 uninitsWhenTrue.andSet(uninitsAfterThenWhenTrue); | 2201 uninitsWhenTrue.andSet(uninitsAfterThenWhenTrue); |
2172 uninitsWhenFalse.andSet(uninitsAfterThenWhenFalse); | 2202 uninitsWhenFalse.andSet(uninitsAfterThenWhenFalse); |
2173 } else { | 2203 } else { |
2174 scanExpr(tree.truepart); | 2204 scanExpr(tree.truepart); |
2175 final Bits initsAfterThen = new Bits(inits); | 2205 final Bits initsAfterThen = new Bits(inits); |
2176 final Bits uninitsAfterThen = new Bits(uninits); | 2206 final Bits uninitsAfterThen = new Bits(uninits); |
2177 assignToInits(tree.truepart, initsBeforeElse); | 2207 inits.assign(initsBeforeElse); |
2178 uninits.assign(uninitsBeforeElse); | 2208 uninits.assign(uninitsBeforeElse); |
2179 scanExpr(tree.falsepart); | 2209 scanExpr(tree.falsepart); |
2180 andSetInits(tree.falsepart, initsAfterThen); | 2210 inits.andSet(initsAfterThen); |
2181 uninits.andSet(uninitsAfterThen); | 2211 uninits.andSet(uninitsAfterThen); |
2182 } | 2212 } |
2183 } | 2213 } |
2184 | 2214 |
2185 public void visitIf(JCIf tree) { | 2215 public void visitIf(JCIf tree) { |
2186 scanCond(tree.cond); | 2216 scanCond(tree.cond); |
2187 final Bits initsBeforeElse = new Bits(initsWhenFalse); | 2217 final Bits initsBeforeElse = new Bits(initsWhenFalse); |
2188 final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse); | 2218 final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse); |
2189 assignToInits(tree.cond, initsWhenTrue); | 2219 inits.assign(initsWhenTrue); |
2190 uninits.assign(uninitsWhenTrue); | 2220 uninits.assign(uninitsWhenTrue); |
2191 scan(tree.thenpart); | 2221 scan(tree.thenpart); |
2192 if (tree.elsepart != null) { | 2222 if (tree.elsepart != null) { |
2193 final Bits initsAfterThen = new Bits(inits); | 2223 final Bits initsAfterThen = new Bits(inits); |
2194 final Bits uninitsAfterThen = new Bits(uninits); | 2224 final Bits uninitsAfterThen = new Bits(uninits); |
2195 assignToInits(tree.thenpart, initsBeforeElse); | 2225 inits.assign(initsBeforeElse); |
2196 uninits.assign(uninitsBeforeElse); | 2226 uninits.assign(uninitsBeforeElse); |
2197 scan(tree.elsepart); | 2227 scan(tree.elsepart); |
2198 andSetInits(tree.elsepart, initsAfterThen); | 2228 inits.andSet(initsAfterThen); |
2199 uninits.andSet(uninitsAfterThen); | 2229 uninits.andSet(uninitsAfterThen); |
2200 } else { | 2230 } else { |
2201 andSetInits(tree.thenpart, initsBeforeElse); | 2231 inits.andSet(initsBeforeElse); |
2202 uninits.andSet(uninitsBeforeElse); | 2232 uninits.andSet(uninitsBeforeElse); |
2203 } | 2233 } |
2204 } | |
2205 | |
2206 protected P createNewPendingExit(JCTree tree, Bits inits, Bits uninits) { | |
2207 return null; | |
2208 } | 2234 } |
2209 | 2235 |
2210 @Override | 2236 @Override |
2211 public void visitBreak(JCBreak tree) { | 2237 public void visitBreak(JCBreak tree) { |
2212 recordExit(tree, createNewPendingExit(tree, inits, uninits)); | 2238 recordExit(new AssignPendingExit(tree, inits, uninits)); |
2213 } | 2239 } |
2214 | 2240 |
2215 @Override | 2241 @Override |
2216 public void visitContinue(JCContinue tree) { | 2242 public void visitContinue(JCContinue tree) { |
2217 recordExit(tree, createNewPendingExit(tree, inits, uninits)); | 2243 recordExit(new AssignPendingExit(tree, inits, uninits)); |
2218 } | 2244 } |
2219 | 2245 |
2220 @Override | 2246 @Override |
2221 public void visitReturn(JCReturn tree) { | 2247 public void visitReturn(JCReturn tree) { |
2222 scanExpr(tree.expr); | 2248 scanExpr(tree.expr); |
2223 recordExit(tree, createNewPendingExit(tree, inits, uninits)); | 2249 recordExit(new AssignPendingExit(tree, inits, uninits)); |
2224 } | 2250 } |
2225 | 2251 |
2226 public void visitThrow(JCThrow tree) { | 2252 public void visitThrow(JCThrow tree) { |
2227 scanExpr(tree.expr); | 2253 scanExpr(tree.expr); |
2228 markDead(tree.expr); | 2254 markDead(); |
2229 } | 2255 } |
2230 | 2256 |
2231 public void visitApply(JCMethodInvocation tree) { | 2257 public void visitApply(JCMethodInvocation tree) { |
2232 scanExpr(tree.meth); | 2258 scanExpr(tree.meth); |
2233 scanExprs(tree.args); | 2259 scanExprs(tree.args); |
2242 @Override | 2268 @Override |
2243 public void visitLambda(JCLambda tree) { | 2269 public void visitLambda(JCLambda tree) { |
2244 final Bits prevUninits = new Bits(uninits); | 2270 final Bits prevUninits = new Bits(uninits); |
2245 final Bits prevInits = new Bits(inits); | 2271 final Bits prevInits = new Bits(inits); |
2246 int returnadrPrev = returnadr; | 2272 int returnadrPrev = returnadr; |
2247 ListBuffer<P> prevPending = pendingExits; | 2273 ListBuffer<AssignPendingExit> prevPending = pendingExits; |
2248 try { | 2274 try { |
2249 returnadr = nextadr; | 2275 returnadr = nextadr; |
2250 pendingExits = new ListBuffer<P>(); | 2276 pendingExits = new ListBuffer<>(); |
2251 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) { | 2277 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) { |
2252 JCVariableDecl def = l.head; | 2278 JCVariableDecl def = l.head; |
2253 scan(def); | 2279 scan(def); |
2254 inits.incl(def.sym.adr); | 2280 inits.incl(def.sym.adr); |
2255 uninits.excl(def.sym.adr); | 2281 uninits.excl(def.sym.adr); |
2261 } | 2287 } |
2262 } | 2288 } |
2263 finally { | 2289 finally { |
2264 returnadr = returnadrPrev; | 2290 returnadr = returnadrPrev; |
2265 uninits.assign(prevUninits); | 2291 uninits.assign(prevUninits); |
2266 assignToInits(tree, prevInits); | 2292 inits.assign(prevInits); |
2267 pendingExits = prevPending; | 2293 pendingExits = prevPending; |
2268 } | 2294 } |
2269 } | 2295 } |
2270 | 2296 |
2271 public void visitNewArray(JCNewArray tree) { | 2297 public void visitNewArray(JCNewArray tree) { |
2277 final Bits initsExit = new Bits(inits); | 2303 final Bits initsExit = new Bits(inits); |
2278 final Bits uninitsExit = new Bits(uninits); | 2304 final Bits uninitsExit = new Bits(uninits); |
2279 scanCond(tree.cond); | 2305 scanCond(tree.cond); |
2280 uninitsExit.andSet(uninitsWhenTrue); | 2306 uninitsExit.andSet(uninitsWhenTrue); |
2281 if (tree.detail != null) { | 2307 if (tree.detail != null) { |
2282 assignToInits(tree, initsWhenFalse); | 2308 inits.assign(initsWhenFalse); |
2283 uninits.assign(uninitsWhenFalse); | 2309 uninits.assign(uninitsWhenFalse); |
2284 scanExpr(tree.detail); | 2310 scanExpr(tree.detail); |
2285 } | 2311 } |
2286 assignToInits(tree, initsExit); | 2312 inits.assign(initsExit); |
2287 uninits.assign(uninitsExit); | 2313 uninits.assign(uninitsExit); |
2288 } | 2314 } |
2289 | 2315 |
2290 public void visitAssign(JCAssign tree) { | 2316 public void visitAssign(JCAssign tree) { |
2291 JCTree lhs = TreeInfo.skipParens(tree.lhs); | 2317 JCTree lhs = TreeInfo.skipParens(tree.lhs); |
2349 switch (tree.getTag()) { | 2375 switch (tree.getTag()) { |
2350 case AND: | 2376 case AND: |
2351 scanCond(tree.lhs); | 2377 scanCond(tree.lhs); |
2352 final Bits initsWhenFalseLeft = new Bits(initsWhenFalse); | 2378 final Bits initsWhenFalseLeft = new Bits(initsWhenFalse); |
2353 final Bits uninitsWhenFalseLeft = new Bits(uninitsWhenFalse); | 2379 final Bits uninitsWhenFalseLeft = new Bits(uninitsWhenFalse); |
2354 assignToInits(tree.lhs, initsWhenTrue); | 2380 inits.assign(initsWhenTrue); |
2355 uninits.assign(uninitsWhenTrue); | 2381 uninits.assign(uninitsWhenTrue); |
2356 scanCond(tree.rhs); | 2382 scanCond(tree.rhs); |
2357 initsWhenFalse.andSet(initsWhenFalseLeft); | 2383 initsWhenFalse.andSet(initsWhenFalseLeft); |
2358 uninitsWhenFalse.andSet(uninitsWhenFalseLeft); | 2384 uninitsWhenFalse.andSet(uninitsWhenFalseLeft); |
2359 break; | 2385 break; |
2360 case OR: | 2386 case OR: |
2361 scanCond(tree.lhs); | 2387 scanCond(tree.lhs); |
2362 final Bits initsWhenTrueLeft = new Bits(initsWhenTrue); | 2388 final Bits initsWhenTrueLeft = new Bits(initsWhenTrue); |
2363 final Bits uninitsWhenTrueLeft = new Bits(uninitsWhenTrue); | 2389 final Bits uninitsWhenTrueLeft = new Bits(uninitsWhenTrue); |
2364 assignToInits(tree.lhs, initsWhenFalse); | 2390 inits.assign(initsWhenFalse); |
2365 uninits.assign(uninitsWhenFalse); | 2391 uninits.assign(uninitsWhenFalse); |
2366 scanCond(tree.rhs); | 2392 scanCond(tree.rhs); |
2367 initsWhenTrue.andSet(initsWhenTrueLeft); | 2393 initsWhenTrue.andSet(initsWhenTrueLeft); |
2368 uninitsWhenTrue.andSet(uninitsWhenTrueLeft); | 2394 uninitsWhenTrue.andSet(uninitsWhenTrueLeft); |
2369 break; | 2395 break; |
2434 unrefdResources = null; | 2460 unrefdResources = null; |
2435 } | 2461 } |
2436 } | 2462 } |
2437 } | 2463 } |
2438 | 2464 |
2439 public class AssignAnalyzer extends AbstractAssignAnalyzer<AssignAnalyzer.AssignPendingExit> { | |
2440 | |
2441 public class AssignPendingExit extends AbstractAssignAnalyzer<AssignPendingExit>.AbstractAssignPendingExit { | |
2442 | |
2443 public AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) { | |
2444 super(tree, inits, uninits); | |
2445 } | |
2446 } | |
2447 | |
2448 @Override | |
2449 protected AssignPendingExit createNewPendingExit(JCTree tree, | |
2450 Bits inits, Bits uninits) { | |
2451 return new AssignPendingExit(tree, inits, uninits); | |
2452 } | |
2453 | |
2454 /** Record an initialization of a trackable variable. | |
2455 */ | |
2456 @Override | |
2457 void letInit(DiagnosticPosition pos, VarSymbol sym) { | |
2458 if (sym.adr >= firstadr && trackable(sym)) { | |
2459 if ((sym.flags() & EFFECTIVELY_FINAL) != 0) { | |
2460 if (!uninits.isMember(sym.adr)) { | |
2461 //assignment targeting an effectively final variable | |
2462 //makes the variable lose its status of effectively final | |
2463 //if the variable is _not_ definitively unassigned | |
2464 sym.flags_field &= ~EFFECTIVELY_FINAL; | |
2465 } else { | |
2466 uninit(sym); | |
2467 } | |
2468 } | |
2469 else if ((sym.flags() & FINAL) != 0) { | |
2470 if ((sym.flags() & PARAMETER) != 0) { | |
2471 if ((sym.flags() & UNION) != 0) { //multi-catch parameter | |
2472 log.error(pos, "multicatch.parameter.may.not.be.assigned", sym); | |
2473 } | |
2474 else { | |
2475 log.error(pos, "final.parameter.may.not.be.assigned", | |
2476 sym); | |
2477 } | |
2478 } else if (!uninits.isMember(sym.adr)) { | |
2479 log.error(pos, flowKind.errKey, sym); | |
2480 } else { | |
2481 uninit(sym); | |
2482 } | |
2483 } | |
2484 inits.incl(sym.adr); | |
2485 } else if ((sym.flags() & FINAL) != 0) { | |
2486 log.error(pos, "var.might.already.be.assigned", sym); | |
2487 } | |
2488 } | |
2489 | |
2490 @Override | |
2491 void checkInit(DiagnosticPosition pos, VarSymbol sym, String errkey) { | |
2492 if ((sym.adr >= firstadr || sym.owner.kind != TYP) && | |
2493 trackable(sym) && | |
2494 !inits.isMember(sym.adr)) { | |
2495 log.error(pos, errkey, sym); | |
2496 inits.incl(sym.adr); | |
2497 } | |
2498 } | |
2499 | |
2500 @Override | |
2501 void reportWarning(Lint.LintCategory lc, DiagnosticPosition pos, | |
2502 String key, Object ... args) { | |
2503 log.warning(lc, pos, key, args); | |
2504 } | |
2505 | |
2506 @Override | |
2507 int getLogNumberOfErrors() { | |
2508 return log.nerrors; | |
2509 } | |
2510 | |
2511 @Override | |
2512 boolean isEnabled(Lint.LintCategory lc) { | |
2513 return lint.isEnabled(lc); | |
2514 } | |
2515 | |
2516 @Override | |
2517 public void visitClassDef(JCClassDecl tree) { | |
2518 if (tree.sym == null) { | |
2519 return; | |
2520 } | |
2521 | |
2522 Lint lintPrev = lint; | |
2523 lint = lint.augment(tree.sym); | |
2524 try { | |
2525 super.visitClassDef(tree); | |
2526 } finally { | |
2527 lint = lintPrev; | |
2528 } | |
2529 } | |
2530 | |
2531 @Override | |
2532 public void visitMethodDef(JCMethodDecl tree) { | |
2533 if (tree.body == null) { | |
2534 return; | |
2535 } | |
2536 | |
2537 /* MemberEnter can generate synthetic methods ignore them | |
2538 */ | |
2539 if ((tree.sym.flags() & SYNTHETIC) != 0) { | |
2540 return; | |
2541 } | |
2542 | |
2543 Lint lintPrev = lint; | |
2544 lint = lint.augment(tree.sym); | |
2545 try { | |
2546 super.visitMethodDef(tree); | |
2547 } finally { | |
2548 lint = lintPrev; | |
2549 } | |
2550 } | |
2551 | |
2552 @Override | |
2553 public void visitVarDef(JCVariableDecl tree) { | |
2554 if (tree.init == null) { | |
2555 super.visitVarDef(tree); | |
2556 } else { | |
2557 Lint lintPrev = lint; | |
2558 lint = lint.augment(tree.sym); | |
2559 try{ | |
2560 super.visitVarDef(tree); | |
2561 } finally { | |
2562 lint = lintPrev; | |
2563 } | |
2564 } | |
2565 } | |
2566 | |
2567 } | |
2568 | |
2569 /** | 2465 /** |
2570 * This pass implements the last step of the dataflow analysis, namely | 2466 * This pass implements the last step of the dataflow analysis, namely |
2571 * the effectively-final analysis check. This checks that every local variable | 2467 * the effectively-final analysis check. This checks that every local variable |
2572 * reference from a lambda body/local inner class is either final or effectively final. | 2468 * reference from a lambda body/local inner class is either final or effectively final. |
2573 * As effectively final variables are marked as such during DA/DU, this pass must run after | 2469 * As effectively final variables are marked as such during DA/DU, this pass must run after |
2576 class CaptureAnalyzer extends BaseAnalyzer<BaseAnalyzer.PendingExit> { | 2472 class CaptureAnalyzer extends BaseAnalyzer<BaseAnalyzer.PendingExit> { |
2577 | 2473 |
2578 JCTree currentTree; //local class or lambda | 2474 JCTree currentTree; //local class or lambda |
2579 | 2475 |
2580 @Override | 2476 @Override |
2581 void markDead(JCTree tree) { | 2477 void markDead() { |
2582 //do nothing | 2478 //do nothing |
2583 } | 2479 } |
2584 | 2480 |
2585 @SuppressWarnings("fallthrough") | 2481 @SuppressWarnings("fallthrough") |
2586 void checkEffectivelyFinal(DiagnosticPosition pos, VarSymbol sym) { | 2482 void checkEffectivelyFinal(DiagnosticPosition pos, VarSymbol sym) { |
2713 } | 2609 } |
2714 public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) { | 2610 public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) { |
2715 try { | 2611 try { |
2716 attrEnv = env; | 2612 attrEnv = env; |
2717 Flow.this.make = make; | 2613 Flow.this.make = make; |
2718 pendingExits = new ListBuffer<PendingExit>(); | 2614 pendingExits = new ListBuffer<>(); |
2719 scan(tree); | 2615 scan(tree); |
2720 } finally { | 2616 } finally { |
2721 pendingExits = null; | 2617 pendingExits = null; |
2722 Flow.this.make = null; | 2618 Flow.this.make = null; |
2723 } | 2619 } |