Skip to content

Commit a5a30cd

Browse files
committed
Enable detection of Move Class in commit
javaparser/javaparser@2f5b010 Move Class japa.bdd.samples.JavaConcepts.A moved to japa.bdd.samples.JavaConceptsMethods.A
1 parent 895651e commit a5a30cd

File tree

4 files changed

+74
-6
lines changed

4 files changed

+74
-6
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -509,11 +509,11 @@ Moreover, the benchmark has been extended with valid instances for the following
509509
* `Move Code`
510510
* `Split Class`
511511

512-
As of **November 14, 2025** the precision and recall of RefactoringMiner on this benchmark is:
512+
As of **November 15, 2025** the precision and recall of RefactoringMiner on this benchmark is:
513513

514514
| Refactoring Type | TP | FP | FN | Precision | Recall |
515515
|:-----------------------|-----------:|--------:|--------:|--------:|--------:|
516-
|**Total**|3443 | 46 | 86 | 0.987 | 0.976|
516+
|**Total**|3446 | 44 | 85 | 0.987 | 0.976|
517517
|Extract Method|373 | 1 | 4 | 0.997 | 0.989|
518518
|Rename Class|233 | 0 | 1 | 1.000 | 0.996|
519519
|Move Attribute|72 | 0 | 7 | 1.000 | 0.911|
@@ -523,7 +523,7 @@ As of **November 14, 2025** the precision and recall of RefactoringMiner on this
523523
|Move Method|266 | 1 | 0 | 0.996 | 1.000|
524524
|Move And Rename Method|24 | 4 | 1 | 0.857 | 0.960|
525525
|Pull Up Method|45 | 0 | 1 | 1.000 | 0.978|
526-
|Move Class|141 | 4 | 2 | 0.972 | 0.986|
526+
|Move Class|144 | 2 | 1 | 0.986 | 0.993|
527527
|Move And Rename Class|28 | 0 | 0 | 1.000 | 1.000|
528528
|Pull Up Attribute|12 | 0 | 0 | 1.000 | 1.000|
529529
|Push Down Attribute| 6 | 0 | 0 | 1.000 | 1.000|

src/main/java/gr/uom/java/xmi/diff/UMLModelDiff.java

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ public class UMLModelDiff {
105105
private Map<MergeVariableReplacement, Set<CandidateMergeVariableRefactoring>> mergeMap = new LinkedHashMap<MergeVariableReplacement, Set<CandidateMergeVariableRefactoring>>();
106106
private List<UMLCommentListDiff> commentsMovedBetweenClasses = new ArrayList<UMLCommentListDiff>();
107107
private Map<MethodInvocationReplacement, UMLOperationBodyMapper> consistentMethodInvocationRenames = new LinkedHashMap<>();
108+
private List<UMLClassMoveDiff> classMoveDiffListToBePostProcessed = new ArrayList<>();
108109

109110
public UMLModelDiff(UMLModel parentModel, UMLModel childModel) {
110111
this.parentModel = parentModel;
@@ -778,6 +779,11 @@ public void checkForMovedClasses(Set<String> repositoryDirectories, UMLClassMatc
778779
UMLClassMoveDiff classMoveDiff = new UMLClassMoveDiff(removedClass, addedClass, this, matchResult);
779780
diffSet.add(classMoveDiff);
780781
}
782+
else {
783+
UMLClassMoveDiff classMoveDiff = new UMLClassMoveDiff(removedClass, addedClass, this, matchResult);
784+
if(!classMoveDiffListToBePostProcessed.contains(classMoveDiff))
785+
classMoveDiffListToBePostProcessed.add(classMoveDiff);
786+
}
781787
}
782788
}
783789
if(!diffSet.isEmpty()) {
@@ -841,6 +847,11 @@ public void checkForMovedClasses(Set<String> repositoryDirectories, UMLClassMatc
841847
UMLClassMoveDiff classMoveDiff = new UMLClassMoveDiff(removedClass, addedClass, this, matchResult);
842848
diffSet.add(classMoveDiff);
843849
}
850+
else {
851+
UMLClassMoveDiff classMoveDiff = new UMLClassMoveDiff(removedClass, addedClass, this, matchResult);
852+
if(!classMoveDiffListToBePostProcessed.contains(classMoveDiff))
853+
classMoveDiffListToBePostProcessed.add(classMoveDiff);
854+
}
844855
}
845856
}
846857
if(!diffSet.isEmpty()) {
@@ -4365,6 +4376,63 @@ else if(r.getRefactoringType().equals(RefactoringType.EXTRACT_AND_MOVE_OPERATION
43654376
}
43664377
}
43674378
}
4379+
//check the presence of the same class being moved to multiple targets
4380+
Map<String, Set<String>> moveTargetMap = new LinkedHashMap<>();
4381+
for(Refactoring r : refactorings) {
4382+
if(r instanceof PackageLevelRefactoring pack) {
4383+
UMLClass originalClass = pack.getOriginalClass();
4384+
UMLClass movedClass = pack.getMovedClass();
4385+
if(!originalClass.isTopLevel() && !movedClass.isTopLevel()) {
4386+
String outerOriginalClass = originalClass.getPackageName();
4387+
String outerMovedClass = movedClass.getPackageName();
4388+
String topOriginalClass = outerOriginalClass.contains(".") ? outerOriginalClass.substring(0, outerOriginalClass.lastIndexOf(".")) : outerOriginalClass;
4389+
String topMovedClass = outerMovedClass.contains(".") ? outerMovedClass.substring(0, outerMovedClass.lastIndexOf(".")) : outerMovedClass;
4390+
if(moveTargetMap.containsKey(outerOriginalClass)) {
4391+
moveTargetMap.get(outerOriginalClass).add(outerMovedClass);
4392+
}
4393+
else if(moveTargetMap.containsKey(topOriginalClass)) {
4394+
moveTargetMap.get(topOriginalClass).add(topMovedClass);
4395+
}
4396+
else {
4397+
Set<String> set = new LinkedHashSet<>();
4398+
set.add(outerMovedClass);
4399+
moveTargetMap.put(outerOriginalClass, set);
4400+
}
4401+
}
4402+
}
4403+
}
4404+
for(UMLClassMoveDiff moveDiff : classMoveDiffListToBePostProcessed) {
4405+
boolean proceed = false;
4406+
UMLClass originalClass = moveDiff.getOriginalClass();
4407+
UMLClass movedClass = moveDiff.getMovedClass();
4408+
if(!originalClass.isTopLevel() && !movedClass.isTopLevel()) {
4409+
String outerOriginalClass = originalClass.getPackageName();
4410+
if(moveTargetMap.containsKey(outerOriginalClass) && moveTargetMap.get(outerOriginalClass).size() > 1) {
4411+
proceed = true;
4412+
}
4413+
}
4414+
if(!classMoveDiffList.contains(moveDiff) && proceed) {
4415+
moveDiff.process();
4416+
refactorings.addAll(moveDiff.getRefactorings());
4417+
classMoveDiffList.add(moveDiff);
4418+
Refactoring refactoring = new MoveClassRefactoring(moveDiff.getOriginalClass(), moveDiff.getMovedClass());
4419+
refactorings.add(refactoring);
4420+
removedClasses.remove(moveDiff.getOriginalClass());
4421+
addedClasses.remove(moveDiff.getMovedClass());
4422+
//eliminate inner classes being reported as moved
4423+
List<MoveClassRefactoring> toBeRemoved = new ArrayList<MoveClassRefactoring>();
4424+
for(Refactoring r : refactorings) {
4425+
if(r instanceof MoveClassRefactoring) {
4426+
MoveClassRefactoring moveClass = (MoveClassRefactoring)r;
4427+
if(moveClass.getOriginalClassName().startsWith(moveDiff.getOriginalClassName() + ".") &&
4428+
moveClass.getMovedClassName().startsWith(moveDiff.getNextClassName() + ".")) {
4429+
toBeRemoved.add(moveClass);
4430+
}
4431+
}
4432+
}
4433+
this.refactorings.removeAll(toBeRemoved);
4434+
}
4435+
}
43684436
//match any remaining interface methods with changes in signature
43694437
for(UMLClassDiff classDiff : commonClassDiffList) {
43704438
if(classDiff.getOriginalClass().isInterface() && classDiff.getNextClass().isInterface()) {

src/test/java/org/refactoringminer/test/TestNewDatasetRefactorings.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,6 @@ public void testAllRefactorings() throws Exception {
5252
.or(Refactorings.SplitClass.getValue());
5353
TestBuilder test = new TestBuilder(detector, REPOS, types);
5454
RefactoringPopulator.feedTSERefactoringInstances(test);
55-
test.assertExpectationsWithGitHubAPI(3443, 46, 86);
55+
test.assertExpectationsWithGitHubAPI(3446, 44, 85);
5656
}
5757
}

src/test/resources/oracle/tse-dataset/javaparser.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -229,12 +229,12 @@
229229
{
230230
"type": "MOVE_CLASS",
231231
"description": "Move Class\tjapa.bdd.samples.JavaConcepts.JavaConcepts.X moved to japa.bdd.samples.JavaConceptsInnerClasses.JavaConceptsInnerClasses.X",
232-
"validation": false
232+
"validation": true
233233
},
234234
{
235235
"type": "MOVE_CLASS",
236236
"description": "Move Class\tjapa.bdd.samples.JavaConcepts.JavaConcepts.Y moved to japa.bdd.samples.JavaConceptsInnerClasses.JavaConceptsInnerClasses.Y",
237-
"validation": false
237+
"validation": true
238238
},
239239
{
240240
"type": "CHANGE_ATTRIBUTE_TYPE",

0 commit comments

Comments
 (0)