All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.siyeh.ig.controlflow.IfMayBeConditionalInspection Maven / Gradle / Ivy

Go to download

A packaging of the IntelliJ Community Edition java-analysis-impl library. This is release number 1 of trunk branch 142.

The newest version!
/*
 * Copyright 2008-2012 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.ig.controlflow;

import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.util.IncorrectOperationException;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
import com.siyeh.ig.InspectionGadgetsFix;
import com.siyeh.ig.PsiReplacementUtil;
import com.siyeh.ig.psiutils.ControlFlowUtils;
import com.siyeh.ig.psiutils.EquivalenceChecker;
import com.siyeh.ig.psiutils.ParenthesesUtils;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;

public class IfMayBeConditionalInspection extends BaseInspection {

  @SuppressWarnings("PublicField")
  public boolean reportMethodCalls = false;

  @Override
  @Nls
  @NotNull
  public String getDisplayName() {
    return InspectionGadgetsBundle.message(
      "if.may.be.conditional.display.name");
  }

  @Override
  @NotNull
  protected String buildErrorString(Object... infos) {
    return InspectionGadgetsBundle.message(
      "if.may.be.conditional.problem.descriptor");
  }

  @Override
  public JComponent createOptionsPanel() {
    return new SingleCheckboxOptionsPanel(InspectionGadgetsBundle.message("if.may.be.conditional.report.method.calls.option"),
                                          this, "reportMethodCalls");
  }

  @Override
  protected InspectionGadgetsFix buildFix(Object... infos) {
    return new IfMayBeConditionalFix();
  }

  private static class IfMayBeConditionalFix extends InspectionGadgetsFix {

    @Override
    @NotNull
    public String getName() {
      return InspectionGadgetsBundle.message(
        "if.may.be.conditional.quickfix");
    }

    @NotNull
    @Override
    public String getFamilyName() {
      return getName();
    }

    @Override
    protected void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException {
      final PsiElement element = descriptor.getPsiElement();
      final PsiIfStatement ifStatement = (PsiIfStatement)element.getParent();
      final PsiStatement thenBranch = ifStatement.getThenBranch();
      final PsiStatement thenStatement = ControlFlowUtils.stripBraces(thenBranch);
      final PsiStatement elseBranch = ifStatement.getElseBranch();
      final PsiStatement elseStatement = ControlFlowUtils.stripBraces(elseBranch);
      final PsiExpression condition = ifStatement.getCondition();
      @NonNls final StringBuilder replacementText = new StringBuilder();
      if (thenStatement instanceof PsiReturnStatement) {
        final PsiReturnStatement elseReturn = (PsiReturnStatement)elseStatement;
        final PsiReturnStatement thenReturn = (PsiReturnStatement)thenStatement;
        replacementText.append("return ");
        appendExpressionText(condition, replacementText);
        replacementText.append('?');
        final PsiExpression thenReturnValue = thenReturn.getReturnValue();
        appendExpressionText(thenReturnValue, replacementText);
        replacementText.append(':');
        if (elseReturn != null) {
          final PsiExpression elseReturnValue = elseReturn.getReturnValue();
          appendExpressionText(elseReturnValue, replacementText);
        }
        replacementText.append(';');
      }
      else if (thenStatement instanceof PsiExpressionStatement && elseStatement instanceof PsiExpressionStatement) {
        final PsiExpressionStatement thenExpressionStatement = (PsiExpressionStatement)thenStatement;
        final PsiExpressionStatement elseExpressionStatement = (PsiExpressionStatement)elseStatement;
        final PsiExpression thenExpression = thenExpressionStatement.getExpression();
        final PsiExpression elseExpression = elseExpressionStatement.getExpression();
        if (thenExpression instanceof PsiAssignmentExpression && elseExpression instanceof PsiAssignmentExpression) {
          final PsiAssignmentExpression thenAssignmentExpression = (PsiAssignmentExpression)thenExpression;
          final PsiExpression lhs = thenAssignmentExpression.getLExpression();
          replacementText.append(lhs.getText());
          final PsiJavaToken token = thenAssignmentExpression.getOperationSign();
          replacementText.append(token.getText());
          appendExpressionText(condition, replacementText);
          replacementText.append('?');
          final PsiExpression thenRhs = thenAssignmentExpression.getRExpression();
          appendExpressionText(thenRhs, replacementText);
          replacementText.append(':');
          final PsiAssignmentExpression elseAssignmentExpression = (PsiAssignmentExpression)elseExpression;
          final PsiExpression elseRhs = elseAssignmentExpression.getRExpression();
          appendExpressionText(elseRhs, replacementText);
          replacementText.append(';');
        }
        else if (thenExpression instanceof PsiMethodCallExpression && elseExpression instanceof PsiMethodCallExpression) {
          final PsiMethodCallExpression thenMethodCallExpression = (PsiMethodCallExpression)thenExpression;
          final PsiMethodCallExpression elseMethodCallExpression = (PsiMethodCallExpression)elseExpression;
          final PsiReferenceExpression thenMethodExpression = thenMethodCallExpression.getMethodExpression();
          replacementText.append(thenMethodExpression.getText());
          replacementText.append('(');
          final PsiExpressionList thenArgumentList = thenMethodCallExpression.getArgumentList();
          final PsiExpression[] thenArguments = thenArgumentList.getExpressions();
          final PsiExpressionList elseArgumentList = elseMethodCallExpression.getArgumentList();
          final PsiExpression[] elseArguments = elseArgumentList.getExpressions();
          for (int i = 0, length = thenArguments.length; i < length; i++) {
            if (i > 0) {
              replacementText.append(',');
            }
            final PsiExpression thenArgument = thenArguments[i];
            final PsiExpression elseArgument = elseArguments[i];
            if (EquivalenceChecker.expressionsAreEquivalent(thenArgument, elseArgument)) {
              replacementText.append(thenArgument.getText());
            }
            else {
              appendExpressionText(condition, replacementText);
              replacementText.append('?');
              appendExpressionText(thenArgument, replacementText);
              replacementText.append(':');
              appendExpressionText(elseArgument, replacementText);
            }
          }
          replacementText.append(");");
        }
        else {
          return;
        }
      }
      PsiReplacementUtil.replaceStatement(ifStatement, replacementText.toString());
    }

    private static void appendExpressionText(@Nullable PsiExpression expression, StringBuilder out) {
      expression = ParenthesesUtils.stripParentheses(expression);
      if (expression == null) {
        return;
      }
      final String expressionText = expression.getText();
      if (ParenthesesUtils.getPrecedence(expression) > ParenthesesUtils.CONDITIONAL_PRECEDENCE) {
        out.append('(');
        out.append(expressionText);
        out.append(')');
      }
      else {
        out.append(expressionText);
      }
    }
  }

  @Override
  public BaseInspectionVisitor buildVisitor() {
    return new IfMayBeConditionalVisitor();
  }

  private class IfMayBeConditionalVisitor extends BaseInspectionVisitor {

    @Override
    public void visitIfStatement(PsiIfStatement statement) {
      super.visitIfStatement(statement);
      final PsiStatement thenBranch = statement.getThenBranch();
      final PsiStatement elseBranch = statement.getElseBranch();
      final PsiStatement thenStatement = ControlFlowUtils.stripBraces(thenBranch);
      if (thenStatement == null) {
        return;
      }
      final PsiStatement elseStatement = ControlFlowUtils.stripBraces(elseBranch);
      if (elseStatement == null) {
        return;
      }
      if (thenStatement instanceof PsiReturnStatement) {
        if (!(elseStatement instanceof PsiReturnStatement)) {
          return;
        }
        final PsiReturnStatement thenReturnStatement = (PsiReturnStatement)thenStatement;
        final PsiExpression thenReturnValue = ParenthesesUtils.stripParentheses(thenReturnStatement.getReturnValue());
        if (thenReturnValue instanceof PsiConditionalExpression) {
          return;
        }
        final PsiReturnStatement elseReturnStatement = (PsiReturnStatement)elseStatement;
        final PsiExpression elseReturnValue = ParenthesesUtils.stripParentheses(elseReturnStatement.getReturnValue());
        if (elseReturnValue instanceof PsiConditionalExpression) {
          return;
        }
        registerStatementError(statement);
      }
      else if (thenStatement instanceof PsiExpressionStatement) {
        if (!(elseStatement instanceof PsiExpressionStatement)) {
          return;
        }
        final PsiExpressionStatement thenExpressionStatement = (PsiExpressionStatement)thenStatement;
        final PsiExpression thenExpression = thenExpressionStatement.getExpression();
        final PsiExpressionStatement elseExpressionStatement = (PsiExpressionStatement)elseStatement;
        final PsiExpression elseExpression = elseExpressionStatement.getExpression();
        if (thenExpression instanceof PsiAssignmentExpression) {
          if (!(elseExpression instanceof PsiAssignmentExpression)) {
            return;
          }
          final PsiAssignmentExpression thenAssignmentExpression = (PsiAssignmentExpression)thenExpression;
          final PsiAssignmentExpression elseAssignmentExpression = (PsiAssignmentExpression)elseExpression;
          if (!thenAssignmentExpression.getOperationTokenType().equals(elseAssignmentExpression.getOperationTokenType())) {
            return;
          }
          final PsiExpression thenLhs = thenAssignmentExpression.getLExpression();
          final PsiExpression elseLhs = elseAssignmentExpression.getLExpression();
          if (!EquivalenceChecker.expressionsAreEquivalent(thenLhs, elseLhs)) {
            return;
          }
          final PsiExpression thenRhs = ParenthesesUtils.stripParentheses(thenAssignmentExpression.getRExpression());
          if (thenRhs instanceof PsiConditionalExpression) {
            return;
          }
          final PsiExpression elseRhs = ParenthesesUtils.stripParentheses(elseAssignmentExpression.getRExpression());
          if (elseRhs instanceof PsiConditionalExpression) {
            return;
          }
          registerStatementError(statement);
        }
        else if (reportMethodCalls && thenExpression instanceof PsiMethodCallExpression) {
          if (!(elseExpression instanceof PsiMethodCallExpression)) {
            return;
          }
          final PsiMethodCallExpression thenMethodCallExpression = (PsiMethodCallExpression)thenExpression;
          final PsiMethodCallExpression elseMethodCallExpression = (PsiMethodCallExpression)elseExpression;
          final PsiReferenceExpression thenMethodExpression = thenMethodCallExpression.getMethodExpression();
          final PsiReferenceExpression elseMethodExpression = elseMethodCallExpression.getMethodExpression();
          if (!EquivalenceChecker.expressionsAreEquivalent(thenMethodExpression, elseMethodExpression)) {
            return;
          }
          final PsiExpressionList thenArgumentList = thenMethodCallExpression.getArgumentList();
          final PsiExpression[] thenArguments = thenArgumentList.getExpressions();
          final PsiExpressionList elseArgumentList = elseMethodCallExpression.getArgumentList();
          final PsiExpression[] elseArguments = elseArgumentList.getExpressions();
          if (thenArguments.length != elseArguments.length) {
            return;
          }
          int differences = 0;
          for (int i = 0, length = thenArguments.length; i < length; i++) {
            final PsiExpression thenArgument = thenArguments[i];
            final PsiExpression elseArgument = elseArguments[i];
            if (!EquivalenceChecker.expressionsAreEquivalent(thenArgument,  elseArgument)) {
              differences++;
            }
          }
          if (differences == 1) {
            registerStatementError(statement);
          }
        }
      }
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy