diff --git a/src/main/java/tfm/exec/PDGLog.java b/src/main/java/tfm/exec/PDGLog.java index 6634a78aa903e725e1bc61807d1af36eee3da4d9..5ed01629705f85219e6f87e47e6ac12b549ea236 100644 --- a/src/main/java/tfm/exec/PDGLog.java +++ b/src/main/java/tfm/exec/PDGLog.java @@ -31,8 +31,9 @@ public class PDGLog extends GraphLog { Logger.log(graph.vertexSet().stream() .sorted(Comparator.comparingInt(GraphNode::getId)) .map(node -> - String.format("GraphNode { id: %s, declared: %s, defined: %s, used: %s }", + String.format("GraphNode { id: %s, instruction: %s, declared: %s, defined: %s, used: %s }", node.getId(), + node.getInstruction(), node.getDeclaredVariables(), node.getDefinedVariables(), node.getUsedVariables()) diff --git a/src/main/java/tfm/graphs/Graph.java b/src/main/java/tfm/graphs/Graph.java index 45fe331767e6a14f6350a941261346b86f884cec..e20452c91ccd102e56fc3dff9a3b6cc151fb9c69 100644 --- a/src/main/java/tfm/graphs/Graph.java +++ b/src/main/java/tfm/graphs/Graph.java @@ -1,11 +1,12 @@ package tfm.graphs; import com.github.javaparser.ast.Node; -import org.jgrapht.graph.DefaultDirectedGraph; +import org.jgrapht.graph.DirectedPseudograph; import org.jgrapht.io.DOTExporter; import tfm.arcs.Arc; import tfm.nodes.GraphNode; import tfm.nodes.NodeFactory; +import tfm.utils.ASTUtils; import java.util.*; import java.util.function.Consumer; @@ -14,7 +15,7 @@ import java.util.stream.Collectors; /** * * */ -public abstract class Graph extends DefaultDirectedGraph, Arc> { +public abstract class Graph extends DirectedPseudograph, Arc> { protected static final int DEFAULT_VERTEX_START_ID = 0; @@ -74,7 +75,7 @@ public abstract class Graph extends DefaultDirectedGraph, Arc> { @SuppressWarnings("unchecked") public Optional> findNodeByASTNode(ASTNode astNode) { return vertexSet().stream() - .filter(node -> Objects.equals(node.getAstNode(), astNode)) + .filter(node -> ASTUtils.equalsWithRangeInCU(node.getAstNode(), astNode)) .findFirst() .map(node -> (GraphNode) node); } diff --git a/src/main/java/tfm/graphs/cfg/CFG.java b/src/main/java/tfm/graphs/cfg/CFG.java index 1aed4700270570d3240ae1eb323c63433b506e7f..41c969756f6a6e29804e5a752774284f0e8b15c1 100644 --- a/src/main/java/tfm/graphs/cfg/CFG.java +++ b/src/main/java/tfm/graphs/cfg/CFG.java @@ -37,10 +37,10 @@ public class CFG extends GraphWithRootNode { public Set> findLastDefinitionsFrom(GraphNode startNode, String variable) { if (!this.containsVertex(startNode)) throw new NodeNotFoundException(startNode, this); - return findLastDefinitionsFrom(new HashSet<>(), startNode, startNode, variable); + return findLastDefinitionsFrom(new HashSet<>(), startNode.getId(), startNode, variable); } - private Set> findLastDefinitionsFrom(Set visited, GraphNode startNode, GraphNode currentNode, String variable) { + private Set> findLastDefinitionsFrom(Set visited, int startNode, GraphNode currentNode, String variable) { visited.add(currentNode.getId()); Set> res = new HashSet<>(); @@ -50,7 +50,7 @@ public class CFG extends GraphWithRootNode { continue; GraphNode from = getEdgeSource(arc); - if (!Objects.equals(startNode, from) && visited.contains(from.getId())) { + if (!Objects.equals(startNode, from.getId()) && visited.contains(from.getId())) { continue; } diff --git a/src/main/java/tfm/graphs/pdg/DataDependencyBuilder.java b/src/main/java/tfm/graphs/pdg/DataDependencyBuilder.java index 7972730e5750a1dce273148890304d8fe995552c..42042b666e3ac578cd1d4401322e46108e702d50 100644 --- a/src/main/java/tfm/graphs/pdg/DataDependencyBuilder.java +++ b/src/main/java/tfm/graphs/pdg/DataDependencyBuilder.java @@ -1,14 +1,10 @@ package tfm.graphs.pdg; +import com.github.javaparser.ast.Node; import com.github.javaparser.ast.stmt.*; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; import tfm.graphs.cfg.CFG; -import tfm.graphs.pdg.PDG; import tfm.nodes.GraphNode; -import tfm.variables.VariableExtractor; - -import java.util.Optional; -import java.util.Set; class DataDependencyBuilder extends VoidVisitorAdapter { @@ -43,17 +39,13 @@ class DataDependencyBuilder extends VoidVisitorAdapter { @Override public void visit(ForStmt forStmt, Void ignored) { - GraphNode forNode = pdg.findNodeByASTNode(forStmt).get(); - - forStmt.getInitialization().stream() - .map(ExpressionStmt::new) - .forEach(expressionStmt -> buildDataDependency(forNode, expressionStmt)); + forStmt.getInitialization() + .forEach(this::buildDataDependency); buildDataDependency(forStmt); // Only for comparison - forStmt.getUpdate().stream() - .map(ExpressionStmt::new) - .forEach(expressionStmt -> buildDataDependency(forNode, expressionStmt)); + forStmt.getUpdate() + .forEach(this::buildDataDependency); forStmt.getBody().accept(this, null); } @@ -79,51 +71,14 @@ class DataDependencyBuilder extends VoidVisitorAdapter { switchEntryStmt.getStatements().accept(this, null); } - private void buildDataDependency(Statement statement) { - buildDataDependency(pdg.findNodeByASTNode(statement).get()); + private void buildDataDependency(Node node) { + buildDataDependency(pdg.findNodeByASTNode(node).get()); } private void buildDataDependency(GraphNode node) { - new VariableExtractor() - .setOnVariableUseListener(variable -> { - node.addUsedVariable(variable); - - Optional> nodeOptional = cfg.findNodeByASTNode(node.getAstNode()); - - if (!nodeOptional.isPresent()) { - return; - } - - GraphNode cfgNode = nodeOptional.get(); - - Set> lastDefinitions = cfg.findLastDefinitionsFrom(cfgNode, variable); - - for (GraphNode definitionNode : lastDefinitions) { - pdg.findNodeByASTNode(definitionNode.getAstNode()) - .ifPresent(pdgNode -> pdg.addDataDependencyArc(pdgNode, node, variable)); - } - }) - .setOnVariableDefinitionListener(node::addDefinedVariable) - .setOnVariableDeclarationListener(node::addDeclaredVariable) - .visit(node.getAstNode()); - } - - // For statement special case - private void buildDataDependency(GraphNode forNode, Statement statement) { - new VariableExtractor() - .setOnVariableUseListener(variable -> { - forNode.addUsedVariable(variable); - - Optional> nodeOptional = cfg.findNodeByASTNode(statement); - - if (!nodeOptional.isPresent()) { - return; - } - - pdg.addDataDependencyArc(forNode, forNode, variable); - }) - .setOnVariableDefinitionListener(forNode::addDefinedVariable) - .setOnVariableDeclarationListener(forNode::addDeclaredVariable) - .visit(statement); + for (String usedVariable : node.getUsedVariables()) { + cfg.findLastDefinitionsFrom(node, usedVariable) + .forEach(definitionNode -> pdg.addDataDependencyArc(definitionNode, node, usedVariable)); + } } } diff --git a/src/main/java/tfm/graphs/pdg/PDGBuilder.java b/src/main/java/tfm/graphs/pdg/PDGBuilder.java index 77d67eedc6206b3c7a5457231dba17a139c4efbe..070b89cbeea0349f69e33d1e0066e75b56d8da43 100644 --- a/src/main/java/tfm/graphs/pdg/PDGBuilder.java +++ b/src/main/java/tfm/graphs/pdg/PDGBuilder.java @@ -5,6 +5,8 @@ import com.github.javaparser.ast.stmt.BlockStmt; import tfm.graphs.cfg.CFG; import tfm.nodes.GraphNode; +import java.util.Objects; + /** * Populates a {@link PDG}, given a complete {@link CFG}, an empty {@link PDG} and an AST root node. * For now it only accepts {@link MethodDeclaration} as root, as it can only receive a single CFG. @@ -47,9 +49,9 @@ public class PDGBuilder { cfg.build(methodDeclaration); // Copy nodes from CFG to PDG - for (GraphNode node : cfg.vertexSet()) - if (!node.equals(cfg.getExitNode())) - pdg.addVertex(node); + cfg.vertexSet().stream() + .filter(node -> !Objects.equals(node, cfg.getExitNode())) + .forEach(node -> pdg.addVertex(node)); // Build control dependency ControlDependencyBuilder controlDependencyBuilder = new ControlDependencyBuilder(pdg, cfg); diff --git a/src/main/java/tfm/nodes/GraphNode.java b/src/main/java/tfm/nodes/GraphNode.java index d8d645897f6a90e7bb0aad32abdc7f9ca310b991..bd4e741d28606ddef868b0a5ac06fc2f8263cbb2 100644 --- a/src/main/java/tfm/nodes/GraphNode.java +++ b/src/main/java/tfm/nodes/GraphNode.java @@ -6,6 +6,7 @@ import org.jetbrains.annotations.NotNull; import tfm.graphs.cfg.CFG; import tfm.graphs.pdg.PDG; import tfm.graphs.sdg.SDG; +import tfm.utils.ASTUtils; import tfm.utils.Utils; import tfm.variables.VariableExtractor; @@ -44,9 +45,7 @@ public class GraphNode implements Comparable> { Utils.emptySet() ); - if (astNode instanceof Statement) { - extractVariables((Statement) astNode); - } + extractVariables(astNode); } GraphNode( @@ -66,12 +65,12 @@ public class GraphNode implements Comparable> { this.usedVariables = new HashSet<>(usedVariables); } - private void extractVariables(@NotNull Statement statement) { + private void extractVariables(@NotNull Node node) { new VariableExtractor() .setOnVariableDeclarationListener(this.declaredVariables::add) .setOnVariableDefinitionListener(this.definedVariables::add) .setOnVariableUseListener(this.usedVariables::add) - .visit(statement); + .visit(node); } public int getId() { diff --git a/src/main/java/tfm/utils/ASTUtils.java b/src/main/java/tfm/utils/ASTUtils.java index e0c9320e855f9c28c5dbec06c1ece05cb9c3bd27..7744e8b349e7873193689f81f1558a57aa6fe238 100644 --- a/src/main/java/tfm/utils/ASTUtils.java +++ b/src/main/java/tfm/utils/ASTUtils.java @@ -1,7 +1,9 @@ package tfm.utils; +import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.Node; import com.github.javaparser.ast.NodeList; +import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; import com.github.javaparser.ast.stmt.*; import java.util.Objects; @@ -77,4 +79,23 @@ public class ASTUtils { || node instanceof TryStmt || node instanceof CatchClause; } + + public static boolean equalsWithRange(Node n1, Node n2) { + return Objects.equals(n1.getRange(), n2.getRange()) && Objects.equals(n1, n2); + } + + public static boolean equalsWithRangeInCU(Node n1, Node n2) { + // Find the compilation unit of each node + Optional optionalCompilationUnit1 = n1.findCompilationUnit(); + Optional optionalCompilationUnit2 = n2.findCompilationUnit(); + + // If they are inside the same compilation unit, compare with range + if (optionalCompilationUnit1.isPresent() && optionalCompilationUnit2.isPresent()) { + return Objects.equals(optionalCompilationUnit1.get(), optionalCompilationUnit2.get()) + && equalsWithRange(n1, n2); + } + + // If not, just compare with range + return equalsWithRange(n1, n2); + } } diff --git a/src/main/java/tfm/variables/VariableExtractor.java b/src/main/java/tfm/variables/VariableExtractor.java index add760a60047c96ffb7ad0ee00ca736ca10ae61b..962e5389061ee8d147a894fcee956e07f829c772 100644 --- a/src/main/java/tfm/variables/VariableExtractor.java +++ b/src/main/java/tfm/variables/VariableExtractor.java @@ -54,10 +54,6 @@ public class VariableExtractor { node.accept(this.visitor, VariableAction.Actions.USE); } - public void visit(@NonNull Expression expression) { - expression.accept(this.visitor, VariableAction.Actions.USE); - } - @FunctionalInterface public interface OnVariableDeclarationListener { void onVariableDeclaration(String variable);