package fr.inria.diversify.transformation.ast;
import fr.inria.diversify.codeFragment.CodeFragment;
import fr.inria.diversify.transformation.SingleTransformation;
import fr.inria.diversify.transformation.ast.exception.ApplyTransformationException;
import fr.inria.diversify.util.Log;
import spoon.compiler.Environment;
import spoon.reflect.code.*;
import spoon.reflect.cu.SourcePosition;
import spoon.reflect.declaration.CtExecutable;
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: 7/11/13
* Time: 4:15 PM
*/
public abstract class ASTTransformation extends SingleTransformation {
protected boolean subType;
/**
* Transplantation point that is going to be modified, either by an Add, Replace or Delete transformation
*/
protected CodeFragment transplantationPoint;
CtCodeElement copyTransplant;
public ASTTransformation() {
}
/**
* String describing the level of the transformation, it may be at the statement, or block level.
*
* @return a string describing the level.
*/
public String getLevel() {
CtCodeElement stmt = transplantationPoint.getCtCodeFragment();
if (stmt instanceof CtLocalVariable
|| stmt instanceof CtNewClass
|| stmt instanceof CtBreak
|| stmt instanceof CtUnaryOperator
|| stmt instanceof CtAssignment
|| stmt instanceof CtReturn
|| stmt instanceof CtOperatorAssignment
|| stmt instanceof CtContinue
|| stmt instanceof CtInvocation)
return "statement";
return "block";
}
/**
* @return
* @throws Exception
*/
public String getTransformationString() throws Exception {
copyTransplant = buildReplacementElement();
transplantationPoint.getCtCodeFragment().replace(copyTransplant);
String ret = transplantationPoint.getCtCodeFragment().getParent().toString();
copyTransplant.replace(transplantationPoint.getCtCodeFragment());
return ret;
}
/**
* 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 abstract boolean usedOfSubType();
/**
* Logs description of the transformation that is going to be perform
*/
protected abstract void applyInfo();
/**
* 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.getCtCodeFragment().replace(copyTransplant);
printJavaFile(srcDir);
} catch (Exception e) {
throw new ApplyTransformationException("", e);
}
}
/**
* 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);
}
/**
* All AST transformations takes the transplantation point (TP) and replaces it by :
* 1. The TP + transplant (add operation)
* 2. The transplant (replace operation)
* 3. And empty statement (delete operation)
* <p/>
* This method builds the such replacement element
*
* @return The resulting CtElement after the transformation
* @throws Exception
* @Note: Renamed after buildCopyElement.
*/
protected abstract CtCodeElement buildReplacementElement();
/**
* 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.getCtCodeFragment());
} catch (Throwable e) {
e.printStackTrace();
Log.debug("");
}
printJavaFile(srcDir);
}
public abstract void updateStatementList();
public CtType<?> getOriginalClass(CodeFragment cf) {
return cf.getCompilationUnit().getMainType();
}
/**
* Returns the transplantation point of the transformation
*
* @return A code fragment representing the transplantation point
*/
public CodeFragment getTransplantationPoint() {
return transplantationPoint;
}
public void setTransplantationPoint(CodeFragment transplantationPoint) {
this.transplantationPoint = transplantationPoint;
}
/**
* Returns the qualified name of the source class of the transplantation point
*
* @return
*/
public String classLocationName() {
return transplantationPoint.getSourceClass().getQualifiedName();
}
/**
* Returns the qualified name of the package of the transplantation points
*
* @return
*/
public String packageLocationName() {
return transplantationPoint.getSourcePackage().getQualifiedName();
}
/**
* Starting line number at wish the transplantation point is located
*
* @return An integer describing the starting line number
*/
public int line() {
return transplantationPoint.getStartLine();
}
/**
* Subtype of the transformation, add, delete, replace, replaceWitgestein, addSteroid, etc.
*
* @param type
*/
//for stupid transformation
public void setName(String type) {
name = type;
}
public String methodLocationName() {
CtExecutable elem = transplantationPoint.getCtCodeFragment().getParent(CtExecutable.class);
if (elem != null) return elem.getSimpleName();
return "field";
}
public void setSubType(boolean subType) {
this.subType = subType;
}
@Override
public SourcePosition getPosition() {
return transplantationPoint.getCtCodeFragment().getPosition();
}
public CtCodeElement getCopyTransplant() {
return copyTransplant;
}
}