package kr.ac.snu.selab.soot.analyzer.decNcor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import kr.ac.snu.selab.soot.analyzer.Analysis;
import kr.ac.snu.selab.soot.analyzer.AnalysisResult;
import kr.ac.snu.selab.soot.analyzer.MethodAnalysisResult;
import kr.ac.snu.selab.soot.analyzer.MyField;
import kr.ac.snu.selab.soot.analyzer.MyMethod;
import kr.ac.snu.selab.soot.graph.Graph;
import kr.ac.snu.selab.soot.graph.GraphPathCollector;
import kr.ac.snu.selab.soot.graph.MyNode;
import kr.ac.snu.selab.soot.graph.Path;
import kr.ac.snu.selab.soot.graph.collectors.AllPathCollector;
import kr.ac.snu.selab.soot.util.MyUtil;
import kr.ac.snu.selab.soot.util.XMLWriter;
import org.apache.log4j.Logger;
import soot.Hierarchy;
import soot.SootClass;
import soot.SootField;
import soot.SootMethod;
import soot.Unit;
import soot.jimple.internal.JAssignStmt;
import soot.jimple.internal.JInvokeStmt;
public class DecNCorAnalysis extends Analysis {
public DecNCorAnalysis(List<SootClass> aClassList, Hierarchy aHierarchy,
boolean useSimpleCallGraph) {
super(aClassList, aHierarchy, useSimpleCallGraph);
}
private static Logger logger = Logger.getLogger(DecNCorAnalysis.class);
protected boolean isAbstractTypeClass(SootClass aClass) {
boolean result = false;
if (aClass.isInterface() || aClass.isAbstract()) {
result = true;
} else {
if (!hierarchy.getDirectSubclassesOf(aClass).isEmpty()) {
result = true;
}
}
return result;
}
public AnalysisResult analyzeOverType(SootClass aType) {
AnalysisResult anAnalysisResult = new DecNCorAnalysisResult();
List<MethodAnalysisResult> methodAnalysisResultList = new ArrayList<MethodAnalysisResult>();
HashMap<String, MyNode> nodeMap = new HashMap<String, MyNode>();
for (SootClass aClass : classList) {
for (SootField aField : aClass.getFields()) {
// We only consider fields of the abstract type.
if (aField.getType().toString().equals(aType.toString())) {
nodeMap.put(aField.toString(), new MyField(aField));
}
}
for (SootMethod aMethod : aClass.getMethods()) {
nodeMap.put(aMethod.toString(), new MyMethod(aMethod));
}
}
anAnalysisResult.setAbstractType(aType);
for (SootClass aClass : classList) {
for (SootMethod aMethod : aClass.getMethods()) {
methodAnalysisResultList.add(analyzeMethodOverType(aMethod,
aType, nodeMap));
}
}
for (MethodAnalysisResult aResult : methodAnalysisResultList) {
MyNode node = aResult.getSelf();
if (node.isCaller()) {
anAnalysisResult.addCaller(node);
}
if (node.isCreator()) {
anAnalysisResult.addCreator(node);
}
}
Graph<MyNode> referenceFlowGraph = getGraphFromMethodAnalysisResultList(methodAnalysisResultList);
for (MyNode callerNode : anAnalysisResult.getCallers()) {
GraphPathCollector<MyNode> pathCollector = new AllPathCollector<MyNode>(
callerNode, referenceFlowGraph);
List<Path<MyNode>> pathList = pathCollector.run();
List<Path<MyNode>> pathIncludeStoreList = new ArrayList<Path<MyNode>>();
for (Path<MyNode> aPath : pathList) {
boolean doesPathIncludeStore = false;
for (MyNode aNode : aPath.getNodeList()) {
if (aNode.isStore()) {
doesPathIncludeStore = true;
break;
}
}
if (doesPathIncludeStore) {
pathIncludeStoreList.add(aPath);
}
}
if (!pathIncludeStoreList.isEmpty()) {
if (pathIncludeStoreList.size() > 10) {
anAnalysisResult.putReferenceFlowPath(callerNode.key(),
pathIncludeStoreList.subList(0, 9));
} else {
anAnalysisResult.putReferenceFlowPath(callerNode.key(),
pathIncludeStoreList);
}
}
}
// List<MyNode> creatorList = new ArrayList<MyNode>();
// // for (MyNode aNode : aPath.getNodeList()) {
// // if (aNode.isCreator()) {
// // creatorList.add(aNode);
// // }
// // }
// for (MyNode aNode : anAnalysisResult.getCreators()) {
// creatorList.add(aNode);
// }
// check whether the caller's call is recursive
for (MyNode callerNode : anAnalysisResult.getCallers()) {
SootMethod callerMethod = (SootMethod) (callerNode.getElement());
SootClass callerClass = callerMethod.getDeclaringClass();
for (Unit aUnit : ((MyMethod) callerNode).getCallStatementList()) {
SootMethod calledMethod = null;
if (aUnit instanceof JInvokeStmt) {
calledMethod = ((JInvokeStmt) aUnit).getInvokeExpr()
.getMethod();
} else if (aUnit instanceof JAssignStmt) {
calledMethod = ((JAssignStmt) aUnit).getInvokeExpr()
.getMethod();
}
if (callerMethod.getName().equals(calledMethod.getName())) {
// if the result has recursive calls
// check whether the store's type is superclass of the
// store's class
if (!anAnalysisResult.containsReferenceFlowPath(callerNode
.key()))
continue;
for (Path<MyNode> aPath : anAnalysisResult
.getReferenceFlowPaths(callerNode.key())) {
for (MyNode aNode : aPath.getNodeList()) {
if (aNode.isStore()) {
SootField storeField = (SootField) (((MyField) aNode)
.getElement());
SootClass storeClass = storeField
.getDeclaringClass();
SootClass storeType = classMap.get(storeField
.getType().toString());
if (storeClass.equals(callerClass)) {
if (isClassOfDirectSubTypeExcluding(
storeClass, storeType)) {
if (getNumberOfDirectSubClasses(storeType) >= 2) {
if (getNumberOfDirectSubClasses(storeClass) >= 2) {
// check if any concrete
// decorator has
// been created
// boolean
// anyCreatedClassOfStoreClass =
// false;
//
// for (MyNode creatorNode :
// creatorList) {
// List<Unit>
// createStatementList =
// ((MyMethod) creatorNode)
// .getCreateStatementList();
// if
// (anyCreatedClassSubTypeExcluding(
// createStatementList,
// storeClass)) {
// anyCreatedClassOfStoreClass =
// true;
// break;
// }
// }
// if
// (anyCreatedClassOfStoreClass)
// {
((DecNCorAnalysisResult) anAnalysisResult)
.setIsDecorator(true);
((DecNCorAnalysisResult) anAnalysisResult)
.setStoreClassName(storeClass
.toString());
// }
}
}
} else if (storeClass.equals(storeType)) {
((DecNCorAnalysisResult) anAnalysisResult)
.setIsCor(true);
((DecNCorAnalysisResult) anAnalysisResult)
.setStoreClassName(storeClass
.toString());
}
}
}
}
}
}
}
}
return anAnalysisResult;
}
private int getNumberOfDirectSubClasses(SootClass aClass) {
if (aClass.isInterface()) {
return hierarchy.getDirectImplementersOf(aClass).size();
} else {
return hierarchy.getDirectSubclassesOf(aClass).size();
}
}
@SuppressWarnings("unchecked")
private boolean isClassOfDirectSubTypeExcluding(SootClass aClass,
SootClass aType) {
boolean result = false;
if (aType.isInterface() && !(aClass.isInterface())) {
List<SootClass> directImplementerList = hierarchy
.getDirectImplementersOf(aType);
result = directImplementerList.contains(aClass);
} else if (aType.isInterface() && aClass.isInterface()) {
if (hierarchy.isInterfaceDirectSubinterfaceOf(aClass, aType)) {
result = true;
}
} else if (!(aType.isInterface()) && !(aClass.isInterface())) {
List<SootClass> directSubclassList = hierarchy
.getDirectSubclassesOf(aType);
result = directSubclassList.contains(aClass);
}
return result;
}
private boolean anyCreatedClassSubTypeExcluding(
List<Unit> createStatementList, SootClass aType) {
boolean result = false;
for (Unit aUnit : createStatementList) {
if (aUnit instanceof JAssignStmt) {
// remove "new " from "new ClassName"
String className = ((JAssignStmt) aUnit).getRightOp()
.toString().substring(4);
SootClass createdClass = classMap.get(className);
if (createdClass != null) {
if (isClassOfSubTypeExcluding(createdClass, aType)) {
result = true;
break;
}
}
}
}
return result;
}
public void writeAnalysisResultOverAllAbstractTypes(String outputDirectory) {
List<SootClass> abstractTypeList = getAbstractTypeClassList();
// String graphXML = "<GraphList>";
for (SootClass aType : abstractTypeList) {
DecNCorAnalysisResult anAnalysisResult = null;
anAnalysisResult = (DecNCorAnalysisResult) (analyzeOverType(aType));
if (anAnalysisResult == null)
continue;
String patternName = null;
if (((DecNCorAnalysisResult) anAnalysisResult).isCor()) {
patternName = "CoR";
} else if (((DecNCorAnalysisResult) anAnalysisResult).isDecorator()) {
patternName = "Dec";
}
if (patternName == null)
continue;
logger.debug("Writing output....");
String fileName = "DecNCorAnalysis_"
+ anAnalysisResult.getAbstractTypeName();
String outputPath = MyUtil.getPath(
outputDirectory,
fileName
+ "_"
+ patternName
+ "_storeClass_"
+ ((DecNCorAnalysisResult) anAnalysisResult)
.storeClassName() + ".xml");
XMLWriter writer = new XMLWriter(outputPath);
anAnalysisResult.writeXML(writer);
writer.close();
logger.debug("Writing output finished....");
}
// graphXML = graphXML + "</GraphList>";
// MyUtil.stringToFile(graphXML,
// "/Users/chanwoo/Documents/workspace/StatePatternExample2/output/StatePatternExample2_ReferenceFlowGraph.xml");
}
}