From 6db0410250683c657352847b24b32ab65a331f6d Mon Sep 17 00:00:00 2001 From: syntax Date: Fri, 8 Nov 2024 15:17:12 +0000 Subject: [PATCH 1/3] refactor towards decoupling --- src/main/java/org/pdgdiff/Main.java | 12 +-- .../org/pdgdiff/edit/EditScriptGenerator.java | 46 +++++----- .../java/org/pdgdiff/edit/model/Delete.java | 3 +- .../org/pdgdiff/edit/model/EditOperation.java | 7 +- .../java/org/pdgdiff/edit/model/Insert.java | 3 +- .../java/org/pdgdiff/edit/model/Move.java | 3 +- .../pdgdiff/edit/model/SyntaxDifference.java | 15 ++-- .../java/org/pdgdiff/edit/model/Update.java | 3 +- .../org/pdgdiff/graph/GraphGenerator.java | 71 +++++++++++++-- .../org/pdgdiff/graph/GraphTraversal.java | 69 +++++++------- .../java/org/pdgdiff/graph/model/MyPDG.java | 55 ++++++++++++ .../org/pdgdiff/graph/model/MyPDGNode.java | 89 +++++++++++++++++++ .../pdgdiff/graph/model/MyPDGNodeType.java | 7 ++ .../org/pdgdiff/matching/GraphMapping.java | 17 ++-- .../org/pdgdiff/matching/GraphMatcher.java | 10 +-- .../pdgdiff/matching/GraphMatcherFactory.java | 4 +- .../org/pdgdiff/matching/NodeMapping.java | 24 ++--- .../org/pdgdiff/matching/PDGComparator.java | 11 +-- .../models/HeuristicGraphMatcher.java | 9 +- .../matching/models/UllmannGraphMatcher.java | 19 ++-- .../matching/models/VF2GraphMatcher.java | 23 ++--- .../models/heuristic/HeuristicMatcher.java | 22 ++--- .../models/ullmann/UllmannMatcher.java | 28 +++--- .../matching/models/vf2/VF2Matcher.java | 13 ++- .../pdgdiff/matching/models/vf2/VF2State.java | 71 +++++++-------- 25 files changed, 429 insertions(+), 205 deletions(-) create mode 100644 src/main/java/org/pdgdiff/graph/model/MyPDG.java create mode 100644 src/main/java/org/pdgdiff/graph/model/MyPDGNode.java create mode 100644 src/main/java/org/pdgdiff/graph/model/MyPDGNodeType.java diff --git a/src/main/java/org/pdgdiff/Main.java b/src/main/java/org/pdgdiff/Main.java index b6bf166..c7246f8 100644 --- a/src/main/java/org/pdgdiff/Main.java +++ b/src/main/java/org/pdgdiff/Main.java @@ -2,6 +2,8 @@ import org.pdgdiff.graph.GraphExporter; import org.pdgdiff.graph.GraphGenerator; +import org.pdgdiff.graph.model.MyPDG; +import org.pdgdiff.graph.model.MyPDGNode; import org.pdgdiff.matching.PDGComparator; import org.pdgdiff.util.SootInitializer; import soot.Scene; @@ -36,8 +38,8 @@ public static void main(String[] args) { SootClass testAdder2 = Scene.v().getSootClass(class2Name); // Generate PDGs for all methods in both classes and store in lists - List pdgsClass1 = generatePDGsForClass(testAdder1); - List pdgsClass2 = generatePDGsForClass(testAdder2); + List pdgsClass1 = generatePDGsForClass(testAdder1); + List pdgsClass2 = generatePDGsForClass(testAdder2); // Print the number of PDGs generated for each class System.out.println("PDGs generated for " + testAdder1.getName() + ": " + pdgsClass1.size()); @@ -57,8 +59,8 @@ public static void main(String[] args) { } // Method to generate PDGs for all methods in a given class and store them in a list - private static List generatePDGsForClass(SootClass sootClass) { - List pdgList = new ArrayList<>(); + private static List generatePDGsForClass(SootClass sootClass) { + List pdgList = new ArrayList<>(); System.out.println("Generating PDGs for class: " + sootClass.getName()); // TODO investigate getting metadata from here. // Iterate over each method in the class @@ -70,7 +72,7 @@ private static List generatePDGsForClass(SootClass sootClass) { System.out.println("Successfully retrieved active body for: " + method.getName() + " in " + sootClass.getName()); // Generate the PDG for the method - HashMutablePDG pdg = GraphGenerator.generatePDG(sootClass, method); + MyPDG pdg = GraphGenerator.generatePDG(sootClass, method); if (pdg != null) { pdgList.add(pdg); System.out.println("PDG generated for method: " + method.getName()); diff --git a/src/main/java/org/pdgdiff/edit/EditScriptGenerator.java b/src/main/java/org/pdgdiff/edit/EditScriptGenerator.java index c556957..e496f0d 100644 --- a/src/main/java/org/pdgdiff/edit/EditScriptGenerator.java +++ b/src/main/java/org/pdgdiff/edit/EditScriptGenerator.java @@ -1,6 +1,8 @@ package org.pdgdiff.edit; import org.pdgdiff.edit.model.*; +import org.pdgdiff.graph.model.MyPDG; +import org.pdgdiff.graph.model.MyPDGNode; import org.pdgdiff.matching.GraphMapping; import org.pdgdiff.matching.NodeMapping; import org.pdgdiff.util.CodeAnalysisUtils; @@ -21,8 +23,8 @@ public class EditScriptGenerator { public static List generateEditScript( - HashMutablePDG srcPDG, - HashMutablePDG dstPDG, + MyPDG srcPDG, + MyPDG dstPDG, GraphMapping graphMapping, String srcSourceFilePath, String dstSourceFilePath, @@ -38,15 +40,15 @@ public static List generateEditScript( NodeMapping nodeMapping = graphMapping.getNodeMapping(srcPDG); - Map mappings = nodeMapping.getNodeMapping(); - Set srcNodesMapped = mappings.keySet(); - Set dstNodesMapped = new HashSet<>(mappings.values()); + Map mappings = nodeMapping.getNodeMapping(); + Set srcNodesMapped = mappings.keySet(); + Set dstNodesMapped = new HashSet<>(mappings.values()); - Set visitedNodes = new HashSet<>(); + Set visitedNodes = new HashSet<>(); // process mapped nodes for updates or moves - for (PDGNode srcNode : srcNodesMapped) { - PDGNode dstNode = mappings.get(srcNode); + for (MyPDGNode srcNode : srcNodesMapped) { + MyPDGNode dstNode = mappings.get(srcNode); if (!visitedNodes.contains(srcNode)) { ComparisonResult compResult = nodesAreEqual(srcNode, dstNode, visitedNodes, srcCodeMapper, dstCodeMapper, nodeMapping); @@ -63,7 +65,7 @@ public static List generateEditScript( int newLineNumber = syntaxDiff.getNewLineNumber(); String oldCodeSnippet = syntaxDiff.getOldCodeSnippet(); String newCodeSnippet = syntaxDiff.getNewCodeSnippet(); - PDGNode node = srcNode; + MyPDGNode node = srcNode; Update update = new Update(node, oldLineNumber, newLineNumber, oldCodeSnippet, newCodeSnippet, syntaxDiff); editScriptSet.add(update); } @@ -73,7 +75,7 @@ public static List generateEditScript( } // handle deletions - for (PDGNode srcNode : srcPDG) { + for (MyPDGNode srcNode : srcPDG) { if (!srcNodesMapped.contains(srcNode) && !visitedNodes.contains(srcNode)) { int lineNumber = getNodeLineNumber(srcNode); String codeSnippet = srcCodeMapper.getCodeLine(lineNumber); @@ -82,7 +84,7 @@ public static List generateEditScript( } // handle insertions - for (PDGNode dstNode : dstPDG) { + for (MyPDGNode dstNode : dstPDG) { if (!dstNodesMapped.contains(dstNode) && !visitedNodes.contains(dstNode)) { int lineNumber = getNodeLineNumber(dstNode); String codeSnippet = dstCodeMapper.getCodeLine(lineNumber); @@ -147,7 +149,7 @@ public static int getNodeLineNumber(PDGNode node) { return -1; } - private static ComparisonResult nodesAreEqual(PDGNode n1, PDGNode n2, Set visitedNodes, + private static ComparisonResult nodesAreEqual(MyPDGNode n1, MyPDGNode n2, Set visitedNodes, SourceCodeMapper srcCodeMapper, SourceCodeMapper dstCodeMapper, NodeMapping nodeMapping) { if (visitedNodes.contains(n1)) { @@ -181,11 +183,11 @@ private static ComparisonResult compareRegionNodes(PDGNode n1, PDGNode n2, Set

differences = compareUnitLists(units1, units2, srcCodeMapper, dstCodeMapper); // recurively compare child regions - List childNodes1 = getRegionChildNodes(n1); - List childNodes2 = getRegionChildNodes(n2); + List childNodes1 = getRegionChildNodes(n1); + List childNodes2 = getRegionChildNodes(n2); - for (PDGNode child1 : childNodes1) { - PDGNode child2 = nodeMapping.getMappedNode(child1); + for (MyPDGNode child1 : childNodes1) { + MyPDGNode child2 = nodeMapping.getMappedNode(child1); if (child2 != null) { ComparisonResult compResult = nodesAreEqual(child1, child2, visitedNodes, srcCodeMapper, dstCodeMapper, nodeMapping); if (!compResult.isEqual) { @@ -197,8 +199,8 @@ private static ComparisonResult compareRegionNodes(PDGNode n1, PDGNode n2, Set

getRegionChildNodes(PDGNode regionNode) { - List childNodes = new ArrayList<>(); - for (PDGNode dependent : regionNode.getDependents()) { + private static List getRegionChildNodes(MyPDGNode regionNode) { + List childNodes = new ArrayList<>(); + for (MyPDGNode dependent : regionNode.getDependents()) { childNodes.add(dependent); } return childNodes; } - private static ComparisonResult compareCFGNodes(PDGNode n1, PDGNode n2, + private static ComparisonResult compareCFGNodes(MyPDGNode n1, MyPDGNode n2, SourceCodeMapper srcCodeMapper, SourceCodeMapper dstCodeMapper) { Block block1 = (Block) n1.getNode(); Block block2 = (Block) n2.getNode(); diff --git a/src/main/java/org/pdgdiff/edit/model/Delete.java b/src/main/java/org/pdgdiff/edit/model/Delete.java index 85ef93b..7e7b504 100644 --- a/src/main/java/org/pdgdiff/edit/model/Delete.java +++ b/src/main/java/org/pdgdiff/edit/model/Delete.java @@ -1,5 +1,6 @@ package org.pdgdiff.edit.model; +import org.pdgdiff.graph.model.MyPDGNode; import soot.toolkits.graph.pdg.PDGNode; import java.util.Objects; @@ -8,7 +9,7 @@ public class Delete extends EditOperation { private int lineNumber; private String codeSnippet; - public Delete(PDGNode node, int lineNumber, String codeSnippet) { + public Delete(MyPDGNode node, int lineNumber, String codeSnippet) { super(node); this.lineNumber = lineNumber; this.codeSnippet = codeSnippet; diff --git a/src/main/java/org/pdgdiff/edit/model/EditOperation.java b/src/main/java/org/pdgdiff/edit/model/EditOperation.java index ade98e0..81de72f 100644 --- a/src/main/java/org/pdgdiff/edit/model/EditOperation.java +++ b/src/main/java/org/pdgdiff/edit/model/EditOperation.java @@ -1,15 +1,16 @@ package org.pdgdiff.edit.model; +import org.pdgdiff.graph.model.MyPDGNode; import soot.toolkits.graph.pdg.PDGNode; public abstract class EditOperation { - protected PDGNode node; + protected MyPDGNode node; - public EditOperation(PDGNode node) { + public EditOperation(MyPDGNode node) { this.node = node; } - public PDGNode getNode() { + public MyPDGNode getNode() { return node; } diff --git a/src/main/java/org/pdgdiff/edit/model/Insert.java b/src/main/java/org/pdgdiff/edit/model/Insert.java index b7634cd..1b4ae6e 100644 --- a/src/main/java/org/pdgdiff/edit/model/Insert.java +++ b/src/main/java/org/pdgdiff/edit/model/Insert.java @@ -1,5 +1,6 @@ package org.pdgdiff.edit.model; +import org.pdgdiff.graph.model.MyPDGNode; import soot.toolkits.graph.pdg.PDGNode; import java.util.Objects; @@ -8,7 +9,7 @@ public class Insert extends EditOperation { private int lineNumber; private String codeSnippet; - public Insert(PDGNode node, int lineNumber, String codeSnippet) { + public Insert(MyPDGNode node, int lineNumber, String codeSnippet) { super(node); this.lineNumber = lineNumber; this.codeSnippet = codeSnippet; diff --git a/src/main/java/org/pdgdiff/edit/model/Move.java b/src/main/java/org/pdgdiff/edit/model/Move.java index b607f44..d19edd9 100644 --- a/src/main/java/org/pdgdiff/edit/model/Move.java +++ b/src/main/java/org/pdgdiff/edit/model/Move.java @@ -1,5 +1,6 @@ package org.pdgdiff.edit.model; +import org.pdgdiff.graph.model.MyPDGNode; import soot.toolkits.graph.pdg.PDGNode; import java.util.Objects; @@ -13,7 +14,7 @@ public class Move extends EditOperation { private int newLineNumber; private String codeSnippet; - public Move(PDGNode node, int oldLineNumber, int newLineNumber, String codeSnippet) { + public Move(MyPDGNode node, int oldLineNumber, int newLineNumber, String codeSnippet) { super(node); this.oldLineNumber = oldLineNumber; this.newLineNumber = newLineNumber; diff --git a/src/main/java/org/pdgdiff/edit/model/SyntaxDifference.java b/src/main/java/org/pdgdiff/edit/model/SyntaxDifference.java index 7c69990..a35b322 100644 --- a/src/main/java/org/pdgdiff/edit/model/SyntaxDifference.java +++ b/src/main/java/org/pdgdiff/edit/model/SyntaxDifference.java @@ -1,6 +1,7 @@ package org.pdgdiff.edit.model; import org.pdgdiff.edit.EditScriptGenerator; +import org.pdgdiff.graph.model.MyPDGNode; import org.pdgdiff.util.SourceCodeMapper; import soot.Unit; import soot.tagkit.LineNumberTag; @@ -14,8 +15,8 @@ public class SyntaxDifference { private Unit oldUnit; private Unit newUnit; - private PDGNode oldNode; - private PDGNode newNode; + private MyPDGNode oldNode; + private MyPDGNode newNode; private String message; private int oldLineNumber; @@ -38,7 +39,7 @@ public SyntaxDifference(Unit oldUnit, Unit newUnit, this.newJimpleCode = newUnit != null ? newUnit.toString() : null; } - public SyntaxDifference(PDGNode oldNode, PDGNode newNode, + public SyntaxDifference(MyPDGNode oldNode, MyPDGNode newNode, SourceCodeMapper oldSourceMapper, SourceCodeMapper newSourceMapper) { this.oldNode = oldNode; this.newNode = newNode; @@ -62,11 +63,11 @@ public Unit getNewUnit() { return newUnit; } - public PDGNode getOldNode() { + public MyPDGNode getOldNode() { return oldNode; } - public PDGNode getNewNode() { + public MyPDGNode getNewNode() { return newNode; } @@ -133,14 +134,14 @@ private int getLineNumber(Unit unit) { return -1; } - private int getNodeLineNumber(PDGNode node) { + private int getNodeLineNumber(MyPDGNode node) { if (node == null) { return -1; } return EditScriptGenerator.getNodeLineNumber(node); } - private String getNodeCodeSnippet(PDGNode node, SourceCodeMapper codeMapper) { + private String getNodeCodeSnippet(MyPDGNode node, SourceCodeMapper codeMapper) { int lineNumber = getNodeLineNumber(node); if (lineNumber != -1) { return codeMapper.getCodeLine(lineNumber); diff --git a/src/main/java/org/pdgdiff/edit/model/Update.java b/src/main/java/org/pdgdiff/edit/model/Update.java index 77a7775..2df259b 100644 --- a/src/main/java/org/pdgdiff/edit/model/Update.java +++ b/src/main/java/org/pdgdiff/edit/model/Update.java @@ -1,5 +1,6 @@ package org.pdgdiff.edit.model; +import org.pdgdiff.graph.model.MyPDGNode; import soot.toolkits.graph.pdg.PDGNode; import java.util.Objects; @@ -14,7 +15,7 @@ public class Update extends EditOperation { private String newCodeSnippet; private SyntaxDifference syntaxDifference; - public Update(PDGNode node, int oldLineNumber, int newLineNumber, + public Update(MyPDGNode node, int oldLineNumber, int newLineNumber, String oldCodeSnippet, String newCodeSnippet, SyntaxDifference syntaxDifference) { super(node); diff --git a/src/main/java/org/pdgdiff/graph/GraphGenerator.java b/src/main/java/org/pdgdiff/graph/GraphGenerator.java index 37e5d28..d224d34 100644 --- a/src/main/java/org/pdgdiff/graph/GraphGenerator.java +++ b/src/main/java/org/pdgdiff/graph/GraphGenerator.java @@ -1,33 +1,88 @@ package org.pdgdiff.graph; +import org.pdgdiff.graph.model.MyPDG; +import org.pdgdiff.graph.model.MyPDGNode; +import org.pdgdiff.graph.model.MyPDGNodeType; import soot.Body; import soot.SootClass; import soot.SootMethod; +import soot.Unit; +import soot.tagkit.LineNumberTag; import soot.toolkits.graph.ExceptionalUnitGraph; import soot.toolkits.graph.UnitGraph; import soot.toolkits.graph.pdg.HashMutablePDG; +import soot.toolkits.graph.pdg.PDGNode; + +import java.util.HashMap; +import java.util.Map; -/** - * GraphGenerator class to generate a Program Dependency Graph (PDG) for a specific method - */ public class GraphGenerator { - // Method to generate PDG for a specific method - public static HashMutablePDG generatePDG(SootClass sootClass, SootMethod method) { + public static MyPDG generatePDG(SootClass sootClass, SootMethod method) { try { Body body = method.retrieveActiveBody(); - // TODO: invesigate optimisations applied a thtis point, probably. UnitGraph unitGraph = new ExceptionalUnitGraph(body); + HashMutablePDG sootPDG = new HashMutablePDG(unitGraph); + + // Convert Soot PDG to MyPDG + MyPDG myPDG = new MyPDG(); + myPDG.setMethodSignature(method.getSignature()); + myPDG.setMethod(method); + + // Map to keep track of node correspondences + Map nodeMap = new HashMap<>(); + + // Create MyPDGNodes + for (PDGNode sootNode : sootPDG) { + MyPDGNodeType type = MyPDGNodeType.valueOf(sootNode.getType().name()); + String attrib = sootNode.getAttrib() != null ? sootNode.getAttrib().toString() : ""; + + // Extract line number if available + int lineNumber = extractLineNumber(sootNode); + + MyPDGNode myNode = new MyPDGNode(sootNode.getNode(), type, attrib); + myNode.setLineNumber(lineNumber); + nodeMap.put(sootNode, myNode); + myPDG.addNode(myNode); + } - HashMutablePDG pdg = new HashMutablePDG(unitGraph); + // Set start node + PDGNode sootStartNode = sootPDG.GetStartNode(); + MyPDGNode myStartNode = nodeMap.get(sootStartNode); + myPDG.setStartNode(myStartNode); + + // Set dependents and back-dependents + for (PDGNode sootNode : sootPDG) { + MyPDGNode myNode = nodeMap.get(sootNode); + + for (PDGNode dep : sootNode.getDependents()) { + myNode.addDependent(nodeMap.get(dep)); + } + + for (PDGNode backDep : sootNode.getBackDependets()) { + myNode.addBackDependent(nodeMap.get(backDep)); + } + } System.out.println("PDG for method " + method.getName() + " generated"); - return pdg; + return myPDG; } catch (Exception e) { System.err.println("Error generating PDG for method: " + method.getName()); e.printStackTrace(); return null; } } + + private static int extractLineNumber(PDGNode node) { + Object nodeObj = node.getNode(); + if (nodeObj instanceof Unit) { + Unit unit = (Unit) nodeObj; + LineNumberTag tag = (LineNumberTag) unit.getTag("LineNumberTag"); + if (tag != null) { + return tag.getLineNumber(); + } + } + return -1; + } } diff --git a/src/main/java/org/pdgdiff/graph/GraphTraversal.java b/src/main/java/org/pdgdiff/graph/GraphTraversal.java index 3df4e78..a3bc10e 100644 --- a/src/main/java/org/pdgdiff/graph/GraphTraversal.java +++ b/src/main/java/org/pdgdiff/graph/GraphTraversal.java @@ -1,7 +1,8 @@ package org.pdgdiff.graph; -import soot.toolkits.graph.pdg.HashMutablePDG; -import soot.toolkits.graph.pdg.PDGNode; + +import org.pdgdiff.graph.model.MyPDG; +import org.pdgdiff.graph.model.MyPDGNode; import java.util.*; @@ -18,32 +19,32 @@ public static void setLogging(boolean enable) { } // Method to traverse the graph using a breadth-first search and collect all nodes - public static List collectNodesBFS(HashMutablePDG pdg) { + public static List collectNodesBFS(MyPDG pdg) { if (debug) System.out.println("[BFS] Traversing graph"); - PDGNode start_node = pdg.GetStartNode(); - List nodeList = new ArrayList<>(); + MyPDGNode startNode = pdg.getStartNode(); + List nodeList = new ArrayList<>(); - if (start_node == null) { + if (startNode == null) { if (debug) System.out.println("[BFS] No start node found in the PDG."); return nodeList; } - Queue queue = new LinkedList<>(); - Set visited = new HashSet<>(); + Queue queue = new LinkedList<>(); + Set visited = new HashSet<>(); - queue.add(start_node); - visited.add(start_node); - nodeList.add(start_node); + queue.add(startNode); + visited.add(startNode); + nodeList.add(startNode); // Begin BFS while (!queue.isEmpty()) { - PDGNode current_node = queue.poll(); - if (debug) System.out.println("[BFS] Visiting node: " + current_node.toShortString()); + MyPDGNode currentNode = queue.poll(); + if (debug) System.out.println("[BFS] Visiting node: " + currentNode.toShortString()); // Add dependents to the queue - List dependents = current_node.getDependents(); - for (PDGNode dependent : dependents) { + List dependents = currentNode.getDependents(); + for (MyPDGNode dependent : dependents) { if (!visited.contains(dependent)) { queue.add(dependent); visited.add(dependent); @@ -57,32 +58,32 @@ public static List collectNodesBFS(HashMutablePDG pdg) { } // Method to traverse the graph using a depth-first search and collect all nodes - public static List collectNodesDFS(HashMutablePDG pdg) { + public static List collectNodesDFS(MyPDG pdg) { if (debug) System.out.println("[DFS] Traversing graph"); - PDGNode start_node = pdg.GetStartNode(); - List nodeList = new ArrayList<>(); + MyPDGNode startNode = pdg.getStartNode(); + List nodeList = new ArrayList<>(); - if (start_node == null) { + if (startNode == null) { if (debug) System.out.println("[DFS] No start node found in the PDG."); return nodeList; } - Stack stack = new Stack<>(); - Set visited = new HashSet<>(); + Stack stack = new Stack<>(); + Set visited = new HashSet<>(); - stack.push(start_node); - visited.add(start_node); - nodeList.add(start_node); + stack.push(startNode); + visited.add(startNode); + nodeList.add(startNode); // Begin DFS while (!stack.isEmpty()) { - PDGNode current_node = stack.pop(); - if (debug) System.out.println("[DFS] Visiting node: " + current_node.toShortString()); + MyPDGNode currentNode = stack.pop(); + if (debug) System.out.println("[DFS] Visiting node: " + currentNode.toShortString()); // Add dependents to the stack - List dependents = current_node.getDependents(); - for (PDGNode dependent : dependents) { + List dependents = currentNode.getDependents(); + for (MyPDGNode dependent : dependents) { if (!visited.contains(dependent)) { stack.push(dependent); visited.add(dependent); @@ -95,14 +96,10 @@ public static List collectNodesDFS(HashMutablePDG pdg) { return nodeList; } - public static int getNodeCount(HashMutablePDG pdg) { - List nodeList = collectNodesBFS(pdg); - return nodeList.size(); - } - - // Optionally, if you have already collected nodes and want to avoid traversal: - public static int getNodeCount(List nodeList) { + public static int getNodeCount(MyPDG pdg) { + List nodeList = collectNodesBFS(pdg); return nodeList.size(); } -} + public static int getNodeCount(List nodeList) { return nodeList.size(); } +} \ No newline at end of file diff --git a/src/main/java/org/pdgdiff/graph/model/MyPDG.java b/src/main/java/org/pdgdiff/graph/model/MyPDG.java new file mode 100644 index 0000000..bef66ef --- /dev/null +++ b/src/main/java/org/pdgdiff/graph/model/MyPDG.java @@ -0,0 +1,55 @@ +package org.pdgdiff.graph.model; + +import soot.SootMethod; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class MyPDG implements Iterable { + private MyPDGNode startNode; + private List nodes; + private String methodSignature; + private SootMethod method; + + public MyPDG() { + this.nodes = new ArrayList<>(); + } + + public void setStartNode(MyPDGNode startNode) { + this.startNode = startNode; + } + + public MyPDGNode getStartNode() { + return startNode; + } + + public void addNode(MyPDGNode node) { + nodes.add(node); + } + + public List getNodes() { + return nodes; + } + + public void setMethodSignature(String methodSignature) { + this.methodSignature = methodSignature; + } + + public String getMethodSignature() { + return methodSignature; + } + + public void setMethod(SootMethod method) { + this.method = method; + } + + public SootMethod getMethod() { + return method; + } + + @Override + public Iterator iterator() { + return nodes.iterator(); + } +} diff --git a/src/main/java/org/pdgdiff/graph/model/MyPDGNode.java b/src/main/java/org/pdgdiff/graph/model/MyPDGNode.java new file mode 100644 index 0000000..c36c391 --- /dev/null +++ b/src/main/java/org/pdgdiff/graph/model/MyPDGNode.java @@ -0,0 +1,89 @@ +package org.pdgdiff.graph.model; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public class MyPDGNode { + private Object node; + private MyPDGNodeType type; + private String attrib; + private List dependents; + private List backDependents; + private int lineNumber; + + public MyPDGNode(Object node, MyPDGNodeType type, String attrib) { + this.node = node; + this.type = type; + this.attrib = attrib; + this.dependents = new ArrayList<>(); + this.backDependents = new ArrayList<>(); + } + + public Object getNode() { + return node; + } + + public MyPDGNodeType getType() { + return type; + } + + public String getAttrib() { + return attrib; + } + + public List getDependents() { + return dependents; + } + + public List getBackDependets() { + return backDependents; + } + + // add dependent nodes + public void addDependent(MyPDGNode node) { + this.dependents.add(node); + } + + public void addBackDependent(MyPDGNode node) { + this.backDependents.add(node); + } + + // Utility methods + public String toShortString() { + return "Node[type=" + type + ", attrib=" + attrib + "]"; + } + + @Override + public String toString() { + return "MyPDGNode{" + + "type=" + type + + ", attrib='" + attrib + '\'' + + '}'; + } + + public void setLineNumber(int lineNumber) { + this.lineNumber = lineNumber; + } + + public int getLineNumber() { + return lineNumber; + } + + // equals and hashCode for correct functioning in collections + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + MyPDGNode that = (MyPDGNode) o; + return Objects.equals(node, that.node) && + type == that.type && + Objects.equals(attrib, that.attrib); + } + + @Override + public int hashCode() { + return Objects.hash(node, type, attrib); + } +} diff --git a/src/main/java/org/pdgdiff/graph/model/MyPDGNodeType.java b/src/main/java/org/pdgdiff/graph/model/MyPDGNodeType.java new file mode 100644 index 0000000..68b627b --- /dev/null +++ b/src/main/java/org/pdgdiff/graph/model/MyPDGNodeType.java @@ -0,0 +1,7 @@ +package org.pdgdiff.graph.model; + +public enum MyPDGNodeType { + CFGNODE, + REGION, + // Add other types as needed +} diff --git a/src/main/java/org/pdgdiff/matching/GraphMapping.java b/src/main/java/org/pdgdiff/matching/GraphMapping.java index b320058..939aa92 100644 --- a/src/main/java/org/pdgdiff/matching/GraphMapping.java +++ b/src/main/java/org/pdgdiff/matching/GraphMapping.java @@ -1,6 +1,7 @@ package org.pdgdiff.matching; -import soot.toolkits.graph.pdg.HashMutablePDG; +import org.pdgdiff.graph.model.MyPDG; + import java.util.HashMap; import java.util.Map; @@ -10,8 +11,8 @@ * PDGs in two lists that have been matched by the GraphMatcher. */ public class GraphMapping { - private Map graphMapping; - private Map nodeMappings; // TODO: make heuristic algo find node mappings + private Map graphMapping; + private Map nodeMappings; // TODO: make heuristic algo find node mappings public GraphMapping() { this.graphMapping = new HashMap<>(); @@ -19,29 +20,29 @@ public GraphMapping() { } // Adds a mapping between two PDGs - public void addGraphMapping(HashMutablePDG srcPDG, HashMutablePDG dstPDG, NodeMapping nodeMapping) { + public void addGraphMapping(MyPDG srcPDG, MyPDG dstPDG, NodeMapping nodeMapping) { graphMapping.put(srcPDG, dstPDG); nodeMappings.put(srcPDG, nodeMapping); } // Retrieves the mapped PDG for a given PDG - public HashMutablePDG getMappedGraph(HashMutablePDG srcPDG) { + public MyPDG getMappedGraph(MyPDG srcPDG) { return graphMapping.get(srcPDG); } // Retrieves the node mapping for a given PDG pair - public NodeMapping getNodeMapping(HashMutablePDG srcPDG) { + public NodeMapping getNodeMapping(MyPDG srcPDG) { return nodeMappings.get(srcPDG); } // Exposes the entire graph mapping - public Map getGraphMapping() { + public Map getGraphMapping() { return graphMapping; } // Pretty print all graph mappings for debugging public void printGraphMappings() { - for (Map.Entry entry : graphMapping.entrySet()) { + for (Map.Entry entry : graphMapping.entrySet()) { System.out.println("Source PDG: " + entry.getKey() + " --> Mapped to: " + entry.getValue()); NodeMapping nodeMapping = nodeMappings.get(entry.getKey()); if (nodeMapping != null) { diff --git a/src/main/java/org/pdgdiff/matching/GraphMatcher.java b/src/main/java/org/pdgdiff/matching/GraphMatcher.java index 61cbb03..db93521 100644 --- a/src/main/java/org/pdgdiff/matching/GraphMatcher.java +++ b/src/main/java/org/pdgdiff/matching/GraphMatcher.java @@ -1,6 +1,6 @@ package org.pdgdiff.matching; -import soot.toolkits.graph.pdg.HashMutablePDG; +import org.pdgdiff.graph.model.MyPDG; import java.util.HashSet; import java.util.List; @@ -11,12 +11,12 @@ * This class uses a custom similarity score to compare PDG nodes and labels. WIP. */ public abstract class GraphMatcher { - protected final HashSet matchedPDGs; - protected List pdgList1; - protected List pdgList2; + protected final HashSet matchedPDGs; + protected List pdgList1; + protected List pdgList2; protected GraphMapping graphMapping; // To store graph-level and node-level mappings - public GraphMatcher(List list1, List list2) { + public GraphMatcher(List list1, List list2) { this.pdgList1 = list1; this.pdgList2 = list2; this.graphMapping = new GraphMapping(); diff --git a/src/main/java/org/pdgdiff/matching/GraphMatcherFactory.java b/src/main/java/org/pdgdiff/matching/GraphMatcherFactory.java index 354b77f..548ca2c 100644 --- a/src/main/java/org/pdgdiff/matching/GraphMatcherFactory.java +++ b/src/main/java/org/pdgdiff/matching/GraphMatcherFactory.java @@ -1,5 +1,7 @@ package org.pdgdiff.matching; +import org.pdgdiff.graph.model.MyPDG; +import org.pdgdiff.graph.model.MyPDGNode; import org.pdgdiff.matching.models.HeuristicGraphMatcher; import org.pdgdiff.matching.models.UllmannGraphMatcher; import org.pdgdiff.matching.models.VF2GraphMatcher; @@ -8,7 +10,7 @@ import java.util.List; public class GraphMatcherFactory { - public static GraphMatcher createMatcher(String strategy, List srcPDGs, List destPDGs) { + public static GraphMatcher createMatcher(String strategy, List srcPDGs, List destPDGs) { switch (strategy.toLowerCase()) { case "vf2": return new VF2GraphMatcher(srcPDGs, destPDGs); diff --git a/src/main/java/org/pdgdiff/matching/NodeMapping.java b/src/main/java/org/pdgdiff/matching/NodeMapping.java index 5823554..5d9c925 100644 --- a/src/main/java/org/pdgdiff/matching/NodeMapping.java +++ b/src/main/java/org/pdgdiff/matching/NodeMapping.java @@ -1,6 +1,6 @@ package org.pdgdiff.matching; -import soot.toolkits.graph.pdg.PDGNode; +import org.pdgdiff.graph.model.MyPDGNode; import java.util.HashMap; import java.util.Map; @@ -10,8 +10,8 @@ * nodes in two PDGs that have been matched by the GraphMatcher. */ public class NodeMapping { - private Map nodeMapping; - private Map reverseNodeMapping; + private Map nodeMapping; + private Map reverseNodeMapping; public NodeMapping() { nodeMapping = new HashMap<>(); @@ -19,53 +19,53 @@ public NodeMapping() { } // Adds a mapping between a source node and a destination node - public void addMapping(PDGNode srcNode, PDGNode dstNode) { + public void addMapping(MyPDGNode srcNode, MyPDGNode dstNode) { nodeMapping.put(srcNode, dstNode); reverseNodeMapping.put(dstNode, srcNode); } // Retrieves the mapped destination node for a given source node - public PDGNode getMappedNode(PDGNode node) { + public MyPDGNode getMappedNode(MyPDGNode node) { return nodeMapping.get(node); } // Retrieves the mapped source node for a given destination node - public PDGNode getReverseMappedNode(PDGNode node) { + public MyPDGNode getReverseMappedNode(MyPDGNode node) { return reverseNodeMapping.get(node); } // Exposes the entire node mapping - public Map getNodeMapping() { + public Map getNodeMapping() { return nodeMapping; } // Exposes the reverse node mapping - public Map getReverseNodeMapping() { + public Map getReverseNodeMapping() { return reverseNodeMapping; } // Pretty print all node mappings for debugging public void printMappings() { - for (Map.Entry entry : nodeMapping.entrySet()) { + for (Map.Entry entry : nodeMapping.entrySet()) { System.out.println("Source Node: " + entry.getKey().toShortString() + " --> Mapped to: " + entry.getValue().toShortString()); } } public void printMappingsVerbose() { - for (Map.Entry entry : nodeMapping.entrySet()) { + for (Map.Entry entry : nodeMapping.entrySet()) { System.out.println("Source Node: " + entry.getKey().toString() + " --> Mapped to: " + entry.getValue().toString()); } } // Check if a node is already mapped - public boolean isMapped(PDGNode node) { + public boolean isMapped(MyPDGNode node) { return nodeMapping.containsKey(node); } // Check if a destination node is already reverse-mapped - public boolean isReverseMapped(PDGNode node) { + public boolean isReverseMapped(MyPDGNode node) { return reverseNodeMapping.containsKey(node); } diff --git a/src/main/java/org/pdgdiff/matching/PDGComparator.java b/src/main/java/org/pdgdiff/matching/PDGComparator.java index dfa4448..2dfbddd 100644 --- a/src/main/java/org/pdgdiff/matching/PDGComparator.java +++ b/src/main/java/org/pdgdiff/matching/PDGComparator.java @@ -5,6 +5,7 @@ import org.pdgdiff.edit.EditDistanceCalculator; import org.pdgdiff.edit.EditScriptGenerator; import org.pdgdiff.edit.model.EditOperation; +import org.pdgdiff.graph.model.MyPDG; import org.pdgdiff.io.JsonOperationSerializer; import org.pdgdiff.io.OperationSerializer; import soot.SootClass; @@ -23,7 +24,7 @@ public class PDGComparator { - public static void compareAndPrintGraphSimilarity(List pdgList1, List pdgList2, + public static void compareAndPrintGraphSimilarity(List pdgList1, List pdgList2, String strategy, String srcSourceFilePath, String dstSourceFilePath) throws IOException { GraphMatcher matcher = GraphMatcherFactory.createMatcher(strategy, pdgList1, pdgList2); @@ -35,8 +36,8 @@ public static void compareAndPrintGraphSimilarity(List pdgList1, System.out.println("--> Graph matching complete using strategy: " + strategy); graphMapping.getGraphMapping().forEach((srcPDG, dstPDG) -> { - String method1 = srcPDG.getCFG().getBody().getMethod().getSignature(); - String method2 = dstPDG.getCFG().getBody().getMethod().getSignature(); + String method1 = srcPDG.getMethodSignature(); + String method2 = dstPDG.getMethodSignature(); System.out.println("---\n> PDG from class 1: " + method1 + " is matched with PDG from class 2: " + method2); NodeMapping nodeMapping = graphMapping.getNodeMapping(srcPDG); if (nodeMapping != null) { @@ -48,8 +49,8 @@ public static void compareAndPrintGraphSimilarity(List pdgList1, // collecting of 'metadata' of the code, i.e. function signatures and fields, will occur here. it should not have // any impact on the actual matching process, to ensure that this is as semantic and language-agnostic as possible. - SootMethod srcObj = srcPDG.getCFG().getBody().getMethod(); - SootMethod destObj = dstPDG.getCFG().getBody().getMethod(); + SootMethod srcObj = srcPDG.getMethod(); + SootMethod destObj = dstPDG.getMethod(); List editScript = EditScriptGenerator.generateEditScript(srcPDG, dstPDG, graphMapping, srcSourceFilePath, dstSourceFilePath, srcObj, destObj); diff --git a/src/main/java/org/pdgdiff/matching/models/HeuristicGraphMatcher.java b/src/main/java/org/pdgdiff/matching/models/HeuristicGraphMatcher.java index c2ef9cf..e572a67 100644 --- a/src/main/java/org/pdgdiff/matching/models/HeuristicGraphMatcher.java +++ b/src/main/java/org/pdgdiff/matching/models/HeuristicGraphMatcher.java @@ -1,5 +1,6 @@ package org.pdgdiff.matching.models; +import org.pdgdiff.graph.model.MyPDG; import org.pdgdiff.matching.GraphMapping; import org.pdgdiff.matching.GraphMatcher; import org.pdgdiff.matching.NodeMapping; @@ -9,7 +10,7 @@ import java.util.List; public class HeuristicGraphMatcher extends GraphMatcher { - public HeuristicGraphMatcher(List list1, List list2) { + public HeuristicGraphMatcher(List list1, List list2) { super(list1, list2); } @@ -17,13 +18,13 @@ public HeuristicGraphMatcher(List list1, List li public GraphMapping matchPDGLists() { HeuristicMatcher heuristicMatcher = new HeuristicMatcher(); - for (HashMutablePDG pdg1 : pdgList1) { - HashMutablePDG bestMatch = null; + for (MyPDG pdg1 : pdgList1) { + MyPDG bestMatch = null; NodeMapping bestNodeMapping = null; // Track node-level mappings double bestScore = Double.NEGATIVE_INFINITY; // Start with a very low score // Compare pdg1 with each PDG from the second list - for (HashMutablePDG pdg2 : pdgList2) { + for (MyPDG pdg2 : pdgList2) { // Skip if this PDG has already been matched if (matchedPDGs.contains(pdg2)) { continue; diff --git a/src/main/java/org/pdgdiff/matching/models/UllmannGraphMatcher.java b/src/main/java/org/pdgdiff/matching/models/UllmannGraphMatcher.java index 1acec8d..a5cafe1 100644 --- a/src/main/java/org/pdgdiff/matching/models/UllmannGraphMatcher.java +++ b/src/main/java/org/pdgdiff/matching/models/UllmannGraphMatcher.java @@ -1,6 +1,7 @@ package org.pdgdiff.matching.models; import org.pdgdiff.graph.GraphTraversal; +import org.pdgdiff.graph.model.MyPDG; import org.pdgdiff.matching.GraphMapping; import org.pdgdiff.matching.GraphMatcher; import org.pdgdiff.matching.NodeMapping; @@ -11,24 +12,24 @@ import java.util.List; public class UllmannGraphMatcher extends GraphMatcher { - public UllmannGraphMatcher(List list1, List list2) { + public UllmannGraphMatcher(List list1, List list2) { super(list1, list2); } @Override public GraphMapping matchPDGLists() { - List unmappedPDGs1 = new ArrayList<>(pdgList1); - List unmappedPDGs2 = new ArrayList<>(pdgList2); + List unmappedPDGs1 = new ArrayList<>(pdgList1); + List unmappedPDGs2 = new ArrayList<>(pdgList2); while (!unmappedPDGs1.isEmpty() && !unmappedPDGs2.isEmpty()) { double maxScore = Double.NEGATIVE_INFINITY; - HashMutablePDG bestPdg1 = null; - HashMutablePDG bestPdg2 = null; + MyPDG bestPdg1 = null; + MyPDG bestPdg2 = null; NodeMapping bestNodeMapping = null; // for each pair of unmapped PDGs, compute similarity score - for (HashMutablePDG pdg1 : unmappedPDGs1) { - for (HashMutablePDG pdg2 : unmappedPDGs2) { + for (MyPDG pdg1 : unmappedPDGs1) { + for (MyPDG pdg2 : unmappedPDGs2) { UllmannMatcher ullmannMatcher = new UllmannMatcher(pdg1, pdg2); NodeMapping nodeMapping = ullmannMatcher.match(); @@ -61,8 +62,8 @@ public GraphMapping matchPDGLists() { } } - for (HashMutablePDG pdg1 : unmappedPDGs1) { - System.out.println("No matching PDG found for: " + pdg1.getCFG().getBody().getMethod().getSignature()); + for (MyPDG pdg1 : unmappedPDGs1) { + System.out.println("No matching PDG found for: " + pdg1.getMethodSignature()); } return graphMapping; diff --git a/src/main/java/org/pdgdiff/matching/models/VF2GraphMatcher.java b/src/main/java/org/pdgdiff/matching/models/VF2GraphMatcher.java index 8473e52..be2ded5 100644 --- a/src/main/java/org/pdgdiff/matching/models/VF2GraphMatcher.java +++ b/src/main/java/org/pdgdiff/matching/models/VF2GraphMatcher.java @@ -1,35 +1,36 @@ package org.pdgdiff.matching.models; import org.pdgdiff.graph.GraphTraversal; +import org.pdgdiff.graph.model.MyPDG; import org.pdgdiff.matching.GraphMapping; import org.pdgdiff.matching.GraphMatcher; import org.pdgdiff.matching.NodeMapping; import org.pdgdiff.matching.models.vf2.VF2Matcher; -import soot.toolkits.graph.pdg.HashMutablePDG; import java.util.ArrayList; import java.util.List; public class VF2GraphMatcher extends GraphMatcher { - public VF2GraphMatcher(List list1, List list2) { + public VF2GraphMatcher(List list1, List list2) { + // TODO: rename these legacy names 'pdglist1' to be more informative i.e. src and dest super(list1, list2); } @Override public GraphMapping matchPDGLists() { - // TODO: rename these legacy names 'pdglist1' to be more informative i.e. src and dest - List unmappedPDGs1 = new ArrayList<>(pdgList1); - List unmappedPDGs2 = new ArrayList<>(pdgList2); + + List unmappedPDGs1 = new ArrayList<>(pdgList1); + List unmappedPDGs2 = new ArrayList<>(pdgList2); while (!unmappedPDGs1.isEmpty() && !unmappedPDGs2.isEmpty()) { double maxScore = Double.NEGATIVE_INFINITY; - HashMutablePDG bestPdg1 = null; - HashMutablePDG bestPdg2 = null; + MyPDG bestPdg1 = null; + MyPDG bestPdg2 = null; NodeMapping bestNodeMapping = null; // for each pair of unmapped PDGs, compute similarity score - for (HashMutablePDG pdg1 : unmappedPDGs1) { - for (HashMutablePDG pdg2 : unmappedPDGs2) { + for (MyPDG pdg1 : unmappedPDGs1) { + for (MyPDG pdg2 : unmappedPDGs2) { VF2Matcher vf2Matcher = new VF2Matcher(pdg1, pdg2); NodeMapping nodeMapping = vf2Matcher.match(); @@ -63,8 +64,8 @@ public GraphMapping matchPDGLists() { } // handling PDGs in src that were not matched - for (HashMutablePDG pdg1 : unmappedPDGs1) { - System.out.println("No matching PDG found for: " + pdg1.getCFG().getBody().getMethod().getSignature()); + for (MyPDG pdg1 : unmappedPDGs1) { + System.out.println("No matching PDG found for PDG: " + pdg1); } return graphMapping; diff --git a/src/main/java/org/pdgdiff/matching/models/heuristic/HeuristicMatcher.java b/src/main/java/org/pdgdiff/matching/models/heuristic/HeuristicMatcher.java index 5759089..73872bd 100644 --- a/src/main/java/org/pdgdiff/matching/models/heuristic/HeuristicMatcher.java +++ b/src/main/java/org/pdgdiff/matching/models/heuristic/HeuristicMatcher.java @@ -1,5 +1,7 @@ package org.pdgdiff.matching.models.heuristic; +import org.pdgdiff.graph.model.MyPDG; +import org.pdgdiff.graph.model.MyPDGNode; import org.pdgdiff.matching.NodeMapping; import org.pdgdiff.graph.GraphTraversal; import soot.toolkits.graph.pdg.HashMutablePDG; @@ -10,17 +12,17 @@ public class HeuristicMatcher { // Compare two individual PDGs - public double comparePDGs(HashMutablePDG pdg1, HashMutablePDG pdg2, NodeMapping nodeMapping) { + public double comparePDGs(MyPDG pdg1, MyPDG pdg2, NodeMapping nodeMapping) { double totalScore = 0.0; // Get nodes from the PDGs - List nodes1 = getPDGNodes(pdg1); - List nodes2 = getPDGNodes(pdg2); + List nodes1 = getPDGNodes(pdg1); + List nodes2 = getPDGNodes(pdg2); // Match nodes between the two PDGs for (int i = 0; i < Math.min(nodes1.size(), nodes2.size()); i++) { - PDGNode node1 = nodes1.get(i); - PDGNode node2 = nodes2.get(i); + MyPDGNode node1 = nodes1.get(i); + MyPDGNode node2 = nodes2.get(i); double nodeScore = similarityScore(node1, node2); @@ -35,8 +37,8 @@ public double comparePDGs(HashMutablePDG pdg1, HashMutablePDG pdg2, NodeMapping totalScore = totalScore / Math.max(nodes1.size(), nodes2.size()); // Include method name similarity - String methodName1 = pdg1.getCFG().getBody().getMethod().getName(); - String methodName2 = pdg2.getCFG().getBody().getMethod().getName(); + String methodName1 = pdg1.getMethod().getName(); + String methodName2 = pdg2.getMethod().getName(); double nameSimilarity = JaroWinklerSimilarity.JaroWinklerSimilarity(methodName1, methodName2); totalScore += nameSimilarity * 2; @@ -45,12 +47,12 @@ public double comparePDGs(HashMutablePDG pdg1, HashMutablePDG pdg2, NodeMapping } // Use GraphTraversal to get all nodes in a PDG - private List getPDGNodes(HashMutablePDG pdg) { + private List getPDGNodes(MyPDG pdg) { return GraphTraversal.collectNodesBFS(pdg); } // Calculate a similarity score between two PDG nodes - private double similarityScore(PDGNode node1, PDGNode node2) { + private double similarityScore(MyPDGNode node1, MyPDGNode node2) { double score = 0.0; // Compare node types @@ -83,7 +85,7 @@ private double similarityScore(PDGNode node1, PDGNode node2) { } // Extract the actual code or detailed label from the PDGNode's m_node field - private String extractCodeOrLabel(PDGNode node) { + private String extractCodeOrLabel(MyPDGNode node) { Object m_node = node.getNode(); if (m_node instanceof soot.toolkits.graph.Block) { diff --git a/src/main/java/org/pdgdiff/matching/models/ullmann/UllmannMatcher.java b/src/main/java/org/pdgdiff/matching/models/ullmann/UllmannMatcher.java index 5f264c5..f06ce3b 100644 --- a/src/main/java/org/pdgdiff/matching/models/ullmann/UllmannMatcher.java +++ b/src/main/java/org/pdgdiff/matching/models/ullmann/UllmannMatcher.java @@ -1,6 +1,8 @@ package org.pdgdiff.matching.models.ullmann; import org.pdgdiff.graph.GraphTraversal; +import org.pdgdiff.graph.model.MyPDG; +import org.pdgdiff.graph.model.MyPDGNode; import org.pdgdiff.matching.NodeMapping; import soot.toolkits.graph.pdg.HashMutablePDG; import soot.toolkits.graph.pdg.PDGNode; @@ -12,18 +14,18 @@ * This class contains methods to match two PDGs and return the node mappings between them. */ public class UllmannMatcher { - private HashMutablePDG pdg1; - private HashMutablePDG pdg2; + private MyPDG pdg1; + private MyPDG pdg2; private NodeMapping nodeMapping; - private List nodes1; - private List nodes2; + private List nodes1; + private List nodes2; private int n; private int m; private int[][] M; // Compatibility matrix private Stack MStack; - public UllmannMatcher(HashMutablePDG pdg1, HashMutablePDG pdg2) { + public UllmannMatcher(MyPDG pdg1, MyPDG pdg2) { this.pdg1 = pdg1; this.pdg2 = pdg2; this.nodeMapping = new NodeMapping(); @@ -55,9 +57,9 @@ public NodeMapping match() { private void initializeM() { for (int i = 0; i < n; i++) { - PDGNode node1 = nodes1.get(i); + MyPDGNode node1 = nodes1.get(i); for (int j = 0; j < m; j++) { - PDGNode node2 = nodes2.get(j); + MyPDGNode node2 = nodes2.get(j); M[i][j] = nodesAreCompatible(node1, node2) ? 1 : 0; } } @@ -99,8 +101,8 @@ private boolean matchRecursive(int depth) { private boolean isFeasible(int i, int j) { // TODO: build more domain specific into thsi // Check adjacency compatibility - PDGNode node1 = nodes1.get(i); - PDGNode node2 = nodes2.get(j); + MyPDGNode node1 = nodes1.get(i); + MyPDGNode node2 = nodes2.get(j); // For all previously mapped nodes for (int k = 0; k < i; k++) { @@ -113,8 +115,8 @@ private boolean isFeasible(int i, int j) { } } if (mappedIndex != -1) { - PDGNode mappedNode1 = nodes1.get(k); - PDGNode mappedNode2 = nodes2.get(mappedIndex); + MyPDGNode mappedNode1 = nodes1.get(k); + MyPDGNode mappedNode2 = nodes2.get(mappedIndex); // check if adjacency is preserved boolean adjInPDG1 = areAdjacent(node1, mappedNode1); @@ -128,7 +130,7 @@ private boolean isFeasible(int i, int j) { return true; } - private boolean areAdjacent(PDGNode n1, PDGNode n2) { + private boolean areAdjacent(MyPDGNode n1, MyPDGNode n2) { // Check if n1 and n2 are adjacent in the PDG return n1.getDependents().contains(n2) || n1.getBackDependets().contains(n2) || n2.getDependents().contains(n1) || n2.getBackDependets().contains(n1); @@ -145,7 +147,7 @@ private void buildNodeMapping() { } } - private boolean nodesAreCompatible(PDGNode n1, PDGNode n2) { + private boolean nodesAreCompatible(MyPDGNode n1, MyPDGNode n2) { // TODO: add more like VF2 // compare node types and attributes return n1.getType().equals(n2.getType()) && n1.getAttrib().equals(n2.getAttrib()); diff --git a/src/main/java/org/pdgdiff/matching/models/vf2/VF2Matcher.java b/src/main/java/org/pdgdiff/matching/models/vf2/VF2Matcher.java index 35928a6..d03c8ed 100644 --- a/src/main/java/org/pdgdiff/matching/models/vf2/VF2Matcher.java +++ b/src/main/java/org/pdgdiff/matching/models/vf2/VF2Matcher.java @@ -1,9 +1,8 @@ package org.pdgdiff.matching.models.vf2; +import org.pdgdiff.graph.model.MyPDG; +import org.pdgdiff.graph.model.MyPDGNode; import org.pdgdiff.matching.NodeMapping; -import soot.toolkits.graph.pdg.HashMutablePDG; -import soot.toolkits.graph.pdg.PDGNode; - import java.util.Map; /** @@ -12,11 +11,11 @@ * TODO: Check I have done this correctly, quite tired at time of implementation (its 11pm :( ) */ public class VF2Matcher { - private HashMutablePDG pdg1; - private HashMutablePDG pdg2; + private MyPDG pdg1; + private MyPDG pdg2; private NodeMapping nodeMapping; - public VF2Matcher(HashMutablePDG pdg1, HashMutablePDG pdg2) { + public VF2Matcher(MyPDG pdg1, MyPDG pdg2) { this.pdg1 = pdg1; this.pdg2 = pdg2; this.nodeMapping = new NodeMapping(); @@ -40,7 +39,7 @@ public NodeMapping match() { private boolean matchRecursive(VF2State state) { if (state.isComplete()) { // Mapping is complete, transfer mappings to nodeMapping - for (Map.Entry entry : state.getMapping().entrySet()) { + for (Map.Entry entry : state.getMapping().entrySet()) { nodeMapping.addMapping(entry.getKey(), entry.getValue()); } return true; diff --git a/src/main/java/org/pdgdiff/matching/models/vf2/VF2State.java b/src/main/java/org/pdgdiff/matching/models/vf2/VF2State.java index 752eccd..6465f6f 100644 --- a/src/main/java/org/pdgdiff/matching/models/vf2/VF2State.java +++ b/src/main/java/org/pdgdiff/matching/models/vf2/VF2State.java @@ -1,8 +1,9 @@ package org.pdgdiff.matching.models.vf2; import org.pdgdiff.graph.GraphTraversal; -import soot.toolkits.graph.pdg.HashMutablePDG; -import soot.toolkits.graph.pdg.PDGNode; +import org.pdgdiff.graph.model.MyPDG; +import org.pdgdiff.graph.model.MyPDGNode; + import java.util.*; @@ -11,17 +12,17 @@ * of the VF2 algorithm and perform operations on the state. */ class VF2State { - private HashMutablePDG pdg1; - private HashMutablePDG pdg2; - private Map mapping; // The current partial mapping + private MyPDG pdg1; + private MyPDG pdg2; + private Map mapping; // The current partial mapping - private Set T1; // Nodes in PDG1 that are in the mapping or adjacent to mapped nodes - private Set T2; // Same for PDG2 + private Set T1; // Nodes in PDG1 that are in the mapping or adjacent to mapped nodes + private Set T2; // Same for PDG2 - private Set unmapped1; // Unmapped nodes in PDG1 - private Set unmapped2; // Unmapped nodes in PDG2 + private Set unmapped1; // Unmapped nodes in PDG1 + private Set unmapped2; // Unmapped nodes in PDG2 - public VF2State(HashMutablePDG pdg1, HashMutablePDG pdg2) { + public VF2State(MyPDG pdg1, MyPDG pdg2) { this.pdg1 = pdg1; this.pdg2 = pdg2; this.mapping = new LinkedHashMap<>(); @@ -38,7 +39,7 @@ public boolean isComplete() { return mapping.size() >= Math.min(GraphTraversal.getNodeCount(pdg1), GraphTraversal.getNodeCount(pdg2)); } - public Map getMapping() { + public Map getMapping() { return mapping; } @@ -50,16 +51,16 @@ public List generateCandidates() { if (!T1.isEmpty() && !T2.isEmpty()) { // Pick nodes from T1 and T2 - PDGNode n1 = selectNode(T1); - for (PDGNode n2 : T2) { + MyPDGNode n1 = selectNode(T1); + for (MyPDGNode n2 : T2) { if (nodesAreCompatible(n1, n2)) { candidates.add(new CandidatePair(n1, n2)); } } } else { // If T1 and T2 are empty, pick any unmapped nodes - PDGNode n1 = selectNode(unmapped1); - for (PDGNode n2 : unmapped2) { + MyPDGNode n1 = selectNode(unmapped1); + for (MyPDGNode n2 : unmapped2) { if (nodesAreCompatible(n1, n2)) { candidates.add(new CandidatePair(n1, n2)); } @@ -96,7 +97,7 @@ public void removePair(CandidatePair pair) { // Helper methods... - private boolean nodesAreCompatible(PDGNode n1, PDGNode n2) { + private boolean nodesAreCompatible(MyPDGNode n1, MyPDGNode n2) { // Compare node types, labels, attributes return n1.getType().equals(n2.getType()) && n1.getAttrib().equals(n2.getAttrib()); } @@ -113,8 +114,8 @@ private boolean checkSemanticFeasibility(CandidatePair pair) { // For all edges (n1', n1) in pdg1 // NB getBackDependets typo exists in original soot code - for (PDGNode n1Prime : pair.n1.getBackDependets()) { - PDGNode mappedN1Prime = mapping.get(n1Prime); + for (MyPDGNode n1Prime : pair.n1.getBackDependets()) { + MyPDGNode mappedN1Prime = mapping.get(n1Prime); if (mappedN1Prime != null) { // There should be an edge (mappedN1Prime, n2) in pdg2 if (!mappedN1Prime.getDependents().contains(pair.n2)) { @@ -124,8 +125,8 @@ private boolean checkSemanticFeasibility(CandidatePair pair) { } // For all edges (n1, n1'') in pdg1 - for (PDGNode n1DoublePrime : pair.n1.getDependents()) { - PDGNode mappedN1DoublePrime = mapping.get(n1DoublePrime); + for (MyPDGNode n1DoublePrime : pair.n1.getDependents()) { + MyPDGNode mappedN1DoublePrime = mapping.get(n1DoublePrime); if (mappedN1DoublePrime != null) { // There should be an edge (n2, mappedN1DoublePrime) in pdg2 if (!pair.n2.getDependents().contains(mappedN1DoublePrime)) { @@ -135,9 +136,9 @@ private boolean checkSemanticFeasibility(CandidatePair pair) { } // Ensure no conflicting mappings exist - for (Map.Entry entry : mapping.entrySet()) { - PDGNode mappedN1 = entry.getKey(); - PDGNode mappedN2 = entry.getValue(); + for (Map.Entry entry : mapping.entrySet()) { + MyPDGNode mappedN1 = entry.getKey(); + MyPDGNode mappedN2 = entry.getValue(); // Check if there is an edge between pair.n1 and mappedN1 in pdg1 boolean edgeInPDG1 = pair.n1.getDependents().contains(mappedN1) || pair.n1.getBackDependets().contains(mappedN1); @@ -151,26 +152,26 @@ private boolean checkSemanticFeasibility(CandidatePair pair) { return true; } - private void updateTerminalSets(PDGNode n1, PDGNode n2) { + private void updateTerminalSets(MyPDGNode n1, MyPDGNode n2) { // Add neighbors of n1 to T1 if they are not mapped - for (PDGNode neighbor : n1.getDependents()) { + for (MyPDGNode neighbor : n1.getDependents()) { if (!mapping.containsKey(neighbor)) { T1.add(neighbor); } } - for (PDGNode neighbor : n1.getBackDependets()) { + for (MyPDGNode neighbor : n1.getBackDependets()) { if (!mapping.containsKey(neighbor)) { T1.add(neighbor); } } // Same for n2 - for (PDGNode neighbor : n2.getDependents()) { + for (MyPDGNode neighbor : n2.getDependents()) { if (!mapping.containsValue(neighbor)) { T2.add(neighbor); } } - for (PDGNode neighbor : n2.getBackDependets()) { + for (MyPDGNode neighbor : n2.getBackDependets()) { if (!mapping.containsValue(neighbor)) { T2.add(neighbor); } @@ -184,25 +185,25 @@ private void updateTerminalSets(PDGNode n1, PDGNode n2) { private void recalculateTerminalSets() { T1.clear(); T2.clear(); - for (PDGNode mappedNode1 : mapping.keySet()) { - for (PDGNode neighbor : mappedNode1.getDependents()) { + for (MyPDGNode mappedNode1 : mapping.keySet()) { + for (MyPDGNode neighbor : mappedNode1.getDependents()) { if (!mapping.containsKey(neighbor)) { T1.add(neighbor); } } - for (PDGNode neighbor : mappedNode1.getBackDependets()) { + for (MyPDGNode neighbor : mappedNode1.getBackDependets()) { if (!mapping.containsKey(neighbor)) { T1.add(neighbor); } } } - for (PDGNode mappedNode2 : mapping.values()) { - for (PDGNode neighbor : mappedNode2.getDependents()) { + for (MyPDGNode mappedNode2 : mapping.values()) { + for (MyPDGNode neighbor : mappedNode2.getDependents()) { if (!mapping.containsValue(neighbor)) { T2.add(neighbor); } } - for (PDGNode neighbor : mappedNode2.getBackDependets()) { + for (MyPDGNode neighbor : mappedNode2.getBackDependets()) { if (!mapping.containsValue(neighbor)) { T2.add(neighbor); } @@ -210,7 +211,7 @@ private void recalculateTerminalSets() { } } - private PDGNode selectNode(Set nodeSet) { + private MyPDGNode selectNode(Set nodeSet) { // TODO: implement a more sophisticated node selection strategy here // ATM return any node from the set return nodeSet.iterator().next(); From ab48844d8b99beb58f2f1c6dac4a61bdcd894c48 Mon Sep 17 00:00:00 2001 From: syntax Date: Fri, 8 Nov 2024 15:48:24 +0000 Subject: [PATCH 2/3] complete prelim decoupling --- .../java/org/pdgdiff/edit/EditScriptGenerator.java | 13 +++++++------ src/main/java/org/pdgdiff/graph/GraphExporter.java | 7 ++++--- src/main/java/org/pdgdiff/graph/model/MyPDG.java | 1 + .../java/org/pdgdiff/io/JsonOperationFormatter.java | 1 + .../java/org/pdgdiff/matching/PDGComparator.java | 4 ++-- .../pdgdiff/matching/models/vf2/CandidatePair.java | 7 ++++--- 6 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/pdgdiff/edit/EditScriptGenerator.java b/src/main/java/org/pdgdiff/edit/EditScriptGenerator.java index e496f0d..6286f51 100644 --- a/src/main/java/org/pdgdiff/edit/EditScriptGenerator.java +++ b/src/main/java/org/pdgdiff/edit/EditScriptGenerator.java @@ -3,6 +3,7 @@ import org.pdgdiff.edit.model.*; import org.pdgdiff.graph.model.MyPDG; import org.pdgdiff.graph.model.MyPDGNode; +import org.pdgdiff.graph.model.MyPDGNodeType; import org.pdgdiff.matching.GraphMapping; import org.pdgdiff.matching.NodeMapping; import org.pdgdiff.util.CodeAnalysisUtils; @@ -136,12 +137,12 @@ public ComparisonResult(boolean isEqual, boolean isMove, Set s } - public static int getNodeLineNumber(PDGNode node) { - if (node.getType() == PDGNode.Type.CFGNODE) { + public static int getNodeLineNumber(MyPDGNode node) { + if (node.getType() == MyPDGNodeType.CFGNODE) { Block block = (Block) node.getNode(); Unit headUnit = block.getHead(); return getLineNumber(headUnit); - } else if (node.getType() == PDGNode.Type.REGION) { + } else if (node.getType() == MyPDGNodeType.REGION) { IRegion region = (IRegion) node.getNode(); Unit firstUnit = region.getFirst(); return getLineNumber(firstUnit); @@ -162,16 +163,16 @@ private static ComparisonResult nodesAreEqual(MyPDGNode n1, MyPDGNode n2, Set visitedNodes, + private static ComparisonResult compareRegionNodes(MyPDGNode n1, MyPDGNode n2, Set visitedNodes, SourceCodeMapper srcCodeMapper, SourceCodeMapper dstCodeMapper, NodeMapping nodeMapping) { IRegion region1 = (IRegion) n1.getNode(); diff --git a/src/main/java/org/pdgdiff/graph/GraphExporter.java b/src/main/java/org/pdgdiff/graph/GraphExporter.java index 9a52b3c..f3946cc 100644 --- a/src/main/java/org/pdgdiff/graph/GraphExporter.java +++ b/src/main/java/org/pdgdiff/graph/GraphExporter.java @@ -1,6 +1,7 @@ package org.pdgdiff.graph; import org.pdgdiff.client.PDGDotVisualizer; +import org.pdgdiff.graph.model.MyPDG; import soot.SootMethod; import soot.toolkits.graph.pdg.HashMutablePDG; @@ -36,9 +37,9 @@ public static void clearOutputFolder(String folderPath) { * @param dotFileName The filename for the DOT file * @param txtFileName The filename for the text file */ - public static void exportPDG(HashMutablePDG pdg, String dotFileName, String txtFileName) throws IOException { + public static void exportPDG(MyPDG pdg, String dotFileName, String txtFileName) throws IOException { // Get the method associated with the PDG via the UnitGraph in HashMutablePDG - SootMethod method = pdg.getCFG().getBody().getMethod(); + SootMethod method = pdg.getMethod(); // Export the PDG to a DOT file exportPDGToDot(method, dotFileName); @@ -49,7 +50,7 @@ public static void exportPDG(HashMutablePDG pdg, String dotFileName, String txtF // Method to export PDG to a file for each class - public static void exportPDGToFile(HashMutablePDG pdg, String fileName, String methodName) throws IOException { + public static void exportPDGToFile(MyPDG pdg, String fileName, String methodName) throws IOException { PrintWriter writer = null; try { writer = new PrintWriter(new FileWriter(fileName, true)); diff --git a/src/main/java/org/pdgdiff/graph/model/MyPDG.java b/src/main/java/org/pdgdiff/graph/model/MyPDG.java index bef66ef..8371deb 100644 --- a/src/main/java/org/pdgdiff/graph/model/MyPDG.java +++ b/src/main/java/org/pdgdiff/graph/model/MyPDG.java @@ -6,6 +6,7 @@ import java.util.Iterator; import java.util.List; + public class MyPDG implements Iterable { private MyPDGNode startNode; private List nodes; diff --git a/src/main/java/org/pdgdiff/io/JsonOperationFormatter.java b/src/main/java/org/pdgdiff/io/JsonOperationFormatter.java index f68d9f4..44e499b 100644 --- a/src/main/java/org/pdgdiff/io/JsonOperationFormatter.java +++ b/src/main/java/org/pdgdiff/io/JsonOperationFormatter.java @@ -6,6 +6,7 @@ import java.io.Writer; public class JsonOperationFormatter implements OperationFormatter { + // TODO: remove Soot specific terms from here, e.g. no longer Jimple instead should read 'IR' private final JsonWriter writer; public JsonOperationFormatter(Writer writer) { diff --git a/src/main/java/org/pdgdiff/matching/PDGComparator.java b/src/main/java/org/pdgdiff/matching/PDGComparator.java index 2dfbddd..cd8599c 100644 --- a/src/main/java/org/pdgdiff/matching/PDGComparator.java +++ b/src/main/java/org/pdgdiff/matching/PDGComparator.java @@ -73,8 +73,8 @@ public static void compareAndPrintGraphSimilarity(List pdgList1, List Date: Sat, 9 Nov 2024 17:02:18 +0000 Subject: [PATCH 3/3] cleanup redundant soot imports, create new inhouse classes --- py-visualise/out/diff.json | 2 +- .../pdgdiff/edit/model/SyntaxDifference.java | 1 - .../java/org/pdgdiff/edit/model/Update.java | 1 - .../java/org/pdgdiff/graph/model/MyBlock.java | 40 +++++++++++++++++++ .../org/pdgdiff/graph/model/MyMethod.java | 5 +++ .../org/pdgdiff/graph/model/MyPDGNode.java | 2 +- .../org/pdgdiff/graph/model/MyRegion.java | 26 ++++++++++++ .../java/org/pdgdiff/graph/model/MyUnit.java | 39 ++++++++++++++++++ .../java/org/pdgdiff/graph/model/model.md | 5 +++ .../pdgdiff/matching/GraphMatcherFactory.java | 2 - .../org/pdgdiff/matching/PDGComparator.java | 1 - .../models/HeuristicGraphMatcher.java | 1 - .../matching/models/UllmannGraphMatcher.java | 1 - .../models/heuristic/HeuristicMatcher.java | 3 +- .../models/ullmann/UllmannMatcher.java | 2 - .../matching/models/vf2/CandidatePair.java | 1 - 16 files changed, 118 insertions(+), 14 deletions(-) create mode 100644 src/main/java/org/pdgdiff/graph/model/MyBlock.java create mode 100644 src/main/java/org/pdgdiff/graph/model/MyMethod.java create mode 100644 src/main/java/org/pdgdiff/graph/model/MyRegion.java create mode 100644 src/main/java/org/pdgdiff/graph/model/MyUnit.java create mode 100644 src/main/java/org/pdgdiff/graph/model/model.md diff --git a/py-visualise/out/diff.json b/py-visualise/out/diff.json index 50924dd..df76062 100644 --- a/py-visualise/out/diff.json +++ b/py-visualise/out/diff.json @@ -1 +1 @@ -{"actions":[{"action":"Update","oldLine":-1,"newLine":-1,"oldCode":"","newCode":"","difference":{"message":null,"oldJimple":"this := @this: org.pdgdiff.testclasses.TestAdder1","newJimple":"this := @this: org.pdgdiff.testclasses.TestAdder2"}},{"action":"Update","oldLine":12,"newLine":12,"oldCode":" System.out.println(\"Result: \" + result);","newCode":" System.out.println(\"Result: \" + result);","difference":{"message":null,"oldJimple":"virtualinvoke $stack9.($stack12)","newJimple":"virtualinvoke $stack11.($stack14)"}},{"action":"Update","oldLine":19,"newLine":21,"oldCode":" System.out.println(\"identical Result: \" + t);","newCode":" System.out.println(\"identical Result: \" + meep);","difference":{"message":null,"oldJimple":"$stack30 = virtualinvoke $stack29.()","newJimple":"$stack32 = virtualinvoke $stack31.()"}},{"action":"Update","oldLine":12,"newLine":12,"oldCode":" System.out.println(\"Result: \" + result);","newCode":" System.out.println(\"Result: \" + result);","difference":{"message":null,"oldJimple":"$stack8 = new java.lang.StringBuilder","newJimple":"$stack10 = new java.lang.StringBuilder"}},{"action":"Update","oldLine":10,"newLine":8,"oldCode":" TestAdder1 test = new TestAdder1();","newCode":" TestAdder2 test = new TestAdder2();","difference":{"message":null,"oldJimple":"specialinvoke $stack6.()>()","newJimple":"specialinvoke $stack8.()>()"}},{"action":"Update","oldLine":14,"newLine":14,"oldCode":" System.out.println(\"Result: \" + res);","newCode":" System.out.println(\"Product: \" + product);","difference":{"message":null,"oldJimple":"$stack15 = ","newJimple":"$stack17 = "}},{"action":"Update","oldLine":18,"newLine":20,"oldCode":" int t = test.identical(5, 10);","newCode":" System.out.println(\"Complex Calculation Result: \" + complexResult);","difference":{"message":null,"oldJimple":"$stack25 = virtualinvoke $stack6.(5, 10)","newJimple":"virtualinvoke $stack24.($stack27)"}},{"action":"Update","oldLine":12,"newLine":12,"oldCode":" System.out.println(\"Result: \" + result);","newCode":" System.out.println(\"Result: \" + result);","difference":{"message":null,"oldJimple":"$stack11 = virtualinvoke $stack10.($stack7)","newJimple":"$stack13 = virtualinvoke $stack12.($stack9)"}},{"action":"Update","oldLine":11,"newLine":11,"oldCode":" int result = test.addNumbers(5, 10);","newCode":" int result = test.addNumbers(number1, number2);","difference":{"message":null,"oldJimple":"$stack7 = virtualinvoke $stack6.(5, 10)","newJimple":"$stack9 = virtualinvoke $stack8.(5, 4)"}},{"action":"Update","oldLine":16,"newLine":18,"oldCode":" int complexRes = test.detailedComputation(5, 10);","newCode":" int complexResult = test.complexCalculation(number1, number2);","difference":{"message":null,"oldJimple":"$stack19 = virtualinvoke $stack6.(5, 10)","newJimple":"$stack21 = virtualinvoke $stack8.(5, 4)"}},{"action":"Update","oldLine":19,"newLine":21,"oldCode":" System.out.println(\"identical Result: \" + t);","newCode":" System.out.println(\"identical Result: \" + meep);","difference":{"message":null,"oldJimple":"virtualinvoke $stack27.($stack30)","newJimple":"virtualinvoke $stack29.($stack32)"}},{"action":"Update","oldLine":14,"newLine":14,"oldCode":" System.out.println(\"Result: \" + res);","newCode":" System.out.println(\"Product: \" + product);","difference":{"message":null,"oldJimple":"$stack17 = virtualinvoke $stack16.($stack13)","newJimple":"$stack19 = virtualinvoke $stack18.($stack15)"}},{"action":"Update","oldLine":13,"newLine":13,"oldCode":" int res = test.minus(10, 5);","newCode":" int product = test.multiplyNumbers(number1, number2);","difference":{"message":null,"oldJimple":"$stack13 = virtualinvoke $stack6.(10, 5)","newJimple":"$stack15 = virtualinvoke $stack8.(5, 4)"}},{"action":"Update","oldLine":14,"newLine":14,"oldCode":" System.out.println(\"Result: \" + res);","newCode":" System.out.println(\"Product: \" + product);","difference":{"message":null,"oldJimple":"$stack14 = new java.lang.StringBuilder","newJimple":"$stack16 = new java.lang.StringBuilder"}},{"action":"Update","oldLine":17,"newLine":20,"oldCode":" System.out.println(\"Detailed Computation Result: \" + complexRes);","newCode":" System.out.println(\"Complex Calculation Result: \" + complexResult);","difference":{"message":null,"oldJimple":"$stack20 = new java.lang.StringBuilder","newJimple":"$stack24 = "}},{"action":"Update","oldLine":19,"newLine":21,"oldCode":" System.out.println(\"identical Result: \" + t);","newCode":" System.out.println(\"identical Result: \" + meep);","difference":{"message":null,"oldJimple":"$stack26 = new java.lang.StringBuilder","newJimple":"$stack28 = new java.lang.StringBuilder"}},{"action":"Update","oldLine":14,"newLine":14,"oldCode":" System.out.println(\"Result: \" + res);","newCode":" System.out.println(\"Product: \" + product);","difference":{"message":null,"oldJimple":"$stack16 = virtualinvoke $stack14.(\"Result: \")","newJimple":"$stack18 = virtualinvoke $stack16.(\"Product: \")"}},{"action":"Update","oldLine":17,"newLine":20,"oldCode":" System.out.println(\"Detailed Computation Result: \" + complexRes);","newCode":" System.out.println(\"Complex Calculation Result: \" + complexResult);","difference":{"message":null,"oldJimple":"$stack24 = virtualinvoke $stack23.()","newJimple":"$stack26 = virtualinvoke $stack25.($stack21)"}},{"action":"Update","oldLine":19,"newLine":21,"oldCode":" System.out.println(\"identical Result: \" + t);","newCode":" System.out.println(\"identical Result: \" + meep);","difference":{"message":null,"oldJimple":"$stack29 = virtualinvoke $stack28.($stack25)","newJimple":"$stack31 = virtualinvoke $stack30.($stack22)"}},{"action":"Update","oldLine":17,"newLine":19,"oldCode":" System.out.println(\"Detailed Computation Result: \" + complexRes);","newCode":" int meep = test.identical(3,10);","difference":{"message":null,"oldJimple":"$stack21 = ","newJimple":"$stack22 = virtualinvoke $stack8.(3, 10)"}},{"action":"Update","oldLine":17,"newLine":20,"oldCode":" System.out.println(\"Detailed Computation Result: \" + complexRes);","newCode":" System.out.println(\"Complex Calculation Result: \" + complexResult);","difference":{"message":null,"oldJimple":"specialinvoke $stack20.()>()","newJimple":"$stack23 = new java.lang.StringBuilder"}},{"action":"Update","oldLine":14,"newLine":14,"oldCode":" System.out.println(\"Result: \" + res);","newCode":" System.out.println(\"Product: \" + product);","difference":{"message":null,"oldJimple":"specialinvoke $stack14.()>()","newJimple":"specialinvoke $stack16.()>()"}},{"action":"Update","oldLine":19,"newLine":21,"oldCode":" System.out.println(\"identical Result: \" + t);","newCode":" System.out.println(\"identical Result: \" + meep);","difference":{"message":null,"oldJimple":"specialinvoke $stack26.()>()","newJimple":"specialinvoke $stack28.()>()"}},{"action":"Update","oldLine":17,"newLine":20,"oldCode":" System.out.println(\"Detailed Computation Result: \" + complexRes);","newCode":" System.out.println(\"Complex Calculation Result: \" + complexResult);","difference":{"message":null,"oldJimple":"$stack22 = virtualinvoke $stack20.(\"Detailed Computation Result: \")","newJimple":"specialinvoke $stack23.()>()"}},{"action":"Update","oldLine":19,"newLine":21,"oldCode":" System.out.println(\"identical Result: \" + t);","newCode":" System.out.println(\"identical Result: \" + meep);","difference":{"message":null,"oldJimple":"$stack28 = virtualinvoke $stack26.(\"identical Result: \")","newJimple":"$stack30 = virtualinvoke $stack28.(\"identical Result: \")"}},{"action":"Update","oldLine":17,"newLine":20,"oldCode":" System.out.println(\"Detailed Computation Result: \" + complexRes);","newCode":" System.out.println(\"Complex Calculation Result: \" + complexResult);","difference":{"message":null,"oldJimple":"virtualinvoke $stack21.($stack24)","newJimple":"$stack27 = virtualinvoke $stack26.()"}},{"action":"Update","oldLine":14,"newLine":14,"oldCode":" System.out.println(\"Result: \" + res);","newCode":" System.out.println(\"Product: \" + product);","difference":{"message":null,"oldJimple":"$stack18 = virtualinvoke $stack17.()","newJimple":"$stack20 = virtualinvoke $stack19.()"}},{"action":"Update","oldLine":14,"newLine":14,"oldCode":" System.out.println(\"Result: \" + res);","newCode":" System.out.println(\"Product: \" + product);","difference":{"message":null,"oldJimple":"virtualinvoke $stack15.($stack18)","newJimple":"virtualinvoke $stack17.($stack20)"}},{"action":"Update","oldLine":12,"newLine":12,"oldCode":" System.out.println(\"Result: \" + result);","newCode":" System.out.println(\"Result: \" + result);","difference":{"message":null,"oldJimple":"$stack12 = virtualinvoke $stack11.()","newJimple":"$stack14 = virtualinvoke $stack13.()"}},{"action":"Update","oldLine":19,"newLine":21,"oldCode":" System.out.println(\"identical Result: \" + t);","newCode":" System.out.println(\"identical Result: \" + meep);","difference":{"message":null,"oldJimple":"$stack27 = ","newJimple":"$stack29 = "}},{"action":"Update","oldLine":17,"newLine":20,"oldCode":" System.out.println(\"Detailed Computation Result: \" + complexRes);","newCode":" System.out.println(\"Complex Calculation Result: \" + complexResult);","difference":{"message":null,"oldJimple":"$stack23 = virtualinvoke $stack22.($stack19)","newJimple":"$stack25 = virtualinvoke $stack23.(\"Complex Calculation Result: \")"}},{"action":"Update","oldLine":12,"newLine":12,"oldCode":" System.out.println(\"Result: \" + result);","newCode":" System.out.println(\"Result: \" + result);","difference":{"message":null,"oldJimple":"$stack9 = ","newJimple":"$stack11 = "}},{"action":"Update","oldLine":12,"newLine":12,"oldCode":" System.out.println(\"Result: \" + result);","newCode":" System.out.println(\"Result: \" + result);","difference":{"message":null,"oldJimple":"$stack10 = virtualinvoke $stack8.(\"Result: \")","newJimple":"$stack12 = virtualinvoke $stack10.(\"Result: \")"}},{"action":"Update","oldLine":10,"newLine":8,"oldCode":" TestAdder1 test = new TestAdder1();","newCode":" TestAdder2 test = new TestAdder2();","difference":{"message":null,"oldJimple":"$stack6 = new org.pdgdiff.testclasses.TestAdder1","newJimple":"$stack8 = new org.pdgdiff.testclasses.TestAdder2"}},{"action":"Update","oldLine":12,"newLine":12,"oldCode":" System.out.println(\"Result: \" + result);","newCode":" System.out.println(\"Result: \" + result);","difference":{"message":null,"oldJimple":"specialinvoke $stack8.()>()","newJimple":"specialinvoke $stack10.()>()"}},{"action":"Update","oldLine":-1,"newLine":-1,"oldCode":"","newCode":"","difference":{"message":null,"oldJimple":"this := @this: org.pdgdiff.testclasses.TestAdder1","newJimple":"this := @this: org.pdgdiff.testclasses.TestAdder2"}},{"action":"Update","oldLine":-1,"newLine":-1,"oldCode":"","newCode":"","difference":{"message":null,"oldJimple":"b := @parameter1: int","newJimple":"number2 := @parameter1: int"}},{"action":"Update","oldLine":39,"newLine":25,"oldCode":" int sum = toadd1 + toadd2;","newCode":" int sum = number - number2;","difference":{"message":null,"oldJimple":"sum = a + b","newJimple":"sum = number - number2"}},{"action":"Update","oldLine":-1,"newLine":-1,"oldCode":"","newCode":"","difference":{"message":null,"oldJimple":"a := @parameter0: int","newJimple":"number := @parameter0: int"}},{"action":"Update","oldLine":44,"newLine":30,"oldCode":" int sum = a - b;","newCode":" int product = number * number2;","difference":{"message":null,"oldJimple":"sum = a - b","newJimple":"product = number * number2"}},{"action":"Update","oldLine":43,"newLine":29,"oldCode":"public int minus(int, int)","newCode":"public int multiplyNumbers(int, int)","difference":"signature change"},{"action":"Update","oldLine":-1,"newLine":-1,"oldCode":"","newCode":"","difference":{"message":null,"oldJimple":"this := @this: org.pdgdiff.testclasses.TestAdder1","newJimple":"this := @this: org.pdgdiff.testclasses.TestAdder2"}},{"action":"Update","oldLine":-1,"newLine":-1,"oldCode":"","newCode":"","difference":{"message":null,"oldJimple":"b := @parameter1: int","newJimple":"number2 := @parameter1: int"}},{"action":"Update","oldLine":45,"newLine":31,"oldCode":" return sum;","newCode":" return product;","difference":{"message":null,"oldJimple":"return sum","newJimple":"return product"}},{"action":"Update","oldLine":-1,"newLine":-1,"oldCode":"","newCode":"","difference":{"message":null,"oldJimple":"a := @parameter0: int","newJimple":"number := @parameter0: int"}},{"action":"Update","oldLine":57,"newLine":42,"oldCode":" result = num1 - num2;","newCode":" result = num1 + num2;","difference":{"message":null,"oldJimple":"result = num1 - num2","newJimple":"result = num1 + num2"}},{"action":"Update","oldLine":74,"newLine":59,"oldCode":" if (i % 2 == 1) {","newCode":" if (i % 2 == 0) {","difference":{"message":null,"oldJimple":"if $stack5 != 1 goto i = i + 1","newJimple":"if $stack5 != 0 goto result = result - i"}},{"action":"Update","oldLine":65,"newLine":50,"oldCode":" if (result % 3 == 0) {","newCode":" if (result % 2 == 0) {","difference":{"message":null,"oldJimple":"if $stack8 != 0 goto $stack9 = i * 2","newJimple":"if $stack8 != 0 goto result = result * 3"}},{"action":"Update","oldLine":50,"newLine":35,"oldCode":"public int detailedComputation(int, int)","newCode":"public int complexCalculation(int, int)","difference":"signature change"},{"action":"Update","oldLine":64,"newLine":49,"oldCode":" result -= i;","newCode":" result += i;","difference":{"message":null,"oldJimple":"result = result - i","newJimple":"result = result + i"}},{"action":"Update","oldLine":65,"newLine":50,"oldCode":" if (result % 3 == 0) {","newCode":" if (result % 2 == 0) {","difference":{"message":null,"oldJimple":"$stack8 = result % 3","newJimple":"$stack8 = result % 2"}},{"action":"Update","oldLine":63,"newLine":48,"oldCode":" for (int i = 0; i < 4; i++) {","newCode":" for (int i = 0; i < 3; i++) {","difference":{"message":null,"oldJimple":"if i >= 4 goto i = 0","newJimple":"if i >= 3 goto i = 0"}},{"action":"Update","oldLine":73,"newLine":58,"oldCode":" for (int i = 0; i < 6; i++) {","newCode":" for (int i = 0; i < 5; i++) {","difference":{"message":null,"oldJimple":"if i >= 6 goto return result","newJimple":"if i >= 5 goto return result"}},{"action":"Update","oldLine":55,"newLine":40,"oldCode":" result = num1 + num2;","newCode":" result = num1 - num2;","difference":{"message":null,"oldJimple":"result = num1 + num2","newJimple":"result = num1 - num2"}},{"action":"Insert","line":62,"code":" result -= i;"},{"action":"Update","oldLine":68,"newLine":53,"oldCode":" result += i * 2;","newCode":" result *= 3;","difference":{"message":null,"oldJimple":"$stack9 = i * 2","newJimple":"result = result * 3"}},{"action":"Update","oldLine":-1,"newLine":-1,"oldCode":"","newCode":"","difference":{"message":null,"oldJimple":"this := @this: org.pdgdiff.testclasses.TestAdder1","newJimple":"this := @this: org.pdgdiff.testclasses.TestAdder2"}},{"action":"Update","oldLine":66,"newLine":51,"oldCode":" result /= 3;","newCode":" result /= 2;","difference":{"message":null,"oldJimple":"result = result / 3","newJimple":"result = result / 2"}},{"action":"Update","oldLine":68,"newLine":-1,"oldCode":" result += i * 2;","newCode":"","difference":{"message":null,"oldJimple":"result = result + $stack9","newJimple":null}},{"action":"Update","oldLine":-1,"newLine":60,"oldCode":"","newCode":" result += i;","difference":{"message":null,"oldJimple":null,"newJimple":"goto [?= i = i + 1]"}},{"action":"Update","oldLine":75,"newLine":60,"oldCode":" result *= i;","newCode":" result += i;","difference":{"message":null,"oldJimple":"result = result * i","newJimple":"result = result + i"}},{"action":"Update","oldLine":-1,"newLine":-1,"oldCode":"","newCode":"","difference":{"message":null,"oldJimple":"this := @this: org.pdgdiff.testclasses.TestAdder1","newJimple":"this := @this: org.pdgdiff.testclasses.TestAdder2"}},{"action":"Delete","line":5,"code":"private int cheese;"},{"action":"Delete","line":7,"code":"public String swag;"},{"action":"Insert","line":5,"code":"private int another;"}]} \ No newline at end of file +{"actions":[{"action":"Update","oldLine":-1,"newLine":-1,"oldCode":"","newCode":"","difference":{"message":null,"oldJimple":"this := @this: org.pdgdiff.testclasses.TestAdder1","newJimple":"this := @this: org.pdgdiff.testclasses.TestAdder2"}},{"action":"Update","oldLine":12,"newLine":12,"oldCode":" System.out.println(\"Result: \" + result);","newCode":" System.out.println(\"Result: \" + result);","difference":{"message":null,"oldJimple":"virtualinvoke $stack9.($stack12)","newJimple":"virtualinvoke $stack11.($stack14)"}},{"action":"Update","oldLine":19,"newLine":21,"oldCode":" System.out.println(\"identical Result: \" + t);","newCode":" System.out.println(\"identical Result: \" + meep);","difference":{"message":null,"oldJimple":"$stack30 = virtualinvoke $stack29.()","newJimple":"$stack32 = virtualinvoke $stack31.()"}},{"action":"Update","oldLine":12,"newLine":12,"oldCode":" System.out.println(\"Result: \" + result);","newCode":" System.out.println(\"Result: \" + result);","difference":{"message":null,"oldJimple":"$stack8 = new java.lang.StringBuilder","newJimple":"$stack10 = new java.lang.StringBuilder"}},{"action":"Update","oldLine":10,"newLine":8,"oldCode":" TestAdder1 test = new TestAdder1();","newCode":" TestAdder2 test = new TestAdder2();","difference":{"message":null,"oldJimple":"specialinvoke $stack6.()>()","newJimple":"specialinvoke $stack8.()>()"}},{"action":"Update","oldLine":14,"newLine":14,"oldCode":" System.out.println(\"Result: \" + res);","newCode":" System.out.println(\"Product: \" + product);","difference":{"message":null,"oldJimple":"$stack15 = ","newJimple":"$stack17 = "}},{"action":"Update","oldLine":18,"newLine":20,"oldCode":" int t = test.identical(5, 10);","newCode":" System.out.println(\"Complex Calculation Result: \" + complexResult);","difference":{"message":null,"oldJimple":"$stack25 = virtualinvoke $stack6.(5, 10)","newJimple":"virtualinvoke $stack24.($stack27)"}},{"action":"Update","oldLine":12,"newLine":12,"oldCode":" System.out.println(\"Result: \" + result);","newCode":" System.out.println(\"Result: \" + result);","difference":{"message":null,"oldJimple":"$stack11 = virtualinvoke $stack10.($stack7)","newJimple":"$stack13 = virtualinvoke $stack12.($stack9)"}},{"action":"Update","oldLine":11,"newLine":11,"oldCode":" int result = test.addNumbers(5, 10);","newCode":" int result = test.addNumbers(number1, number2);","difference":{"message":null,"oldJimple":"$stack7 = virtualinvoke $stack6.(5, 10)","newJimple":"$stack9 = virtualinvoke $stack8.(5, 4)"}},{"action":"Update","oldLine":16,"newLine":18,"oldCode":" int complexRes = test.detailedComputation(5, 10);","newCode":" int complexResult = test.complexCalculation(number1, number2);","difference":{"message":null,"oldJimple":"$stack19 = virtualinvoke $stack6.(5, 10)","newJimple":"$stack21 = virtualinvoke $stack8.(5, 4)"}},{"action":"Update","oldLine":19,"newLine":21,"oldCode":" System.out.println(\"identical Result: \" + t);","newCode":" System.out.println(\"identical Result: \" + meep);","difference":{"message":null,"oldJimple":"virtualinvoke $stack27.($stack30)","newJimple":"virtualinvoke $stack29.($stack32)"}},{"action":"Update","oldLine":14,"newLine":14,"oldCode":" System.out.println(\"Result: \" + res);","newCode":" System.out.println(\"Product: \" + product);","difference":{"message":null,"oldJimple":"$stack17 = virtualinvoke $stack16.($stack13)","newJimple":"$stack19 = virtualinvoke $stack18.($stack15)"}},{"action":"Update","oldLine":13,"newLine":13,"oldCode":" int res = test.minus(10, 5);","newCode":" int product = test.multiplyNumbers(number1, number2);","difference":{"message":null,"oldJimple":"$stack13 = virtualinvoke $stack6.(10, 5)","newJimple":"$stack15 = virtualinvoke $stack8.(5, 4)"}},{"action":"Update","oldLine":14,"newLine":14,"oldCode":" System.out.println(\"Result: \" + res);","newCode":" System.out.println(\"Product: \" + product);","difference":{"message":null,"oldJimple":"$stack14 = new java.lang.StringBuilder","newJimple":"$stack16 = new java.lang.StringBuilder"}},{"action":"Update","oldLine":17,"newLine":20,"oldCode":" System.out.println(\"Detailed Computation Result: \" + complexRes);","newCode":" System.out.println(\"Complex Calculation Result: \" + complexResult);","difference":{"message":null,"oldJimple":"$stack20 = new java.lang.StringBuilder","newJimple":"$stack24 = "}},{"action":"Update","oldLine":19,"newLine":21,"oldCode":" System.out.println(\"identical Result: \" + t);","newCode":" System.out.println(\"identical Result: \" + meep);","difference":{"message":null,"oldJimple":"$stack26 = new java.lang.StringBuilder","newJimple":"$stack28 = new java.lang.StringBuilder"}},{"action":"Update","oldLine":14,"newLine":14,"oldCode":" System.out.println(\"Result: \" + res);","newCode":" System.out.println(\"Product: \" + product);","difference":{"message":null,"oldJimple":"$stack16 = virtualinvoke $stack14.(\"Result: \")","newJimple":"$stack18 = virtualinvoke $stack16.(\"Product: \")"}},{"action":"Update","oldLine":17,"newLine":20,"oldCode":" System.out.println(\"Detailed Computation Result: \" + complexRes);","newCode":" System.out.println(\"Complex Calculation Result: \" + complexResult);","difference":{"message":null,"oldJimple":"$stack24 = virtualinvoke $stack23.()","newJimple":"$stack26 = virtualinvoke $stack25.($stack21)"}},{"action":"Update","oldLine":19,"newLine":21,"oldCode":" System.out.println(\"identical Result: \" + t);","newCode":" System.out.println(\"identical Result: \" + meep);","difference":{"message":null,"oldJimple":"$stack29 = virtualinvoke $stack28.($stack25)","newJimple":"$stack31 = virtualinvoke $stack30.($stack22)"}},{"action":"Update","oldLine":17,"newLine":19,"oldCode":" System.out.println(\"Detailed Computation Result: \" + complexRes);","newCode":" int meep = test.identical(3,10);","difference":{"message":null,"oldJimple":"$stack21 = ","newJimple":"$stack22 = virtualinvoke $stack8.(3, 10)"}},{"action":"Update","oldLine":17,"newLine":20,"oldCode":" System.out.println(\"Detailed Computation Result: \" + complexRes);","newCode":" System.out.println(\"Complex Calculation Result: \" + complexResult);","difference":{"message":null,"oldJimple":"specialinvoke $stack20.()>()","newJimple":"$stack23 = new java.lang.StringBuilder"}},{"action":"Update","oldLine":14,"newLine":14,"oldCode":" System.out.println(\"Result: \" + res);","newCode":" System.out.println(\"Product: \" + product);","difference":{"message":null,"oldJimple":"specialinvoke $stack14.()>()","newJimple":"specialinvoke $stack16.()>()"}},{"action":"Update","oldLine":19,"newLine":21,"oldCode":" System.out.println(\"identical Result: \" + t);","newCode":" System.out.println(\"identical Result: \" + meep);","difference":{"message":null,"oldJimple":"specialinvoke $stack26.()>()","newJimple":"specialinvoke $stack28.()>()"}},{"action":"Update","oldLine":17,"newLine":20,"oldCode":" System.out.println(\"Detailed Computation Result: \" + complexRes);","newCode":" System.out.println(\"Complex Calculation Result: \" + complexResult);","difference":{"message":null,"oldJimple":"$stack22 = virtualinvoke $stack20.(\"Detailed Computation Result: \")","newJimple":"specialinvoke $stack23.()>()"}},{"action":"Update","oldLine":19,"newLine":21,"oldCode":" System.out.println(\"identical Result: \" + t);","newCode":" System.out.println(\"identical Result: \" + meep);","difference":{"message":null,"oldJimple":"$stack28 = virtualinvoke $stack26.(\"identical Result: \")","newJimple":"$stack30 = virtualinvoke $stack28.(\"identical Result: \")"}},{"action":"Update","oldLine":17,"newLine":20,"oldCode":" System.out.println(\"Detailed Computation Result: \" + complexRes);","newCode":" System.out.println(\"Complex Calculation Result: \" + complexResult);","difference":{"message":null,"oldJimple":"virtualinvoke $stack21.($stack24)","newJimple":"$stack27 = virtualinvoke $stack26.()"}},{"action":"Update","oldLine":14,"newLine":14,"oldCode":" System.out.println(\"Result: \" + res);","newCode":" System.out.println(\"Product: \" + product);","difference":{"message":null,"oldJimple":"$stack18 = virtualinvoke $stack17.()","newJimple":"$stack20 = virtualinvoke $stack19.()"}},{"action":"Update","oldLine":14,"newLine":14,"oldCode":" System.out.println(\"Result: \" + res);","newCode":" System.out.println(\"Product: \" + product);","difference":{"message":null,"oldJimple":"virtualinvoke $stack15.($stack18)","newJimple":"virtualinvoke $stack17.($stack20)"}},{"action":"Update","oldLine":12,"newLine":12,"oldCode":" System.out.println(\"Result: \" + result);","newCode":" System.out.println(\"Result: \" + result);","difference":{"message":null,"oldJimple":"$stack12 = virtualinvoke $stack11.()","newJimple":"$stack14 = virtualinvoke $stack13.()"}},{"action":"Update","oldLine":19,"newLine":21,"oldCode":" System.out.println(\"identical Result: \" + t);","newCode":" System.out.println(\"identical Result: \" + meep);","difference":{"message":null,"oldJimple":"$stack27 = ","newJimple":"$stack29 = "}},{"action":"Update","oldLine":17,"newLine":20,"oldCode":" System.out.println(\"Detailed Computation Result: \" + complexRes);","newCode":" System.out.println(\"Complex Calculation Result: \" + complexResult);","difference":{"message":null,"oldJimple":"$stack23 = virtualinvoke $stack22.($stack19)","newJimple":"$stack25 = virtualinvoke $stack23.(\"Complex Calculation Result: \")"}},{"action":"Update","oldLine":12,"newLine":12,"oldCode":" System.out.println(\"Result: \" + result);","newCode":" System.out.println(\"Result: \" + result);","difference":{"message":null,"oldJimple":"$stack9 = ","newJimple":"$stack11 = "}},{"action":"Update","oldLine":12,"newLine":12,"oldCode":" System.out.println(\"Result: \" + result);","newCode":" System.out.println(\"Result: \" + result);","difference":{"message":null,"oldJimple":"$stack10 = virtualinvoke $stack8.(\"Result: \")","newJimple":"$stack12 = virtualinvoke $stack10.(\"Result: \")"}},{"action":"Update","oldLine":10,"newLine":8,"oldCode":" TestAdder1 test = new TestAdder1();","newCode":" TestAdder2 test = new TestAdder2();","difference":{"message":null,"oldJimple":"$stack6 = new org.pdgdiff.testclasses.TestAdder1","newJimple":"$stack8 = new org.pdgdiff.testclasses.TestAdder2"}},{"action":"Update","oldLine":12,"newLine":12,"oldCode":" System.out.println(\"Result: \" + result);","newCode":" System.out.println(\"Result: \" + result);","difference":{"message":null,"oldJimple":"specialinvoke $stack8.()>()","newJimple":"specialinvoke $stack10.()>()"}},{"action":"Update","oldLine":-1,"newLine":-1,"oldCode":"","newCode":"","difference":{"message":null,"oldJimple":"this := @this: org.pdgdiff.testclasses.TestAdder1","newJimple":"this := @this: org.pdgdiff.testclasses.TestAdder2"}},{"action":"Update","oldLine":-1,"newLine":-1,"oldCode":"","newCode":"","difference":{"message":null,"oldJimple":"b := @parameter1: int","newJimple":"number2 := @parameter1: int"}},{"action":"Update","oldLine":39,"newLine":25,"oldCode":" int sum = toadd1 + toadd2;","newCode":" int sum = number - number2;","difference":{"message":null,"oldJimple":"sum = a + b","newJimple":"sum = number - number2"}},{"action":"Update","oldLine":-1,"newLine":-1,"oldCode":"","newCode":"","difference":{"message":null,"oldJimple":"a := @parameter0: int","newJimple":"number := @parameter0: int"}},{"action":"Update","oldLine":44,"newLine":30,"oldCode":" int sum = a - b;","newCode":" int product = number * number2;","difference":{"message":null,"oldJimple":"sum = a - b","newJimple":"product = number * number2"}},{"action":"Update","oldLine":43,"newLine":29,"oldCode":"public int minus(int, int)","newCode":"public int multiplyNumbers(int, int)","difference":"signature or class metadata change"},{"action":"Update","oldLine":-1,"newLine":-1,"oldCode":"","newCode":"","difference":{"message":null,"oldJimple":"this := @this: org.pdgdiff.testclasses.TestAdder1","newJimple":"this := @this: org.pdgdiff.testclasses.TestAdder2"}},{"action":"Update","oldLine":-1,"newLine":-1,"oldCode":"","newCode":"","difference":{"message":null,"oldJimple":"b := @parameter1: int","newJimple":"number2 := @parameter1: int"}},{"action":"Update","oldLine":45,"newLine":31,"oldCode":" return sum;","newCode":" return product;","difference":{"message":null,"oldJimple":"return sum","newJimple":"return product"}},{"action":"Update","oldLine":-1,"newLine":-1,"oldCode":"","newCode":"","difference":{"message":null,"oldJimple":"a := @parameter0: int","newJimple":"number := @parameter0: int"}},{"action":"Insert","line":-1,"code":""},{"action":"Update","oldLine":57,"newLine":42,"oldCode":" result = num1 - num2;","newCode":" result = num1 + num2;","difference":{"message":null,"oldJimple":"result = num1 - num2","newJimple":"result = num1 + num2"}},{"action":"Update","oldLine":74,"newLine":59,"oldCode":" if (i % 2 == 1) {","newCode":" if (i % 2 == 0) {","difference":{"message":null,"oldJimple":"if $stack5 != 1 goto i = i + 1","newJimple":"if $stack5 != 0 goto result = result - i"}},{"action":"Update","oldLine":65,"newLine":50,"oldCode":" if (result % 3 == 0) {","newCode":" if (result % 2 == 0) {","difference":{"message":null,"oldJimple":"if $stack8 != 0 goto $stack9 = i * 2","newJimple":"if $stack8 != 0 goto result = result * 3"}},{"action":"Update","oldLine":50,"newLine":35,"oldCode":"public int detailedComputation(int, int)","newCode":"public int complexCalculation(int, int)","difference":"signature or class metadata change"},{"action":"Update","oldLine":64,"newLine":49,"oldCode":" result -= i;","newCode":" result += i;","difference":{"message":null,"oldJimple":"result = result - i","newJimple":"result = result + i"}},{"action":"Update","oldLine":65,"newLine":50,"oldCode":" if (result % 3 == 0) {","newCode":" if (result % 2 == 0) {","difference":{"message":null,"oldJimple":"$stack8 = result % 3","newJimple":"$stack8 = result % 2"}},{"action":"Update","oldLine":63,"newLine":48,"oldCode":" for (int i = 0; i < 4; i++) {","newCode":" for (int i = 0; i < 3; i++) {","difference":{"message":null,"oldJimple":"if i >= 4 goto i = 0","newJimple":"if i >= 3 goto i = 0"}},{"action":"Update","oldLine":73,"newLine":58,"oldCode":" for (int i = 0; i < 6; i++) {","newCode":" for (int i = 0; i < 5; i++) {","difference":{"message":null,"oldJimple":"if i >= 6 goto return result","newJimple":"if i >= 5 goto return result"}},{"action":"Update","oldLine":55,"newLine":40,"oldCode":" result = num1 + num2;","newCode":" result = num1 - num2;","difference":{"message":null,"oldJimple":"result = num1 + num2","newJimple":"result = num1 - num2"}},{"action":"Insert","line":62,"code":" result -= i;"},{"action":"Update","oldLine":68,"newLine":53,"oldCode":" result += i * 2;","newCode":" result *= 3;","difference":{"message":null,"oldJimple":"$stack9 = i * 2","newJimple":"result = result * 3"}},{"action":"Update","oldLine":66,"newLine":51,"oldCode":" result /= 3;","newCode":" result /= 2;","difference":{"message":null,"oldJimple":"result = result / 3","newJimple":"result = result / 2"}},{"action":"Update","oldLine":-1,"newLine":-1,"oldCode":"","newCode":"","difference":{"message":null,"oldJimple":"this := @this: org.pdgdiff.testclasses.TestAdder1","newJimple":"this := @this: org.pdgdiff.testclasses.TestAdder2"}},{"action":"Update","oldLine":-1,"newLine":60,"oldCode":"","newCode":" result += i;","difference":{"message":null,"oldJimple":null,"newJimple":"goto [?= i = i + 1]"}},{"action":"Update","oldLine":68,"newLine":-1,"oldCode":" result += i * 2;","newCode":"","difference":{"message":null,"oldJimple":"result = result + $stack9","newJimple":null}},{"action":"Update","oldLine":75,"newLine":60,"oldCode":" result *= i;","newCode":" result += i;","difference":{"message":null,"oldJimple":"result = result * i","newJimple":"result = result + i"}},{"action":"Update","oldLine":-1,"newLine":-1,"oldCode":"","newCode":"","difference":{"message":null,"oldJimple":"this := @this: org.pdgdiff.testclasses.TestAdder1","newJimple":"this := @this: org.pdgdiff.testclasses.TestAdder2"}},{"action":"Update","oldLine":5,"newLine":5,"oldCode":"private int cheese;","newCode":"private int another;","difference":"signature or class metadata change"},{"action":"Delete","line":7,"code":"public String swag;"}]} \ No newline at end of file diff --git a/src/main/java/org/pdgdiff/edit/model/SyntaxDifference.java b/src/main/java/org/pdgdiff/edit/model/SyntaxDifference.java index a35b322..795a2d2 100644 --- a/src/main/java/org/pdgdiff/edit/model/SyntaxDifference.java +++ b/src/main/java/org/pdgdiff/edit/model/SyntaxDifference.java @@ -5,7 +5,6 @@ import org.pdgdiff.util.SourceCodeMapper; import soot.Unit; import soot.tagkit.LineNumberTag; -import soot.toolkits.graph.pdg.PDGNode; import java.util.Objects; diff --git a/src/main/java/org/pdgdiff/edit/model/Update.java b/src/main/java/org/pdgdiff/edit/model/Update.java index 2df259b..2a2cfe5 100644 --- a/src/main/java/org/pdgdiff/edit/model/Update.java +++ b/src/main/java/org/pdgdiff/edit/model/Update.java @@ -1,7 +1,6 @@ package org.pdgdiff.edit.model; import org.pdgdiff.graph.model.MyPDGNode; -import soot.toolkits.graph.pdg.PDGNode; import java.util.Objects; diff --git a/src/main/java/org/pdgdiff/graph/model/MyBlock.java b/src/main/java/org/pdgdiff/graph/model/MyBlock.java new file mode 100644 index 0000000..d87071b --- /dev/null +++ b/src/main/java/org/pdgdiff/graph/model/MyBlock.java @@ -0,0 +1,40 @@ +package org.pdgdiff.graph.model; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + + +// Follows how soot does it, a block is a collection of units (i.e. block of code) +public class MyBlock implements Iterable { + + private List units; + + public MyBlock() { + this.units = new ArrayList<>(); + } + + public MyBlock(List units) { + this.units = units; + } + + public List getUnits() { + return units; + } + + public void addUnit(MyUnit unit) { + units.add(unit); + } + + @Override + public Iterator iterator() { + return units.iterator(); + } + + public MyUnit getHead() { + if (!units.isEmpty()) { + return units.get(0); + } + return null; + } +} diff --git a/src/main/java/org/pdgdiff/graph/model/MyMethod.java b/src/main/java/org/pdgdiff/graph/model/MyMethod.java new file mode 100644 index 0000000..e01c685 --- /dev/null +++ b/src/main/java/org/pdgdiff/graph/model/MyMethod.java @@ -0,0 +1,5 @@ +package org.pdgdiff.graph.model; + +public class MyMethod { + // TODO if trying to decouple from Soot completely. Also going to need to decouple from SootClass. +} diff --git a/src/main/java/org/pdgdiff/graph/model/MyPDGNode.java b/src/main/java/org/pdgdiff/graph/model/MyPDGNode.java index c36c391..02edc49 100644 --- a/src/main/java/org/pdgdiff/graph/model/MyPDGNode.java +++ b/src/main/java/org/pdgdiff/graph/model/MyPDGNode.java @@ -5,7 +5,7 @@ import java.util.Objects; public class MyPDGNode { - private Object node; + private Object node; // this will either by block or region private MyPDGNodeType type; private String attrib; private List dependents; diff --git a/src/main/java/org/pdgdiff/graph/model/MyRegion.java b/src/main/java/org/pdgdiff/graph/model/MyRegion.java new file mode 100644 index 0000000..1ec5ec6 --- /dev/null +++ b/src/main/java/org/pdgdiff/graph/model/MyRegion.java @@ -0,0 +1,26 @@ +package org.pdgdiff.graph.model; + +import java.util.List; + +public interface MyRegion { + + int getID(); + + MyUnit getFirst(); + + MyUnit getLast(); + + List getUnits(); + + List getUnits(MyUnit from, MyUnit to); + + List getBlocks(); + + void setParent(MyRegion parent); + + MyRegion getParent(); + + void addChildRegion(MyRegion child); + + List getChildRegions(); +} diff --git a/src/main/java/org/pdgdiff/graph/model/MyUnit.java b/src/main/java/org/pdgdiff/graph/model/MyUnit.java new file mode 100644 index 0000000..76725e5 --- /dev/null +++ b/src/main/java/org/pdgdiff/graph/model/MyUnit.java @@ -0,0 +1,39 @@ +package org.pdgdiff.graph.model; + +// single piece of code +public class MyUnit { + + private String code; + private int lineNumber; + + public MyUnit(String code, int lineNumber) { + this.code = code; + this.lineNumber = lineNumber; + } + + public String getCode() { + return code; + } + + public int getLineNumber() { + return lineNumber; + } + + @Override + public String toString() { + return code; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (!(obj instanceof MyUnit)) return false; + MyUnit other = (MyUnit) obj; + return code.equals(other.code) && lineNumber == other.lineNumber; + } + + @Override + public int hashCode() { + return code.hashCode() * 31 + lineNumber; + } +} diff --git a/src/main/java/org/pdgdiff/graph/model/model.md b/src/main/java/org/pdgdiff/graph/model/model.md new file mode 100644 index 0000000..c0afb3f --- /dev/null +++ b/src/main/java/org/pdgdiff/graph/model/model.md @@ -0,0 +1,5 @@ +A brief explanation of the model; + +A PDG is a directed graph that represents the control flow of a program. +It is composed of multiple PDGNodes. Each node can be either a CFG Node, represented by a Block, or a Region, represented by a Region NOde. +A Block consits of multiple units, where a unit is a single statement or expression. \ No newline at end of file diff --git a/src/main/java/org/pdgdiff/matching/GraphMatcherFactory.java b/src/main/java/org/pdgdiff/matching/GraphMatcherFactory.java index 548ca2c..e681728 100644 --- a/src/main/java/org/pdgdiff/matching/GraphMatcherFactory.java +++ b/src/main/java/org/pdgdiff/matching/GraphMatcherFactory.java @@ -1,11 +1,9 @@ package org.pdgdiff.matching; import org.pdgdiff.graph.model.MyPDG; -import org.pdgdiff.graph.model.MyPDGNode; import org.pdgdiff.matching.models.HeuristicGraphMatcher; import org.pdgdiff.matching.models.UllmannGraphMatcher; import org.pdgdiff.matching.models.VF2GraphMatcher; -import soot.toolkits.graph.pdg.HashMutablePDG; import java.util.List; diff --git a/src/main/java/org/pdgdiff/matching/PDGComparator.java b/src/main/java/org/pdgdiff/matching/PDGComparator.java index cd8599c..a251420 100644 --- a/src/main/java/org/pdgdiff/matching/PDGComparator.java +++ b/src/main/java/org/pdgdiff/matching/PDGComparator.java @@ -9,7 +9,6 @@ import org.pdgdiff.io.JsonOperationSerializer; import org.pdgdiff.io.OperationSerializer; import soot.SootClass; -import soot.toolkits.graph.pdg.HashMutablePDG; import com.google.gson.JsonArray; diff --git a/src/main/java/org/pdgdiff/matching/models/HeuristicGraphMatcher.java b/src/main/java/org/pdgdiff/matching/models/HeuristicGraphMatcher.java index e572a67..66cb712 100644 --- a/src/main/java/org/pdgdiff/matching/models/HeuristicGraphMatcher.java +++ b/src/main/java/org/pdgdiff/matching/models/HeuristicGraphMatcher.java @@ -5,7 +5,6 @@ import org.pdgdiff.matching.GraphMatcher; import org.pdgdiff.matching.NodeMapping; import org.pdgdiff.matching.models.heuristic.HeuristicMatcher; -import soot.toolkits.graph.pdg.HashMutablePDG; import java.util.List; diff --git a/src/main/java/org/pdgdiff/matching/models/UllmannGraphMatcher.java b/src/main/java/org/pdgdiff/matching/models/UllmannGraphMatcher.java index a5cafe1..892f0d7 100644 --- a/src/main/java/org/pdgdiff/matching/models/UllmannGraphMatcher.java +++ b/src/main/java/org/pdgdiff/matching/models/UllmannGraphMatcher.java @@ -6,7 +6,6 @@ import org.pdgdiff.matching.GraphMatcher; import org.pdgdiff.matching.NodeMapping; import org.pdgdiff.matching.models.ullmann.UllmannMatcher; -import soot.toolkits.graph.pdg.HashMutablePDG; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/org/pdgdiff/matching/models/heuristic/HeuristicMatcher.java b/src/main/java/org/pdgdiff/matching/models/heuristic/HeuristicMatcher.java index 73872bd..3bd07ea 100644 --- a/src/main/java/org/pdgdiff/matching/models/heuristic/HeuristicMatcher.java +++ b/src/main/java/org/pdgdiff/matching/models/heuristic/HeuristicMatcher.java @@ -4,8 +4,7 @@ import org.pdgdiff.graph.model.MyPDGNode; import org.pdgdiff.matching.NodeMapping; import org.pdgdiff.graph.GraphTraversal; -import soot.toolkits.graph.pdg.HashMutablePDG; -import soot.toolkits.graph.pdg.PDGNode; + import java.util.List; diff --git a/src/main/java/org/pdgdiff/matching/models/ullmann/UllmannMatcher.java b/src/main/java/org/pdgdiff/matching/models/ullmann/UllmannMatcher.java index f06ce3b..7550f31 100644 --- a/src/main/java/org/pdgdiff/matching/models/ullmann/UllmannMatcher.java +++ b/src/main/java/org/pdgdiff/matching/models/ullmann/UllmannMatcher.java @@ -4,8 +4,6 @@ import org.pdgdiff.graph.model.MyPDG; import org.pdgdiff.graph.model.MyPDGNode; import org.pdgdiff.matching.NodeMapping; -import soot.toolkits.graph.pdg.HashMutablePDG; -import soot.toolkits.graph.pdg.PDGNode; import java.util.*; diff --git a/src/main/java/org/pdgdiff/matching/models/vf2/CandidatePair.java b/src/main/java/org/pdgdiff/matching/models/vf2/CandidatePair.java index be259c6..3459529 100644 --- a/src/main/java/org/pdgdiff/matching/models/vf2/CandidatePair.java +++ b/src/main/java/org/pdgdiff/matching/models/vf2/CandidatePair.java @@ -1,7 +1,6 @@ package org.pdgdiff.matching.models.vf2; import org.pdgdiff.graph.model.MyPDGNode; -import soot.toolkits.graph.pdg.PDGNode; class CandidatePair { MyPDGNode n1;