예제 #1
0
    /**
     * 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;
    }
예제 #2
0
    @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));
    }
예제 #3
0
    @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));
    }