@Override
 protected CommonRuleIssue doProcessFile(Component file, ActiveRule activeRule) {
   Optional<Measure> coverageMeasure = measureRepository.getRawMeasure(file, coverageMetric);
   if (!file.getFileAttributes().isUnitTest() && coverageMeasure.isPresent()) {
     double coverage = coverageMeasure.get().getDoubleValue();
     double minimumCoverage = getMinDensityParam(activeRule, minPropertyKey);
     if (coverage < minimumCoverage) {
       return generateIssue(file, minimumCoverage);
     }
   }
   return null;
 }
  @Override
  public void visitAny(Component component) {
    componentIssues.clear();
    processIssues(component);

    componentsWithUnprocessedIssues.remove(component.getUuid());
    Optional<MovedFilesRepository.OriginalFile> originalFile =
        movedFilesRepository.getOriginalFile(component);
    if (originalFile.isPresent()) {
      componentsWithUnprocessedIssues.remove(originalFile.get().getUuid());
    }
    componentIssuesRepository.setIssues(component, componentIssues);
  }
 private void processIssues(Component component) {
   DiskCache<DefaultIssue>.DiskAppender cacheAppender = issueCache.newAppender();
   try {
     Tracking<DefaultIssue, DefaultIssue> tracking = tracker.track(component);
     issueVisitors.beforeComponent(component);
     fillNewOpenIssues(component, tracking, cacheAppender);
     fillExistingOpenIssues(component, tracking, cacheAppender);
     closeUnmatchedBaseIssues(component, tracking, cacheAppender);
     issueVisitors.afterComponent(component);
   } catch (Exception e) {
     throw new IllegalStateException(
         String.format("Fail to process issues of component '%s'", component.getKey()), e);
   } finally {
     cacheAppender.close();
   }
 }