Skip to content

Commit

Permalink
Generate diffs for moved code (issue #703)
Browse files Browse the repository at this point in the history
  • Loading branch information
tsantalis committed Apr 30, 2024
1 parent d710f53 commit 592a1cf
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 8 deletions.
9 changes: 5 additions & 4 deletions src/main/java/gui/webdiff/DirComparator.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public class DirComparator {
private final List<ASTDiff> diffs;
private final ProjectASTDiff projectASTDiff;
private final DefaultMutableTreeNode compressedTree;
private final Map<String,String> modifiedFilesName;
private final List<Pair<String,String>> modifiedFilesName;
private Set<String> removedFilesName;
private Set<String> addedFilesName;

Expand All @@ -27,7 +27,7 @@ public Set<String> getAddedFilesName() {
return addedFilesName;
}

public Map<String,String> getModifiedFilesName() {
public List<Pair<String,String>> getModifiedFilesName() {
return modifiedFilesName;
}
public Pair<String,String> getFileContentsPair(int id)
Expand All @@ -42,7 +42,8 @@ public DirComparator(ProjectASTDiff projectASTDiff)
{
this.projectASTDiff = projectASTDiff;
this.diffs = new ArrayList<>(projectASTDiff.getDiffSet());
modifiedFilesName = new LinkedHashMap<>();
this.diffs.addAll(projectASTDiff.getMoveDiffSet());
modifiedFilesName = new ArrayList<>();
compare();
compressedTree = new TreeViewGenerator(getModifiedFilesName(), diffs).getCompressedTree();
}
Expand All @@ -55,7 +56,7 @@ private void compare() {
addedFilesName = new HashSet<>(afterFiles);

for (ASTDiff diff : diffs) {
modifiedFilesName.put(diff.getSrcPath(),diff.getDstPath());
modifiedFilesName.add(new Pair<>(diff.getSrcPath(),diff.getDstPath()));
removedFilesName.remove(diff.getSrcPath());
addedFilesName.remove(diff.getDstPath());
}
Expand Down
9 changes: 5 additions & 4 deletions src/main/java/gui/webdiff/TreeViewGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@

import org.refactoringminer.astDiff.actions.ASTDiff;

import com.github.gumtreediff.utils.Pair;

import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeNode;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;

/* Created by pourya on 2024-04-16*/
public class TreeViewGenerator {
Expand All @@ -18,10 +19,10 @@ public DefaultMutableTreeNode getCompressedTree() {
return compressedTree;
}

public TreeViewGenerator(Map<String, String> modifiedFilesName, List<ASTDiff> diffs){
public TreeViewGenerator(List<Pair<String,String>> modifiedFilesName, List<ASTDiff> diffs){
this.diffs = diffs;
for(Map.Entry<String, String> pair : modifiedFilesName.entrySet()) {
String fileName = pair.getValue();
for(Pair<String, String> pair : modifiedFilesName) {
String fileName = pair.second;
String[] tokens = fileName.split("/");
int counter = 1;
for(String token : tokens) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

public class ProjectASTDiff {
private final Set<ASTDiff> diffSet = new LinkedHashSet<>();
private final Set<ASTDiff> moveDiffSet = new LinkedHashSet<>();
private Map<String, String> fileContentsBefore;
private Map<String, String> fileContentsAfter;
private List<Refactoring> refactorings;
Expand All @@ -30,10 +31,18 @@ public Set<ASTDiff> getDiffSet() {
return diffSet;
}

public Set<ASTDiff> getMoveDiffSet() {
return moveDiffSet;
}

public void addASTDiff(ASTDiff diff) {
diffSet.add(diff);
}

public void addMoveASTDiff(ASTDiff diff) {
moveDiffSet.add(diff);
}

public void setRefactorings(List<Refactoring> refactorings) {this.refactorings = refactorings;}

public List<Refactoring> getRefactorings() { return refactorings;}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.refactoringminer.astDiff.matchers;

import com.github.gumtreediff.actions.model.Action;
import com.github.gumtreediff.matchers.Mapping;
import com.github.gumtreediff.tree.Tree;
import com.github.gumtreediff.tree.TreeContext;
import com.github.gumtreediff.utils.Pair;
Expand All @@ -14,7 +16,9 @@
import org.refactoringminer.api.RefactoringMinerTimedOutException;
import org.refactoringminer.api.RefactoringType;
import org.refactoringminer.astDiff.actions.ASTDiff;
import org.refactoringminer.astDiff.actions.ExtendedOnlyRootsClassifier;
import org.refactoringminer.astDiff.actions.ProjectASTDiff;
import org.refactoringminer.astDiff.actions.model.MoveOut;
import org.refactoringminer.astDiff.utils.TreeUtilFunctions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -70,8 +74,112 @@ private void diff() throws RefactoringMinerTimedOutException {
long diff_execution_finished = System.currentTimeMillis();
logger.info("Diff execution: " + (diff_execution_finished - diff_execution_started)/ 1000 + " seconds");
computeAllEditScripts();
createASTDiffsForMovedDeclarations();
}

private void createASTDiffsForMovedDeclarations() {
Map<Pair<String, String>, List<Mapping>> filePairMappings = new LinkedHashMap<>();
for(ASTDiff diff : projectASTDiff.getDiffSet()) {
Map<Tree, List<Mapping>> methodDeclarationMappings = new LinkedHashMap<Tree, List<Mapping>>();
Map<Tree, List<Mapping>> fieldDeclarationMappings = new LinkedHashMap<Tree, List<Mapping>>();
Map<Tree, Action> actionMap = new LinkedHashMap<Tree, Action>();
ExtendedOnlyRootsClassifier classifier = (ExtendedOnlyRootsClassifier) diff.createRootNodesClassifier();
Map<Tree, Action> map = classifier.getSrcMoveOutTreeMap();
for(Tree src : map.keySet()) {
Tree methodRoot = TreeUtilFunctions.getParentUntilType(src, Constants.METHOD_DECLARATION);
if(methodRoot != null) {
if(methodDeclarationMappings.containsKey(methodRoot)) {
methodDeclarationMappings.get(methodRoot).addAll(getMappingForLeft(diff, src));
}
else {
List<Mapping> mappings = new ArrayList<Mapping>();
mappings.addAll(getMappingForLeft(diff, src));
methodDeclarationMappings.put(methodRoot, mappings);
if(map.containsKey(methodRoot)) {
actionMap.put(methodRoot, map.get(methodRoot));
}
}
}
Tree fieldRoot = TreeUtilFunctions.getParentUntilType(src, Constants.FIELD_DECLARATION);
if(fieldRoot != null) {
if(methodDeclarationMappings.containsKey(fieldRoot)) {
fieldDeclarationMappings.get(fieldRoot).addAll(getMappingForLeft(diff, src));
}
else {
List<Mapping> mappings = new ArrayList<Mapping>();
mappings.addAll(getMappingForLeft(diff, src));
fieldDeclarationMappings.put(fieldRoot, mappings);
if(map.containsKey(fieldRoot)) {
actionMap.put(fieldRoot, map.get(fieldRoot));
}
}
}
}
//group the mappings based on the pair of src and dst files.
String srcPath = diff.getSrcPath();
for(Tree key : methodDeclarationMappings.keySet()) {
if(actionMap.containsKey(key)) {
Action action = actionMap.get(key);
if(action instanceof MoveOut) {
MoveOut moveOut = (MoveOut)action;
String dstPath = moveOut.getDstFile();
Pair<String, String> pair = new Pair<String, String>(srcPath, dstPath);
if(filePairMappings.containsKey(pair)) {
filePairMappings.get(pair).addAll(methodDeclarationMappings.get(key));
}
else {
List<Mapping> mappings = new ArrayList<Mapping>();
mappings.addAll(methodDeclarationMappings.get(key));
filePairMappings.put(pair, mappings);
}
}
}
}
for(Tree key : fieldDeclarationMappings.keySet()) {
if(actionMap.containsKey(key)) {
Action action = actionMap.get(key);
if(action instanceof MoveOut) {
MoveOut moveOut = (MoveOut)action;
String dstPath = moveOut.getDstFile();
Pair<String, String> pair = new Pair<String, String>(srcPath, dstPath);
if(filePairMappings.containsKey(pair)) {
filePairMappings.get(pair).addAll(fieldDeclarationMappings.get(key));
}
else {
List<Mapping> mappings = new ArrayList<Mapping>();
mappings.addAll(fieldDeclarationMappings.get(key));
filePairMappings.put(pair, mappings);
}
}
}
}
}
for(Pair<String, String> pair : filePairMappings.keySet()) {
Pair<TreeContext, TreeContext> treeContextPairs = findTreeContexts(pair.first, pair.second);
List<Mapping> mappings = filePairMappings.get(pair);
if(mappings.size() > 0) {
Tree leftRoot = TreeUtilFunctions.getFinalRoot(mappings.get(0).first);
Tree rightRoot = TreeUtilFunctions.getFinalRoot(mappings.get(0).second);
ExtendedMultiMappingStore store = new ExtendedMultiMappingStore(leftRoot, rightRoot);
for(Mapping m : mappings) {
store.addMapping(m.first, m.second);
}
ASTDiff diff = new ASTDiff(pair.first, pair.second, treeContextPairs.first, treeContextPairs.second, store);
projectASTDiff.addMoveASTDiff(diff);
}
}
}

private List<Mapping> getMappingForLeft(ASTDiff diff, Tree left) {
List<Mapping> matchingMappings = new ArrayList<Mapping>();
for(Mapping mapping : diff.getAllMappings()) {
if(mapping.first.equals(left)) {
matchingMappings.add(mapping);
}
}
return matchingMappings;
}

private List<? extends UMLAbstractClassDiff> withCorrectOrder(List<? extends UMLAbstractClassDiff> umlDiffs) {
ArrayList<UMLAbstractClassDiff> result = new ArrayList<>(umlDiffs);
Set<UMLAbstractClassDiff> seen = new HashSet<>();
Expand Down Expand Up @@ -140,6 +248,11 @@ else if (existing.getDstPath().equals(classBaseDiff.getNextClass().getSourceFile
return null;
}

private Pair<TreeContext, TreeContext> findTreeContexts(String srcPath, String dstPath) {
return new Pair<>(modelDiff.getParentModel().getTreeContextMap().get(srcPath),
modelDiff.getChildModel().getTreeContextMap().get(dstPath));
}

private Pair<TreeContext, TreeContext> findTreeContexts(UMLAbstractClassDiff classDiff) {
return new Pair<>(modelDiff.getParentModel().getTreeContextMap().get(classDiff.getOriginalClass().getSourceFile()),
modelDiff.getChildModel().getTreeContextMap().get(classDiff.getNextClass().getSourceFile()));
Expand Down

0 comments on commit 592a1cf

Please sign in to comment.