2026:03c26c60499c | 2027:4932bb04c4b8 |
---|---|
205 return instance; | 205 return instance; |
206 } | 206 } |
207 | 207 |
208 public void analyzeTree(Env<AttrContext> env, TreeMaker make) { | 208 public void analyzeTree(Env<AttrContext> env, TreeMaker make) { |
209 new AliveAnalyzer().analyzeTree(env, make); | 209 new AliveAnalyzer().analyzeTree(env, make); |
210 new AssignAnalyzer().analyzeTree(env, make); | 210 new AssignAnalyzer(log, syms, lint, names).analyzeTree(env); |
211 new FlowAnalyzer().analyzeTree(env, make); | 211 new FlowAnalyzer().analyzeTree(env, make); |
212 new CaptureAnalyzer().analyzeTree(env, make); | 212 new CaptureAnalyzer().analyzeTree(env, make); |
213 } | 213 } |
214 | 214 |
215 public void analyzeLambda(Env<AttrContext> env, JCLambda that, TreeMaker make, boolean speculative) { | 215 public void analyzeLambda(Env<AttrContext> env, JCLambda that, TreeMaker make, boolean speculative) { |
237 //message will be reported and will cause compilation to skip the flow analyis | 237 //message will be reported and will cause compilation to skip the flow analyis |
238 //step - if we suppress diagnostics, we won't stop at Attr for flow-analysis | 238 //step - if we suppress diagnostics, we won't stop at Attr for flow-analysis |
239 //related errors, which will allow for more errors to be detected | 239 //related errors, which will allow for more errors to be detected |
240 Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log); | 240 Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log); |
241 try { | 241 try { |
242 new AssignAnalyzer().analyzeTree(env, that, make); | 242 new AssignAnalyzer(log, syms, lint, names).analyzeTree(env); |
243 LambdaFlowAnalyzer flowAnalyzer = new LambdaFlowAnalyzer(); | 243 LambdaFlowAnalyzer flowAnalyzer = new LambdaFlowAnalyzer(); |
244 flowAnalyzer.analyzeTree(env, that, make); | 244 flowAnalyzer.analyzeTree(env, that, make); |
245 return flowAnalyzer.inferredThrownTypes; | 245 return flowAnalyzer.inferredThrownTypes; |
246 } finally { | 246 } finally { |
247 log.popDiagnosticHandler(diagHandler); | 247 log.popDiagnosticHandler(diagHandler); |
290 allowImprovedCatchAnalysis = source.allowImprovedCatchAnalysis(); | 290 allowImprovedCatchAnalysis = source.allowImprovedCatchAnalysis(); |
291 allowEffectivelyFinalInInnerClasses = source.allowEffectivelyFinalInInnerClasses(); | 291 allowEffectivelyFinalInInnerClasses = source.allowEffectivelyFinalInInnerClasses(); |
292 } | 292 } |
293 | 293 |
294 /** | 294 /** |
295 * Utility method to reset several Bits instances. | |
296 */ | |
297 private void resetBits(Bits... bits) { | |
298 for (Bits b : bits) { | |
299 b.reset(); | |
300 } | |
301 } | |
302 | |
303 /** | |
304 * Base visitor class for all visitors implementing dataflow analysis logic. | 295 * Base visitor class for all visitors implementing dataflow analysis logic. |
305 * This class define the shared logic for handling jumps (break/continue statements). | 296 * This class define the shared logic for handling jumps (break/continue statements). |
306 */ | 297 */ |
307 static abstract class BaseAnalyzer<P extends BaseAnalyzer.PendingExit> extends TreeScanner { | 298 static abstract class BaseAnalyzer<P extends BaseAnalyzer.PendingExit> extends TreeScanner { |
308 | 299 |
345 | 336 |
346 PendingExit(JCTree tree) { | 337 PendingExit(JCTree tree) { |
347 this.tree = tree; | 338 this.tree = tree; |
348 } | 339 } |
349 | 340 |
350 void resolveJump() { | 341 void resolveJump(JCTree tree) { |
351 //do nothing | 342 //do nothing |
352 } | 343 } |
353 } | 344 } |
354 | 345 |
355 abstract void markDead(); | 346 abstract void markDead(JCTree tree); |
356 | 347 |
357 /** Record an outward transfer of control. */ | 348 /** Record an outward transfer of control. */ |
358 void recordExit(JCTree tree, P pe) { | 349 void recordExit(JCTree tree, P pe) { |
359 pendingExits.append(pe); | 350 pendingExits.append(pe); |
360 markDead(); | 351 markDead(tree); |
361 } | 352 } |
362 | 353 |
363 /** Resolve all jumps of this statement. */ | 354 /** Resolve all jumps of this statement. */ |
364 private boolean resolveJump(JCTree tree, | 355 private boolean resolveJump(JCTree tree, |
365 ListBuffer<P> oldPendingExits, | 356 ListBuffer<P> oldPendingExits, |
369 pendingExits = oldPendingExits; | 360 pendingExits = oldPendingExits; |
370 for (; exits.nonEmpty(); exits = exits.tail) { | 361 for (; exits.nonEmpty(); exits = exits.tail) { |
371 P exit = exits.head; | 362 P exit = exits.head; |
372 if (exit.tree.hasTag(jk.treeTag) && | 363 if (exit.tree.hasTag(jk.treeTag) && |
373 jk.getTarget(exit.tree) == tree) { | 364 jk.getTarget(exit.tree) == tree) { |
374 exit.resolveJump(); | 365 exit.resolveJump(tree); |
375 resolved = true; | 366 resolved = true; |
376 } else { | 367 } else { |
377 pendingExits.append(exit); | 368 pendingExits.append(exit); |
378 } | 369 } |
379 } | 370 } |
380 return resolved; | 371 return resolved; |
381 } | 372 } |
382 | 373 |
383 /** Resolve all breaks of this statement. */ | 374 /** Resolve all continues of this statement. */ |
384 boolean resolveContinues(JCTree tree) { | 375 boolean resolveContinues(JCTree tree) { |
385 return resolveJump(tree, new ListBuffer<P>(), JumpKind.CONTINUE); | 376 return resolveJump(tree, new ListBuffer<P>(), JumpKind.CONTINUE); |
386 } | 377 } |
387 | 378 |
388 /** Resolve all continues of this statement. */ | 379 /** Resolve all breaks of this statement. */ |
389 boolean resolveBreaks(JCTree tree, ListBuffer<P> oldPendingExits) { | 380 boolean resolveBreaks(JCTree tree, ListBuffer<P> oldPendingExits) { |
390 return resolveJump(tree, oldPendingExits, JumpKind.BREAK); | 381 return resolveJump(tree, oldPendingExits, JumpKind.BREAK); |
391 } | 382 } |
392 | 383 |
393 @Override | 384 @Override |
412 * complete normally. | 403 * complete normally. |
413 */ | 404 */ |
414 private boolean alive; | 405 private boolean alive; |
415 | 406 |
416 @Override | 407 @Override |
417 void markDead() { | 408 void markDead(JCTree tree) { |
418 alive = false; | 409 alive = false; |
419 } | 410 } |
420 | 411 |
421 /************************************************************************* | 412 /************************************************************************* |
422 * Visitor methods for statements and definitions | 413 * Visitor methods for statements and definitions |
694 recordExit(tree, new PendingExit(tree)); | 685 recordExit(tree, new PendingExit(tree)); |
695 } | 686 } |
696 | 687 |
697 public void visitThrow(JCThrow tree) { | 688 public void visitThrow(JCThrow tree) { |
698 scan(tree.expr); | 689 scan(tree.expr); |
699 markDead(); | 690 markDead(tree); |
700 } | 691 } |
701 | 692 |
702 public void visitApply(JCMethodInvocation tree) { | 693 public void visitApply(JCMethodInvocation tree) { |
703 scan(tree.meth); | 694 scan(tree.meth); |
704 scan(tree.args); | 695 scan(tree.args); |
795 this.thrown = thrown; | 786 this.thrown = thrown; |
796 } | 787 } |
797 } | 788 } |
798 | 789 |
799 @Override | 790 @Override |
800 void markDead() { | 791 void markDead(JCTree tree) { |
801 //do nothing | 792 //do nothing |
802 } | 793 } |
803 | 794 |
804 /*-------------------- Exceptions ----------------------*/ | 795 /*-------------------- Exceptions ----------------------*/ |
805 | 796 |
1220 } | 1211 } |
1221 } | 1212 } |
1222 else { | 1213 else { |
1223 markThrown(tree, tree.expr.type); | 1214 markThrown(tree, tree.expr.type); |
1224 } | 1215 } |
1225 markDead(); | 1216 markDead(tree); |
1226 } | 1217 } |
1227 | 1218 |
1228 public void visitApply(JCMethodInvocation tree) { | 1219 public void visitApply(JCMethodInvocation tree) { |
1229 scan(tree.meth); | 1220 scan(tree.meth); |
1230 scan(tree.args); | 1221 scan(tree.args); |
1370 * each variable is assigned when used and (ii) definite unassignment analysis, | 1361 * each variable is assigned when used and (ii) definite unassignment analysis, |
1371 * which ensures that no final variable is assigned more than once. This visitor | 1362 * which ensures that no final variable is assigned more than once. This visitor |
1372 * depends on the results of the liveliness analyzer. This pass is also used to mark | 1363 * depends on the results of the liveliness analyzer. This pass is also used to mark |
1373 * effectively-final local variables/parameters. | 1364 * effectively-final local variables/parameters. |
1374 */ | 1365 */ |
1375 class AssignAnalyzer extends BaseAnalyzer<AssignAnalyzer.AssignPendingExit> { | 1366 |
1367 public abstract static class AbstractAssignAnalyzer<P extends AbstractAssignAnalyzer.AbstractAssignPendingExit> | |
1368 extends BaseAnalyzer<P> { | |
1376 | 1369 |
1377 /** The set of definitely assigned variables. | 1370 /** The set of definitely assigned variables. |
1378 */ | 1371 */ |
1379 final Bits inits; | 1372 protected final Bits inits; |
1380 | 1373 |
1381 /** The set of definitely unassigned variables. | 1374 /** The set of definitely unassigned variables. |
1382 */ | 1375 */ |
1383 final Bits uninits; | 1376 final Bits uninits; |
1384 | 1377 |
1400 final Bits uninitsWhenTrue; | 1393 final Bits uninitsWhenTrue; |
1401 final Bits uninitsWhenFalse; | 1394 final Bits uninitsWhenFalse; |
1402 | 1395 |
1403 /** A mapping from addresses to variable symbols. | 1396 /** A mapping from addresses to variable symbols. |
1404 */ | 1397 */ |
1405 JCVariableDecl[] vardecls; | 1398 protected JCVariableDecl[] vardecls; |
1406 | 1399 |
1407 /** The current class being defined. | 1400 /** The current class being defined. |
1408 */ | 1401 */ |
1409 JCClassDecl classDef; | 1402 JCClassDecl classDef; |
1410 | 1403 |
1412 */ | 1405 */ |
1413 int firstadr; | 1406 int firstadr; |
1414 | 1407 |
1415 /** The next available variable sequence number. | 1408 /** The next available variable sequence number. |
1416 */ | 1409 */ |
1417 int nextadr; | 1410 protected int nextadr; |
1418 | 1411 |
1419 /** The first variable sequence number in a block that can return. | 1412 /** The first variable sequence number in a block that can return. |
1420 */ | 1413 */ |
1421 int returnadr; | 1414 protected int returnadr; |
1422 | 1415 |
1423 /** The list of unreferenced automatic resources. | 1416 /** The list of unreferenced automatic resources. |
1424 */ | 1417 */ |
1425 Scope unrefdResources; | 1418 Scope unrefdResources; |
1426 | 1419 |
1428 FlowKind flowKind = FlowKind.NORMAL; | 1421 FlowKind flowKind = FlowKind.NORMAL; |
1429 | 1422 |
1430 /** The starting position of the analysed tree */ | 1423 /** The starting position of the analysed tree */ |
1431 int startPos; | 1424 int startPos; |
1432 | 1425 |
1433 AssignAnalyzer() { | 1426 final Symtab syms; |
1434 inits = new Bits(); | 1427 |
1428 protected Names names; | |
1429 | |
1430 public static class AbstractAssignPendingExit extends BaseAnalyzer.PendingExit { | |
1431 | |
1432 final Bits inits; | |
1433 final Bits uninits; | |
1434 final Bits exit_inits = new Bits(true); | |
1435 final Bits exit_uninits = new Bits(true); | |
1436 | |
1437 public AbstractAssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) { | |
1438 super(tree); | |
1439 this.inits = inits; | |
1440 this.uninits = uninits; | |
1441 this.exit_inits.assign(inits); | |
1442 this.exit_uninits.assign(uninits); | |
1443 } | |
1444 | |
1445 @Override | |
1446 public void resolveJump(JCTree tree) { | |
1447 inits.andSet(exit_inits); | |
1448 uninits.andSet(exit_uninits); | |
1449 } | |
1450 } | |
1451 | |
1452 public AbstractAssignAnalyzer(Bits inits, Symtab syms, Names names) { | |
1453 this.inits = inits; | |
1435 uninits = new Bits(); | 1454 uninits = new Bits(); |
1436 uninitsTry = new Bits(); | 1455 uninitsTry = new Bits(); |
1437 initsWhenTrue = new Bits(true); | 1456 initsWhenTrue = new Bits(true); |
1438 initsWhenFalse = new Bits(true); | 1457 initsWhenFalse = new Bits(true); |
1439 uninitsWhenTrue = new Bits(true); | 1458 uninitsWhenTrue = new Bits(true); |
1440 uninitsWhenFalse = new Bits(true); | 1459 uninitsWhenFalse = new Bits(true); |
1441 } | 1460 this.syms = syms; |
1442 | 1461 this.names = names; |
1443 class AssignPendingExit extends BaseAnalyzer.PendingExit { | 1462 } |
1444 | 1463 |
1445 final Bits exit_inits = new Bits(true); | 1464 @Override |
1446 final Bits exit_uninits = new Bits(true); | 1465 protected void markDead(JCTree tree) { |
1447 | |
1448 AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) { | |
1449 super(tree); | |
1450 this.exit_inits.assign(inits); | |
1451 this.exit_uninits.assign(uninits); | |
1452 } | |
1453 | |
1454 void resolveJump() { | |
1455 inits.andSet(exit_inits); | |
1456 uninits.andSet(exit_uninits); | |
1457 } | |
1458 } | |
1459 | |
1460 @Override | |
1461 void markDead() { | |
1462 inits.inclRange(returnadr, nextadr); | 1466 inits.inclRange(returnadr, nextadr); |
1463 uninits.inclRange(returnadr, nextadr); | 1467 uninits.inclRange(returnadr, nextadr); |
1464 } | 1468 } |
1465 | 1469 |
1466 /*-------------- Processing variables ----------------------*/ | 1470 /*-------------- Processing variables ----------------------*/ |
1467 | 1471 |
1468 /** Do we need to track init/uninit state of this symbol? | 1472 /** Do we need to track init/uninit state of this symbol? |
1469 * I.e. is symbol either a local or a blank final variable? | 1473 * I.e. is symbol either a local or a blank final variable? |
1470 */ | 1474 */ |
1471 boolean trackable(VarSymbol sym) { | 1475 protected boolean trackable(VarSymbol sym) { |
1472 return | 1476 return |
1473 sym.pos >= startPos && | 1477 sym.pos >= startPos && |
1474 ((sym.owner.kind == MTH || | 1478 ((sym.owner.kind == MTH || |
1475 ((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL && | 1479 ((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL && |
1476 classDef.sym.isEnclosedBy((ClassSymbol)sym.owner)))); | 1480 classDef.sym.isEnclosedBy((ClassSymbol)sym.owner)))); |
1486 if ((sym.flags() & FINAL) == 0) { | 1490 if ((sym.flags() & FINAL) == 0) { |
1487 sym.flags_field |= EFFECTIVELY_FINAL; | 1491 sym.flags_field |= EFFECTIVELY_FINAL; |
1488 } | 1492 } |
1489 sym.adr = nextadr; | 1493 sym.adr = nextadr; |
1490 vardecls[nextadr] = varDecl; | 1494 vardecls[nextadr] = varDecl; |
1491 inits.excl(nextadr); | 1495 exclVarFromInits(varDecl, nextadr); |
1492 uninits.incl(nextadr); | 1496 uninits.incl(nextadr); |
1493 nextadr++; | 1497 nextadr++; |
1494 } | 1498 } |
1495 | 1499 |
1500 protected void exclVarFromInits(JCTree tree, int adr) { | |
1501 inits.excl(adr); | |
1502 } | |
1503 | |
1504 protected void assignToInits(JCTree tree, Bits bits) { | |
1505 inits.assign(bits); | |
1506 } | |
1507 | |
1508 protected void andSetInits(JCTree tree, Bits bits) { | |
1509 inits.andSet(bits); | |
1510 } | |
1511 | |
1512 protected void orSetInits(JCTree tree, Bits bits) { | |
1513 inits.orSet(bits); | |
1514 } | |
1515 | |
1496 /** Record an initialization of a trackable variable. | 1516 /** Record an initialization of a trackable variable. |
1497 */ | 1517 */ |
1498 void letInit(DiagnosticPosition pos, VarSymbol sym) { | 1518 void letInit(DiagnosticPosition pos, VarSymbol sym) { |
1499 if (sym.adr >= firstadr && trackable(sym)) { | 1519 if (sym.adr >= firstadr && trackable(sym)) { |
1500 if ((sym.flags() & EFFECTIVELY_FINAL) != 0) { | 1520 if (uninits.isMember(sym.adr)) { |
1501 if (!uninits.isMember(sym.adr)) { | 1521 uninit(sym); |
1502 //assignment targeting an effectively final variable | |
1503 //makes the variable lose its status of effectively final | |
1504 //if the variable is _not_ definitively unassigned | |
1505 sym.flags_field &= ~EFFECTIVELY_FINAL; | |
1506 } else { | |
1507 uninit(sym); | |
1508 } | |
1509 } | |
1510 else if ((sym.flags() & FINAL) != 0) { | |
1511 if ((sym.flags() & PARAMETER) != 0) { | |
1512 if ((sym.flags() & UNION) != 0) { //multi-catch parameter | |
1513 log.error(pos, "multicatch.parameter.may.not.be.assigned", | |
1514 sym); | |
1515 } | |
1516 else { | |
1517 log.error(pos, "final.parameter.may.not.be.assigned", | |
1518 sym); | |
1519 } | |
1520 } else if (!uninits.isMember(sym.adr)) { | |
1521 log.error(pos, flowKind.errKey, sym); | |
1522 } else { | |
1523 uninit(sym); | |
1524 } | |
1525 } | 1522 } |
1526 inits.incl(sym.adr); | 1523 inits.incl(sym.adr); |
1527 } else if ((sym.flags() & FINAL) != 0) { | |
1528 log.error(pos, "var.might.already.be.assigned", sym); | |
1529 } | 1524 } |
1530 } | 1525 } |
1531 //where | 1526 //where |
1532 void uninit(VarSymbol sym) { | 1527 void uninit(VarSymbol sym) { |
1533 if (!inits.isMember(sym.adr)) { | 1528 if (!inits.isMember(sym.adr)) { |
1557 /** Check that trackable variable is initialized. | 1552 /** Check that trackable variable is initialized. |
1558 */ | 1553 */ |
1559 void checkInit(DiagnosticPosition pos, VarSymbol sym) { | 1554 void checkInit(DiagnosticPosition pos, VarSymbol sym) { |
1560 checkInit(pos, sym, "var.might.not.have.been.initialized"); | 1555 checkInit(pos, sym, "var.might.not.have.been.initialized"); |
1561 } | 1556 } |
1562 void checkInit(DiagnosticPosition pos, VarSymbol sym, String errkey) { | 1557 |
1563 if ((sym.adr >= firstadr || sym.owner.kind != TYP) && | 1558 void checkInit(DiagnosticPosition pos, VarSymbol sym, String errkey) {} |
1564 trackable(sym) && | 1559 |
1565 !inits.isMember(sym.adr)) { | 1560 /** Utility method to reset several Bits instances. |
1566 log.error(pos, errkey, sym); | 1561 */ |
1567 inits.incl(sym.adr); | 1562 private void resetBits(Bits... bits) { |
1563 for (Bits b : bits) { | |
1564 b.reset(); | |
1568 } | 1565 } |
1569 } | 1566 } |
1570 | 1567 |
1571 /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets | 1568 /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets |
1572 */ | 1569 */ |
1580 } | 1577 } |
1581 } | 1578 } |
1582 | 1579 |
1583 /** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets. | 1580 /** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets. |
1584 */ | 1581 */ |
1585 void merge() { | 1582 protected void merge(JCTree tree) { |
1586 inits.assign(initsWhenFalse.andSet(initsWhenTrue)); | 1583 inits.assign(initsWhenFalse.andSet(initsWhenTrue)); |
1587 uninits.assign(uninitsWhenFalse.andSet(uninitsWhenTrue)); | 1584 uninits.assign(uninitsWhenFalse.andSet(uninitsWhenTrue)); |
1588 } | 1585 } |
1589 | 1586 |
1590 /* ************************************************************************ | 1587 /* ************************************************************************ |
1595 * (un)initsWhenTrue(WhenFalse) on exit. | 1592 * (un)initsWhenTrue(WhenFalse) on exit. |
1596 */ | 1593 */ |
1597 void scanExpr(JCTree tree) { | 1594 void scanExpr(JCTree tree) { |
1598 if (tree != null) { | 1595 if (tree != null) { |
1599 scan(tree); | 1596 scan(tree); |
1600 if (inits.isReset()) merge(); | 1597 if (inits.isReset()) { |
1598 merge(tree); | |
1599 } | |
1601 } | 1600 } |
1602 } | 1601 } |
1603 | 1602 |
1604 /** Analyze a list of expressions. | 1603 /** Analyze a list of expressions. |
1605 */ | 1604 */ |
1612 /** Analyze a condition. Make sure to set (un)initsWhenTrue(WhenFalse) | 1611 /** Analyze a condition. Make sure to set (un)initsWhenTrue(WhenFalse) |
1613 * rather than (un)inits on exit. | 1612 * rather than (un)inits on exit. |
1614 */ | 1613 */ |
1615 void scanCond(JCTree tree) { | 1614 void scanCond(JCTree tree) { |
1616 if (tree.type.isFalse()) { | 1615 if (tree.type.isFalse()) { |
1617 if (inits.isReset()) merge(); | 1616 if (inits.isReset()) merge(tree); |
1618 initsWhenTrue.assign(inits); | 1617 initsWhenTrue.assign(inits); |
1619 initsWhenTrue.inclRange(firstadr, nextadr); | 1618 initsWhenTrue.inclRange(firstadr, nextadr); |
1620 uninitsWhenTrue.assign(uninits); | 1619 uninitsWhenTrue.assign(uninits); |
1621 uninitsWhenTrue.inclRange(firstadr, nextadr); | 1620 uninitsWhenTrue.inclRange(firstadr, nextadr); |
1622 initsWhenFalse.assign(inits); | 1621 initsWhenFalse.assign(inits); |
1623 uninitsWhenFalse.assign(uninits); | 1622 uninitsWhenFalse.assign(uninits); |
1624 } else if (tree.type.isTrue()) { | 1623 } else if (tree.type.isTrue()) { |
1625 if (inits.isReset()) merge(); | 1624 if (inits.isReset()) merge(tree); |
1626 initsWhenFalse.assign(inits); | 1625 initsWhenFalse.assign(inits); |
1627 initsWhenFalse.inclRange(firstadr, nextadr); | 1626 initsWhenFalse.inclRange(firstadr, nextadr); |
1628 uninitsWhenFalse.assign(uninits); | 1627 uninitsWhenFalse.assign(uninits); |
1629 uninitsWhenFalse.inclRange(firstadr, nextadr); | 1628 uninitsWhenFalse.inclRange(firstadr, nextadr); |
1630 initsWhenTrue.assign(inits); | 1629 initsWhenTrue.assign(inits); |
1639 } | 1638 } |
1640 } | 1639 } |
1641 | 1640 |
1642 /* ------------ Visitor methods for various sorts of trees -------------*/ | 1641 /* ------------ Visitor methods for various sorts of trees -------------*/ |
1643 | 1642 |
1643 @Override | |
1644 public void visitClassDef(JCClassDecl tree) { | 1644 public void visitClassDef(JCClassDecl tree) { |
1645 if (tree.sym == null) return; | 1645 if (tree.sym == null) { |
1646 return; | |
1647 } | |
1646 | 1648 |
1647 JCClassDecl classDefPrev = classDef; | 1649 JCClassDecl classDefPrev = classDef; |
1648 int firstadrPrev = firstadr; | 1650 int firstadrPrev = firstadr; |
1649 int nextadrPrev = nextadr; | 1651 int nextadrPrev = nextadr; |
1650 ListBuffer<AssignPendingExit> pendingExitsPrev = pendingExits; | 1652 ListBuffer<P> pendingExitsPrev = pendingExits; |
1651 Lint lintPrev = lint; | 1653 |
1652 | 1654 pendingExits = new ListBuffer<P>(); |
1653 pendingExits = new ListBuffer<AssignPendingExit>(); | |
1654 if (tree.name != names.empty) { | 1655 if (tree.name != names.empty) { |
1655 firstadr = nextadr; | 1656 firstadr = nextadr; |
1656 } | 1657 } |
1657 classDef = tree; | 1658 classDef = tree; |
1658 lint = lint.augment(tree.sym); | |
1659 | |
1660 try { | 1659 try { |
1661 // define all the static fields | 1660 // define all the static fields |
1662 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { | 1661 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { |
1663 if (l.head.hasTag(VARDEF)) { | 1662 if (l.head.hasTag(VARDEF)) { |
1664 JCVariableDecl def = (JCVariableDecl)l.head; | 1663 JCVariableDecl def = (JCVariableDecl)l.head; |
1665 if ((def.mods.flags & STATIC) != 0) { | 1664 if ((def.mods.flags & STATIC) != 0) { |
1666 VarSymbol sym = def.sym; | 1665 VarSymbol sym = def.sym; |
1667 if (trackable(sym)) | 1666 if (trackable(sym)) { |
1668 newVar(def); | 1667 newVar(def); |
1668 } | |
1669 } | 1669 } |
1670 } | 1670 } |
1671 } | 1671 } |
1672 | 1672 |
1673 // process all the static initializers | 1673 // process all the static initializers |
1682 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { | 1682 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { |
1683 if (l.head.hasTag(VARDEF)) { | 1683 if (l.head.hasTag(VARDEF)) { |
1684 JCVariableDecl def = (JCVariableDecl)l.head; | 1684 JCVariableDecl def = (JCVariableDecl)l.head; |
1685 if ((def.mods.flags & STATIC) == 0) { | 1685 if ((def.mods.flags & STATIC) == 0) { |
1686 VarSymbol sym = def.sym; | 1686 VarSymbol sym = def.sym; |
1687 if (trackable(sym)) | 1687 if (trackable(sym)) { |
1688 newVar(def); | 1688 newVar(def); |
1689 } | |
1689 } | 1690 } |
1690 } | 1691 } |
1691 } | 1692 } |
1692 | 1693 |
1693 // process all the instance initializers | 1694 // process all the instance initializers |
1707 } finally { | 1708 } finally { |
1708 pendingExits = pendingExitsPrev; | 1709 pendingExits = pendingExitsPrev; |
1709 nextadr = nextadrPrev; | 1710 nextadr = nextadrPrev; |
1710 firstadr = firstadrPrev; | 1711 firstadr = firstadrPrev; |
1711 classDef = classDefPrev; | 1712 classDef = classDefPrev; |
1712 lint = lintPrev; | 1713 } |
1713 } | 1714 } |
1714 } | 1715 |
1715 | 1716 @Override |
1716 public void visitMethodDef(JCMethodDecl tree) { | 1717 public void visitMethodDef(JCMethodDecl tree) { |
1717 if (tree.body == null) return; | 1718 if (tree.body == null) { |
1719 return; | |
1720 } | |
1721 /* MemberEnter can generate synthetic methods, ignore them | |
1722 */ | |
1723 if ((tree.sym.flags() & SYNTHETIC) != 0) { | |
1724 return; | |
1725 } | |
1718 | 1726 |
1719 final Bits initsPrev = new Bits(inits); | 1727 final Bits initsPrev = new Bits(inits); |
1720 final Bits uninitsPrev = new Bits(uninits); | 1728 final Bits uninitsPrev = new Bits(uninits); |
1721 int nextadrPrev = nextadr; | 1729 int nextadrPrev = nextadr; |
1722 int firstadrPrev = firstadr; | 1730 int firstadrPrev = firstadr; |
1723 int returnadrPrev = returnadr; | 1731 int returnadrPrev = returnadr; |
1724 Lint lintPrev = lint; | |
1725 | |
1726 lint = lint.augment(tree.sym); | |
1727 | 1732 |
1728 Assert.check(pendingExits.isEmpty()); | 1733 Assert.check(pendingExits.isEmpty()); |
1729 | 1734 |
1730 try { | 1735 try { |
1731 boolean isInitialConstructor = | 1736 boolean isInitialConstructor = |
1732 TreeInfo.isInitialConstructor(tree); | 1737 TreeInfo.isInitialConstructor(tree); |
1733 | 1738 |
1734 if (!isInitialConstructor) | 1739 if (!isInitialConstructor) { |
1735 firstadr = nextadr; | 1740 firstadr = nextadr; |
1741 } | |
1736 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) { | 1742 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) { |
1737 JCVariableDecl def = l.head; | 1743 JCVariableDecl def = l.head; |
1738 scan(def); | 1744 scan(def); |
1739 inits.incl(def.sym.adr); | 1745 Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag"); |
1740 uninits.excl(def.sym.adr); | 1746 /* If we are executing the code from Gen, then there can be |
1747 * synthetic or mandated variables, ignore them. | |
1748 */ | |
1749 initParam(def); | |
1741 } | 1750 } |
1742 // else we are in an instance initializer block; | 1751 // else we are in an instance initializer block; |
1743 // leave caught unchanged. | 1752 // leave caught unchanged. |
1744 scan(tree.body); | 1753 scan(tree.body); |
1745 | 1754 |
1759 checkInit(TreeInfo.diagEndPos(tree.body), var); | 1768 checkInit(TreeInfo.diagEndPos(tree.body), var); |
1760 } | 1769 } |
1761 } | 1770 } |
1762 } | 1771 } |
1763 } | 1772 } |
1764 List<AssignPendingExit> exits = pendingExits.toList(); | 1773 List<P> exits = pendingExits.toList(); |
1765 pendingExits = new ListBuffer<AssignPendingExit>(); | 1774 pendingExits = new ListBuffer<>(); |
1766 while (exits.nonEmpty()) { | 1775 while (exits.nonEmpty()) { |
1767 AssignPendingExit exit = exits.head; | 1776 P exit = exits.head; |
1768 exits = exits.tail; | 1777 exits = exits.tail; |
1769 Assert.check(exit.tree.hasTag(RETURN), exit.tree); | 1778 Assert.check(exit.tree.hasTag(RETURN), exit.tree); |
1770 if (isInitialConstructor) { | 1779 if (isInitialConstructor) { |
1771 inits.assign(exit.exit_inits); | 1780 assignToInits(exit.tree, exit.exit_inits); |
1772 for (int i = firstadr; i < nextadr; i++) | 1781 for (int i = firstadr; i < nextadr; i++) { |
1773 checkInit(exit.tree.pos(), vardecls[i].sym); | 1782 checkInit(exit.tree.pos(), vardecls[i].sym); |
1783 } | |
1774 } | 1784 } |
1775 } | 1785 } |
1776 } finally { | 1786 } finally { |
1777 inits.assign(initsPrev); | 1787 assignToInits(tree, initsPrev); |
1778 uninits.assign(uninitsPrev); | 1788 uninits.assign(uninitsPrev); |
1779 nextadr = nextadrPrev; | 1789 nextadr = nextadrPrev; |
1780 firstadr = firstadrPrev; | 1790 firstadr = firstadrPrev; |
1781 returnadr = returnadrPrev; | 1791 returnadr = returnadrPrev; |
1782 lint = lintPrev; | 1792 } |
1783 } | 1793 } |
1794 | |
1795 protected void initParam(JCVariableDecl def) { | |
1796 inits.incl(def.sym.adr); | |
1797 uninits.excl(def.sym.adr); | |
1784 } | 1798 } |
1785 | 1799 |
1786 public void visitVarDef(JCVariableDecl tree) { | 1800 public void visitVarDef(JCVariableDecl tree) { |
1787 boolean track = trackable(tree.sym); | 1801 boolean track = trackable(tree.sym); |
1788 if (track && tree.sym.owner.kind == MTH) newVar(tree); | 1802 if (track && tree.sym.owner.kind == MTH) { |
1803 newVar(tree); | |
1804 } | |
1789 if (tree.init != null) { | 1805 if (tree.init != null) { |
1790 Lint lintPrev = lint; | 1806 scanExpr(tree.init); |
1791 lint = lint.augment(tree.sym); | 1807 if (track) { |
1792 try{ | 1808 letInit(tree.pos(), tree.sym); |
1793 scanExpr(tree.init); | |
1794 if (track) letInit(tree.pos(), tree.sym); | |
1795 } finally { | |
1796 lint = lintPrev; | |
1797 } | 1809 } |
1798 } | 1810 } |
1799 } | 1811 } |
1800 | 1812 |
1801 public void visitBlock(JCBlock tree) { | 1813 public void visitBlock(JCBlock tree) { |
1802 int nextadrPrev = nextadr; | 1814 int nextadrPrev = nextadr; |
1803 scan(tree.stats); | 1815 scan(tree.stats); |
1804 nextadr = nextadrPrev; | 1816 nextadr = nextadrPrev; |
1805 } | 1817 } |
1806 | 1818 |
1819 int getLogNumberOfErrors() { | |
1820 return 0; | |
1821 } | |
1822 | |
1807 public void visitDoLoop(JCDoWhileLoop tree) { | 1823 public void visitDoLoop(JCDoWhileLoop tree) { |
1808 ListBuffer<AssignPendingExit> prevPendingExits = pendingExits; | 1824 ListBuffer<P> prevPendingExits = pendingExits; |
1809 FlowKind prevFlowKind = flowKind; | 1825 FlowKind prevFlowKind = flowKind; |
1810 flowKind = FlowKind.NORMAL; | 1826 flowKind = FlowKind.NORMAL; |
1811 final Bits initsSkip = new Bits(true); | 1827 final Bits initsSkip = new Bits(true); |
1812 final Bits uninitsSkip = new Bits(true); | 1828 final Bits uninitsSkip = new Bits(true); |
1813 pendingExits = new ListBuffer<AssignPendingExit>(); | 1829 pendingExits = new ListBuffer<P>(); |
1814 int prevErrors = log.nerrors; | 1830 int prevErrors = getLogNumberOfErrors(); |
1815 do { | 1831 do { |
1816 final Bits uninitsEntry = new Bits(uninits); | 1832 final Bits uninitsEntry = new Bits(uninits); |
1817 uninitsEntry.excludeFrom(nextadr); | 1833 uninitsEntry.excludeFrom(nextadr); |
1818 scan(tree.body); | 1834 scan(tree.body); |
1819 resolveContinues(tree); | 1835 resolveContinues(tree); |
1820 scanCond(tree.cond); | 1836 scanCond(tree.cond); |
1821 if (!flowKind.isFinal()) { | 1837 if (!flowKind.isFinal()) { |
1822 initsSkip.assign(initsWhenFalse); | 1838 initsSkip.assign(initsWhenFalse); |
1823 uninitsSkip.assign(uninitsWhenFalse); | 1839 uninitsSkip.assign(uninitsWhenFalse); |
1824 } | 1840 } |
1825 if (log.nerrors != prevErrors || | 1841 if (getLogNumberOfErrors() != prevErrors || |
1826 flowKind.isFinal() || | 1842 flowKind.isFinal() || |
1827 new Bits(uninitsEntry).diffSet(uninitsWhenTrue).nextBit(firstadr)==-1) | 1843 new Bits(uninitsEntry).diffSet(uninitsWhenTrue).nextBit(firstadr)==-1) |
1828 break; | 1844 break; |
1829 inits.assign(initsWhenTrue); | 1845 assignToInits(tree.cond, initsWhenTrue); |
1830 uninits.assign(uninitsEntry.andSet(uninitsWhenTrue)); | 1846 uninits.assign(uninitsEntry.andSet(uninitsWhenTrue)); |
1831 flowKind = FlowKind.SPECULATIVE_LOOP; | 1847 flowKind = FlowKind.SPECULATIVE_LOOP; |
1832 } while (true); | 1848 } while (true); |
1833 flowKind = prevFlowKind; | 1849 flowKind = prevFlowKind; |
1834 inits.assign(initsSkip); | 1850 assignToInits(tree, initsSkip); |
1835 uninits.assign(uninitsSkip); | 1851 uninits.assign(uninitsSkip); |
1836 resolveBreaks(tree, prevPendingExits); | 1852 resolveBreaks(tree, prevPendingExits); |
1837 } | 1853 } |
1838 | 1854 |
1839 public void visitWhileLoop(JCWhileLoop tree) { | 1855 public void visitWhileLoop(JCWhileLoop tree) { |
1840 ListBuffer<AssignPendingExit> prevPendingExits = pendingExits; | 1856 ListBuffer<P> prevPendingExits = pendingExits; |
1841 FlowKind prevFlowKind = flowKind; | 1857 FlowKind prevFlowKind = flowKind; |
1842 flowKind = FlowKind.NORMAL; | 1858 flowKind = FlowKind.NORMAL; |
1843 final Bits initsSkip = new Bits(true); | 1859 final Bits initsSkip = new Bits(true); |
1844 final Bits uninitsSkip = new Bits(true); | 1860 final Bits uninitsSkip = new Bits(true); |
1845 pendingExits = new ListBuffer<AssignPendingExit>(); | 1861 pendingExits = new ListBuffer<>(); |
1846 int prevErrors = log.nerrors; | 1862 int prevErrors = getLogNumberOfErrors(); |
1847 final Bits uninitsEntry = new Bits(uninits); | 1863 final Bits uninitsEntry = new Bits(uninits); |
1848 uninitsEntry.excludeFrom(nextadr); | 1864 uninitsEntry.excludeFrom(nextadr); |
1849 do { | 1865 do { |
1850 scanCond(tree.cond); | 1866 scanCond(tree.cond); |
1851 if (!flowKind.isFinal()) { | 1867 if (!flowKind.isFinal()) { |
1852 initsSkip.assign(initsWhenFalse) ; | 1868 initsSkip.assign(initsWhenFalse) ; |
1853 uninitsSkip.assign(uninitsWhenFalse); | 1869 uninitsSkip.assign(uninitsWhenFalse); |
1854 } | 1870 } |
1855 inits.assign(initsWhenTrue); | 1871 assignToInits(tree, initsWhenTrue); |
1856 uninits.assign(uninitsWhenTrue); | 1872 uninits.assign(uninitsWhenTrue); |
1857 scan(tree.body); | 1873 scan(tree.body); |
1858 resolveContinues(tree); | 1874 resolveContinues(tree); |
1859 if (log.nerrors != prevErrors || | 1875 if (getLogNumberOfErrors() != prevErrors || |
1860 flowKind.isFinal() || | 1876 flowKind.isFinal() || |
1861 new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1) | 1877 new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1) { |
1862 break; | 1878 break; |
1879 } | |
1863 uninits.assign(uninitsEntry.andSet(uninits)); | 1880 uninits.assign(uninitsEntry.andSet(uninits)); |
1864 flowKind = FlowKind.SPECULATIVE_LOOP; | 1881 flowKind = FlowKind.SPECULATIVE_LOOP; |
1865 } while (true); | 1882 } while (true); |
1866 flowKind = prevFlowKind; | 1883 flowKind = prevFlowKind; |
1867 //a variable is DA/DU after the while statement, if it's DA/DU assuming the | 1884 //a variable is DA/DU after the while statement, if it's DA/DU assuming the |
1868 //branch is not taken AND if it's DA/DU before any break statement | 1885 //branch is not taken AND if it's DA/DU before any break statement |
1869 inits.assign(initsSkip); | 1886 assignToInits(tree.body, initsSkip); |
1870 uninits.assign(uninitsSkip); | 1887 uninits.assign(uninitsSkip); |
1871 resolveBreaks(tree, prevPendingExits); | 1888 resolveBreaks(tree, prevPendingExits); |
1872 } | 1889 } |
1873 | 1890 |
1874 public void visitForLoop(JCForLoop tree) { | 1891 public void visitForLoop(JCForLoop tree) { |
1875 ListBuffer<AssignPendingExit> prevPendingExits = pendingExits; | 1892 ListBuffer<P> prevPendingExits = pendingExits; |
1876 FlowKind prevFlowKind = flowKind; | 1893 FlowKind prevFlowKind = flowKind; |
1877 flowKind = FlowKind.NORMAL; | 1894 flowKind = FlowKind.NORMAL; |
1878 int nextadrPrev = nextadr; | 1895 int nextadrPrev = nextadr; |
1879 scan(tree.init); | 1896 scan(tree.init); |
1880 final Bits initsSkip = new Bits(true); | 1897 final Bits initsSkip = new Bits(true); |
1881 final Bits uninitsSkip = new Bits(true); | 1898 final Bits uninitsSkip = new Bits(true); |
1882 pendingExits = new ListBuffer<AssignPendingExit>(); | 1899 pendingExits = new ListBuffer<P>(); |
1883 int prevErrors = log.nerrors; | 1900 int prevErrors = getLogNumberOfErrors(); |
1884 do { | 1901 do { |
1885 final Bits uninitsEntry = new Bits(uninits); | 1902 final Bits uninitsEntry = new Bits(uninits); |
1886 uninitsEntry.excludeFrom(nextadr); | 1903 uninitsEntry.excludeFrom(nextadr); |
1887 if (tree.cond != null) { | 1904 if (tree.cond != null) { |
1888 scanCond(tree.cond); | 1905 scanCond(tree.cond); |
1889 if (!flowKind.isFinal()) { | 1906 if (!flowKind.isFinal()) { |
1890 initsSkip.assign(initsWhenFalse); | 1907 initsSkip.assign(initsWhenFalse); |
1891 uninitsSkip.assign(uninitsWhenFalse); | 1908 uninitsSkip.assign(uninitsWhenFalse); |
1892 } | 1909 } |
1893 inits.assign(initsWhenTrue); | 1910 assignToInits(tree.body, initsWhenTrue); |
1894 uninits.assign(uninitsWhenTrue); | 1911 uninits.assign(uninitsWhenTrue); |
1895 } else if (!flowKind.isFinal()) { | 1912 } else if (!flowKind.isFinal()) { |
1896 initsSkip.assign(inits); | 1913 initsSkip.assign(inits); |
1897 initsSkip.inclRange(firstadr, nextadr); | 1914 initsSkip.inclRange(firstadr, nextadr); |
1898 uninitsSkip.assign(uninits); | 1915 uninitsSkip.assign(uninits); |
1899 uninitsSkip.inclRange(firstadr, nextadr); | 1916 uninitsSkip.inclRange(firstadr, nextadr); |
1900 } | 1917 } |
1901 scan(tree.body); | 1918 scan(tree.body); |
1902 resolveContinues(tree); | 1919 resolveContinues(tree); |
1903 scan(tree.step); | 1920 scan(tree.step); |
1904 if (log.nerrors != prevErrors || | 1921 if (getLogNumberOfErrors() != prevErrors || |
1905 flowKind.isFinal() || | 1922 flowKind.isFinal() || |
1906 new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1) | 1923 new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1) |
1907 break; | 1924 break; |
1908 uninits.assign(uninitsEntry.andSet(uninits)); | 1925 uninits.assign(uninitsEntry.andSet(uninits)); |
1909 flowKind = FlowKind.SPECULATIVE_LOOP; | 1926 flowKind = FlowKind.SPECULATIVE_LOOP; |
1910 } while (true); | 1927 } while (true); |
1911 flowKind = prevFlowKind; | 1928 flowKind = prevFlowKind; |
1912 //a variable is DA/DU after a for loop, if it's DA/DU assuming the | 1929 //a variable is DA/DU after a for loop, if it's DA/DU assuming the |
1913 //branch is not taken AND if it's DA/DU before any break statement | 1930 //branch is not taken AND if it's DA/DU before any break statement |
1914 inits.assign(initsSkip); | 1931 assignToInits(tree.body, initsSkip); |
1915 uninits.assign(uninitsSkip); | 1932 uninits.assign(uninitsSkip); |
1916 resolveBreaks(tree, prevPendingExits); | 1933 resolveBreaks(tree, prevPendingExits); |
1917 nextadr = nextadrPrev; | 1934 nextadr = nextadrPrev; |
1918 } | 1935 } |
1919 | 1936 |
1920 public void visitForeachLoop(JCEnhancedForLoop tree) { | 1937 public void visitForeachLoop(JCEnhancedForLoop tree) { |
1921 visitVarDef(tree.var); | 1938 visitVarDef(tree.var); |
1922 | 1939 |
1923 ListBuffer<AssignPendingExit> prevPendingExits = pendingExits; | 1940 ListBuffer<P> prevPendingExits = pendingExits; |
1924 FlowKind prevFlowKind = flowKind; | 1941 FlowKind prevFlowKind = flowKind; |
1925 flowKind = FlowKind.NORMAL; | 1942 flowKind = FlowKind.NORMAL; |
1926 int nextadrPrev = nextadr; | 1943 int nextadrPrev = nextadr; |
1927 scan(tree.expr); | 1944 scan(tree.expr); |
1928 final Bits initsStart = new Bits(inits); | 1945 final Bits initsStart = new Bits(inits); |
1929 final Bits uninitsStart = new Bits(uninits); | 1946 final Bits uninitsStart = new Bits(uninits); |
1930 | 1947 |
1931 letInit(tree.pos(), tree.var.sym); | 1948 letInit(tree.pos(), tree.var.sym); |
1932 pendingExits = new ListBuffer<AssignPendingExit>(); | 1949 pendingExits = new ListBuffer<P>(); |
1933 int prevErrors = log.nerrors; | 1950 int prevErrors = getLogNumberOfErrors(); |
1934 do { | 1951 do { |
1935 final Bits uninitsEntry = new Bits(uninits); | 1952 final Bits uninitsEntry = new Bits(uninits); |
1936 uninitsEntry.excludeFrom(nextadr); | 1953 uninitsEntry.excludeFrom(nextadr); |
1937 scan(tree.body); | 1954 scan(tree.body); |
1938 resolveContinues(tree); | 1955 resolveContinues(tree); |
1939 if (log.nerrors != prevErrors || | 1956 if (getLogNumberOfErrors() != prevErrors || |
1940 flowKind.isFinal() || | 1957 flowKind.isFinal() || |
1941 new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1) | 1958 new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1) |
1942 break; | 1959 break; |
1943 uninits.assign(uninitsEntry.andSet(uninits)); | 1960 uninits.assign(uninitsEntry.andSet(uninits)); |
1944 flowKind = FlowKind.SPECULATIVE_LOOP; | 1961 flowKind = FlowKind.SPECULATIVE_LOOP; |
1945 } while (true); | 1962 } while (true); |
1946 flowKind = prevFlowKind; | 1963 flowKind = prevFlowKind; |
1947 inits.assign(initsStart); | 1964 assignToInits(tree.body, initsStart); |
1948 uninits.assign(uninitsStart.andSet(uninits)); | 1965 uninits.assign(uninitsStart.andSet(uninits)); |
1949 resolveBreaks(tree, prevPendingExits); | 1966 resolveBreaks(tree, prevPendingExits); |
1950 nextadr = nextadrPrev; | 1967 nextadr = nextadrPrev; |
1951 } | 1968 } |
1952 | 1969 |
1953 public void visitLabelled(JCLabeledStatement tree) { | 1970 public void visitLabelled(JCLabeledStatement tree) { |
1954 ListBuffer<AssignPendingExit> prevPendingExits = pendingExits; | 1971 ListBuffer<P> prevPendingExits = pendingExits; |
1955 pendingExits = new ListBuffer<AssignPendingExit>(); | 1972 pendingExits = new ListBuffer<P>(); |
1956 scan(tree.body); | 1973 scan(tree.body); |
1957 resolveBreaks(tree, prevPendingExits); | 1974 resolveBreaks(tree, prevPendingExits); |
1958 } | 1975 } |
1959 | 1976 |
1960 public void visitSwitch(JCSwitch tree) { | 1977 public void visitSwitch(JCSwitch tree) { |
1961 ListBuffer<AssignPendingExit> prevPendingExits = pendingExits; | 1978 ListBuffer<P> prevPendingExits = pendingExits; |
1962 pendingExits = new ListBuffer<AssignPendingExit>(); | 1979 pendingExits = new ListBuffer<>(); |
1963 int nextadrPrev = nextadr; | 1980 int nextadrPrev = nextadr; |
1964 scanExpr(tree.selector); | 1981 scanExpr(tree.selector); |
1965 final Bits initsSwitch = new Bits(inits); | 1982 final Bits initsSwitch = new Bits(inits); |
1966 final Bits uninitsSwitch = new Bits(uninits); | 1983 final Bits uninitsSwitch = new Bits(uninits); |
1967 boolean hasDefault = false; | 1984 boolean hasDefault = false; |
1968 for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) { | 1985 for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) { |
1969 inits.assign(initsSwitch); | 1986 assignToInits(l.head, initsSwitch); |
1970 uninits.assign(uninits.andSet(uninitsSwitch)); | 1987 uninits.assign(uninits.andSet(uninitsSwitch)); |
1971 JCCase c = l.head; | 1988 JCCase c = l.head; |
1972 if (c.pat == null) | 1989 if (c.pat == null) { |
1973 hasDefault = true; | 1990 hasDefault = true; |
1974 else | 1991 } else { |
1975 scanExpr(c.pat); | 1992 scanExpr(c.pat); |
1993 } | |
1994 if (hasDefault) { | |
1995 assignToInits(null, initsSwitch); | |
1996 uninits.assign(uninits.andSet(uninitsSwitch)); | |
1997 } | |
1976 scan(c.stats); | 1998 scan(c.stats); |
1977 addVars(c.stats, initsSwitch, uninitsSwitch); | 1999 addVars(c.stats, initsSwitch, uninitsSwitch); |
2000 if (!hasDefault) { | |
2001 assignToInits(l.head.stats.last(), initsSwitch); | |
2002 uninits.assign(uninits.andSet(uninitsSwitch)); | |
2003 } | |
1978 // Warn about fall-through if lint switch fallthrough enabled. | 2004 // Warn about fall-through if lint switch fallthrough enabled. |
1979 } | 2005 } |
1980 if (!hasDefault) { | 2006 if (!hasDefault) { |
1981 inits.andSet(initsSwitch); | 2007 andSetInits(null, initsSwitch); |
1982 } | 2008 } |
1983 resolveBreaks(tree, prevPendingExits); | 2009 resolveBreaks(tree, prevPendingExits); |
1984 nextadr = nextadrPrev; | 2010 nextadr = nextadrPrev; |
1985 } | 2011 } |
1986 // where | 2012 // where |
1995 uninits.incl(adr); | 2021 uninits.incl(adr); |
1996 } | 2022 } |
1997 } | 2023 } |
1998 } | 2024 } |
1999 | 2025 |
2026 boolean isEnabled(Lint.LintCategory lc) { | |
2027 return false; | |
2028 } | |
2029 | |
2030 void reportWarning(Lint.LintCategory lc, DiagnosticPosition pos, String key, Object ... args) {} | |
2031 | |
2000 public void visitTry(JCTry tree) { | 2032 public void visitTry(JCTry tree) { |
2001 ListBuffer<JCVariableDecl> resourceVarDecls = ListBuffer.lb(); | 2033 ListBuffer<JCVariableDecl> resourceVarDecls = ListBuffer.lb(); |
2002 final Bits uninitsTryPrev = new Bits(uninitsTry); | 2034 final Bits uninitsTryPrev = new Bits(uninitsTry); |
2003 ListBuffer<AssignPendingExit> prevPendingExits = pendingExits; | 2035 ListBuffer<P> prevPendingExits = pendingExits; |
2004 pendingExits = new ListBuffer<AssignPendingExit>(); | 2036 pendingExits = new ListBuffer<>(); |
2005 final Bits initsTry = new Bits(inits); | 2037 final Bits initsTry = new Bits(inits); |
2006 uninitsTry.assign(uninits); | 2038 uninitsTry.assign(uninits); |
2007 for (JCTree resource : tree.resources) { | 2039 for (JCTree resource : tree.resources) { |
2008 if (resource instanceof JCVariableDecl) { | 2040 if (resource instanceof JCVariableDecl) { |
2009 JCVariableDecl vdecl = (JCVariableDecl) resource; | 2041 JCVariableDecl vdecl = (JCVariableDecl) resource; |
2021 final Bits initsEnd = new Bits(inits); | 2053 final Bits initsEnd = new Bits(inits); |
2022 final Bits uninitsEnd = new Bits(uninits); | 2054 final Bits uninitsEnd = new Bits(uninits); |
2023 int nextadrCatch = nextadr; | 2055 int nextadrCatch = nextadr; |
2024 | 2056 |
2025 if (!resourceVarDecls.isEmpty() && | 2057 if (!resourceVarDecls.isEmpty() && |
2026 lint.isEnabled(Lint.LintCategory.TRY)) { | 2058 isEnabled(Lint.LintCategory.TRY)) { |
2027 for (JCVariableDecl resVar : resourceVarDecls) { | 2059 for (JCVariableDecl resVar : resourceVarDecls) { |
2028 if (unrefdResources.includes(resVar.sym)) { | 2060 if (unrefdResources.includes(resVar.sym)) { |
2029 log.warning(Lint.LintCategory.TRY, resVar.pos(), | 2061 reportWarning(Lint.LintCategory.TRY, resVar.pos(), |
2030 "try.resource.not.referenced", resVar.sym); | 2062 "try.resource.not.referenced", resVar.sym); |
2031 unrefdResources.remove(resVar.sym); | 2063 unrefdResources.remove(resVar.sym); |
2032 } | 2064 } |
2033 } | 2065 } |
2034 } | 2066 } |
2040 final Bits initsCatchPrev = new Bits(initsTry); | 2072 final Bits initsCatchPrev = new Bits(initsTry); |
2041 final Bits uninitsCatchPrev = new Bits(uninitsTry); | 2073 final Bits uninitsCatchPrev = new Bits(uninitsTry); |
2042 | 2074 |
2043 for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) { | 2075 for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) { |
2044 JCVariableDecl param = l.head.param; | 2076 JCVariableDecl param = l.head.param; |
2045 inits.assign(initsCatchPrev); | 2077 assignToInits(tree.body, initsCatchPrev); |
2046 uninits.assign(uninitsCatchPrev); | 2078 uninits.assign(uninitsCatchPrev); |
2047 scan(param); | 2079 scan(param); |
2048 inits.incl(param.sym.adr); | 2080 /* If this is a TWR and we are executing the code from Gen, |
2049 uninits.excl(param.sym.adr); | 2081 * then there can be synthetic variables, ignore them. |
2082 */ | |
2083 initParam(param); | |
2050 scan(l.head.body); | 2084 scan(l.head.body); |
2051 initsEnd.andSet(inits); | 2085 initsEnd.andSet(inits); |
2052 uninitsEnd.andSet(uninits); | 2086 uninitsEnd.andSet(uninits); |
2053 nextadr = nextadrCatch; | 2087 nextadr = nextadrCatch; |
2054 } | 2088 } |
2055 if (tree.finalizer != null) { | 2089 if (tree.finalizer != null) { |
2056 inits.assign(initsTry); | 2090 assignToInits(tree.finalizer, initsTry); |
2057 uninits.assign(uninitsTry); | 2091 uninits.assign(uninitsTry); |
2058 ListBuffer<AssignPendingExit> exits = pendingExits; | 2092 ListBuffer<P> exits = pendingExits; |
2059 pendingExits = prevPendingExits; | 2093 pendingExits = prevPendingExits; |
2060 scan(tree.finalizer); | 2094 scan(tree.finalizer); |
2061 if (!tree.finallyCanCompleteNormally) { | 2095 if (!tree.finallyCanCompleteNormally) { |
2062 // discard exits and exceptions from try and finally | 2096 // discard exits and exceptions from try and finally |
2063 } else { | 2097 } else { |
2064 uninits.andSet(uninitsEnd); | 2098 uninits.andSet(uninitsEnd); |
2065 // FIX: this doesn't preserve source order of exits in catch | 2099 // FIX: this doesn't preserve source order of exits in catch |
2066 // versus finally! | 2100 // versus finally! |
2067 while (exits.nonEmpty()) { | 2101 while (exits.nonEmpty()) { |
2068 AssignPendingExit exit = exits.next(); | 2102 P exit = exits.next(); |
2069 if (exit.exit_inits != null) { | 2103 if (exit.exit_inits != null) { |
2070 exit.exit_inits.orSet(inits); | 2104 exit.exit_inits.orSet(inits); |
2071 exit.exit_uninits.andSet(uninits); | 2105 exit.exit_uninits.andSet(uninits); |
2072 } | 2106 } |
2073 pendingExits.append(exit); | 2107 pendingExits.append(exit); |
2074 } | 2108 } |
2075 inits.orSet(initsEnd); | 2109 orSetInits(tree, initsEnd); |
2076 } | 2110 } |
2077 } else { | 2111 } else { |
2078 inits.assign(initsEnd); | 2112 assignToInits(tree, initsEnd); |
2079 uninits.assign(uninitsEnd); | 2113 uninits.assign(uninitsEnd); |
2080 ListBuffer<AssignPendingExit> exits = pendingExits; | 2114 ListBuffer<P> exits = pendingExits; |
2081 pendingExits = prevPendingExits; | 2115 pendingExits = prevPendingExits; |
2082 while (exits.nonEmpty()) pendingExits.append(exits.next()); | 2116 while (exits.nonEmpty()) pendingExits.append(exits.next()); |
2083 } | 2117 } |
2084 uninitsTry.andSet(uninitsTryPrev).andSet(uninits); | 2118 uninitsTry.andSet(uninitsTryPrev).andSet(uninits); |
2085 } | 2119 } |
2086 | 2120 |
2087 public void visitConditional(JCConditional tree) { | 2121 public void visitConditional(JCConditional tree) { |
2088 scanCond(tree.cond); | 2122 scanCond(tree.cond); |
2089 final Bits initsBeforeElse = new Bits(initsWhenFalse); | 2123 final Bits initsBeforeElse = new Bits(initsWhenFalse); |
2090 final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse); | 2124 final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse); |
2091 inits.assign(initsWhenTrue); | 2125 assignToInits(tree.cond, initsWhenTrue); |
2092 uninits.assign(uninitsWhenTrue); | 2126 uninits.assign(uninitsWhenTrue); |
2093 if (tree.truepart.type.hasTag(BOOLEAN) && | 2127 if (tree.truepart.type.hasTag(BOOLEAN) && |
2094 tree.falsepart.type.hasTag(BOOLEAN)) { | 2128 tree.falsepart.type.hasTag(BOOLEAN)) { |
2095 // if b and c are boolean valued, then | 2129 // if b and c are boolean valued, then |
2096 // v is (un)assigned after a?b:c when true iff | 2130 // v is (un)assigned after a?b:c when true iff |
2099 scanCond(tree.truepart); | 2133 scanCond(tree.truepart); |
2100 final Bits initsAfterThenWhenTrue = new Bits(initsWhenTrue); | 2134 final Bits initsAfterThenWhenTrue = new Bits(initsWhenTrue); |
2101 final Bits initsAfterThenWhenFalse = new Bits(initsWhenFalse); | 2135 final Bits initsAfterThenWhenFalse = new Bits(initsWhenFalse); |
2102 final Bits uninitsAfterThenWhenTrue = new Bits(uninitsWhenTrue); | 2136 final Bits uninitsAfterThenWhenTrue = new Bits(uninitsWhenTrue); |
2103 final Bits uninitsAfterThenWhenFalse = new Bits(uninitsWhenFalse); | 2137 final Bits uninitsAfterThenWhenFalse = new Bits(uninitsWhenFalse); |
2104 inits.assign(initsBeforeElse); | 2138 assignToInits(tree.truepart, initsBeforeElse); |
2105 uninits.assign(uninitsBeforeElse); | 2139 uninits.assign(uninitsBeforeElse); |
2106 scanCond(tree.falsepart); | 2140 scanCond(tree.falsepart); |
2107 initsWhenTrue.andSet(initsAfterThenWhenTrue); | 2141 initsWhenTrue.andSet(initsAfterThenWhenTrue); |
2108 initsWhenFalse.andSet(initsAfterThenWhenFalse); | 2142 initsWhenFalse.andSet(initsAfterThenWhenFalse); |
2109 uninitsWhenTrue.andSet(uninitsAfterThenWhenTrue); | 2143 uninitsWhenTrue.andSet(uninitsAfterThenWhenTrue); |
2110 uninitsWhenFalse.andSet(uninitsAfterThenWhenFalse); | 2144 uninitsWhenFalse.andSet(uninitsAfterThenWhenFalse); |
2111 } else { | 2145 } else { |
2112 scanExpr(tree.truepart); | 2146 scanExpr(tree.truepart); |
2113 final Bits initsAfterThen = new Bits(inits); | 2147 final Bits initsAfterThen = new Bits(inits); |
2114 final Bits uninitsAfterThen = new Bits(uninits); | 2148 final Bits uninitsAfterThen = new Bits(uninits); |
2115 inits.assign(initsBeforeElse); | 2149 assignToInits(tree.truepart, initsBeforeElse); |
2116 uninits.assign(uninitsBeforeElse); | 2150 uninits.assign(uninitsBeforeElse); |
2117 scanExpr(tree.falsepart); | 2151 scanExpr(tree.falsepart); |
2118 inits.andSet(initsAfterThen); | 2152 andSetInits(tree.falsepart, initsAfterThen); |
2119 uninits.andSet(uninitsAfterThen); | 2153 uninits.andSet(uninitsAfterThen); |
2120 } | 2154 } |
2121 } | 2155 } |
2122 | 2156 |
2123 public void visitIf(JCIf tree) { | 2157 public void visitIf(JCIf tree) { |
2124 scanCond(tree.cond); | 2158 scanCond(tree.cond); |
2125 final Bits initsBeforeElse = new Bits(initsWhenFalse); | 2159 final Bits initsBeforeElse = new Bits(initsWhenFalse); |
2126 final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse); | 2160 final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse); |
2127 inits.assign(initsWhenTrue); | 2161 assignToInits(tree.cond, initsWhenTrue); |
2128 uninits.assign(uninitsWhenTrue); | 2162 uninits.assign(uninitsWhenTrue); |
2129 scan(tree.thenpart); | 2163 scan(tree.thenpart); |
2130 if (tree.elsepart != null) { | 2164 if (tree.elsepart != null) { |
2131 final Bits initsAfterThen = new Bits(inits); | 2165 final Bits initsAfterThen = new Bits(inits); |
2132 final Bits uninitsAfterThen = new Bits(uninits); | 2166 final Bits uninitsAfterThen = new Bits(uninits); |
2133 inits.assign(initsBeforeElse); | 2167 assignToInits(tree.thenpart, initsBeforeElse); |
2134 uninits.assign(uninitsBeforeElse); | 2168 uninits.assign(uninitsBeforeElse); |
2135 scan(tree.elsepart); | 2169 scan(tree.elsepart); |
2136 inits.andSet(initsAfterThen); | 2170 andSetInits(tree.elsepart, initsAfterThen); |
2137 uninits.andSet(uninitsAfterThen); | 2171 uninits.andSet(uninitsAfterThen); |
2138 } else { | 2172 } else { |
2139 inits.andSet(initsBeforeElse); | 2173 andSetInits(tree.thenpart, initsBeforeElse); |
2140 uninits.andSet(uninitsBeforeElse); | 2174 uninits.andSet(uninitsBeforeElse); |
2141 } | 2175 } |
2142 } | 2176 } |
2143 | 2177 |
2178 protected P createNewPendingExit(JCTree tree, Bits inits, Bits uninits) { | |
2179 return null; | |
2180 } | |
2181 | |
2182 @Override | |
2144 public void visitBreak(JCBreak tree) { | 2183 public void visitBreak(JCBreak tree) { |
2145 recordExit(tree, new AssignPendingExit(tree, inits, uninits)); | 2184 recordExit(tree, createNewPendingExit(tree, inits, uninits)); |
2146 } | 2185 } |
2147 | 2186 |
2187 @Override | |
2148 public void visitContinue(JCContinue tree) { | 2188 public void visitContinue(JCContinue tree) { |
2149 recordExit(tree, new AssignPendingExit(tree, inits, uninits)); | 2189 recordExit(tree, createNewPendingExit(tree, inits, uninits)); |
2150 } | 2190 } |
2151 | 2191 |
2192 @Override | |
2152 public void visitReturn(JCReturn tree) { | 2193 public void visitReturn(JCReturn tree) { |
2153 scanExpr(tree.expr); | 2194 scanExpr(tree.expr); |
2154 recordExit(tree, new AssignPendingExit(tree, inits, uninits)); | 2195 recordExit(tree, createNewPendingExit(tree, inits, uninits)); |
2155 } | 2196 } |
2156 | 2197 |
2157 public void visitThrow(JCThrow tree) { | 2198 public void visitThrow(JCThrow tree) { |
2158 scanExpr(tree.expr); | 2199 scanExpr(tree.expr); |
2159 markDead(); | 2200 markDead(tree.expr); |
2160 } | 2201 } |
2161 | 2202 |
2162 public void visitApply(JCMethodInvocation tree) { | 2203 public void visitApply(JCMethodInvocation tree) { |
2163 scanExpr(tree.meth); | 2204 scanExpr(tree.meth); |
2164 scanExprs(tree.args); | 2205 scanExprs(tree.args); |
2173 @Override | 2214 @Override |
2174 public void visitLambda(JCLambda tree) { | 2215 public void visitLambda(JCLambda tree) { |
2175 final Bits prevUninits = new Bits(uninits); | 2216 final Bits prevUninits = new Bits(uninits); |
2176 final Bits prevInits = new Bits(inits); | 2217 final Bits prevInits = new Bits(inits); |
2177 int returnadrPrev = returnadr; | 2218 int returnadrPrev = returnadr; |
2178 ListBuffer<AssignPendingExit> prevPending = pendingExits; | 2219 ListBuffer<P> prevPending = pendingExits; |
2179 try { | 2220 try { |
2180 returnadr = nextadr; | 2221 returnadr = nextadr; |
2181 pendingExits = new ListBuffer<AssignPendingExit>(); | 2222 pendingExits = new ListBuffer<P>(); |
2182 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) { | 2223 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) { |
2183 JCVariableDecl def = l.head; | 2224 JCVariableDecl def = l.head; |
2184 scan(def); | 2225 scan(def); |
2185 inits.incl(def.sym.adr); | 2226 inits.incl(def.sym.adr); |
2186 uninits.excl(def.sym.adr); | 2227 uninits.excl(def.sym.adr); |
2192 } | 2233 } |
2193 } | 2234 } |
2194 finally { | 2235 finally { |
2195 returnadr = returnadrPrev; | 2236 returnadr = returnadrPrev; |
2196 uninits.assign(prevUninits); | 2237 uninits.assign(prevUninits); |
2197 inits.assign(prevInits); | 2238 assignToInits(tree, prevInits); |
2198 pendingExits = prevPending; | 2239 pendingExits = prevPending; |
2199 } | 2240 } |
2200 } | 2241 } |
2201 | 2242 |
2202 public void visitNewArray(JCNewArray tree) { | 2243 public void visitNewArray(JCNewArray tree) { |
2208 final Bits initsExit = new Bits(inits); | 2249 final Bits initsExit = new Bits(inits); |
2209 final Bits uninitsExit = new Bits(uninits); | 2250 final Bits uninitsExit = new Bits(uninits); |
2210 scanCond(tree.cond); | 2251 scanCond(tree.cond); |
2211 uninitsExit.andSet(uninitsWhenTrue); | 2252 uninitsExit.andSet(uninitsWhenTrue); |
2212 if (tree.detail != null) { | 2253 if (tree.detail != null) { |
2213 inits.assign(initsWhenFalse); | 2254 assignToInits(tree, initsWhenFalse); |
2214 uninits.assign(uninitsWhenFalse); | 2255 uninits.assign(uninitsWhenFalse); |
2215 scanExpr(tree.detail); | 2256 scanExpr(tree.detail); |
2216 } | 2257 } |
2217 inits.assign(initsExit); | 2258 assignToInits(tree, initsExit); |
2218 uninits.assign(uninitsExit); | 2259 uninits.assign(uninitsExit); |
2219 } | 2260 } |
2220 | 2261 |
2221 public void visitAssign(JCAssign tree) { | 2262 public void visitAssign(JCAssign tree) { |
2222 JCTree lhs = TreeInfo.skipParens(tree.lhs); | 2263 JCTree lhs = TreeInfo.skipParens(tree.lhs); |
2258 switch (tree.getTag()) { | 2299 switch (tree.getTag()) { |
2259 case AND: | 2300 case AND: |
2260 scanCond(tree.lhs); | 2301 scanCond(tree.lhs); |
2261 final Bits initsWhenFalseLeft = new Bits(initsWhenFalse); | 2302 final Bits initsWhenFalseLeft = new Bits(initsWhenFalse); |
2262 final Bits uninitsWhenFalseLeft = new Bits(uninitsWhenFalse); | 2303 final Bits uninitsWhenFalseLeft = new Bits(uninitsWhenFalse); |
2263 inits.assign(initsWhenTrue); | 2304 assignToInits(tree.lhs, initsWhenTrue); |
2264 uninits.assign(uninitsWhenTrue); | 2305 uninits.assign(uninitsWhenTrue); |
2265 scanCond(tree.rhs); | 2306 scanCond(tree.rhs); |
2266 initsWhenFalse.andSet(initsWhenFalseLeft); | 2307 initsWhenFalse.andSet(initsWhenFalseLeft); |
2267 uninitsWhenFalse.andSet(uninitsWhenFalseLeft); | 2308 uninitsWhenFalse.andSet(uninitsWhenFalseLeft); |
2268 break; | 2309 break; |
2269 case OR: | 2310 case OR: |
2270 scanCond(tree.lhs); | 2311 scanCond(tree.lhs); |
2271 final Bits initsWhenTrueLeft = new Bits(initsWhenTrue); | 2312 final Bits initsWhenTrueLeft = new Bits(initsWhenTrue); |
2272 final Bits uninitsWhenTrueLeft = new Bits(uninitsWhenTrue); | 2313 final Bits uninitsWhenTrueLeft = new Bits(uninitsWhenTrue); |
2273 inits.assign(initsWhenFalse); | 2314 assignToInits(tree.lhs, initsWhenFalse); |
2274 uninits.assign(uninitsWhenFalse); | 2315 uninits.assign(uninitsWhenFalse); |
2275 scanCond(tree.rhs); | 2316 scanCond(tree.rhs); |
2276 initsWhenTrue.andSet(initsWhenTrueLeft); | 2317 initsWhenTrue.andSet(initsWhenTrueLeft); |
2277 uninitsWhenTrue.andSet(uninitsWhenTrueLeft); | 2318 uninitsWhenTrue.andSet(uninitsWhenTrueLeft); |
2278 break; | 2319 break; |
2306 * main method | 2347 * main method |
2307 *************************************************************************/ | 2348 *************************************************************************/ |
2308 | 2349 |
2309 /** Perform definite assignment/unassignment analysis on a tree. | 2350 /** Perform definite assignment/unassignment analysis on a tree. |
2310 */ | 2351 */ |
2311 public void analyzeTree(Env<AttrContext> env, TreeMaker make) { | 2352 public void analyzeTree(Env<?> env) { |
2312 analyzeTree(env, env.tree, make); | 2353 analyzeTree(env, env.tree); |
2313 } | 2354 } |
2314 | 2355 |
2315 public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) { | 2356 public void analyzeTree(Env<?> env, JCTree tree) { |
2316 try { | 2357 try { |
2317 attrEnv = env; | |
2318 Flow.this.make = make; | |
2319 startPos = tree.pos().getStartPosition(); | 2358 startPos = tree.pos().getStartPosition(); |
2320 | 2359 |
2321 if (vardecls == null) | 2360 if (vardecls == null) |
2322 vardecls = new JCVariableDecl[32]; | 2361 vardecls = new JCVariableDecl[32]; |
2323 else | 2362 else |
2324 for (int i=0; i<vardecls.length; i++) | 2363 for (int i=0; i<vardecls.length; i++) |
2325 vardecls[i] = null; | 2364 vardecls[i] = null; |
2326 firstadr = 0; | 2365 firstadr = 0; |
2327 nextadr = 0; | 2366 nextadr = 0; |
2328 pendingExits = new ListBuffer<AssignPendingExit>(); | 2367 pendingExits = new ListBuffer<>(); |
2329 this.classDef = null; | 2368 this.classDef = null; |
2330 unrefdResources = new Scope(env.enclClass.sym); | 2369 unrefdResources = new Scope(env.enclClass.sym); |
2331 scan(tree); | 2370 scan(tree); |
2332 } finally { | 2371 } finally { |
2333 // note that recursive invocations of this method fail hard | 2372 // note that recursive invocations of this method fail hard |
2334 startPos = -1; | 2373 startPos = -1; |
2335 resetBits(inits, uninits, uninitsTry, initsWhenTrue, | 2374 resetBits(inits, uninits, uninitsTry, initsWhenTrue, |
2336 initsWhenFalse, uninitsWhenTrue, uninitsWhenFalse); | 2375 initsWhenFalse, uninitsWhenTrue, uninitsWhenFalse); |
2337 if (vardecls != null) for (int i=0; i<vardecls.length; i++) | 2376 if (vardecls != null) { |
2338 vardecls[i] = null; | 2377 for (int i=0; i<vardecls.length; i++) |
2378 vardecls[i] = null; | |
2379 } | |
2339 firstadr = 0; | 2380 firstadr = 0; |
2340 nextadr = 0; | 2381 nextadr = 0; |
2341 pendingExits = null; | 2382 pendingExits = null; |
2342 Flow.this.make = null; | |
2343 this.classDef = null; | 2383 this.classDef = null; |
2344 unrefdResources = null; | 2384 unrefdResources = null; |
2345 } | 2385 } |
2346 } | 2386 } |
2387 } | |
2388 | |
2389 public static class AssignAnalyzer | |
2390 extends AbstractAssignAnalyzer<AssignAnalyzer.AssignPendingExit> { | |
2391 | |
2392 Log log; | |
2393 Lint lint; | |
2394 | |
2395 public static class AssignPendingExit | |
2396 extends AbstractAssignAnalyzer.AbstractAssignPendingExit { | |
2397 | |
2398 public AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) { | |
2399 super(tree, inits, uninits); | |
2400 } | |
2401 } | |
2402 | |
2403 public AssignAnalyzer(Log log, Symtab syms, Lint lint, Names names) { | |
2404 super(new Bits(), syms, names); | |
2405 this.log = log; | |
2406 this.lint = lint; | |
2407 } | |
2408 | |
2409 @Override | |
2410 protected AssignPendingExit createNewPendingExit(JCTree tree, | |
2411 Bits inits, Bits uninits) { | |
2412 return new AssignPendingExit(tree, inits, uninits); | |
2413 } | |
2414 | |
2415 /** Record an initialization of a trackable variable. | |
2416 */ | |
2417 @Override | |
2418 void letInit(DiagnosticPosition pos, VarSymbol sym) { | |
2419 if (sym.adr >= firstadr && trackable(sym)) { | |
2420 if ((sym.flags() & EFFECTIVELY_FINAL) != 0) { | |
2421 if (!uninits.isMember(sym.adr)) { | |
2422 //assignment targeting an effectively final variable | |
2423 //makes the variable lose its status of effectively final | |
2424 //if the variable is _not_ definitively unassigned | |
2425 sym.flags_field &= ~EFFECTIVELY_FINAL; | |
2426 } else { | |
2427 uninit(sym); | |
2428 } | |
2429 } | |
2430 else if ((sym.flags() & FINAL) != 0) { | |
2431 if ((sym.flags() & PARAMETER) != 0) { | |
2432 if ((sym.flags() & UNION) != 0) { //multi-catch parameter | |
2433 log.error(pos, "multicatch.parameter.may.not.be.assigned", sym); | |
2434 } | |
2435 else { | |
2436 log.error(pos, "final.parameter.may.not.be.assigned", | |
2437 sym); | |
2438 } | |
2439 } else if (!uninits.isMember(sym.adr)) { | |
2440 log.error(pos, flowKind.errKey, sym); | |
2441 } else { | |
2442 uninit(sym); | |
2443 } | |
2444 } | |
2445 inits.incl(sym.adr); | |
2446 } else if ((sym.flags() & FINAL) != 0) { | |
2447 log.error(pos, "var.might.already.be.assigned", sym); | |
2448 } | |
2449 } | |
2450 | |
2451 @Override | |
2452 void checkInit(DiagnosticPosition pos, VarSymbol sym, String errkey) { | |
2453 if ((sym.adr >= firstadr || sym.owner.kind != TYP) && | |
2454 trackable(sym) && | |
2455 !inits.isMember(sym.adr)) { | |
2456 log.error(pos, errkey, sym); | |
2457 inits.incl(sym.adr); | |
2458 } | |
2459 } | |
2460 | |
2461 @Override | |
2462 void reportWarning(Lint.LintCategory lc, DiagnosticPosition pos, | |
2463 String key, Object ... args) { | |
2464 log.warning(lc, pos, key, args); | |
2465 } | |
2466 | |
2467 @Override | |
2468 int getLogNumberOfErrors() { | |
2469 return log.nerrors; | |
2470 } | |
2471 | |
2472 @Override | |
2473 boolean isEnabled(Lint.LintCategory lc) { | |
2474 return lint.isEnabled(lc); | |
2475 } | |
2476 | |
2477 @Override | |
2478 public void visitClassDef(JCClassDecl tree) { | |
2479 if (tree.sym == null) { | |
2480 return; | |
2481 } | |
2482 | |
2483 Lint lintPrev = lint; | |
2484 lint = lint.augment(tree.sym); | |
2485 try { | |
2486 super.visitClassDef(tree); | |
2487 } finally { | |
2488 lint = lintPrev; | |
2489 } | |
2490 } | |
2491 | |
2492 @Override | |
2493 public void visitMethodDef(JCMethodDecl tree) { | |
2494 if (tree.body == null) { | |
2495 return; | |
2496 } | |
2497 | |
2498 /* MemberEnter can generate synthetic methods ignore them | |
2499 */ | |
2500 if ((tree.sym.flags() & SYNTHETIC) != 0) { | |
2501 return; | |
2502 } | |
2503 | |
2504 Lint lintPrev = lint; | |
2505 lint = lint.augment(tree.sym); | |
2506 try { | |
2507 super.visitMethodDef(tree); | |
2508 } finally { | |
2509 lint = lintPrev; | |
2510 } | |
2511 } | |
2512 | |
2513 @Override | |
2514 public void visitVarDef(JCVariableDecl tree) { | |
2515 if (tree.init == null) { | |
2516 super.visitVarDef(tree); | |
2517 } else { | |
2518 Lint lintPrev = lint; | |
2519 lint = lint.augment(tree.sym); | |
2520 try{ | |
2521 super.visitVarDef(tree); | |
2522 } finally { | |
2523 lint = lintPrev; | |
2524 } | |
2525 } | |
2526 } | |
2527 | |
2347 } | 2528 } |
2348 | 2529 |
2349 /** | 2530 /** |
2350 * This pass implements the last step of the dataflow analysis, namely | 2531 * This pass implements the last step of the dataflow analysis, namely |
2351 * the effectively-final analysis check. This checks that every local variable | 2532 * the effectively-final analysis check. This checks that every local variable |
2356 class CaptureAnalyzer extends BaseAnalyzer<BaseAnalyzer.PendingExit> { | 2537 class CaptureAnalyzer extends BaseAnalyzer<BaseAnalyzer.PendingExit> { |
2357 | 2538 |
2358 JCTree currentTree; //local class or lambda | 2539 JCTree currentTree; //local class or lambda |
2359 | 2540 |
2360 @Override | 2541 @Override |
2361 void markDead() { | 2542 void markDead(JCTree tree) { |
2362 //do nothing | 2543 //do nothing |
2363 } | 2544 } |
2364 | 2545 |
2365 @SuppressWarnings("fallthrough") | 2546 @SuppressWarnings("fallthrough") |
2366 void checkEffectivelyFinal(DiagnosticPosition pos, VarSymbol sym) { | 2547 void checkEffectivelyFinal(DiagnosticPosition pos, VarSymbol sym) { |