package fr.inria.diversify.transformation.query;
import fr.inria.diversify.diversification.InputProgram;
import fr.inria.diversify.transformation.ReplaceArrayListToLinkedListTransformation;
import fr.inria.diversify.transformation.Transformation;
import org.reflections.Reflections;
import spoon.reflect.code.CtAssignment;
import spoon.reflect.code.CtConstructorCall;
import spoon.reflect.code.CtExpression;
import spoon.reflect.code.CtReturn;
import spoon.reflect.declaration.CtElement;
import spoon.reflect.declaration.CtMethod;
import spoon.reflect.factory.Factory;
import spoon.reflect.reference.CtExecutableReference;
import spoon.reflect.reference.CtTypeReference;
import spoon.support.reflect.code.CtInvocationImpl;
import spoon.support.reflect.code.CtLocalVariableImpl;
import java.lang.reflect.Constructor;
import java.util.*;
/**
* Created by lguerin on 04/06/15.
*/
public class ReplaceArrayListToLinkedListQuery extends TransformationQuery{
public ReplaceArrayListToLinkedListQuery(InputProgram inputProgram) {
super(inputProgram);
}
@Override
public Transformation query() throws QueryException {
ReplaceArrayListToLinkedListTransformation transformation=new ReplaceArrayListToLinkedListTransformation();
List<CtElement> newClasses = getInputProgram().getAllElement(CtConstructorCall.class);
List<CtConstructorCall> candidates=new ArrayList<>();
for(int i=0;i<newClasses.size();i++){
if(isCandidate((CtConstructorCall)newClasses.get(i))){
CtConstructorCall ctConstructorCall=(CtConstructorCall)newClasses.get(i);
candidates.add(ctConstructorCall);
}
}
CtConstructorCall newCtConstructorCall;
for(int i=0;i<candidates.size();i++){
newCtConstructorCall=constructCtConstructorCall(candidates.get(i));
transformation.addTransplantationPoint(candidates.get(i), newCtConstructorCall);
}
return transformation;
}
private boolean isCandidate(CtConstructorCall ctConstructorCall) {
CtElement parent=ctConstructorCall.getParent();
Class staticType=null;
try{
//
ctConstructorCall.getType().getActualClass();
//
if(parent instanceof CtLocalVariableImpl) {
staticType= ((CtLocalVariableImpl) parent).getType().getActualClass();
}else if(parent instanceof CtAssignment){
staticType= ((CtAssignment) parent).getType().getActualClass();
}else if(parent instanceof spoon.reflect.declaration.CtField){
staticType= ((spoon.reflect.declaration.CtField) parent).getType().getActualClass();
}else if(parent instanceof CtInvocationImpl){
parent=(CtInvocationImpl) parent;
List<CtExpression> argumentsInvocation=((CtInvocationImpl) parent).getArguments();
CtExecutableReference executable=((CtInvocationImpl) parent).getExecutable();
List<CtTypeReference> argumentsExecutable=executable.getParameters();
for(int i=0; i<argumentsInvocation.size();i++){
if(argumentsInvocation.get(i).equals(ctConstructorCall)){
staticType=argumentsExecutable.get(i).getActualClass();
}
}
}else if(parent instanceof CtReturn){
while (! (parent instanceof CtMethod) ){parent=parent.getParent();}
staticType=((CtMethod) parent).getType().getActualClass();
}
}catch(Exception e){
return false;
}
return (staticType!=null && staticType.getSimpleName().equals("List") && ctConstructorCall.getType().getActualClass().getSimpleName().equals("ArrayList"));
}
/**
* this function construct an ctConstructorCall which can replace the ctConstructor
* @param ctConstructorCall
* @return CtConstructorCall
*/
private CtConstructorCall constructCtConstructorCall(CtConstructorCall ctConstructorCall) {
Factory factory=ctConstructorCall.getFactory();
CtConstructorCall newConstructorCall=factory.Core().createConstructorCall();
List<CtExpression<?>> arguments=ctConstructorCall.getArguments();
Class linkedList=LinkedList.class;
newConstructorCall.setType(factory.Type().createReference(linkedList));
if(arguments.size()==0 || !(arguments.get(0).getType().getSimpleName().equals("int"))){
newConstructorCall.setArguments(arguments);
}
return newConstructorCall;
}
}