package fr.inria.diversify.transformation.query; import fr.inria.diversify.codeFragment.CodeFragment; import fr.inria.diversify.diversification.InputProgram; import fr.inria.diversify.transformation.ast.ASTReplace; import spoon.reflect.code.*; import spoon.reflect.reference.CtVariableReference; import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.stream.Collectors; /** * Created by Simon on 22/08/14. */ public class CheckReturn extends ADRTransformationQuery { protected List<CodeFragment> returns; protected List<CodeFragment> checks; public CheckReturn(InputProgram inputProgram) { super(inputProgram); initReturn(); initCheck(); } protected void initReturn() { returns = new ArrayList<>(); for (CodeFragment cf : getInputProgram().getCodeFragments()) { if (isReturnVariable(cf.getCtCodeFragment())) { returns.add(cf); } } } protected void initCheck() { checks = new ArrayList<>(); for (CodeFragment cf : getAllUniqueCodeFragments()) { try { CtCodeElement stmt = cf.getCtCodeFragment(); if (stmt instanceof CtIf) { CtIf ifStmt = (CtIf) stmt; if (ifStmt.getElseStatement() == null) { CtBlock block = ifStmt.getThenStatement(); if (block.getStatements().size() == 1) { CtStatement thenStmt = block.getStatement(0); if (isReturnVariable(thenStmt)) { checks.add(cf); } } } else { CtBlock thenBlock = ifStmt.getThenStatement(); CtBlock elseBlock = ifStmt.getThenStatement(); if (thenBlock.getStatements().size() == 1 && elseBlock.getStatements().size() == 1) { CtStatement thenStmt = thenBlock.getStatement(0); CtStatement elseStmt = elseBlock.getStatement(0); if ((isReturnVariable(thenStmt) && isThrowStatement(elseStmt)) || (isReturnVariable(elseStmt) && isThrowStatement(thenStmt))) checks.add(cf); } } } } catch (Exception e) { } } } protected boolean isReturnVariable(CtCodeElement stmt) { if (stmt instanceof CtReturn) { CtReturn ret = (CtReturn) stmt; if (ret.getReturnedExpression() instanceof CtVariableReference || ret.getReturnedExpression() instanceof CtVariableAccess) { return true; } } return false; } protected boolean isThrowStatement(CtCodeElement stmt) { return stmt instanceof CtThrow; } protected ASTReplace transformation() throws Exception { ASTReplace tf = new ASTReplace(); CodeFragment transplantationPoint = null; CodeFragment transplant = null; while (transplant == null) { transplantationPoint = findRandomReturnToReplace(true); transplant = findRandomCheck(transplantationPoint, false); } tf.setTransplantationPoint(transplantationPoint); tf.setTransplant(transplant); 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 findRandomReturnToReplace(boolean withCoverage) { Random r = new Random(); int size = returns.size(); CodeFragment stmt = returns.get(r.nextInt(size)); while (withCoverage && getInputProgram().getCoverageReport().codeFragmentCoverage(stmt) == 0) stmt = returns.get(r.nextInt(size)); return stmt; } protected CodeFragment findRandomCheck(CodeFragment cf, boolean varNameMatch) throws IllegalAccessException, InstantiationException { List<CodeFragment> list = checks.stream() .filter(codeFragment -> cf.isReplaceableBy(codeFragment, varNameMatch, subType)) .collect(Collectors.toList()); if (list.isEmpty()) return null; Random r = new Random(); CtCodeElement tmp = (CtCodeElement) copyElem(list.get(r.nextInt(list.size())).getCtCodeFragment()); CodeFragment ret = (CodeFragment) codeFragmentClass.newInstance(); ret.init(tmp); return ret; } public long nbOfTransformation(boolean varNameMatch) { long nb = 0; for (CodeFragment transplant : returns) { List<CodeFragment> list = new ArrayList(); for (CodeFragment check : checks) if (transplant.isReplaceableBy(check, varNameMatch, subType) && transplant.getCtCodeFragment().getParent(CtIf.class) != check) { list.add(check); } nb = nb + list.size(); } return nb; } }