package fr.inria.diversify.transformation;
import fr.inria.diversify.codeFragment.CodeFragment;
import fr.inria.diversify.diversification.InputProgram;
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 fr.inria.diversify.transformation.bytecode.BytecodeAdd;
import fr.inria.diversify.transformation.bytecode.BytecodeDelete;
import fr.inria.diversify.transformation.bytecode.BytecodeReplace;
import fr.inria.diversify.transformation.bytecode.BytecodeTransformation;
import fr.inria.diversify.transformation.cvl.*;
import fr.inria.diversify.transformation.mutation.*;
import fr.inria.diversify.transformation.other.ShuffleStmtTransformation;
import fr.inria.diversify.util.Log;
import javassist.CtMethod;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import spoon.reflect.code.CtBinaryOperator;
import spoon.reflect.code.CtBlock;
import spoon.reflect.code.CtLocalVariable;
import spoon.reflect.code.CtReturn;
import spoon.reflect.declaration.CtClass;
import spoon.reflect.declaration.CtElement;
import spoon.reflect.declaration.CtPackage;
import spoon.reflect.declaration.CtType;
import spoon.reflect.reference.CtTypeReference;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.util.*;
/**
* The TransformationJSONParser is a great tool to load Transformations from a JSON file and link them to the existing
* input program.
* <p/>
* This JSON - Transformation parser is a refactoring of the TransformationParser. It has a slightly improved exception
* management
* <p/>
* Created by Simmon
* Modified by Marcelino
*/
@Deprecated
public class TransformationJsonParser {
private Properties filterProperties;
/**
* Number of json tuples that we where unable to parse
*/
private int countError = 0;
/**
* Transformations that we where able to parse
*/
Collection<Transformation> transformations;
/**
* Input program to link the pase to
*/
InputProgram inputProgram;
private HashMap<Integer, String> failureDictionary;
private int parsingTransfIndex;
private ActionListener listener;
private Collection<String> errors;
public TransformationJsonParser(boolean toSet, InputProgram inputProgram) {
this.inputProgram = inputProgram;
if (toSet)
transformations = new HashSet<>();
else
transformations = new ArrayList<>();
}
public Collection<Transformation> parseDir(String dir) throws TransformationParserException {
File file = new File(dir);
int countFile = 0;
Log.debug("transformation directory: {}", file.getAbsolutePath());
for (File f : file.listFiles())
if (f.getName().endsWith(".json")) {
countFile++;
Log.debug("Current number of transformation {}", transformations.size());
Log.debug("parse tranformation file: " + f.getName());
transformations.addAll(parseFile(f));
}
Log.debug("number of transformation file: {}", countFile);
Log.debug("number of transformation : {}", transformations.size());
Log.debug("number of parse error : {}", countError);
return transformations;
}
public Transformation parseUniqueTransformation(File file) throws TransformationParserException {
try {
BufferedReader br = new BufferedReader(new FileReader(file));
StringBuilder sb = new StringBuilder();
String line = br.readLine();
while (line != null) {
sb.append(line);
line = br.readLine();
}
if (sb.length() == 0)
return null;
JSONObject jsonObject = new JSONObject(sb.toString());
return parseTransformation(jsonObject);
} catch (IOException | JSONException e) {
throw new TransformationParserException(e);
}
}
/**
* Sets the load progress listener
*/
public void setListener(ActionListener listener) {
this.listener = listener;
}
public List<Transformation> parseArray(JSONArray array) throws JSONException {
ArrayList<Transformation> list = new ArrayList<Transformation>();
int stepSize = array.length() / 10;
int step = stepSize;
int length = array.length();
for (int i = 0; i < length; i++) {
try {
parsingTransfIndex = i;
JSONObject jsonObject = array.getJSONObject(i);
if (filter(jsonObject)) {
Transformation t = parseTransformation(jsonObject);
list.add(t);
}
step--;
if (step <= 0 && stepSize > 0 && listener != null) {
step = stepSize;
listener.actionPerformed(new ActionEvent(i / length, 0, ""));
}
} catch (TransformationParserException e) {
String err = "Unable to parse transformation " + i;
Log.warn(err);
getErrors().add(err);
e.printStackTrace();
}
}
parseFailureDictionay(array);
return list;
}
/**
* Parses a list of files
*
* @param files Files to parse
* @return A list of transformations
* @throws TransformationParserException
*/
public List<Transformation> parseFileList(List<String> files) throws TransformationParserException {
ArrayList<Transformation> result = new ArrayList<>();
for (String s : files) {
result.addAll(parseFile(new File(s)));
}
return result;
}
public List<Transformation> parseFile(File file) throws TransformationParserException {
try {
BufferedReader br = null;
StringBuilder sb = null;
try {
br = new BufferedReader(new FileReader(file));
sb = new StringBuilder();
String line = br.readLine();
while (line != null) {
sb.append(line);
line = br.readLine();
}
if (sb.length() == 0)
return new ArrayList<>();
} finally {
if (br != null) br.close();
}
JSONArray array = null;
String fileStr = sb.toString();
try {
array = new JSONArray(fileStr);
} catch (JSONException e) {
if (e.toString().contains("A JSONArray text must start with '['")) {
try {
array = new JSONObject(fileStr).getJSONArray("transformations");
} catch (JSONException ex) {
//Try contingency plan with malformed JSON files
fileStr.replace("\n", ",");
fileStr = "[" + fileStr + "]";
array = new JSONArray(fileStr);
}
}
}
List<Transformation> list = parseArray(array);
return list;
} catch (IOException | JSONException e) {
throw new TransformationParserException(e);
}
}
/**
* Filter by the given properties to avoid reading every transformation, wich can be potentially slow
*
* @param o Object to be filtered
* @return
*/
protected boolean filter(JSONObject o) {
try {
if (o.has("failureDictionary")) return false;
if (getFilterProperties() == null) return true;
for (Object k : getFilterProperties().keySet()) {
String p = (String) k;
if (!o.has(p) || !(getFilterProperties().getProperty(p).contains(o.get(p).toString()))) {
return false;
}
}
return true;
} catch (JSONException e) {
return false;
}
}
protected JSONObject getObject(JSONArray array, int index) {
try {
return array.getJSONObject(index);
} catch (JSONException e) {
return null;
}
}
public Transformation parseTransformation(JSONObject jsonObject) throws TransformationParserException {
try {
String type = jsonObject.getString("type");
Transformation trans = null;
if (type.equals("multi"))
trans = parseMultiTransformation(jsonObject);
if (type.equals("mutation"))
trans = parseMutation(jsonObject);
if (type.equals("adrStmt"))
trans = parseStmt(jsonObject);
if (type.equals("adrBytecode"))
trans = parseBytecode(jsonObject);
if (type.equals("cvl"))
trans = parseCvl(jsonObject);
if (type.equals("foo"))
trans = parseOther(jsonObject);
if (trans == null)
throw new TransformationParserException("Unknown transformation type for " + jsonObject.toString());
if (jsonObject.has("tindex")) {
// Integer i = jsonObject.getInt("tindex");
// trans.setIndex(UUID.fromString(i.toString()));
}
trans.setFailures(getFailures(jsonObject));
trans.setStatus(jsonObject.getInt("status"));
trans.setInputProgram(inputProgram);
if (jsonObject.has("parent"))
trans.setParent(parseTransformation(jsonObject.getJSONObject("parent")));
return trans;
} catch (JSONException e) {
throw new TransformationParserException(e);
}
}
private Transformation parseMultiTransformation(JSONObject jsonObject) throws JSONException, TransformationParserException {
MultiTransformation trans = new MultiTransformation(true);
JSONArray array = jsonObject.getJSONArray("transformations");
for(int i = 0; i < array.length(); i++) {
trans.add(parseTransformation(array.getJSONObject(i)));
}
return trans;
}
protected Transformation parseOther(JSONObject jsonObject) throws JSONException, TransformationParserException {
ShuffleStmtTransformation shuffle = new ShuffleStmtTransformation();
shuffle.setTransformationPoint(getBlock(jsonObject.getString("transformationPoint")));
int[] array = parseIntArray(jsonObject.getString("newStmtOrder"));
boolean ordre = true;
for (int i = 0; i < array.length; i++) {
if (array[i] != i) {
ordre = false;
break;
}
}
if (ordre)
throw new TransformationParserException("");
shuffle.buildNewOrder(array);
return shuffle;
}
protected int[] parseIntArray(String newStmtOrder) throws JSONException {
String[] tmp = newStmtOrder.substring(1, newStmtOrder.length() - 1).split(", ");
int[] array = new int[tmp.length];
for (int i = 0; i < tmp.length; i++)
array[i] = Integer.parseInt(tmp[i]);
return array;
}
protected CtBlock getBlock(String positionObject) throws TransformationParserException {
CtBlock o = null;
for (CtElement object : inputProgram.getAllElement(CtBlock.class)) {
String position = object.getParent(CtPackage.class).getQualifiedName()
+ "." + object.getPosition().getCompilationUnit().getMainType().getSimpleName() + ":" + object.getPosition().getLine();
if (position.equals(positionObject)) {
o = (CtBlock) object;
break;
}
}
if (o == null) {
throw new TransformationParserException("Cannot find block at position: " + positionObject);
}
return o;
}
protected Transformation parseCvl(JSONObject jsonObject) throws JSONException {
String name = jsonObject.getString("name");
CVLTransformation trans = null;
if (name.equals("linkExistence"))
trans = parseLinkExistence(jsonObject);
if (name.equals("linkSubstitution"))
trans = parseLinkSubstitution(jsonObject);
if (name.equals("objectExistence"))
trans = parseObjectExistence(jsonObject);
if (name.equals("objectSubstitution"))
trans = parseObjectSubstitution(jsonObject);
trans.setTransformationPoint(getObject(jsonObject.getString("transformationPoint"), jsonObject.getString("nodeType")));
return trans;
}
protected CtElement getObject(String positionObject, String objectType)
throws JSONException {
CtElement o = null;
for (CtElement object : inputProgram.getAllElement(CtElement.class)) {
String position = object.getParent(CtPackage.class).getQualifiedName()
+ "." + object.getPosition().getCompilationUnit().getMainType().getSimpleName() + ":" + object.getPosition().getLine();
if (position.equals(positionObject) && object.getClass().getSimpleName().equals(objectType)) {
o = object;
break;
}
}
if (o == null) {
throw new JSONException("");
}
return o;
}
protected CVLTransformation parseObjectExistence(JSONObject jsonObject) {
ObjectExistence oe = new ObjectExistence();
return oe;
}
protected CVLTransformation parseObjectSubstitution(JSONObject jsonObject) throws JSONException {
ObjectSubstitution os = new ObjectSubstitution();
os.setTransplant(getObject(jsonObject.getString("transplant"), jsonObject.getString("nodeType")));
return os;
}
protected CVLTransformation parseLinkSubstitution(JSONObject jsonObject) throws JSONException {
LinkSubstitution ls = new LinkSubstitution();
String nodeType = jsonObject.getString("nodeType");
if (nodeType.equals("CtClassImpl")) {
String clName = jsonObject.getString("classOrInterfaceExistence");
CtClass cl = (CtClass) getObject(jsonObject.getString("transformationPoint"), jsonObject.getString("nodeType"));
List<CtTypeReference> set = new ArrayList<>();
if (cl.getSuperclass() != null)
set.add(cl.getSuperclass());
set.addAll(cl.getSuperInterfaces());
for (CtTypeReference ref : set) {
if (clName.equals(ref.getPackage() + "." + ref.getSimpleName()))
ls.setClassOrInterfaceSubstitution(ref);
break;
}
}
ls.setTransplant(getObject(jsonObject.getString("transplant"), nodeType));
return ls;
}
protected CVLTransformation parseLinkExistence(JSONObject jsonObject) throws JSONException {
LinkExistence le = new LinkExistence();
String nodeType = jsonObject.getString("nodeType");
if (nodeType.equals("CtClassImpl")) {
String clName = jsonObject.getString("classOrInterfaceExistence");
CtClass cl = (CtClass) getObject(jsonObject.getString("transformationPoint"), jsonObject.getString("nodeType"));
List<CtTypeReference> set = new ArrayList<>();
if (cl.getSuperclass() != null)
set.add(cl.getSuperclass());
set.addAll(cl.getSuperInterfaces());
for (CtTypeReference ref : set) {
if (clName.equals(ref.getPackage() + "." + ref.getSimpleName()))
le.setClassOrInterfaceExistance(ref);
break;
}
}
return le;
}
protected Transformation parseMutation(JSONObject jsonObject) throws TransformationParserException {
Transformation trans;
try {
String name = jsonObject.getString("name");
if (name.equals("inlineConstant"))
trans = parseInlineConstantMutation(jsonObject);
else if (name.equals("returnValue"))
trans = parseReturnValueMutation(jsonObject);
else
trans = parseBinaryOperatorMutation(jsonObject);
} catch (JSONException e) {
throw new TransformationParserException("Cannot parse mutation", e);
}
return trans;
}
protected Transformation parseStmt(JSONObject jsonObject) throws TransformationParserException {
ASTTransformation trans = null;
try {
String name = jsonObject.getString("name");
if (name.startsWith("replace"))
trans = parseASTReplace(jsonObject);
if (name.startsWith("add"))
trans = parseASTAdd(jsonObject);
if (name.equals("delete"))
trans = parseASTDelete(jsonObject);
if ( jsonObject.has("tindex") ) {
// Integer i = jsonObject.getInt("tindex");
// trans.setIndex(UUID.fromString(i.toString()));
}
trans.setName(jsonObject.getString("name"));
trans.setTransplantationPoint(findCodeFragment(jsonObject.getJSONObject("transplantationPoint")));
} catch (JSONException e) {
throw new TransformationParserException(e);
}
return trans;
}
protected BytecodeTransformation parseBytecode(JSONObject jsonObject) throws TransformationParserException {
String name;
BytecodeTransformation trans = null;
try {
name = jsonObject.getString("name");
if (name.equals("replace"))
trans = parseBytecodeReplace(jsonObject);
if (name.equals("add"))
trans = parseBytecodeAdd(jsonObject);
if (name.equals("delete"))
trans = parseBytecodeDelete(jsonObject);
trans.setOpcodeIndex(jsonObject.getInt("opcodeIndex"));
trans.setMethodLocation(getMethod(jsonObject.getString("methodLocation")));
} catch (JSONException e) {
throw new TransformationParserException("Cannot find JSON data", e);
}
return trans;
}
protected Transformation parseBinaryOperatorMutation(JSONObject jsonObject) throws JSONException,
TransformationParserException {
String name = jsonObject.getString("name");
BinaryOperatorMutation trans = null;
if (name.equals("conditionalBoundary"))
trans = new ConditionalBoundaryMutation();
if (name.equals("math"))
trans = new MathMutation();
if (name.equals("negateConditional"))
trans = new NegateConditionalMutation();
if (name.equals("removeConditional"))
trans = new RemoveConditionalMutation();
CtBinaryOperator<?> p = null;
Object jsonPosition = jsonObject.get("position");
for (CtElement ret : inputProgram.getAllElement(CtBinaryOperator.class)) {
String position = ret.getParent(CtPackage.class).getQualifiedName()
+ "." + ret.getParent(CtType.class).getSimpleName() + ":" + ret.getPosition().getLine();
if (position.equals(jsonPosition)) {
p = (CtBinaryOperator) ret;
break;
}
}
if (p == null) {
throw new TransformationParserException("Cannot find binary operation mutation at " + jsonPosition);
}
trans.setTransformationPoint(p);
return trans;
}
protected Transformation parseReturnValueMutation(JSONObject jsonObject) throws JSONException,
TransformationParserException {
ReturnValueMutation trans = new ReturnValueMutation();
Object jsonPosition = jsonObject.get("position");
CtReturn p = null;
for (CtReturn<?> ret : inputProgram.getReturns()) {
String position = ret.getParent(CtPackage.class).getQualifiedName()
+ "." + ret.getParent(CtType.class).getSimpleName() + ":" + ret.getPosition().getLine();
if (position.equals(jsonPosition)) {
p = ret;
break;
}
}
if (p == null) {
throw new TransformationParserException("Cannot find return statement that matches position " + jsonPosition);
}
trans.setTransformationPoint(p);
return trans;
}
protected Transformation parseInlineConstantMutation(JSONObject jsonObject) throws TransformationParserException {
InlineConstantMutation trans = new InlineConstantMutation();
Object jsonPos;
try {
jsonPos = jsonObject.get("position");
} catch (JSONException e) {
throw new TransformationParserException("Cannot find position data", e);
}
CtLocalVariable p = null;
for (CtLocalVariable<?> ret : inputProgram.getInlineConstant()) {
String position = ret.getParent(CtPackage.class).getQualifiedName()
+ "." + ret.getParent(CtType.class).getSimpleName() + ":" + ret.getPosition().getLine();
if (position.equals(jsonPos)) {
p = ret;
break;
}
}
if (p == null) {
throw new TransformationParserException("Cannot find inline constant");
}
trans.setTransformationPoint(p);
return trans;
}
protected BytecodeTransformation parseBytecodeDelete(JSONObject jsonObject) {
return new BytecodeDelete();
}
protected BytecodeTransformation parseBytecodeAdd(JSONObject jsonObject) throws JSONException {
BytecodeAdd trans = new BytecodeAdd();
trans.setByteCodeToAdd(parseByteCode(jsonObject.getString("byteCodeToAdd")));
return trans;
}
protected BytecodeTransformation parseBytecodeReplace(JSONObject jsonObject) throws JSONException {
BytecodeReplace trans = new BytecodeReplace();
try {
trans.setByteCodeToReplace(parseByteCode(jsonObject.getString("byteCodeToReplace")));
} catch (JSONException e) {
}
return trans;
}
protected ASTTransformation parseASTDelete(JSONObject jsonObject) {
return new ASTDelete();
}
protected ASTTransformation parseASTAdd(JSONObject jsonObject) throws JSONException, TransformationParserException {
ASTAdd trans = new ASTAdd();
trans.setTransplant(findCodeFragment(jsonObject.getJSONObject("transplant")));
trans.setVarMapping(parseVariableMapping(jsonObject.getJSONObject("variableMapping")));
return trans;
}
protected ASTTransformation parseASTReplace(JSONObject jsonObject) throws JSONException,
TransformationParserException {
ASTReplace trans = new ASTReplace();
trans.setCodeFragmentToReplace(findCodeFragment(jsonObject.getJSONObject("transplant")));
trans.setVarMapping(parseVariableMapping(jsonObject.getJSONObject("variableMapping")));
return trans;
}
protected CodeFragment findCodeFragment(JSONObject jsonObject) throws TransformationParserException {
CodeFragment cf = null;
// String position = null;
// String sourceCode = null;
// try {
// position = jsonObject.getString("position");
// sourceCode = jsonObject.getString("sourcecode");
// } catch (JSONException e) {
// e.printStackTrace();
// }
//// String sourceCode = jsonObject.getString("sourceCode");
// cf =inputProgram.getCodeFragment(position, sourceCode);
cf = inputProgram.getCodeFragment(jsonObject);
if (cf == null) {
throw new TransformationParserException(
"Cannot find a code fragment that matches the current JSON object " + jsonObject.toString());
}
return cf;
}
protected Map<String, String> parseVariableMapping(JSONObject jsonObject) throws JSONException {
Map<String, String> map = new HashMap<>();
Iterator it = jsonObject.keys();
while (it.hasNext()) {
String key = it.next().toString();
map.put(key, jsonObject.get(key).toString());
}
return map;
}
protected byte[] parseByteCode(String bytecodes) {
String[] bytecode = bytecodes.substring(1, bytecodes.length() - 1).split(", ");
byte[] tab = new byte[bytecode.length];
for (int i = 0; i < tab.length; i++)
tab[i] = Byte.parseByte(bytecode[i]);
return tab;
}
/**
* Obtains a javassist method of the given name
*
* @param name Name of the method
* @return
* @throws TransformationParserException
*/
protected CtMethod getMethod(String name) throws TransformationParserException {
for (CtMethod mth : inputProgram.getJavassistMethods()) {
if (mth.getLongName().equals(name))
return mth;
}
throw new TransformationParserException("Could not find javassist method " + name);
}
protected List<String> getFailures(JSONObject jsonObject) throws JSONException {
List<String> list = new ArrayList<>();
JSONArray array = jsonObject.getJSONArray("failures");
for (int i = 0; i < array.length(); i++) {
if (failureDictionary == null)
list.add(array.getString(i));
else
list.add(failureDictionary.get(array.getInt(i)));
}
return list;
}
protected void parseFailureDictionay(JSONArray array) throws JSONException {
for (int i = 0; i < array.length(); i++) {
JSONObject object = array.getJSONObject(i);
if (object.has("failureDictionary")) {
failureDictionary = new HashMap<>();
JSONObject dico = object.getJSONObject("failureDictionary");
Iterator it = dico.keys();
while (it.hasNext()) {
String key = it.next().toString();
failureDictionary.put(dico.getInt(key), key);
}
}
}
}
/**
* Used to filter what properties in the JSON we want, making the processing faster.
*/
public Properties getFilterProperties() {
return filterProperties;
}
public void setFilterProperties(Properties filterProperties) {
this.filterProperties = filterProperties;
}
public static void saveToFile(List<Transformation> transf, String fileName) throws JSONException, IOException {
JSONArray a = new JSONArray();
for ( Transformation t : transf ) {
a.put(t.toJSONObject());
}
FileWriter fw = null;
try {
fw = new FileWriter(fileName);
a.write(fw);
} finally {
if (fw != null) {
fw.close();
}
}
}
public Collection<String> getErrors() {
if ( errors == null ) errors = new ArrayList<>();
return errors;
}
}