package fr.inria.diversify.logger.transformationUsed;
import fr.inria.diversify.transformation.ast.ASTReplace;
import fr.inria.diversify.transformation.ast.ASTTransformation;
import spoon.reflect.code.*;
import spoon.reflect.cu.SourcePosition;
import spoon.reflect.declaration.CtElement;
import spoon.reflect.visitor.Query;
import spoon.reflect.visitor.filter.TypeFilter;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
* User: Simon
* Date: 08/09/15
* Time: 11:20
*/
public class StaticDiffBuilder {
protected Map<String, SourcePosition> branchPosition;
protected Map<String, Set<String>> testsByBranch;
public StaticDiffBuilder(Map<String, SourcePosition> branchPosition, Map<String, Set<String>> testsByBranch) {
this.branchPosition = branchPosition;
this.testsByBranch = testsByBranch;
}
public StaticDiff buildDiff(ASTTransformation transformation, Map<String, Set<String>> branchesUsedByTest) {
return new StaticDiff(branchDiff(transformation, branchesUsedByTest),
methodDiff(transformation, branchesUsedByTest));
}
public Map<String, Set<String>> methodDiff(ASTTransformation transformation, Map<String, Set<String>> branchesUsedByTest) {
Map<String, Set<String>> methodDiffs = new HashMap<>();
Map<String, CtStatement> add = getAddBranches(transformation);
Map<String, CtStatement> delete = getDeleteBranches(transformation);
// Query.getElements(transformation.getTransplantationPoint().getCtCodeFragment(), new TypeFilter(CtInvocation.class));
for(String test : branchesUsedByTest.keySet()) {
for(String branch : branchesUsedByTest.get(test)) {
if(add.containsKey(branch)) {
if(!methodDiffs.containsKey(test)) {
methodDiffs.put(test, new HashSet<>());
}
methodDiffs.get(test).add(branch);
}
if(delete.containsKey(branch)) {
if(!methodDiffs.containsKey(test)) {
methodDiffs.put(test, new HashSet<>());
}
methodDiffs.get(test).add(branch);
}
}
}
return methodDiffs;
}
public Map<String, Set<String>> branchDiff(ASTTransformation transformation, Map<String, Set<String>> branchesUsedByTest) {
Map<String, Set<String>> branchesDiff = new HashMap<>();
Map<String, CtStatement> add = getAddBranches(transformation);
add.remove("b");
Map<String, CtStatement> delete = getDeleteBranches(transformation);
delete.remove("b");
if(add.isEmpty() && delete.isEmpty()) {
return branchesDiff;
}
for(String test : branchesUsedByTest.keySet()) {
for(String branch : branchesUsedByTest.get(test)) {
if(add.containsKey(branch)) {
if(!branchesDiff.containsKey(test)) {
branchesDiff.put(test, new HashSet<>());
}
branchesDiff.get(test).add(branch);
}
if(delete.containsKey(branch)) {
if(!branchesDiff.containsKey(test)) {
branchesDiff.put(test, new HashSet<>());
}
branchesDiff.get(test).add(branch);
}
}
}
return branchesDiff;
}
protected Map<String, CtStatement> getAddBranches(ASTTransformation transformation) {
String name = transformation.getName();
if(name.equals("add")) {
return getBranches(transformation.getTransplantationPoint().getCtCodeFragment());
}
if(name.equals("replace")) {
ASTReplace replace = (ASTReplace) transformation;
Map<String, CtStatement> odlBranches = getBranches(transformation.getTransplantationPoint().getCtCodeFragment());
Map<String, CtStatement> newBranches = getBranches(replace.getTransplant().getCtCodeFragment());
newBranches.keySet().stream()
.forEach(key -> odlBranches.remove(key));
return newBranches;
}
return new HashMap<>();
}
protected Map<String, CtStatement> getDeleteBranches(ASTTransformation transformation) {
String name = transformation.getName();
if(name.equals("delete")) {
return getBranches(transformation.getTransplantationPoint().getCtCodeFragment());
}
if(name.equals("replace")) {
ASTReplace replace = (ASTReplace) transformation;
Map<String, CtStatement> odlBranches = getBranches(transformation.getTransplantationPoint().getCtCodeFragment());
Map<String, CtStatement> newBranches = getBranches(replace.getTransplant().getCtCodeFragment());
odlBranches.keySet().stream()
.forEach(key -> newBranches.remove(key));
return odlBranches;
}
return new HashMap<>();
}
protected Set<CtInvocation> getAddMethodCall(ASTTransformation transformation) {
Map<String, CtStatement> branches = getAddBranches(transformation);
return (Set<CtInvocation>) branches.values().stream()
.flatMap(stmt -> Query.getElements(stmt, new TypeFilter(CtInvocation.class)).stream())
.collect(Collectors.toSet());
}
protected Set<CtInvocation> getDeleteMethodCall(ASTTransformation transformation) {
Map<String, CtStatement> branches = getDeleteBranches(transformation);
return (Set<CtInvocation>) branches.values().stream()
.flatMap(stmt -> Query.getElements(stmt, new TypeFilter(CtInvocation.class)).stream())
.collect(Collectors.toSet());
}
protected Map<String, CtStatement> getBranches(CtElement stmt) {
Map<String, CtStatement> branches = new HashMap<>();
int count = 0;
for(Object object : Query.getElements(stmt, new TypeFilter(CtIf.class))) {
CtIf ctIf = (CtIf) object;
branches.put("t" + count, ctIf.getElseStatement());
count++;
if (ctIf.getElseStatement() != null) {
branches.put("e" + count, ctIf.getElseStatement());
count++;
}
}
for(Object object : Query.getElements(stmt, new TypeFilter(CtLoop.class))) {
CtLoop loop = (CtLoop) object;
branches.put("l" + count, loop.getBody());
count++;
}
for(Object object : Query.getElements(stmt, new TypeFilter(CtCatch.class))) {
CtCatch ctCatch = (CtCatch) object;
branches.put("c" + count, ctCatch.getBody());
count++;
}
if(count == 0) {
branches.put("b", (CtStatement)stmt);
}
return branches;
}
}