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

org.sonar.java.symexec.ExecutionState Maven / Gradle / Ivy

There is a newer version: 8.6.0.37351
Show newest version
/*
 * SonarQube Java
 * Copyright (C) 2012 SonarSource
 * [email protected]
 *
 * 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  02
 */
package org.sonar.java.symexec;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import com.google.common.collect.Table;

import javax.annotation.Nullable;

import java.util.Map;
import java.util.Set;

import static org.sonar.java.symexec.SymbolicBooleanConstraint.FALSE;
import static org.sonar.java.symexec.SymbolicBooleanConstraint.TRUE;
import static org.sonar.java.symexec.SymbolicRelation.EQUAL_TO;
import static org.sonar.java.symexec.SymbolicRelation.GREATER_EQUAL;
import static org.sonar.java.symexec.SymbolicRelation.GREATER_THAN;
import static org.sonar.java.symexec.SymbolicRelation.LESS_EQUAL;
import static org.sonar.java.symexec.SymbolicRelation.LESS_THAN;
import static org.sonar.java.symexec.SymbolicRelation.NOT_EQUAL;
import static org.sonar.java.symexec.SymbolicRelation.UNKNOWN;

public class ExecutionState {

  // FIXME(merciesa): find a better name...
  @VisibleForTesting
  static final Table RELATION_RELATION_MAP = HashBasedTable.create();

  static {
    RELATION_RELATION_MAP.put(EQUAL_TO, EQUAL_TO, TRUE);
    RELATION_RELATION_MAP.put(EQUAL_TO, GREATER_EQUAL, TRUE);
    RELATION_RELATION_MAP.put(EQUAL_TO, GREATER_THAN, FALSE);
    RELATION_RELATION_MAP.put(EQUAL_TO, LESS_EQUAL, TRUE);
    RELATION_RELATION_MAP.put(EQUAL_TO, LESS_THAN, FALSE);
    RELATION_RELATION_MAP.put(EQUAL_TO, NOT_EQUAL, FALSE);
    RELATION_RELATION_MAP.put(EQUAL_TO, UNKNOWN, SymbolicBooleanConstraint.UNKNOWN);

    RELATION_RELATION_MAP.put(GREATER_EQUAL, EQUAL_TO, SymbolicBooleanConstraint.UNKNOWN);
    RELATION_RELATION_MAP.put(GREATER_EQUAL, GREATER_EQUAL, TRUE);
    RELATION_RELATION_MAP.put(GREATER_EQUAL, GREATER_THAN, SymbolicBooleanConstraint.UNKNOWN);
    RELATION_RELATION_MAP.put(GREATER_EQUAL, LESS_EQUAL, SymbolicBooleanConstraint.UNKNOWN);
    RELATION_RELATION_MAP.put(GREATER_EQUAL, LESS_THAN, FALSE);
    RELATION_RELATION_MAP.put(GREATER_EQUAL, NOT_EQUAL, SymbolicBooleanConstraint.UNKNOWN);
    RELATION_RELATION_MAP.put(GREATER_EQUAL, UNKNOWN, SymbolicBooleanConstraint.UNKNOWN);

    RELATION_RELATION_MAP.put(GREATER_THAN, EQUAL_TO, FALSE);
    RELATION_RELATION_MAP.put(GREATER_THAN, GREATER_EQUAL, TRUE);
    RELATION_RELATION_MAP.put(GREATER_THAN, GREATER_THAN, TRUE);
    RELATION_RELATION_MAP.put(GREATER_THAN, LESS_EQUAL, FALSE);
    RELATION_RELATION_MAP.put(GREATER_THAN, LESS_THAN, FALSE);
    RELATION_RELATION_MAP.put(GREATER_THAN, NOT_EQUAL, SymbolicBooleanConstraint.TRUE);
    RELATION_RELATION_MAP.put(GREATER_THAN, UNKNOWN, SymbolicBooleanConstraint.UNKNOWN);

    RELATION_RELATION_MAP.put(LESS_EQUAL, EQUAL_TO, SymbolicBooleanConstraint.UNKNOWN);
    RELATION_RELATION_MAP.put(LESS_EQUAL, GREATER_EQUAL, SymbolicBooleanConstraint.UNKNOWN);
    RELATION_RELATION_MAP.put(LESS_EQUAL, GREATER_THAN, FALSE);
    RELATION_RELATION_MAP.put(LESS_EQUAL, LESS_EQUAL, TRUE);
    RELATION_RELATION_MAP.put(LESS_EQUAL, LESS_THAN, SymbolicBooleanConstraint.UNKNOWN);
    RELATION_RELATION_MAP.put(LESS_EQUAL, NOT_EQUAL, SymbolicBooleanConstraint.UNKNOWN);
    RELATION_RELATION_MAP.put(LESS_EQUAL, UNKNOWN, SymbolicBooleanConstraint.UNKNOWN);

    RELATION_RELATION_MAP.put(LESS_THAN, EQUAL_TO, FALSE);
    RELATION_RELATION_MAP.put(LESS_THAN, GREATER_EQUAL, FALSE);
    RELATION_RELATION_MAP.put(LESS_THAN, GREATER_THAN, FALSE);
    RELATION_RELATION_MAP.put(LESS_THAN, LESS_EQUAL, TRUE);
    RELATION_RELATION_MAP.put(LESS_THAN, LESS_THAN, TRUE);
    RELATION_RELATION_MAP.put(LESS_THAN, NOT_EQUAL, TRUE);
    RELATION_RELATION_MAP.put(LESS_THAN, UNKNOWN, SymbolicBooleanConstraint.UNKNOWN);

    RELATION_RELATION_MAP.put(NOT_EQUAL, EQUAL_TO, FALSE);
    RELATION_RELATION_MAP.put(NOT_EQUAL, GREATER_EQUAL, SymbolicBooleanConstraint.UNKNOWN);
    RELATION_RELATION_MAP.put(NOT_EQUAL, GREATER_THAN, SymbolicBooleanConstraint.UNKNOWN);
    RELATION_RELATION_MAP.put(NOT_EQUAL, LESS_EQUAL, SymbolicBooleanConstraint.UNKNOWN);
    RELATION_RELATION_MAP.put(NOT_EQUAL, LESS_THAN, SymbolicBooleanConstraint.UNKNOWN);
    RELATION_RELATION_MAP.put(NOT_EQUAL, NOT_EQUAL, TRUE);
    RELATION_RELATION_MAP.put(NOT_EQUAL, UNKNOWN, SymbolicBooleanConstraint.UNKNOWN);

    RELATION_RELATION_MAP.put(UNKNOWN, EQUAL_TO, SymbolicBooleanConstraint.UNKNOWN);
    RELATION_RELATION_MAP.put(UNKNOWN, GREATER_EQUAL, SymbolicBooleanConstraint.UNKNOWN);
    RELATION_RELATION_MAP.put(UNKNOWN, GREATER_THAN, SymbolicBooleanConstraint.UNKNOWN);
    RELATION_RELATION_MAP.put(UNKNOWN, LESS_EQUAL, SymbolicBooleanConstraint.UNKNOWN);
    RELATION_RELATION_MAP.put(UNKNOWN, LESS_THAN, SymbolicBooleanConstraint.UNKNOWN);
    RELATION_RELATION_MAP.put(UNKNOWN, NOT_EQUAL, SymbolicBooleanConstraint.UNKNOWN);
    RELATION_RELATION_MAP.put(UNKNOWN, UNKNOWN, SymbolicBooleanConstraint.UNKNOWN);
  }

  @Nullable
  @VisibleForTesting
  final ExecutionState parentState;
  @VisibleForTesting
  final Table relations;

  public ExecutionState() {
    this.parentState = null;
    this.relations = HashBasedTable.create();
  }

  ExecutionState(ExecutionState parentState) {
    this.parentState = parentState;
    this.relations = HashBasedTable.create();
  }

  @VisibleForTesting
  SymbolicRelation getRelation(SymbolicValue leftValue, SymbolicValue rightValue) {
    SymbolicRelation result = relations.get(leftValue, rightValue);
    if(result != null) {
      return result;
    }
    return parentState != null ? parentState.getRelation(leftValue, rightValue) : UNKNOWN;
  }

