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

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

/*
 * 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.symexecengine;

import com.google.common.collect.HashMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.SetMultimap;
import com.google.common.collect.Sets;
import org.sonar.plugins.java.api.semantic.Symbol;
import org.sonar.plugins.java.api.tree.Tree;

import javax.annotation.CheckForNull;

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

public class ExecutionState {

  final ExecutionState parent;
  private SetMultimap reachableValues = HashMultimap.create();
  private SetMultimap unreachableValues = HashMultimap.create();
  /**
   * List of symbol that were declared within this execution state.
   */
  private List definedInState = Lists.newArrayList();
  private Map stateOfValue = Maps.newHashMap();

  public ExecutionState(ExecutionState executionState) {
    this.parent = executionState;
    this.reachableValues = HashMultimap.create(executionState.reachableValues);
    this.unreachableValues = HashMultimap.create(executionState.unreachableValues);
  }

  /**
   * ParentState constructor.
   */
  public ExecutionState() {
    this.parent = null;
  }

  public void defineSymbol(Symbol symbol) {
    definedInState.add(symbol);
  }

  public ExecutionState merge(ExecutionState executionState) {
    for (Symbol symbol : executionState.reachableValues.keys()) {
      if (!executionState.definedInState.contains(symbol)) {
        this.reachableValues.putAll(symbol, executionState.reachableValues.get(symbol));
      }
    }
    for (Symbol symbol : executionState.unreachableValues.keys()) {
      if (!executionState.definedInState.contains(symbol)) {
        this.unreachableValues.putAll(symbol, executionState.unreachableValues.get(symbol));
      }
    }

    for (Symbol symbol : unreachableValues.keys()) {
      // cleanup after merge of reachable/unreachable values
      for (SymbolicValue value : unreachableValues.get(symbol)) {
        reachableValues.remove(symbol, value);
      }
    }
    // Merge states of values
    for (Map.Entry valueStateEntry : executionState.stateOfValue.entrySet()) {
      SymbolicValue value = valueStateEntry.getKey();
      State state = valueStateEntry.getValue();
      State valueState = getStateOfValue(value);
      if (valueState == null) {
        valueState = state;
      } else {
        valueState = valueState.merge(state);
      }
      this.stateOfValue.put(value, valueState);
    }
    return this;
  }

  public ExecutionState overrideBy(ExecutionState executionState) {
    this.unreachableValues.putAll(executionState.unreachableValues);
    this.reachableValues = executionState.reachableValues;
    this.stateOfValue.putAll(executionState.stateOfValue);
    return this;
  }

  public ExecutionState restoreParent() {
    return parent.merge(this);
  }

  Set getStatesOfCurrentExecutionState() {
    Set results = Sets.newHashSet();
    for (Symbol symbol : definedInState) {
      for (SymbolicValue value : Iterables.concat(reachableValues.get(symbol), unreachableValues.get(symbol))) {
        State state = stateOfValue.get(value);
        if (state != null) {
          results.add(state);
        }
      }
    }
    return results;
  }

  // FIXME : Hideous hack for closeable to get "Ignored" variables
  public List getStatesOf(Symbol symbol) {
    List states = Lists.newArrayList();
    for (SymbolicValue value : Iterables.concat(reachableValues.get(symbol), unreachableValues.get(symbol))) {
      State state = stateOfValue.get(value);
      if (state != null) {
        states.add(state);
      }
    }
    return states;
  }

  @CheckForNull
  private State getStateOfValue(SymbolicValue value) {
    ExecutionState currentState = this;
    while (currentState != null) {
      State state = currentState.stateOfValue.get(value);
      if (state != null) {
        return state;
      }
      currentState = currentState.parent;
    }
    return null;
  }

  Iterable getValues(Symbol symbol) {
    return reachableValues.get(symbol);
  }

  public SymbolicValue createValueForSymbol(Symbol symbol, Tree tree) {
    // When creating a new value, all reachable values are now unreachable.
    Set values = this.reachableValues.get(symbol);
    unreachableValues.putAll(symbol, values);
    values.clear();
    SymbolicValue value = new SymbolicValue(tree);
    reachableValues.put(symbol, value);
    stateOfValue.put(value, State.UNSET);
    return value;
  }

  public void markValueAs(Symbol symbol, State state) {
    for (SymbolicValue value : getValues(symbol)) {
      stateOfValue.put(value, state);
    }
  }

  public void markValueAs(SymbolicValue value, State state) {
    stateOfValue.put(value, state);
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy