// Path: FlowTwist/test/flow/twist/test/util/selectors/TrackableSelector.java
// public interface TrackableSelector {
// 	boolean matches(Trackable trackable);
// }
// 
// Path: FlowTwist/test/flow/twist/test/util/selectors/UnitSelector.java
// public interface UnitSelector {
// 	boolean matches(SootMethod method, Unit unit);
// }
// 
// Path: FlowTwist/src/flow/twist/trackable/Trackable.java
// public abstract class Trackable implements LinkedNode<Trackable> {
// 
// 	public final Trackable predecessor;
// 	public final Unit sourceUnit;
// 	private final List<Trackable> neighbors;
// 	private final Set<Object> payload;
// 
// 	protected Trackable() {
// 		this.predecessor = null;
// 		this.sourceUnit = null;
// 		payload = Sets.newHashSet();
// 		neighbors = Lists.newLinkedList();
// 	}
// 
// 	public Trackable(Unit sourceUnit, Trackable predecessor) {
// 		this.predecessor = predecessor;
// 		this.sourceUnit = sourceUnit;
// 		payload = Sets.newHashSet();
// 		neighbors = Lists.newLinkedList();
// 		payload.addAll(predecessor.payload);
// 	}
// 
// 	public void addPayload(Object payload) {
// 		this.payload.add(payload);
// 	}
// 
// 	public void addNeighbor(Trackable trackable) {
// 		// trackable.neighbors.addAll(getSelfAndNeighbors());
// 		neighbors.add(trackable);
// 	}
// 
// 	public Collection<Trackable> getSelfAndNeighbors() {
// 		LinkedList<Trackable> result = Lists.newLinkedList(neighbors);
// 		result.add(this);
// 		return result;
// 	}
// 
// 	public boolean hasSelfOrNeighborAnPredecessor() {
// 		for (Trackable t : getSelfAndNeighbors())
// 			if (t.predecessor != null)
// 				return true;
// 		return false;
// 	}
// 
// 	public abstract Trackable cloneWithoutNeighborsAndPayload();
// 
// 	@Override
// 	public int hashCode() {
// 		final int prime = 31;
// 		int result = 1;
// 		result = prime * result + ((payload == null) ? 0 : payload.hashCode());
// 		return result;
// 	}
// 
// 	@Override
// 	public boolean equals(Object obj) {
// 		if (this == obj)
// 			return true;
// 		if (obj == null)
// 			return false;
// 		if (!(obj instanceof Trackable))
// 			return false;
// 		Trackable other = (Trackable) obj;
// 		if (payload == null) {
// 			if (other.payload != null)
// 				return false;
// 		} else if (!payload.equals(other.payload))
// 			return false;
// 		return true;
// 	}
// 
// 	public String payloadString() {
// 		if (payload.size() == 0)
// 			return "";
// 		return "(" + Joiner.on(",").join(payload) + ")";
// 	}
// 
// 	public abstract Trackable createAlias(Unit sourceUnits);
// 
// 	public Collection<Object> getPayload() {
// 		return payload;
// 	}
// }


import static java.lang.String.format;
import heros.solver.Pair;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import junit.framework.AssertionFailedError;
import org.junit.Assert;
import soot.SootMethod;
import soot.Unit;
import soot.util.IdentityHashSet;
import com.google.common.base.Supplier;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import com.google.common.collect.Sets;
import flow.twist.config.AnalysisContext;
import flow.twist.reporter.IfdsReporter;
import flow.twist.reporter.Report;
import flow.twist.reporter.TrackableGraphPlotter;
import flow.twist.test.util.selectors.TrackableSelector;
import flow.twist.test.util.selectors.UnitSelector;
import flow.twist.trackable.Trackable;
package flow.twist.test.util;








public class AnalysisGraphVerifier implements IfdsReporter {

	private TrackableGraphPlotter debugPlotter;
	private Map<Unit, SootMethod> unit2Method = Maps.newHashMap();
	private Multimap<Unit, Pair<Unit, Trackable>> successors = HashMultimap.create();
	private Multimap<Unit, Trackable> trackablesAtUnit = Multimaps.newSetMultimap(new HashMap<Unit, Collection<Trackable>>(),
			new Supplier<Set<Trackable>>() {
				@Override
				public Set<Trackable> get() {
					return new IdentityHashSet<>();
				}
			});

	public AnalysisGraphVerifier() {
		// debugPlotter = new DebugPlotter();
		debugPlotter = new TrackableGraphPlotter();
	}

