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

com.siyeh.ig.assignment.IncrementDecrementUsedAsExpressionInspection 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 2003-2015 Dave Griffith, 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.assignment;

import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.search.LocalSearchScope;
import com.intellij.psi.search.SearchScope;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
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 org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public class IncrementDecrementUsedAsExpressionInspection
  extends BaseInspection {

  @Override
  @NotNull
  public String getID() {
    return "ValueOfIncrementOrDecrementUsed";
  }

  @Override
  @NotNull
  public String getDisplayName() {
    return InspectionGadgetsBundle.message(
      "increment.decrement.display.name");
  }

  @Override
  @NotNull
  public String buildErrorString(Object... infos) {
    final Object info = infos[0];
    if (info instanceof PsiPostfixExpression) {
      final PsiPostfixExpression postfixExpression =
        (PsiPostfixExpression)info;
      final IElementType tokenType =
        postfixExpression.getOperationTokenType();
      if (tokenType.equals(JavaTokenType.PLUSPLUS)) {
        return InspectionGadgetsBundle.message(
          "value.of.post.increment.problem.descriptor");
      }
      else {
        return InspectionGadgetsBundle.message(
          "value.of.post.decrement.problem.descriptor");
      }
    }
    else {
      final PsiPrefixExpression prefixExpression =
        (PsiPrefixExpression)info;
      final IElementType tokenType =
        prefixExpression.getOperationTokenType();
      if (tokenType.equals(JavaTokenType.PLUSPLUS)) {
        return InspectionGadgetsBundle.message(
          "value.of.pre.increment.problem.descriptor");
      }
      else {
        return InspectionGadgetsBundle.message(
          "value.of.pre.decrement.problem.descriptor");
      }
    }
  }

  @Override
  @Nullable
  protected InspectionGadgetsFix buildFix(Object... infos) {
    final PsiExpression expression = (PsiExpression)infos[0];
    if (PsiTreeUtil.getParentOfType(expression, PsiCodeBlock.class, true, PsiMember.class) == null) {
      return null;
    }
    return new IncrementDecrementUsedAsExpressionFix(expression.getText());
  }

  private static class IncrementDecrementUsedAsExpressionFix
    extends InspectionGadgetsFix {

    private final String elementText;

    IncrementDecrementUsedAsExpressionFix(String elementText) {
      this.elementText = elementText;
    }

    @Override
    @NotNull
    public String getName() {
      return InspectionGadgetsBundle.message(
        "increment.decrement.used.as.expression.quickfix",
        elementText);
    }

    @NotNull
    @Override
    public String getFamilyName() {
      return "Extract to separate statement";
    }

    @Override
    protected void doFix(Project project, ProblemDescriptor descriptor) {
      extractPrefixPostfixExpressionToSeparateStatement(descriptor.getPsiElement());
    }
  }

  public static void extractPrefixPostfixExpressionToSeparateStatement(PsiElement element) {
    final PsiExpression operand;
    if (element instanceof PsiPostfixExpression) {
      final PsiPostfixExpression postfixExpression = (PsiPostfixExpression)element;
      operand = postfixExpression.getOperand();
    }
    else if (element instanceof PsiPrefixExpression){
      final PsiPrefixExpression prefixExpression = (PsiPrefixExpression)element;
      operand = prefixExpression.getOperand();
    }
    else {
      assert false;
      return;
    }
    if (operand == null) {
      return;
    }
    final PsiStatement statement =
      PsiTreeUtil.getParentOfType(element, PsiStatement.class);
    if (statement == null) {
      return;
    }
    final PsiElement parent = statement.getParent();
    if (parent == null) {
      return;
    }
    final Project project = element.getProject();
    final PsiElementFactory factory =
      JavaPsiFacade.getInstance(project).getElementFactory();
    final String newStatementText = element.getText() + ';';
    final String operandText = operand.getText();
    if (parent instanceof PsiIfStatement ||
        parent instanceof PsiLoopStatement) {
      // need to add braces because
      // in/decrement is inside braceless control statement body
      final StringBuilder text = new StringBuilder();
      text.append('{');
      final String elementText =
        PsiReplacementUtil.getElementText(statement, element, operandText);
      if (element instanceof PsiPostfixExpression) {
        text.append(elementText);
        text.append(newStatementText);
      }
      else {
        text.append(newStatementText);
        text.append(elementText);
      }
      text.append('}');
      final PsiCodeBlock codeBlock =
        factory.createCodeBlockFromText(text.toString(), parent);
      statement.replace(codeBlock);
      return;
    }
    final PsiStatement newStatement =
      factory.createStatementFromText(newStatementText, element);
    if (statement instanceof PsiReturnStatement) {
      if (element instanceof PsiPostfixExpression) {
        // special handling of postfix expression in return statement
        final PsiReturnStatement returnStatement =
          (PsiReturnStatement)statement;
        final PsiExpression returnValue =
          returnStatement.getReturnValue();
        if (returnValue == null) {
          return;
        }
        final JavaCodeStyleManager javaCodeStyleManager =
          JavaCodeStyleManager.getInstance(project);
        final String variableName =
          javaCodeStyleManager.suggestUniqueVariableName(
            "result", returnValue, true);
        final PsiType type = returnValue.getType();
        if (type == null) {
          return;
        }
        final String newReturnValueText = PsiReplacementUtil.getElementText(
          returnValue, element, operandText);
        final String declarationStatementText =
          type.getCanonicalText() + ' ' + variableName +
          '=' + newReturnValueText + ';';
        final PsiStatement declarationStatement =
          factory.createStatementFromText(declarationStatementText,
                                          returnStatement);
        parent.addBefore(declarationStatement, statement);
        parent.addBefore(newStatement, statement);
        final PsiStatement newReturnStatement =
          factory.createStatementFromText(
            "return " + variableName + ';',
            returnStatement);
        returnStatement.replace(newReturnStatement);
        return;
      }
      else {
        parent.addBefore(newStatement, statement);
      }
    }
    else if (statement instanceof PsiThrowStatement) {
      if (element instanceof PsiPostfixExpression) {
        // special handling of postfix expression in throw statement
        final PsiThrowStatement returnStatement =
          (PsiThrowStatement)statement;
        final PsiExpression exception =
          returnStatement.getException();
        if (exception == null) {
          return;
        }
        final JavaCodeStyleManager javaCodeStyleManager =
          JavaCodeStyleManager.getInstance(project);
        final String variableName =
          javaCodeStyleManager.suggestUniqueVariableName(
            "e", exception, true);
        final PsiType type = exception.getType();
        if (type == null) {
          return;
        }
        final String newReturnValueText = PsiReplacementUtil.getElementText(
          exception, element, operandText);
        final String declarationStatementText =
          type.getCanonicalText() + ' ' + variableName +
          '=' + newReturnValueText + ';';
        final PsiStatement declarationStatement =
          factory.createStatementFromText(declarationStatementText,
                                          returnStatement);
        parent.addBefore(declarationStatement, statement);
        parent.addBefore(newStatement, statement);
        final PsiStatement newReturnStatement =
          factory.createStatementFromText(
            "throw " + variableName + ';',
            returnStatement);
        returnStatement.replace(newReturnStatement);
        return;
      }
      else {
        parent.addBefore(newStatement, statement);
      }
    }
    else if (!(statement instanceof PsiForStatement)) {
      if (element instanceof PsiPostfixExpression) {
        parent.addAfter(newStatement, statement);
      }
      else {
        parent.addBefore(newStatement, statement);
      }
    }
    else if (operand instanceof PsiReferenceExpression) {
      final PsiReferenceExpression referenceExpression =
        (PsiReferenceExpression)operand;
      final PsiElement target = referenceExpression.resolve();
      if (target != null) {
        final SearchScope useScope = target.getUseScope();
        if (!new LocalSearchScope(statement).equals(useScope)) {
          if (element instanceof PsiPostfixExpression) {
            parent.addAfter(newStatement, statement);
          }
          else {
            parent.addBefore(newStatement, statement);
          }
        }
      }
    }
    if (statement instanceof PsiLoopStatement) {
      // in/decrement inside loop statement condition
      final PsiLoopStatement loopStatement =
        (PsiLoopStatement)statement;
      final PsiStatement body = loopStatement.getBody();
      if (body instanceof PsiBlockStatement) {
        final PsiBlockStatement blockStatement =
          (PsiBlockStatement)body;
        final PsiCodeBlock codeBlock =
          blockStatement.getCodeBlock();
        if (element instanceof PsiPostfixExpression) {
          final PsiElement firstElement =
            codeBlock.getFirstBodyElement();
          codeBlock.addBefore(newStatement, firstElement);
        }
        else {
          codeBlock.add(newStatement);
        }
      }
      else {
        final StringBuilder blockText = new StringBuilder();
        blockText.append('{');
        if (element instanceof PsiPostfixExpression) {
          blockText.append(newStatementText);
          if (body != null) {
            blockText.append(body.getText());
          }
        }
        else {
          if (body != null) {
            blockText.append(body.getText());
          }
          blockText.append(newStatementText);
        }
        blockText.append('}');
        final PsiStatement blockStatement =
          factory.createStatementFromText(
            blockText.toString(), statement);
        if (body == null) {
          loopStatement.add(blockStatement);
        }
        else {
          body.replace(blockStatement);
        }
      }
    }
    PsiReplacementUtil.replaceExpression((PsiExpression)element, operandText);
  }

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

  private static class IncrementDecrementUsedAsExpressionVisitor
    extends BaseInspectionVisitor {

    @Override
    public void visitPostfixExpression(
      @NotNull PsiPostfixExpression expression) {
      super.visitPostfixExpression(expression);
      final PsiElement parent = expression.getParent();
      if (parent instanceof PsiExpressionStatement ||
          (parent instanceof PsiExpressionList &&
           parent.getParent() instanceof
             PsiExpressionListStatement)) {
        return;
      }
      final IElementType tokenType = expression.getOperationTokenType();
      if (!tokenType.equals(JavaTokenType.PLUSPLUS) &&
          !tokenType.equals(JavaTokenType.MINUSMINUS)) {
        return;
      }
      registerError(expression, expression);
    }

    @Override
    public void visitPrefixExpression(
      @NotNull PsiPrefixExpression expression) {
      super.visitPrefixExpression(expression);
      final PsiElement parent = expression.getParent();
      if (parent instanceof PsiExpressionStatement ||
          (parent instanceof PsiExpressionList &&
           parent.getParent() instanceof
             PsiExpressionListStatement)) {
        return;
      }
      final IElementType tokenType = expression.getOperationTokenType();
      if (!tokenType.equals(JavaTokenType.PLUSPLUS) &&
          !tokenType.equals(JavaTokenType.MINUSMINUS)) {
        return;
      }
      registerError(expression, expression);
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy