@@ -401,6 +401,44 @@ public UMLClassBaseDiff getUMLClassDiff(UMLType type) {
401401 return null ;
402402 }
403403
404+ private Set <UMLClass > getRemovedUMLClassWithAttribute (String attributeName ) {
405+ Set <UMLClass > classes = new LinkedHashSet <>();
406+ for (UMLClass umlClass : removedClasses ) {
407+ for (UMLAttribute attribute : umlClass .getAttributes ()) {
408+ if (attribute .getName ().equals (attributeName )) {
409+ classes .add (umlClass );
410+ break ;
411+ }
412+ }
413+ for (UMLAttribute attribute : umlClass .getEnumConstants ()) {
414+ if (attribute .getName ().equals (attributeName )) {
415+ classes .add (umlClass );
416+ break ;
417+ }
418+ }
419+ }
420+ return classes ;
421+ }
422+
423+ private Set <UMLClass > getAddedUMLClassWithAttribute (String attributeName ) {
424+ Set <UMLClass > classes = new LinkedHashSet <>();
425+ for (UMLClass umlClass : addedClasses ) {
426+ for (UMLAttribute attribute : umlClass .getAttributes ()) {
427+ if (attribute .getName ().equals (attributeName )) {
428+ classes .add (umlClass );
429+ break ;
430+ }
431+ }
432+ for (UMLAttribute attribute : umlClass .getEnumConstants ()) {
433+ if (attribute .getName ().equals (attributeName )) {
434+ classes .add (umlClass );
435+ break ;
436+ }
437+ }
438+ }
439+ return classes ;
440+ }
441+
404442 private UMLClassBaseDiff getUMLClassDiffWithAttribute (Replacement pattern ) {
405443 String before = new String (pattern .getBefore ());
406444 String after = new String (pattern .getAfter ());
@@ -3737,9 +3775,24 @@ public List<Refactoring> getRefactorings() throws RefactoringMinerTimedOutExcept
37373775 }
37383776 }
37393777 }
3778+ Map <Pair <UMLClass , UMLClass >, Set <CandidateAttributeRefactoring >> inferredClassRenames = new LinkedHashMap <>();
37403779 for (Replacement pattern : renameMap .keySet ()) {
37413780 UMLClassBaseDiff diff = getUMLClassDiffWithAttribute (pattern );
37423781 Set <CandidateAttributeRefactoring > set = renameMap .get (pattern );
3782+ if (diff == null ) {
3783+ Set <UMLClass > removedClassesWithAttribute = getRemovedUMLClassWithAttribute (pattern .getBefore ());
3784+ Set <UMLClass > addedClassesWithAttribute = getAddedUMLClassWithAttribute (pattern .getAfter ());
3785+ if (removedClassesWithAttribute .size () == 1 && addedClassesWithAttribute .size () == 1 ) {
3786+ Pair <UMLClass , UMLClass > pair = Pair .of (removedClassesWithAttribute .iterator ().next (), addedClassesWithAttribute .iterator ().next ());
3787+ if (inferredClassRenames .containsKey (pair )) {
3788+ inferredClassRenames .get (pair ).addAll (set );
3789+ }
3790+ else {
3791+ Set <CandidateAttributeRefactoring > newSet = new LinkedHashSet <>(set );
3792+ inferredClassRenames .put (pair , newSet );
3793+ }
3794+ }
3795+ }
37433796 String before = new String (pattern .getBefore ());
37443797 String after = new String (pattern .getAfter ());
37453798 if (before .contains ("." ) && after .contains ("." )) {
@@ -3952,6 +4005,121 @@ else if(candidate.getOriginalAttribute().getName().equals(a2.getName())) {
39524005 }
39534006 }
39544007 }
4008+ if (!partialModel ()) {
4009+ for (Pair <UMLClass , UMLClass > pair : inferredClassRenames .keySet ()) {
4010+ UMLClass parentClass = pair .getLeft ();
4011+ UMLClass childClass = pair .getRight ();
4012+ Set <CandidateAttributeRefactoring > set = inferredClassRenames .get (pair );
4013+ if (set .size () > 1 ) {
4014+ if (!parentClass .getNonQualifiedName ().equals (childClass .getNonQualifiedName ())) {
4015+ int totalOperations = parentClass .getOperations ().size () + childClass .getOperations ().size ();
4016+ int totalAttributes = parentClass .getAttributes ().size () + childClass .getAttributes ().size ();
4017+ MatchResult matchResult = new MatchResult (0 , set .size (), 0 , totalOperations , totalAttributes , true );
4018+ UMLClassRenameDiff renameDiff = new UMLClassRenameDiff (parentClass , childClass , this , matchResult );
4019+ renameDiff .process ();
4020+ refactorings .addAll (renameDiff .getRefactorings ());
4021+ classRenameDiffList .add (renameDiff );
4022+ Refactoring refactoring = null ;
4023+ if (renameDiff .samePackage ())
4024+ refactoring = new RenameClassRefactoring (renameDiff .getOriginalClass (), renameDiff .getRenamedClass ());
4025+ else
4026+ refactoring = new MoveAndRenameClassRefactoring (renameDiff .getOriginalClass (), renameDiff .getRenamedClass ());
4027+ refactorings .add (refactoring );
4028+ removedClasses .remove (parentClass );
4029+ addedClasses .remove (childClass );
4030+ for (CandidateAttributeRefactoring candidate : set ) {
4031+ UMLAttribute a1 = parentClass .attributeWithName (candidate .getOriginalVariableName ());
4032+ UMLAttribute a2 = childClass .attributeWithName (candidate .getRenamedVariableName ());
4033+ if (a1 instanceof UMLEnumConstant && a2 instanceof UMLEnumConstant ) {
4034+ UMLEnumConstantDiff enumConstantDiff = new UMLEnumConstantDiff ((UMLEnumConstant )a1 , (UMLEnumConstant )a2 , renameDiff , this );
4035+ if (!renameDiff .getEnumConstantDiffList ().contains (enumConstantDiff )) {
4036+ renameDiff .getEnumConstantDiffList ().add (enumConstantDiff );
4037+ }
4038+ Set <Refactoring > enumConstantDiffRefactorings = enumConstantDiff .getRefactorings (set );
4039+ if (!refactorings .containsAll (enumConstantDiffRefactorings )) {
4040+ refactorings .addAll (enumConstantDiffRefactorings );
4041+ }
4042+ }
4043+ else {
4044+ UMLAttributeDiff attributeDiff = new UMLAttributeDiff (a1 , a2 , renameDiff , this );
4045+ if (!renameDiff .getAttributeDiffList ().contains (attributeDiff )) {
4046+ renameDiff .getAttributeDiffList ().add (attributeDiff );
4047+ }
4048+ Set <Refactoring > attributeDiffRefactorings = attributeDiff .getRefactorings (set );
4049+ if (!refactorings .containsAll (attributeDiffRefactorings )) {
4050+ refactorings .addAll (attributeDiffRefactorings );
4051+ }
4052+ }
4053+ }
4054+ //eliminate inner classes being reported as moved
4055+ List <MoveClassRefactoring > toBeRemoved = new ArrayList <MoveClassRefactoring >();
4056+ for (Refactoring r : refactorings ) {
4057+ if (r instanceof MoveClassRefactoring ) {
4058+ MoveClassRefactoring moveClass = (MoveClassRefactoring )r ;
4059+ if (moveClass .getOriginalClassName ().startsWith (renameDiff .getOriginalClassName () + "." ) &&
4060+ moveClass .getMovedClassName ().startsWith (renameDiff .getNextClassName () + "." )) {
4061+ toBeRemoved .add (moveClass );
4062+ }
4063+ }
4064+ }
4065+ this .refactorings .removeAll (toBeRemoved );
4066+ }
4067+ else {
4068+ int totalOperations = parentClass .getOperations ().size () + childClass .getOperations ().size ();
4069+ int totalAttributes = parentClass .getAttributes ().size () + childClass .getAttributes ().size ();
4070+ MatchResult matchResult = new MatchResult (0 , set .size (), 0 , totalOperations , totalAttributes , true );
4071+ UMLClassMoveDiff moveDiff = new UMLClassMoveDiff (parentClass , childClass , this , matchResult );
4072+ moveDiff .process ();
4073+ refactorings .addAll (moveDiff .getRefactorings ());
4074+ classMoveDiffList .add (moveDiff );
4075+ UMLClassBaseDiff parentClassDiff = getUMLClassDiff (parentClass .getPackageName ());
4076+ boolean parentClassIsMoved = parentClassDiff instanceof UMLClassMoveDiff m && m .getNextClassName ().equals (childClass .getPackageName ());
4077+ if (!parentClassIsMoved ) {
4078+ Refactoring refactoring = new MoveClassRefactoring (moveDiff .getOriginalClass (), moveDiff .getMovedClass ());
4079+ refactorings .add (refactoring );
4080+ }
4081+ removedClasses .remove (parentClass );
4082+ addedClasses .remove (childClass );
4083+ for (CandidateAttributeRefactoring candidate : set ) {
4084+ UMLAttribute a1 = parentClass .attributeWithName (candidate .getOriginalVariableName ());
4085+ UMLAttribute a2 = childClass .attributeWithName (candidate .getRenamedVariableName ());
4086+ if (a1 instanceof UMLEnumConstant && a2 instanceof UMLEnumConstant ) {
4087+ UMLEnumConstantDiff enumConstantDiff = new UMLEnumConstantDiff ((UMLEnumConstant )a1 , (UMLEnumConstant )a2 , moveDiff , this );
4088+ if (!moveDiff .getEnumConstantDiffList ().contains (enumConstantDiff )) {
4089+ moveDiff .getEnumConstantDiffList ().add (enumConstantDiff );
4090+ }
4091+ Set <Refactoring > enumConstantDiffRefactorings = enumConstantDiff .getRefactorings (set );
4092+ if (!refactorings .containsAll (enumConstantDiffRefactorings )) {
4093+ refactorings .addAll (enumConstantDiffRefactorings );
4094+ }
4095+ }
4096+ else {
4097+ UMLAttributeDiff attributeDiff = new UMLAttributeDiff (a1 , a2 , moveDiff , this );
4098+ if (!moveDiff .getAttributeDiffList ().contains (attributeDiff )) {
4099+ moveDiff .getAttributeDiffList ().add (attributeDiff );
4100+ }
4101+ Set <Refactoring > attributeDiffRefactorings = attributeDiff .getRefactorings (set );
4102+ if (!refactorings .containsAll (attributeDiffRefactorings )) {
4103+ refactorings .addAll (attributeDiffRefactorings );
4104+ }
4105+ }
4106+ }
4107+ //eliminate inner classes being reported as moved
4108+ List <MoveClassRefactoring > toBeRemoved = new ArrayList <MoveClassRefactoring >();
4109+ for (Refactoring r : refactorings ) {
4110+ if (r instanceof MoveClassRefactoring ) {
4111+ MoveClassRefactoring moveClass = (MoveClassRefactoring )r ;
4112+ if (moveClass .getOriginalClassName ().startsWith (moveDiff .getOriginalClassName () + "." ) &&
4113+ moveClass .getMovedClassName ().startsWith (moveDiff .getNextClassName () + "." )) {
4114+ toBeRemoved .add (moveClass );
4115+ }
4116+ }
4117+ }
4118+ this .refactorings .removeAll (toBeRemoved );
4119+ }
4120+ }
4121+ }
4122+ }
39554123 refactorings .addAll (identifyExtractSuperclassRefactorings ());
39564124 refactorings .addAll (identifyCollapseHierarchyRefactorings ());
39574125 refactorings .addAll (identifyExtractClassRefactorings (commonClassDiffList ));
0 commit comments