]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-12802 SONAR-12927 Fix moved file detection for cobol and when calculating new...
authorDuarte Meneses <duarte.meneses@sonarsource.com>
Wed, 29 Jan 2020 16:06:07 +0000 (10:06 -0600)
committerSonarTech <sonartech@sonarsource.com>
Fri, 7 Feb 2020 19:46:16 +0000 (20:46 +0100)
24 files changed:
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/filemove/FileMoveDetectionStep.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/filemove/FileSimilarity.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/filemove/MovedFilesRepository.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/filemove/MutableMovedFilesRepositoryImpl.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/ClosedIssuesInputFactory.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/MovedIssueVisitor.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/RemoveProcessedComponentsVisitor.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/TrackerBaseInputFactory.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/scm/ScmInfoDbLoader.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/source/DbLineHashVersion.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/source/PersistFileSourcesStep.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/source/SourceLinesDiffImpl.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/source/SourceLinesHashRepositoryImpl.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/filemove/MutableMovedFilesRepositoryImplTest.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/filemove/MutableMovedFilesRepositoryRule.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/ClosedIssuesInputFactoryTest.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/IntegrateIssuesVisitorTest.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/MovedIssueVisitorTest.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/RemoveProcessedComponentsVisitorTest.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/TrackerBaseInputFactoryTest.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/scm/ScmInfoDbLoaderTest.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/source/SourceLinesDiffImplTest.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/source/SourceLinesHashRepositoryImplTest.java
server/sonar-db-dao/src/main/java/org/sonar/db/source/FileSourceDao.java

index 8d415c46f1d12c16cc475118f4e12f519811d27f..4f28c15ddbe8eb0f127b400ef0a17e938dbc99e1 100644 (file)
@@ -26,6 +26,7 @@ import com.google.common.collect.Multimap;
 import com.google.common.collect.Sets;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -33,6 +34,7 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.stream.Collectors;
 import javax.annotation.Nullable;
 import javax.annotation.concurrent.Immutable;
 import org.apache.ibatis.session.ResultContext;
@@ -57,7 +59,6 @@ import org.sonar.db.DbSession;
 import org.sonar.db.component.FileMoveRowDto;
 import org.sonar.db.source.LineHashesWithUuidDto;
 
-import static com.google.common.collect.FluentIterable.from;
 import static org.sonar.ce.task.projectanalysis.component.ComponentVisitor.Order.POST_ORDER;
 
 public class FileMoveDetectionStep implements ComputationStep {
@@ -125,7 +126,7 @@ public class FileMoveDetectionStep implements ComputationStep {
 
     Set<String> removedFileUuids = difference(dbFilesByUuid.keySet(), reportFilesByUuid.keySet());
 
-    // can find matches if at least one of the added or removed files groups is empty => abort
+    // can't find matches if at least one of the added or removed files groups is empty => abort
     if (addedFileUuids.isEmpty() || removedFileUuids.isEmpty()) {
       registerAddedFiles(addedFileUuids, reportFilesByUuid, null);
       LOG.debug("Either no files added or no files removed. Do nothing.");
@@ -133,12 +134,12 @@ public class FileMoveDetectionStep implements ComputationStep {
     }
 
     // retrieve file data from report
-    Map<String, File> reportFileSourcesByUuid = getReportFileSourcesByUuid(reportFilesByUuid, addedFileUuids);
+    Map<String, File> addedFileHashesByUuid = getReportFileHashesByUuid(reportFilesByUuid, addedFileUuids);
     p.stopTrace("loaded");
 
     // compute score matrix
     p.start();
-    ScoreMatrix scoreMatrix = computeScoreMatrix(dbFilesByUuid, removedFileUuids, reportFileSourcesByUuid);
+    ScoreMatrix scoreMatrix = computeScoreMatrix(dbFilesByUuid, removedFileUuids, addedFileHashesByUuid);
     p.stopTrace("Score matrix computed");
     scoreMatrixDumper.dumpAsCsv(scoreMatrix);
 
@@ -153,7 +154,7 @@ public class FileMoveDetectionStep implements ComputationStep {
     p.start();
     MatchesByScore matchesByScore = MatchesByScore.create(scoreMatrix);
 
-    ElectedMatches electedMatches = electMatches(removedFileUuids, reportFileSourcesByUuid, matchesByScore);
+    ElectedMatches electedMatches = electMatches(removedFileUuids, addedFileHashesByUuid, matchesByScore);
     p.stopTrace("Matches elected");
 
     context.getStatistics().add("movedFiles", electedMatches.size());
@@ -219,25 +220,21 @@ public class FileMoveDetectionStep implements ComputationStep {
     return builder.build();
   }
 
-  private Map<String, File> getReportFileSourcesByUuid(Map<String, Component> reportFilesByUuid, Set<String> addedFileUuids) {
-    ImmutableMap.Builder<String, File> builder = ImmutableMap.builder();
-    for (String fileUuid : addedFileUuids) {
+  private Map<String, File> getReportFileHashesByUuid(Map<String, Component> reportFilesByUuid, Set<String> addedFileUuids) {
+    return addedFileUuids.stream().collect(Collectors.toMap(fileUuid -> fileUuid, fileUuid -> {
       Component component = reportFilesByUuid.get(fileUuid);
-      File file = new LazyFileImpl(
-        component.getName(),
-        () -> getReportFileLineHashes(component),
-        component.getFileAttributes().getLines());
-      builder.put(fileUuid, file);
-    }
-    return builder.build();
+      return new LazyFileImpl(() -> getReportFileLineHashes(component), component.getFileAttributes().getLines());
+    }));
   }
 
   private List<String> getReportFileLineHashes(Component component) {
+    // this is not ideal because if the file moved, this component won't exist in DB with the same UUID.
+    // Assuming that the file also had significant code before the move, it will be fine.
     return sourceLinesHash.getLineHashesMatchingDBVersion(component);
   }
 
-  private ScoreMatrix computeScoreMatrix(Map<String, DbComponent> dtosByUuid, Set<String> removedFileUuids, Map<String, File> newFileSourcesByUuid) {
-    ScoreMatrix.ScoreFile[] newFiles = newFileSourcesByUuid.entrySet().stream()
+  private ScoreMatrix computeScoreMatrix(Map<String, DbComponent> dtosByUuid, Set<String> removedFileUuids, Map<String, File> addedFileHashesByUuid) {
+    ScoreMatrix.ScoreFile[] addedFiles = addedFileHashesByUuid.entrySet().stream()
       .map(e -> new ScoreMatrix.ScoreFile(e.getKey(), e.getValue().getLineCount()))
       .toArray(ScoreMatrix.ScoreFile[]::new);
     ScoreMatrix.ScoreFile[] removedFiles = removedFileUuids.stream()
@@ -246,48 +243,50 @@ public class FileMoveDetectionStep implements ComputationStep {
         return new ScoreMatrix.ScoreFile(dbComponent.getUuid(), dbComponent.getLineCount());
       })
       .toArray(ScoreMatrix.ScoreFile[]::new);
+
     // sort by highest line count first
-    Arrays.sort(newFiles, SCORE_FILE_COMPARATOR);
+    Arrays.sort(addedFiles, SCORE_FILE_COMPARATOR);
     Arrays.sort(removedFiles, SCORE_FILE_COMPARATOR);
-    int[][] scoreMatrix = new int[removedFiles.length][newFiles.length];
-    int lastNewFileIndex = newFiles.length - 1;
+    int[][] scoreMatrix = new int[removedFiles.length][addedFiles.length];
+    int smallestAddedFileSize = addedFiles[0].getLineCount();
+    int largestAddedFileSize = addedFiles[addedFiles.length - 1].getLineCount();
 
-    Map<String, Integer> removedFilesIndexes = new HashMap<>(removedFileUuids.size());
+    Map<String, Integer> removedFilesIndexesByUuid = new HashMap<>(removedFileUuids.size());
     for (int removeFileIndex = 0; removeFileIndex < removedFiles.length; removeFileIndex++) {
       ScoreMatrix.ScoreFile removedFile = removedFiles[removeFileIndex];
       int lowerBound = (int) Math.floor(removedFile.getLineCount() * LOWER_BOUND_RATIO);
       int upperBound = (int) Math.ceil(removedFile.getLineCount() * UPPER_BOUND_RATIO);
       // no need to compute score if all files are out of bound, so no need to load line hashes from DB
-      if (newFiles[0].getLineCount() <= lowerBound || newFiles[lastNewFileIndex].getLineCount() >= upperBound) {
+      if (smallestAddedFileSize <= lowerBound || largestAddedFileSize >= upperBound) {
         continue;
       }
-      removedFilesIndexes.put(removedFile.getFileUuid(), removeFileIndex);
+      removedFilesIndexesByUuid.put(removedFile.getFileUuid(), removeFileIndex);
     }
 
-    LineHashesWithKeyDtoResultHandler rowHandler = new LineHashesWithKeyDtoResultHandler(removedFilesIndexes, removedFiles,
-      newFiles, newFileSourcesByUuid, scoreMatrix);
+    LineHashesWithKeyDtoResultHandler rowHandler = new LineHashesWithKeyDtoResultHandler(removedFilesIndexesByUuid, removedFiles,
+      addedFiles, addedFileHashesByUuid, scoreMatrix);
     try (DbSession dbSession = dbClient.openSession(false)) {
-      dbClient.fileSourceDao().scrollLineHashes(dbSession, removedFilesIndexes.keySet(), rowHandler);
+      dbClient.fileSourceDao().scrollLineHashes(dbSession, removedFilesIndexesByUuid.keySet(), rowHandler);
     }
 
-    return new ScoreMatrix(removedFiles, newFiles, scoreMatrix, rowHandler.getMaxScore());
+    return new ScoreMatrix(removedFiles, addedFiles, scoreMatrix, rowHandler.getMaxScore());
   }
 
   private final class LineHashesWithKeyDtoResultHandler implements ResultHandler<LineHashesWithUuidDto> {
-    private final Map<String, Integer> removedFilesIndexes;
+    private final Map<String, Integer> removedFileIndexesByUuid;
     private final ScoreMatrix.ScoreFile[] removedFiles;
     private final ScoreMatrix.ScoreFile[] newFiles;
-    private final Map<String, File> newFileSourcesByKey;
+    private final Map<String, File> newFilesByUuid;
     private final int[][] scoreMatrix;
     private int maxScore;
 
-    private LineHashesWithKeyDtoResultHandler(Map<String, Integer> removedFilesIndexes, ScoreMatrix.ScoreFile[] removedFiles,
-      ScoreMatrix.ScoreFile[] newFiles, Map<String, File> newFileSourcesByKey,
+    private LineHashesWithKeyDtoResultHandler(Map<String, Integer> removedFileIndexesByUuid, ScoreMatrix.ScoreFile[] removedFiles,
+      ScoreMatrix.ScoreFile[] newFiles, Map<String, File> newFilesByUuid,
       int[][] scoreMatrix) {
-      this.removedFilesIndexes = removedFilesIndexes;
+      this.removedFileIndexesByUuid = removedFileIndexesByUuid;
       this.removedFiles = removedFiles;
       this.newFiles = newFiles;
-      this.newFileSourcesByKey = newFileSourcesByKey;
+      this.newFilesByUuid = newFilesByUuid;
       this.scoreMatrix = scoreMatrix;
     }
 
@@ -297,8 +296,8 @@ public class FileMoveDetectionStep implements ComputationStep {
       if (lineHashesDto.getPath() == null) {
         return;
       }
-      int removeFileIndex = removedFilesIndexes.get(lineHashesDto.getUuid());
-      ScoreMatrix.ScoreFile removedFile = removedFiles[removeFileIndex];
+      int removedFileIndex = removedFileIndexesByUuid.get(lineHashesDto.getUuid());
+      ScoreMatrix.ScoreFile removedFile = removedFiles[removedFileIndex];
       int lowerBound = (int) Math.floor(removedFile.getLineCount() * LOWER_BOUND_RATIO);
       int upperBound = (int) Math.ceil(removedFile.getLineCount() * UPPER_BOUND_RATIO);
 
@@ -311,10 +310,10 @@ public class FileMoveDetectionStep implements ComputationStep {
           break;
         }
 
-        File fileInDb = new FileImpl(lineHashesDto.getPath(), lineHashesDto.getLineHashes());
-        File unmatchedFile = newFileSourcesByKey.get(newFile.getFileUuid());
-        int score = fileSimilarity.score(fileInDb, unmatchedFile);
-        scoreMatrix[removeFileIndex][newFileIndex] = score;
+        File fileHashesInDb = new FileImpl(lineHashesDto.getLineHashes());
+        File unmatchedFile = newFilesByUuid.get(newFile.getFileUuid());
+        int score = fileSimilarity.score(fileHashesInDb, unmatchedFile);
+        scoreMatrix[removedFileIndex][newFileIndex] = score;
         if (score > maxScore) {
           maxScore = score;
         }
@@ -408,9 +407,9 @@ public class FileMoveDetectionStep implements ComputationStep {
     private final List<Match> matches;
     private final Set<String> matchedFileUuids;
 
-    public ElectedMatches(MatchesByScore matchesByScore, Set<String> dbFileUuids, Map<String, File> reportFileSourcesByUuid) {
+    public ElectedMatches(MatchesByScore matchesByScore, Set<String> dbFileUuids, Map<String, File> reportFileHashesByUuid) {
       this.matches = new ArrayList<>(matchesByScore.getSize());
-      this.matchedFileUuids = new HashSet<>(dbFileUuids.size() + reportFileSourcesByUuid.size());
+      this.matchedFileUuids = new HashSet<>(dbFileUuids.size() + reportFileHashesByUuid.size());
     }
 
     public void add(Match match) {
@@ -419,8 +418,8 @@ public class FileMoveDetectionStep implements ComputationStep {
       matchedFileUuids.add(match.getReportUuid());
     }
 
-    public List<Match> filter(Iterable<Match> matches) {
-      return from(matches).filter(this::notAlreadyMatched).toList();
+    public List<Match> filter(Collection<Match> matches) {
+      return matches.stream().filter(this::notAlreadyMatched).collect(Collectors.toList());
     }
 
     private boolean notAlreadyMatched(Match input) {
index 9a456cf6c76ab0a0ca4a883f597d7e7555ff53ab..18f13da8dd130c0129247f013e80881794e2b0ac 100644 (file)
@@ -29,28 +29,20 @@ import static java.util.Objects.requireNonNull;
 public interface FileSimilarity {
 
   interface File {
-    String getPath();
-
     List<String> getLineHashes();
 
     int getLineCount();
   }
 
   final class FileImpl implements File {
-    private final String path;
     private final List<String> lineHashes;
     private final int lineCount;
 
-    FileImpl(String path, List<String> lineHashes) {
-      this.path = requireNonNull(path, "path can not be null");
+    FileImpl(List<String> lineHashes) {
       this.lineHashes = requireNonNull(lineHashes, "lineHashes can not be null");
       this.lineCount = lineHashes.size();
     }
 
-    public String getPath() {
-      return path;
-    }
-
     /**
      * List of hash of each line. An empty list is returned
      * if file content is empty.
@@ -65,21 +57,15 @@ public interface FileSimilarity {
   }
 
   final class LazyFileImpl implements File {
-    private final String path;
     private final Supplier<List<String>> supplier;
     private final int lineCount;
     private List<String> lineHashes;
 
-    LazyFileImpl(String path, Supplier<List<String>> supplier, int lineCount) {
-      this.path = requireNonNull(path, "path can not be null");
+    LazyFileImpl(Supplier<List<String>> supplier, int lineCount) {
       this.supplier = requireNonNull(supplier, "supplier can not be null");
       this.lineCount = lineCount;
     }
 
-    public String getPath() {
-      return path;
-    }
-
     /**
      * List of hash of each line. An empty list is returned
      * if file content is empty.
index f84e2fdf29a585fcbd5cc3d797b015e29e684a4c..ddd90a7467b05c5b9bec52d2b556902c63cc5180 100644 (file)
@@ -19,7 +19,7 @@
  */
 package org.sonar.ce.task.projectanalysis.filemove;
 
-import com.google.common.base.Optional;
+import java.util.Optional;
 import javax.annotation.Nullable;
 import org.sonar.ce.task.projectanalysis.component.Component;
 
@@ -29,7 +29,7 @@ public interface MovedFilesRepository {
   /**
    * The original file for the specified component if it was registered as a moved file in the repository.
    * <p>
-   * Calling this method with a Component which is not a file, will always return {@link Optional#absent()}.
+   * Calling this method with a Component which is not a file, will always return {@link Optional#empty()}.
    * </p>
    */
   Optional<OriginalFile> getOriginalFile(Component file);
index 3d73cbe62918e2d8d29afeaa5d559268be24e35e..87355c167edcbfe47f1906552bbe23c6647258c2 100644 (file)
@@ -19,9 +19,9 @@
  */
 package org.sonar.ce.task.projectanalysis.filemove;
 
-import com.google.common.base.Optional;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Optional;
 import org.sonar.ce.task.projectanalysis.component.Component;
 
 import static com.google.common.base.Preconditions.checkArgument;
@@ -49,9 +49,9 @@ public class MutableMovedFilesRepositoryImpl implements MutableMovedFilesReposit
   public Optional<OriginalFile> getOriginalFile(Component file) {
     requireNonNull(file, "file can't be null");
     if (file.getType() != Component.Type.FILE) {
-      return Optional.absent();
+      return Optional.empty();
     }
 
-    return Optional.fromNullable(originalFiles.get(file.getDbKey()));
+    return Optional.ofNullable(originalFiles.get(file.getDbKey()));
   }
 }
index 36e220e7b02060d04a727053a81ae4f4811b8cae..461076a07fb2018f48cf75778f0ce0770c69cddb 100644 (file)
@@ -39,7 +39,7 @@ public class ClosedIssuesInputFactory extends BaseInputFactory {
   }
 
   public Input<DefaultIssue> create(Component component) {
-    return new ClosedIssuesLazyInput(dbClient, component, movedFilesRepository.getOriginalFile(component).orNull());
+    return new ClosedIssuesLazyInput(dbClient, component, movedFilesRepository.getOriginalFile(component).orElse(null));
   }
 
   private class ClosedIssuesLazyInput extends BaseLazyInput {
index 6ce17bf07e89f4eb4d3af80e938e05e550f00dba..d578bff92fdbad07279a83fc6103475ededcaf90 100644 (file)
@@ -19,8 +19,8 @@
  */
 package org.sonar.ce.task.projectanalysis.issue;
 
-import com.google.common.base.Optional;
 import java.util.Date;
+import java.util.Optional;
 import org.sonar.ce.task.projectanalysis.component.Component;
 import org.sonar.core.issue.DefaultIssue;
 import org.sonar.core.issue.IssueChangeContext;
index bd79bb5585b896042c06dd90d7137d6057d16c00..47e89e4b7eafef678eb435ad6bb81f68e7971e26 100644 (file)
@@ -19,7 +19,7 @@
  */
 package org.sonar.ce.task.projectanalysis.issue;
 
-import com.google.common.base.Optional;
+import java.util.Optional;
 import org.sonar.ce.task.projectanalysis.component.Component;
 import org.sonar.ce.task.projectanalysis.filemove.MovedFilesRepository;
 
index 7ed6561857ad5f1e84be0744ec25c237e933a599..56a185eb3a8f38563226736e27760b9170681e0d 100644 (file)
@@ -63,7 +63,7 @@ public class TrackerBaseInputFactory extends BaseInputFactory {
       // Folders have no issues
       return new EmptyTrackerBaseLazyInput(dbClient, component);
     }
-    return new FileTrackerBaseLazyInput(dbClient, component, movedFilesRepository.getOriginalFile(component).orNull());
+    return new FileTrackerBaseLazyInput(dbClient, component, movedFilesRepository.getOriginalFile(component).orElse(null));
   }
 
   private class FileTrackerBaseLazyInput extends BaseLazyInput {
index 260940d4bcec4f2a4315f6c13373dc836de9e68e..40c626be956b2a764bd64f0fec2b7d687fd47679 100644 (file)
@@ -26,6 +26,7 @@ import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder;
 import org.sonar.ce.task.projectanalysis.analysis.Branch;
 import org.sonar.ce.task.projectanalysis.component.Component;
 import org.sonar.ce.task.projectanalysis.component.ReferenceBranchComponentUuids;
+import org.sonar.ce.task.projectanalysis.filemove.MovedFilesRepository;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.source.FileSourceDto;
@@ -34,11 +35,14 @@ public class ScmInfoDbLoader {
   private static final Logger LOGGER = Loggers.get(ScmInfoDbLoader.class);
 
   private final AnalysisMetadataHolder analysisMetadataHolder;
+  private final MovedFilesRepository movedFilesRepository;
   private final DbClient dbClient;
   private final ReferenceBranchComponentUuids referenceBranchComponentUuid;
 
-  public ScmInfoDbLoader(AnalysisMetadataHolder analysisMetadataHolder, DbClient dbClient, ReferenceBranchComponentUuids referenceBranchComponentUuid) {
+  public ScmInfoDbLoader(AnalysisMetadataHolder analysisMetadataHolder, MovedFilesRepository movedFilesRepository, DbClient dbClient,
+    ReferenceBranchComponentUuids referenceBranchComponentUuid) {
     this.analysisMetadataHolder = analysisMetadataHolder;
+    this.movedFilesRepository = movedFilesRepository;
     this.dbClient = dbClient;
     this.referenceBranchComponentUuid = referenceBranchComponentUuid;
   }
@@ -61,6 +65,10 @@ public class ScmInfoDbLoader {
 
   private Optional<String> getFileUUid(Component file) {
     if (!analysisMetadataHolder.isFirstAnalysis() && !analysisMetadataHolder.isPullRequest()) {
+      Optional<MovedFilesRepository.OriginalFile> originalFile = movedFilesRepository.getOriginalFile(file);
+      if (originalFile.isPresent()) {
+        return originalFile.map(MovedFilesRepository.OriginalFile::getUuid);
+      }
       return Optional.of(file.getUuid());
     }
 
index d2771166a2b9a0187bbeb6b7e375654dedb55b65..b03996d1acfc49567f6c6a819047882bff01c2af 100644 (file)
@@ -42,7 +42,7 @@ public class DbLineHashVersion {
   }
 
   /**
-   * Reads from DB the version of line hashes for a component and returns if it was generated taking into account the ranges of significant code.
+   * Reads from DB the version of line hashes for a component and returns whether it was generated taking into account the ranges of significant code.
    * The response is cached.
    * Returns false if the component is not in the DB.
    */
@@ -50,6 +50,15 @@ public class DbLineHashVersion {
     return lineHashVersionPerComponent.computeIfAbsent(component, this::compute) == LineHashVersion.WITH_SIGNIFICANT_CODE;
   }
 
+  /**
+   * Reads from DB the version of line hashes for a component and returns whether it was generated taking into account the ranges of significant code.
+   * The response is cached.
+   * Returns false if the component is not in the DB.
+   */
+  public boolean hasLineHashesWithoutSignificantCode(Component component) {
+    return lineHashVersionPerComponent.computeIfAbsent(component, this::compute) == LineHashVersion.WITHOUT_SIGNIFICANT_CODE;
+  }
+
   @CheckForNull
   private LineHashVersion compute(Component component) {
     try (DbSession session = dbClient.openSession(false)) {
index c8040f53bc30d6660510c908abc54449d219b415..6c92a9deae4471f413de5309be99b1f258d9e6bc 100644 (file)
@@ -113,7 +113,6 @@ public class PersistFileSourcesStep implements ComputationStep {
       Changeset latestChangeWithRevision = fileSourceData.getLatestChangeWithRevision();
       int lineHashesVersion = sourceLinesHash.getLineHashesVersion(file);
       FileSourceDto previousDto = previousFileSourcesByUuid.get(file.getUuid());
-
       if (previousDto == null) {
         FileSourceDto dto = new FileSourceDto()
           .setProjectUuid(projectUuid)
index 4fecf2e152d1c73b4cceacea3cfb04cfa652a3e1..edf49bc6b69d16099b823b4eb6b5a2b0b25025eb 100644 (file)
@@ -21,9 +21,11 @@ package org.sonar.ce.task.projectanalysis.source;
 
 import java.util.Collections;
 import java.util.List;
+import java.util.Optional;
 import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder;
 import org.sonar.ce.task.projectanalysis.component.Component;
 import org.sonar.ce.task.projectanalysis.component.ReferenceBranchComponentUuids;
+import org.sonar.ce.task.projectanalysis.filemove.MovedFilesRepository;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.source.FileSourceDao;
@@ -34,14 +36,16 @@ public class SourceLinesDiffImpl implements SourceLinesDiff {
   private final FileSourceDao fileSourceDao;
   private final SourceLinesHashRepository sourceLinesHash;
   private final ReferenceBranchComponentUuids referenceBranchComponentUuids;
+  private final MovedFilesRepository movedFilesRepository;
   private final AnalysisMetadataHolder analysisMetadataHolder;
 
   public SourceLinesDiffImpl(DbClient dbClient, FileSourceDao fileSourceDao, SourceLinesHashRepository sourceLinesHash,
-    ReferenceBranchComponentUuids referenceBranchComponentUuids, AnalysisMetadataHolder analysisMetadataHolder) {
+    ReferenceBranchComponentUuids referenceBranchComponentUuids, MovedFilesRepository movedFilesRepository, AnalysisMetadataHolder analysisMetadataHolder) {
     this.dbClient = dbClient;
     this.fileSourceDao = fileSourceDao;
     this.sourceLinesHash = sourceLinesHash;
     this.referenceBranchComponentUuids = referenceBranchComponentUuids;
+    this.movedFilesRepository = movedFilesRepository;
     this.analysisMetadataHolder = analysisMetadataHolder;
   }
 
@@ -59,7 +63,8 @@ public class SourceLinesDiffImpl implements SourceLinesDiff {
       if (analysisMetadataHolder.isPullRequest()) {
         uuid = referenceBranchComponentUuids.getComponentUuid(component.getDbKey());
       } else {
-        uuid = component.getUuid();
+        Optional<MovedFilesRepository.OriginalFile> originalFile = movedFilesRepository.getOriginalFile(component);
+        uuid = originalFile.map(MovedFilesRepository.OriginalFile::getUuid).orElse(component.getUuid());
       }
 
       if (uuid == null) {
index dbb4e649d1a24f2ec7c024a0ea1627e68bd50aca..6de8247c44f60d8735d1a5041320370f58d739d9 100644 (file)
@@ -61,7 +61,7 @@ public class SourceLinesHashRepositoryImpl implements SourceLinesHashRepository
     boolean cacheHit = cache.contains(component);
 
     // check if line hashes are cached and if we can use it
-    if (cacheHit && dbLineHashesVersion.hasLineHashesWithSignificantCode(component)) {
+    if (cacheHit && !dbLineHashesVersion.hasLineHashesWithoutSignificantCode(component)) {
       return new CachedLineHashesComputer(cache.get(component));
     }
 
@@ -75,10 +75,11 @@ public class SourceLinesHashRepositoryImpl implements SourceLinesHashRepository
   }
 
   private List<String> createLineHashesMatchingDBVersion(Component component) {
-    if (!dbLineHashesVersion.hasLineHashesWithSignificantCode(component)) {
+    if (dbLineHashesVersion.hasLineHashesWithoutSignificantCode(component)) {
       return createLineHashes(component, Optional.empty());
     }
 
+    // if the file is not in the DB, this will be used too
     Optional<LineRange[]> significantCodePerLine = significantCodeRepository.getRangesPerLine(component);
     return createLineHashes(component, significantCodePerLine);
   }
index 138267d47076b537fbfe20a7819d9f33188832ce..e7ebf5151aa6510aab872a162fa403924def9378 100644 (file)
@@ -28,7 +28,6 @@ import org.sonar.ce.task.projectanalysis.component.ViewsComponent;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.fail;
-import static org.assertj.guava.api.Assertions.assertThat;
 import static org.sonar.ce.task.projectanalysis.component.ReportComponent.builder;
 
 public class MutableMovedFilesRepositoryImplTest {
@@ -113,9 +112,9 @@ public class MutableMovedFilesRepositoryImplTest {
 
   @Test
   public void getOriginalFile_returns_absent_for_any_component_type_when_empty() {
-    assertThat(underTest.getOriginalFile(SOME_FILE)).isAbsent();
+    assertThat(underTest.getOriginalFile(SOME_FILE)).isEmpty();
     for (Component component : COMPONENTS_EXCEPT_FILE) {
-      assertThat(underTest.getOriginalFile(component)).isAbsent();
+      assertThat(underTest.getOriginalFile(component)).isEmpty();
     }
   }
 
@@ -124,7 +123,7 @@ public class MutableMovedFilesRepositoryImplTest {
     underTest.setOriginalFile(SOME_FILE, SOME_ORIGINAL_FILE);
 
     for (Component component : COMPONENTS_EXCEPT_FILE) {
-      assertThat(underTest.getOriginalFile(component)).isAbsent();
+      assertThat(underTest.getOriginalFile(component)).isEmpty();
     }
     assertThat(underTest.getOriginalFile(SOME_FILE)).contains(SOME_ORIGINAL_FILE);
   }
index 23c2bb680e22bbe33cecb95d4a4ffc878a3f9a62..c90841facadcbf573e211b04c6a2446ac1f90b3c 100644 (file)
@@ -19,8 +19,8 @@
  */
 package org.sonar.ce.task.projectanalysis.filemove;
 
-import com.google.common.base.Optional;
 import java.util.HashSet;
+import java.util.Optional;
 import java.util.Set;
 import javax.annotation.CheckForNull;
 import org.junit.rules.ExternalResource;
index bbc549cd277ed6a2a50e8188298d743f9a25b5ff..2113bce0b92e24ec24355b00fd4e49fc7b7ba860 100644 (file)
@@ -19,9 +19,9 @@
  */
 package org.sonar.ce.task.projectanalysis.issue;
 
-import com.google.common.base.Optional;
 import com.google.common.collect.ImmutableList;
 import java.util.List;
+import java.util.Optional;
 import org.junit.Test;
 import org.sonar.ce.task.projectanalysis.component.Component;
 import org.sonar.ce.task.projectanalysis.component.ReportComponent;
@@ -47,7 +47,7 @@ public class ClosedIssuesInputFactoryTest {
   public void underTest_returns_inputFactory_loading_closed_issues_only_when_getIssues_is_called() {
     String componentUuid = randomAlphanumeric(12);
     ReportComponent component = ReportComponent.builder(Component.Type.FILE, 1).setUuid(componentUuid).build();
-    when(movedFilesRepository.getOriginalFile(component)).thenReturn(Optional.absent());
+    when(movedFilesRepository.getOriginalFile(component)).thenReturn(Optional.empty());
 
     Input<DefaultIssue> input = underTest.create(component);
 
@@ -81,7 +81,7 @@ public class ClosedIssuesInputFactoryTest {
   public void underTest_returns_inputFactory_which_caches_loaded_issues() {
     String componentUuid = randomAlphanumeric(12);
     ReportComponent component = ReportComponent.builder(Component.Type.FILE, 1).setUuid(componentUuid).build();
-    when(movedFilesRepository.getOriginalFile(component)).thenReturn(Optional.absent());
+    when(movedFilesRepository.getOriginalFile(component)).thenReturn(Optional.empty());
 
     Input<DefaultIssue> input = underTest.create(component);
 
index 93fa3ae344c437976179a05cea67f38a285d52a7..2c8dff9c260a06b7190de47331e684ad289d73a1 100644 (file)
@@ -19,8 +19,8 @@
  */
 package org.sonar.ce.task.projectanalysis.issue;
 
-import com.google.common.base.Optional;
 import java.util.List;
+import java.util.Optional;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -140,7 +140,7 @@ public class IntegrateIssuesVisitorTest {
     IssueVisitors issueVisitors = new IssueVisitors(new IssueVisitor[] {issueVisitor});
 
     defaultIssueCaptor = ArgumentCaptor.forClass(DefaultIssue.class);
-    when(movedFilesRepository.getOriginalFile(any(Component.class))).thenReturn(Optional.absent());
+    when(movedFilesRepository.getOriginalFile(any(Component.class))).thenReturn(Optional.empty());
 
     DbClient dbClient = dbTester.getDbClient();
     TrackerRawInputFactory rawInputFactory = new TrackerRawInputFactory(treeRootHolder, reportReader, sourceLinesHash, new CommonRuleEngineImpl(),
index 20451ad1e152dc4e598e963489fb7a197aefc489..e69963d7deb347a9b92c33f83b4cf82c325202d2 100644 (file)
@@ -19,8 +19,8 @@
  */
 package org.sonar.ce.task.projectanalysis.issue;
 
-import com.google.common.base.Optional;
 import java.util.Date;
+import java.util.Optional;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
@@ -63,7 +63,7 @@ public class MovedIssueVisitorTest {
   public void setUp() {
     analysisMetadataHolder.setAnalysisDate(ANALYSIS_DATE);
     when(movedFilesRepository.getOriginalFile(any(Component.class)))
-      .thenReturn(Optional.absent());
+      .thenReturn(Optional.empty());
   }
 
   @Test
index 5cfb4e01bbe41bb8f1bafd20f2f06d68a49dc0f9..362eebf6c92ca0edf1b8d1a293ec6edcaa99d32d 100644 (file)
@@ -19,7 +19,7 @@
  */
 package org.sonar.ce.task.projectanalysis.issue;
 
-import com.google.common.base.Optional;
+import java.util.Optional;
 import org.junit.Before;
 import org.junit.Test;
 import org.sonar.ce.task.projectanalysis.component.Component;
@@ -46,7 +46,7 @@ public class RemoveProcessedComponentsVisitorTest {
 
   @Test
   public void remove_processed_files() {
-    when(movedFilesRepository.getOriginalFile(any(Component.class))).thenReturn(Optional.absent());
+    when(movedFilesRepository.getOriginalFile(any(Component.class))).thenReturn(Optional.empty());
     underTest.afterComponent(component);
 
     verify(movedFilesRepository).getOriginalFile(component);
index ce158a72340622d28b219b4e516463add638f451..e2abc551938a95d5cb165f7cc1f043e979d3a16a 100644 (file)
@@ -19,7 +19,7 @@
  */
 package org.sonar.ce.task.projectanalysis.issue;
 
-import com.google.common.base.Optional;
+import java.util.Optional;
 import org.junit.Before;
 import org.junit.Test;
 import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolderRule;
@@ -65,7 +65,7 @@ public class TrackerBaseInputFactoryTest {
     when(dbClient.openSession(false)).thenReturn(dbSession);
     when(dbClient.fileSourceDao()).thenReturn(fileSourceDao);
     when(movedFilesRepository.getOriginalFile(any(Component.class)))
-      .thenReturn(Optional.absent());
+      .thenReturn(Optional.empty());
   }
 
   @Test
index 33cfdb245d152afa253635d796c2d1fc9d5f6b21..800bd0203aea9f668386882a21145251a9e4a62b 100644 (file)
@@ -35,6 +35,7 @@ import org.sonar.ce.task.projectanalysis.analysis.Branch;
 import org.sonar.ce.task.projectanalysis.batch.BatchReportReaderRule;
 import org.sonar.ce.task.projectanalysis.component.Component;
 import org.sonar.ce.task.projectanalysis.component.ReferenceBranchComponentUuids;
+import org.sonar.ce.task.projectanalysis.filemove.MutableMovedFilesRepositoryRule;
 import org.sonar.core.hash.SourceHashComputer;
 import org.sonar.db.DbTester;
 import org.sonar.db.component.BranchType;
@@ -67,11 +68,13 @@ public class ScmInfoDbLoaderTest {
   public DbTester dbTester = DbTester.create(System2.INSTANCE);
   @Rule
   public BatchReportReaderRule reportReader = new BatchReportReaderRule();
+  @Rule
+  public MutableMovedFilesRepositoryRule movedFiles = new MutableMovedFilesRepositoryRule();
 
   private Branch branch = mock(Branch.class);
   private ReferenceBranchComponentUuids referenceBranchComponentUuids = mock(ReferenceBranchComponentUuids.class);
 
-  private ScmInfoDbLoader underTest = new ScmInfoDbLoader(analysisMetadataHolder, dbTester.getDbClient(), referenceBranchComponentUuids);
+  private ScmInfoDbLoader underTest = new ScmInfoDbLoader(analysisMetadataHolder, movedFiles, dbTester.getDbClient(), referenceBranchComponentUuids);
 
   @Test
   public void returns_ScmInfo_from_DB() {
index 8ae9f4bd043e07107801a2f43bf474b46ed727c6..82af3ffcc2cae6ebdc00142f37159d6782c2aeef 100644 (file)
@@ -21,10 +21,12 @@ package org.sonar.ce.task.projectanalysis.source;
 
 import java.util.Arrays;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder;
 import org.sonar.ce.task.projectanalysis.component.Component;
 import org.sonar.ce.task.projectanalysis.component.ReferenceBranchComponentUuids;
+import org.sonar.ce.task.projectanalysis.filemove.MutableMovedFilesRepositoryRule;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.component.ComponentDao;
@@ -45,9 +47,11 @@ public class SourceLinesDiffImplTest {
   private SourceLinesHashRepository sourceLinesHash = mock(SourceLinesHashRepository.class);
   private AnalysisMetadataHolder analysisMetadataHolder = mock(AnalysisMetadataHolder.class);
   private ReferenceBranchComponentUuids referenceBranchComponentUuids = mock(ReferenceBranchComponentUuids.class);
+  @Rule
+  public MutableMovedFilesRepositoryRule movedFiles = new MutableMovedFilesRepositoryRule();
 
   private SourceLinesDiffImpl underTest = new SourceLinesDiffImpl(dbClient, fileSourceDao, sourceLinesHash,
-    referenceBranchComponentUuids, analysisMetadataHolder);
+    referenceBranchComponentUuids, movedFiles, analysisMetadataHolder);
 
   private static final int FILE_REF = 1;
 
index 419e5868ca9c3d635037d5952e410c1ed98f8056..1ca98731ca192ed2727a4a5d8853afbc49a06642 100644 (file)
@@ -88,24 +88,24 @@ public class SourceLinesHashRepositoryImplTest {
 
   @Test
   public void should_create_hash_without_significant_code_if_db_has_no_significant_code() {
-    when(dbLineHashVersion.hasLineHashesWithSignificantCode(file)).thenReturn(false);
+    when(dbLineHashVersion.hasLineHashesWithoutSignificantCode(file)).thenReturn(true);
     List<String> lineHashes = underTest.getLineHashesMatchingDBVersion(file);
 
     assertLineHashes(lineHashes, "line1", "line2", "line3");
-    verify(dbLineHashVersion).hasLineHashesWithSignificantCode(file);
+    verify(dbLineHashVersion).hasLineHashesWithoutSignificantCode(file);
     verifyNoMoreInteractions(dbLineHashVersion);
     verifyZeroInteractions(significantCodeRepository);
   }
 
   @Test
   public void should_create_hash_without_significant_code_if_report_has_no_significant_code() {
-    when(dbLineHashVersion.hasLineHashesWithSignificantCode(file)).thenReturn(true);
+    when(dbLineHashVersion.hasLineHashesWithoutSignificantCode(file)).thenReturn(false);
     when(significantCodeRepository.getRangesPerLine(file)).thenReturn(Optional.empty());
 
     List<String> lineHashes = underTest.getLineHashesMatchingDBVersion(file);
 
     assertLineHashes(lineHashes, "line1", "line2", "line3");
-    verify(dbLineHashVersion).hasLineHashesWithSignificantCode(file);
+    verify(dbLineHashVersion).hasLineHashesWithoutSignificantCode(file);
     verifyNoMoreInteractions(dbLineHashVersion);
     verify(significantCodeRepository).getRangesPerLine(file);
     verifyNoMoreInteractions(significantCodeRepository);
@@ -121,7 +121,7 @@ public class SourceLinesHashRepositoryImplTest {
     List<String> lineHashes = underTest.getLineHashesMatchingDBVersion(file);
 
     assertLineHashes(lineHashes, "l", "", "ine3");
-    verify(dbLineHashVersion).hasLineHashesWithSignificantCode(file);
+    verify(dbLineHashVersion).hasLineHashesWithoutSignificantCode(file);
     verifyNoMoreInteractions(dbLineHashVersion);
     verify(significantCodeRepository).getRangesPerLine(file);
     verifyNoMoreInteractions(significantCodeRepository);
@@ -154,7 +154,7 @@ public class SourceLinesHashRepositoryImplTest {
     LineRange[] lineRanges = {new LineRange(0, 1), null, new LineRange(1, 5)};
     sourceLinesHashCache.computeIfAbsent(file, c -> lineHashes);
 
-    when(dbLineHashVersion.hasLineHashesWithSignificantCode(file)).thenReturn(true);
+    when(dbLineHashVersion.hasLineHashesWithoutSignificantCode(file)).thenReturn(false);
     when(significantCodeRepository.getRangesPerLine(file)).thenReturn(Optional.of(lineRanges));
 
     LineHashesComputer hashesComputer = underTest.getLineHashesComputerToPersist(file);
@@ -168,7 +168,7 @@ public class SourceLinesHashRepositoryImplTest {
     List<String> lineHashes = Lists.newArrayList("line1", "line2", "line3");
     sourceLinesHashCache.computeIfAbsent(file, c -> lineHashes);
 
-    when(dbLineHashVersion.hasLineHashesWithSignificantCode(file)).thenReturn(false);
+    when(dbLineHashVersion.hasLineHashesWithoutSignificantCode(file)).thenReturn(true);
     when(significantCodeRepository.getRangesPerLine(file)).thenReturn(Optional.empty());
 
     LineHashesComputer hashesComputer = underTest.getLineHashesComputerToPersist(file);
@@ -185,7 +185,7 @@ public class SourceLinesHashRepositoryImplTest {
     sourceLinesHashCache.computeIfAbsent(file, c -> lineHashes);
 
     // DB has line hashes without significant code and significant code is available in the report, so we need to generate new line hashes
-    when(dbLineHashVersion.hasLineHashesWithSignificantCode(file)).thenReturn(false);
+    when(dbLineHashVersion.hasLineHashesWithoutSignificantCode(file)).thenReturn(true);
     when(significantCodeRepository.getRangesPerLine(file)).thenReturn(Optional.of(lineRanges));
 
     LineHashesComputer hashesComputer = underTest.getLineHashesComputerToPersist(file);
index 7b235580598cae1092a9b858284c65d53ead1bdb..ff006368b287031c19401ec87575a051d3080a7b 100644 (file)
@@ -50,7 +50,7 @@ public class FileSourceDao implements Dao {
   @CheckForNull
   public LineHashVersion selectLineHashesVersion(DbSession dbSession, String fileUuid) {
     Integer version = mapper(dbSession).selectLineHashesVersion(fileUuid);
-    return version == null ? LineHashVersion.WITHOUT_SIGNIFICANT_CODE : LineHashVersion.valueOf(version);
+    return version == null ? null : LineHashVersion.valueOf(version);
   }
 
   @CheckForNull
@@ -82,8 +82,8 @@ public class FileSourceDao implements Dao {
    * uuids in no specific order with 'SOURCE' source and a non null path.
    */
   public void scrollLineHashes(DbSession dbSession, Collection<String> fileUUids, ResultHandler<LineHashesWithUuidDto> rowHandler) {
-    for (List<String> partition : toUniqueAndSortedPartitions(fileUUids)) {
-      mapper(dbSession).scrollLineHashes(partition, rowHandler);
+    for (List<String> fileUuidsPartition : toUniqueAndSortedPartitions(fileUUids)) {
+      mapper(dbSession).scrollLineHashes(fileUuidsPartition, rowHandler);
     }
   }