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

org.checkerframework.dataflow.expression.BinaryOperation Maven / Gradle / Ivy

Go to download

The Checker Framework enhances Java's type system to make it more powerful and useful. This lets software developers detect and prevent errors in their Java programs. The Checker Framework includes compiler plug-ins ("checkers") that find bugs or verify their absence. It also permits you to write your own compiler plug-ins.

There is a newer version: 3.44.0
Show newest version
package org.checkerframework.dataflow.expression;

import com.sun.source.tree.Tree;
import java.util.Objects;
import javax.lang.model.type.TypeMirror;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.dataflow.analysis.Store;
import org.checkerframework.dataflow.cfg.node.BinaryOperationNode;
import org.checkerframework.javacutil.AnnotationProvider;
import org.checkerframework.javacutil.BugInCF;

/** JavaExpression for binary operations. */
public class BinaryOperation extends JavaExpression {

  /** The binary operation kind. */
  protected final Tree.Kind operationKind;
  /** The left operand. */
  protected final JavaExpression left;
  /** The right operand. */
  protected final JavaExpression right;

  /**
   * Create a binary operation.
   *
   * @param type the result type
   * @param operationKind the operator
   * @param left the left operand
   * @param right the right operand
   */
  public BinaryOperation(
      TypeMirror type, Tree.Kind operationKind, JavaExpression left, JavaExpression right) {
    super(type);
    this.operationKind = operationKind;
    this.left = left;
    this.right = right;
  }

  /**
   * Create a binary operation.
   *
   * @param node the binary operation node
   * @param left the left operand
   * @param right the right operand
   */
  public BinaryOperation(BinaryOperationNode node, JavaExpression left, JavaExpression right) {
    this(node.getType(), node.getTree().getKind(), left, right);
  }

  /**
   * Returns the operator of this binary operation.
   *
   * @return the binary operation kind
   */
  public Tree.Kind getOperationKind() {
    return operationKind;
  }

  /**
   * Returns the left operand of this binary operation.
   *
   * @return the left operand
   */
  public JavaExpression getLeft() {
    return left;
  }

  /**
   * Returns the right operand of this binary operation.
   *
   * @return the right operand
   */
  public JavaExpression getRight() {
    return right;
  }

  @Override
  public boolean containsOfClass(Class clazz) {
    if (getClass() == clazz) {
      return true;
    }
    return left.containsOfClass(clazz) || right.containsOfClass(clazz);
  }

  @Override
  public boolean isDeterministic(AnnotationProvider provider) {
    return left.isDeterministic(provider) && right.isDeterministic(provider);
  }

  @Override
  public boolean isUnassignableByOtherCode() {
    return left.isUnassignableByOtherCode() && right.isUnassignableByOtherCode();
  }

  @Override
  public boolean isUnmodifiableByOtherCode() {
    return left.isUnmodifiableByOtherCode() && right.isUnmodifiableByOtherCode();
  }

  @Override
  public boolean syntacticEquals(JavaExpression je) {
    if (!(je instanceof BinaryOperation)) {
      return false;
    }
    BinaryOperation other = (BinaryOperation) je;
    return operationKind == other.getOperationKind()
        && left.syntacticEquals(other.left)
        && right.syntacticEquals(other.right);
  }

  @Override
  public boolean containsSyntacticEqualJavaExpression(JavaExpression other) {
    return this.syntacticEquals(other)
        || left.containsSyntacticEqualJavaExpression(other)
        || right.containsSyntacticEqualJavaExpression(other);
  }

  @Override
  public boolean containsModifiableAliasOf(Store store, JavaExpression other) {
    return left.containsModifiableAliasOf(store, other)
        || right.containsModifiableAliasOf(store, other);
  }

  @Override
  public int hashCode() {
    return Objects.hash(operationKind, left, right);
  }

  @Override
  public boolean equals(@Nullable Object other) {
    if (!(other instanceof BinaryOperation)) {
      return false;
    }
    BinaryOperation biOp = (BinaryOperation) other;
    if (!(operationKind == biOp.getOperationKind())) {
      return false;
    }
    if (isCommutative()) {
      return (left.equals(biOp.left) && right.equals(biOp.right))
          || (left.equals(biOp.right) && right.equals(biOp.left));
    }
    return left.equals(biOp.left) && right.equals(biOp.right);
  }

  /**
   * Returns true if the binary operation is commutative, e.g., x + y == y + x.
   *
   * @return true if the binary operation is commutative
   */
  private boolean isCommutative() {
    switch (operationKind) {
      case PLUS:
      case MULTIPLY:
      case AND:
      case OR:
      case XOR:
      case EQUAL_TO:
      case NOT_EQUAL_TO:
      case CONDITIONAL_AND:
      case CONDITIONAL_OR:
        return true;
      default:
        return false;
    }
  }

  @Override
  public String toString() {
    return left.toString() + " " + operationKindToString(operationKind) + " " + right.toString();
  }

  /**
   * Return the Java source code representation of the given operation.
   *
   * @param operationKind an unary operation kind
   * @return the Java source code representation of the given operation
   */
  private String operationKindToString(Tree.Kind operationKind) {
    switch (operationKind) {
      case CONDITIONAL_AND:
        return "&&";
      case AND:
        return "&";
      case OR:
        return "|";
      case DIVIDE:
        return "/";
      case EQUAL_TO:
        return "==";
      case GREATER_THAN:
        return ">";
      case GREATER_THAN_EQUAL:
        return ">=";
      case LEFT_SHIFT:
        return "<<";
      case LESS_THAN:
        return "<";
      case LESS_THAN_EQUAL:
        return "<=";
      case MINUS:
        return "-";
      case MULTIPLY:
        return "*";
      case NOT_EQUAL_TO:
        return "!=";
      case CONDITIONAL_OR:
        return "||";
      case PLUS:
        return "+";
      case REMAINDER:
        return "%";
      case RIGHT_SHIFT:
        return ">>";
      case UNSIGNED_RIGHT_SHIFT:
        return ">>>";
      case XOR:
        return "^";
      default:
        throw new BugInCF("unhandled " + operationKind);
    }
  }

  @Override
  public  R accept(JavaExpressionVisitor visitor, P p) {
    return visitor.visitBinaryOperation(this, p);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy