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

com.siyeh.ig.performance.TrivialStringConcatenationInspection 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-2013 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.performance;

import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiUtil;
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.ExpressionUtils;
import com.siyeh.ig.psiutils.ParenthesesUtils;
import com.siyeh.ig.psiutils.TypeUtils;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;

public class TrivialStringConcatenationInspection extends BaseInspection {

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

  @Override
  @NotNull
  public String getDisplayName() {
    return InspectionGadgetsBundle.message("trivial.string.concatenation.display.name");
  }

  @Override
  @NotNull
  public String buildErrorString(Object... infos) {
    return InspectionGadgetsBundle.message("trivial.string.concatenation.problem.descriptor");
  }

  @NonNls
  static String calculateReplacementExpression(PsiLiteralExpression expression) {
    final PsiElement parent = ParenthesesUtils.getParentSkipParentheses(expression);
    if (!(parent instanceof PsiPolyadicExpression)) {
      return null;
    }
    if (parent instanceof PsiBinaryExpression) {
      final PsiBinaryExpression binaryExpression = (PsiBinaryExpression)parent;
      final PsiExpression lOperand = ParenthesesUtils.stripParentheses(binaryExpression.getLOperand());
      final PsiExpression rOperand = ParenthesesUtils.stripParentheses(binaryExpression.getROperand());
      final PsiExpression replacement;
      if (ExpressionUtils.isEmptyStringLiteral(lOperand)) {
        replacement = rOperand;
      }
      else {
        replacement = lOperand;
      }
      return replacement == null ? "" : buildReplacement(replacement, false);
    }
    final PsiPolyadicExpression polyadicExpression = (PsiPolyadicExpression)parent;
    final PsiExpression[] operands = polyadicExpression.getOperands();
    final PsiClassType stringType = TypeUtils.getStringType(expression);
    boolean seenString = false;
    boolean seenEmpty = false;
    boolean replaced = false;
    PsiExpression operandToReplace = null;
    final StringBuilder text = new StringBuilder();
    for (PsiExpression operand : operands) {
      if (operandToReplace != null && !replaced) {
        if (ExpressionUtils.hasStringType(operand)) {
          seenString = true;
        }
        if (text.length() > 0) {
          text.append(" + ");
        }
        text.append(buildReplacement(operandToReplace, seenString));
        text.append(" + ");
        text.append(operand.getText());
        replaced = true;
        continue;
      }
      if (ParenthesesUtils.stripParentheses(operand) == expression) {
        seenEmpty = true;
        continue;
      }
      if (seenEmpty && !replaced) {
        operandToReplace = operand;
        continue;
      }
      if (stringType.equals(operand.getType())) {
        seenString = true;
      }
      if (text.length() > 0) {
        text.append(" + ");
      }
      text.append(operand.getText());
    }
    if (!replaced && operandToReplace != null) {
      text.append(" + ");
      text.append(buildReplacement(operandToReplace, seenString));
    }
    return text.toString();
  }

  @NonNls
  static String buildReplacement(@NotNull PsiExpression operandToReplace, boolean seenString) {
    if (ExpressionUtils.isNullLiteral(operandToReplace)) {
      if (seenString) {
        return "null";
      }
      else {
        return "String.valueOf((Object)null)";
      }
    }
    if (seenString || ExpressionUtils.hasStringType(operandToReplace)) {
      return operandToReplace.getText();
    }
    return "String.valueOf(" + operandToReplace.getText() + ')';
  }

  @Override
  public InspectionGadgetsFix buildFix(Object... infos) {
    return new UnnecessaryTemporaryObjectFix((PsiLiteralExpression)infos[0]);
  }

  private static class UnnecessaryTemporaryObjectFix extends InspectionGadgetsFix {

    private final String m_name;

    private UnnecessaryTemporaryObjectFix(PsiLiteralExpression expression) {
      m_name = InspectionGadgetsBundle.message("string.replace.quickfix", calculateReplacementExpression(expression));
    }

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

    @NotNull
    @Override
    public String getFamilyName() {
      return "Replace concatenation";
    }

    @Override
    public void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException {
      final PsiLiteralExpression expression = (PsiLiteralExpression)descriptor.getPsiElement();
      final PsiElement parent = ParenthesesUtils.getParentSkipParentheses(expression);
      if (!(parent instanceof PsiExpression)) {
        return;
      }
      final String newExpression = calculateReplacementExpression(expression);
      PsiReplacementUtil.replaceExpression((PsiExpression)parent, newExpression);
    }
  }

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

  private static class TrivialStringConcatenationVisitor extends BaseInspectionVisitor {

    @Override
    public void visitPolyadicExpression(PsiPolyadicExpression expression) {
      super.visitPolyadicExpression(expression);
      if (!ExpressionUtils.hasStringType(expression)) {
        return;
      }
      final PsiExpression[] operands = expression.getOperands();
      for (PsiExpression operand : operands) {
        operand = ParenthesesUtils.stripParentheses(operand);
        if (operand == null) {
          return;
        }
        if (!ExpressionUtils.isEmptyStringLiteral(operand)) {
          continue;
        }
        if (PsiUtil.isConstantExpression(expression)) {
          return;
        }
        registerError(operand, operand);
      }
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy