package fr.inria.diversify.transformation.query;
import fr.inria.diversify.codeFragment.CodeFragment;
import fr.inria.diversify.codeFragment.Statement;
import fr.inria.diversify.diversification.InputProgram;
import fr.inria.diversify.transformation.Transformation;
import fr.inria.diversify.transformation.ast.ASTAdd;
import fr.inria.diversify.transformation.ast.ASTDelete;
import fr.inria.diversify.transformation.ast.ASTReplace;
import fr.inria.diversify.transformation.ast.ASTTransformation;
import spoon.reflect.code.CtLocalVariable;
import spoon.reflect.code.CtReturn;
import spoon.reflect.declaration.CtElement;
import spoon.reflect.factory.Factory;
import java.util.*;
import java.util.function.ToDoubleFunction;
import java.util.stream.Collectors;
/**
* A transformation executeQuery over the AST
* <p>
* User: Simon
* Modified: Marcelino
* Date: 7/9/13
* Time: 10:02 AM
*/
public class ADRTransformationQuery extends TransformationQuery {
/**
* Class of the code fragment. Defaults to Statement
*/
protected Class codeFragmentClass = Statement.class;
/**
* Indicates if we do solely simple transformations. Defaults to the simple ones
*/
protected boolean stupid = true;
/**
* Indicates if variable matching used sub type
*/
protected boolean subType = true;
protected ToDoubleFunction<Transformation> evalFunction;
/**
* Short constructor assuming the fragment class to be statement and the transformation to be stupid
*
* @param inputProgram Input program over the queries are going to be made
*/
public ADRTransformationQuery(InputProgram inputProgram) {
//This we assume be defect
super(inputProgram);
codeFragmentClass = Statement.class;
}
/**
* Long constructor assuming nothing
* @param inputProgram Input Input program over the queries are going to be made
* @param fragmentClass Class of the fragments
* @param isStupid Is this a stupid transformation?
*/
public ADRTransformationQuery(InputProgram inputProgram, Class fragmentClass, boolean subType, boolean isStupid) {
super(inputProgram);
codeFragmentClass = fragmentClass;
stupid = isStupid;
this.subType = subType;
}
@Override
public Transformation query() throws QueryException {
if(evalFunction == null) {
return pQuery();
} else {
return query(evalFunction);
}
}
public Transformation pQuery() throws QueryException {
try {
Random r = new Random();
ASTTransformation t = null;
int i = r.nextInt(stupid ? 15 : 5);
switch (i) {
case 0:
case 1:
case 2:
t = replace(subType);
break;
case 3:
t = add(subType);
break;
case 4:
t = delete();
break;
case 5:
case 6:
case 7:
t = replaceRandom();
break;
case 8:
case 9:
case 10:
t = addRandom();
break;
case 11:
t = replaceWittgenstein();
break;
case 12:
t = addWittgenstein();
break;
case 13: {
t = replace(subType);
t.setName("replaceReaction");
break;
}
case 14: {
t = add(subType);
t.setName("addReaction");
break;
}
}
t.setInputProgram(getInputProgram());
return t;
} catch (Exception e) {
throw new QueryException(e);
}
}
protected Transformation query(ToDoubleFunction<Transformation> eval) throws QueryException {
try {
Set<Transformation> set = new HashSet<>();
while (set.size() < 10) {
set.add(pQuery());
}
return set.stream()
.sorted((cf1, cf2) -> Double.compare(eval.applyAsDouble(cf2), eval.applyAsDouble(cf1)))
.findFirst()
.get();
} catch (Exception e) {
throw new QueryException(e);
}
}
/**
*
* @return
* @throws Exception
*/
protected ASTReplace replace(boolean subType) throws Exception {
ASTReplace tf = new ASTReplace();
CodeFragment transplantationPoint = null;
CodeFragment transplant = null;
while (transplant == null) {
transplantationPoint = findRandomFragment(true);
transplant = findRandomFragmentCandidate(transplantationPoint, false, subType);
}
tf.setTransplantationPoint(transplantationPoint);
tf.setTransplant(transplant);
tf.setSubType(subType);
return tf;
}
protected ASTReplace replaceReaction(CodeFragment transplantationPoint, boolean subType) throws Exception {
ASTReplace tf = new ASTReplace();
CodeFragment transplant = findRandomFragmentCandidate(transplantationPoint, false, subType);
if (transplant == null)
throw new Exception("pas de candidat pour " + transplant);
tf.setTransplantationPoint(transplantationPoint);
tf.setTransplant(transplant);
tf.setName("replaceReaction");
tf.setSubType(subType);
return tf;
}
protected ASTReplace replaceWittgenstein() throws Exception {
ASTReplace tf = new ASTReplace();
CodeFragment transplant = null;
CodeFragment transplantationPoint = null;
while (transplantationPoint == null) {
transplant = findRandomFragment(true);
transplantationPoint = findRandomFragmentCandidate(transplant, true, false);
}
tf.setName("replaceWittgenstein");
tf.setTransplantationPoint(transplantationPoint);
tf.setTransplant(transplant);
tf.setSubType(subType);
return tf;
}
protected ASTReplace replaceRandom() throws Exception {
ASTReplace tf = new ASTReplace();
tf.setTransplantationPoint(findRandomFragment(true));
tf.setTransplant(findRandomFragment(false));
tf.setName("replaceRandom");
tf.setSubType(subType);
return tf;
}
protected ASTAdd addRandom() throws Exception {
ASTAdd tf = new ASTAdd();
tf.setTransplantationPoint(findRandomFragment(true));
tf.setTransplant(findRandomFragment(false));
tf.setName("addRandom");
tf.setSubType(subType);
return tf;
}
protected ASTReplace replace(CodeFragment transplantationPoint, boolean varNameMatch, boolean subType) throws Exception {
ASTReplace tf = new ASTReplace();
CodeFragment cfReplacedBy = findRandomFragmentCandidate(transplantationPoint, varNameMatch, subType);
if (cfReplacedBy == null)
throw new Exception("pas de candidat pour " + transplantationPoint);
tf.setTransplantationPoint(transplantationPoint);
tf.setTransplant(cfReplacedBy);
tf.setSubType(subType);
return tf;
}
protected ASTAdd addWittgenstein() throws Exception {
ASTAdd tf = new ASTAdd();
CodeFragment transplantationPoint = null;
CodeFragment transplant = null;
while (transplant == null) {
transplantationPoint = findRandomFragment(true);
transplant = findRandomFragmentCandidate(transplantationPoint, true, false);
}
tf.setTransplantationPoint(transplantationPoint);
tf.setTransplant(transplant);
tf.setName("addWittgenstein");
tf.setSubType(subType);
return tf;
}
protected ASTAdd add(boolean subType) throws Exception {
ASTAdd tf = new ASTAdd();
CodeFragment transplantationPoint = null;
CodeFragment transplant = null;
while (transplant == null) {
transplantationPoint = findRandomFragment(true);
transplant = findRandomFragmentCandidate(transplantationPoint, false, subType);
}
tf.setTransplantationPoint(transplantationPoint);
tf.setTransplant(transplant);
tf.setSubType(subType);
return tf;
}
protected ASTAdd addReaction(CodeFragment transplantationPoint, boolean subType) throws Exception {
ASTAdd tf = new ASTAdd();
CodeFragment transplant = findRandomFragmentCandidate(transplantationPoint, false, subType);
if (transplant == null)
throw new Exception("pas de candidat pour " + transplant);
tf.setTransplantationPoint(transplantationPoint);
tf.setTransplant(transplant);
tf.setName("addReaction");
tf.setSubType(subType);
return tf;
}
protected ASTAdd add(CodeFragment transplantationPoint, boolean varNameMatch, boolean subType) throws Exception {
ASTAdd tf = new ASTAdd();
CodeFragment transplant = findRandomFragmentCandidate(transplantationPoint, varNameMatch, subType);
if (transplant == null)
throw new Exception("pas de candidat pour " + transplantationPoint);
tf.setTransplantationPoint(transplantationPoint);
tf.setTransplant(transplant);
tf.setSubType(subType);
return tf;
}
protected ASTDelete delete() throws Exception {
ASTDelete tf = new ASTDelete();
CodeFragment transplantationPoint = null;
while (transplantationPoint == null) {
transplantationPoint = findRandomFragment(true);
if (transplantationPoint.getCtCodeFragment() instanceof CtReturn
|| transplantationPoint.getCtCodeFragment() instanceof CtLocalVariable)
transplantationPoint = null;
}
tf.setTransplantationPoint(transplantationPoint);
return tf;
}
protected ASTDelete delete(CodeFragment transplantationPoint) throws Exception {
ASTDelete tf = new ASTDelete();
tf.setTransplantationPoint(transplantationPoint);
return tf;
}
/**
* Find code fragments to replace, i.e, transplantation points
*
* @param withCoverage Indicates if the transplantation points must have coverage by the test suite.
* @return
*/
protected CodeFragment findRandomFragment(boolean withCoverage) {
Random r = new Random();
int size = getInputProgram().getCodeFragments().size();
CodeFragment stmt = getInputProgram().getCodeFragments().get(r.nextInt(size));
while (withCoverage && getInputProgram().getCoverageReport().codeFragmentCoverage(stmt) == 0) {
stmt = getInputProgram().getCodeFragments().get(r.nextInt(size));
}
return stmt;
}
/**
* Find a random code fragment candidate to replace
*
*
* @param cf
* @param varNameMatch
* @return
* @throws IllegalAccessException
* @throws InstantiationException
*/
protected CodeFragment findRandomFragmentCandidate(CodeFragment cf,
boolean varNameMatch, boolean subType) throws IllegalAccessException, InstantiationException {
String cfString = cf.equalString();
for(CodeFragment codeFragment : getAllUniqueCodeFragments()) {
if(cf.isReplaceableBy(codeFragment, varNameMatch, subType) && !codeFragment.equalString().equals(cfString)) {
return codeFragment;
}
}
return null;
}
protected CtElement copyElem(CtElement elem) {
Factory factory = elem.getFactory();
CtElement tmp = factory.Core().clone(elem);
tmp.setParent(elem.getParent());
return tmp;
}
protected List<CodeFragment> getAllUniqueCodeFragments() {
List<CodeFragment> list = new ArrayList<>(getInputProgram().getCodeFragments().getUniqueCodeFragmentList());
Collections.shuffle(list);
return list;
}
public Collection<Transformation> isstaTransformation(int nb) throws Exception {
List<Transformation> transformations = new ArrayList<>();
for(int i = 0; i< nb; i++) {
ASTReplace replace = replace(subType);
transformations.add(replace);
try {
ASTReplace replaceW = replace(replace.getTransplantationPoint(), true, subType);
replaceW.setName("replaceWittgenstein");
transformations.add(replaceW);
} catch (Exception e) {}
try {
ASTReplace replaceReaction = replaceReaction(replace.getTransplantationPoint(), subType);
transformations.add(replaceReaction);
} catch (Exception e) {}
try {
ASTReplace replaceRandom = new ASTReplace();
replaceRandom.setTransplantationPoint(replace.getTransplantationPoint());
replaceRandom.setTransplant(findRandomFragment(false));
replaceRandom.setName("replaceRandom");
transformations.add(replaceRandom);
} catch (Exception e) {}
try {
ASTAdd add = add(replace.getTransplantationPoint(), false, subType);
transformations.add(add);
} catch (Exception e) {}
try {
ASTAdd addW = add(replace.getTransplantationPoint(), true, false);
addW.setName("addWittgenstein");
transformations.add(addW);
} catch (Exception e) {}
try {
ASTAdd addReaction = addReaction(replace.getTransplantationPoint(),subType);
transformations.add(addReaction);
} catch (Exception e) {}
try {
ASTAdd addRandom = new ASTAdd();
addRandom.setTransplantationPoint(replace.getTransplantationPoint());
addRandom.setTransplant(findRandomFragment(false));
addRandom.setName("addRandom");
transformations.add(addRandom);
} catch (Exception e) {}
try {
ASTDelete delete = new ASTDelete();
delete.setTransplantationPoint(replace.getTransplantationPoint());
transformations.add(delete);
} catch (Exception e) {}
}
return transformations;
}
public void setEvalFunction(ToDoubleFunction<Transformation> evalFunction) {
this.evalFunction = evalFunction;
}
}