@Override
 public boolean visit(ForStatement node) {
   List<Expression> initializers = node.getInitializers();
   // The for-loop initializers can either be a single variable declaration
   // expression or a list of initializer expressions.
   if (initializers.size() == 1 && initializers.get(0) instanceof VariableDeclarationExpression) {
     VariableDeclarationExpression decl = (VariableDeclarationExpression) initializers.get(0);
     extractVariableDeclarationFragments(
         decl.getFragments(), TreeUtil.asStatementList(node).subList(0, 0));
   } else {
     extractExpressionList(initializers, TreeUtil.asStatementList(node).subList(0, 0), false);
   }
   Expression expr = node.getExpression();
   if (expr != null) {
     newExpression(expr);
     expr.accept(this);
     List<VariableAccess> toExtract = getUnsequencedAccesses();
     if (!toExtract.isEmpty()) {
       // Convert "if (;cond;)" into "if (;;) { if (!(cond)) break; ...}".
       List<Statement> stmtList = TreeUtil.asStatementList(node.getBody()).subList(0, 0);
       extractOrderedAccesses(stmtList, currentTopNode, toExtract);
       stmtList.add(createLoopTermination(node.getExpression()));
       node.setExpression(null);
     }
   }
   extractExpressionList(node.getUpdaters(), TreeUtil.asStatementList(node.getBody()), true);
   node.getBody().accept(this);
   return false;
 }
 private void extractVariableDeclarationFragments(
     List<VariableDeclarationFragment> fragments, List<Statement> stmtList) {
   for (int i = 0; i < fragments.size(); i++) {
     VariableDeclarationFragment frag = fragments.get(i);
     Expression init = frag.getInitializer();
     if (init == null) {
       continue;
     }
     newExpression(init);
     init.accept(this);
     List<VariableAccess> toExtract = getUnsequencedAccesses();
     if (!toExtract.isEmpty()) {
       if (i > 0) {
         // Extract all fragments before the current one to preserve ordering.
         VariableDeclarationStatement newDecl =
             new VariableDeclarationStatement(fragments.get(0).copy());
         for (int j = 1; j < i; j++) {
           newDecl.getFragments().add(fragments.get(j).copy());
         }
         stmtList.add(newDecl);
         fragments.subList(0, i).clear();
       }
       extractOrderedAccesses(stmtList, currentTopNode, toExtract);
       i = 0;
     }
   }
 }
 /**
  * Returns TRUE of FALSE if 'expr' is a boolean expression and its value is known statically. The
  * caller should be careful when replacing this expression as it may have side effects.
  */
 private Boolean getKnownValue(Expression expr) {
   Object value = expr.getConstantValue();
   if (value instanceof Boolean) {
     return (Boolean) value;
   }
   switch (expr.getKind()) {
     case BOOLEAN_LITERAL:
       return ((BooleanLiteral) expr).booleanValue();
     case INFIX_EXPRESSION:
       {
         InfixExpression infixExpr = (InfixExpression) expr;
         InfixExpression.Operator op = infixExpr.getOperator();
         if (op == CONDITIONAL_AND || op == CONDITIONAL_OR) {
           // We assume that this node has already been visited and pruned so
           // if it has a known value, it will be equal to the last operand.
           List<Expression> operands = infixExpr.getOperands();
           Boolean lastOperand = getKnownValue(operands.get(operands.size() - 1));
           if (lastOperand != null && lastOperand.booleanValue() == (op == CONDITIONAL_OR)) {
             return lastOperand;
           }
         }
         return null;
       }
     case PARENTHESIZED_EXPRESSION:
       return getKnownValue(((ParenthesizedExpression) expr).getExpression());
     default:
       return null;
   }
 }
