diff --git a/src/main/java/gui/webdiff/DirComparator.java b/src/main/java/gui/webdiff/DirComparator.java index ef2cc4ae0a..c2324a1fd2 100644 --- a/src/main/java/gui/webdiff/DirComparator.java +++ b/src/main/java/gui/webdiff/DirComparator.java @@ -11,7 +11,7 @@ public class DirComparator { private final List diffs; private final ProjectASTDiff projectASTDiff; private final DefaultMutableTreeNode compressedTree; - private final Map modifiedFilesName; + private final List> modifiedFilesName; private Set removedFilesName; private Set addedFilesName; @@ -27,7 +27,7 @@ public Set getAddedFilesName() { return addedFilesName; } - public Map getModifiedFilesName() { + public List> getModifiedFilesName() { return modifiedFilesName; } public Pair getFileContentsPair(int id) @@ -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(); } @@ -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()); } diff --git a/src/main/java/gui/webdiff/TreeViewGenerator.java b/src/main/java/gui/webdiff/TreeViewGenerator.java index 9c4b5c3334..763db4b9bc 100644 --- a/src/main/java/gui/webdiff/TreeViewGenerator.java +++ b/src/main/java/gui/webdiff/TreeViewGenerator.java @@ -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 { @@ -18,10 +19,10 @@ public DefaultMutableTreeNode getCompressedTree() { return compressedTree; } - public TreeViewGenerator(Map modifiedFilesName, List diffs){ + public TreeViewGenerator(List> modifiedFilesName, List diffs){ this.diffs = diffs; - for(Map.Entry pair : modifiedFilesName.entrySet()) { - String fileName = pair.getValue(); + for(Pair pair : modifiedFilesName) { + String fileName = pair.second; String[] tokens = fileName.split("/"); int counter = 1; for(String token : tokens) { diff --git a/src/main/java/org/refactoringminer/astDiff/actions/ProjectASTDiff.java b/src/main/java/org/refactoringminer/astDiff/actions/ProjectASTDiff.java index fb3ad1cbdf..d20436d5ba 100644 --- a/src/main/java/org/refactoringminer/astDiff/actions/ProjectASTDiff.java +++ b/src/main/java/org/refactoringminer/astDiff/actions/ProjectASTDiff.java @@ -9,6 +9,7 @@ public class ProjectASTDiff { private final Set diffSet = new LinkedHashSet<>(); + private final Set moveDiffSet = new LinkedHashSet<>(); private Map fileContentsBefore; private Map fileContentsAfter; private List refactorings; @@ -30,10 +31,18 @@ public Set getDiffSet() { return diffSet; } + public Set getMoveDiffSet() { + return moveDiffSet; + } + public void addASTDiff(ASTDiff diff) { diffSet.add(diff); } + public void addMoveASTDiff(ASTDiff diff) { + moveDiffSet.add(diff); + } + public void setRefactorings(List refactorings) {this.refactorings = refactorings;} public List getRefactorings() { return refactorings;} diff --git a/src/main/java/org/refactoringminer/astDiff/matchers/ProjectASTDiffer.java b/src/main/java/org/refactoringminer/astDiff/matchers/ProjectASTDiffer.java index 4582e66479..9beacf387e 100644 --- a/src/main/java/org/refactoringminer/astDiff/matchers/ProjectASTDiffer.java +++ b/src/main/java/org/refactoringminer/astDiff/matchers/ProjectASTDiffer.java @@ -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; @@ -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; @@ -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, List> filePairMappings = new LinkedHashMap<>(); + for(ASTDiff diff : projectASTDiff.getDiffSet()) { + Map> methodDeclarationMappings = new LinkedHashMap>(); + Map> fieldDeclarationMappings = new LinkedHashMap>(); + Map actionMap = new LinkedHashMap(); + ExtendedOnlyRootsClassifier classifier = (ExtendedOnlyRootsClassifier) diff.createRootNodesClassifier(); + Map 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 mappings = new ArrayList(); + 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 mappings = new ArrayList(); + 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 pair = new Pair(srcPath, dstPath); + if(filePairMappings.containsKey(pair)) { + filePairMappings.get(pair).addAll(methodDeclarationMappings.get(key)); + } + else { + List mappings = new ArrayList(); + 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 pair = new Pair(srcPath, dstPath); + if(filePairMappings.containsKey(pair)) { + filePairMappings.get(pair).addAll(fieldDeclarationMappings.get(key)); + } + else { + List mappings = new ArrayList(); + mappings.addAll(fieldDeclarationMappings.get(key)); + filePairMappings.put(pair, mappings); + } + } + } + } + } + for(Pair pair : filePairMappings.keySet()) { + Pair treeContextPairs = findTreeContexts(pair.first, pair.second); + List 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 getMappingForLeft(ASTDiff diff, Tree left) { + List matchingMappings = new ArrayList(); + for(Mapping mapping : diff.getAllMappings()) { + if(mapping.first.equals(left)) { + matchingMappings.add(mapping); + } + } + return matchingMappings; + } + private List withCorrectOrder(List umlDiffs) { ArrayList result = new ArrayList<>(umlDiffs); Set seen = new HashSet<>(); @@ -140,6 +248,11 @@ else if (existing.getDstPath().equals(classBaseDiff.getNextClass().getSourceFile return null; } + private Pair findTreeContexts(String srcPath, String dstPath) { + return new Pair<>(modelDiff.getParentModel().getTreeContextMap().get(srcPath), + modelDiff.getChildModel().getTreeContextMap().get(dstPath)); + } + private Pair findTreeContexts(UMLAbstractClassDiff classDiff) { return new Pair<>(modelDiff.getParentModel().getTreeContextMap().get(classDiff.getOriginalClass().getSourceFile()), modelDiff.getChildModel().getTreeContextMap().get(classDiff.getNextClass().getSourceFile()));