	@Override
	public void reportTrackable(Report report) {
		debugPlotter.reportTrackable(report);
		createEdges(report.context, report.trackable, report.targetUnit);
	}

// Path: FlowTwist/test/flow/twist/test/util/selectors/TrackableSelector.java
// public interface TrackableSelector {
// 	boolean matches(Trackable trackable);
// }
// 
// Path: FlowTwist/test/flow/twist/test/util/selectors/UnitSelector.java
// public interface UnitSelector {
// 	boolean matches(SootMethod method, Unit unit);
// }
// 
// Path: FlowTwist/src/flow/twist/trackable/Trackable.java
// public abstract class Trackable implements LinkedNode<Trackable> {
// 
// 	public final Trackable predecessor;
// 	public final Unit sourceUnit;
// 	private final List<Trackable> neighbors;
// 	private final Set<Object> payload;
// 
// 	protected Trackable() {
// 		this.predecessor = null;
// 		this.sourceUnit = null;
// 		payload = Sets.newHashSet();
// 		neighbors = Lists.newLinkedList();
// 	}
// 
// 	public Trackable(Unit sourceUnit, Trackable predecessor) {
// 		this.predecessor = predecessor;
// 		this.sourceUnit = sourceUnit;
// 		payload = Sets.newHashSet();
// 		neighbors = Lists.newLinkedList();
// 		payload.addAll(predecessor.payload);
// 	}
// 
// 	public void addPayload(Object payload) {
// 		this.payload.add(payload);
// 	}
// 
// 	public void addNeighbor(Trackable trackable) {
// 		// trackable.neighbors.addAll(getSelfAndNeighbors());
// 		neighbors.add(trackable);
// 	}
// 
// 	public Collection<Trackable> getSelfAndNeighbors() {
// 		LinkedList<Trackable> result = Lists.newLinkedList(neighbors);
// 		result.add(this);
// 		return result;
// 	}
// 
// 	public boolean hasSelfOrNeighborAnPredecessor() {
// 		for (Trackable t : getSelfAndNeighbors())
// 			if (t.predecessor != null)
// 				return true;
// 		return false;
// 	}
// 
// 	public abstract Trackable cloneWithoutNeighborsAndPayload();
// 
// 	@Override
// 	public int hashCode() {
// 		final int prime = 31;
// 		int result = 1;
// 		result = prime * result + ((payload == null) ? 0 : payload.hashCode());
// 		return result;
// 	}
// 
// 	@Override
// 	public boolean equals(Object obj) {
// 		if (this == obj)
// 			return true;
// 		if (obj == null)
// 			return false;
// 		if (!(obj instanceof Trackable))
// 			return false;
// 		Trackable other = (Trackable) obj;
// 		if (payload == null) {
// 			if (other.payload != null)
// 				return false;
// 		} else if (!payload.equals(other.payload))
// 			return false;
// 		return true;
// 	}
// 
// 	public String payloadString() {
// 		if (payload.size() == 0)
// 			return "";
// 		return "(" + Joiner.on(",").join(payload) + ")";
// 	}
// 
// 	public abstract Trackable createAlias(Unit sourceUnits);
// 
// 	public Collection<Object> getPayload() {
// 		return payload;
// 	}
// }


// Path: FlowTwist/test/flow/twist/test/util/AnalysisGraphVerifier.java
import static java.lang.String.format;
import heros.solver.Pair;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import junit.framework.AssertionFailedError;
import org.junit.Assert;
import soot.SootMethod;
import soot.Unit;
import soot.util.IdentityHashSet;
import com.google.common.base.Supplier;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import com.google.common.collect.Sets;
import flow.twist.config.AnalysisContext;
import flow.twist.reporter.IfdsReporter;
import flow.twist.reporter.Report;
import flow.twist.reporter.TrackableGraphPlotter;
import flow.twist.test.util.selectors.TrackableSelector;
import flow.twist.test.util.selectors.UnitSelector;
import flow.twist.trackable.Trackable;

package flow.twist.test.util;








public class AnalysisGraphVerifier implements IfdsReporter {

	private TrackableGraphPlotter debugPlotter;
	private Map<Unit, SootMethod> unit2Method = Maps.newHashMap();
	private Multimap<Unit, Pair<Unit, Trackable>> successors = HashMultimap.create();
	private Multimap<Unit, Trackable> trackablesAtUnit = Multimaps.newSetMultimap(new HashMap<Unit, Collection<Trackable>>(),
			new Supplier<Set<Trackable>>() {
				@Override
				public Set<Trackable> get() {
					return new IdentityHashSet<>();
				}
			});

	public AnalysisGraphVerifier() {
		// debugPlotter = new DebugPlotter();
		debugPlotter = new TrackableGraphPlotter();
	}

	@Override
	public void reportTrackable(Report report) {
		debugPlotter.reportTrackable(report);
		createEdges(report.context, report.trackable, report.targetUnit);
	}

	private void createEdges(AnalysisContext context, Trackable trackable, Unit unit) {