From e0e5b3cc42f85ac6c8319dd3878763e8349ac0ba Mon Sep 17 00:00:00 2001 From: tsantalis Date: Tue, 2 Jul 2024 08:08:32 -0400 Subject: [PATCH] Forgot to push blame implementation for attributes --- .../org/codetracker/AttributeTrackerImpl.java | 212 ++++++++++++++++++ 1 file changed, 212 insertions(+) diff --git a/src/main/java/org/codetracker/AttributeTrackerImpl.java b/src/main/java/org/codetracker/AttributeTrackerImpl.java index 9f12b3af911..531ccc24f9c 100644 --- a/src/main/java/org/codetracker/AttributeTrackerImpl.java +++ b/src/main/java/org/codetracker/AttributeTrackerImpl.java @@ -241,6 +241,218 @@ else if (leftInitializer != null && rightInitializer == null) { } } + public HistoryInfo blame() throws Exception { + HistoryImpl.HistoryReportImpl historyReport = new HistoryImpl.HistoryReportImpl(); + try (Git git = new Git(repository)) { + Version startVersion = gitRepository.getVersion(startCommitId); + UMLModel umlModel = getUMLModel(startCommitId, Collections.singleton(filePath)); + Attribute start = getAttribute(umlModel, startVersion, changeHistory::isStartAttribute); + if (start == null) { + throw new CodeElementNotFoundException(filePath, changeHistory.getAttributeName(), changeHistory.getAttributeDeclarationLineNumber()); + } + start.setStart(true); + changeHistory.get().addNode(start); + + ArrayDeque attributes = new ArrayDeque<>(); + attributes.addFirst(start); + Map> commitMap = new LinkedHashMap<>(); + HashSet analysedCommits = new HashSet<>(); + List commits = null; + String lastFileName = null; + while (!attributes.isEmpty()) { + History.HistoryInfo blame = blameReturn(); + if (blame != null) return blame; + Attribute currentAttribute = attributes.poll(); + if (currentAttribute.isAdded() || currentAttribute.getVersion().getId().equals("0")) { + commits = null; + continue; + } + if (commits == null || !currentAttribute.getFilePath().equals(lastFileName)) { + lastFileName = currentAttribute.getFilePath(); + commits = getCommits(repository, currentAttribute.getVersion().getId(), lastFileName, git); + if (commitMap.containsKey(currentAttribute.getVersion().getId()) && commitMap.get(currentAttribute.getVersion().getId()).equals(commits)) { + break; + } + commitMap.put(currentAttribute.getVersion().getId(), commits); + historyReport.gitLogCommandCallsPlusPlus(); + analysedCommits.clear(); + } + if (commits == null || analysedCommits.containsAll(commits)) + break; + for (String commitId : commits) { + if (analysedCommits.contains(commitId)) + continue; + //System.out.println("processing " + commitId); + analysedCommits.add(commitId); + + Version currentVersion = gitRepository.getVersion(commitId); + String parentCommitId = gitRepository.getParentId(commitId); + Version parentVersion = gitRepository.getVersion(parentCommitId); + + + UMLModel rightModel = getUMLModel(commitId, Collections.singleton(currentAttribute.getFilePath())); + Attribute rightAttribute = getAttribute(rightModel, currentVersion, currentAttribute::equalIdentifierIgnoringVersion); + if (rightAttribute == null) { + continue; + } + historyReport.analysedCommitsPlusPlus(); + if ("0".equals(parentCommitId)) { + Attribute leftAttribute = Attribute.of(rightAttribute.getUmlAttribute(), parentVersion); + changeHistory.get().handleAdd(leftAttribute, rightAttribute, "Initial commit!"); + changeHistory.get().connectRelatedNodes(); + attributes.add(leftAttribute); + break; + } + UMLModel leftModel = getUMLModel(parentCommitId, Collections.singleton(rightAttribute.getFilePath())); + + //NO CHANGE + Attribute leftAttribute = getAttribute(leftModel, parentVersion, rightAttribute::equalIdentifierIgnoringVersion); + if (leftAttribute != null) { + historyReport.step2PlusPlus(); + //check if initializer changed + AbstractExpression leftInitializer = leftAttribute.getUmlAttribute().getVariableDeclaration().getInitializer(); + AbstractExpression rightInitializer = rightAttribute.getUmlAttribute().getVariableDeclaration().getInitializer(); + if (leftInitializer != null && rightInitializer != null) { + if (!leftInitializer.getString().equals(rightInitializer.getString())) { + changeHistory.get().addChange(leftAttribute, rightAttribute, ChangeFactory.forAttribute(Type.INITIALIZER_CHANGE)); + attributes.add(leftAttribute); + } + } + else if (leftInitializer == null && rightInitializer != null) { + changeHistory.get().addChange(leftAttribute, rightAttribute, ChangeFactory.forAttribute(Type.INITIALIZER_ADDED)); + attributes.add(leftAttribute); + } + else if (leftInitializer != null && rightInitializer == null) { + changeHistory.get().addChange(leftAttribute, rightAttribute, ChangeFactory.forAttribute(Type.INITIALIZER_REMOVED)); + attributes.add(leftAttribute); + } + continue; + } + + String extractedClassFilePath = null; + //Local Refactoring + UMLModelDiff umlModelDiffLocal = leftModel.diff(rightModel); + { + List refactorings = umlModelDiffLocal.getRefactorings(); + Set attributeContainerChanged = changeHistory.isAttributeContainerChanged(umlModelDiffLocal, refactorings, currentVersion, parentVersion, rightAttribute::equalIdentifierIgnoringVersion, getClassMoveDiffList(umlModelDiffLocal)); + boolean containerChanged = !attributeContainerChanged.isEmpty(); + + String renamedAttributeClassType = null; + for (Refactoring r : refactorings) { + if (r.getRefactoringType().equals(RefactoringType.RENAME_ATTRIBUTE)) { + RenameAttributeRefactoring renameAttributeRefactoring = (RenameAttributeRefactoring)r; + if (renameAttributeRefactoring.getRenamedAttribute().getType() != null) { + renamedAttributeClassType = renameAttributeRefactoring.getRenamedAttribute().getType().getClassType(); + } + if (renamedAttributeClassType != null) { + CommitModel commitModel = getCommitModel(currentVersion.getId()); + for (String filePath : commitModel.fileContentsCurrentOriginal.keySet()) { + if (filePath.endsWith(renamedAttributeClassType + ".java") && !commitModel.fileContentsBeforeOriginal.keySet().contains(filePath)) { + extractedClassFilePath = filePath; + break; + } + } + } + } + } + Set attributeRefactored = null; + if (extractedClassFilePath == null) + attributeRefactored = changeHistory.analyseAttributeRefactorings(refactorings, currentVersion, parentVersion, rightAttribute::equalIdentifierIgnoringVersion); + else + attributeRefactored = Collections.emptySet(); + boolean refactored = !attributeRefactored.isEmpty(); + + if (containerChanged || refactored) { + Set leftSideAttributes = new HashSet<>(); + leftSideAttributes.addAll(attributeContainerChanged); + leftSideAttributes.addAll(attributeRefactored); + leftSideAttributes.forEach(attributes::addFirst); + historyReport.step4PlusPlus(); + break; + } + } + //All refactorings + { + CommitModel commitModel = getCommitModel(commitId); + if (!commitModel.moveSourceFolderRefactorings.isEmpty()) { + Pair umlModelPairPartial = getUMLModelPair(commitModel, currentAttribute.getFilePath(), s -> true, true); + UMLModelDiff umlModelDiffPartial = umlModelPairPartial.getLeft().diff(umlModelPairPartial.getRight()); + List refactoringsPartial = umlModelDiffPartial.getRefactorings(); + Set attributeContainerChanged = changeHistory.isAttributeContainerChanged(umlModelDiffPartial, refactoringsPartial, currentVersion, parentVersion, rightAttribute::equalIdentifierIgnoringVersion, getClassMoveDiffList(umlModelDiffPartial)); + boolean containerChanged = !attributeContainerChanged.isEmpty(); + + Set attributeRefactored = changeHistory.analyseAttributeRefactorings(refactoringsPartial, currentVersion, parentVersion, rightAttribute::equalIdentifierIgnoringVersion); + boolean refactored = !attributeRefactored.isEmpty(); + + if (containerChanged || refactored) { + Set leftSideAttributes = new HashSet<>(); + leftSideAttributes.addAll(attributeContainerChanged); + leftSideAttributes.addAll(attributeRefactored); + leftSideAttributes.forEach(attributes::addFirst); + historyReport.step5PlusPlus(); + break; + } + } + { + Set fileNames = getRightSideFileNames(currentAttribute.getFilePath(), currentAttribute.getUmlAttribute().getClassName(), Collections.emptySet(), commitModel, umlModelDiffLocal); + if (extractedClassFilePath != null) { + fileNames.add(extractedClassFilePath); + } + Pair umlModelPairAll = getUMLModelPair(commitModel, currentAttribute.getFilePath(), fileNames::contains, false); + UMLModelDiff umlModelDiffAll = umlModelPairAll.getLeft().diff(umlModelPairAll.getRight()); + + List refactorings = umlModelDiffAll.getRefactorings(); + + int moveAttributeRefactorings = 0; + 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()); + moveAttributeRefactorings++; + } + } + } + if (moveAttributeRefactorings == 1) { + umlModelPairAll = getUMLModelPair(commitModel, currentAttribute.getFilePath(), fileNames::contains, false); + umlModelDiffAll = umlModelPairAll.getLeft().diff(umlModelPairAll.getRight()); + refactorings = umlModelDiffAll.getRefactorings(); + } + + Set attributeContainerChanged = changeHistory.isAttributeContainerChanged(umlModelDiffAll, refactorings, currentVersion, parentVersion, rightAttribute::equalIdentifierIgnoringVersion, getClassMoveDiffList(umlModelDiffAll)); + boolean containerChanged = !attributeContainerChanged.isEmpty(); + + Set attributeRefactored; + if (moveAttributeRefactorings <= 1) { + attributeRefactored = changeHistory.analyseAttributeRefactorings(refactorings, currentVersion, parentVersion, rightAttribute::equalIdentifierIgnoringVersion); + } + else { + attributeRefactored = Collections.emptySet(); + } + boolean refactored = !attributeRefactored.isEmpty(); + + if (containerChanged || refactored) { + Set leftAttributes = new HashSet<>(); + leftAttributes.addAll(attributeContainerChanged); + leftAttributes.addAll(attributeRefactored); + leftAttributes.forEach(attributes::addFirst); + historyReport.step5PlusPlus(); + break; + } + + if (changeHistory.isAttributeAdded(umlModelDiffAll, attributes, rightAttribute.getUmlAttribute().getClassName(), currentVersion, parentVersion, rightAttribute::equalIdentifierIgnoringVersion, getAllClassesDiff(umlModelDiffAll))) { + historyReport.step5PlusPlus(); + break; + } + } + } + } + } + } + return null; + } + private History.HistoryInfo blameReturn() { List> history = HistoryImpl.processHistory(changeHistory.get().getCompleteGraph()); Collections.reverse(history);