Skip to content

Commit

Permalink
Bug fix when class is added (attributes + inner classes)
Browse files Browse the repository at this point in the history
  • Loading branch information
tsantalis committed Aug 18, 2024
1 parent bf5c735 commit 08672ca
Show file tree
Hide file tree
Showing 3 changed files with 182 additions and 6 deletions.
70 changes: 67 additions & 3 deletions src/main/java/org/codetracker/FileTrackerImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,8 @@ else if (leftSuperclass == null && rightSuperclass != null) {

if (startClassChangeHistory.isClassAdded(umlModelDiffAll, currentVersion, parentVersion, rightClass::equalIdentifierIgnoringVersion)) {
processAddedMethods(umlModelPairAll.getRight(), umlModelDiffAll, currentVersion, parentVersion);
processAddedAttributes(umlModelDiffAll, currentVersion, parentVersion);
processAddedAttributes(umlModelPairAll.getRight(), umlModelDiffAll, currentVersion, parentVersion);
processAddedInnerClasses(umlModelPairAll.getRight(), umlModelDiffAll, currentVersion, parentVersion, startClass);
processAddedImportsAndClassComments(rightClass, parentVersion);
break;
}
Expand Down Expand Up @@ -513,7 +514,62 @@ else if (key instanceof Comment) {
}
}

private void processAddedAttributes(UMLModelDiff umlModelDiffAll, Version currentVersion, Version parentVersion) {
private void processAddedInnerClasses(UMLModel rightModel, UMLModelDiff umlModelDiffAll, Version currentVersion, Version parentVersion, Class startClass) {
for (CodeElement key : programElementMap.keySet()) {
if (key instanceof Class && !key.equals(startClass)) {
Class startInnerClass = (Class)key;
ClassTrackerChangeHistory startInnerClassChangeHistory = (ClassTrackerChangeHistory) programElementMap.get(startInnerClass);
Class currentClass = startInnerClassChangeHistory.peek();
if (currentClass == null) {
currentClass = startInnerClassChangeHistory.getCurrent();
}
if (currentClass == null || currentClass.isAdded()) {
continue;
}
Class rightClass = getClass(rightModel, currentVersion, currentClass::equalIdentifierIgnoringVersion);
if (rightClass == null) {
continue;
}
startInnerClassChangeHistory.poll();
if (startInnerClassChangeHistory.isClassAdded(umlModelDiffAll, currentVersion, parentVersion, rightClass::equalIdentifierIgnoringVersion)) {
for (CodeElement key2 : programElementMap.keySet()) {
if (key2 instanceof Comment) {
Comment startComment = (Comment)key2;
CommentTrackerChangeHistory startCommentChangeHistory = (CommentTrackerChangeHistory) programElementMap.get(startComment);
if ((startComment.getClazz().isPresent() && startComment.getClazz().get().equals(startInnerClass.getUmlClass())) ||
(!startCommentChangeHistory.isEmpty() && startCommentChangeHistory.peek().getClazz().isPresent() && rightClass.getUmlClass().equals(startCommentChangeHistory.peek().getClazz().get()))) {
Comment currentComment = startCommentChangeHistory.poll();
Comment rightComment = rightClass.findComment(currentComment::equalIdentifierIgnoringVersion);
if (rightComment != null) {
Comment commentBefore = Comment.of(rightComment.getComment(), rightComment.getClazz().get(), parentVersion);
startCommentChangeHistory.get().handleAdd(commentBefore, rightComment, "added with inner class");
startCommentChangeHistory.add(commentBefore);
startCommentChangeHistory.get().connectRelatedNodes();
}
}
}
else if (key2 instanceof Annotation) {
Annotation startAnnotation = (Annotation)key2;
AnnotationTrackerChangeHistory startAnnotationChangeHistory = (AnnotationTrackerChangeHistory) programElementMap.get(startAnnotation);
if ((startAnnotation.getClazz().isPresent() && startAnnotation.getClazz().get().equals(startInnerClass.getUmlClass())) ||
(!startAnnotationChangeHistory.isEmpty() && startAnnotationChangeHistory.peek().getClazz().isPresent() && rightClass.getUmlClass().equals(startAnnotationChangeHistory.peek().getClazz().get()))) {
Annotation currentAnnotation = startAnnotationChangeHistory.poll();
Annotation rightAnnotation = rightClass.findAnnotation(currentAnnotation::equalIdentifierIgnoringVersion);
if (rightAnnotation != null) {
Annotation annotationBefore = Annotation.of(rightAnnotation.getAnnotation(), rightAnnotation.getClazz().get(), parentVersion);
startAnnotationChangeHistory.get().handleAdd(annotationBefore, rightAnnotation, "added with inner class");
startAnnotationChangeHistory.add(annotationBefore);
startAnnotationChangeHistory.get().connectRelatedNodes();
}
}
}
}
}
}
}
}

private void processAddedAttributes(UMLModel rightModel, UMLModelDiff umlModelDiffAll, Version currentVersion, Version parentVersion) {
for (CodeElement key : programElementMap.keySet()) {
if (key instanceof Attribute) {
Attribute startAttribute = (Attribute)key;
Expand All @@ -525,7 +581,9 @@ private void processAddedAttributes(UMLModelDiff umlModelDiffAll, Version curren
if (currentAttribute == null || currentAttribute.isAdded()) {
continue;
}
Attribute rightAttribute = currentAttribute;
Attribute rightAttribute = getAttribute(rightModel, currentVersion, currentAttribute::equalIdentifierIgnoringVersion);
if (rightAttribute == null)
rightAttribute = currentAttribute;
if (startAttributeChangeHistory.isAttributeAdded(umlModelDiffAll, rightAttribute.getUmlAttribute().getClassName(), currentVersion, parentVersion, rightAttribute::equalIdentifierIgnoringVersion, getAllClassesDiff(umlModelDiffAll))) {
for (CodeElement key2 : programElementMap.keySet()) {
if (key2 instanceof Comment) {
Expand Down Expand Up @@ -681,6 +739,9 @@ private void processLocallyRefactoredAttributes(Map<Attribute, AttributeTrackerC
leftSideAttributes.addAll(attributeContainerChanged);
leftSideAttributes.addAll(attributeRefactored);
leftSideAttributes.forEach(startAttributeChangeHistory::addFirst);
if (leftSideAttributes.size() == 1) {
startAttributeChangeHistory.setCurrent(leftSideAttributes.iterator().next());
}
for (CodeElement key2 : programElementMap.keySet()) {
if (key2 instanceof Comment) {
Comment startComment = (Comment)key2;
Expand Down Expand Up @@ -1028,6 +1089,9 @@ private void processLocallyRefactoredInnerClasses(Map<Class, ClassTrackerChangeH
if (refactored) {
Set<Class> leftSideClasses = new HashSet<>(classRefactored);
leftSideClasses.forEach(startInnerClassChangeHistory::addFirst);
if (leftSideClasses.size() == 1) {
startInnerClassChangeHistory.setCurrent(leftSideClasses.iterator().next());
}
for (CodeElement key : programElementMap.keySet()) {
if (key instanceof Comment) {
Comment startComment = (Comment)key;
Expand Down
70 changes: 67 additions & 3 deletions src/main/java/org/codetracker/FileTrackerWithLocalFilesImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,8 @@ else if (leftSuperclass == null && rightSuperclass != null) {

if (startClassChangeHistory.isClassAdded(umlModelDiffAll, currentVersion, parentVersion, rightClass::equalIdentifierIgnoringVersion)) {
processAddedMethods(umlModelPairAll.getRight(), umlModelDiffAll, currentVersion, parentVersion);
processAddedAttributes(umlModelDiffAll, currentVersion, parentVersion);
processAddedAttributes(umlModelPairAll.getRight(), umlModelDiffAll, currentVersion, parentVersion);
processAddedInnerClasses(umlModelPairAll.getRight(), umlModelDiffAll, currentVersion, parentVersion, startClass);
processAddedImportsAndClassComments(rightClass, parentVersion);
break;
}
Expand Down Expand Up @@ -520,7 +521,62 @@ else if (key instanceof Comment) {
}
}

private void processAddedAttributes(UMLModelDiff umlModelDiffAll, Version currentVersion, Version parentVersion) {
private void processAddedInnerClasses(UMLModel rightModel, UMLModelDiff umlModelDiffAll, Version currentVersion, Version parentVersion, Class startClass) {
for (CodeElement key : programElementMap.keySet()) {
if (key instanceof Class && !key.equals(startClass)) {
Class startInnerClass = (Class)key;
ClassTrackerChangeHistory startInnerClassChangeHistory = (ClassTrackerChangeHistory) programElementMap.get(startInnerClass);
Class currentClass = startInnerClassChangeHistory.peek();
if (currentClass == null) {
currentClass = startInnerClassChangeHistory.getCurrent();
}
if (currentClass == null || currentClass.isAdded()) {
continue;
}
Class rightClass = getClass(rightModel, currentVersion, currentClass::equalIdentifierIgnoringVersion);
if (rightClass == null) {
continue;
}
startInnerClassChangeHistory.poll();
if (startInnerClassChangeHistory.isClassAdded(umlModelDiffAll, currentVersion, parentVersion, rightClass::equalIdentifierIgnoringVersion)) {
for (CodeElement key2 : programElementMap.keySet()) {
if (key2 instanceof Comment) {
Comment startComment = (Comment)key2;
CommentTrackerChangeHistory startCommentChangeHistory = (CommentTrackerChangeHistory) programElementMap.get(startComment);
if ((startComment.getClazz().isPresent() && startComment.getClazz().get().equals(startInnerClass.getUmlClass())) ||
(!startCommentChangeHistory.isEmpty() && startCommentChangeHistory.peek().getClazz().isPresent() && rightClass.getUmlClass().equals(startCommentChangeHistory.peek().getClazz().get()))) {
Comment currentComment = startCommentChangeHistory.poll();
Comment rightComment = rightClass.findComment(currentComment::equalIdentifierIgnoringVersion);
if (rightComment != null) {
Comment commentBefore = Comment.of(rightComment.getComment(), rightComment.getClazz().get(), parentVersion);
startCommentChangeHistory.get().handleAdd(commentBefore, rightComment, "added with inner class");
startCommentChangeHistory.add(commentBefore);
startCommentChangeHistory.get().connectRelatedNodes();
}
}
}
else if (key2 instanceof Annotation) {
Annotation startAnnotation = (Annotation)key2;
AnnotationTrackerChangeHistory startAnnotationChangeHistory = (AnnotationTrackerChangeHistory) programElementMap.get(startAnnotation);
if ((startAnnotation.getClazz().isPresent() && startAnnotation.getClazz().get().equals(startInnerClass.getUmlClass())) ||
(!startAnnotationChangeHistory.isEmpty() && startAnnotationChangeHistory.peek().getClazz().isPresent() && rightClass.getUmlClass().equals(startAnnotationChangeHistory.peek().getClazz().get()))) {
Annotation currentAnnotation = startAnnotationChangeHistory.poll();
Annotation rightAnnotation = rightClass.findAnnotation(currentAnnotation::equalIdentifierIgnoringVersion);
if (rightAnnotation != null) {
Annotation annotationBefore = Annotation.of(rightAnnotation.getAnnotation(), rightAnnotation.getClazz().get(), parentVersion);
startAnnotationChangeHistory.get().handleAdd(annotationBefore, rightAnnotation, "added with inner class");
startAnnotationChangeHistory.add(annotationBefore);
startAnnotationChangeHistory.get().connectRelatedNodes();
}
}
}
}
}
}
}
}

private void processAddedAttributes(UMLModel rightModel, UMLModelDiff umlModelDiffAll, Version currentVersion, Version parentVersion) {
for (CodeElement key : programElementMap.keySet()) {
if (key instanceof Attribute) {
Attribute startAttribute = (Attribute)key;
Expand All @@ -532,7 +588,9 @@ private void processAddedAttributes(UMLModelDiff umlModelDiffAll, Version curren
if (currentAttribute == null || currentAttribute.isAdded()) {
continue;
}
Attribute rightAttribute = currentAttribute;
Attribute rightAttribute = getAttribute(rightModel, currentVersion, currentAttribute::equalIdentifierIgnoringVersion);
if (rightAttribute == null)
rightAttribute = currentAttribute;
if (startAttributeChangeHistory.isAttributeAdded(umlModelDiffAll, rightAttribute.getUmlAttribute().getClassName(), currentVersion, parentVersion, rightAttribute::equalIdentifierIgnoringVersion, getAllClassesDiff(umlModelDiffAll))) {
for (CodeElement key2 : programElementMap.keySet()) {
if (key2 instanceof Comment) {
Expand Down Expand Up @@ -688,6 +746,9 @@ private void processLocallyRefactoredAttributes(Map<Attribute, AttributeTrackerC
leftSideAttributes.addAll(attributeContainerChanged);
leftSideAttributes.addAll(attributeRefactored);
leftSideAttributes.forEach(startAttributeChangeHistory::addFirst);
if (leftSideAttributes.size() == 1) {
startAttributeChangeHistory.setCurrent(leftSideAttributes.iterator().next());
}
for (CodeElement key2 : programElementMap.keySet()) {
if (key2 instanceof Comment) {
Comment startComment = (Comment)key2;
Expand Down Expand Up @@ -1035,6 +1096,9 @@ private void processLocallyRefactoredInnerClasses(Map<Class, ClassTrackerChangeH
if (refactored) {
Set<Class> leftSideClasses = new HashSet<>(classRefactored);
leftSideClasses.forEach(startInnerClassChangeHistory::addFirst);
if (leftSideClasses.size() == 1) {
startInnerClassChangeHistory.setCurrent(leftSideClasses.iterator().next());
}
for (CodeElement key : programElementMap.keySet()) {
if (key instanceof Comment) {
Comment startComment = (Comment)key;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package org.codetracker.blame;

import java.io.FileInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;

import org.apache.commons.io.IOUtils;
import org.codetracker.FileTrackerWithLocalFilesImpl;
import org.codetracker.blame.util.BlameFormatter;
import org.codetracker.blame.util.TabularPrint;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.refactoringminer.astDiff.utils.URLHelper;

public class CodeTrackerBlameWithLocalFilesTest {

@ParameterizedTest
@CsvSource({
"https://github.com/checkstyle/checkstyle/commit/119fd4fb33bef9f5c66fc950396669af842c21a3, src/main/java/com/puppycrawl/tools/checkstyle/Checker.java, /src/test/resources/blame/blameTestWithLocalRepo3.txt",
"https://github.com/javaparser/javaparser/commit/97555053af3025556efe1a168fd7943dac28a2a6, javaparser-core/src/main/java/com/github/javaparser/printer/lexicalpreservation/Difference.java, /src/test/resources/blame/blameTestWithLocalRepo4.txt",
"https://github.com/javaparser/javaparser/commit/97555053af3025556efe1a168fd7943dac28a2a6, javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/MethodCallExprContext.java, /src/test/resources/blame/blameTestWithLocalRepo5.txt",
"https://github.com/spring-projects/spring-framework/commit/b325c74216fd9564a36602158fa1269e2e832874, spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodProcessor.java, /src/test/resources/blame/blameTestWithLocalRepo6.txt",
"https://github.com/eclipse/jgit/commit/bd1a82502680b5de5bf86f6c4470185fd1602386, org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java, /src/test/resources/blame/blameTestUntilCommitZero.txt",
"https://github.com/JetBrains/intellij-community/commit/ecb1bb9d4d484ae63ee77f8ad45bdce154db9356, java/compiler/impl/src/com/intellij/compiler/CompilerManagerImpl.java, /src/test/resources/blame/blameTestUntilCommitZero2.txt",
"https://github.com/JetBrains/intellij-community/commit/ecb1bb9d4d484ae63ee77f8ad45bdce154db9356, java/compiler/impl/src/com/intellij/compiler/actions/CompileDirtyAction.java, /src/test/resources/blame/blameTestUntilCommitZero3.txt"
})
public void testBlameWithLocalRepoUsingFileTracker(String url, String filePath, String testResultFileName) throws Exception {
String expectedFilePath = System.getProperty("user.dir") + testResultFileName;
String cloneURL = URLHelper.getRepo(url);
String commitId = URLHelper.getCommit(url);
FileTrackerWithLocalFilesImpl fileTracker = new FileTrackerWithLocalFilesImpl(cloneURL, commitId, filePath);
fileTracker.blame();
BlameFormatter blameFormatter = new BlameFormatter(fileTracker.getLines());
List<String[]> results = blameFormatter.make(fileTracker.getBlameInfo());
String actual = TabularPrint.make(results);
assertEqualWithFile(expectedFilePath, actual);
}

private void assertEqualWithFile(String expectedResultPath, String actual) throws IOException {
String expected = IOUtils.toString(
new FileInputStream(expectedResultPath),
StandardCharsets.UTF_8
);
Assertions.assertEquals(expected, actual);
}
}

0 comments on commit 08672ca

Please sign in to comment.