package kr.ac.snu.selab.soot.analyzer.code;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import kr.ac.snu.selab.soot.analyzer.AbstractAnalyzer;
import kr.ac.snu.selab.soot.core.AbstractProject;
import kr.ac.snu.selab.soot.util.MyUtil;
import org.apache.log4j.Logger;
import soot.Body;
import soot.Hierarchy;
import soot.SootClass;
import soot.SootField;
import soot.SootMethod;
import soot.Unit;
import soot.UnitBox;
import soot.Value;
import soot.ValueBox;
import soot.jimple.internal.JAssignStmt;
import soot.jimple.internal.JIdentityStmt;
import soot.jimple.internal.JInvokeStmt;
public class CodeAnalyzer extends AbstractAnalyzer {
private static Logger log = Logger.getLogger(CodeAnalyzer.class);
private String codeAnalysisOutputPath;
public CodeAnalyzer(AbstractProject project) {
super(project);
}
private List<Unit> getUnits(SootMethod aMethod) {
List<Unit> unitList = new ArrayList<Unit>();
if (aMethod.hasActiveBody()) {
Body body = aMethod.getActiveBody();
unitList.addAll(body.getUnits());
}
return unitList;
}
private void writeClass(SootClass aClass, PrintWriter writer) {
writer.print("<Class>");
writer.print("<ToString>");
writer.print(MyUtil.removeBracket(aClass.toString()));
writer.print("</ToString>");
writer.print("<FieldList>");
for (SootField aField : aClass.getFields()) {
writer.print("<Field>");
writer.print("<Signature>");
writer.print(MyUtil.removeBracket(aField.getSignature()));
writer.print("</Signature>");
writer.print("<SubSignature>");
writer.print(MyUtil.removeBracket(aField.getSubSignature()));
writer.print("</SubSignature>");
writer.print("<ToString>");
writer.print(MyUtil.removeBracket(aField.toString()));
writer.print("</ToString>");
writer.print("<Type>");
writer.print(MyUtil.removeBracket(aField.getType().toString()));
writer.print("</Type>");
writer.print("<Name>");
writer.print(MyUtil.removeBracket(aField.getName()));
writer.print("</Name>");
writer.print("</Field>");
}
writer.print("</FieldList>");
writer.print("<MethodList>");
for (SootMethod aMethod : aClass.getMethods()) {
writeMethod(aMethod, writer);
}
writer.print("</MethodList>");
writer.print("</Class>");
}
private void writeMethod(SootMethod aMethod, PrintWriter writer) {
writer.print("<Method>");
writer.print("<Name>");
writer.print(MyUtil.removeBracket(aMethod.getName()));
writer.print("</Name>");
writer.print("<Signature>");
writer.print(MyUtil.removeBracket(aMethod.getSignature()));
writer.print("</Signature>");
writer.print("<SubSignature>");
writer.print(MyUtil.removeBracket(aMethod.getSubSignature()));
writer.print("</SubSignature>");
writer.print("<ToString>");
writer.print(MyUtil.removeBracket(aMethod.toString()));
writer.print("</ToString>");
writer.print("<ReturnType>");
writer.print(MyUtil.removeBracket(aMethod.getReturnType().toString()));
writer.print("</ReturnType>");
writer.print("<ParameterList>");
int i = 0;
for (Object aType : aMethod.getParameterTypes()) {
writer.print(String.format("<Parameter%d>", i));
writer.print(MyUtil.removeBracket(aType.toString()));
writer.print(String.format("</Parameter%d>", i));
}
writer.print("</ParameterList>");
writer.print("<UnitList>");
for (Unit aUnit : getUnits(aMethod)) {
writeUnit(aUnit, writer);
}
writer.print("</UnitList>");
writer.print("</Method>");
}
private void writeUnit(Unit aUnit, PrintWriter writer) {
writer.print("<Unit>");
writer.print("<ToString>");
writer.print(MyUtil.removeBracket(aUnit.toString()));
writer.print("</ToString>");
writer.print("<UnitClass>");
writer.print(MyUtil.removeBracket(aUnit.getClass().getName()));
writer.print("</UnitClass>");
for (UnitBox unitBox : aUnit.getBoxesPointingToThis()) {
writer.print("<UnitBoxPointingToThis>");
writer.print(MyUtil.removeBracket(unitBox.toString()));
writer.print("</UnitBoxPointingToThis>");
}
int i = 0;
for (ValueBox valueBox : aUnit.getDefBoxes()) {
writer.print(String.format("<DefBox%d>", i));
writer.print("<ToString>");
writer.print(MyUtil.removeBracket(valueBox.toString()));
writer.print("</ToString>");
writer.print("<Type>");
writer.print(MyUtil.removeBracket(valueBox.getValue().getType()
.toString()));
writer.print("</Type>");
writer.print(String.format("</DefBox%d>", i));
i = i + 1;
}
i = 0;
for (ValueBox valueBox : aUnit.getUseBoxes()) {
writer.print(String.format("<UseBox%d>", i));
writer.print("<ToString>");
writer.print(MyUtil.removeBracket(valueBox.toString()));
writer.print("</ToString>");
writer.print("<Type>");
writer.print(MyUtil.removeBracket(valueBox.getValue().getType()
.toString()));
writer.print("</Type>");
writer.print(String.format("</UseBox%d>", i));
i = i + 1;
}
if (aUnit instanceof JInvokeStmt) {
JInvokeStmt jInvokeStatement = (JInvokeStmt) aUnit;
SootMethod invokeMethod = jInvokeStatement.getInvokeExpr()
.getMethod();
writer.print("<InvokeExpr>");
writer.print(MyUtil.removeBracket(jInvokeStatement.getInvokeExpr()
.toString()));
writer.print("</InvokeExpr>");
}
if (aUnit instanceof JIdentityStmt) {
JIdentityStmt jIdentityStatement = (JIdentityStmt) aUnit;
Value leftOp = jIdentityStatement.getLeftOp();
Value rightOp = jIdentityStatement.getRightOp();
writer.print("<LeftOp>");
writer.print(MyUtil.removeBracket(leftOp.toString()));
writer.print("</LeftOp>");
writer.print("<RightOp>");
writer.print(MyUtil.removeBracket(rightOp.toString()));
writer.print("</RightOp>");
}
if (aUnit instanceof JAssignStmt) {
JAssignStmt jAssignStatement = (JAssignStmt) aUnit;
Value leftOp = jAssignStatement.getLeftOp();
Value rightOp = jAssignStatement.getRightOp();
writer.print("<LeftOp>");
writer.print(MyUtil.removeBracket(leftOp.toString()));
writer.print("</LeftOp>");
writer.print("<RightOp>");
writer.print(MyUtil.removeBracket(rightOp.toString()));
writer.print("</RightOp>");
writer.print("<RightOpType>");
writer.print(MyUtil.removeBracket(rightOp.getType().toString()));
writer.print("</RightOpType>");
if (jAssignStatement.containsInvokeExpr()) {
writer.print("<InvokeExpr>");
writer.print(MyUtil.removeBracket(jAssignStatement.getInvokeExpr().toString()
));
writer.print("</InvokeExpr>");
}
}
writer.print("</Unit>");
}
@Override
protected void preAnalysis() {
this.codeAnalysisOutputPath = MyUtil.getPath(
project.getOutputDirectory(), project.getProjectName()
+ "_code.xml");
}
@Override
protected void analyze(List<SootClass> classList, Hierarchy hierarchy) {
try {
File outputFile = new File(codeAnalysisOutputPath);
File dir = outputFile.getParentFile();
if (!dir.exists()) {
dir.mkdirs();
}
PrintWriter writer = new PrintWriter(new FileWriter(
codeAnalysisOutputPath));
writer.print("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
writer.print("<ClassList>");
for (SootClass aClass : classList) {
writeClass(aClass, writer);
}
writer.print("</ClassList>");
writer.close();
} catch (IOException ex) {
log.error(ex.getMessage(), ex);
}
}
}