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

edu.umd.cs.findbugs.ba.obl.StateSet Maven / Gradle / Ivy

There is a newer version: 4.8.6
Show newest version
/*
 * Bytecode Analysis Framework
 * Copyright (C) 2005,2008 University of Maryland
 *
 * This library 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 2.1 of the License, or (at your option) any later version.
 *
 * This library 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 library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package edu.umd.cs.findbugs.ba.obl;

import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import edu.umd.cs.findbugs.ba.Path;

/**
 * A dataflow fact used in ObligationAnalysis. It is a set of State objects,
 * plus the additional capability to represent top and bottom elements.
 *
 * 

* Invariant: no StateSet may contain more than one State with the same * ObligationSet. *

* *

* See Weimer and Necula, Finding and preventing run-time error handling mistakes, OOPSLA 2004. *

* * @author David Hovemeyer */ public class StateSet { private boolean isTop; private boolean isBottom; private boolean onExceptionPath; private Map stateMap; public boolean isEmpty() { return stateMap.isEmpty(); } private final ObligationFactory factory; public StateSet(ObligationFactory factory) { this.isTop = this.isBottom = false; this.stateMap = new HashMap<>(); this.factory = factory; } public void setTop() { this.isTop = true; this.isBottom = false; this.onExceptionPath = false; this.stateMap.clear(); } public boolean isTop() { return isTop; } public void setBottom() { this.isBottom = true; this.isTop = false; } public boolean isBottom() { return this.isBottom; } public boolean isValid() { return !this.isTop && !this.isBottom; } public boolean isOnExceptionPath() { return onExceptionPath; } public void setOnExceptionPath(boolean onExceptionPath) { this.onExceptionPath = onExceptionPath; } public void clear() { this.isTop = this.isBottom = this.onExceptionPath = false; stateMap.clear(); } /** * Return an Iterator over the States in the StateSet. * * @return an Iterator over the States in the StateSet */ public Iterator stateIterator() { return stateMap.values().iterator(); } /** * Get Set of all ObligationsSets in this StateSet. * * @return Set of all ObligationsSets in this StateSet */ public Set getAllObligationSets() { return Collections.unmodifiableSet(stateMap.keySet()); } /** * Get the State which has the given ObligationSet. Returns null if there is * no such state. * * @param obligationSet * we want to get the State with this ObligationSet * @return the State with the given ObligationSet, or null if there is no * such State */ public State getStateWithObligationSet(ObligationSet obligationSet) { return stateMap.get(obligationSet); } // /** // * Initialize this object as the entry fact for a method: // * a single state with empty obligation set and path. // * // * @param factory the ObligationFactory used for the analysis // */ // public void initEntryFact(ObligationFactory factory) { // this.isTop = this.isBottom = false; // this.stateMap.clear(); // // // Add initial fact: empty obligations, empty path // State initState = new State(factory); // this.stateMap.put(initState.getObligationSet(), initState); // } /** * Make this StateSet an exact copy of the given StateSet. * * @param other * a StateSet; this StateSet will be made identical to it */ public void copyFrom(StateSet other) { this.isTop = other.isTop; this.isBottom = other.isBottom; this.onExceptionPath = other.onExceptionPath; this.stateMap.clear(); for (State state : other.stateMap.values()) { State dup = state.duplicate(); this.stateMap.put(dup.getObligationSet(), dup); } } /** * Return an exact deep copy of this StateSet. * * @return an exact deep copy of this StateSet */ public StateSet duplicate() { StateSet dup = new StateSet(factory); dup.copyFrom(this); return dup; } /** * Add an obligation to every State in the StateSet. * * @param obligation * the obligation to add * @param basicBlockId * the id of the basic block (path component) adding the * obligation */ public void addObligation(final Obligation obligation, int basicBlockId) throws ObligationAcquiredOrReleasedInLoopException { Map updatedStateMap = new HashMap<>(); if (stateMap.isEmpty()) { State s = new State(factory); s.getObligationSet().add(obligation); updatedStateMap.put(s.getObligationSet(), s); } else { for (State state : stateMap.values()) { checkCircularity(state, obligation, basicBlockId); state.getObligationSet().add(obligation); updatedStateMap.put(state.getObligationSet(), state); } } replaceMap(updatedStateMap); } /** * Remove an Obligation from every State in the StateSet. * * @param obligation * the obligation to remove * @param basicBlockId * the id of the basic block (path component) removing the * obligation * @throws ObligationAcquiredOrReleasedInLoopException */ public void deleteObligation(final Obligation obligation, int basicBlockId) throws ObligationAcquiredOrReleasedInLoopException { Map updatedStateMap = new HashMap<>(); for (Iterator i = stateIterator(); i.hasNext();) { State state = i.next(); checkCircularity(state, obligation, basicBlockId); ObligationSet obligationSet = state.getObligationSet(); obligationSet.remove(obligation); if (!obligationSet.isEmpty()) { updatedStateMap.put(obligationSet, state); } } replaceMap(updatedStateMap); } /** * Bail out of the analysis is an obligation is acquired or released in a * loop. * * @param state * a State to which an obligation is being added or removed * @param obligation * the Obligation being added or removed * @param basicBlockId * the id of the BasicBlock adding or removing the obligation */ private void checkCircularity(State state, Obligation obligation, int basicBlockId) throws ObligationAcquiredOrReleasedInLoopException { if (state.getPath().hasComponent(basicBlockId)) { throw new ObligationAcquiredOrReleasedInLoopException(obligation); } } /** * Replace the map of ObligationSets to States with the given one. * * @param stateMap * enw map of ObligationSets to States */ public void replaceMap(Map stateMap) { this.stateMap = stateMap; } /** * Get all States that have Paths which are prefixes of the given Path. * * @param path * a Path * @return Collection of States that have Paths which are prefixes of the * given Path */ public List getPrefixStates(Path path) { List result = new LinkedList<>(); for (State state : stateMap.values()) { if (state.getPath().isPrefixOf(path)) { result.add(state); } } return result; } @Override public boolean equals(Object o) { if (o == null || o.getClass() != this.getClass()) { return false; } StateSet other = (StateSet) o; return this.isTop == other.isTop && this.isBottom == other.isBottom && this.onExceptionPath == other.onExceptionPath && this.stateMap.equals(other.stateMap); } @Override public int hashCode() { throw new UnsupportedOperationException(); } @Override public String toString() { if (isTop) { return "TOP"; } else if (isBottom) { return "BOTTOM"; } else { StringBuilder buf = new StringBuilder(); buf.append(stateMap); if (onExceptionPath) { buf.append(" On exception path"); } return buf.toString(); } } /** * Return a newly allocated Map of ObligationSet to State that may be passed * to applyToAllStatesAndUpdateMap(). */ public Map createEmptyMap() { return new HashMap<>(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy