/** * Creates a JMultiExpression from a set of JExpressionStatements, optionally terminated by a * JReturnStatement. If the method doesn't match this pattern, it returns <code>null</code>. * * <p>If a method has a non-void return statement and can be represented as a multi-expression, * the output of the multi-expression will be the return expression of the method. If the method * is void, the output of the multi-expression should be considered undefined. */ private List<JExpression> extractExpressionsFromBody(JMethodBody body) { List<JExpression> expressions = Lists.newArrayList(); CloneCalleeExpressionVisitor cloner = new CloneCalleeExpressionVisitor(); for (JStatement stmt : body.getStatements()) { if (stmt instanceof JDeclarationStatement) { JDeclarationStatement declStatement = (JDeclarationStatement) stmt; if (!(declStatement.getVariableRef() instanceof JLocalRef)) { return null; } JExpression initializer = declStatement.getInitializer(); if (initializer == null) { continue; } JLocal local = (JLocal) declStatement.getVariableRef().getTarget(); JExpression clone = new JBinaryOperation( stmt.getSourceInfo(), local.getType(), JBinaryOperator.ASG, new JLocalRef(declStatement.getVariableRef().getSourceInfo(), local), cloner.cloneExpression(initializer)); expressions.add(clone); } else if (stmt instanceof JExpressionStatement) { JExpressionStatement exprStmt = (JExpressionStatement) stmt; JExpression expr = exprStmt.getExpr(); JExpression clone = cloner.cloneExpression(expr); expressions.add(clone); } else if (stmt instanceof JReturnStatement) { JReturnStatement returnStatement = (JReturnStatement) stmt; JExpression expr = returnStatement.getExpr(); if (expr != null) { JExpression clone = cloner.cloneExpression(expr); clone = maybeCast(clone, body.getMethod().getType()); expressions.add(clone); } // We hit an unconditional return; no need to evaluate anything else. break; } else { // Any other kind of statement won't be inlinable. return null; } } return expressions; }
@Override public void endVisit(JLocalRef x, Context ctx) { JLocal originalLocal = x.getLocal(); JLocal newLocal = newLocalsByOriginalLocal.get(originalLocal); if (newLocal == null) { newLocal = JProgram.createLocal( originalLocal.getSourceInfo(), originalLocal.getName(), originalLocal.getType(), originalLocal.isFinal(), methodBody); newLocalsByOriginalLocal.put(originalLocal, newLocal); } ctx.replaceMe(new JLocalRef(x.getSourceInfo(), newLocal)); }
@Override public void endVisit(JTryStatement x, Context ctx) { if (x.getCatchClauses().isEmpty()) { return; } SourceInfo catchInfo = x.getCatchClauses().get(0).getBlock().getSourceInfo(); JLocal exceptionVariable = newExceptionVariable(x.getSourceInfo()); JBlock newCatchBlock = new JBlock(catchInfo); { // $e = Exceptions.wrap($e) JMethodCall call = new JMethodCall(catchInfo, null, wrapMethod); call.addArg(new JLocalRef(catchInfo, exceptionVariable)); newCatchBlock.addStmt( JProgram.createAssignmentStmt( catchInfo, new JLocalRef(catchInfo, exceptionVariable), call)); } /* * Build up a series of if, else if statements to test the type of the * exception object against the types of the user's catch block. Each catch block might have * multiple types in Java 7. * * Go backwards so we can nest the else statements in the correct order! */ // rethrow the current exception if no one caught it. JStatement cur = new JThrowStatement(catchInfo, new JLocalRef(catchInfo, exceptionVariable)); for (int i = x.getCatchClauses().size() - 1; i >= 0; i--) { JTryStatement.CatchClause clause = x.getCatchClauses().get(i); JBlock block = clause.getBlock(); JLocalRef arg = clause.getArg(); List<JType> exceptionsTypes = clause.getTypes(); catchInfo = block.getSourceInfo(); // if ($e instanceof ArgType1 or $e instanceof ArgType2 ...) { // var userVar = $e; <user code> // } // Handle the first Exception type. JExpression ifTest = new JInstanceOf( catchInfo, (JReferenceType) exceptionsTypes.get(0), new JLocalRef(catchInfo, exceptionVariable)); // Handle the rest of the Exception types if any. for (int j = 1; j < exceptionsTypes.size(); j++) { JExpression orExp = new JInstanceOf( catchInfo, (JReferenceType) exceptionsTypes.get(j), new JLocalRef(catchInfo, exceptionVariable)); ifTest = new JBinaryOperation( catchInfo, JPrimitiveType.BOOLEAN, JBinaryOperator.OR, ifTest, orExp); } JDeclarationStatement declaration = new JDeclarationStatement(catchInfo, arg, new JLocalRef(catchInfo, exceptionVariable)); block.addStmt(0, declaration); // nest the previous as an else for me cur = new JIfStatement(catchInfo, ifTest, block, cur); } newCatchBlock.addStmt(cur); // Replace with a single catch block. x.getCatchClauses().clear(); List<JType> newCatchTypes = new ArrayList<JType>(1); newCatchTypes.add(exceptionVariable.getType()); x.getCatchClauses() .add( new JTryStatement.CatchClause( newCatchTypes, new JLocalRef(newCatchBlock.getSourceInfo(), exceptionVariable), newCatchBlock)); }