package fr.inria.diversify.transformation;
import fr.inria.diversify.transformation.ast.exception.ApplyTransformationException;
import fr.inria.diversify.util.Log;
import spoon.compiler.Environment;
import spoon.reflect.cu.SourcePosition;
import spoon.reflect.declaration.CtElement;
import spoon.reflect.declaration.CtExecutable;
import spoon.reflect.declaration.CtPackage;
import spoon.reflect.declaration.CtType;
import spoon.reflect.factory.Factory;
import spoon.reflect.visitor.DefaultJavaPrettyPrinter;
import spoon.support.JavaOutputProcessor;
import java.io.File;
import java.io.IOException;
/**
* User: Simon
* Date: 27/05/15
* Time: 14:34
*/
public abstract class RefactorSpoonTransformation<P extends CtElement, T extends CtElement> extends SingleTransformation {
protected P transplantationPoint;
protected T transplant;
protected T copyTransplant;
/**
* Apply the transformation. After the transformation is performed, the result will be copied to the output directory
*
* @param srcDir Path of the output directory
* @throws Exception
*/
public void apply(String srcDir) throws Exception {
applyInfo();
try {
copyTransplant = buildReplacementElement();
transplantationPoint.replace(copyTransplant);
printJavaFile(srcDir);
} catch (Exception e) {
throw new ApplyTransformationException("", e);
}
}
protected abstract T buildReplacementElement();
/**
* Applies the transformation having into consideration the parent transformation
*
* @param srcDir Path of the output directory
* @throws Exception
*/
@Override
public void applyWithParent(String srcDir) throws Exception {
if (parent != null) parent.apply(srcDir);
apply(srcDir);
}
/**
* Undo the transformation. After the transformation is restored, the result will be copy to the output directory
*
* @param srcDir Path of the output directory
* @throws Exception
*/
public void restore(String srcDir) throws Exception {
if (parent != null) {
parent.restore(srcDir);
}
try {
copyTransplant.replace(transplantationPoint);
} catch (Throwable e) {
e.printStackTrace();
Log.debug("");
}
printJavaFile(srcDir);
}
/**
* Prints the modified java file. When the transformation is done a new java file is created. This method performs a
* pretty print of it
*
* @param directory Directory where the java file is going to be placed
* @throws IOException
*/
public void printJavaFile(String directory) throws IOException {
CtType<?> type = getOriginalClass(transplantationPoint);
Factory factory = type.getFactory();
Environment env = factory.getEnvironment();
JavaOutputProcessor processor = new JavaOutputProcessor(new File(directory), new DefaultJavaPrettyPrinter(env));
processor.setFactory(factory);
processor.createJavaFile(type);
Log.debug("write type {} in directory {}", type.getQualifiedName(), directory);
}
public CtType<?> getOriginalClass(CtElement element) {
return element.getPosition().getCompilationUnit().getMainType();
}
public String classLocationName() {
CtType c = transplantationPoint.getParent(CtType.class);
if(c == null && transplantationPoint instanceof CtType)
c = (CtType) transplantationPoint;
if(c == null)
return "null";
return c.getQualifiedName();
}
public String packageLocationName() {
CtPackage p = transplantationPoint.getParent(CtPackage.class);
if(p == null && transplantationPoint instanceof CtPackage)
p = (CtPackage) transplantationPoint;
return p.getQualifiedName();
}
public String methodLocationName() {
CtExecutable elem = transplantationPoint.getParent(CtExecutable.class);
if(elem != null)
return elem.getSimpleName();
return "null";
}
@Override
public int line() {
return transplantationPoint.getPosition().getLine();
}
protected void applyInfo() {
Log.debug("transformation: {}, {}",type,name);
Log.debug("transplantationPoint:\n {}", transplantationPoint);
Log.debug("--------------------\nposition: {}", transplantationPoint.getPosition());
if(transplant != null) {
Log.debug("transplant:\n {}", transplant);
Log.debug("--------------------\nposition: {}", transplant.getPosition());
}
}
@Override
public SourcePosition getPosition() {
return transplantationPoint.getPosition();
}
public void setTransplantationPoint(P object) {
this.transplantationPoint = object;
}
public P setTransplantationPoint() {
return transplantationPoint;
}
public void setTransplant(T transplant) {
this.transplant = transplant;
}
public T getTransplant() {
return transplant;
}
public String getTransformationString() throws Exception {
copyTransplant = buildReplacementElement();
transplantationPoint.replace(copyTransplant);
String ret = transplantationPoint.getParent().toString();
copyTransplant.replace(transplantationPoint);
return ret;
}
}