forked from spgroup/conflict-static-analysis
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(spgroup#31): oa inter first version with comments
- Loading branch information
1 parent
0ebd4fc
commit b98d8fa
Showing
1 changed file
with
264 additions
and
19 deletions.
There are no files selected for viewing
283 changes: 264 additions & 19 deletions
283
src/main/java/br/unb/cic/analysis/ioa/InterproceduralOverrideAssignment.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,56 +1,301 @@ | ||
package br.unb.cic.analysis.ioa; | ||
|
||
import br.unb.cic.analysis.AbstractAnalysis; | ||
import br.unb.cic.analysis.AbstractMergeConflictDefinition; | ||
import br.unb.cic.analysis.df.DataFlowAbstraction; | ||
import br.unb.cic.analysis.model.Conflict; | ||
import br.unb.cic.analysis.model.Statement; | ||
import soot.*; | ||
import soot.jimple.AssignStmt; | ||
import soot.jimple.InstanceFieldRef; | ||
import soot.jimple.InvokeStmt; | ||
import soot.jimple.StaticFieldRef; | ||
import soot.toolkits.scalar.ArraySparseSet; | ||
import soot.toolkits.scalar.FlowSet; | ||
|
||
import java.util.*; | ||
import java.util.stream.Collectors; | ||
|
||
public class InterproceduralOverrideAssignment extends SceneTransformer { | ||
public class InterproceduralOverrideAssignment extends SceneTransformer implements AbstractAnalysis { | ||
|
||
private Set<Conflict> conflicts; | ||
private Set<SootMethod> visitedMethods; | ||
|
||
private PointsToAnalysis pta; | ||
|
||
private AbstractMergeConflictDefinition definition; | ||
|
||
// TODO dataflowabstraction provavelmente deve ser subustituido por algo que faça mais sentido na analise inter procedural | ||
// TODO Adicionar tratamento de if, loops... (ForwardFlowAnalysis) | ||
private FlowSet<DataFlowAbstraction> res; | ||
private Body body; | ||
|
||
public InterproceduralOverrideAssignment(AbstractMergeConflictDefinition definition) { | ||
visitedMethods = new HashSet<>(); | ||
|
||
this.visitedMethods = new HashSet<>(); | ||
this.conflicts = new HashSet<>(); | ||
|
||
this.definition = definition; | ||
this.res = new ArraySparseSet<>(); | ||
} | ||
|
||
@Override | ||
public void clear() { | ||
conflicts.clear(); | ||
} | ||
|
||
@Override | ||
public Set<Conflict> getConflicts() { | ||
return conflicts; | ||
} | ||
|
||
private void configureEntryPoints() { | ||
List<SootMethod> entryPoints = new ArrayList<>(); | ||
definition.getSourceStatements().forEach(s -> { | ||
entryPoints.add(s.getSootMethod()); | ||
}); | ||
Scene.v().setEntryPoints(entryPoints); | ||
} | ||
|
||
@Override | ||
protected void internalTransform(String s, Map<String, String> map) { | ||
definition.loadSourceStatements(); | ||
definition.loadSinkStatements(); | ||
List<SootMethod> traversedMethods = new ArrayList<>(); | ||
|
||
configureEntryPoints(); | ||
|
||
List<SootMethod> methods = Scene.v().getEntryPoints(); | ||
pta = Scene.v().getPointsToAnalysis(); | ||
methods.forEach(m -> traverse(m)); | ||
methods.forEach(m -> traverse(m, traversedMethods, Statement.Type.IN_BETWEEN)); | ||
} | ||
|
||
private void traverse(SootMethod m) { | ||
if(visitedMethods.contains(m) || m.isPhantom()) { | ||
// TODO rename type to changeTag | ||
private void traverse(SootMethod sm, List<SootMethod> traversed, Statement.Type type) { | ||
// TODO Verificar o que é isPhantom() | ||
if (visitedMethods.contains(sm) || sm.isPhantom()) { | ||
return; | ||
} | ||
|
||
Body body = m.retrieveActiveBody(); | ||
traversed.add(sm); | ||
this.body = sm.retrieveActiveBody(); | ||
|
||
body.getUnits().forEach(unit -> { | ||
// TODO: write specific code for Override Assignment. | ||
|
||
detectConflict(res, unit, type, sm); | ||
// TODO isInLeftStatementFLow ... isInRightStatementFLow | ||
if ((isLeftStatement(unit) || isRightStatement(unit)) || | ||
(type.equals(Statement.Type.SOURCE) || type.equals(Statement.Type.SINK))) { | ||
// TODO mover if e else para metodos diferentes | ||
if (unit instanceof AssignStmt) { | ||
// TODO Verificar AssignStmt contem objetos, arrays ou outros tipos? | ||
AssignStmt assignStmt = (AssignStmt) unit; | ||
|
||
// TODO Verificar caso: x = foo() + foo() | ||
if (assignStmt.containsInvokeExpr()) { | ||
traverse(assignStmt.getInvokeExpr().getMethod(), traversed, type); | ||
} | ||
|
||
// TODO renomear Statement. (UnitWithExtraInformations) | ||
Statement stmt = getStatementAssociatedWithUnit(sm, unit, type); | ||
gen(stmt); | ||
|
||
// TODO Verificar tratamento em caso de for | ||
} else if (unit instanceof InvokeStmt) { | ||
InvokeStmt invokeStmt = (InvokeStmt) unit; | ||
Statement stmt = getStatementAssociatedWithUnit(sm, unit, type); | ||
// TODO trocar stmt.getType() por type | ||
traverse(invokeStmt.getInvokeExpr().getMethod(), traversed, stmt.getType()); | ||
} | ||
} else { | ||
// TODO parametrizar | ||
if (unit instanceof AssignStmt) { | ||
AssignStmt assignStmt = (AssignStmt) unit; | ||
Statement stmt = getStatementAssociatedWithUnit(sm, unit, type); | ||
|
||
if (assignStmt.containsInvokeExpr()) { | ||
traverse(assignStmt.getInvokeExpr().getMethod(), traversed, stmt.getType()); | ||
} | ||
|
||
kill(unit); | ||
|
||
} else if (unit instanceof InvokeStmt) { | ||
InvokeStmt invokeStmt = (InvokeStmt) unit; | ||
Statement stmt = getStatementAssociatedWithUnit(sm, unit, type); | ||
traverse(invokeStmt.getInvokeExpr().getMethod(), traversed, stmt.getType()); | ||
} | ||
} | ||
}); | ||
} | ||
|
||
private void configureEntryPoints() { | ||
List<SootMethod> entryPoints = new ArrayList<>(); | ||
definition.getSourceStatements().forEach(s -> { | ||
entryPoints.add(s.getSootMethod()); | ||
// TODO precisa tratar outros casos | ||
// TODO adicionar em duas litas (left e right). | ||
// TODO adicionar profundidade InstanceFieldRef e StaticFieldRef | ||
private void gen(Statement stmt) { | ||
stmt.getUnit().getDefBoxes().forEach(valueBox -> { | ||
if (valueBox.getValue() instanceof Local) { | ||
res.add(new DataFlowAbstraction((Local) valueBox.getValue(), stmt)); | ||
} else if (valueBox.getValue() instanceof StaticFieldRef) { | ||
res.add(new DataFlowAbstraction((StaticFieldRef) valueBox.getValue(), stmt)); | ||
} else if (valueBox.getValue() instanceof InstanceFieldRef) { | ||
// TODO verificar o que é adicionado. (Objeto.field) | ||
res.add(new DataFlowAbstraction((InstanceFieldRef) valueBox.getValue(), stmt)); | ||
} | ||
}); | ||
Scene.v().setEntryPoints(entryPoints); | ||
// TODO: after fixing the logic for | ||
// setting the entry points, remove the following | ||
// line. | ||
throw new RuntimeException("not implemented yet..."); | ||
} | ||
|
||
private void kill(Unit unit) { | ||
for (DataFlowAbstraction dataFlowAbstraction : res) { | ||
// TODO extrair metodo res.removeAll(unit.getDefBoxes()) | ||
for (ValueBox valueBox : unit.getDefBoxes()) { | ||
if (compareItens(valueBox, dataFlowAbstraction)) { | ||
res.remove(dataFlowAbstraction); | ||
} | ||
} | ||
} | ||
} | ||
|
||
// TODO Obter res via atributo | ||
/* | ||
* To detect conflicts in verified if "u" is owned by LEFT or RIGHT | ||
* and we fill in the "potentialConflictingAssignments" list with the changes from the other developer. | ||
* | ||
* We pass "u" and "potentialConflictingAssignments" to the checkConflits method | ||
* to see if Left assignments interfere with Right changes or | ||
* Right assignments interfere with Left changes. | ||
*/ | ||
private void detectConflict(FlowSet<DataFlowAbstraction> in, Unit u, Statement.Type type, SootMethod sm) { | ||
|
||
if (!(isRightStatement(u) || isLeftStatement(u) || type.equals(Statement.Type.SOURCE) | ||
|| type.equals(Statement.Type.SINK))) { | ||
return; | ||
} | ||
|
||
List<DataFlowAbstraction> potentialConflictingAssignments = new ArrayList<>(); | ||
|
||
if (isRightStatement(u) || type.equals(Statement.Type.SINK)) { | ||
potentialConflictingAssignments = in.toList().stream().filter( | ||
DataFlowAbstraction::containsLeftStatement).collect(Collectors.toList()); | ||
} else if (isLeftStatement(u) || type.equals(Statement.Type.SOURCE)) { | ||
potentialConflictingAssignments = in.toList().stream().filter( | ||
DataFlowAbstraction::containsRightStatement).collect(Collectors.toList()); | ||
} | ||
|
||
checkConflicts(u, potentialConflictingAssignments, type, sm); | ||
|
||
} | ||
|
||
/* | ||
* Checks if there is a conflict and if so adds it to the conflict list. | ||
*/ | ||
private void checkConflicts(Unit unit, List<DataFlowAbstraction> potentialConflictingAssignments, Statement.Type type, SootMethod sm) { | ||
for (DataFlowAbstraction dataFlowAbstraction : potentialConflictingAssignments) { | ||
for (ValueBox valueBox : unit.getDefBoxes()) { | ||
if (compareItens(valueBox, dataFlowAbstraction)) { | ||
Conflict c = new Conflict(getStatementAssociatedWithUnit(sm, unit, type), dataFlowAbstraction.getStmt()); | ||
conflicts.add(c); | ||
System.out.println(c); | ||
} | ||
} | ||
} | ||
} | ||
|
||
// TODO melhorar nome do metodo | ||
// TODO não comparar como string | ||
private boolean compareItens(ValueBox valueBox, DataFlowAbstraction dataFlowAbstraction) { | ||
if (valueBox.getValue() instanceof InstanceFieldRef && dataFlowAbstraction.getFieldRef() != null) { | ||
return getVariableNameInFromValueBoxInstanceFieldRef(valueBox).equals(dataFlowAbstraction.getFieldRef().getBase().toString()); | ||
} else if (valueBox.getValue() instanceof StaticFieldRef && dataFlowAbstraction.getLocalStaticRef() != null) { | ||
return getVariableNameInFromValueBoxStaticFieldRef(valueBox).equals(dataFlowAbstraction.getLocalStaticRef().getField().getName()); | ||
} else if (valueBox.getValue() instanceof Local && dataFlowAbstraction.getLocal() != null) { | ||
return getVariableNameInFromValueBoxLocal(valueBox).equals(dataFlowAbstraction.getLocal().getName()); | ||
} | ||
return false; | ||
} | ||
|
||
private String getVariableNameInFromValueBoxInstanceFieldRef(ValueBox valueBox) { | ||
InstanceFieldRef instanceFieldRef = (InstanceFieldRef) valueBox.getValue(); | ||
return instanceFieldRef.getBase().toString(); | ||
} | ||
|
||
private String getVariableNameInFromValueBoxStaticFieldRef(ValueBox valueBox) { | ||
StaticFieldRef staticFieldRef = (StaticFieldRef) valueBox.getValue(); | ||
return staticFieldRef.getField().getName(); | ||
} | ||
|
||
private String getVariableNameInFromValueBoxLocal(ValueBox valueBox) { | ||
Local local = (Local) valueBox.getValue(); | ||
return local.getName(); | ||
} | ||
|
||
/* | ||
* Returns the Statement type | ||
*/ | ||
private Statement getStatementAssociatedWithUnit(SootMethod sm, Unit u, Statement.Type type) { | ||
if (isLeftStatement(u)) { | ||
return findLeftStatement(u); | ||
} else if (isRightStatement(u)) { | ||
return findRightStatement(u); | ||
} else if (!isLeftStatement(u) && type.equals(Statement.Type.SOURCE)) { | ||
return createStatement(sm, u, type); | ||
} else if (!isRightStatement(u) && type.equals(Statement.Type.SINK)) { | ||
return createStatement(sm, u, type); | ||
} | ||
return findStatementBase(u); | ||
} | ||
|
||
private boolean isLeftStatement(Unit u) { | ||
return definition.getSourceStatements().stream().map(Statement::getUnit).collect(Collectors.toList()).contains(u); | ||
} | ||
|
||
private boolean isRightStatement(Unit u) { | ||
return definition.getSinkStatements().stream().map(Statement::getUnit).collect(Collectors.toList()).contains(u); | ||
} | ||
|
||
private Statement findRightStatement(Unit u) { | ||
return definition.getSinkStatements().stream().filter(s -> s.getUnit().equals(u)). | ||
findFirst().get(); | ||
} | ||
|
||
private Statement findLeftStatement(Unit u) { | ||
return definition.getSourceStatements().stream().filter(s -> s.getUnit().equals(u)). | ||
findFirst().get(); | ||
} | ||
|
||
private Statement findStatementBase(Unit d) { | ||
return Statement.builder() | ||
.setClass(body.getMethod().getDeclaringClass()) | ||
.setMethod(body.getMethod()) | ||
.setType(Statement.Type.IN_BETWEEN) | ||
.setUnit(d) | ||
.setSourceCodeLineNumber(d.getJavaSourceStartLineNumber()).build(); | ||
} | ||
|
||
private Statement createStatement(SootMethod sm, Unit u, Statement.Type type) { | ||
return Statement.builder().setClass(sm.getDeclaringClass()).setMethod(sm) | ||
.setUnit(u).setType(type).setSourceCodeLineNumber(u.getJavaSourceStartLineNumber()) | ||
.build(); | ||
} | ||
|
||
/*private String getVariableNameInFromValueBox(ValueBox valueBox) { | ||
if (valueBox.getValue() instanceof InstanceFieldRef) { | ||
InstanceFieldRef instanceFieldRef = (InstanceFieldRef) valueBox.getValue(); | ||
return instanceFieldRef.getBase().toString(); | ||
} else if (valueBox.getValue() instanceof Local) { | ||
Local local = (Local) valueBox.getValue(); | ||
return local.getName(); | ||
} else if (valueBox.getValue() instanceof StaticFieldRef) { | ||
StaticFieldRef staticFieldRef = (StaticFieldRef) valueBox.getValue(); | ||
return staticFieldRef.getField().getName(); | ||
} else { | ||
return ""; | ||
} | ||
}*/ | ||
/* private String getVariableNameInDataFlowAbstraction(DataFlowAbstraction dataFlowAbstraction) { | ||
if (dataFlowAbstraction.getLocal() != null) { | ||
return dataFlowAbstraction.getLocal().getName(); | ||
} else if (dataFlowAbstraction.getLocalStaticRef() != null) { | ||
return dataFlowAbstraction.getLocalStaticRef().getField().getName(); | ||
} else { | ||
return dataFlowAbstraction.getFieldRef().getBase().toString(); | ||
} | ||
}*/ | ||
} |