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

org.sonar.java.checks.AbstractForLoopRule Maven / Gradle / Ivy

There is a newer version: 8.6.0.37351
Show newest version
/*
 * SonarQube Java
 * Copyright (C) 2012-2016 SonarSource SA
 * mailto:contact AT sonarsource DOT com
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package org.sonar.java.checks;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import org.sonar.plugins.java.api.IssuableSubscriptionVisitor;
import org.sonar.plugins.java.api.tree.AssignmentExpressionTree;
import org.sonar.plugins.java.api.tree.BinaryExpressionTree;
import org.sonar.plugins.java.api.tree.ExpressionStatementTree;
import org.sonar.plugins.java.api.tree.ExpressionTree;
import org.sonar.plugins.java.api.tree.ForStatementTree;
import org.sonar.plugins.java.api.tree.IdentifierTree;
import org.sonar.plugins.java.api.tree.StatementTree;
import org.sonar.plugins.java.api.tree.Tree;
import org.sonar.plugins.java.api.tree.Tree.Kind;
import org.sonar.plugins.java.api.tree.UnaryExpressionTree;
import org.sonar.plugins.java.api.tree.VariableTree;

import javax.annotation.CheckForNull;
import javax.annotation.Nullable;

import java.util.List;

import static org.sonar.java.model.LiteralUtils.intLiteralValue;

public abstract class AbstractForLoopRule extends IssuableSubscriptionVisitor {

  @Override
  public List nodesToVisit() {
    return ImmutableList.of(Tree.Kind.FOR_STATEMENT);
  }

  @Override
  public void visitNode(Tree tree) {
    ForStatementTree forStatement = (ForStatementTree) tree;
    visitForStatement(forStatement);
  }

  public abstract void visitForStatement(ForStatementTree forStatement);

  protected static boolean isSameIdentifier(IdentifierTree identifier, ExpressionTree expression) {
    if (expression.is(Tree.Kind.IDENTIFIER)) {
      IdentifierTree other = (IdentifierTree) expression;
      return other.name().equals(identifier.name());
    }
    return false;
  }

  protected static class IntVariable {

    private final IdentifierTree identifier;

    public IntVariable(IdentifierTree identifier) {
      this.identifier = identifier;
    }

    public boolean hasSameIdentifier(ExpressionTree expression) {
      return isSameIdentifier(identifier, expression);
    }

    public IdentifierTree identifier() {
      return identifier;
    }
  }

  protected static class ForLoopInitializer extends IntVariable {

    private final Integer value;

    public ForLoopInitializer(IdentifierTree identifier, @Nullable Integer value) {
      super(identifier);
      this.value = value;
    }

    @CheckForNull
    public Integer value() {
      return value;
    }

    public static Iterable list(ForStatementTree forStatement) {
      List list = Lists.newArrayList();
      for (StatementTree statement : forStatement.initializer()) {
        if (statement.is(Tree.Kind.VARIABLE)) {
          VariableTree variable = (VariableTree) statement;
          ExpressionTree initializer = variable.initializer();
          Integer value = initializer == null ? null : intLiteralValue(initializer);
          list.add(new ForLoopInitializer(variable.simpleName(), value));
        }
        if (statement.is(Tree.Kind.EXPRESSION_STATEMENT)) {
          ExpressionTree expression = ((ExpressionStatementTree) statement).expression();
          ForLoopInitializer initializer = assignmentInitializer(expression);
          if (initializer != null) {
            list.add(initializer);
          }
        }
      }
      return list;
    }

    private static ForLoopInitializer assignmentInitializer(ExpressionTree expression) {
      if (expression.is(Tree.Kind.ASSIGNMENT)) {
        AssignmentExpressionTree assignment = (AssignmentExpressionTree) expression;
        ExpressionTree variable = assignment.variable();
        if (variable.is(Tree.Kind.IDENTIFIER)) {
          return new ForLoopInitializer((IdentifierTree) variable, intLiteralValue(assignment.expression()));
        }
      }
      return null;
    }

  }

  protected static class ForLoopIncrement extends IntVariable {

    private final Integer value;

    public ForLoopIncrement(IdentifierTree identifier, @Nullable Integer value) {
      super(identifier);
      this.value = value;
    }

    public boolean hasValue() {
      return value != null;
    }

    public int value() {
      Preconditions.checkState(value != null, "This ForLoopIncrement has no value");
      return value;
    }

    @CheckForNull
    public static ForLoopIncrement findInUpdates(ForStatementTree forStatement) {
      ForLoopIncrement result = null;
      List updates = forStatement.update();
      if (updates.size() == 1) {
        ExpressionStatementTree statement = (ExpressionStatementTree) updates.get(0);
        ExpressionTree expression = statement.expression();
        if (expression.is(Tree.Kind.POSTFIX_INCREMENT, Tree.Kind.PREFIX_INCREMENT)) {
          UnaryExpressionTree unaryExp = (UnaryExpressionTree) expression;
          result = increment(unaryExp.expression(), 1);
        } else if (expression.is(Tree.Kind.POSTFIX_DECREMENT, Tree.Kind.PREFIX_DECREMENT)) {
          UnaryExpressionTree unaryExp = (UnaryExpressionTree) expression;
          result = increment(unaryExp.expression(), -1);
        } else if (expression.is(Tree.Kind.PLUS_ASSIGNMENT)) {
          AssignmentExpressionTree assignmentExp = (AssignmentExpressionTree) expression;
          result = increment(assignmentExp.variable(), intLiteralValue(assignmentExp.expression()));
        } else if (expression.is(Tree.Kind.MINUS_ASSIGNMENT)) {
          AssignmentExpressionTree assignmentExp = (AssignmentExpressionTree) expression;
          result = increment(assignmentExp.variable(), minus(intLiteralValue(assignmentExp.expression())));
        } else if (expression.is(Tree.Kind.ASSIGNMENT)) {
          AssignmentExpressionTree assignment = (AssignmentExpressionTree) expression;
          result = assignmentIncrement(assignment);
        }
      }
      return result;
    }

    @CheckForNull
    private static ForLoopIncrement increment(ExpressionTree expression, Integer value) {
      if (expression.is(Tree.Kind.IDENTIFIER)) {
        return new ForLoopIncrement((IdentifierTree) expression, value);
      }
      return null;
    }

    @CheckForNull
    private static Integer minus(@Nullable Integer nullableInteger) {
      return nullableInteger == null ? null : -nullableInteger;
    }

    private static ForLoopIncrement assignmentIncrement(AssignmentExpressionTree assignmentExpression) {
      ExpressionTree expression = assignmentExpression.expression();
      ExpressionTree variable = assignmentExpression.variable();
      if (variable.is(Tree.Kind.IDENTIFIER) && expression.is(Tree.Kind.PLUS, Tree.Kind.MINUS)) {
        BinaryExpressionTree binaryExp = (BinaryExpressionTree) expression;
        Integer increment = intLiteralValue(binaryExp.rightOperand());
        if (increment != null && isSameIdentifier((IdentifierTree) variable, binaryExp.leftOperand())) {
          increment = expression.is(Tree.Kind.MINUS) ? minus(increment) : increment;
          return increment(variable, increment);
        }
        return new ForLoopIncrement((IdentifierTree) variable, null);
      }
      return null;
    }

  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy