Complete API change
This commit is contained in:
parent
f24b00c255
commit
e77fe8f772
2 changed files with 115 additions and 131 deletions
|
@ -4,34 +4,90 @@ import com.github.javaparser.ast.Node;
|
|||
import com.github.javaparser.ast.expr.BooleanLiteralExpr;
|
||||
import com.github.javaparser.ast.stmt.*;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
import java.util.*;
|
||||
|
||||
public class CFG {
|
||||
private final List<Node> nodes = new LinkedList<>();
|
||||
private final LinkedList<Block> blocks = new LinkedList<>();
|
||||
private Stack<Block> blockStack = new Stack<>();
|
||||
private final Stack<Block> blockStack = new Stack<>();
|
||||
private final List<Edge> edges = new LinkedList<>();
|
||||
private Node beginNode, endNode;
|
||||
private final Node beginNode = new EmptyStmt(), endNode = new EmptyStmt();
|
||||
private final List<Node> nodeList = new LinkedList<>();
|
||||
|
||||
private String nextLabel;
|
||||
|
||||
public void addNode(Node stmt) {
|
||||
private void registerNode(Node stmt) {
|
||||
nodes.add(stmt);
|
||||
if (!blockStack.isEmpty())
|
||||
blockStack.peek().add(stmt);
|
||||
System.out.println("NODO: " + node2str(stmt));
|
||||
}
|
||||
|
||||
public void beginBlock(Node node, Node condition) {
|
||||
beginBlock(node, condition, true);
|
||||
public void setNode(Node node) {
|
||||
clearNode();
|
||||
appendNode(node);
|
||||
}
|
||||
|
||||
public void beginBlock(Node node, Node condition, boolean addNow) {
|
||||
public void clearNode() {
|
||||
nodeList.clear();
|
||||
}
|
||||
|
||||
public void connectTo(Node node) {
|
||||
connectTo(node, true);
|
||||
}
|
||||
|
||||
public void connectTo(Node node, boolean overwrite) {
|
||||
if (!nodesContains(node))
|
||||
registerNode(node);
|
||||
for (Node begin : nodeList)
|
||||
connect(begin, node);
|
||||
if (overwrite)
|
||||
setNode(node);
|
||||
}
|
||||
|
||||
private boolean nodesContains(Object object) {
|
||||
for (Node n : nodes)
|
||||
if (n == object)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public void removeNode(Node node) {
|
||||
nodeList.remove(node);
|
||||
}
|
||||
|
||||
public void appendNode(Node node) {
|
||||
nodeList.add(node);
|
||||
}
|
||||
|
||||
public void appendNodes(Collection<? extends Node> nodes) {
|
||||
nodeList.addAll(nodes);
|
||||
}
|
||||
|
||||
public List<Node> getNodeList() {
|
||||
return Collections.unmodifiableList(nodeList);
|
||||
}
|
||||
|
||||
public void setNodeList(List<Node> nodes) {
|
||||
nodeList.clear();
|
||||
nodeList.addAll(nodes);
|
||||
}
|
||||
|
||||
public void beginMethod() {
|
||||
nodeList.clear();
|
||||
nodeList.add(beginNode);
|
||||
}
|
||||
|
||||
public void finishMethod() {
|
||||
for (Node begin : nodeList)
|
||||
if (begin != endNode)
|
||||
connect(begin, endNode);
|
||||
}
|
||||
|
||||
public void beginBlock(Node node, Node condition) {
|
||||
Block b = new Block(node, condition);
|
||||
if (condition != null && addNow)
|
||||
addNode(condition);
|
||||
if (condition != null)
|
||||
registerNode(condition);
|
||||
if (blockStack.isEmpty())
|
||||
blocks.addFirst(b);
|
||||
else
|
||||
|
@ -47,27 +103,12 @@ public class CFG {
|
|||
nextLabel = String.valueOf(b);
|
||||
}
|
||||
|
||||
public void connect(Node begin, Node end) {
|
||||
private void connect(Node begin, Node end) {
|
||||
edges.add(new Edge(begin, end, nextLabel));
|
||||
nextLabel = null;
|
||||
}
|
||||
|
||||
public void connect(Collection<Node> begin, Node end) {
|
||||
for (Node n : begin)
|
||||
connect(n, end);
|
||||
}
|
||||
|
||||
public Node beginNode() {
|
||||
if (beginNode == null) {
|
||||
beginNode = new EmptyStmt();
|
||||
}
|
||||
return beginNode;
|
||||
}
|
||||
|
||||
public Node endNode() {
|
||||
if (endNode == null) {
|
||||
endNode = new EmptyStmt();
|
||||
}
|
||||
public Node getEndNode() {
|
||||
return endNode;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,76 +7,51 @@ import com.github.javaparser.ast.expr.Expression;
|
|||
import com.github.javaparser.ast.stmt.*;
|
||||
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
public class Visitador extends VoidVisitorAdapter<CFG> {
|
||||
//********************************************************/
|
||||
//********************** Atributos ***********************/
|
||||
//********************************************************/
|
||||
|
||||
private List<Node> prevNode;
|
||||
private Stack<SwitchStmt> switchStack = new Stack<>();
|
||||
private List<BreakStmt> brokenStmts = new LinkedList<>();
|
||||
|
||||
//********************************************************/
|
||||
//*********************** Metodos ************************/
|
||||
//********************************************************/
|
||||
|
||||
// Visitador de métodos
|
||||
// Este visitador añade el nodo final al CFG
|
||||
@Override
|
||||
public void visit(MethodDeclaration methodDeclaration, CFG graph) {
|
||||
prevNode = Collections.singletonList(graph.beginNode());
|
||||
|
||||
// Visitamos el método
|
||||
graph.beginMethod();
|
||||
super.visit(methodDeclaration, graph);
|
||||
|
||||
// Añadimos el nodo final al CFG
|
||||
Node end = graph.endNode();
|
||||
for (Node n : prevNode)
|
||||
if (n != end)
|
||||
graph.connect(n, end);
|
||||
graph.finishMethod();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ReturnStmt n, CFG arg) {
|
||||
arg.addNode(n);
|
||||
arg.connect(prevNode, n);
|
||||
super.visit(n, arg);
|
||||
arg.connect(n, arg.endNode());
|
||||
prevNode = Collections.emptyList();
|
||||
arg.connectTo(n);
|
||||
arg.connectTo(arg.getEndNode());
|
||||
arg.clearNode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(IfStmt n, CFG graph) {
|
||||
// Connect to the condition
|
||||
Node ifStart = n.getCondition();
|
||||
graph.beginBlock(n, ifStart);
|
||||
graph.connect(prevNode, ifStart);
|
||||
|
||||
// TODO: shortcut conditions (||, &&)
|
||||
|
||||
prevNode = Collections.singletonList(ifStart);
|
||||
graph.connectTo(ifStart);
|
||||
// Connect condition to then block
|
||||
graph.setNextLabel(true);
|
||||
List<Node> prevNodeBegin = prevNode;
|
||||
n.getThenStmt().accept(this, graph);
|
||||
List<Node> newPrev = new LinkedList<>();
|
||||
if (prevNode == prevNodeBegin)
|
||||
newPrev.add(ifStart);
|
||||
else newPrev.addAll(prevNode);
|
||||
prevNode = Collections.singletonList(ifStart);
|
||||
// Save end of then block
|
||||
List<Node> newPrev = new LinkedList<>(graph.getNodeList());
|
||||
// Connect condition to else block
|
||||
graph.setNode(ifStart);
|
||||
graph.setNextLabel(false);
|
||||
if (n.getElseStmt().isPresent()) {
|
||||
n.getElseStmt().get().accept(this, graph);
|
||||
if (prevNode == prevNodeBegin)
|
||||
newPrev.add(ifStart);
|
||||
else newPrev.addAll(prevNode);
|
||||
newPrev.addAll(graph.getNodeList());
|
||||
} else {
|
||||
newPrev.add(ifStart);
|
||||
}
|
||||
prevNode = newPrev;
|
||||
// Set ends of then/else as the new list
|
||||
graph.setNodeList(newPrev);
|
||||
graph.endBlock();
|
||||
}
|
||||
|
||||
|
@ -84,15 +59,10 @@ public class Visitador extends VoidVisitorAdapter<CFG> {
|
|||
public void visit(WhileStmt n, CFG graph) {
|
||||
Node whileStart = n.getCondition();
|
||||
graph.beginBlock(n, whileStart);
|
||||
graph.connect(prevNode, whileStart);
|
||||
|
||||
// TODO: shortcut conditions (||, &&)
|
||||
|
||||
prevNode = Collections.singletonList(whileStart);
|
||||
graph.connectTo(whileStart);
|
||||
graph.setNextLabel(true);
|
||||
n.getBody().accept(this, graph);
|
||||
graph.connect(prevNode, whileStart);
|
||||
prevNode = Collections.singletonList(whileStart);
|
||||
graph.connectTo(whileStart);
|
||||
graph.setNextLabel(false);
|
||||
graph.endBlock();
|
||||
}
|
||||
|
@ -100,13 +70,10 @@ public class Visitador extends VoidVisitorAdapter<CFG> {
|
|||
@Override
|
||||
public void visit(DoStmt n, CFG graph) {
|
||||
Node condition = n.getCondition();
|
||||
graph.beginBlock(n, condition, false);
|
||||
prevNode = new LinkedList<>(prevNode);
|
||||
prevNode.add(condition);
|
||||
graph.beginBlock(n, condition);
|
||||
graph.appendNode(condition);
|
||||
n.getBody().accept(this, graph);
|
||||
graph.addNode(condition);
|
||||
graph.connect(prevNode, condition);
|
||||
prevNode = Collections.singletonList(condition);
|
||||
graph.connectTo(condition);
|
||||
graph.setNextLabel(false);
|
||||
graph.endBlock();
|
||||
}
|
||||
|
@ -117,41 +84,31 @@ public class Visitador extends VoidVisitorAdapter<CFG> {
|
|||
// Initialization expressions
|
||||
if (n.getInitialization() != null) {
|
||||
for (Expression e : n.getInitialization()) {
|
||||
graph.addNode(e);
|
||||
graph.connect(prevNode, e);
|
||||
prevNode = Collections.singletonList(e);
|
||||
graph.connectTo(e);
|
||||
}
|
||||
}
|
||||
// Comparison expression
|
||||
// TODO: shortcut conditions (||, &&)
|
||||
if (n.getCompare().isPresent()) {
|
||||
graph.addNode(n.getCompare().get());
|
||||
graph.connect(prevNode, n.getCompare().get());
|
||||
prevNode = Collections.singletonList(n.getCompare().get());
|
||||
graph.connectTo(n.getCompare().get());
|
||||
graph.setNextLabel(true);
|
||||
}
|
||||
// Loop body
|
||||
n.getBody().accept(this, graph);
|
||||
// Update expressions
|
||||
if (n.getUpdate() != null) {
|
||||
for (Expression e : n.getUpdate()) {
|
||||
graph.addNode(e);
|
||||
graph.connect(prevNode, e);
|
||||
prevNode = Collections.singletonList(e);
|
||||
}
|
||||
}
|
||||
if (n.getUpdate() != null)
|
||||
for (Expression e : n.getUpdate())
|
||||
graph.connectTo(e);
|
||||
// Connect to comparison expression
|
||||
if (n.getCompare().isPresent())
|
||||
graph.connect(prevNode, n.getCompare().get());
|
||||
else {
|
||||
// TODO: connect last update / end of loop with first element of loop body
|
||||
}
|
||||
// Set comparison as last possible statement
|
||||
if (n.getCompare().isPresent()) {
|
||||
prevNode = Collections.singletonList(n.getCompare().get());
|
||||
graph.connectTo(n.getCompare().get());
|
||||
graph.setNextLabel(false);
|
||||
} else // There is no comparison, can't exit the loop TODO implement break and continue as way to exit
|
||||
prevNode = Collections.emptyList();
|
||||
} else {
|
||||
// TODO: connect last update / end of loop with first element of loop body
|
||||
// There is no comparison, can't exit the loop TODO implement break and continue as way to exit
|
||||
graph.clearNode();
|
||||
}
|
||||
graph.endBlock();
|
||||
}
|
||||
|
||||
|
@ -159,11 +116,11 @@ public class Visitador extends VoidVisitorAdapter<CFG> {
|
|||
public void visit(ForeachStmt n, CFG graph) {
|
||||
ForeachStmt copy = new ForeachStmt(n.getTokenRange().orElse(null), n.getVariable(), n.getIterable(), new EmptyStmt());
|
||||
graph.beginBlock(n, copy);
|
||||
graph.connect(prevNode, copy);
|
||||
prevNode = Collections.singletonList(copy);
|
||||
graph.connectTo(copy);
|
||||
graph.setNextLabel(true);
|
||||
n.getBody().accept(this, graph);
|
||||
graph.connect(prevNode, copy);
|
||||
prevNode = Collections.singletonList(copy);
|
||||
graph.connectTo(copy);
|
||||
graph.setNextLabel(false);
|
||||
graph.endBlock();
|
||||
}
|
||||
|
||||
|
@ -171,9 +128,7 @@ public class Visitador extends VoidVisitorAdapter<CFG> {
|
|||
public void visit(SwitchEntryStmt n, CFG graph) {
|
||||
// Case header
|
||||
Node caseNode = new SwitchEntryStmt(n.getTokenRange().orElse(null), n.getLabel().orElse(null), new NodeList<>());
|
||||
graph.addNode(caseNode);
|
||||
graph.connect(prevNode, caseNode);
|
||||
prevNode = Collections.singletonList(caseNode);
|
||||
graph.connectTo(caseNode);
|
||||
// Case body
|
||||
n.getStatements().accept(this, graph);
|
||||
}
|
||||
|
@ -183,39 +138,32 @@ public class Visitador extends VoidVisitorAdapter<CFG> {
|
|||
// Link previous statement to the switch's selector
|
||||
Node selectorNode = n.getSelector();
|
||||
graph.beginBlock(n, selectorNode);
|
||||
graph.connect(prevNode, selectorNode);
|
||||
graph.connectTo(selectorNode);
|
||||
// Analyze switch's cases
|
||||
prevNode = Collections.singletonList(selectorNode);
|
||||
switchStack.push(n);
|
||||
for (SwitchEntryStmt entry : n.getEntries()) {
|
||||
entry.accept(this, graph);
|
||||
if (prevNode.isEmpty()) {
|
||||
prevNode = Collections.singletonList(selectorNode);
|
||||
} else {
|
||||
prevNode = new LinkedList<>(prevNode);
|
||||
prevNode.add(selectorNode);
|
||||
}
|
||||
graph.appendNode(selectorNode);
|
||||
}
|
||||
switchStack.pop();
|
||||
// The next statement will be linked to:
|
||||
// 1. All break statements that broke from the switch
|
||||
// 2. If the switch doesn't have a default statement, the switch's selector
|
||||
// 3. If the last entry doesn't break, to the last statement
|
||||
prevNode = new LinkedList<>(prevNode); // 3
|
||||
prevNode.remove(selectorNode);
|
||||
prevNode.addAll(brokenStmts); // 1
|
||||
graph.removeNode(selectorNode);
|
||||
graph.appendNodes(brokenStmts); // 1
|
||||
brokenStmts.clear();
|
||||
if (n.getEntries().get(n.getEntries().size() - 1).getLabel().isPresent())
|
||||
prevNode.add(selectorNode); // 2
|
||||
graph.appendNode(selectorNode); // 2
|
||||
graph.endBlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(BreakStmt n, CFG graph) {
|
||||
if (!switchStack.isEmpty() && !n.getLabel().isPresent()) {
|
||||
graph.addNode(n);
|
||||
graph.connect(prevNode, n);
|
||||
graph.connectTo(n, false);
|
||||
brokenStmts.add(n);
|
||||
prevNode = Collections.emptyList();
|
||||
graph.clearNode();
|
||||
return;
|
||||
}
|
||||
super.visit(n, graph);
|
||||
|
@ -223,11 +171,6 @@ public class Visitador extends VoidVisitorAdapter<CFG> {
|
|||
|
||||
@Override
|
||||
public void visit(ExpressionStmt es, CFG graph) {
|
||||
graph.addNode(es);
|
||||
graph.connect(prevNode, es);
|
||||
prevNode = Collections.singletonList(es);
|
||||
|
||||
// Seguimos visitando...
|
||||
super.visit(es, graph);
|
||||
graph.connectTo(es);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue