package fr.inria.diversify.processor.main;
import fr.inria.diversify.diversification.InputProgram;
import fr.inria.diversify.processor.ProcessorUtil;
import spoon.reflect.code.*;
import spoon.reflect.declaration.CtExecutable;
import spoon.reflect.factory.Factory;
import spoon.reflect.visitor.Query;
import spoon.reflect.visitor.filter.TypeFilter;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* User: Simon
* Date: 09/04/15
*/
public class BranchCoverageProcessor extends AbstractLoggingInstrumenter<CtExecutable> {
List<String> methodsId;
Map<Integer, Integer> blockIds;
boolean addBodyBranch;
public BranchCoverageProcessor(InputProgram inputProgram, String outputDir, boolean addBodyBranch) throws IOException {
super(inputProgram);
File file = new File(outputDir + "/log/");
if(!file.exists()) {
file.mkdirs();
}
methodsId = new ArrayList<>();
blockIds = new HashMap<>();
this.addBodyBranch = addBodyBranch;
}
@Override
public boolean isToBeProcessed(CtExecutable method) {
return method.getBody() != null;
}
@Override
public void process(CtExecutable method) {
int methodId = methodId(method);
String info = methodId + ";" + method.getReference().getDeclaringType().getQualifiedName() + "_" + method.getSignature().replace(" ", "_");
if(addBodyBranch) {
addBranchLogger(tryFinallyBody(method).getBody(),"b");
info += ";b";
}
for(Object object : Query.getElements(tryFinallyBody(method), new TypeFilter(CtIf.class))) {
CtIf ctIf = (CtIf) object;
int branchId = idBranch(methodId);
CtStatement stmt = ctIf.getThenStatement();
if (!(stmt instanceof CtBlock)) {
CtBlock block = getFactory().Core().createBlock();
block.setParent(stmt.getParent());
block.addStatement(stmt);
ctIf.setThenStatement(block);
}
addBranchLogger(ctIf.getThenStatement(),"t" + branchId);
info += ";t" + branchId;
if (ctIf.getElseStatement() == null) {
CtBlock block = getFactory().Core().createBlock();
block.setParent(stmt.getParent());
ctIf.setElseStatement(block);
} else {
stmt = ctIf.getElseStatement();
if (!(stmt instanceof CtBlock)) {
CtBlock block = getFactory().Core().createBlock();
block.setParent(stmt.getParent());
block.addStatement(stmt);
ctIf.setElseStatement(block);
}
}
addBranchLogger(ctIf.getElseStatement(), "e" + branchId);
info += ";e" + branchId;
}
for(Object object : Query.getElements(tryFinallyBody(method), new TypeFilter(CtCase.class))) {
CtCase ctCase = (CtCase) object;
int branchId = idBranch(methodId);
addBranchLogger(ctCase, "s" + branchId);
info += ";s" + branchId;
}
for(Object object : Query.getElements(tryFinallyBody(method), new TypeFilter(CtLoop.class))) {
CtLoop ctLoop = (CtLoop) object;
CtStatement stmt = ctLoop.getBody();
if (!(stmt instanceof CtBlock)) {
CtBlock block = getFactory().Core().createBlock();
if (stmt != null) {
block.setParent(stmt.getParent());
block.addStatement(stmt);
} else {
block.setParent(ctLoop);
}
ctLoop.setBody(block);
}
int branchId = idBranch(methodId);
addBranchLogger((CtBlock) ctLoop.getBody(), "l" + branchId);
info += ";l" + branchId;
}
for(Object object : Query.getElements(tryFinallyBody(method), new TypeFilter(CtCatch.class))) {
CtCatch ctCatch = (CtCatch) object;
CtStatement stmt = ctCatch.getBody();
if (!(stmt instanceof CtBlock)) {
CtBlock block = getFactory().Core().createBlock();
block.setParent(stmt.getParent());
block.addStatement(stmt);
ctCatch.setBody(block);
}
int branchId = idBranch(methodId);
addBranchLogger((CtBlock)ctCatch.getBody(), "c" +branchId );
info += ";c" + branchId;
}
addInOut(method, methodId);
ProcessorUtil.addInfo(info);
}
protected void addBranchLogger(CtStatementList stmts, String idBranch) {
String snippet = getLogger() + ".branch(Thread.currentThread(),\"" + idBranch + "\")";
CtCodeSnippetStatement beginStmt = getFactory().Core().createCodeSnippetStatement();
beginStmt.setValue(snippet);
if(stmts.getStatements().isEmpty()) {
stmts.addStatement(beginStmt);
} else {
stmts.getStatements().add(0,beginStmt);
}
}
protected void addBranchLogger(CtBlock block, String idBranch) {
String snippet = getLogger() + ".branch(Thread.currentThread(),\"" + idBranch + "\")";
CtCodeSnippetStatement beginStmt = getFactory().Core().createCodeSnippetStatement();
beginStmt.setValue(snippet);
block.insertBegin(beginStmt);
}
protected void addInOut(CtExecutable method, int id) {
CtTry ctTry = tryFinallyBody(method);
Factory factory = method.getFactory();
String snippet = getLogger() + ".methodIn(Thread.currentThread(),\"" + id + "\")";
CtCodeSnippetStatement beginStmt = factory.Core().createCodeSnippetStatement();
beginStmt.setValue(snippet);
ctTry.getBody().insertBegin(beginStmt);
CtCodeSnippetStatement stmt = factory.Core().createCodeSnippetStatement();
stmt.setValue(getLogger() + ".methodOut(Thread.currentThread(),\"" + id + "\")");
ctTry.getFinalizer().addStatement(stmt);
}
protected int idBranch(int methodId) {
if(!blockIds.containsKey(methodId)) {
blockIds.put(methodId, 0);
}
blockIds.put(methodId, blockIds.get(methodId) + 1);
return blockIds.get(methodId);
}
}