package kr.ac.snu.selab.soot;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import kr.ac.snu.selab.soot.analyzer.AbstractAnalyzer;
import kr.ac.snu.selab.soot.analyzer.AnalysisUtil;
import kr.ac.snu.selab.soot.analyzer.Creator;
import kr.ac.snu.selab.soot.analyzer.LocalInfo;
import kr.ac.snu.selab.soot.analyzer.MethodInfo;
import kr.ac.snu.selab.soot.analyzer.MethodInternalPath;
import kr.ac.snu.selab.soot.analyzer.Pair;
import kr.ac.snu.selab.soot.analyzer.RoleRepository;
import kr.ac.snu.selab.soot.core.AbstractProject;
import kr.ac.snu.selab.soot.core.ProjectManager;
import kr.ac.snu.selab.soot.graph.MetaInfo;
import kr.ac.snu.selab.soot.graph.Path;
import kr.ac.snu.selab.soot.graph.refgraph.LocalInfoNode;
import kr.ac.snu.selab.soot.graph.refgraph.ReferenceFlowGraph;
import kr.ac.snu.selab.soot.util.XMLWriter;
import org.apache.log4j.Logger;
import org.junit.Before;
import org.junit.Test;
import soot.Hierarchy;
import soot.Local;
import soot.PackManager;
import soot.Scene;
import soot.SootClass;
import soot.SootMethod;
import soot.Transform;
import soot.Unit;
import soot.jimple.toolkits.callgraph.CallGraph;
public class ReferenceFlowTest {
private static Logger logger = Logger.getLogger(ReferenceFlowTest.class);
private static final String PROJECTS_NAME = "StatePatternExample";
private static final String PROJECTS_FILE_NAME = "projects.xml";
static AnalysisUtil au;
static Map<String, SootClass> classMap;
static Hierarchy hierarchy;
static CallGraph cg;
static List<Unit> units;
static Map<String, Local> locals;
static Map<String, LocalInfo> allLocalInfos;
// In
static Map<String, LocalInfo> localsOfMethodParam;
static Map<String, LocalInfo> localsLeftOfField;
static Map<String, LocalInfo> localsLeftOfInvoke;
// Out
static Map<String, LocalInfo> localsOfInvokeParam;
static Map<String, LocalInfo> localsRightOfField;
static Map<String, LocalInfo> localOfReturn;
// Creation
static Map<String, LocalInfo> creations;
static int numOfFieldInRightStmt;
static int numOfFieldInLeftStmt;
static int numOfInvokeInRightStmt;
static SootClass a;
static SootClass b;
static SootClass c;
static SootClass d;
static SootClass i;
static SootClass subD;
static SootClass subI;
static Map<SootClass, List<Creator>> creatorsOfI;
static Map<SootClass, List<Creator>> creatorsOfA;
static Map<SootClass, List<Creator>> creatorsOfB;
static Map<SootClass, List<Creator>> creatorsOfC;
static MethodInternalPath mip_methodParamToReturn1;
static MethodInternalPath mip_methodParamToReturn2;
static MethodInternalPath mip_methodParamToReturn3;
static List<Pair<LocalInfo, LocalInfo>> internalEdges;
static MethodInfo methodInfo;
static Map<SootMethod, MethodInfo> methodInfoMap;
static SootMethod inout;
static ReferenceFlowGraph referenceFlowGraph;
static Map<LocalInfoNode, List<Path<LocalInfoNode>>> referenceFlows;
static Set<Path<MetaInfo>> abstractReferenceFlows;
// for paramter number consistency test
static Map<String, LocalInfo> localsOfMethodParam_methodForAnalyzeMethodParamToReturnTest;
static Map<String, LocalInfo> localsOfMethodParam_methodForAnalyzeMethodParamToReturnTest2;
static Map<String, LocalInfo> localsOfInvokeParam_main;
// for interMethodConnectionTest
static SootMethod main;
static boolean touch = false;
@Before
public void prepare() throws Throwable {
if (touch)
return;
touch = true;
au = new AnalysisUtil();
ProjectManager projects = ProjectManager.getInstance();
FileInputStream fis = null;
try {
fis = new FileInputStream(findProjectsFile());
projects.loadProjects(fis);
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
}
}
}
AbstractProject project = projects.getProject(PROJECTS_NAME);
assertNotNull("Cannot find project!!!", project);
AbstractAnalyzer analyzer = new TestRunner(project);
PackManager.v().getPack("jtp")
.add(new Transform("jtp.Experiment", analyzer));
final String[] arguments = { "-cp", project.getClassPath(), "-f", "J",
"-w", "-p", "cg.spark", "verbose:true,on-fly-cg:true", "-d",
project.getJimpleDirectory(), "--process-dir",
project.getSourceDirectory() };
soot.Main.main(arguments);
}
@Test
public void abstractReferenceFlowsTest() {
// FIXME: Fix these codes!!!
File outputDir = new File("/Users/chanwoo/Downloads");
if (!outputDir.exists() || !outputDir.isDirectory()) {
outputDir = new File("/Users/dolicoli/Downloads");
}
File output = new File(outputDir, "paths.xml");
XMLWriter writer = null;
try {
writer = new XMLWriter(new FileWriter(output));
} catch (IOException e) {
logger.error(e);
}
if (writer == null) {
fail("Can not open output file.");
return;
}
try {
writer.startElement("abstractReferenceFlows");
for (Path<MetaInfo> path : abstractReferenceFlows) {
path.writeXML(writer);
}
writer.endElement();
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
writer.close();
}
private class TestRunner extends AbstractAnalyzer {
public TestRunner(AbstractProject project) {
super(project);
}
@Override
protected void analyze(List<SootClass> classList, Hierarchy aHierarchy) {
cg = Scene.v().getCallGraph();
assertNotNull("Target classes not found", classList);
hierarchy = aHierarchy;
classMap = new HashMap<String, SootClass>();
for (SootClass aClass : classList) {
classMap.put(aClass.toString(), aClass);
}
i = classMap.get("State");
// preparation for abstractReferenceFlowsTest
Map<String, MetaInfo> metaInfoMap = au.metaInfoMap(classList);
RoleRepository roles = new RoleRepository();
abstractReferenceFlows = au.abstractReferenceFlows(i, classMap, hierarchy, cg, metaInfoMap, roles);
}
}
private static File findProjectsFile() {
URL url = ClassLoader.getSystemResource(PROJECTS_FILE_NAME);
if (url == null) {
return null;
}
File file = new File(url.getFile());
if (file == null || !file.exists() || !file.isFile()) {
return null;
}
return file;
}
}