Beispiel #4
0
 private boolean needsIdCast(Expression lhs, Expression rhs) {
   ITypeBinding lhsType = lhs.getTypeBinding();
   ITypeBinding rhsType = rhs.getTypeBinding();
   return !lhsType.isPrimitive()
       && !rhsType.isPrimitive()
       && !lhsType.isAssignmentCompatible(rhsType)
       && !rhsType.isAssignmentCompatible(lhsType);
 }
 @Override
 public boolean visit(SuperConstructorInvocation node) {
   newExpression(node);
   for (Expression arg : node.getArguments()) {
     arg.accept(this);
   }
   extractUnsequenced(node);
   return false;
 }
 @Override
 public boolean visit(Assignment node) {
   Expression lhs = node.getLeftHandSide();
   IVariableBinding lhsVar = TreeUtil.getVariableBinding(lhs);
   // Access order is important. If the lhs is a variable, then we must record
   // its access after visiting the rhs. Otherwise, visit both sides.
   if (lhsVar == null) {
     lhs.accept(this);
   }
   node.getRightHandSide().accept(this);
   addVariableAccess(lhsVar, node, true);
   return false;
 }
 @Override
 public void endVisit(SuperConstructorInvocation node) {
   Expression outerExpression = node.getExpression();
   if (outerExpression == null) {
     return;
   }
   node.setExpression(null);
   ITypeBinding outerExpressionType = outerExpression.getTypeBinding();
   GeneratedMethodBinding binding =
       new GeneratedMethodBinding(node.getMethodBinding().getMethodDeclaration());
   node.setMethodBinding(binding);
   node.getArguments().add(0, outerExpression);
   binding.addParameter(0, outerExpressionType);
 }
Beispiel #8
0
 private ITypeBinding getDeclaredType(Expression expr) {
   IVariableBinding var = TreeUtil.getVariableBinding(expr);
   if (var != null) {
     return var.getVariableDeclaration().getType();
   }
   switch (expr.getKind()) {
     case CLASS_INSTANCE_CREATION:
       return typeEnv.resolveIOSType("id");
     case FUNCTION_INVOCATION:
       {
         ITypeBinding returnType =
             ((FunctionInvocation) expr).getFunctionBinding().getReturnType();
         if (returnType.isTypeVariable()) {
           return typeEnv.resolveIOSType("id");
         }
         return returnType;
       }
     case METHOD_INVOCATION:
       {
         MethodInvocation invocation = (MethodInvocation) expr;
         IMethodBinding method = invocation.getMethodBinding();
         // Object receiving the message, or null if it's a method in this class.
         Expression receiver = invocation.getExpression();
         ITypeBinding receiverType =
             receiver != null ? receiver.getTypeBinding() : method.getDeclaringClass();
         return getDeclaredReturnType(method, receiverType);
       }
     case PARENTHESIZED_EXPRESSION:
       return getDeclaredType(((ParenthesizedExpression) expr).getExpression());
     case SUPER_METHOD_INVOCATION:
       {
         SuperMethodInvocation invocation = (SuperMethodInvocation) expr;
         IMethodBinding method = invocation.getMethodBinding();
         if (invocation.getQualifier() != null) {
           // For a qualified super invocation, the statement generator will look
           // up the IMP using instanceMethodForSelector.
           if (!method.getReturnType().isPrimitive()) {
             return typeEnv.resolveIOSType("id");
           } else {
             return null;
           }
         }
         return getDeclaredReturnType(
             method, TreeUtil.getOwningType(invocation).getTypeBinding().getSuperclass());
       }
     default:
       return null;
   }
 }
 private void visitAndExtract(Expression expr, Statement stmt) {
   if (expr != null) {
     newExpression(expr);
     expr.accept(this);
     extractUnsequenced(stmt);
   }
 }
 /**
  * Returns an expression containing the side effects of the given expression. The evaluated result
  * of the expression may differ from the original.
  */
 private Expression extractSideEffects(Expression expr) {
   switch (expr.getKind()) {
     case INFIX_EXPRESSION:
       {
         List<Expression> operands = ((InfixExpression) expr).getOperands();
         Expression lastOperand = operands.remove(operands.size() - 1);
         lastOperand = extractSideEffects(lastOperand);
         if (lastOperand != null) {
           operands.add(lastOperand);
         }
         if (operands.size() == 1) {
           return operands.remove(0);
         }
         return TreeUtil.remove(expr);
       }
     case PARENTHESIZED_EXPRESSION:
       {
         Expression sideEffects =
             extractSideEffects(((ParenthesizedExpression) expr).getExpression());
         if (sideEffects != null) {
           return ParenthesizedExpression.parenthesize(sideEffects);
         }
         return null;
       }
     default:
       return null;
   }
 }
Beispiel #11
0
  @Override
  public void endVisit(CastExpression node) {
    ITypeBinding type = node.getType().getTypeBinding();
    Expression expr = node.getExpression();
    ITypeBinding exprType = expr.getTypeBinding();

    // TODO(kirbs): Implement correct conversion of Java 8 intersection types to Objective-C.
    if (node.getType().isIntersectionType() && !Options.isJava8Translator()) {
      // Technically we can't currently get here, but as we add support and change flags in the
      // future this should alert us to implement intersection types.
      assert false : "not implemented yet";
    }

    if (BindingUtil.isFloatingPoint(exprType)) {
      assert type.isPrimitive(); // Java wouldn't allow a cast from primitive to non-primitive.
      switch (type.getBinaryName().charAt(0)) {
        case 'J':
          node.replaceWith(rewriteFloatToIntegralCast(type, expr, "JreFpToLong", type));
          return;
        case 'C':
          node.replaceWith(rewriteFloatToIntegralCast(type, expr, "JreFpToChar", type));
          return;
        case 'B':
        case 'S':
        case 'I':
          node.replaceWith(
              rewriteFloatToIntegralCast(type, expr, "JreFpToInt", typeEnv.resolveJavaType("int")));
          return;
      }
      // else fall-through.
    }

    // Lean on Java's type-checking.
    if (!type.isPrimitive() && exprType.isAssignmentCompatible(type.getErasure())) {
      node.replaceWith(TreeUtil.remove(expr));
      return;
    }

    FunctionInvocation castCheck = createCastCheck(type, expr);
    if (castCheck != null) {
      node.setExpression(castCheck);
    }
  }
 private IfStatement createLoopTermination(Expression loopCondition) {
   IfStatement newIf = new IfStatement();
   newIf.setExpression(
       new PrefixExpression(
           typeEnv.resolveJavaType("boolean"),
           PrefixExpression.Operator.NOT,
           ParenthesizedExpression.parenthesize(loopCondition.copy())));
   newIf.setThenStatement(new BreakStatement());
   return newIf;
 }
 private void extractExpressionList(
     List<Expression> expressions, List<Statement> stmtList, boolean extractModifiedExpression) {
   for (int i = 0; i < expressions.size(); i++) {
     Expression expr = expressions.get(i);
     newExpression(expr);
     expr.accept(this);
     List<VariableAccess> unsequencedAccesses = getUnsequencedAccesses();
     if (!unsequencedAccesses.isEmpty()) {
       for (int j = 0; j < i; j++) {
         stmtList.add(new ExpressionStatement(expressions.get(j).copy()));
       }
       expressions.subList(0, i).clear();
       extractOrderedAccesses(stmtList, currentTopNode, unsequencedAccesses);
       i = 0;
       if (extractModifiedExpression) {
         stmtList.add(new ExpressionStatement(expressions.get(0).copy()));
         expressions.remove(0);
         i = -1;
       }
     }
   }
 }
 @Override
 public boolean visit(AssertStatement node) {
   Expression expr = node.getExpression();
   visitAndExtract(expr, node);
   Expression msg = node.getMessage();
   if (msg != null) {
     newExpression(msg);
     msg.accept(this);
     List<VariableAccess> toExtract = getUnsequencedAccesses();
     if (!toExtract.isEmpty()) {
       // If the message expression needs any extraction, then we first extract
       // the entire boolean expression to preserve ordering between the two.
       IVariableBinding exprVar =
           new GeneratedVariableBinding(
               "unseq$" + count++, 0, expr.getTypeBinding(), false, false, null, currentMethod);
       TreeUtil.insertBefore(
           node, new VariableDeclarationStatement(exprVar, node.getExpression().copy()));
       node.setExpression(new SimpleName(exprVar));
       extractOrderedAccesses(
           TreeUtil.asStatementList(node).subList(0, 0), currentTopNode, toExtract);
     }
   }
   return false;
 }
Beispiel #15
0
  // Some native objective-c methods are declared to return NSUInteger.
  private boolean returnValueNeedsIntCast(Expression arg) {
    IMethodBinding methodBinding = TreeUtil.getMethodBinding(arg);
    assert methodBinding != null;

    if (arg.getParent() instanceof ExpressionStatement) {
      // Avoid "unused return value" warning.
      return false;
    }

    String methodName = nameTable.getMethodSelector(methodBinding);
    if (methodName.equals("hash")
        && methodBinding.getReturnType().isEqualTo(typeEnv.resolveJavaType("int"))) {
      return true;
    }
    if (typeEnv.isStringType(methodBinding.getDeclaringClass()) && methodName.equals("length")) {
      return true;
    }
    return false;
  }
Beispiel #16
0
 private boolean needsCast(Expression expr, ITypeBinding expectedType, boolean shouldCastFromId) {
   ITypeBinding declaredType = getDeclaredType(expr);
   if (declaredType == null) {
     return false;
   }
   ITypeBinding exprType = typeEnv.mapType(expr.getTypeBinding());
   declaredType = typeEnv.mapType(declaredType);
   if (
   // In general we do not need to cast primitive types.
   exprType.isPrimitive()
       // In most cases we don't need to cast from an id type. However, if the
       // expression is being dereferenced then the compiler needs the type
       // info.
       || (typeEnv.isIdType(declaredType) && !shouldCastFromId)
       // If the declared type can be assigned into the actual type, or the
       // expected type, then the compiler already has sufficient type info.
       || typeEnv.isIdType(exprType)
       || typeEnv.isIdType(expectedType)
       || declaredType.isAssignmentCompatible(exprType)
       || declaredType.isAssignmentCompatible(expectedType)) {
     return false;
   }
   return true;
 }
Beispiel #17
0
 private void addCast(Expression expr) {
   ITypeBinding exprType = typeEnv.mapType(expr.getTypeBinding());
   CastExpression castExpr = new CastExpression(exprType, null);
   expr.replaceWith(ParenthesizedExpression.parenthesize(castExpr));
   castExpr.setExpression(expr);
 }
 private void extractConditionalExpression(
     List<Statement> stmtList, ConditionalExpression conditional, List<VariableAccess> toExtract) {
   Expression condition = conditional.getExpression();
   Expression thenExpr = conditional.getThenExpression();
   Expression elseExpr = conditional.getElseExpression();
   List<VariableAccess> conditionAccesses = Lists.newArrayList();
   List<VariableAccess> thenAccesses = Lists.newArrayList();
   List<VariableAccess> elseAccesses = Lists.newArrayList();
   boolean needsExtraction = false;
   for (VariableAccess access : toExtract) {
     TreeNode node = access.expression;
     while (node.getParent() != conditional) {
       node = node.getParent();
     }
     if (node == condition) {
       conditionAccesses.add(access);
     } else if (node == thenExpr) {
       thenAccesses.add(access);
     } else if (node == elseExpr) {
       elseAccesses.add(access);
     } else {
       throw new AssertionError();
     }
     if (node != condition && access.isModification) {
       // We only need to extract an if-statement if there is a modification
       // that executes conditionally.
       needsExtraction = true;
     }
   }
   extractOrderedAccesses(stmtList, condition, conditionAccesses);
   // The recursive call might replace the condition child.
   condition = conditional.getExpression();
   if (needsExtraction) {
     IVariableBinding resultVar =
         new GeneratedVariableBinding(
             "unseq$" + count++,
             0,
             conditional.getTypeBinding(),
             false,
             false,
             null,
             currentMethod);
     conditional.replaceWith(new SimpleName(resultVar));
     stmtList.add(new VariableDeclarationStatement(resultVar, null));
     IfStatement newIf = new IfStatement();
     newIf.setExpression(condition.copy());
     stmtList.add(newIf);
     Block thenBlock = new Block();
     newIf.setThenStatement(thenBlock);
     List<Statement> thenStmts = thenBlock.getStatements();
     extractOrderedAccesses(thenStmts, thenExpr, thenAccesses);
     // The recursive call might replace the then expression child.
     thenExpr = conditional.getThenExpression();
     thenStmts.add(
         new ExpressionStatement(new Assignment(new SimpleName(resultVar), thenExpr.copy())));
     Block elseBlock = new Block();
     newIf.setElseStatement(elseBlock);
     List<Statement> elseStmts = elseBlock.getStatements();
     extractOrderedAccesses(elseStmts, elseExpr, elseAccesses);
     // The recursive call might replace the else expression child.
     elseExpr = conditional.getElseExpression();
     elseStmts.add(
         new ExpressionStatement(new Assignment(new SimpleName(resultVar), elseExpr.copy())));
   } else {
     extractOrderedAccesses(stmtList, thenExpr, thenAccesses);
     extractOrderedAccesses(stmtList, elseExpr, elseAccesses);
   }
 }