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