blob: d76eaaffc86ce91be48b0da7fef4a77560266a67 [file] [log] [blame]
/*
* Copyright 2009-2014 Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.siyeh.ipp.forloop;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.tree.IElementType;
import com.intellij.util.IncorrectOperationException;
import com.siyeh.ig.psiutils.ComparisonUtils;
import com.siyeh.ig.psiutils.ExpressionUtils;
import com.siyeh.ig.psiutils.ParenthesesUtils;
import com.siyeh.ig.psiutils.VariableAccessUtils;
import com.siyeh.ipp.base.Intention;
import com.siyeh.ipp.base.PsiElementPredicate;
import org.jetbrains.annotations.NotNull;
public class ReverseForLoopDirectionIntention extends Intention {
@NotNull
@Override
protected PsiElementPredicate getElementPredicate() {
return new ReverseForLoopDirectionPredicate();
}
@Override
protected void processIntention(@NotNull PsiElement element)
throws IncorrectOperationException {
final PsiForStatement forStatement =
(PsiForStatement)element.getParent();
final PsiDeclarationStatement initialization =
(PsiDeclarationStatement)forStatement.getInitialization();
if (initialization == null) {
return;
}
final PsiBinaryExpression condition =
(PsiBinaryExpression)forStatement.getCondition();
if (condition == null) {
return;
}
final PsiLocalVariable variable =
(PsiLocalVariable)initialization.getDeclaredElements()[0];
final PsiExpression initializer = variable.getInitializer();
if (initializer == null) {
return;
}
final PsiExpression lhs = condition.getLOperand();
final PsiExpression rhs = condition.getROperand();
if (rhs == null) {
return;
}
final PsiExpressionStatement update =
(PsiExpressionStatement)forStatement.getUpdate();
if (update == null) {
return;
}
final PsiExpression updateExpression = update.getExpression();
final String variableName = variable.getName();
final StringBuilder newUpdateText = new StringBuilder();
if (updateExpression instanceof PsiPrefixExpression) {
final PsiPrefixExpression prefixExpression =
(PsiPrefixExpression)updateExpression;
final IElementType tokenType =
prefixExpression.getOperationTokenType();
if (JavaTokenType.PLUSPLUS == tokenType) {
newUpdateText.append("--");
}
else if (JavaTokenType.MINUSMINUS == tokenType) {
newUpdateText.append("++");
}
else {
return;
}
newUpdateText.append(variableName);
}
else if (updateExpression instanceof PsiPostfixExpression) {
newUpdateText.append(variableName);
final PsiPostfixExpression postfixExpression =
(PsiPostfixExpression)updateExpression;
final IElementType tokenType =
postfixExpression.getOperationTokenType();
if (JavaTokenType.PLUSPLUS == tokenType) {
newUpdateText.append("--");
}
else if (JavaTokenType.MINUSMINUS == tokenType) {
newUpdateText.append("++");
}
else {
return;
}
}
else {
return;
}
final Project project = element.getProject();
final PsiElementFactory factory =
JavaPsiFacade.getElementFactory(project);
final PsiExpression newUpdate = factory.createExpressionFromText(
newUpdateText.toString(), element);
updateExpression.replace(newUpdate);
final IElementType sign = condition.getOperationTokenType();
final String negatedSign = ComparisonUtils.getNegatedComparison(sign);
final StringBuilder conditionText = new StringBuilder();
final StringBuilder newInitializerText = new StringBuilder();
if (VariableAccessUtils.evaluatesToVariable(lhs, variable)) {
conditionText.append(variableName);
conditionText.append(negatedSign);
if (sign == JavaTokenType.GE) {
conditionText.append(incrementExpression(initializer, true));
}
else if (sign == JavaTokenType.LE) {
conditionText.append(incrementExpression(initializer, false));
}
else {
conditionText.append(initializer.getText());
}
if (sign == JavaTokenType.LT) {
newInitializerText.append(incrementExpression(rhs, false));
}
else if (sign == JavaTokenType.GT) {
newInitializerText.append(incrementExpression(rhs, true));
}
else {
newInitializerText.append(rhs.getText());
}
}
else if (VariableAccessUtils.evaluatesToVariable(rhs, variable)) {
if (sign == JavaTokenType.LE) {
conditionText.append(incrementExpression(initializer, true));
}
else if (sign == JavaTokenType.GE) {
conditionText.append(incrementExpression(initializer, false));
}
else {
conditionText.append(initializer.getText());
}
conditionText.append(negatedSign);
conditionText.append(variableName);
if (sign == JavaTokenType.GT) {
newInitializerText.append(incrementExpression(lhs, false));
}
else if (sign == JavaTokenType.LT) {
newInitializerText.append(incrementExpression(lhs, true));
}
else {
newInitializerText.append(lhs.getText());
}
}
else {
return;
}
final PsiExpression newInitializer = factory.createExpressionFromText(
newInitializerText.toString(), element);
variable.setInitializer(newInitializer);
final PsiExpression newCondition = factory.createExpressionFromText(
conditionText.toString(), element);
condition.replace(newCondition);
}
private static String incrementExpression(PsiExpression expression,
boolean positive) {
if (expression instanceof PsiLiteralExpression) {
final PsiLiteralExpression literalExpression =
(PsiLiteralExpression)expression;
final Number value = (Number)literalExpression.getValue();
if (value == null) {
return null;
}
if (positive) {
return String.valueOf(value.longValue() + 1L);
}
else {
return String.valueOf(value.longValue() - 1L);
}
}
else {
if (expression instanceof PsiBinaryExpression) {
// see if we can remove a -1 instead of adding a +1
final PsiBinaryExpression binaryExpression =
(PsiBinaryExpression)expression;
final PsiExpression rhs = binaryExpression.getROperand();
if (ExpressionUtils.isOne(rhs)) {
final IElementType tokenType =
binaryExpression.getOperationTokenType();
if (tokenType == JavaTokenType.MINUS && positive) {
return binaryExpression.getLOperand().getText();
}
else if (tokenType == JavaTokenType.PLUS && !positive) {
return binaryExpression.getLOperand().getText();
}
}
}
final String expressionText;
if (ParenthesesUtils.getPrecedence(expression) >
ParenthesesUtils.ADDITIVE_PRECEDENCE) {
expressionText = '(' + expression.getText() + ')';
}
else {
expressionText = expression.getText();
}
if (positive) {
return expressionText + "+1";
}
else {
return expressionText + "-1";
}
}
}
}