package uk.ac.cam.gpe21.droidssl.analysis.trans;

import soot.*;
import soot.jimple.AbstractStmtSwitch;
import soot.jimple.AssignStmt;
import soot.jimple.InvokeStmt;
import soot.toolkits.graph.UnitGraph;
import soot.toolkits.scalar.ForwardFlowAnalysis;
import uk.ac.cam.gpe21.droidssl.analysis.util.Types;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

public final class SslContextFlowAnalysis extends ForwardFlowAnalysis<Unit, Set<Local>> {
	public SslContextFlowAnalysis(UnitGraph graph) {
		super(graph);
		doAnalysis();
	}

	@Override
	protected void flowThrough(final Set<Local> in, Unit node, final Set<Local> out) {
		node.apply(new AbstractStmtSwitch() {
			@Override
			public void caseInvokeStmt(InvokeStmt stmt) {
				out.addAll(in);

				SootMethod targetMethod = stmt.getInvokeExpr().getMethod();
				if (!targetMethod.getDeclaringClass().getType().equals(Types.SSL_CONTEXT))
					return;

				if (!targetMethod.getName().equals("init"))
					return;

				List<ValueBox> list = stmt.getInvokeExpr().getUseBoxes();
				if (list.size() < 1)
					return; /* TODO could this ever happen? */

				Value value = list.get(0).getValue();
				if (!(value instanceof Local))
					return; /* TODO could this ever happen? */

				Local local = (Local) value;
				out.add(local);
			}

			@Override
			public void caseAssignStmt(AssignStmt stmt) {
				out.addAll(in);

				Value left = stmt.getLeftOp();
				Value right = stmt.getRightOp();

				if (left instanceof Local) {
					Local left0 = (Local) left;
					if (out.contains(left0))
						out.remove(left0);

					if (right instanceof Local) {
						Local right0 = (Local) right;
						if (out.contains(right0))
							out.add(left0);
					}
				}
			}

			@Override
			public void defaultCase(Object obj) {
				out.addAll(in);
			}
		});
	}

	@Override
	protected Set<Local> newInitialFlow() {
		return new HashSet<>(); // TODO use FlowSet
	}

	@Override
	protected Set<Local> entryInitialFlow() {
		return new HashSet<>();
	}

	@Override
	protected void merge(Set<Local> in1, Set<Local> in2, Set<Local> out) {
		out.addAll(in1);
		out.addAll(in2);
	}

	@Override
	protected void copy(Set<Local> source, Set<Local> dest) {
		dest.addAll(source);
	}
}

@@ -197,16 +197,97 @@
 tGraph;%0A
+import soot.toolkits.scalar.ArraySparseSet;%0Aimport soot.toolkits.scalar.FlowSet;%0A
 import s
@@ -402,59 +402,11 @@
 til.
-HashSet;%0Aimport java.util.List;%0Aimport java.util.Se
+Lis
 t;%0A%0A
@@ -481,26 +481,23 @@
 s%3CUnit, 
-Set%3CLocal%3E
+FlowSet
 %3E %7B%0A%09pub
@@ -623,26 +623,23 @@
 h(final 
-Set%3CLocal%3E
+FlowSet
  in, Uni
@@ -652,26 +652,23 @@
 , final 
-Set%3CLocal%3E
+FlowSet
  out) %7B%0A
@@ -769,37 +769,35 @@
 stmt) %7B%0A%09%09%09%09
-out.addAll(in
+in.copy(out
 );%0A%0A%09%09%09%09Soot
@@ -1394,29 +1394,27 @@
 ) %7B%0A%09%09%09%09
-out.addAll(in
+in.copy(out
 );%0A%0A%09%09%09%09
@@ -1807,29 +1807,27 @@
 ) %7B%0A%09%09%09%09
-out.addAll(in
+in.copy(out
 );%0A%09%09%09%7D%0A
@@ -1858,26 +1858,23 @@
 otected 
-Set%3CLocal%3E
+FlowSet
  newInit
@@ -1902,40 +1902,25 @@
 new 
-Hash
+ArraySparse
 Set
-%3C%3E
 ();
- // TODO use FlowSet
 %0A%09%7D%0A
@@ -1942,26 +1942,23 @@
 otected 
-Set%3CLocal%3E
+FlowSet
  entryIn
@@ -1988,17 +1988,22 @@
 new 
-Hash
+ArraySparse
 Set
-%3C%3E
 ();%0A
@@ -2043,190 +2043,158 @@
 rge(
-Set%3CLocal%3E in1, Set%3CLocal%3E in2, Set%3CLocal%3E out) %7B%0A%09%09out.addAll(in1);%0A%09%09out.addAll(in2);%0A%09%7D%0A%0A%09@Override%0A%09protected void copy(Set%3CLocal%3E source, Set%3CLocal%3E dest) %7B%0A%09%09dest.addAll(source
+FlowSet in1, FlowSet in2, FlowSet out) %7B%0A%09%09in1.union(in2, out);%0A%09%7D%0A%0A%09@Override%0A%09protected void copy(FlowSet source, FlowSet dest) %7B%0A%09%09source.copy(dest
 );%0A%09

Replace HashSet with ArraySparseSet in SslContextFlowAnalysis.