  SymbolicBooleanConstraint evaluateRelation(SymbolicValue leftValue, SymbolicRelation relation, SymbolicValue rightValue) {
    return RELATION_RELATION_MAP.get(getRelation(leftValue, rightValue), relation);
  }

  ExecutionState setRelation(SymbolicValue leftValue, SymbolicRelation relation, SymbolicValue rightValue) {
    if (!leftValue.equals(rightValue)) {
      relations.put(leftValue, rightValue, relation);
      relations.put(rightValue, leftValue, relation.swap());
    }
    return this;
  }

  void mergeRelations(Iterable states) {
    for (Map.Entry entry : findRelatedValues(states).entries()) {
      SymbolicRelation relation = null;
      for (ExecutionState state : states) {
        relation = state.getRelation(entry.getKey(), entry.getValue()).union(relation);
      }
      if (relation == null) {
        relation = SymbolicRelation.UNKNOWN;
      }
      if (getRelation(entry.getKey(), entry.getValue()) != relation) {
        relations.put(entry.getKey(), entry.getValue(), relation);
        relations.put(entry.getValue(), entry.getKey(), relation.swap());
      }
    }
  }

  private Multimap findRelatedValues(Iterable states) {
    Multimap result = HashMultimap.create();
    for (ExecutionState state : states) {
      for (ExecutionState current = state; !current.equals(this); current = current.parentState) {
        for (Map.Entry> leftEntry : current.relations.rowMap().entrySet()) {
          result.putAll(leftEntry.getKey(), leftEntry.getValue().keySet());
        }
      }
    }
    return result;
  }

  SymbolicBooleanConstraint getBooleanConstraint(SymbolicValue.SymbolicVariableValue variable) {
    switch (getRelation(variable, SymbolicValue.BOOLEAN_TRUE)) {
      case EQUAL_TO:
        return SymbolicBooleanConstraint.TRUE;
      case NOT_EQUAL:
        return SymbolicBooleanConstraint.FALSE;
      default:
        return SymbolicBooleanConstraint.UNKNOWN;
    }
  }

  ExecutionState setBooleanConstraint(SymbolicValue.SymbolicVariableValue variable, SymbolicBooleanConstraint constraint) {
    switch (constraint) {
      case FALSE:
        setRelation(variable, SymbolicRelation.NOT_EQUAL, SymbolicValue.BOOLEAN_TRUE);
        break;
      case TRUE:
        setRelation(variable, SymbolicRelation.EQUAL_TO, SymbolicValue.BOOLEAN_TRUE);
        break;
      default:
        setRelation(variable, SymbolicRelation.UNKNOWN, SymbolicValue.BOOLEAN_TRUE);
        break;
    }
    return this;
  }

  void invalidateRelationsOnValue(SymbolicValue value) {
    Multimap pairs = HashMultimap.create();
    for (ExecutionState current = this; current != null; current = current.parentState) {
      pairs.putAll(value, current.findRelatedValues(value));
    }
    for (Map.Entry entry : pairs.entries()) {
      setRelation(entry.getKey(), SymbolicRelation.UNKNOWN, entry.getValue());
    }
  }

  private Set findRelatedValues(SymbolicValue value) {
    Map map = relations.rowMap().get(value);
    return map != null ? map.keySet() : ImmutableSet.of();
  }

  void invalidateFields() {
    for (ExecutionState state = this; state != null; state = state.parentState) {
      for (Map.Entry> entry : state.relations.rowMap().entrySet()) {
        if (isField(entry.getKey())) {
          for (SymbolicValue other : entry.getValue().keySet()) {
            setRelation(entry.getKey(), SymbolicRelation.UNKNOWN, other);
          }
        }
      }
    }
  }

  private static boolean isField(SymbolicValue value) {
    return value instanceof SymbolicValue.SymbolicVariableValue && ((SymbolicValue.SymbolicVariableValue) value).variable.owner().isTypeSymbol();
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy