/** * 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; } }
/** * 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; } }
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; } }