package grafos; import com.github.javaparser.ast.Node; import com.github.javaparser.ast.NodeList; import com.github.javaparser.ast.body.MethodDeclaration; 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 { //********************************************************/ //********************** Atributos ***********************/ //********************************************************/ private List prevNode; private Stack switchStack = new Stack<>(); private List 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 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); } @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(); } @Override public void visit(IfStmt n, CFG graph) { Node ifStart = n.getCondition(); graph.addNode(ifStart); graph.connect(prevNode, ifStart); // TODO: shortcut conditions (||, &&) prevNode = Collections.singletonList(ifStart); List prevNodeBegin = prevNode; n.getThenStmt().accept(this, graph); List newPrev = new LinkedList<>(); if (prevNode == prevNodeBegin) newPrev.add(ifStart); else newPrev.addAll(prevNode); prevNode = Collections.singletonList(ifStart); if (n.getElseStmt().isPresent()) { n.getElseStmt().get().accept(this, graph); if (prevNode == prevNodeBegin) newPrev.add(ifStart); else newPrev.addAll(prevNode); } else { newPrev.add(ifStart); } prevNode = newPrev; } @Override public void visit(WhileStmt n, CFG graph) { Node whileStart = n.getCondition(); graph.addNode(whileStart); graph.connect(prevNode, whileStart); // TODO: shortcut conditions (||, &&) prevNode = Collections.singletonList(whileStart); n.getBody().accept(this, graph); graph.connect(prevNode, whileStart); prevNode = Collections.singletonList(whileStart); } @Override public void visit(DoStmt n, CFG graph) { prevNode = new LinkedList<>(prevNode); prevNode.add(n.getCondition()); n.getBody().accept(this, graph); graph.addNode(n.getCondition()); graph.connect(prevNode, n.getCondition()); prevNode = Collections.singletonList(n.getCondition()); } @Override public void visit(ForStmt n, CFG graph) { // Initialization expressions if (n.getInitialization() != null) { for (Expression e : n.getInitialization()) { graph.addNode(e); graph.connect(prevNode, e); prevNode = Collections.singletonList(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()); } // 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); } } // 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()); else // There is no comparison, can't exit the loop TODO implement break and continue as way to exit prevNode = Collections.emptyList(); } @Override public void visit(ForeachStmt n, CFG graph) { ForeachStmt copy = new ForeachStmt(n.getTokenRange().orElse(null), n.getVariable(), n.getIterable(), new EmptyStmt()); graph.addNode(copy); graph.connect(prevNode, copy); prevNode = Collections.singletonList(copy); n.getBody().accept(this, graph); graph.connect(prevNode, copy); prevNode = Collections.singletonList(copy); } @Override 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); // Case body n.getStatements().accept(this, graph); } @Override public void visit(SwitchStmt n, CFG graph) { // Link previous statement to the switch's selector Node selectorNode = new SwitchStmt(n.getTokenRange().orElse(null), n.getSelector(), new NodeList<>()); graph.addNode(selectorNode); graph.connect(prevNode, 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); } } 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 if (n.getEntries().get(n.getEntries().size() - 1).getLabel().isPresent()) prevNode.add(selectorNode); // 2 } @Override public void visit(BreakStmt n, CFG graph) { if (!switchStack.isEmpty() && !n.getLabel().isPresent()) { graph.addNode(n); graph.connect(prevNode, n); brokenStmts.add(n); prevNode = Collections.emptyList(); return; } super.visit(n, graph); } @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); } }