diff --git a/src/main/java/org/codetracker/AnnotationTrackerChangeHistory.java b/src/main/java/org/codetracker/AnnotationTrackerChangeHistory.java index 79c8298a619..ad1523eb736 100644 --- a/src/main/java/org/codetracker/AnnotationTrackerChangeHistory.java +++ b/src/main/java/org/codetracker/AnnotationTrackerChangeHistory.java @@ -17,7 +17,6 @@ import org.codetracker.element.Class; import org.codetracker.element.Method; import org.refactoringminer.api.Refactoring; -import org.refactoringminer.api.RefactoringMinerTimedOutException; import gr.uom.java.xmi.LocationInfo.CodeElementType; import gr.uom.java.xmi.UMLAnnotation; @@ -118,7 +117,7 @@ public boolean isStartClass(Class clazz) { clazz.getUmlClass().getLocationInfo().getEndLine() >= methodDeclarationLineNumber; } - public boolean checkForExtractionOrInline(Version currentVersion, Version parentVersion, Predicate equalMethod, Annotation rightAnnotation, List refactorings) throws RefactoringMinerTimedOutException { + public boolean checkForExtractionOrInline(Version currentVersion, Version parentVersion, Predicate equalMethod, Annotation rightAnnotation, List refactorings) { int extractMatches = 0; for (Refactoring refactoring : refactorings) { switch (refactoring.getRefactoringType()) { @@ -221,7 +220,7 @@ public boolean checkForExtractionOrInline(Version currentVersion, Version parent return false; } - public boolean checkClassDiffForAnnotationChange(Version currentVersion, Version parentVersion, Predicate equalMethod, Predicate equalAnnotation, UMLAbstractClassDiff umlClassDiff) throws RefactoringMinerTimedOutException { + public boolean checkClassDiffForAnnotationChange(Version currentVersion, Version parentVersion, Predicate equalMethod, Predicate equalAnnotation, UMLAbstractClassDiff umlClassDiff) { for (UMLOperationBodyMapper operationBodyMapper : umlClassDiff.getOperationBodyMapperList()) { Method method2 = Method.of(operationBodyMapper.getContainer2(), currentVersion); if (equalMethod.test(method2)) { @@ -291,7 +290,7 @@ public void addedAttribute(Attribute rightAttribute, Annotation rightAnnotation, annotationChangeHistory.connectRelatedNodes(); } - public boolean checkBodyOfMatchedOperations(Version currentVersion, Version parentVersion, Predicate equalOperator, UMLOperationBodyMapper umlOperationBodyMapper) throws RefactoringMinerTimedOutException { + public boolean checkBodyOfMatchedOperations(Version currentVersion, Version parentVersion, Predicate equalOperator, UMLOperationBodyMapper umlOperationBodyMapper) { if (umlOperationBodyMapper == null) return false; // check if it is in the matched @@ -351,7 +350,7 @@ private boolean isAdded(UMLOperationBodyMapper umlOperationBodyMapper, Version c return false; } - public boolean checkBodyOfMatchedClasses(Version currentVersion, Version parentVersion, Predicate equalOperator, UMLAbstractClassDiff classDiff) throws RefactoringMinerTimedOutException { + public boolean checkBodyOfMatchedClasses(Version currentVersion, Version parentVersion, Predicate equalOperator, UMLAbstractClassDiff classDiff) { if (classDiff == null) return false; // check if it is in the matched @@ -465,7 +464,7 @@ private boolean isAdded(Pair equalMethod, Annotation rightAnnotation, List refactorings) throws RefactoringMinerTimedOutException { + public boolean checkRefactoredMethod(Version currentVersion, Version parentVersion, Predicate equalMethod, Annotation rightAnnotation, List refactorings) { for (Refactoring refactoring : refactorings) { UMLOperation operationBefore = null; UMLOperation operationAfter = null; @@ -513,7 +512,7 @@ public boolean checkRefactoredMethod(Version currentVersion, Version parentVersi return false; } - public boolean checkRefactoredAttribute(Version currentVersion, Version parentVersion, Predicate equalAttribute, Annotation rightAnnotation, List refactorings) throws RefactoringMinerTimedOutException { + public boolean checkRefactoredAttribute(Version currentVersion, Version parentVersion, Predicate equalAttribute, Annotation rightAnnotation, List refactorings) { for (Refactoring refactoring : refactorings) { UMLAttribute attributeBefore = null; UMLAttribute attributeAfter = null; diff --git a/src/main/java/org/codetracker/BlockTrackerChangeHistory.java b/src/main/java/org/codetracker/BlockTrackerChangeHistory.java index 093ff8d9414..c30b792b5fd 100644 --- a/src/main/java/org/codetracker/BlockTrackerChangeHistory.java +++ b/src/main/java/org/codetracker/BlockTrackerChangeHistory.java @@ -25,7 +25,6 @@ import org.codetracker.element.Block; import org.codetracker.element.Method; import org.refactoringminer.api.Refactoring; -import org.refactoringminer.api.RefactoringMinerTimedOutException; import gr.uom.java.xmi.UMLOperation; import gr.uom.java.xmi.UMLType; @@ -42,8 +41,6 @@ import gr.uom.java.xmi.decomposition.VariableDeclaration; import gr.uom.java.xmi.diff.ExtractOperationRefactoring; import gr.uom.java.xmi.diff.InlineOperationRefactoring; -import gr.uom.java.xmi.diff.MergeCatchRefactoring; -import gr.uom.java.xmi.diff.MergeConditionalRefactoring; import gr.uom.java.xmi.diff.MergeOperationRefactoring; import gr.uom.java.xmi.diff.MoveOperationRefactoring; import gr.uom.java.xmi.diff.PullUpOperationRefactoring; @@ -109,7 +106,7 @@ public boolean isStartMethod(Method method) { method.getUmlOperation().getLocationInfo().getEndLine() >= methodDeclarationLineNumber; } - public boolean checkClassDiffForBlockChange(Version currentVersion, Version parentVersion, Predicate equalMethod, Predicate equalBlock, UMLAbstractClassDiff umlClassDiff) throws RefactoringMinerTimedOutException { + public boolean checkClassDiffForBlockChange(Version currentVersion, Version parentVersion, Predicate equalMethod, Predicate equalBlock, UMLAbstractClassDiff umlClassDiff) { for (UMLOperationBodyMapper operationBodyMapper : umlClassDiff.getOperationBodyMapperList()) { Method method2 = Method.of(operationBodyMapper.getContainer2(), currentVersion); if (equalMethod.test(method2)) { @@ -126,7 +123,7 @@ public boolean checkClassDiffForBlockChange(Version currentVersion, Version pare return false; } - public boolean checkForExtractionOrInline(Version currentVersion, Version parentVersion, Predicate equalMethod, Block rightBlock, List refactorings) throws RefactoringMinerTimedOutException { + public boolean checkForExtractionOrInline(Version currentVersion, Version parentVersion, Predicate equalMethod, Block rightBlock, List refactorings) { int extractMatches = 0; for (Refactoring refactoring : refactorings) { switch (refactoring.getRefactoringType()) { @@ -401,7 +398,7 @@ else if (mapping instanceof LeafMapping && mapping.getFragment1() instanceof Sta return false; } - public boolean checkBodyOfMatchedOperations(Version currentVersion, Version parentVersion, Predicate equalOperator, UMLOperationBodyMapper umlOperationBodyMapper) throws RefactoringMinerTimedOutException { + public boolean checkBodyOfMatchedOperations(Version currentVersion, Version parentVersion, Predicate equalOperator, UMLOperationBodyMapper umlOperationBodyMapper) { if (umlOperationBodyMapper == null) return false; Set refactorings = umlOperationBodyMapper.getRefactoringsAfterPostProcessing(); @@ -764,7 +761,7 @@ private boolean isAdded(UMLOperationBodyMapper umlOperationBodyMapper, Version c return false; } - public boolean checkRefactoredMethod(Version currentVersion, Version parentVersion, Predicate equalMethod, Block rightBlock, List refactorings) throws RefactoringMinerTimedOutException { + public boolean checkRefactoredMethod(Version currentVersion, Version parentVersion, Predicate equalMethod, Block rightBlock, List refactorings) { for (Refactoring refactoring : refactorings) { UMLOperation operationBefore = null; UMLOperation operationAfter = null; diff --git a/src/main/java/org/codetracker/CommentTrackerChangeHistory.java b/src/main/java/org/codetracker/CommentTrackerChangeHistory.java index 827e8ae1a73..1931cdc6c74 100644 --- a/src/main/java/org/codetracker/CommentTrackerChangeHistory.java +++ b/src/main/java/org/codetracker/CommentTrackerChangeHistory.java @@ -18,7 +18,6 @@ import org.codetracker.element.Comment; import org.codetracker.element.Method; import org.refactoringminer.api.Refactoring; -import org.refactoringminer.api.RefactoringMinerTimedOutException; import gr.uom.java.xmi.UMLOperation; import gr.uom.java.xmi.VariableDeclarationContainer; @@ -26,21 +25,37 @@ import gr.uom.java.xmi.UMLAttribute; import gr.uom.java.xmi.UMLClass; import gr.uom.java.xmi.UMLComment; +import gr.uom.java.xmi.UMLEnumConstant; import gr.uom.java.xmi.UMLJavadoc; import gr.uom.java.xmi.decomposition.AbstractCodeFragment; import gr.uom.java.xmi.decomposition.UMLOperationBodyMapper; +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.ExtractOperationRefactoring; import gr.uom.java.xmi.diff.InlineOperationRefactoring; import gr.uom.java.xmi.diff.MergeOperationRefactoring; +import gr.uom.java.xmi.diff.ModifyAttributeAnnotationRefactoring; +import gr.uom.java.xmi.diff.MoveAndRenameAttributeRefactoring; +import gr.uom.java.xmi.diff.MoveAttributeRefactoring; import gr.uom.java.xmi.diff.MoveOperationRefactoring; +import gr.uom.java.xmi.diff.PullUpAttributeRefactoring; import gr.uom.java.xmi.diff.PullUpOperationRefactoring; +import gr.uom.java.xmi.diff.PushDownAttributeRefactoring; import gr.uom.java.xmi.diff.PushDownOperationRefactoring; +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.RenameOperationRefactoring; import gr.uom.java.xmi.diff.SplitOperationRefactoring; import gr.uom.java.xmi.diff.UMLAbstractClassDiff; import gr.uom.java.xmi.diff.UMLAnonymousClassDiff; +import gr.uom.java.xmi.diff.UMLAttributeDiff; import gr.uom.java.xmi.diff.UMLCommentListDiff; import gr.uom.java.xmi.diff.UMLDocumentationDiffProvider; +import gr.uom.java.xmi.diff.UMLEnumConstantDiff; import gr.uom.java.xmi.diff.UMLJavadocDiff; public class CommentTrackerChangeHistory extends AbstractChangeHistory { @@ -96,13 +111,19 @@ public boolean isStartMethod(Method method) { method.getUmlOperation().getLocationInfo().getEndLine() >= methodDeclarationLineNumber; } + public boolean isStartAttribute(Attribute attribute) { + return attribute.getUmlAttribute().getName().equals(methodName) && + attribute.getUmlAttribute().getLocationInfo().getStartLine() <= methodDeclarationLineNumber && + attribute.getUmlAttribute().getLocationInfo().getEndLine() >= methodDeclarationLineNumber; + } + public boolean isStartClass(Class clazz) { return clazz.getUmlClass().getName().equals(methodName) && clazz.getUmlClass().getLocationInfo().getStartLine() <= methodDeclarationLineNumber && clazz.getUmlClass().getLocationInfo().getEndLine() >= methodDeclarationLineNumber; } - public boolean checkClassDiffForCommentChange(Version currentVersion, Version parentVersion, Predicate equalMethod, Predicate equalComment, UMLAbstractClassDiff umlClassDiff) throws RefactoringMinerTimedOutException { + public boolean checkClassDiffForCommentChange(Version currentVersion, Version parentVersion, Predicate equalMethod, Predicate equalComment, UMLAbstractClassDiff umlClassDiff) { for (UMLOperationBodyMapper operationBodyMapper : umlClassDiff.getOperationBodyMapperList()) { Method method2 = Method.of(operationBodyMapper.getContainer2(), currentVersion); if (equalMethod.test(method2)) { @@ -117,7 +138,47 @@ public boolean checkClassDiffForCommentChange(Version currentVersion, Version pa return false; } - public boolean checkForExtractionOrInline(Version currentVersion, Version parentVersion, Predicate equalMethod, Comment rightComment, List refactorings) throws RefactoringMinerTimedOutException { + public boolean checkClassDiffForCommentChange(Version currentVersion, Version parentVersion, Attribute rightAttribute, Predicate equalComment, UMLAbstractClassDiff umlClassDiff) { + if (umlClassDiff == null) + return false; + boolean found = false; + Pair foundPair = null; + for (Pair pair : umlClassDiff.getCommonAtrributes()) { + if (pair.getRight().equals(rightAttribute.getUmlAttribute())) { + foundPair = pair; + break; + } + } + for (Pair pair : umlClassDiff.getCommonEnumConstants()) { + if (pair.getRight().equals(rightAttribute.getUmlAttribute())) { + foundPair = pair; + break; + } + } + UMLDocumentationDiffProvider provider = null; + for (UMLAttributeDiff attributeDiff : umlClassDiff.getAttributeDiffList()) { + if (attributeDiff.getContainer2().equals(rightAttribute.getUmlAttribute())) { + provider = attributeDiff; + break; + } + } + for (UMLEnumConstantDiff attributeDiff : umlClassDiff.getEnumConstantDiffList()) { + if (attributeDiff.getContainer2().equals(rightAttribute.getUmlAttribute())) { + provider = attributeDiff; + break; + } + } + if (foundPair != null) { + Pair pair = Pair.of(foundPair.getLeft(), foundPair.getRight()); + found = checkBodyOfMatchedAttributes(currentVersion, parentVersion, equalComment, pair); + } + if (provider != null) { + found = checkBodyOfMatchedOperations(currentVersion, parentVersion, equalComment, provider); + } + return found; + } + + public boolean checkForExtractionOrInline(Version currentVersion, Version parentVersion, Predicate equalMethod, Comment rightComment, List refactorings) { int extractMatches = 0; for (Refactoring refactoring : refactorings) { switch (refactoring.getRefactoringType()) { @@ -304,7 +365,7 @@ public boolean checkBodyOfMatchedAttributes(Version currentVersion, Version pare return isAdded(pair, currentVersion, parentVersion, equalOperator); } - public boolean checkBodyOfMatchedOperations(Version currentVersion, Version parentVersion, Predicate equalOperator, UMLDocumentationDiffProvider umlOperationBodyMapper) throws RefactoringMinerTimedOutException { + public boolean checkBodyOfMatchedOperations(Version currentVersion, Version parentVersion, Predicate equalOperator, UMLDocumentationDiffProvider umlOperationBodyMapper) { if (umlOperationBodyMapper == null) return false; // check if it is in the matched @@ -485,7 +546,7 @@ private boolean isAdded(UMLDocumentationDiffProvider umlOperationBodyMapper, Ver return false; } - public boolean checkBodyOfMatchedClasses(Version currentVersion, Version parentVersion, Predicate equalOperator, UMLAbstractClassDiff classDiff) throws RefactoringMinerTimedOutException { + public boolean checkBodyOfMatchedClasses(Version currentVersion, Version parentVersion, Predicate equalOperator, UMLAbstractClassDiff classDiff) { if (classDiff == null) return false; // check if it is in the matched @@ -621,7 +682,7 @@ private boolean isAdded(UMLAbstractClassDiff classDiff, Version currentVersion, return false; } - public boolean checkRefactoredMethod(Version currentVersion, Version parentVersion, Predicate equalMethod, Comment rightComment, List refactorings) throws RefactoringMinerTimedOutException { + public boolean checkRefactoredMethod(Version currentVersion, Version parentVersion, Predicate equalMethod, Comment rightComment, List refactorings) { for (Refactoring refactoring : refactorings) { UMLOperation operationBefore = null; UMLOperation operationAfter = null; @@ -669,6 +730,120 @@ public boolean checkRefactoredMethod(Version currentVersion, Version parentVersi return false; } + public boolean checkRefactoredAttribute(Version currentVersion, Version parentVersion, Predicate equalAttribute, Comment rightComment, List refactorings) { + 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; + 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 (equalAttribute.test(rightAttribute)) { + addedAttribute(rightAttribute, rightComment, parentVersion); + return true; + } + break; + } + } + if (attributeAfter != null) { + Attribute fieldAfter = Attribute.of(attributeAfter, currentVersion); + if (equalAttribute.test(fieldAfter)) { + Pair pair = Pair.of(attributeBefore, attributeAfter); + boolean found = checkBodyOfMatchedAttributes(currentVersion, parentVersion, rightComment::equalIdentifierIgnoringVersion, pair); + if (found) + return true; + } + } + } + return false; + } + public HistoryInfo blameReturn() { List> history = getHistory(); for (History.HistoryInfo historyInfo : history) { diff --git a/src/main/java/org/codetracker/CommentTrackerImpl.java b/src/main/java/org/codetracker/CommentTrackerImpl.java index 38921054169..1effe5b1bdc 100644 --- a/src/main/java/org/codetracker/CommentTrackerImpl.java +++ b/src/main/java/org/codetracker/CommentTrackerImpl.java @@ -14,6 +14,7 @@ import org.codetracker.api.Version; import org.codetracker.change.Change; import org.codetracker.change.ChangeFactory; +import org.codetracker.element.Attribute; import org.codetracker.element.Class; import org.codetracker.element.Comment; import org.codetracker.element.Method; @@ -22,7 +23,9 @@ import org.refactoringminer.api.Refactoring; import org.refactoringminer.api.RefactoringType; +import gr.uom.java.xmi.UMLAttribute; import gr.uom.java.xmi.UMLClass; +import gr.uom.java.xmi.UMLEnumConstant; import gr.uom.java.xmi.UMLInitializer; import gr.uom.java.xmi.UMLJavadoc; import gr.uom.java.xmi.UMLModel; @@ -30,6 +33,8 @@ import gr.uom.java.xmi.VariableDeclarationContainer; import gr.uom.java.xmi.LocationInfo.CodeElementType; import gr.uom.java.xmi.decomposition.UMLOperationBodyMapper; +import gr.uom.java.xmi.diff.MoveAndRenameAttributeRefactoring; +import gr.uom.java.xmi.diff.MoveAttributeRefactoring; import gr.uom.java.xmi.diff.MoveOperationRefactoring; import gr.uom.java.xmi.diff.MoveSourceFolderRefactoring; import gr.uom.java.xmi.diff.UMLAbstractClassDiff; @@ -52,8 +57,9 @@ public History.HistoryInfo blame() throws Exception { Version startVersion = gitRepository.getVersion(startCommitId); UMLModel umlModel = getUMLModel(startCommitId, Collections.singleton(filePath)); Method startMethod = getMethod(umlModel, startVersion, changeHistory::isStartMethod); + Attribute startAttribute = getAttribute(umlModel, startVersion, changeHistory::isStartAttribute); Class startClass = getClass(umlModel, startVersion, changeHistory::isStartClass); - if (startMethod == null && startClass == null) { + if (startMethod == null && startClass == null && startAttribute == null) { throw new CodeElementNotFoundException(filePath, changeHistory.getMethodName(), changeHistory.getMethodDeclarationLineNumber()); } Comment startComment = null; @@ -61,6 +67,8 @@ public History.HistoryInfo blame() throws Exception { startComment = startMethod.findComment(changeHistory::isStartComment); if (startClass != null) startComment = startClass.findComment(changeHistory::isStartComment); + if (startAttribute != null) + startComment = startAttribute.findComment(changeHistory::isStartComment); if (startComment == null) { throw new CodeElementNotFoundException(filePath, changeHistory.getCommentType().name(), changeHistory.getCommentStartLineNumber()); } @@ -95,243 +103,436 @@ public History.HistoryInfo blame() throws Exception { String parentCommitId = gitRepository.getParentId(commitId); Version parentVersion = gitRepository.getVersion(parentCommitId); if (currentComment.getOperation().isPresent()) { - Method currentMethod = Method.of(currentComment.getOperation().get(), currentVersion); - UMLModel rightModel = getUMLModel(commitId, Collections.singleton(currentMethod.getFilePath())); - Method rightMethod = getMethod(rightModel, currentVersion, currentMethod::equalIdentifierIgnoringVersion); - if (rightMethod == null) { - continue; - } - String rightMethodClassName = rightMethod.getUmlOperation().getClassName(); - Comment rightComment = rightMethod.findComment(currentComment::equalIdentifierIgnoringVersion); - if (rightComment == null) { - continue; - } - Predicate equalMethod = rightMethod::equalIdentifierIgnoringVersion; - Predicate equalComment = rightComment::equalIdentifierIgnoringVersion; - historyReport.analysedCommitsPlusPlus(); - if ("0".equals(parentCommitId)) { - Method leftMethod = Method.of(rightMethod.getUmlOperation(), parentVersion); - Comment leftComment = Comment.of(rightComment.getComment(), leftMethod); - changeHistory.get().handleAdd(leftComment, rightComment, "Initial commit!"); - changeHistory.get().connectRelatedNodes(); - changeHistory.add(leftComment); - break; - } - UMLModel leftModel = getUMLModel(parentCommitId, Collections.singleton(currentMethod.getFilePath())); - //NO CHANGE - Method leftMethod = getMethod(leftModel, parentVersion, rightMethod::equalIdentifierIgnoringVersion); - if (leftMethod != null) { - UMLJavadoc leftJavadoc = leftMethod.getUmlOperation().getJavadoc(); - UMLJavadoc rightJavadoc = rightMethod.getUmlOperation().getJavadoc(); - if (leftJavadoc == null && rightJavadoc != null && - rightComment.getComment().getLocationInfo().getCodeElementType().equals(CodeElementType.JAVADOC)) { - Comment commentBefore = Comment.of(rightComment.getComment(), rightComment.getOperation().get(), parentVersion); - changeHistory.get().handleAdd(commentBefore, rightComment, "new javadoc"); - changeHistory.add(commentBefore); - changeHistory.get().connectRelatedNodes(); - break; - } - else if (leftJavadoc != null && rightJavadoc != null && !leftJavadoc.getFullText().equals(rightJavadoc.getFullText()) && - rightComment.getComment().getLocationInfo().getCodeElementType().equals(CodeElementType.JAVADOC)) { - Comment commentBefore = Comment.of(leftJavadoc, leftMethod.getUmlOperation(), parentVersion); - Comment commentAfter = Comment.of(rightJavadoc, rightMethod.getUmlOperation(), currentVersion); - changeHistory.get().addChange(commentBefore, commentAfter, ChangeFactory.forComment(Change.Type.BODY_CHANGE)); - changeHistory.addFirst(commentBefore); - changeHistory.get().connectRelatedNodes(); - } - historyReport.step2PlusPlus(); - continue; - } - //CHANGE BODY OR DOCUMENT - leftMethod = getMethod(leftModel, parentVersion, rightMethod::equalIdentifierIgnoringVersionAndDocumentAndBody); - //check if there is another method in leftModel with identical bodyHashCode to the rightMethod - boolean otherExactMatchFound = false; - if (leftMethod != null) { - for (UMLClass leftClass : leftModel.getClassList()) { - for (UMLOperation leftOperation : leftClass.getOperations()) { - if (leftOperation.getBodyHashCode() == rightMethod.getUmlOperation().getBodyHashCode() && !leftOperation.equals(leftMethod.getUmlOperation())) { - otherExactMatchFound = true; - break; - } - } - if(otherExactMatchFound) { - break; - } - } - } - if (leftMethod != null && !otherExactMatchFound) { - VariableDeclarationContainer leftOperation = leftMethod.getUmlOperation(); - VariableDeclarationContainer rightOperation = rightMethod.getUmlOperation(); - UMLOperationBodyMapper bodyMapper = null; - if (leftOperation instanceof UMLOperation && rightOperation instanceof UMLOperation) { - UMLClassBaseDiff lightweightClassDiff = lightweightClassDiff(leftModel, rightModel, leftOperation, rightOperation); - bodyMapper = new UMLOperationBodyMapper((UMLOperation) leftOperation, (UMLOperation) rightOperation, lightweightClassDiff); - } - else if (leftOperation instanceof UMLInitializer && rightOperation instanceof UMLInitializer) { - UMLClassBaseDiff lightweightClassDiff = lightweightClassDiff(leftModel, rightModel, leftOperation, rightOperation); - bodyMapper = new UMLOperationBodyMapper((UMLInitializer) leftOperation, (UMLInitializer) rightOperation, lightweightClassDiff); - } - if (changeHistory.checkBodyOfMatchedOperations(currentVersion, parentVersion, rightComment::equalIdentifierIgnoringVersion, bodyMapper)) { - historyReport.step3PlusPlus(); - break; - } - } - UMLModelDiff umlModelDiffLocal = leftModel.diff(rightModel); - { - //Local Refactoring - List refactorings = umlModelDiffLocal.getRefactorings(); - boolean found = changeHistory.checkForExtractionOrInline(currentVersion, parentVersion, equalMethod, rightComment, refactorings); - if (found) { - historyReport.step4PlusPlus(); - break; - } - found = changeHistory.checkRefactoredMethod(currentVersion, parentVersion, equalMethod, rightComment, refactorings); - if (found) { - historyReport.step4PlusPlus(); - break; - } - found = changeHistory.checkBodyOfMatchedOperations(currentVersion, parentVersion, rightComment::equalIdentifierIgnoringVersion, findBodyMapper(umlModelDiffLocal, rightMethod, currentVersion, parentVersion)); - if (found) { - historyReport.step4PlusPlus(); - break; - } - } - //All refactorings - { - CommitModel commitModel = getCommitModel(commitId); - if (!commitModel.moveSourceFolderRefactorings.isEmpty()) { - String leftFilePath = null; - for (MoveSourceFolderRefactoring ref : commitModel.moveSourceFolderRefactorings) { - if (ref.getIdenticalFilePaths().containsValue(currentComment.getFilePath())) { - for (Map.Entry entry : ref.getIdenticalFilePaths().entrySet()) { - if (entry.getValue().equals(currentComment.getFilePath())) { - leftFilePath = entry.getKey(); - break; - } - } - if (leftFilePath != null) { - break; - } - } - } - Pair umlModelPairPartial = getUMLModelPair(commitModel, currentMethod.getFilePath(), s -> true, true); - if (leftFilePath != null) { - boolean found = false; - for (UMLClass umlClass : umlModelPairPartial.getLeft().getClassList()) { - if (umlClass.getSourceFile().equals(leftFilePath)) { - for (UMLOperation operation : umlClass.getOperations()) { - if (operation.equals(rightMethod.getUmlOperation())) { - VariableDeclarationContainer rightOperation = rightMethod.getUmlOperation(); - UMLClassBaseDiff lightweightClassDiff = lightweightClassDiff(umlModelPairPartial.getLeft(), umlModelPairPartial.getRight(), operation, rightOperation); - UMLOperationBodyMapper bodyMapper = new UMLOperationBodyMapper(operation, (UMLOperation) rightOperation, lightweightClassDiff); - found = changeHistory.isMatched(bodyMapper, currentVersion, parentVersion, rightComment::equalIdentifierIgnoringVersion); - if (found) { - break; - } - } - } - if (found) { - break; - } - } - } - if (found) { - historyReport.step5PlusPlus(); - break; - } - } - else { - UMLModelDiff umlModelDiffPartial = umlModelPairPartial.getLeft().diff(umlModelPairPartial.getRight()); - //List refactoringsPartial = umlModelDiffPartial.getRefactorings(); - - boolean found; - UMLOperationBodyMapper bodyMapper = findBodyMapper(umlModelDiffPartial, rightMethod, currentVersion, parentVersion); - found = changeHistory.checkBodyOfMatchedOperations(currentVersion, parentVersion, rightComment::equalIdentifierIgnoringVersion, bodyMapper); - if (found) { - historyReport.step5PlusPlus(); - break; - } - } - } - { - Set fileNames = getRightSideFileNames(currentMethod, commitModel, umlModelDiffLocal); - Pair umlModelPairAll = getUMLModelPair(commitModel, currentMethod.getFilePath(), fileNames::contains, false); - UMLModelDiff umlModelDiffAll = umlModelPairAll.getLeft().diff(umlModelPairAll.getRight()); - - Set moveRenameClassRefactorings = umlModelDiffAll.getMoveRenameClassRefactorings(); - UMLClassBaseDiff classDiff = umlModelDiffAll.getUMLClassDiff(rightMethodClassName); - if (classDiff != null) { - List classLevelRefactorings = classDiff.getRefactorings(); - boolean found = changeHistory.checkForExtractionOrInline(currentVersion, parentVersion, equalMethod, rightComment, classLevelRefactorings); - if (found) { - historyReport.step5PlusPlus(); - break; - } - - found = changeHistory.checkRefactoredMethod(currentVersion, parentVersion, equalMethod, rightComment, classLevelRefactorings); - if (found) { - historyReport.step5PlusPlus(); - break; - } - - found = changeHistory.checkClassDiffForCommentChange(currentVersion, parentVersion, equalMethod, equalComment, classDiff); - if (found) { - historyReport.step5PlusPlus(); - break; - } - } - List refactorings = umlModelDiffAll.getRefactorings(); - boolean flag = false; - for (Refactoring refactoring : refactorings) { - if (RefactoringType.MOVE_AND_RENAME_OPERATION.equals(refactoring.getRefactoringType()) || RefactoringType.MOVE_OPERATION.equals(refactoring.getRefactoringType())) { - MoveOperationRefactoring moveOperationRefactoring = (MoveOperationRefactoring) refactoring; - Method movedOperation = Method.of(moveOperationRefactoring.getMovedOperation(), currentVersion); - if (rightMethod.equalIdentifierIgnoringVersion(movedOperation)) { - fileNames.add(moveOperationRefactoring.getOriginalOperation().getLocationInfo().getFilePath()); - flag = true; - } - } - } - if (flag) { - umlModelPairAll = getUMLModelPair(commitModel, currentMethod.getFilePath(), fileNames::contains, false); - umlModelDiffAll = umlModelPairAll.getLeft().diff(umlModelPairAll.getRight()); - refactorings = umlModelDiffAll.getRefactorings(); - } - - boolean found = changeHistory.checkForExtractionOrInline(currentVersion, parentVersion, equalMethod, rightComment, refactorings); - if (found) { - historyReport.step5PlusPlus(); - break; - } - - found = changeHistory.checkRefactoredMethod(currentVersion, parentVersion, equalMethod, rightComment, refactorings); - if (found) { - historyReport.step5PlusPlus(); - break; - } - - - UMLAbstractClassDiff umlClassDiff = getUMLClassDiff(umlModelDiffAll, rightMethodClassName); - if (umlClassDiff != null) { - found = changeHistory.checkClassDiffForCommentChange(currentVersion, parentVersion, equalMethod, equalComment, umlClassDiff); - - if (found) { - historyReport.step5PlusPlus(); - break; - } - } - - if (isMethodAdded(umlModelDiffAll, rightMethod.getUmlOperation().getClassName(), rightMethod::equalIdentifierIgnoringVersion, method -> { - }, currentVersion)) { - Comment commentBefore = Comment.of(rightComment.getComment(), rightComment.getOperation().get(), parentVersion); - changeHistory.get().handleAdd(commentBefore, rightComment, "added with method"); + if (currentComment.getOperation().get() instanceof UMLOperation || currentComment.getOperation().get() instanceof UMLInitializer) { + Method currentMethod = Method.of(currentComment.getOperation().get(), currentVersion); + UMLModel rightModel = getUMLModel(commitId, Collections.singleton(currentMethod.getFilePath())); + Method rightMethod = getMethod(rightModel, currentVersion, currentMethod::equalIdentifierIgnoringVersion); + if (rightMethod == null) { + continue; + } + String rightMethodClassName = rightMethod.getUmlOperation().getClassName(); + Comment rightComment = rightMethod.findComment(currentComment::equalIdentifierIgnoringVersion); + if (rightComment == null) { + continue; + } + Predicate equalMethod = rightMethod::equalIdentifierIgnoringVersion; + Predicate equalComment = rightComment::equalIdentifierIgnoringVersion; + historyReport.analysedCommitsPlusPlus(); + if ("0".equals(parentCommitId)) { + Method leftMethod = Method.of(rightMethod.getUmlOperation(), parentVersion); + Comment leftComment = Comment.of(rightComment.getComment(), leftMethod); + changeHistory.get().handleAdd(leftComment, rightComment, "Initial commit!"); + changeHistory.get().connectRelatedNodes(); + changeHistory.add(leftComment); + break; + } + UMLModel leftModel = getUMLModel(parentCommitId, Collections.singleton(currentMethod.getFilePath())); + //NO CHANGE + Method leftMethod = getMethod(leftModel, parentVersion, rightMethod::equalIdentifierIgnoringVersion); + if (leftMethod != null) { + UMLJavadoc leftJavadoc = leftMethod.getUmlOperation().getJavadoc(); + UMLJavadoc rightJavadoc = rightMethod.getUmlOperation().getJavadoc(); + if (leftJavadoc == null && rightJavadoc != null && + rightComment.getComment().getLocationInfo().getCodeElementType().equals(CodeElementType.JAVADOC)) { + Comment commentBefore = Comment.of(rightComment.getComment(), rightComment.getOperation().get(), parentVersion); + changeHistory.get().handleAdd(commentBefore, rightComment, "new javadoc"); changeHistory.add(commentBefore); changeHistory.get().connectRelatedNodes(); - historyReport.step5PlusPlus(); break; - } - } - } + } + else if (leftJavadoc != null && rightJavadoc != null && !leftJavadoc.getFullText().equals(rightJavadoc.getFullText()) && + rightComment.getComment().getLocationInfo().getCodeElementType().equals(CodeElementType.JAVADOC)) { + Comment commentBefore = Comment.of(leftJavadoc, leftMethod.getUmlOperation(), parentVersion); + Comment commentAfter = Comment.of(rightJavadoc, rightMethod.getUmlOperation(), currentVersion); + changeHistory.get().addChange(commentBefore, commentAfter, ChangeFactory.forComment(Change.Type.BODY_CHANGE)); + changeHistory.addFirst(commentBefore); + changeHistory.get().connectRelatedNodes(); + } + historyReport.step2PlusPlus(); + continue; + } + //CHANGE BODY OR DOCUMENT + leftMethod = getMethod(leftModel, parentVersion, rightMethod::equalIdentifierIgnoringVersionAndDocumentAndBody); + //check if there is another method in leftModel with identical bodyHashCode to the rightMethod + boolean otherExactMatchFound = false; + if (leftMethod != null) { + for (UMLClass leftClass : leftModel.getClassList()) { + for (UMLOperation leftOperation : leftClass.getOperations()) { + if (leftOperation.getBodyHashCode() == rightMethod.getUmlOperation().getBodyHashCode() && !leftOperation.equals(leftMethod.getUmlOperation())) { + otherExactMatchFound = true; + break; + } + } + if(otherExactMatchFound) { + break; + } + } + } + if (leftMethod != null && !otherExactMatchFound) { + VariableDeclarationContainer leftOperation = leftMethod.getUmlOperation(); + VariableDeclarationContainer rightOperation = rightMethod.getUmlOperation(); + UMLOperationBodyMapper bodyMapper = null; + if (leftOperation instanceof UMLOperation && rightOperation instanceof UMLOperation) { + UMLClassBaseDiff lightweightClassDiff = lightweightClassDiff(leftModel, rightModel, leftOperation, rightOperation); + bodyMapper = new UMLOperationBodyMapper((UMLOperation) leftOperation, (UMLOperation) rightOperation, lightweightClassDiff); + } + else if (leftOperation instanceof UMLInitializer && rightOperation instanceof UMLInitializer) { + UMLClassBaseDiff lightweightClassDiff = lightweightClassDiff(leftModel, rightModel, leftOperation, rightOperation); + bodyMapper = new UMLOperationBodyMapper((UMLInitializer) leftOperation, (UMLInitializer) rightOperation, lightweightClassDiff); + } + if (changeHistory.checkBodyOfMatchedOperations(currentVersion, parentVersion, rightComment::equalIdentifierIgnoringVersion, bodyMapper)) { + historyReport.step3PlusPlus(); + break; + } + } + UMLModelDiff umlModelDiffLocal = leftModel.diff(rightModel); + { + //Local Refactoring + List refactorings = umlModelDiffLocal.getRefactorings(); + boolean found = changeHistory.checkForExtractionOrInline(currentVersion, parentVersion, equalMethod, rightComment, refactorings); + if (found) { + historyReport.step4PlusPlus(); + break; + } + found = changeHistory.checkRefactoredMethod(currentVersion, parentVersion, equalMethod, rightComment, refactorings); + if (found) { + historyReport.step4PlusPlus(); + break; + } + found = changeHistory.checkBodyOfMatchedOperations(currentVersion, parentVersion, rightComment::equalIdentifierIgnoringVersion, findBodyMapper(umlModelDiffLocal, rightMethod, currentVersion, parentVersion)); + if (found) { + historyReport.step4PlusPlus(); + break; + } + } + //All refactorings + { + CommitModel commitModel = getCommitModel(commitId); + if (!commitModel.moveSourceFolderRefactorings.isEmpty()) { + String leftFilePath = null; + for (MoveSourceFolderRefactoring ref : commitModel.moveSourceFolderRefactorings) { + if (ref.getIdenticalFilePaths().containsValue(currentComment.getFilePath())) { + for (Map.Entry entry : ref.getIdenticalFilePaths().entrySet()) { + if (entry.getValue().equals(currentComment.getFilePath())) { + leftFilePath = entry.getKey(); + break; + } + } + if (leftFilePath != null) { + break; + } + } + } + Pair umlModelPairPartial = getUMLModelPair(commitModel, currentMethod.getFilePath(), s -> true, true); + if (leftFilePath != null) { + boolean found = false; + for (UMLClass umlClass : umlModelPairPartial.getLeft().getClassList()) { + if (umlClass.getSourceFile().equals(leftFilePath)) { + for (UMLOperation operation : umlClass.getOperations()) { + if (operation.equals(rightMethod.getUmlOperation())) { + VariableDeclarationContainer rightOperation = rightMethod.getUmlOperation(); + UMLClassBaseDiff lightweightClassDiff = lightweightClassDiff(umlModelPairPartial.getLeft(), umlModelPairPartial.getRight(), operation, rightOperation); + UMLOperationBodyMapper bodyMapper = new UMLOperationBodyMapper(operation, (UMLOperation) rightOperation, lightweightClassDiff); + found = changeHistory.isMatched(bodyMapper, currentVersion, parentVersion, rightComment::equalIdentifierIgnoringVersion); + if (found) { + break; + } + } + } + if (found) { + break; + } + } + } + if (found) { + historyReport.step5PlusPlus(); + break; + } + } + else { + UMLModelDiff umlModelDiffPartial = umlModelPairPartial.getLeft().diff(umlModelPairPartial.getRight()); + //List refactoringsPartial = umlModelDiffPartial.getRefactorings(); + + boolean found; + UMLOperationBodyMapper bodyMapper = findBodyMapper(umlModelDiffPartial, rightMethod, currentVersion, parentVersion); + found = changeHistory.checkBodyOfMatchedOperations(currentVersion, parentVersion, rightComment::equalIdentifierIgnoringVersion, bodyMapper); + if (found) { + historyReport.step5PlusPlus(); + break; + } + } + } + { + Set fileNames = getRightSideFileNames(currentMethod, commitModel, umlModelDiffLocal); + Pair umlModelPairAll = getUMLModelPair(commitModel, currentMethod.getFilePath(), fileNames::contains, false); + UMLModelDiff umlModelDiffAll = umlModelPairAll.getLeft().diff(umlModelPairAll.getRight()); + + Set moveRenameClassRefactorings = umlModelDiffAll.getMoveRenameClassRefactorings(); + UMLClassBaseDiff classDiff = umlModelDiffAll.getUMLClassDiff(rightMethodClassName); + if (classDiff != null) { + List classLevelRefactorings = classDiff.getRefactorings(); + boolean found = changeHistory.checkForExtractionOrInline(currentVersion, parentVersion, equalMethod, rightComment, classLevelRefactorings); + if (found) { + historyReport.step5PlusPlus(); + break; + } + + found = changeHistory.checkRefactoredMethod(currentVersion, parentVersion, equalMethod, rightComment, classLevelRefactorings); + if (found) { + historyReport.step5PlusPlus(); + break; + } + + found = changeHistory.checkClassDiffForCommentChange(currentVersion, parentVersion, equalMethod, equalComment, classDiff); + if (found) { + historyReport.step5PlusPlus(); + break; + } + } + List refactorings = umlModelDiffAll.getRefactorings(); + boolean flag = false; + for (Refactoring refactoring : refactorings) { + if (RefactoringType.MOVE_AND_RENAME_OPERATION.equals(refactoring.getRefactoringType()) || RefactoringType.MOVE_OPERATION.equals(refactoring.getRefactoringType())) { + MoveOperationRefactoring moveOperationRefactoring = (MoveOperationRefactoring) refactoring; + Method movedOperation = Method.of(moveOperationRefactoring.getMovedOperation(), currentVersion); + if (rightMethod.equalIdentifierIgnoringVersion(movedOperation)) { + fileNames.add(moveOperationRefactoring.getOriginalOperation().getLocationInfo().getFilePath()); + flag = true; + } + } + } + if (flag) { + umlModelPairAll = getUMLModelPair(commitModel, currentMethod.getFilePath(), fileNames::contains, false); + umlModelDiffAll = umlModelPairAll.getLeft().diff(umlModelPairAll.getRight()); + refactorings = umlModelDiffAll.getRefactorings(); + } + + boolean found = changeHistory.checkForExtractionOrInline(currentVersion, parentVersion, equalMethod, rightComment, refactorings); + if (found) { + historyReport.step5PlusPlus(); + break; + } + + found = changeHistory.checkRefactoredMethod(currentVersion, parentVersion, equalMethod, rightComment, refactorings); + if (found) { + historyReport.step5PlusPlus(); + break; + } + + + UMLAbstractClassDiff umlClassDiff = getUMLClassDiff(umlModelDiffAll, rightMethodClassName); + if (umlClassDiff != null) { + found = changeHistory.checkClassDiffForCommentChange(currentVersion, parentVersion, equalMethod, equalComment, umlClassDiff); + + if (found) { + historyReport.step5PlusPlus(); + break; + } + } + + if (isMethodAdded(umlModelDiffAll, rightMethod.getUmlOperation().getClassName(), rightMethod::equalIdentifierIgnoringVersion, method -> { + }, currentVersion)) { + Comment commentBefore = Comment.of(rightComment.getComment(), rightComment.getOperation().get(), parentVersion); + changeHistory.get().handleAdd(commentBefore, rightComment, "added with method"); + changeHistory.add(commentBefore); + changeHistory.get().connectRelatedNodes(); + historyReport.step5PlusPlus(); + break; + } + } + } + } + else if (currentComment.getOperation().get() instanceof UMLAttribute) { + // container is an Attribute + Attribute currentAttribute = Attribute.of((UMLAttribute) currentComment.getOperation().get(), currentVersion); + UMLModel rightModel = getUMLModel(commitId, Collections.singleton(currentAttribute.getFilePath())); + Attribute rightAttribute = getAttribute(rightModel, currentVersion, currentAttribute::equalIdentifierIgnoringVersion); + if (rightAttribute == null) { + continue; + } + String rightAttributeClassName = rightAttribute.getUmlAttribute().getClassName(); + Comment rightComment = rightAttribute.findComment(currentComment::equalIdentifierIgnoringVersion); + if (rightComment == null) { + continue; + } + Predicate equalAttribute = rightAttribute::equalIdentifierIgnoringVersion; + Predicate equalComment = rightComment::equalIdentifierIgnoringVersion; + historyReport.analysedCommitsPlusPlus(); + if ("0".equals(parentCommitId)) { + Attribute leftAttribute = Attribute.of(rightAttribute.getUmlAttribute(), parentVersion); + Comment leftComment = Comment.of(rightComment.getComment(), leftAttribute); + changeHistory.get().handleAdd(leftComment, rightComment, "Initial commit!"); + changeHistory.get().connectRelatedNodes(); + changeHistory.add(leftComment); + break; + } + UMLModel leftModel = getUMLModel(parentCommitId, Collections.singleton(currentAttribute.getFilePath())); + //NO CHANGE + Attribute leftAttribute = getAttribute(leftModel, parentVersion, rightAttribute::equalIdentifierIgnoringVersion); + if (leftAttribute != null) { + Pair pair = Pair.of(leftAttribute.getUmlAttribute(), rightAttribute.getUmlAttribute()); + changeHistory.checkBodyOfMatchedAttributes(currentVersion, parentVersion, equalComment, pair); + historyReport.step2PlusPlus(); + continue; + } + + UMLModelDiff umlModelDiffLocal = leftModel.diff(rightModel); + { + //Local Refactoring + List refactorings = umlModelDiffLocal.getRefactorings(); + boolean found = changeHistory.checkRefactoredAttribute(currentVersion, parentVersion, equalAttribute, rightComment, refactorings); + if (found) { + historyReport.step4PlusPlus(); + break; + } + UMLAbstractClassDiff umlClassDiff = getUMLClassDiff(umlModelDiffLocal, rightAttributeClassName); + found = changeHistory.checkClassDiffForCommentChange(currentVersion, parentVersion, rightAttribute, equalComment, umlClassDiff); + if (found) { + historyReport.step4PlusPlus(); + break; + } + } + //All refactorings + { + CommitModel commitModel = getCommitModel(commitId); + if (!commitModel.moveSourceFolderRefactorings.isEmpty()) { + String leftFilePath = null; + for (MoveSourceFolderRefactoring ref : commitModel.moveSourceFolderRefactorings) { + if (ref.getIdenticalFilePaths().containsValue(currentComment.getFilePath())) { + for (Map.Entry entry : ref.getIdenticalFilePaths().entrySet()) { + if (entry.getValue().equals(currentComment.getFilePath())) { + leftFilePath = entry.getKey(); + break; + } + } + if (leftFilePath != null) { + break; + } + } + } + Pair umlModelPairPartial = getUMLModelPair(commitModel, currentAttribute.getFilePath(), s -> true, true); + if (leftFilePath != null) { + boolean found = false; + for (UMLClass umlClass : umlModelPairPartial.getLeft().getClassList()) { + if (umlClass.getSourceFile().equals(leftFilePath)) { + for (UMLAttribute attribute : umlClass.getAttributes()) { + if (attribute.equals(rightAttribute.getUmlAttribute())) { + UMLAttribute rightField = rightAttribute.getUmlAttribute(); + Pair pair = Pair.of(attribute, rightField); + found = changeHistory.isMatched(pair, currentVersion, parentVersion, rightComment::equalIdentifierIgnoringVersion); + if (found) { + break; + } + } + } + for (UMLEnumConstant attribute : umlClass.getEnumConstants()) { + if (attribute.equals(rightAttribute.getUmlAttribute())) { + UMLAttribute rightField = rightAttribute.getUmlAttribute(); + Pair pair = Pair.of(attribute, rightField); + found = changeHistory.isMatched(pair, currentVersion, parentVersion, rightComment::equalIdentifierIgnoringVersion); + if (found) { + break; + } + } + } + if (found) { + break; + } + } + } + if (found) { + historyReport.step5PlusPlus(); + break; + } + } + else { + UMLModelDiff umlModelDiffPartial = umlModelPairPartial.getLeft().diff(umlModelPairPartial.getRight()); + //List refactoringsPartial = umlModelDiffPartial.getRefactorings(); + + UMLAbstractClassDiff umlClassDiff = getUMLClassDiff(umlModelDiffPartial, rightAttributeClassName); + boolean found = changeHistory.checkClassDiffForCommentChange(currentVersion, parentVersion, rightAttribute, equalComment, umlClassDiff); + if (found) { + historyReport.step5PlusPlus(); + break; + } + } + } + { + Set fileNames = getRightSideFileNames(currentAttribute.getFilePath(), currentAttribute.getUmlAttribute().getClassName(), Collections.emptySet(), commitModel, umlModelDiffLocal); + Pair umlModelPairAll = getUMLModelPair(commitModel, currentAttribute.getFilePath(), fileNames::contains, false); + UMLModelDiff umlModelDiffAll = umlModelPairAll.getLeft().diff(umlModelPairAll.getRight()); + + Set moveRenameClassRefactorings = umlModelDiffAll.getMoveRenameClassRefactorings(); + UMLClassBaseDiff classDiff = umlModelDiffAll.getUMLClassDiff(rightAttributeClassName); + if (classDiff != null) { + List classLevelRefactorings = classDiff.getRefactorings(); + + boolean found = changeHistory.checkRefactoredAttribute(currentVersion, parentVersion, equalAttribute, rightComment, classLevelRefactorings); + if (found) { + historyReport.step5PlusPlus(); + break; + } + + found = changeHistory.checkClassDiffForCommentChange(currentVersion, parentVersion, rightAttribute, equalComment, classDiff); + if (found) { + historyReport.step5PlusPlus(); + break; + } + } + List refactorings = umlModelDiffAll.getRefactorings(); + boolean flag = false; + for (Refactoring refactoring : refactorings) { + if (RefactoringType.MOVE_ATTRIBUTE.equals(refactoring.getRefactoringType())) { + MoveAttributeRefactoring moveAttributeRefactoring = (MoveAttributeRefactoring) refactoring; + Attribute movedAttribute = Attribute.of(moveAttributeRefactoring.getMovedAttribute(), currentVersion); + if (rightAttribute.equalIdentifierIgnoringVersion(movedAttribute)) { + fileNames.add(moveAttributeRefactoring.getOriginalAttribute().getLocationInfo().getFilePath()); + flag = true; + } + } + else if (RefactoringType.MOVE_RENAME_ATTRIBUTE.equals(refactoring.getRefactoringType())) { + MoveAndRenameAttributeRefactoring moveAttributeRefactoring = (MoveAndRenameAttributeRefactoring) refactoring; + Attribute movedAttribute = Attribute.of(moveAttributeRefactoring.getMovedAttribute(), currentVersion); + if (rightAttribute.equalIdentifierIgnoringVersion(movedAttribute)) { + fileNames.add(moveAttributeRefactoring.getOriginalAttribute().getLocationInfo().getFilePath()); + flag = true; + } + } + } + if (flag) { + umlModelPairAll = getUMLModelPair(commitModel, currentAttribute.getFilePath(), fileNames::contains, false); + umlModelDiffAll = umlModelPairAll.getLeft().diff(umlModelPairAll.getRight()); + refactorings = umlModelDiffAll.getRefactorings(); + } + + boolean found = changeHistory.checkRefactoredAttribute(currentVersion, parentVersion, equalAttribute, rightComment, refactorings); + if (found) { + historyReport.step5PlusPlus(); + break; + } + + + UMLAbstractClassDiff umlClassDiff = getUMLClassDiff(umlModelDiffAll, rightAttributeClassName); + if (umlClassDiff != null) { + found = changeHistory.checkClassDiffForCommentChange(currentVersion, parentVersion, rightAttribute, equalComment, umlClassDiff); + + if (found) { + historyReport.step5PlusPlus(); + break; + } + } + + if (isAttributeAdded(umlModelDiffAll, rightAttribute.getUmlAttribute().getClassName(), rightAttribute::equalIdentifierIgnoringVersion, currentVersion)) { + Comment commentBefore = Comment.of(rightComment.getComment(), rightComment.getOperation().get(), parentVersion); + changeHistory.get().handleAdd(commentBefore, rightComment, "added with attribute"); + changeHistory.add(commentBefore); + changeHistory.get().connectRelatedNodes(); + historyReport.step5PlusPlus(); + break; + } + } + } + } } else if (currentComment.getClazz().isPresent()) { Class currentClass = Class.of(currentComment.getClazz().get(), currentVersion); diff --git a/src/main/java/org/codetracker/FileTrackerImpl.java b/src/main/java/org/codetracker/FileTrackerImpl.java index c16c180fdd0..e2b7fccfdcc 100644 --- a/src/main/java/org/codetracker/FileTrackerImpl.java +++ b/src/main/java/org/codetracker/FileTrackerImpl.java @@ -475,7 +475,7 @@ else if (key instanceof Comment) { } } - private void processImportsAndClassComments(UMLAbstractClassDiff classDiff, Class rightClass, Version currentVersion, Version parentVersion) throws RefactoringMinerTimedOutException { + private void processImportsAndClassComments(UMLAbstractClassDiff classDiff, Class rightClass, Version currentVersion, Version parentVersion) { for (CodeElement key : programElementMap.keySet()) { if (key instanceof Import) { Import startImport = (Import)key; @@ -964,7 +964,7 @@ else if (key2 instanceof Annotation) { } private void processInnerClassesWithSameSignature(UMLModel rightModel, Version currentVersion, UMLModel leftModel, Version parentVersion, Class startClass, - Set> foundInnerClasses, Map notFoundInnerClasses) throws RefactoringMinerTimedOutException { + Set> foundInnerClasses, Map notFoundInnerClasses) { for (CodeElement key : programElementMap.keySet()) { if (key instanceof Class && !key.equals(startClass)) { Class startInnerClass = (Class)key; @@ -1069,7 +1069,7 @@ else if (startInnerClassChangeHistory.isClassAdded(umlModelDiff, currentVersion, } } - private Map processAttributesWithSameSignature(UMLModel rightModel, Version currentVersion, UMLModel leftModel, Version parentVersion) throws RefactoringMinerTimedOutException { + private Map processAttributesWithSameSignature(UMLModel rightModel, Version currentVersion, UMLModel leftModel, Version parentVersion) { Map notFoundAttributes = new LinkedHashMap<>(); for (CodeElement key : programElementMap.keySet()) { if (key instanceof Attribute) { diff --git a/src/main/java/org/codetracker/ImportTrackerChangeHistory.java b/src/main/java/org/codetracker/ImportTrackerChangeHistory.java index 67b39899c95..928fd29fbca 100644 --- a/src/main/java/org/codetracker/ImportTrackerChangeHistory.java +++ b/src/main/java/org/codetracker/ImportTrackerChangeHistory.java @@ -14,7 +14,6 @@ import org.codetracker.change.method.BodyChange; import org.codetracker.element.Class; import org.codetracker.element.Import; -import org.refactoringminer.api.RefactoringMinerTimedOutException; import gr.uom.java.xmi.UMLImport; import gr.uom.java.xmi.LocationInfo.CodeElementType; @@ -75,7 +74,7 @@ public boolean isStartClass(Class clazz) { clazz.getUmlClass().getLocationInfo().getEndLine() >= classDeclarationLineNumber; } - public boolean checkBodyOfMatchedClasses(Version currentVersion, Version parentVersion, Predicate equalOperator, UMLAbstractClassDiff classDiff) throws RefactoringMinerTimedOutException { + public boolean checkBodyOfMatchedClasses(Version currentVersion, Version parentVersion, Predicate equalOperator, UMLAbstractClassDiff classDiff) { if (classDiff == null) return false; // check if it is in the matched diff --git a/src/main/java/org/codetracker/VariableTrackerChangeHistory.java b/src/main/java/org/codetracker/VariableTrackerChangeHistory.java index 9d1427d2fbf..f25897017da 100644 --- a/src/main/java/org/codetracker/VariableTrackerChangeHistory.java +++ b/src/main/java/org/codetracker/VariableTrackerChangeHistory.java @@ -16,7 +16,6 @@ import org.codetracker.element.Method; import org.codetracker.element.Variable; import org.refactoringminer.api.Refactoring; -import org.refactoringminer.api.RefactoringMinerTimedOutException; import gr.uom.java.xmi.UMLAnonymousClass; import gr.uom.java.xmi.UMLOperation; @@ -92,7 +91,7 @@ public boolean isStartMethod(Method method) { method.getUmlOperation().getLocationInfo().getEndLine() >= methodDeclarationLineNumber; } - public boolean checkClassDiffForVariableChange(Version currentVersion, Version parentVersion, Predicate equalMethod, Predicate equalVariable, UMLAbstractClassDiff umlClassDiff) throws RefactoringMinerTimedOutException { + public boolean checkClassDiffForVariableChange(Version currentVersion, Version parentVersion, Predicate equalMethod, Predicate equalVariable, UMLAbstractClassDiff umlClassDiff) { for (UMLOperationBodyMapper operationBodyMapper : umlClassDiff.getOperationBodyMapperList()) { Method method2 = Method.of(operationBodyMapper.getContainer2(), currentVersion); if (equalMethod.test(method2)) { @@ -511,7 +510,7 @@ private Set analyseVariableRefactorings(Collection refact return leftVariableSet; } - public boolean checkRefactoredMethod(Version currentVersion, Version parentVersion, Predicate equalMethod, Variable rightVariable, List refactorings) throws RefactoringMinerTimedOutException { + public boolean checkRefactoredMethod(Version currentVersion, Version parentVersion, Predicate equalMethod, Variable rightVariable, List refactorings) { for (Refactoring refactoring : refactorings) { UMLOperation operationAfter = null; UMLOperationBodyMapper umlOperationBodyMapper = null; diff --git a/src/test/java/org/codetracker/blame/CodeTrackerBlameTest.java b/src/test/java/org/codetracker/blame/CodeTrackerBlameTest.java index 6142a1b5447..4385b2908e7 100644 --- a/src/test/java/org/codetracker/blame/CodeTrackerBlameTest.java +++ b/src/test/java/org/codetracker/blame/CodeTrackerBlameTest.java @@ -135,6 +135,20 @@ public void blameTestAttributeAnnotation() throws Exception { Assertions.assertEquals(expected, lineBlameResult.toString()); } + @Test + public void blameTestAttributeComment() throws Exception { + String url = "https://github.com/checkstyle/checkstyle/commit/119fd4fb33bef9f5c66fc950396669af842c21a3"; + String filePath = "src/main/java/com/puppycrawl/tools/checkstyle/Checker.java"; + int lineNumber = 69; + String expected = "LineBlameResult{commitId='b61daf7f44e5b3a817e712b6af84d6bca796fb28', filePath='src/main/java/com/puppycrawl/tools/checkstyle/Checker.java', shortCommitId='b61daf7f4', beforeFilePath='src/main/java/com/puppycrawl/tools/checkstyle/Checker.java', committer='rnveach', commitDate='1481152863', lineNumber=68}"; + String commitId = URLHelper.getCommit(url); + Repository repository = gitService.cloneIfNotExists(REPOS_PATH + "/" + getOwner(url) + "/" + getProject(url), URLHelper.getRepo(url)); + History.HistoryInfo lineBlame = + new CodeTrackerBlame().getLineBlame(repository, commitId, filePath, lineNumber); + LineBlameResult lineBlameResult = LineBlameResult.of(lineBlame); + Assertions.assertEquals(expected, lineBlameResult.toString()); + } + @Test public void testBlameLineRangeWithLocalRepo() throws Exception { String url = "https://github.com/checkstyle/checkstyle/commit/119fd4fb33bef9f5c66fc950396669af842c21a3";