gt: 					SootField sf = ((StaticFieldRef) assign.getLeftOp()).getField();
context: /*******************************************************************************
   * Copyright (c) 2012 Secure Software Engineering Group at EC SPRIDE.
   * All rights reserved. This program and the accompanying materials
   * are made available under the terms of the GNU Lesser Public License v2.1
   * which accompanies this distribution, and is available at
   * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
   * 
   * Contributors: Christian Fritz, Steven Arzt, Siegfried Rasthofer, Eric
   * Bodden, and others.
   ******************************************************************************/
  package soot.jimple.infoflow.solver.cfg;
  
  import heros.solver.IDESolver;
  
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.HashSet;
  import java.util.Iterator;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  import java.util.concurrent.ConcurrentHashMap;
  
  import soot.Local;
  import soot.Scene;
  import soot.SootField;
  import soot.SootMethod;
  import soot.Unit;
  import soot.Value;
  import soot.ValueBox;
  import soot.jimple.AssignStmt;
  import soot.jimple.FieldRef;
  import soot.jimple.StaticFieldRef;
  import soot.jimple.Stmt;
  import soot.jimple.toolkits.callgraph.Edge;
  import soot.jimple.toolkits.ide.icfg.BiDiInterproceduralCFG;
  import soot.jimple.toolkits.ide.icfg.JimpleBasedInterproceduralCFG;
  import soot.toolkits.graph.DirectedGraph;
  import soot.toolkits.graph.MHGPostDominatorsFinder;
  
  import com.google.common.cache.CacheLoader;
  import com.google.common.cache.LoadingCache;
  
  /**
   * Interprocedural control-flow graph for the infoflow solver
   * 
   * @author Steven Arzt
   * @author Eric Bodden
   */
  public class InfoflowCFG implements IInfoflowCFG {
  	
  	private static enum StaticFieldUse {
  		Unknown,
  		Unused,
  		Read,
  		Write,
  		ReadWrite,
  		Unwrite
  	}
  	
  	protected final Map<SootMethod, Map<SootField, StaticFieldUse>> staticFieldUses =
  			new ConcurrentHashMap<SootMethod, Map<SootField,StaticFieldUse>>();
  	protected final Map<SootMethod, Boolean> methodSideEffects =
  			new ConcurrentHashMap<SootMethod, Boolean>();
  	
  	protected final BiDiInterproceduralCFG<Unit, SootMethod> delegate; 
  	
  	protected final LoadingCache<Unit,UnitContainer> unitToPostdominator =
  			IDESolver.DEFAULT_CACHE_BUILDER.build( new CacheLoader<Unit,UnitContainer>() {
  				@Override
  				public UnitContainer load(Unit unit) throws Exception {
  					SootMethod method = getMethodOf(unit);
  					DirectedGraph<Unit> graph = delegate.getOrCreateUnitGraph(method);
  					MHGPostDominatorsFinder<Unit> postdominatorFinder = new MHGPostDominatorsFinder<Unit>(graph);
  					Unit postdom = postdominatorFinder.getImmediateDominator(unit);
  					if (postdom == null)
  						return new UnitContainer(method);
  					else
  						return new UnitContainer(postdom);
  				}
  			});
  	
  	protected final LoadingCache<SootMethod,Local[]> methodToUsedLocals =
  			IDESolver.DEFAULT_CACHE_BUILDER.build( new CacheLoader<SootMethod,Local[]>() {
  				@Override
  				public Local[] load(SootMethod method) throws Exception {
  					if (!method.isConcrete() || !method.hasActiveBody())
  						return new Local[0];
  					
  					List<Local> lcs = new ArrayList<Local>(method.getParameterCount() + (method.isStatic() ? 0 : 1));
  					
  					for (Unit u : method.getActiveBody().getUnits())
  						useBox : for (ValueBox vb : u.getUseBoxes()) {
  							// Check for parameters
  							for (int i = 0; i < method.getParameterCount(); i++) {
  								if (method.getActiveBody().getParameterLocal(i) == vb.getValue()) {
  									lcs.add((Local) vb.getValue());
  									continue useBox;
  								}
  							}
  						}
  					
  					// Add the "this" local
  					if (!method.isStatic())
  						lcs.add(method.getActiveBody().getThisLocal());
  					
  					return lcs.toArray(new Local[lcs.size()]);
  				}
  			});
  	
  	public InfoflowCFG() {
  		this(new JimpleBasedInterproceduralCFG());
  	}
  	
  	public InfoflowCFG(BiDiInterproceduralCFG<Unit, SootMethod> delegate) {
  		this.delegate = delegate;
  	}
  	
  	@Override
  	public UnitContainer getPostdominatorOf(Unit u) {
  		return unitToPostdominator.getUnchecked(u);
  	}
  	
  	//delegate methods follow
  	
  	@Override
  	public SootMethod getMethodOf(Unit u) {
  		return delegate.getMethodOf(u);
  	}
  
  	@Override
  	public List<Unit> getSuccsOf(Unit u) {
  		return delegate.getSuccsOf(u);
  	}
  
  	@Override
  	public boolean isExitStmt(Unit u) {
  		return delegate.isExitStmt(u);
  	}
  
  	@Override
  	public boolean isStartPoint(Unit u) {
  		return delegate.isStartPoint(u);
  	}
  
  	@Override
  	public boolean isFallThroughSuccessor(Unit u, Unit succ) {
  		return delegate.isFallThroughSuccessor(u, succ);
  	}
  
  	@Override
  	public boolean isBranchTarget(Unit u, Unit succ) {
  		return delegate.isBranchTarget(u, succ);
  	}
  
  	@Override
  	public Collection<Unit> getStartPointsOf(SootMethod m) {
  		return delegate.getStartPointsOf(m);
  	}
  
  	@Override
  	public boolean isCallStmt(Unit u) {
  		return delegate.isCallStmt(u);
  	}
  
  	@Override
  	public Set<Unit> allNonCallStartNodes() {
  		return delegate.allNonCallStartNodes();
  	}
  
  	@Override
  	public Collection<SootMethod> getCalleesOfCallAt(Unit u) {
  		return delegate.getCalleesOfCallAt(u);
  	}
  
  	@Override
  	public Collection<Unit> getCallersOf(SootMethod m) {
  		return delegate.getCallersOf(m);
  	}
  
  	@Override
  	public Collection<Unit> getReturnSitesOfCallAt(Unit u) {
  		return delegate.getReturnSitesOfCallAt(u);
  	}
  
  	@Override
  	public Set<Unit> getCallsFromWithin(SootMethod m) {
  		return delegate.getCallsFromWithin(m);
  	}
  
  	@Override
  	public List<Unit> getPredsOf(Unit u) {
  		return delegate.getPredsOf(u);
  	}
  
  	@Override
  	public Collection<Unit> getEndPointsOf(SootMethod m) {
  		return delegate.getEndPointsOf(m);
  	}
  
  	@Override
  	public List<Unit> getPredsOfCallAt(Unit u) {
  		return delegate.getPredsOf(u);
  	}
  
  	@Override
  	public Set<Unit> allNonCallEndNodes() {
  		return delegate.allNonCallEndNodes();
  	}
  
  	@Override
  	public DirectedGraph<Unit> getOrCreateUnitGraph(SootMethod m) {
  		return delegate.getOrCreateUnitGraph(m);
  	}
  
  	@Override
  	public List<Value> getParameterRefs(SootMethod m) {
  		return delegate.getParameterRefs(m);
  	}
  
  	@Override
  	public boolean isReturnSite(Unit n) {
  		return delegate.isReturnSite(n);
  	}
  	
  	@Override
  	public boolean isStaticFieldRead(SootMethod method, SootField variable) {
  		return isStaticFieldUsed(method, variable, new HashSet<SootMethod>(), true);
  	}
  	
  	public boolean isStaticFieldWrite(SootMethod method, SootField variable) {
  		Set<SootMethod> runList = new HashSet<SootMethod>();
  		return isStaticFieldWrite(method, variable, runList);
  	}
  	
  	public boolean isStaticFieldWrite(SootMethod method, SootField variable, Set<SootMethod> runList) {
  		// Without a body, we cannot say much
  		if (!method.hasActiveBody())
  			return false;
  		
  		// Do not process the same method twice
  		if (!runList.add(method))
  			return false;
  		
  		// Do we already have an entry?
  		Map<SootField, StaticFieldUse> entry = staticFieldUses.get(method);
  		if (entry != null) {
  			StaticFieldUse b = entry.get(variable);
  			if (b != null && b != StaticFieldUse.Unknown) {
  				return b == StaticFieldUse.Write;
  			}
  		}
  		
  		// Scan for references to this variable
  		for (Unit u : method.getActiveBody().getUnits()) {
  			if (u instanceof AssignStmt) {
  				AssignStmt assign = (AssignStmt) u;
  				
  				if (assign.getLeftOp() instanceof StaticFieldRef) {
  					SootField sf = ((StaticFieldRef) assign.getLeftOp()).getField();
  					registerStaticVariableUse(method, sf, StaticFieldUse.Write);
  					return true;
  				}
  			}
  			
  			if (((Stmt) u).containsInvokeExpr())
  				for (Iterator<Edge> edgeIt = Scene.v().getCallGraph().edgesOutOf(u); edgeIt.hasNext(); ) {
  					Edge e = edgeIt.next();
  					if (isStaticFieldWrite(e.getTgt().method(), variable, runList));
  						return true;
  				}
  		}
  		
  		// Variable is not read
  		registerStaticVariableUse(method, variable, StaticFieldUse.Unwrite);
  		return false;
  	}
  	
  	@Override
  	public boolean isStaticFieldUsed(SootMethod method, SootField variable) {
  		return isStaticFieldUsed(method, variable, new HashSet<SootMethod>(), false);
  	}
  	
  	private boolean isStaticFieldUsed(SootMethod method, SootField variable,
  			Set<SootMethod> runList, boolean readOnly) {
  		// Without a body, we cannot say much
  		if (!method.hasActiveBody())
  			return false;
  		
  		// Do not process the same method twice
  		if (!runList.add(method))
  			return false;
  		
  		// Do we already have an entry?
  		Map<SootField, StaticFieldUse> entry = staticFieldUses.get(method);
  		if (entry != null) {
  			StaticFieldUse b = entry.get(variable);
  			if (b != null && b != StaticFieldUse.Unknown && b != StaticFieldUse.Unwrite) {
  				if (readOnly)
  					return b == StaticFieldUse.Read || b == StaticFieldUse.ReadWrite;
  				else
  					return b != StaticFieldUse.Unused;
  			}
  		}
  		
  		// Scan for references to this variable
  		for (Unit u : method.getActiveBody().getUnits()) {
  			if (u instanceof AssignStmt) {
  				AssignStmt assign = (AssignStmt) u;
  				
  				if (assign.getLeftOp() instanceof StaticFieldRef) {
  