1383 } 1384 //where 1385 JCExpression loadFreevar(DiagnosticPosition pos, VarSymbol v) { 1386 return access(v, make.at(pos).Ident(v), null, false); 1387 } 1388 1389 /** Construct a tree simulating the expression <C.this>. 1390 * @param pos The source code position to be used for the tree. 1391 * @param c The qualifier class. 1392 */ 1393 JCExpression makeThis(DiagnosticPosition pos, TypeSymbol c) { 1394 if (currentClass == c) { 1395 // in this case, `this' works fine 1396 return make.at(pos).This(c.erasure(types)); 1397 } else { 1398 // need to go via this$n 1399 return makeOuterThis(pos, c); 1400 } 1401 } 1402 1403 /** Construct a tree that represents the outer instance 1404 * <C.this>. Never pick the current `this'. 1405 * @param pos The source code position to be used for the tree. 1406 * @param c The qualifier class. 1407 */ 1408 JCExpression makeOuterThis(DiagnosticPosition pos, TypeSymbol c) { 1409 List<VarSymbol> ots = outerThisStack; 1410 if (ots.isEmpty()) { 1411 log.error(pos, "no.encl.instance.of.type.in.scope", c); 1412 assert false; 1413 return makeNull(); 1414 } 1415 VarSymbol ot = ots.head; 1416 JCExpression tree = access(make.at(pos).Ident(ot)); 1417 TypeSymbol otc = ot.type.tsym; 1418 while (otc != c) { 1419 do { 1420 ots = ots.tail; 1421 if (ots.isEmpty()) { 1422 log.error(pos, 3388 if (tree.name == names._class) 3389 result = classOf(tree.selected); 3390 else if (tree.name == names._this || tree.name == names._super) 3391 result = makeThis(tree.pos(), tree.selected.type.tsym); 3392 else 3393 result = access(tree.sym, tree, enclOp, qualifiedSuperAccess); 3394 } 3395 3396 public void visitLetExpr(LetExpr tree) { 3397 tree.defs = translateVarDefs(tree.defs); 3398 tree.expr = translate(tree.expr, tree.type); 3399 result = tree; 3400 } 3401 3402 // There ought to be nothing to rewrite here; 3403 // we don't generate code. 3404 public void visitAnnotation(JCAnnotation tree) { 3405 result = tree; 3406 } 3407 3408 /************************************************************************** 3409 * main method 3410 *************************************************************************/ 3411 3412 /** Translate a toplevel class and return a list consisting of 3413 * the translated class and translated versions of all inner classes. 3414 * @param env The attribution environment current at the class definition. 3415 * We need this for resolving some additional symbols. 3416 * @param cdef The tree representing the class definition. 3417 */ 3418 public List<JCTree> translateTopLevelClass(Env<AttrContext> env, JCTree cdef, TreeMaker make) { 3419 ListBuffer<JCTree> translated = null; 3420 try { 3421 attrEnv = env; 3422 this.make = make; 3423 endPositions = env.toplevel.endPositions; 3424 currentClass = null; 3425 currentMethodDef = null; 3426 outermostClassDef = (cdef.getTag() == JCTree.CLASSDEF) ? (JCClassDecl)cdef : null; 3427 outermostMemberDef = null; | 1383 } 1384 //where 1385 JCExpression loadFreevar(DiagnosticPosition pos, VarSymbol v) { 1386 return access(v, make.at(pos).Ident(v), null, false); 1387 } 1388 1389 /** Construct a tree simulating the expression <C.this>. 1390 * @param pos The source code position to be used for the tree. 1391 * @param c The qualifier class. 1392 */ 1393 JCExpression makeThis(DiagnosticPosition pos, TypeSymbol c) { 1394 if (currentClass == c) { 1395 // in this case, `this' works fine 1396 return make.at(pos).This(c.erasure(types)); 1397 } else { 1398 // need to go via this$n 1399 return makeOuterThis(pos, c); 1400 } 1401 } 1402 1403 /** Optionally replace a try statement with an automatic resource management 1404 * (ARM) block. 1405 * @param tree The try statement to inspect. 1406 * @return An ARM block, or the original try block if there are no 1407 * resources to manage. 1408 */ 1409 JCTree makeTry(JCTry tree) { 1410 if (tree.resources.isEmpty()) { 1411 return tree; 1412 } 1413 make_at(tree.pos()); 1414 JCBlock armBlock = makeArmBlock(tree.resources, tree.body, 0); 1415 if (tree.catchers.isEmpty() && tree.finalizer == null) 1416 result = translate(armBlock); 1417 else 1418 result = translate(make.Try(armBlock, tree.catchers, tree.finalizer)); 1419 return result; 1420 } 1421 1422 private JCBlock makeArmBlock(List<JCTree> resources, JCBlock block, int depth) { 1423 if (resources.isEmpty()) 1424 return block; 1425 1426 // Add resource declaration or expression to block statements 1427 ListBuffer<JCStatement> stats = new ListBuffer<JCStatement>(); 1428 JCTree resource = resources.head; 1429 JCExpression expr = null; 1430 if (resource instanceof JCVariableDecl) { 1431 JCVariableDecl var = (JCVariableDecl) resource; 1432 var.sym.flags_field |= FINAL; 1433 expr = make.Ident(var.sym); 1434 stats.add(var); 1435 } else { 1436 assert resource instanceof JCExpression; 1437 expr = (JCExpression)resource; 1438 stats.add(make.at(resource.pos()).Exec(expr)); 1439 } 1440 1441 // Add primaryException declaration 1442 VarSymbol primaryException = 1443 new VarSymbol(0, names.fromString("#primaryException" + depth), 1444 syms.throwableType, currentMethodSym); 1445 JCVariableDecl primaryExceptionTreeDecl = make.VarDef(primaryException, makeNull()); 1446 stats.add(primaryExceptionTreeDecl); 1447 1448 // Create catch clause that saves exception and then rethrows it 1449 VarSymbol param = 1450 new VarSymbol(FINAL, names.fromString("t"), syms.throwableType, currentMethodSym); 1451 JCVariableDecl paramTree = make.VarDef(param, null); 1452 JCStatement assign = make.Assignment(primaryException, make.Ident(param)); 1453 JCStatement rethrowStat = make.Throw(make.Ident(param)); 1454 JCBlock catchBlock = make.Block(0L, List.<JCStatement>of(assign, rethrowStat)); 1455 JCCatch catchClause = make.Catch(paramTree, catchBlock); 1456 1457 int oldPos = make.pos; 1458 make.at(TreeInfo.endPos(block)); 1459 JCBlock finallyClause = makeArmFinallyClause(primaryException, expr); 1460 make.at(oldPos); 1461 JCTry outerTry = make.Try(makeArmBlock(resources.tail, block, depth + 1), 1462 List.<JCCatch>of(catchClause), 1463 finallyClause); 1464 stats.add(outerTry); 1465 return make.Block(0L, stats.toList()); 1466 } 1467 1468 private JCBlock makeArmFinallyClause(Symbol primaryException, JCExpression resource) { 1469 // primaryException.addSuppressedException(catchException); 1470 VarSymbol catchException = 1471 new VarSymbol(0, make.paramName(2), 1472 syms.throwableType, 1473 currentMethodSym); 1474 JCStatement addSuppressionStatement = 1475 make.Exec(makeCall(make.Ident(primaryException), 1476 names.fromString("addSuppressedException"), 1477 List.<JCExpression>of(make.Ident(catchException)))); 1478 1479 // try { resource.close(); } catch (e) { primaryException.addSuppressedException(e); } 1480 JCBlock tryBlock = make.Block(0L, List.<JCStatement>of(makeResourceCloseInvocation(resource))); 1481 JCVariableDecl catchExceptionDecl = make.VarDef(catchException, null); 1482 JCBlock catchBlock = make.Block(0L, List.<JCStatement>of(addSuppressionStatement)); 1483 List<JCCatch> catchClauses = List.<JCCatch>of(make.Catch(catchExceptionDecl, catchBlock)); 1484 JCTry tryTree = make.Try(tryBlock, catchClauses, null); 1485 1486 // if (resource != null) resourceClose; 1487 JCExpression nullCheck = makeBinary(JCTree.NE, make.Ident(primaryException), makeNull()); 1488 JCIf closeIfStatement = make.If(nullCheck, tryTree, makeResourceCloseInvocation(resource)); 1489 return make.Block(0L, List.<JCStatement>of(closeIfStatement)); 1490 } 1491 1492 private JCStatement makeResourceCloseInvocation(JCExpression resource) { 1493 // create resource.close() method invocation 1494 Type autoCloseableType = types.asSuper(resource.type, syms.autoCloseableType.tsym); 1495 Symbol closeMethod = autoCloseableType.tsym.members().lookup(names.close).sym; 1496 JCExpression closeInvocation = make.Select(resource, closeMethod); 1497 JCMethodInvocation resourceClose = make.Apply(List.<JCExpression>nil(), 1498 closeInvocation, 1499 List.<JCExpression>nil()); 1500 resourceClose.type = closeMethod.type.getReturnType(); 1501 return make.Exec(resourceClose); 1502 } 1503 1504 /** Construct a tree that represents the outer instance 1505 * <C.this>. Never pick the current `this'. 1506 * @param pos The source code position to be used for the tree. 1507 * @param c The qualifier class. 1508 */ 1509 JCExpression makeOuterThis(DiagnosticPosition pos, TypeSymbol c) { 1510 List<VarSymbol> ots = outerThisStack; 1511 if (ots.isEmpty()) { 1512 log.error(pos, "no.encl.instance.of.type.in.scope", c); 1513 assert false; 1514 return makeNull(); 1515 } 1516 VarSymbol ot = ots.head; 1517 JCExpression tree = access(make.at(pos).Ident(ot)); 1518 TypeSymbol otc = ot.type.tsym; 1519 while (otc != c) { 1520 do { 1521 ots = ots.tail; 1522 if (ots.isEmpty()) { 1523 log.error(pos, 3489 if (tree.name == names._class) 3490 result = classOf(tree.selected); 3491 else if (tree.name == names._this || tree.name == names._super) 3492 result = makeThis(tree.pos(), tree.selected.type.tsym); 3493 else 3494 result = access(tree.sym, tree, enclOp, qualifiedSuperAccess); 3495 } 3496 3497 public void visitLetExpr(LetExpr tree) { 3498 tree.defs = translateVarDefs(tree.defs); 3499 tree.expr = translate(tree.expr, tree.type); 3500 result = tree; 3501 } 3502 3503 // There ought to be nothing to rewrite here; 3504 // we don't generate code. 3505 public void visitAnnotation(JCAnnotation tree) { 3506 result = tree; 3507 } 3508 3509 @Override 3510 public void visitTry(JCTry tree) { 3511 super.visitTry(tree); 3512 result = makeTry(tree); 3513 } 3514 3515 /************************************************************************** 3516 * main method 3517 *************************************************************************/ 3518 3519 /** Translate a toplevel class and return a list consisting of 3520 * the translated class and translated versions of all inner classes. 3521 * @param env The attribution environment current at the class definition. 3522 * We need this for resolving some additional symbols. 3523 * @param cdef The tree representing the class definition. 3524 */ 3525 public List<JCTree> translateTopLevelClass(Env<AttrContext> env, JCTree cdef, TreeMaker make) { 3526 ListBuffer<JCTree> translated = null; 3527 try { 3528 attrEnv = env; 3529 this.make = make; 3530 endPositions = env.toplevel.endPositions; 3531 currentClass = null; 3532 currentMethodDef = null; 3533 outermostClassDef = (cdef.getTag() == JCTree.CLASSDEF) ? (JCClassDecl)cdef : null; 3534 outermostMemberDef = null; |