diff --git a/src/main/java/org/codetracker/AttributeTrackerChangeHistory.java b/src/main/java/org/codetracker/AttributeTrackerChangeHistory.java new file mode 100644 index 00000000000..86d93e8b7ed --- /dev/null +++ b/src/main/java/org/codetracker/AttributeTrackerChangeHistory.java @@ -0,0 +1,355 @@ +package org.codetracker; + +import java.util.ArrayDeque; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import org.codetracker.api.Version; +import org.codetracker.change.Change; +import org.codetracker.change.ChangeFactory; +import org.codetracker.element.Attribute; +import org.refactoringminer.api.Refactoring; +import org.refactoringminer.api.RefactoringType; + +import gr.uom.java.xmi.UMLAnonymousClass; +import gr.uom.java.xmi.UMLAttribute; +import gr.uom.java.xmi.UMLClass; +import gr.uom.java.xmi.UMLModel; +import gr.uom.java.xmi.diff.AddAttributeAnnotationRefactoring; +import gr.uom.java.xmi.diff.AddAttributeModifierRefactoring; +import gr.uom.java.xmi.diff.ChangeAttributeAccessModifierRefactoring; +import gr.uom.java.xmi.diff.ChangeAttributeTypeRefactoring; +import gr.uom.java.xmi.diff.ExtractAttributeRefactoring; +import gr.uom.java.xmi.diff.ModifyAttributeAnnotationRefactoring; +import gr.uom.java.xmi.diff.MoveAndRenameAttributeRefactoring; +import gr.uom.java.xmi.diff.MoveAndRenameClassRefactoring; +import gr.uom.java.xmi.diff.MoveAttributeRefactoring; +import gr.uom.java.xmi.diff.MoveClassRefactoring; +import gr.uom.java.xmi.diff.MoveSourceFolderRefactoring; +import gr.uom.java.xmi.diff.MovedClassToAnotherSourceFolder; +import gr.uom.java.xmi.diff.PullUpAttributeRefactoring; +import gr.uom.java.xmi.diff.PushDownAttributeRefactoring; +import gr.uom.java.xmi.diff.RemoveAttributeAnnotationRefactoring; +import gr.uom.java.xmi.diff.RemoveAttributeModifierRefactoring; +import gr.uom.java.xmi.diff.RenameAttributeRefactoring; +import gr.uom.java.xmi.diff.RenameClassRefactoring; +import gr.uom.java.xmi.diff.UMLAttributeDiff; +import gr.uom.java.xmi.diff.UMLClassBaseDiff; +import gr.uom.java.xmi.diff.UMLClassMoveDiff; +import gr.uom.java.xmi.diff.UMLClassRenameDiff; +import gr.uom.java.xmi.diff.UMLModelDiff; + +public class AttributeTrackerChangeHistory { + private final ChangeHistory attributeChangeHistory = new ChangeHistory<>(); + private final String attributeName; + private final int attributeDeclarationLineNumber; + + public AttributeTrackerChangeHistory(String attributeName, int attributeDeclarationLineNumber) { + this.attributeName = attributeName; + this.attributeDeclarationLineNumber = attributeDeclarationLineNumber; + } + + public ChangeHistory get() { + return attributeChangeHistory; + } + + public String getAttributeName() { + return attributeName; + } + + public int getAttributeDeclarationLineNumber() { + return attributeDeclarationLineNumber; + } + + public static Attribute getAttribute(UMLModel umlModel, Version version, Predicate predicate) { + if (umlModel != null) + for (UMLClass umlClass : umlModel.getClassList()) { + Attribute attribute = getAttribute(version, predicate, umlClass.getAttributes()); + if (attribute != null) return attribute; + attribute = getAttribute(version, predicate, umlClass.getEnumConstants()); + if (attribute != null) return attribute; + for (UMLAnonymousClass anonymousClass : umlClass.getAnonymousClassList()) { + attribute = getAttribute(version, predicate, anonymousClass.getAttributes()); + if (attribute != null) return attribute; + attribute = getAttribute(version, predicate, anonymousClass.getEnumConstants()); + if (attribute != null) return attribute; + } + } + return null; + } + + private static Attribute getAttribute(Version version, Predicate predicate, List attributes) { + for (UMLAttribute umlAttribute : attributes) { + Attribute attribute = Attribute.of(umlAttribute, version); + if (predicate.test(attribute)) + return attribute; + } + return null; + } + + public boolean isStartAttribute(Attribute attribute) { + return attribute.getUmlAttribute().getName().equals(attributeName) && + attribute.getUmlAttribute().getLocationInfo().getStartLine() <= attributeDeclarationLineNumber && + attribute.getUmlAttribute().getLocationInfo().getEndLine() >= attributeDeclarationLineNumber; + } + + public Set analyseAttributeRefactorings(Collection refactorings, Version currentVersion, Version parentVersion, Predicate equalOperator) { + Set leftAttributeSet = new HashSet<>(); + for (Refactoring refactoring : refactorings) { + UMLAttribute attributeBefore = null; + UMLAttribute attributeAfter = null; + Change.Type changeType = null; + + switch (refactoring.getRefactoringType()) { + case PULL_UP_ATTRIBUTE: { + PullUpAttributeRefactoring pullUpAttributeRefactoring = (PullUpAttributeRefactoring) refactoring; + attributeBefore = pullUpAttributeRefactoring.getOriginalAttribute(); + attributeAfter = pullUpAttributeRefactoring.getMovedAttribute(); + changeType = Change.Type.MOVED; + break; + } + case PUSH_DOWN_ATTRIBUTE: { + PushDownAttributeRefactoring pushDownAttributeRefactoring = (PushDownAttributeRefactoring) refactoring; + attributeBefore = pushDownAttributeRefactoring.getOriginalAttribute(); + attributeAfter = pushDownAttributeRefactoring.getMovedAttribute(); + changeType = Change.Type.MOVED; + break; + } + case MOVE_ATTRIBUTE: { + MoveAttributeRefactoring moveAttributeRefactoring = (MoveAttributeRefactoring) refactoring; + attributeBefore = moveAttributeRefactoring.getOriginalAttribute(); + attributeAfter = moveAttributeRefactoring.getMovedAttribute(); + changeType = Change.Type.MOVED; + break; + } + case MOVE_RENAME_ATTRIBUTE: { + MoveAndRenameAttributeRefactoring moveAndRenameAttributeRefactoring = (MoveAndRenameAttributeRefactoring) refactoring; + attributeBefore = moveAndRenameAttributeRefactoring.getOriginalAttribute(); + attributeAfter = moveAndRenameAttributeRefactoring.getMovedAttribute(); + changeType = Change.Type.MOVED; + addAttributeChange(currentVersion, parentVersion, equalOperator, leftAttributeSet, refactoring, attributeBefore, attributeAfter, Change.Type.RENAME); + break; + } + case RENAME_ATTRIBUTE: { + RenameAttributeRefactoring renameAttributeRefactoring = (RenameAttributeRefactoring) refactoring; + attributeBefore = renameAttributeRefactoring.getOriginalAttribute(); + attributeAfter = renameAttributeRefactoring.getRenamedAttribute(); + changeType = Change.Type.RENAME; + break; + } + case ADD_ATTRIBUTE_ANNOTATION: { + AddAttributeAnnotationRefactoring addAttributeAnnotationRefactoring = (AddAttributeAnnotationRefactoring) refactoring; + attributeBefore = addAttributeAnnotationRefactoring.getAttributeBefore(); + attributeAfter = addAttributeAnnotationRefactoring.getAttributeAfter(); + changeType = Change.Type.ANNOTATION_CHANGE; + break; + } + case MODIFY_ATTRIBUTE_ANNOTATION: { + ModifyAttributeAnnotationRefactoring modifyAttributeAnnotationRefactoring = (ModifyAttributeAnnotationRefactoring) refactoring; + attributeBefore = modifyAttributeAnnotationRefactoring.getAttributeBefore(); + attributeAfter = modifyAttributeAnnotationRefactoring.getAttributeAfter(); + changeType = Change.Type.ANNOTATION_CHANGE; + break; + } + case REMOVE_ATTRIBUTE_ANNOTATION: { + RemoveAttributeAnnotationRefactoring removeAttributeAnnotationRefactoring = (RemoveAttributeAnnotationRefactoring) refactoring; + attributeBefore = removeAttributeAnnotationRefactoring.getAttributeBefore(); + attributeAfter = removeAttributeAnnotationRefactoring.getAttributeAfter(); + changeType = Change.Type.ANNOTATION_CHANGE; + break; + } + case CHANGE_ATTRIBUTE_TYPE: { + ChangeAttributeTypeRefactoring changeAttributeTypeRefactoring = (ChangeAttributeTypeRefactoring) refactoring; + attributeBefore = changeAttributeTypeRefactoring.getOriginalAttribute(); + attributeAfter = changeAttributeTypeRefactoring.getChangedTypeAttribute(); + changeType = Change.Type.TYPE_CHANGE; + break; + } + case ADD_ATTRIBUTE_MODIFIER: { + AddAttributeModifierRefactoring addAttributeModifierRefactoring = (AddAttributeModifierRefactoring) refactoring; + attributeBefore = addAttributeModifierRefactoring.getAttributeBefore(); + attributeAfter = addAttributeModifierRefactoring.getAttributeAfter(); + changeType = Change.Type.MODIFIER_CHANGE; + break; + } + case REMOVE_ATTRIBUTE_MODIFIER: { + RemoveAttributeModifierRefactoring removeAttributeModifierRefactoring = (RemoveAttributeModifierRefactoring) refactoring; + attributeBefore = removeAttributeModifierRefactoring.getAttributeBefore(); + attributeAfter = removeAttributeModifierRefactoring.getAttributeAfter(); + changeType = Change.Type.MODIFIER_CHANGE; + break; + } + case CHANGE_ATTRIBUTE_ACCESS_MODIFIER: { + ChangeAttributeAccessModifierRefactoring changeAttributeAccessModifierRefactoring = (ChangeAttributeAccessModifierRefactoring) refactoring; + attributeBefore = changeAttributeAccessModifierRefactoring.getAttributeBefore(); + attributeAfter = changeAttributeAccessModifierRefactoring.getAttributeAfter(); + changeType = Change.Type.ACCESS_MODIFIER_CHANGE; + break; + } + case EXTRACT_ATTRIBUTE: { + ExtractAttributeRefactoring extractAttributeRefactoring = (ExtractAttributeRefactoring) refactoring; + Attribute rightAttribute = Attribute.of(extractAttributeRefactoring.getVariableDeclaration(), currentVersion); + if (equalOperator.test(rightAttribute)) { + Attribute leftAttribute = Attribute.of(extractAttributeRefactoring.getVariableDeclaration(), parentVersion); + attributeChangeHistory.handleAdd(leftAttribute, rightAttribute , refactoring.toString()); + attributeChangeHistory.connectRelatedNodes(); + leftAttributeSet.add(leftAttribute); + return leftAttributeSet; + } + break; + } + + } + + addAttributeChange(currentVersion, parentVersion, equalOperator, leftAttributeSet, refactoring, attributeBefore, attributeAfter, changeType); + } + attributeChangeHistory.connectRelatedNodes(); + return leftAttributeSet; + } + + private boolean addAttributeChange(Version currentVersion, Version parentVersion, Predicate equalOperator, Set leftAttributeSet, Refactoring refactoring, UMLAttribute umlAttributeBefore, UMLAttribute umlAttributeAfter, Change.Type changeType) { + if (umlAttributeAfter != null) { + Attribute attributeAfter = Attribute.of(umlAttributeAfter, currentVersion); + if (equalOperator.test(attributeAfter)) { + Attribute attributeBefore = Attribute.of(umlAttributeBefore, parentVersion); + attributeChangeHistory.addChange(attributeBefore, attributeAfter, ChangeFactory.forAttribute(changeType).refactoring(refactoring)); + leftAttributeSet.add(attributeBefore); + return true; + } + } + return false; + } + + public boolean isAttributeAdded(UMLModelDiff modelDiff, ArrayDeque attributes, String className, Version currentVersion, Version parentVersion, Predicate equalOperator, List allClassesDiff) { + List addedAttributes = allClassesDiff + .stream() + .map(UMLClassBaseDiff::getAddedAttributes) + .flatMap(List::stream) + .collect(Collectors.toList()); + for (UMLAttribute umlAttribute : addedAttributes) { + if (handleAddAttribute(attributes, currentVersion, parentVersion, equalOperator, umlAttribute, "new attribute")) + return true; + } + + UMLClass addedClass = modelDiff.getAddedClass(className); + if (addedClass != null) { + for (UMLAttribute umlAttribute : addedClass.getAttributes()) { + if (handleAddAttribute(attributes, currentVersion, parentVersion, equalOperator, umlAttribute, "added with new class")) + return true; + } + } + + for (UMLClassRenameDiff classRenameDiffList : modelDiff.getClassRenameDiffList()) { + for (UMLAnonymousClass addedAnonymousClasses : classRenameDiffList.getAddedAnonymousClasses()) { + for (UMLAttribute umlAttribute : addedAnonymousClasses.getAttributes()) { + if (handleAddAttribute(attributes, currentVersion, parentVersion, equalOperator, umlAttribute, "added with new anonymous class")) + return true; + } + } + } + return false; + } + + private boolean handleAddAttribute(ArrayDeque attributes, Version currentVersion, Version parentVersion, Predicate equalOperator, UMLAttribute umlAttribute, String comment) { + Attribute rightAttribute = Attribute.of(umlAttribute, currentVersion); + if (equalOperator.test(rightAttribute)) { + Attribute leftAttribute = Attribute.of(umlAttribute, parentVersion); + attributeChangeHistory.handleAdd(leftAttribute, rightAttribute, comment); + attributeChangeHistory.connectRelatedNodes(); + attributes.addFirst(leftAttribute); + return true; + } + return false; + } + + public Set isAttributeContainerChanged(UMLModelDiff umlModelDiffAll, Collection refactorings, Version currentVersion, Version parentVersion, Predicate equalOperator, List classMoveDiffList) { + Set leftAttributeSet = new HashSet<>(); + Change.Type changeType = Change.Type.CONTAINER_CHANGE; + + for (UMLClassMoveDiff umlClassMoveDiff : classMoveDiffList) { + for (UMLAttributeDiff attributeDiff : umlClassMoveDiff.getAttributeDiffList()) { + if (addAttributeChange(currentVersion, parentVersion, equalOperator, leftAttributeSet, new MoveClassRefactoring(umlClassMoveDiff.getOriginalClass(), umlClassMoveDiff.getMovedClass()), attributeDiff.getRemovedAttribute(), attributeDiff.getAddedAttribute(), changeType)) { + attributeChangeHistory.connectRelatedNodes(); + return leftAttributeSet; + } + } + } + + for (UMLClassRenameDiff umlClassRenameDiff : umlModelDiffAll.getClassRenameDiffList()) { + for (UMLAttributeDiff attributeDiff : umlClassRenameDiff.getAttributeDiffList()) { + if (addAttributeChange(currentVersion, parentVersion, equalOperator, leftAttributeSet, new RenameClassRefactoring(umlClassRenameDiff.getOriginalClass(), umlClassRenameDiff.getRenamedClass()), attributeDiff.getRemovedAttribute(), attributeDiff.getAddedAttribute(), changeType)) { + attributeChangeHistory.connectRelatedNodes(); + return leftAttributeSet; + } + } + } + for (UMLClassMoveDiff umlClassMoveDiff : umlModelDiffAll.getInnerClassMoveDiffList()) { + for (UMLAttributeDiff attributeDiff : umlClassMoveDiff.getAttributeDiffList()) { + if (addAttributeChange(currentVersion, parentVersion, equalOperator, leftAttributeSet, new MoveClassRefactoring(umlClassMoveDiff.getOriginalClass(), umlClassMoveDiff.getMovedClass()), attributeDiff.getRemovedAttribute(), attributeDiff.getAddedAttribute(), changeType)) { + attributeChangeHistory.connectRelatedNodes(); + return leftAttributeSet; + } + } + } + + for (Refactoring refactoring : refactorings) { + if (refactoring.getRefactoringType() == RefactoringType.MOVE_SOURCE_FOLDER) { + MoveSourceFolderRefactoring moveSourceFolderRefactoring = (MoveSourceFolderRefactoring) refactoring; + for (MovedClassToAnotherSourceFolder movedClassToAnotherSourceFolder : moveSourceFolderRefactoring.getMovedClassesToAnotherSourceFolder()) { + UMLClass originalClass = movedClassToAnotherSourceFolder.getOriginalClass(); + UMLClass movedClass = movedClassToAnotherSourceFolder.getMovedClass(); + if (checkAttributeContainerChangeInMovedClasses(originalClass, movedClass, currentVersion, parentVersion, equalOperator, refactoring, leftAttributeSet)) { + return leftAttributeSet; + } + } + } else if (refactoring.getRefactoringType() == RefactoringType.MOVE_CLASS) { + MoveClassRefactoring moveClassRefactoring = (MoveClassRefactoring) refactoring; + UMLClass originalClass = moveClassRefactoring.getOriginalClass(); + UMLClass movedClass = moveClassRefactoring.getMovedClass(); + if (checkAttributeContainerChangeInMovedClasses(originalClass, movedClass, currentVersion, parentVersion, equalOperator, refactoring, leftAttributeSet)) { + return leftAttributeSet; + } + } else if (refactoring.getRefactoringType() == RefactoringType.RENAME_CLASS) { + RenameClassRefactoring renameClassRefactoring = (RenameClassRefactoring) refactoring; + UMLClass originalClass = renameClassRefactoring.getOriginalClass(); + UMLClass renamedClass = renameClassRefactoring.getRenamedClass(); + if (checkAttributeContainerChangeInMovedClasses(originalClass, renamedClass, currentVersion, parentVersion, equalOperator, refactoring, leftAttributeSet)) { + return leftAttributeSet; + } + } else if (refactoring.getRefactoringType() == RefactoringType.MOVE_RENAME_CLASS) { + MoveAndRenameClassRefactoring moveAndRenameClassRefactoring = (MoveAndRenameClassRefactoring) refactoring; + UMLClass originalClass = moveAndRenameClassRefactoring.getOriginalClass(); + UMLClass renamedClass = moveAndRenameClassRefactoring.getRenamedClass(); + if (checkAttributeContainerChangeInMovedClasses(originalClass, renamedClass, currentVersion, parentVersion, equalOperator, refactoring, leftAttributeSet)) { + return leftAttributeSet; + } + } + } + return Collections.emptySet(); + } + + private boolean checkAttributeContainerChangeInMovedClasses(UMLClass originalClass, UMLClass movedClass, Version currentVersion, Version parentVersion, Predicate equalOperator, Refactoring refactoring, Set leftAttributeSet) { + for (UMLAttribute umlAttributeAfter : movedClass.getAttributes()) { + Attribute attributeAfter = Attribute.of(umlAttributeAfter, currentVersion); + if (equalOperator.test(attributeAfter)) { + for (UMLAttribute umlAttributeBefore : originalClass.getAttributes()) { + if (umlAttributeAfter.equals(umlAttributeBefore)) { + Attribute attributeBefore = Attribute.of(umlAttributeBefore, parentVersion); + attributeChangeHistory.addChange(attributeBefore, attributeAfter, ChangeFactory.forAttribute(Change.Type.CONTAINER_CHANGE).refactoring(refactoring)); + attributeChangeHistory.connectRelatedNodes(); + leftAttributeSet.add(attributeBefore); + + return true; + } + } + } + + } + return false; + } +} diff --git a/src/main/java/org/codetracker/AttributeTrackerImpl.java b/src/main/java/org/codetracker/AttributeTrackerImpl.java index f478f7a4fb6..7a0aceb5a4d 100644 --- a/src/main/java/org/codetracker/AttributeTrackerImpl.java +++ b/src/main/java/org/codetracker/AttributeTrackerImpl.java @@ -1,67 +1,26 @@ package org.codetracker; -import gr.uom.java.xmi.UMLAnonymousClass; -import gr.uom.java.xmi.UMLAttribute; -import gr.uom.java.xmi.UMLClass; import gr.uom.java.xmi.UMLModel; import gr.uom.java.xmi.diff.*; import org.apache.commons.lang3.tuple.Pair; import org.codetracker.api.AttributeTracker; -import org.codetracker.change.Change; import org.codetracker.api.History; import org.codetracker.api.Version; -import org.codetracker.change.ChangeFactory; import org.codetracker.element.Attribute; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.lib.Repository; import org.refactoringminer.api.Refactoring; import org.refactoringminer.api.RefactoringType; +import static org.codetracker.AttributeTrackerChangeHistory.getAttribute; import java.util.*; -import java.util.function.Predicate; -import java.util.stream.Collectors; public class AttributeTrackerImpl extends BaseTracker implements AttributeTracker { - private final ChangeHistory attributeChangeHistory = new ChangeHistory<>(); - private final String attributeName; - private final int attributeDeclarationLineNumber; + private final AttributeTrackerChangeHistory changeHistory; public AttributeTrackerImpl(Repository repository, String startCommitId, String filePath, String attributeName, int attributeDeclarationLineNumber) { super(repository, startCommitId, filePath); - this.attributeName = attributeName; - this.attributeDeclarationLineNumber = attributeDeclarationLineNumber; - } - - protected static Attribute getAttribute(UMLModel umlModel, Version version, Predicate predicate) { - if (umlModel != null) - for (UMLClass umlClass : umlModel.getClassList()) { - Attribute attribute = getAttribute(version, predicate, umlClass.getAttributes()); - if (attribute != null) return attribute; - attribute = getAttribute(version, predicate, umlClass.getEnumConstants()); - if (attribute != null) return attribute; - for (UMLAnonymousClass anonymousClass : umlClass.getAnonymousClassList()) { - attribute = getAttribute(version, predicate, anonymousClass.getAttributes()); - if (attribute != null) return attribute; - attribute = getAttribute(version, predicate, anonymousClass.getEnumConstants()); - if (attribute != null) return attribute; - } - } - return null; - } - - private static Attribute getAttribute(Version version, Predicate predicate, List attributes) { - for (UMLAttribute umlAttribute : attributes) { - Attribute attribute = Attribute.of(umlAttribute, version); - if (predicate.test(attribute)) - return attribute; - } - return null; - } - - private boolean isStartAttribute(Attribute attribute) { - return attribute.getUmlAttribute().getName().equals(attributeName) && - attribute.getUmlAttribute().getLocationInfo().getStartLine() <= attributeDeclarationLineNumber && - attribute.getUmlAttribute().getLocationInfo().getEndLine() >= attributeDeclarationLineNumber; + this.changeHistory = new AttributeTrackerChangeHistory(attributeName, attributeDeclarationLineNumber); } @Override @@ -70,12 +29,12 @@ public History track() throws Exception { try (Git git = new Git(repository)) { Version startVersion = gitRepository.getVersion(startCommitId); UMLModel umlModel = getUMLModel(startCommitId, Collections.singleton(filePath)); - Attribute start = getAttribute(umlModel, startVersion, this::isStartAttribute); + Attribute start = getAttribute(umlModel, startVersion, changeHistory::isStartAttribute); if (start == null) { return null; } start.setStart(true); - attributeChangeHistory.addNode(start); + changeHistory.get().addNode(start); ArrayDeque attributes = new ArrayDeque<>(); attributes.addFirst(start); @@ -115,8 +74,8 @@ public History track() throws Exception { historyReport.analysedCommitsPlusPlus(); if ("0".equals(parentCommitId)) { Attribute leftAttribute = Attribute.of(rightAttribute.getUmlAttribute(), parentVersion); - attributeChangeHistory.handleAdd(leftAttribute, rightAttribute, "Initial commit!"); - attributeChangeHistory.connectRelatedNodes(); + changeHistory.get().handleAdd(leftAttribute, rightAttribute, "Initial commit!"); + changeHistory.get().connectRelatedNodes(); attributes.add(leftAttribute); break; } @@ -134,7 +93,7 @@ public History track() throws Exception { UMLModelDiff umlModelDiffLocal = leftModel.diff(rightModel); { List refactorings = umlModelDiffLocal.getRefactorings(); - Set attributeContainerChanged = isAttributeContainerChanged(umlModelDiffLocal, refactorings, currentVersion, parentVersion, rightAttribute::equalIdentifierIgnoringVersion); + Set attributeContainerChanged = changeHistory.isAttributeContainerChanged(umlModelDiffLocal, refactorings, currentVersion, parentVersion, rightAttribute::equalIdentifierIgnoringVersion, getClassMoveDiffList(umlModelDiffLocal)); boolean containerChanged = !attributeContainerChanged.isEmpty(); String renamedAttributeClassType = null; @@ -157,7 +116,7 @@ public History track() throws Exception { } Set attributeRefactored = null; if (extractedClassFilePath == null) - attributeRefactored = analyseAttributeRefactorings(refactorings, currentVersion, parentVersion, rightAttribute::equalIdentifierIgnoringVersion); + attributeRefactored = changeHistory.analyseAttributeRefactorings(refactorings, currentVersion, parentVersion, rightAttribute::equalIdentifierIgnoringVersion); else attributeRefactored = Collections.emptySet(); boolean refactored = !attributeRefactored.isEmpty(); @@ -178,10 +137,10 @@ public History track() throws Exception { Pair umlModelPairPartial = getUMLModelPair(commitModel, currentAttribute.getFilePath(), s -> true, true); UMLModelDiff umlModelDiffPartial = umlModelPairPartial.getLeft().diff(umlModelPairPartial.getRight()); List refactoringsPartial = umlModelDiffPartial.getRefactorings(); - Set attributeContainerChanged = isAttributeContainerChanged(umlModelDiffPartial, refactoringsPartial, currentVersion, parentVersion, rightAttribute::equalIdentifierIgnoringVersion); + Set attributeContainerChanged = changeHistory.isAttributeContainerChanged(umlModelDiffPartial, refactoringsPartial, currentVersion, parentVersion, rightAttribute::equalIdentifierIgnoringVersion, getClassMoveDiffList(umlModelDiffPartial)); boolean containerChanged = !attributeContainerChanged.isEmpty(); - Set attributeRefactored = analyseAttributeRefactorings(refactoringsPartial, currentVersion, parentVersion, rightAttribute::equalIdentifierIgnoringVersion); + Set attributeRefactored = changeHistory.analyseAttributeRefactorings(refactoringsPartial, currentVersion, parentVersion, rightAttribute::equalIdentifierIgnoringVersion); boolean refactored = !attributeRefactored.isEmpty(); if (containerChanged || refactored) { @@ -220,12 +179,12 @@ public History track() throws Exception { refactorings = umlModelDiffAll.getRefactorings(); } - Set attributeContainerChanged = isAttributeContainerChanged(umlModelDiffAll, refactorings, currentVersion, parentVersion, rightAttribute::equalIdentifierIgnoringVersion); + Set attributeContainerChanged = changeHistory.isAttributeContainerChanged(umlModelDiffAll, refactorings, currentVersion, parentVersion, rightAttribute::equalIdentifierIgnoringVersion, getClassMoveDiffList(umlModelDiffAll)); boolean containerChanged = !attributeContainerChanged.isEmpty(); Set attributeRefactored; if (moveAttributeRefactorings <= 1) { - attributeRefactored = analyseAttributeRefactorings(refactorings, currentVersion, parentVersion, rightAttribute::equalIdentifierIgnoringVersion); + attributeRefactored = changeHistory.analyseAttributeRefactorings(refactorings, currentVersion, parentVersion, rightAttribute::equalIdentifierIgnoringVersion); } else { attributeRefactored = Collections.emptySet(); @@ -241,7 +200,7 @@ public History track() throws Exception { break; } - if (isAttributeAdded(umlModelDiffAll, attributes, rightAttribute.getUmlAttribute().getClassName(), currentVersion, parentVersion, rightAttribute::equalIdentifierIgnoringVersion)) { + if (changeHistory.isAttributeAdded(umlModelDiffAll, attributes, rightAttribute.getUmlAttribute().getClassName(), currentVersion, parentVersion, rightAttribute::equalIdentifierIgnoringVersion, getAllClassesDiff(umlModelDiffAll))) { historyReport.step5PlusPlus(); break; } @@ -249,264 +208,7 @@ public History track() throws Exception { } } } - return new HistoryImpl<>(attributeChangeHistory.getCompleteGraph(), historyReport); - } - } - - public Set analyseAttributeRefactorings(Collection refactorings, Version currentVersion, Version parentVersion, Predicate equalOperator) { - Set leftAttributeSet = new HashSet<>(); - for (Refactoring refactoring : refactorings) { - UMLAttribute attributeBefore = null; - UMLAttribute attributeAfter = null; - Change.Type changeType = null; - - switch (refactoring.getRefactoringType()) { - case PULL_UP_ATTRIBUTE: { - PullUpAttributeRefactoring pullUpAttributeRefactoring = (PullUpAttributeRefactoring) refactoring; - attributeBefore = pullUpAttributeRefactoring.getOriginalAttribute(); - attributeAfter = pullUpAttributeRefactoring.getMovedAttribute(); - changeType = Change.Type.MOVED; - break; - } - case PUSH_DOWN_ATTRIBUTE: { - PushDownAttributeRefactoring pushDownAttributeRefactoring = (PushDownAttributeRefactoring) refactoring; - attributeBefore = pushDownAttributeRefactoring.getOriginalAttribute(); - attributeAfter = pushDownAttributeRefactoring.getMovedAttribute(); - changeType = Change.Type.MOVED; - break; - } - case MOVE_ATTRIBUTE: { - MoveAttributeRefactoring moveAttributeRefactoring = (MoveAttributeRefactoring) refactoring; - attributeBefore = moveAttributeRefactoring.getOriginalAttribute(); - attributeAfter = moveAttributeRefactoring.getMovedAttribute(); - changeType = Change.Type.MOVED; - break; - } - case MOVE_RENAME_ATTRIBUTE: { - MoveAndRenameAttributeRefactoring moveAndRenameAttributeRefactoring = (MoveAndRenameAttributeRefactoring) refactoring; - attributeBefore = moveAndRenameAttributeRefactoring.getOriginalAttribute(); - attributeAfter = moveAndRenameAttributeRefactoring.getMovedAttribute(); - changeType = Change.Type.MOVED; - addAttributeChange(currentVersion, parentVersion, equalOperator, leftAttributeSet, refactoring, attributeBefore, attributeAfter, Change.Type.RENAME); - break; - } - case RENAME_ATTRIBUTE: { - RenameAttributeRefactoring renameAttributeRefactoring = (RenameAttributeRefactoring) refactoring; - attributeBefore = renameAttributeRefactoring.getOriginalAttribute(); - attributeAfter = renameAttributeRefactoring.getRenamedAttribute(); - changeType = Change.Type.RENAME; - break; - } - case ADD_ATTRIBUTE_ANNOTATION: { - AddAttributeAnnotationRefactoring addAttributeAnnotationRefactoring = (AddAttributeAnnotationRefactoring) refactoring; - attributeBefore = addAttributeAnnotationRefactoring.getAttributeBefore(); - attributeAfter = addAttributeAnnotationRefactoring.getAttributeAfter(); - changeType = Change.Type.ANNOTATION_CHANGE; - break; - } - case MODIFY_ATTRIBUTE_ANNOTATION: { - ModifyAttributeAnnotationRefactoring modifyAttributeAnnotationRefactoring = (ModifyAttributeAnnotationRefactoring) refactoring; - attributeBefore = modifyAttributeAnnotationRefactoring.getAttributeBefore(); - attributeAfter = modifyAttributeAnnotationRefactoring.getAttributeAfter(); - changeType = Change.Type.ANNOTATION_CHANGE; - break; - } - case REMOVE_ATTRIBUTE_ANNOTATION: { - RemoveAttributeAnnotationRefactoring removeAttributeAnnotationRefactoring = (RemoveAttributeAnnotationRefactoring) refactoring; - attributeBefore = removeAttributeAnnotationRefactoring.getAttributeBefore(); - attributeAfter = removeAttributeAnnotationRefactoring.getAttributeAfter(); - changeType = Change.Type.ANNOTATION_CHANGE; - break; - } - case CHANGE_ATTRIBUTE_TYPE: { - ChangeAttributeTypeRefactoring changeAttributeTypeRefactoring = (ChangeAttributeTypeRefactoring) refactoring; - attributeBefore = changeAttributeTypeRefactoring.getOriginalAttribute(); - attributeAfter = changeAttributeTypeRefactoring.getChangedTypeAttribute(); - changeType = Change.Type.TYPE_CHANGE; - break; - } - case ADD_ATTRIBUTE_MODIFIER: { - AddAttributeModifierRefactoring addAttributeModifierRefactoring = (AddAttributeModifierRefactoring) refactoring; - attributeBefore = addAttributeModifierRefactoring.getAttributeBefore(); - attributeAfter = addAttributeModifierRefactoring.getAttributeAfter(); - changeType = Change.Type.MODIFIER_CHANGE; - break; - } - case REMOVE_ATTRIBUTE_MODIFIER: { - RemoveAttributeModifierRefactoring removeAttributeModifierRefactoring = (RemoveAttributeModifierRefactoring) refactoring; - attributeBefore = removeAttributeModifierRefactoring.getAttributeBefore(); - attributeAfter = removeAttributeModifierRefactoring.getAttributeAfter(); - changeType = Change.Type.MODIFIER_CHANGE; - break; - } - case CHANGE_ATTRIBUTE_ACCESS_MODIFIER: { - ChangeAttributeAccessModifierRefactoring changeAttributeAccessModifierRefactoring = (ChangeAttributeAccessModifierRefactoring) refactoring; - attributeBefore = changeAttributeAccessModifierRefactoring.getAttributeBefore(); - attributeAfter = changeAttributeAccessModifierRefactoring.getAttributeAfter(); - changeType = Change.Type.ACCESS_MODIFIER_CHANGE; - break; - } - case EXTRACT_ATTRIBUTE: { - ExtractAttributeRefactoring extractAttributeRefactoring = (ExtractAttributeRefactoring) refactoring; - Attribute rightAttribute = Attribute.of(extractAttributeRefactoring.getVariableDeclaration(), currentVersion); - if (equalOperator.test(rightAttribute)) { - Attribute leftAttribute = Attribute.of(extractAttributeRefactoring.getVariableDeclaration(), parentVersion); - attributeChangeHistory.handleAdd(leftAttribute, rightAttribute , refactoring.toString()); - attributeChangeHistory.connectRelatedNodes(); - leftAttributeSet.add(leftAttribute); - return leftAttributeSet; - } - break; - } - - } - - addAttributeChange(currentVersion, parentVersion, equalOperator, leftAttributeSet, refactoring, attributeBefore, attributeAfter, changeType); - } - attributeChangeHistory.connectRelatedNodes(); - return leftAttributeSet; - } - - public boolean addAttributeChange(Version currentVersion, Version parentVersion, Predicate equalOperator, Set leftAttributeSet, Refactoring refactoring, UMLAttribute umlAttributeBefore, UMLAttribute umlAttributeAfter, Change.Type changeType) { - if (umlAttributeAfter != null) { - Attribute attributeAfter = Attribute.of(umlAttributeAfter, currentVersion); - if (equalOperator.test(attributeAfter)) { - Attribute attributeBefore = Attribute.of(umlAttributeBefore, parentVersion); - attributeChangeHistory.addChange(attributeBefore, attributeAfter, ChangeFactory.forAttribute(changeType).refactoring(refactoring)); - leftAttributeSet.add(attributeBefore); - return true; - } - } - return false; - } - - private boolean isAttributeAdded(UMLModelDiff modelDiff, ArrayDeque attributes, String className, Version currentVersion, Version parentVersion, Predicate equalOperator) { - List addedAttributes = getAllClassesDiff(modelDiff) - .stream() - .map(UMLClassBaseDiff::getAddedAttributes) - .flatMap(List::stream) - .collect(Collectors.toList()); - for (UMLAttribute umlAttribute : addedAttributes) { - if (handleAddAttribute(attributes, currentVersion, parentVersion, equalOperator, umlAttribute, "new attribute")) - return true; - } - - UMLClass addedClass = modelDiff.getAddedClass(className); - if (addedClass != null) { - for (UMLAttribute umlAttribute : addedClass.getAttributes()) { - if (handleAddAttribute(attributes, currentVersion, parentVersion, equalOperator, umlAttribute, "added with new class")) - return true; - } - } - - for (UMLClassRenameDiff classRenameDiffList : modelDiff.getClassRenameDiffList()) { - for (UMLAnonymousClass addedAnonymousClasses : classRenameDiffList.getAddedAnonymousClasses()) { - for (UMLAttribute umlAttribute : addedAnonymousClasses.getAttributes()) { - if (handleAddAttribute(attributes, currentVersion, parentVersion, equalOperator, umlAttribute, "added with new anonymous class")) - return true; - } - } - } - return false; - } - - private boolean handleAddAttribute(ArrayDeque attributes, Version currentVersion, Version parentVersion, Predicate equalOperator, UMLAttribute umlAttribute, String comment) { - Attribute rightAttribute = Attribute.of(umlAttribute, currentVersion); - if (equalOperator.test(rightAttribute)) { - Attribute leftAttribute = Attribute.of(umlAttribute, parentVersion); - attributeChangeHistory.handleAdd(leftAttribute, rightAttribute, comment); - attributeChangeHistory.connectRelatedNodes(); - attributes.addFirst(leftAttribute); - return true; - } - return false; - } - - private Set isAttributeContainerChanged(UMLModelDiff umlModelDiffAll, Collection refactorings, Version currentVersion, Version parentVersion, Predicate equalOperator) { - Set leftAttributeSet = new HashSet<>(); - boolean found = false; - Change.Type changeType = Change.Type.CONTAINER_CHANGE; - - for (UMLClassMoveDiff umlClassMoveDiff : getClassMoveDiffList(umlModelDiffAll)) { - for (UMLAttributeDiff attributeDiff : umlClassMoveDiff.getAttributeDiffList()) { - if (addAttributeChange(currentVersion, parentVersion, equalOperator, leftAttributeSet, new MoveClassRefactoring(umlClassMoveDiff.getOriginalClass(), umlClassMoveDiff.getMovedClass()), attributeDiff.getRemovedAttribute(), attributeDiff.getAddedAttribute(), changeType)) { - attributeChangeHistory.connectRelatedNodes(); - return leftAttributeSet; - } - } - } - - for (UMLClassRenameDiff umlClassRenameDiff : umlModelDiffAll.getClassRenameDiffList()) { - for (UMLAttributeDiff attributeDiff : umlClassRenameDiff.getAttributeDiffList()) { - if (addAttributeChange(currentVersion, parentVersion, equalOperator, leftAttributeSet, new RenameClassRefactoring(umlClassRenameDiff.getOriginalClass(), umlClassRenameDiff.getRenamedClass()), attributeDiff.getRemovedAttribute(), attributeDiff.getAddedAttribute(), changeType)) { - attributeChangeHistory.connectRelatedNodes(); - return leftAttributeSet; - } - } - } - for (UMLClassMoveDiff umlClassMoveDiff : umlModelDiffAll.getInnerClassMoveDiffList()) { - for (UMLAttributeDiff attributeDiff : umlClassMoveDiff.getAttributeDiffList()) { - if (addAttributeChange(currentVersion, parentVersion, equalOperator, leftAttributeSet, new MoveClassRefactoring(umlClassMoveDiff.getOriginalClass(), umlClassMoveDiff.getMovedClass()), attributeDiff.getRemovedAttribute(), attributeDiff.getAddedAttribute(), changeType)) { - attributeChangeHistory.connectRelatedNodes(); - return leftAttributeSet; - } - } - } - - for (Refactoring refactoring : refactorings) { - if (refactoring.getRefactoringType() == RefactoringType.MOVE_SOURCE_FOLDER) { - MoveSourceFolderRefactoring moveSourceFolderRefactoring = (MoveSourceFolderRefactoring) refactoring; - for (MovedClassToAnotherSourceFolder movedClassToAnotherSourceFolder : moveSourceFolderRefactoring.getMovedClassesToAnotherSourceFolder()) { - UMLClass originalClass = movedClassToAnotherSourceFolder.getOriginalClass(); - UMLClass movedClass = movedClassToAnotherSourceFolder.getMovedClass(); - if (checkAttributeContainerChangeInMovedClasses(originalClass, movedClass, currentVersion, parentVersion, equalOperator, refactoring, leftAttributeSet)) { - return leftAttributeSet; - } - } - } else if (refactoring.getRefactoringType() == RefactoringType.MOVE_CLASS) { - MoveClassRefactoring moveClassRefactoring = (MoveClassRefactoring) refactoring; - UMLClass originalClass = moveClassRefactoring.getOriginalClass(); - UMLClass movedClass = moveClassRefactoring.getMovedClass(); - if (checkAttributeContainerChangeInMovedClasses(originalClass, movedClass, currentVersion, parentVersion, equalOperator, refactoring, leftAttributeSet)) { - return leftAttributeSet; - } - } else if (refactoring.getRefactoringType() == RefactoringType.RENAME_CLASS) { - RenameClassRefactoring renameClassRefactoring = (RenameClassRefactoring) refactoring; - UMLClass originalClass = renameClassRefactoring.getOriginalClass(); - UMLClass renamedClass = renameClassRefactoring.getRenamedClass(); - if (checkAttributeContainerChangeInMovedClasses(originalClass, renamedClass, currentVersion, parentVersion, equalOperator, refactoring, leftAttributeSet)) { - return leftAttributeSet; - } - } else if (refactoring.getRefactoringType() == RefactoringType.MOVE_RENAME_CLASS) { - MoveAndRenameClassRefactoring moveAndRenameClassRefactoring = (MoveAndRenameClassRefactoring) refactoring; - UMLClass originalClass = moveAndRenameClassRefactoring.getOriginalClass(); - UMLClass renamedClass = moveAndRenameClassRefactoring.getRenamedClass(); - if (checkAttributeContainerChangeInMovedClasses(originalClass, renamedClass, currentVersion, parentVersion, equalOperator, refactoring, leftAttributeSet)) { - return leftAttributeSet; - } - } - } - return Collections.emptySet(); - } - - public boolean checkAttributeContainerChangeInMovedClasses(UMLClass originalClass, UMLClass movedClass, Version currentVersion, Version parentVersion, Predicate equalOperator, Refactoring refactoring, Set leftAttributeSet) { - for (UMLAttribute umlAttributeAfter : movedClass.getAttributes()) { - Attribute attributeAfter = Attribute.of(umlAttributeAfter, currentVersion); - if (equalOperator.test(attributeAfter)) { - for (UMLAttribute umlAttributeBefore : originalClass.getAttributes()) { - if (umlAttributeAfter.equals(umlAttributeBefore)) { - Attribute attributeBefore = Attribute.of(umlAttributeBefore, parentVersion); - attributeChangeHistory.addChange(attributeBefore, attributeAfter, ChangeFactory.forAttribute(Change.Type.CONTAINER_CHANGE).refactoring(refactoring)); - attributeChangeHistory.connectRelatedNodes(); - leftAttributeSet.add(attributeBefore); - - return true; - } - } - } - + return new HistoryImpl<>(changeHistory.get().getCompleteGraph(), historyReport); } - return false; } - }