From fd62f7f3519fc7ee3e5ecbed11fe0b1f8161fe15 Mon Sep 17 00:00:00 2001 From: Javier Costa Date: Sun, 2 Feb 2020 19:46:57 +0100 Subject: [PATCH 1/3] Graph extends from DirectedPseudograph and nodes equality is made by comparing its ids --- src/main/java/tfm/exec/PDGLog.java | 3 ++- src/main/java/tfm/graphs/Graph.java | 4 ++-- src/main/java/tfm/graphs/cfg/CFG.java | 6 +++--- src/main/java/tfm/nodes/GraphNode.java | 5 +++++ src/main/java/tfm/utils/ASTUtils.java | 5 +++++ 5 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/main/java/tfm/exec/PDGLog.java b/src/main/java/tfm/exec/PDGLog.java index 6634a78..5ed0162 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 45fe331..760d74b 100644 --- a/src/main/java/tfm/graphs/Graph.java +++ b/src/main/java/tfm/graphs/Graph.java @@ -1,7 +1,7 @@ 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; @@ -14,7 +14,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; diff --git a/src/main/java/tfm/graphs/cfg/CFG.java b/src/main/java/tfm/graphs/cfg/CFG.java index 1aed470..41c9697 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/nodes/GraphNode.java b/src/main/java/tfm/nodes/GraphNode.java index d8d6458..bf7fc88 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; @@ -117,6 +118,10 @@ public class GraphNode implements Comparable> { && Objects.equals(astNode, other.astNode); } + public boolean equalsWithASTNodeRange(Object o) { + return equals(o) && ASTUtils.equalsWithRange(((GraphNode) o).astNode, astNode); + } + @Override public int hashCode() { return Objects.hash(getId(), getInstruction(), getAstNode()); diff --git a/src/main/java/tfm/utils/ASTUtils.java b/src/main/java/tfm/utils/ASTUtils.java index e0c9320..1fdbf8f 100644 --- a/src/main/java/tfm/utils/ASTUtils.java +++ b/src/main/java/tfm/utils/ASTUtils.java @@ -77,4 +77,9 @@ 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); + } } -- GitLab From c6356b200dc63a9f7476162c13ba42f3ad4788b6 Mon Sep 17 00:00:00 2001 From: Javier Costa Date: Sun, 2 Feb 2020 23:17:32 +0100 Subject: [PATCH 2/3] Fixed data dependency --- src/main/java/tfm/graphs/Graph.java | 3 +- .../tfm/graphs/pdg/DataDependencyBuilder.java | 67 +++---------------- src/main/java/tfm/graphs/pdg/PDGBuilder.java | 8 ++- src/main/java/tfm/nodes/GraphNode.java | 13 ++-- src/main/java/tfm/utils/ASTUtils.java | 20 +++++- .../java/tfm/variables/VariableExtractor.java | 4 -- 6 files changed, 40 insertions(+), 75 deletions(-) diff --git a/src/main/java/tfm/graphs/Graph.java b/src/main/java/tfm/graphs/Graph.java index 760d74b..e20452c 100644 --- a/src/main/java/tfm/graphs/Graph.java +++ b/src/main/java/tfm/graphs/Graph.java @@ -6,6 +6,7 @@ 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; @@ -74,7 +75,7 @@ public abstract class Graph extends DirectedPseudograph, 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/pdg/DataDependencyBuilder.java b/src/main/java/tfm/graphs/pdg/DataDependencyBuilder.java index 7972730..42042b6 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 77d67ee..070b89c 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 bf7fc88..034a066 100644 --- a/src/main/java/tfm/nodes/GraphNode.java +++ b/src/main/java/tfm/nodes/GraphNode.java @@ -14,6 +14,7 @@ import java.util.Collection; import java.util.HashSet; import java.util.Objects; import java.util.Set; +import java.util.function.BiFunction; /** * Represents a node in the various graphs ({@link CFG CFG}, @@ -45,9 +46,7 @@ public class GraphNode implements Comparable> { Utils.emptySet() ); - if (astNode instanceof Statement) { - extractVariables((Statement) astNode); - } + extractVariables(astNode); } GraphNode( @@ -67,12 +66,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() { @@ -118,10 +117,6 @@ public class GraphNode implements Comparable> { && Objects.equals(astNode, other.astNode); } - public boolean equalsWithASTNodeRange(Object o) { - return equals(o) && ASTUtils.equalsWithRange(((GraphNode) o).astNode, astNode); - } - @Override public int hashCode() { return Objects.hash(getId(), getInstruction(), getAstNode()); diff --git a/src/main/java/tfm/utils/ASTUtils.java b/src/main/java/tfm/utils/ASTUtils.java index 1fdbf8f..7744e8b 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; @@ -79,7 +81,21 @@ public class ASTUtils { } public static boolean equalsWithRange(Node n1, Node n2) { - return Objects.equals(n1.getRange(), n2.getRange()) - && Objects.equals(n1, 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 add760a..962e538 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); -- GitLab From b3e8abeedb4d7f6d8c27c6ab8d868fa960910bac Mon Sep 17 00:00:00 2001 From: Javier Costa Date: Wed, 5 Feb 2020 15:00:36 +0100 Subject: [PATCH 3/3] Removed unused import in GraphNode class --- src/main/java/tfm/nodes/GraphNode.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/tfm/nodes/GraphNode.java b/src/main/java/tfm/nodes/GraphNode.java index 034a066..bd4e741 100644 --- a/src/main/java/tfm/nodes/GraphNode.java +++ b/src/main/java/tfm/nodes/GraphNode.java @@ -14,7 +14,6 @@ import java.util.Collection; import java.util.HashSet; import java.util.Objects; import java.util.Set; -import java.util.function.BiFunction; /** * Represents a node in the various graphs ({@link CFG CFG}, -- GitLab