Loading src/main/java/tfm/graphs/Graph.java +2 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -74,7 +75,7 @@ public abstract class Graph extends DirectedPseudograph<GraphNode<?>, Arc> { @SuppressWarnings("unchecked") public <ASTNode extends Node> Optional<GraphNode<ASTNode>> findNodeByASTNode(ASTNode astNode) { return vertexSet().stream() .filter(node -> Objects.equals(node.getAstNode(), astNode)) .filter(node -> ASTUtils.equalsWithRangeInCU(node.getAstNode(), astNode)) .findFirst() .map(node -> (GraphNode<ASTNode>) node); } Loading src/main/java/tfm/graphs/pdg/DataDependencyBuilder.java +11 −56 Original line number Diff line number Diff line 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<Void> { Loading Loading @@ -43,17 +39,13 @@ class DataDependencyBuilder extends VoidVisitorAdapter<Void> { @Override public void visit(ForStmt forStmt, Void ignored) { GraphNode<ForStmt> 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); } Loading @@ -79,51 +71,14 @@ class DataDependencyBuilder extends VoidVisitorAdapter<Void> { 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<? extends GraphNode<?>> nodeOptional = cfg.findNodeByASTNode(node.getAstNode()); if (!nodeOptional.isPresent()) { return; } GraphNode<?> cfgNode = nodeOptional.get(); Set<GraphNode<?>> 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 (String usedVariable : node.getUsedVariables()) { cfg.findLastDefinitionsFrom(node, usedVariable) .forEach(definitionNode -> pdg.addDataDependencyArc(definitionNode, node, usedVariable)); } // For statement special case private void buildDataDependency(GraphNode<?> forNode, Statement statement) { new VariableExtractor() .setOnVariableUseListener(variable -> { forNode.addUsedVariable(variable); Optional<? extends GraphNode<?>> nodeOptional = cfg.findNodeByASTNode(statement); if (!nodeOptional.isPresent()) { return; } pdg.addDataDependencyArc(forNode, forNode, variable); }) .setOnVariableDefinitionListener(forNode::addDefinedVariable) .setOnVariableDeclarationListener(forNode::addDeclaredVariable) .visit(statement); } } src/main/java/tfm/graphs/pdg/PDGBuilder.java +5 −3 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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); Loading src/main/java/tfm/nodes/GraphNode.java +4 −9 Original line number Diff line number Diff line Loading @@ -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}, Loading Loading @@ -45,9 +46,7 @@ public class GraphNode<N extends Node> implements Comparable<GraphNode<?>> { Utils.emptySet() ); if (astNode instanceof Statement) { extractVariables((Statement) astNode); } extractVariables(astNode); } GraphNode( Loading @@ -67,12 +66,12 @@ public class GraphNode<N extends Node> implements Comparable<GraphNode<?>> { 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() { Loading Loading @@ -118,10 +117,6 @@ public class GraphNode<N extends Node> implements Comparable<GraphNode<?>> { && 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()); Loading src/main/java/tfm/utils/ASTUtils.java +18 −2 Original line number Diff line number Diff line 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; Loading Loading @@ -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<CompilationUnit> optionalCompilationUnit1 = n1.findCompilationUnit(); Optional<CompilationUnit> 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); } } Loading
src/main/java/tfm/graphs/Graph.java +2 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -74,7 +75,7 @@ public abstract class Graph extends DirectedPseudograph<GraphNode<?>, Arc> { @SuppressWarnings("unchecked") public <ASTNode extends Node> Optional<GraphNode<ASTNode>> findNodeByASTNode(ASTNode astNode) { return vertexSet().stream() .filter(node -> Objects.equals(node.getAstNode(), astNode)) .filter(node -> ASTUtils.equalsWithRangeInCU(node.getAstNode(), astNode)) .findFirst() .map(node -> (GraphNode<ASTNode>) node); } Loading
src/main/java/tfm/graphs/pdg/DataDependencyBuilder.java +11 −56 Original line number Diff line number Diff line 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<Void> { Loading Loading @@ -43,17 +39,13 @@ class DataDependencyBuilder extends VoidVisitorAdapter<Void> { @Override public void visit(ForStmt forStmt, Void ignored) { GraphNode<ForStmt> 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); } Loading @@ -79,51 +71,14 @@ class DataDependencyBuilder extends VoidVisitorAdapter<Void> { 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<? extends GraphNode<?>> nodeOptional = cfg.findNodeByASTNode(node.getAstNode()); if (!nodeOptional.isPresent()) { return; } GraphNode<?> cfgNode = nodeOptional.get(); Set<GraphNode<?>> 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 (String usedVariable : node.getUsedVariables()) { cfg.findLastDefinitionsFrom(node, usedVariable) .forEach(definitionNode -> pdg.addDataDependencyArc(definitionNode, node, usedVariable)); } // For statement special case private void buildDataDependency(GraphNode<?> forNode, Statement statement) { new VariableExtractor() .setOnVariableUseListener(variable -> { forNode.addUsedVariable(variable); Optional<? extends GraphNode<?>> nodeOptional = cfg.findNodeByASTNode(statement); if (!nodeOptional.isPresent()) { return; } pdg.addDataDependencyArc(forNode, forNode, variable); }) .setOnVariableDefinitionListener(forNode::addDefinedVariable) .setOnVariableDeclarationListener(forNode::addDeclaredVariable) .visit(statement); } }
src/main/java/tfm/graphs/pdg/PDGBuilder.java +5 −3 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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); Loading
src/main/java/tfm/nodes/GraphNode.java +4 −9 Original line number Diff line number Diff line Loading @@ -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}, Loading Loading @@ -45,9 +46,7 @@ public class GraphNode<N extends Node> implements Comparable<GraphNode<?>> { Utils.emptySet() ); if (astNode instanceof Statement) { extractVariables((Statement) astNode); } extractVariables(astNode); } GraphNode( Loading @@ -67,12 +66,12 @@ public class GraphNode<N extends Node> implements Comparable<GraphNode<?>> { 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() { Loading Loading @@ -118,10 +117,6 @@ public class GraphNode<N extends Node> implements Comparable<GraphNode<?>> { && 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()); Loading
src/main/java/tfm/utils/ASTUtils.java +18 −2 Original line number Diff line number Diff line 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; Loading Loading @@ -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<CompilationUnit> optionalCompilationUnit1 = n1.findCompilationUnit(); Optional<CompilationUnit> 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); } }