From bd28d90a20a021855fe2754faa1b59272ed4970b Mon Sep 17 00:00:00 2001 From: Julien HENRY Date: Thu, 15 Dec 2016 16:31:58 +0100 Subject: [PATCH] Fix quality flaws --- .../sonar/server/issue/SetSeverityAction.java | 8 +- .../DefaultNotificationManager.java | 10 +- .../org/sonar/core/issue/DefaultIssue.java | 24 ++-- .../fs/internal/AbstractFilePredicate.java | 8 +- .../batch/fs/internal/DefaultFileSystem.java | 19 +-- .../api/batch/fs/internal/FileMetadata.java | 1 + .../internal/DefaultHighlighting.java | 14 +- .../sensor/issue/internal/DefaultIssue.java | 19 +-- .../symbol/internal/DefaultSymbolTable.java | 8 +- .../scanner/DefaultFileLinesContext.java | 15 +-- .../org/sonar/scanner/cpd/CpdExecutor.java | 35 ++--- .../scanner/cpd/index/SonarCpdBlockIndex.java | 24 ++-- .../org/sonar/scanner/index/DefaultIndex.java | 2 +- .../scanner/issue/tracking/FileHashes.java | 20 +-- .../phases/InitializerExecutionEvent.java | 2 +- .../phases/InitializersPhaseEvent.java | 5 +- .../scanner/phases/PostJobExecutionEvent.java | 2 +- .../scanner/phases/PostJobPhaseEvent.java | 5 +- .../scanner/phases/ProjectAnalysisEvent.java | 2 +- .../scanner/phases/SensorExecutionEvent.java | 2 +- .../profiling/AbstractTimeProfiling.java | 11 +- .../scanner/report/ActiveRulesPublisher.java | 31 ++--- .../scanner/report/MeasuresPublisher.java | 84 +++++------- .../TestExecutionAndCoveragePublisher.java | 121 ++++++++---------- .../DefaultProjectRepositoriesLoader.java | 6 +- .../rule/DefaultActiveRulesLoader.java | 6 +- .../scanner/scan/filesystem/FileIndexer.java | 26 ++-- .../scan/measure/DeprecatedMetricFinder.java | 12 +- .../scanner/sensor/DefaultSensorStorage.java | 49 +++---- .../scanner/source/DefaultHighlightable.java | 4 +- .../sonar/scanner/cpd/CpdExecutorTest.java | 51 +++++++- 31 files changed, 271 insertions(+), 355 deletions(-) diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/SetSeverityAction.java b/server/sonar-server/src/main/java/org/sonar/server/issue/SetSeverityAction.java index 8a521e5f097..5bb3c9fc8a6 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/SetSeverityAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/SetSeverityAction.java @@ -23,7 +23,6 @@ import com.google.common.base.Strings; import java.util.Collection; import java.util.Map; import org.sonar.api.issue.Issue; -import org.sonar.api.issue.condition.Condition; import org.sonar.api.issue.condition.IsUnResolved; import org.sonar.api.server.ServerSide; import org.sonar.api.web.UserRole; @@ -42,12 +41,7 @@ public class SetSeverityAction extends Action { super(SET_SEVERITY_KEY); this.issueUpdater = issueUpdater; this.userSession = userSession; - super.setConditions(new IsUnResolved(), new Condition() { - @Override - public boolean matches(Issue issue) { - return isCurrentUserIssueAdmin(issue.projectKey()); - } - }); + super.setConditions(new IsUnResolved(), issue -> isCurrentUserIssueAdmin(issue.projectKey())); } private boolean isCurrentUserIssueAdmin(String projectKey) { diff --git a/server/sonar-server/src/main/java/org/sonar/server/notification/DefaultNotificationManager.java b/server/sonar-server/src/main/java/org/sonar/server/notification/DefaultNotificationManager.java index bceb9aa8c4a..83548fbd631 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/notification/DefaultNotificationManager.java +++ b/server/sonar-server/src/main/java/org/sonar/server/notification/DefaultNotificationManager.java @@ -20,7 +20,6 @@ package org.sonar.server.notification; import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Function; import com.google.common.collect.HashMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Multimap; @@ -78,12 +77,7 @@ public class DefaultNotificationManager implements NotificationManager { @Override public void scheduleForSending(List notification) { - notificationQueueDao.insert(Lists.transform(notification, new Function() { - @Override - public NotificationQueueDto apply(Notification notification) { - return NotificationQueueDto.toNotificationQueueDto(notification); - } - })); + notificationQueueDao.insert(Lists.transform(notification, NotificationQueueDto::toNotificationQueueDto)); } /** @@ -130,7 +124,7 @@ public class DefaultNotificationManager implements NotificationManager { */ @Override public Multimap findSubscribedRecipientsForDispatcher(NotificationDispatcher dispatcher, - @Nullable String projectUuid) { + @Nullable String projectUuid) { String dispatcherKey = dispatcher.getKey(); SetMultimap recipients = HashMultimap.create(); diff --git a/sonar-core/src/main/java/org/sonar/core/issue/DefaultIssue.java b/sonar-core/src/main/java/org/sonar/core/issue/DefaultIssue.java index 12b5f9ae573..7202e1af7ce 100644 --- a/sonar-core/src/main/java/org/sonar/core/issue/DefaultIssue.java +++ b/sonar-core/src/main/java/org/sonar/core/issue/DefaultIssue.java @@ -26,8 +26,9 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; import java.io.Serializable; +import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.ArrayList; -import java.util.Calendar; import java.util.Collection; import java.util.Collections; import java.util.Date; @@ -41,7 +42,6 @@ import javax.annotation.Nullable; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.builder.ToStringBuilder; import org.apache.commons.lang.builder.ToStringStyle; -import org.apache.commons.lang.time.DateUtils; import org.sonar.api.issue.Issue; import org.sonar.api.issue.IssueComment; import org.sonar.api.rule.RuleKey; @@ -306,7 +306,6 @@ public class DefaultIssue implements Issue, Trackable, org.sonar.api.ce.measure. return effort; } - @CheckForNull public Long effortInMinutes() { return effort != null ? effort.toMinutes() : null; @@ -366,11 +365,20 @@ public class DefaultIssue implements Issue, Trackable, org.sonar.api.ce.measure. } public DefaultIssue setCreationDate(Date d) { - // d is not marked as Nullable but we still allow null parameter for unit testing. - this.creationDate = d != null ? DateUtils.truncate(d, Calendar.SECOND) : null; + this.creationDate = truncateToSeconds(d); return this; } + @CheckForNull + private static Date truncateToSeconds(@Nullable Date d) { + if (d == null) { + return null; + } + Instant instant = d.toInstant(); + instant = instant.truncatedTo(ChronoUnit.SECONDS); + return Date.from(instant); + } + @Override @CheckForNull public Date updateDate() { @@ -378,7 +386,7 @@ public class DefaultIssue implements Issue, Trackable, org.sonar.api.ce.measure. } public DefaultIssue setUpdateDate(@Nullable Date d) { - this.updateDate = d != null ? DateUtils.truncate(d, Calendar.SECOND) : null; + this.updateDate = truncateToSeconds(d); return this; } @@ -389,7 +397,7 @@ public class DefaultIssue implements Issue, Trackable, org.sonar.api.ce.measure. } public DefaultIssue setCloseDate(@Nullable Date d) { - this.closeDate = d != null ? DateUtils.truncate(d, Calendar.SECOND) : null; + this.closeDate = truncateToSeconds(d); return this; } @@ -580,7 +588,7 @@ public class DefaultIssue implements Issue, Trackable, org.sonar.api.ce.measure. @CheckForNull public T getLocations() { - return (T)locations; + return (T) locations; } public DefaultIssue setLocations(@Nullable Object locations) { diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/AbstractFilePredicate.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/AbstractFilePredicate.java index 98533a05154..2aff265bcf1 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/AbstractFilePredicate.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/AbstractFilePredicate.java @@ -19,7 +19,6 @@ */ package org.sonar.api.batch.fs.internal; -import com.google.common.base.Predicate; import com.google.common.collect.Iterables; import org.sonar.api.batch.fs.FilePredicate; import org.sonar.api.batch.fs.FileSystem.Index; @@ -36,12 +35,7 @@ public abstract class AbstractFilePredicate implements OptimizedFilePredicate { @Override public Iterable filter(Iterable target) { - return Iterables.filter(target, new Predicate() { - @Override - public boolean apply(InputFile input) { - return AbstractFilePredicate.this.apply(input); - } - }); + return Iterables.filter(target, this::apply); } @Override diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultFileSystem.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultFileSystem.java index ceeadaad22b..c7339ed1b2b 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultFileSystem.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultFileSystem.java @@ -19,7 +19,6 @@ */ package org.sonar.api.batch.fs.internal; -import com.google.common.base.Function; import com.google.common.collect.Iterables; import java.io.File; import java.io.IOException; @@ -33,7 +32,6 @@ import java.util.Iterator; import java.util.Map; import java.util.SortedSet; import java.util.TreeSet; -import javax.annotation.CheckForNull; import javax.annotation.Nullable; import org.sonar.api.batch.fs.FilePredicate; import org.sonar.api.batch.fs.FilePredicates; @@ -172,12 +170,7 @@ public class DefaultFileSystem implements FileSystem { @Override public Iterable files(FilePredicate predicate) { doPreloadFiles(); - return Iterables.transform(inputFiles(predicate), new Function() { - @Override - public File apply(InputFile input) { - return input.file(); - } - }); + return Iterables.transform(inputFiles(predicate), InputFile::file); } @Override @@ -249,16 +242,6 @@ public class DefaultFileSystem implements FileSystem { } public abstract static class Cache implements Index { - @Override - public abstract Iterable inputFiles(); - - @Override - @CheckForNull - public abstract InputFile inputFile(String relativePath); - - @Override - @CheckForNull - public abstract InputDir inputDir(String relativePath); protected abstract void doAdd(InputFile inputFile); diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/FileMetadata.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/FileMetadata.java index c72d3e1a744..9a196396462 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/FileMetadata.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/FileMetadata.java @@ -367,6 +367,7 @@ public class FileMetadata { } } + @FunctionalInterface public interface LineHashConsumer { void consume(int lineIdx, @Nullable byte[] hash); diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/highlighting/internal/DefaultHighlighting.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/highlighting/internal/DefaultHighlighting.java index 6ccc541dad3..add43c51cfd 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/highlighting/internal/DefaultHighlighting.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/highlighting/internal/DefaultHighlighting.java @@ -22,7 +22,6 @@ package org.sonar.api.batch.sensor.highlighting.internal; import com.google.common.base.Preconditions; import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; import java.util.Iterator; import java.util.List; import org.sonar.api.batch.fs.InputFile; @@ -109,15 +108,12 @@ public class DefaultHighlighting extends DefaultStorable implements NewHighlight protected void doSave() { checkInputFileNotNull(); // Sort rules to avoid variation during consecutive runs - Collections.sort(syntaxHighlightingRules, new Comparator() { - @Override - public int compare(SyntaxHighlightingRule left, SyntaxHighlightingRule right) { - int result = left.range().start().compareTo(right.range().start()); - if (result == 0) { - result = right.range().end().compareTo(left.range().end()); - } - return result; + Collections.sort(syntaxHighlightingRules, (left, right) -> { + int result = left.range().start().compareTo(right.range().start()); + if (result == 0) { + result = right.range().end().compareTo(left.range().end()); } + return result; }); checkOverlappingBoudaries(); storage.store(this); diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssue.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssue.java index ec123e4df96..ef9db3061bb 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssue.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssue.java @@ -19,10 +19,8 @@ */ package org.sonar.api.batch.sensor.issue.internal; -import com.google.common.base.Function; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; -import com.google.common.collect.Lists; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -37,21 +35,10 @@ import org.sonar.api.batch.sensor.issue.NewIssueLocation; import org.sonar.api.rule.RuleKey; import static java.lang.String.format; +import static java.util.stream.Collectors.toList; public class DefaultIssue extends DefaultStorable implements Issue, NewIssue { - private static final class ToFlow implements Function, Flow> { - @Override - public Flow apply(final List input) { - return new Flow() { - @Override - public List locations() { - return ImmutableList.copyOf(input); - } - }; - } - } - private RuleKey ruleKey; private Double gap; private Severity overriddenSeverity; @@ -147,7 +134,9 @@ public class DefaultIssue extends DefaultStorable implements Issue, NewIssue { @Override public List flows() { - return Lists.transform(this.flows, new ToFlow()); + return this.flows.stream() + .map(l -> () -> ImmutableList.copyOf(l)) + .collect(toList()); } @Override diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/symbol/internal/DefaultSymbolTable.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/symbol/internal/DefaultSymbolTable.java index ba4aa897646..ad4f0770f3b 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/symbol/internal/DefaultSymbolTable.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/symbol/internal/DefaultSymbolTable.java @@ -21,7 +21,6 @@ package org.sonar.api.batch.sensor.symbol.internal; import com.google.common.base.Preconditions; import java.util.Collection; -import java.util.Comparator; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; @@ -86,12 +85,7 @@ public class DefaultSymbolTable extends DefaultStorable implements NewSymbolTabl @Override public NewSymbol newSymbol(TextRange range) { checkInputFileNotNull(); - TreeSet references = new TreeSet<>(new Comparator() { - @Override - public int compare(TextRange o1, TextRange o2) { - return o1.start().compareTo(o2.start()); - } - }); + TreeSet references = new TreeSet<>((o1, o2) -> o1.start().compareTo(o2.start())); referencesBySymbol.put(range, references); return new DefaultSymbol(inputFile, range, references); } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/DefaultFileLinesContext.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/DefaultFileLinesContext.java index 2a22d573b1e..03cfe4ba8da 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/DefaultFileLinesContext.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/DefaultFileLinesContext.java @@ -21,10 +21,10 @@ package org.sonar.scanner; import com.google.common.base.MoreObjects; import com.google.common.base.Preconditions; -import com.google.common.base.Predicate; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Maps; import java.util.Map; +import java.util.Map.Entry; import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.measure.MetricFinder; import org.sonar.api.batch.sensor.SensorContext; @@ -35,17 +35,10 @@ import org.sonar.api.utils.KeyValueFormat; import org.sonar.api.utils.KeyValueFormat.Converter; import org.sonar.scanner.scan.measure.MeasureCache; -import static com.google.common.collect.Maps.filterValues; +import static java.util.stream.Collectors.toMap; public class DefaultFileLinesContext implements FileLinesContext { - private static final Predicate LINES_WITH_NON_ZERO_VALUE = new Predicate() { - @Override - public boolean apply(Object input) { - return !input.equals(0); - } - }; - private final SensorContext context; private final InputFile inputFile; private final MetricFinder metricFinder; @@ -146,7 +139,9 @@ public class DefaultFileLinesContext implements FileLinesContext { private static Map optimizeStorage(String metricKey, Map lines) { // SONAR-7464 Don't store 0 because this is default value anyway if (CoreMetrics.NCLOC_DATA_KEY.equals(metricKey) || CoreMetrics.COMMENT_LINES_DATA_KEY.equals(metricKey) || CoreMetrics.EXECUTABLE_LINES_DATA_KEY.equals(metricKey)) { - return filterValues(lines, LINES_WITH_NON_ZERO_VALUE); + return lines.entrySet().stream() + .filter(entry -> !entry.getValue().equals(0)) + .collect(toMap(Entry::getKey, Entry::getValue)); } return lines; } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/CpdExecutor.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/CpdExecutor.java index c3ca55c4507..db8ba5417cb 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/CpdExecutor.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/CpdExecutor.java @@ -58,7 +58,7 @@ import static com.google.common.collect.FluentIterable.from; public class CpdExecutor { private static final Logger LOG = Loggers.get(CpdExecutor.class); // timeout for the computation of duplicates in a file (seconds) - private static final int TIMEOUT = 5 * 60; + private static final int TIMEOUT = 5 * 60 * 1000; static final int MAX_CLONE_GROUP_PER_FILE = 100; static final int MAX_CLONE_PART_PER_GROUP = 100; @@ -66,7 +66,6 @@ public class CpdExecutor { private final ReportPublisher publisher; private final BatchComponentCache batchComponentCache; private final Settings settings; - private final ExecutorService executorService; private final ProgressReport progressReport; private int count; private int total; @@ -76,50 +75,54 @@ public class CpdExecutor { this.index = index; this.publisher = publisher; this.batchComponentCache = batchComponentCache; - this.executorService = Executors.newSingleThreadExecutor(); this.progressReport = new ProgressReport("CPD computation", TimeUnit.SECONDS.toMillis(10)); } public void execute() { + execute(TIMEOUT); + } + + @VisibleForTesting + void execute(long timeout) { total = index.noResources(); progressReport.start(String.format("Calculating CPD for %d files", total)); + ExecutorService executorService = Executors.newSingleThreadExecutor(); try { Iterator it = index.iterator(); while (it.hasNext()) { ResourceBlocks resourceBlocks = it.next(); - runCpdAnalysis(resourceBlocks.resourceId(), resourceBlocks.blocks()); + runCpdAnalysis(executorService, resourceBlocks.resourceId(), resourceBlocks.blocks(), timeout); count++; } progressReport.stop("CPD calculation finished"); } catch (Exception e) { progressReport.stop(""); throw e; + } finally { + executorService.shutdown(); } } - private void runCpdAnalysis(String resource, final Collection fileBlocks) { - LOG.debug("Detection of duplications for {}", resource); - - BatchComponent component = batchComponentCache.get(resource); + @VisibleForTesting + void runCpdAnalysis(ExecutorService executorService, String componentKey, final Collection fileBlocks, long timeout) { + BatchComponent component = batchComponentCache.get(componentKey); if (component == null) { - LOG.error("Resource not found in component cache: {}. Skipping CPD computation for it", resource); + LOG.error("Resource not found in component cache: {}. Skipping CPD computation for it", componentKey); return; } InputFile inputFile = (InputFile) component.inputComponent(); + LOG.debug("Detection of duplications for {}", inputFile.absolutePath()); progressReport.message(String.format("%d/%d - current file: %s", count, total, inputFile.absolutePath())); List duplications; - Future> futureResult = null; + Future> futureResult = executorService.submit(() -> SuffixTreeCloneDetectionAlgorithm.detect(index, fileBlocks)); try { - futureResult = executorService.submit(() -> SuffixTreeCloneDetectionAlgorithm.detect(index, fileBlocks)); - duplications = futureResult.get(TIMEOUT, TimeUnit.SECONDS); + duplications = futureResult.get(timeout, TimeUnit.MILLISECONDS); } catch (TimeoutException e) { LOG.warn("Timeout during detection of duplications for " + inputFile.absolutePath()); - if (futureResult != null) { - futureResult.cancel(true); - } + futureResult.cancel(true); return; } catch (Exception e) { throw new IllegalStateException("Fail during detection of duplication for " + inputFile.absolutePath(), e); @@ -158,7 +161,7 @@ public class CpdExecutor { LOG.warn("Too many duplication groups on file " + component.inputComponent() + ". Keep only the first " + MAX_CLONE_GROUP_PER_FILE + " groups."); } - Iterable reportDuplications = from(duplications) + Iterable reportDuplications = from(duplications) .limit(MAX_CLONE_GROUP_PER_FILE) .transform( new Function() { diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/index/SonarCpdBlockIndex.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/index/SonarCpdBlockIndex.java index b20e5f2c763..619a06e4c20 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/index/SonarCpdBlockIndex.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/index/SonarCpdBlockIndex.java @@ -19,12 +19,11 @@ */ package org.sonar.scanner.cpd.index; -import com.google.common.base.Function; -import com.google.common.collect.Iterables; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.Set; +import java.util.stream.Collectors; import org.apache.commons.lang.StringUtils; import org.sonar.api.CoreProperties; import org.sonar.api.batch.fs.InputFile; @@ -62,18 +61,15 @@ public class SonarCpdBlockIndex extends AbstractCloneIndex { throw new UnsupportedOperationException("Trying to save CPD tokens twice for the same file is not supported: " + inputFile.absolutePath()); } final ScannerReport.CpdTextBlock.Builder builder = ScannerReport.CpdTextBlock.newBuilder(); - publisher.getWriter().writeCpdTextBlocks(id, Iterables.transform(blocks, new Function() { - @Override - public ScannerReport.CpdTextBlock apply(Block input) { - builder.clear(); - builder.setStartLine(input.getStartLine()); - builder.setEndLine(input.getEndLine()); - builder.setStartTokenIndex(input.getStartUnit()); - builder.setEndTokenIndex(input.getEndUnit()); - builder.setHash(input.getBlockHash().toHexString()); - return builder.build(); - } - })); + publisher.getWriter().writeCpdTextBlocks(id, blocks.stream().map(block -> { + builder.clear(); + builder.setStartLine(block.getStartLine()); + builder.setEndLine(block.getEndLine()); + builder.setStartTokenIndex(block.getStartUnit()); + builder.setEndTokenIndex(block.getEndUnit()); + builder.setHash(block.getBlockHash().toHexString()); + return builder.build(); + }).collect(Collectors.toList())); } for (Block block : blocks) { mem.insert(block); diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/index/DefaultIndex.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/index/DefaultIndex.java index 851df664962..030518b26f5 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/index/DefaultIndex.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/index/DefaultIndex.java @@ -166,7 +166,7 @@ public class DefaultIndex { } private static Measure toDeprecated(org.sonar.api.batch.sensor.measure.Measure measure) { - org.sonar.api.measures.Measure deprecatedMeasure = new org.sonar.api.measures.Measure((Metric) measure.metric()); + Measure deprecatedMeasure = new Measure((Metric) measure.metric()); setValueAccordingToMetricType(measure, deprecatedMeasure); return deprecatedMeasure; } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/tracking/FileHashes.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/tracking/FileHashes.java index c65081e5f44..bac3c9b6888 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/tracking/FileHashes.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/tracking/FileHashes.java @@ -19,18 +19,13 @@ */ package org.sonar.scanner.issue.tracking; -import org.sonar.api.batch.fs.internal.FileMetadata; -import org.sonar.api.batch.fs.internal.FileMetadata.LineHashConsumer; - import com.google.common.collect.LinkedHashMultimap; import com.google.common.collect.Multimap; +import java.util.Collection; import org.apache.commons.codec.binary.Hex; import org.apache.commons.lang.ObjectUtils; import org.sonar.api.batch.fs.internal.DefaultInputFile; - -import javax.annotation.Nullable; - -import java.util.Collection; +import org.sonar.api.batch.fs.internal.FileMetadata; /** * Wraps a {@link Sequence} to assign hash codes to elements. @@ -57,13 +52,8 @@ public final class FileHashes { public static FileHashes create(DefaultInputFile f) { final byte[][] hashes = new byte[f.lines()][]; - FileMetadata.computeLineHashesForIssueTracking(f, new LineHashConsumer() { - - @Override - public void consume(int lineIdx, @Nullable byte[] hash) { - hashes[lineIdx - 1] = hash; - } - }); + FileMetadata.computeLineHashesForIssueTracking(f, + (lineIdx, hash) -> hashes[lineIdx - 1] = hash); int size = hashes.length; Multimap linesByHash = LinkedHashMultimap.create(); @@ -84,7 +74,7 @@ public final class FileHashes { public Collection getLinesForHash(String hash) { return linesByHash.get(hash); } - + public String[] hashes() { return hashes; } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/InitializerExecutionEvent.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/InitializerExecutionEvent.java index 1f7b4bbd067..1ce95e83387 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/InitializerExecutionEvent.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/InitializerExecutionEvent.java @@ -23,7 +23,7 @@ import org.sonar.api.batch.Initializer; import org.sonar.api.batch.events.InitializerExecutionHandler; class InitializerExecutionEvent extends AbstractPhaseEvent - implements org.sonar.api.batch.events.InitializerExecutionHandler.InitializerExecutionEvent { + implements InitializerExecutionHandler.InitializerExecutionEvent { private final Initializer initializer; diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/InitializersPhaseEvent.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/InitializersPhaseEvent.java index 6a45a4d67e5..fa54af9f9b0 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/InitializersPhaseEvent.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/InitializersPhaseEvent.java @@ -19,13 +19,12 @@ */ package org.sonar.scanner.phases; +import java.util.List; import org.sonar.api.batch.Initializer; import org.sonar.api.batch.events.InitializersPhaseHandler; -import java.util.List; - class InitializersPhaseEvent extends AbstractPhaseEvent - implements org.sonar.api.batch.events.InitializersPhaseHandler.InitializersPhaseEvent { + implements InitializersPhaseHandler.InitializersPhaseEvent { private final List initializers; diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/PostJobExecutionEvent.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/PostJobExecutionEvent.java index 3c519326f06..b49abcb2df7 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/PostJobExecutionEvent.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/PostJobExecutionEvent.java @@ -23,7 +23,7 @@ import org.sonar.api.batch.PostJob; import org.sonar.api.batch.events.PostJobExecutionHandler; class PostJobExecutionEvent extends AbstractPhaseEvent - implements org.sonar.api.batch.events.PostJobExecutionHandler.PostJobExecutionEvent { + implements PostJobExecutionHandler.PostJobExecutionEvent { private final PostJob postJob; diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/PostJobPhaseEvent.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/PostJobPhaseEvent.java index f3cfae99ae3..033ec017d5e 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/PostJobPhaseEvent.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/PostJobPhaseEvent.java @@ -19,13 +19,12 @@ */ package org.sonar.scanner.phases; +import java.util.List; import org.sonar.api.batch.PostJob; import org.sonar.api.batch.events.PostJobsPhaseHandler; -import java.util.List; - class PostJobPhaseEvent extends AbstractPhaseEvent - implements org.sonar.api.batch.events.PostJobsPhaseHandler.PostJobsPhaseEvent { + implements PostJobsPhaseHandler.PostJobsPhaseEvent { private final List postJobs; diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/ProjectAnalysisEvent.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/ProjectAnalysisEvent.java index feb427679ed..aca9dc99bd7 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/ProjectAnalysisEvent.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/ProjectAnalysisEvent.java @@ -23,7 +23,7 @@ import org.sonar.api.batch.events.ProjectAnalysisHandler; import org.sonar.api.resources.Project; class ProjectAnalysisEvent extends AbstractPhaseEvent - implements org.sonar.api.batch.events.ProjectAnalysisHandler.ProjectAnalysisEvent { + implements ProjectAnalysisHandler.ProjectAnalysisEvent { private final Project project; diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/SensorExecutionEvent.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/SensorExecutionEvent.java index ebb1aeed3c1..1a9c203306a 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/SensorExecutionEvent.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/SensorExecutionEvent.java @@ -23,7 +23,7 @@ import org.sonar.api.batch.Sensor; import org.sonar.api.batch.events.SensorExecutionHandler; class SensorExecutionEvent extends AbstractPhaseEvent - implements org.sonar.api.batch.events.SensorExecutionHandler.SensorExecutionEvent { + implements SensorExecutionHandler.SensorExecutionEvent { private final Sensor sensor; diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/profiling/AbstractTimeProfiling.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/profiling/AbstractTimeProfiling.java index 17527ab1959..f9464531d2d 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/profiling/AbstractTimeProfiling.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/profiling/AbstractTimeProfiling.java @@ -22,7 +22,6 @@ package org.sonar.scanner.profiling; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.Comparator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -72,14 +71,8 @@ public abstract class AbstractTimeProfiling { } static Map sortByDescendingTotalTime(Map unsorted) { - List> entries = - new ArrayList>(unsorted.entrySet()); - Collections.sort(entries, new Comparator>() { - @Override - public int compare(Map.Entry o1, Map.Entry o2) { - return Long.valueOf(o2.getValue().totalTime()).compareTo(o1.getValue().totalTime()); - } - }); + List> entries = new ArrayList<>(unsorted.entrySet()); + Collections.sort(entries, (o1, o2) -> Long.valueOf(o2.getValue().totalTime()).compareTo(o1.getValue().totalTime())); Map sortedMap = new LinkedHashMap<>(); for (Map.Entry entry : entries) { sortedMap.put(entry.getKey(), entry.getValue()); diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ActiveRulesPublisher.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ActiveRulesPublisher.java index d2fbf437618..2a751aa04b4 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ActiveRulesPublisher.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ActiveRulesPublisher.java @@ -19,15 +19,13 @@ */ package org.sonar.scanner.report; -import com.google.common.base.Function; -import com.google.common.collect.FluentIterable; -import javax.annotation.Nonnull; -import org.sonar.api.batch.rule.ActiveRule; import org.sonar.api.batch.rule.ActiveRules; import org.sonar.scanner.protocol.Constants; import org.sonar.scanner.protocol.output.ScannerReport; import org.sonar.scanner.protocol.output.ScannerReportWriter; +import static java.util.stream.Collectors.toList; + public class ActiveRulesPublisher implements ReportPublisherStep { private final ActiveRules activeRules; @@ -38,21 +36,16 @@ public class ActiveRulesPublisher implements ReportPublisherStep { @Override public void publish(ScannerReportWriter writer) { - Iterable activeRuleMessages = FluentIterable.from(activeRules.findAll()).transform(new ToMessage()); - writer.writeActiveRules(activeRuleMessages); + final ScannerReport.ActiveRule.Builder builder = ScannerReport.ActiveRule.newBuilder(); + writer.writeActiveRules(activeRules.findAll().stream() + .map(input -> { + builder.clear(); + builder.setRuleRepository(input.ruleKey().repository()); + builder.setRuleKey(input.ruleKey().rule()); + builder.setSeverity(Constants.Severity.valueOf(input.severity())); + builder.getMutableParamsByKey().putAll(input.params()); + return builder.build(); + }).collect(toList())); } - private static class ToMessage implements Function { - private final ScannerReport.ActiveRule.Builder builder = ScannerReport.ActiveRule.newBuilder(); - - @Override - public ScannerReport.ActiveRule apply(@Nonnull ActiveRule input) { - builder.clear(); - builder.setRuleRepository(input.ruleKey().repository()); - builder.setRuleKey(input.ruleKey().rule()); - builder.setSeverity(Constants.Severity.valueOf(input.severity())); - builder.getMutableParamsByKey().putAll(input.params()); - return builder.build(); - } - } } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MeasuresPublisher.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MeasuresPublisher.java index 4686aaea47a..33f58a8db3f 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MeasuresPublisher.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MeasuresPublisher.java @@ -19,13 +19,11 @@ */ package org.sonar.scanner.report; -import com.google.common.base.Function; import com.google.common.collect.Iterables; import java.io.Serializable; import java.util.Collections; import java.util.Map; import java.util.stream.StreamSupport; -import javax.annotation.Nonnull; import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.fs.InputFile.Type; import org.sonar.api.batch.measure.Metric; @@ -34,6 +32,7 @@ import org.sonar.api.measures.CoreMetrics; import org.sonar.api.test.MutableTestPlan; import org.sonar.api.test.TestCase.Status; import org.sonar.api.utils.KeyValueFormat; +import org.sonar.core.util.stream.Collectors; import org.sonar.scanner.deprecated.test.TestPlanBuilder; import org.sonar.scanner.index.BatchComponent; import org.sonar.scanner.index.BatchComponentCache; @@ -46,7 +45,6 @@ import org.sonar.scanner.protocol.output.ScannerReport.Measure.StringValue; import org.sonar.scanner.protocol.output.ScannerReportWriter; import org.sonar.scanner.scan.measure.MeasureCache; -import static com.google.common.collect.Iterables.transform; import static org.sonar.api.measures.CoreMetrics.CONDITIONS_TO_COVER; import static org.sonar.api.measures.CoreMetrics.CONDITIONS_TO_COVER_KEY; import static org.sonar.api.measures.CoreMetrics.LINES_TO_COVER; @@ -68,53 +66,6 @@ import static org.sonar.api.measures.CoreMetrics.UNCOVERED_LINES_KEY; public class MeasuresPublisher implements ReportPublisherStep { - private static final class MeasureToReportMeasure implements Function { - private final BatchComponent resource; - private final ScannerReport.Measure.Builder builder = ScannerReport.Measure.newBuilder(); - - private MeasureToReportMeasure(BatchComponent resource) { - this.resource = resource; - } - - @Override - public ScannerReport.Measure apply(@Nonnull DefaultMeasure input) { - validateMeasure(input, resource.key()); - return toReportMeasure(builder, input); - } - - private static void validateMeasure(DefaultMeasure measure, String componentKey) { - if (measure.value() == null) { - throw new IllegalArgumentException(String.format("Measure on metric '%s' and component '%s' has no value, but it's not allowed", measure.metric().key(), componentKey)); - } - } - - private static ScannerReport.Measure toReportMeasure(ScannerReport.Measure.Builder builder, DefaultMeasure measure) { - builder.clear(); - builder.setMetricKey(measure.metric().key()); - setValueAccordingToType(builder, measure); - return builder.build(); - } - - private static void setValueAccordingToType(ScannerReport.Measure.Builder builder, DefaultMeasure measure) { - Serializable value = measure.value(); - Metric metric = measure.metric(); - if (Boolean.class.equals(metric.valueType())) { - builder.setBooleanValue(BoolValue.newBuilder().setValue(((Boolean) value).booleanValue())); - } else if (Integer.class.equals(metric.valueType())) { - builder.setIntValue(IntValue.newBuilder().setValue(((Number) value).intValue())); - } else if (Double.class.equals(metric.valueType())) { - builder.setDoubleValue(DoubleValue.newBuilder().setValue(((Number) value).doubleValue())); - } else if (String.class.equals(metric.valueType())) { - builder.setStringValue(StringValue.newBuilder().setValue((String) value)); - } else if (Long.class.equals(metric.valueType())) { - builder.setLongValue(LongValue.newBuilder().setValue(((Number) value).longValue())); - } else { - throw new UnsupportedOperationException("Unsupported type :" + metric.valueType()); - } - } - - } - private final BatchComponentCache componentCache; private final MeasureCache measureCache; private final TestPlanBuilder testPlanBuilder; @@ -127,6 +78,8 @@ public class MeasuresPublisher implements ReportPublisherStep { @Override public void publish(ScannerReportWriter writer) { + final ScannerReport.Measure.Builder builder = ScannerReport.Measure.newBuilder(); + for (final BatchComponent component : componentCache.all()) { // Recompute all coverage measures from line data to take into account the possible merge of several reports updateCoverageFromLineData(component); @@ -134,8 +87,35 @@ public class MeasuresPublisher implements ReportPublisherStep { updateTestExecutionFromTestPlan(component); Iterable> scannerMeasures = measureCache.byComponentKey(component.key()); - Iterable reportMeasures = transform(scannerMeasures, new MeasureToReportMeasure(component)); - writer.writeComponentMeasures(component.batchId(), reportMeasures); + writer.writeComponentMeasures(component.batchId(), StreamSupport.stream(scannerMeasures.spliterator(), false) + .map(input -> { + if (input.value() == null) { + throw new IllegalArgumentException( + String.format("Measure on metric '%s' and component '%s' has no value, but it's not allowed", input.metric().key(), component.key())); + } + builder.clear(); + builder.setMetricKey(input.metric().key()); + setValueAccordingToType(builder, input); + return builder.build(); + }).collect(Collectors.toList())); + } + } + + private static void setValueAccordingToType(ScannerReport.Measure.Builder builder, DefaultMeasure measure) { + Serializable value = measure.value(); + Metric metric = measure.metric(); + if (Boolean.class.equals(metric.valueType())) { + builder.setBooleanValue(BoolValue.newBuilder().setValue(((Boolean) value).booleanValue())); + } else if (Integer.class.equals(metric.valueType())) { + builder.setIntValue(IntValue.newBuilder().setValue(((Number) value).intValue())); + } else if (Double.class.equals(metric.valueType())) { + builder.setDoubleValue(DoubleValue.newBuilder().setValue(((Number) value).doubleValue())); + } else if (String.class.equals(metric.valueType())) { + builder.setStringValue(StringValue.newBuilder().setValue((String) value)); + } else if (Long.class.equals(metric.valueType())) { + builder.setLongValue(LongValue.newBuilder().setValue(((Number) value).longValue())); + } else { + throw new UnsupportedOperationException("Unsupported type :" + metric.valueType()); } } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/TestExecutionAndCoveragePublisher.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/TestExecutionAndCoveragePublisher.java index d37c9439e8b..04ae3e824eb 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/TestExecutionAndCoveragePublisher.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/TestExecutionAndCoveragePublisher.java @@ -19,11 +19,10 @@ */ package org.sonar.scanner.report; -import com.google.common.base.Function; import com.google.common.collect.Iterables; import java.util.HashSet; import java.util.Set; -import javax.annotation.Nonnull; +import java.util.stream.StreamSupport; import org.sonar.api.test.CoverageBlock; import org.sonar.api.test.MutableTestCase; import org.sonar.api.test.MutableTestPlan; @@ -38,69 +37,9 @@ import org.sonar.scanner.protocol.output.ScannerReport.Test; import org.sonar.scanner.protocol.output.ScannerReport.Test.TestStatus; import org.sonar.scanner.protocol.output.ScannerReportWriter; -public class TestExecutionAndCoveragePublisher implements ReportPublisherStep { - - private static final class TestConverter implements Function { - private final Set testNamesWithCoverage; - private ScannerReport.Test.Builder builder = ScannerReport.Test.newBuilder(); - - private TestConverter(Set testNamesWithCoverage) { - this.testNamesWithCoverage = testNamesWithCoverage; - } - - @Override - public Test apply(@Nonnull MutableTestCase testCase) { - builder.clear(); - builder.setName(testCase.name()); - if (testCase.doesCover()) { - testNamesWithCoverage.add(testCase.name()); - } - Long durationInMs = testCase.durationInMs(); - if (durationInMs != null) { - builder.setDurationInMs(durationInMs.longValue()); - } - String msg = testCase.message(); - if (msg != null) { - builder.setMsg(msg); - } - String stack = testCase.stackTrace(); - if (stack != null) { - builder.setStacktrace(stack); - } - TestCase.Status status = testCase.status(); - if (status != null) { - builder.setStatus(TestStatus.valueOf(status.name())); - } - return builder.build(); - } - } - - private final class TestCoverageConverter implements Function { - private final MutableTestPlan testPlan; - private ScannerReport.CoverageDetail.Builder builder = ScannerReport.CoverageDetail.newBuilder(); - private ScannerReport.CoverageDetail.CoveredFile.Builder coveredBuilder = ScannerReport.CoverageDetail.CoveredFile.newBuilder(); - - private TestCoverageConverter(MutableTestPlan testPlan) { - this.testPlan = testPlan; - } +import static java.util.stream.Collectors.toList; - @Override - public CoverageDetail apply(@Nonnull String testName) { - // Take first test with provided name - MutableTestCase testCase = testPlan.testCasesByName(testName).iterator().next(); - builder.clear(); - builder.setTestName(testName); - for (CoverageBlock block : testCase.coverageBlocks()) { - coveredBuilder.clear(); - coveredBuilder.setFileRef(componentCache.get(((DefaultTestable) block.testable()).inputFile().key()).batchId()); - for (int line : block.lines()) { - coveredBuilder.addCoveredLine(line); - } - builder.addCoveredFile(coveredBuilder.build()); - } - return builder.build(); - } - } +public class TestExecutionAndCoveragePublisher implements ReportPublisherStep { private final BatchComponentCache componentCache; private final TestPlanBuilder testPlanBuilder; @@ -112,6 +51,9 @@ public class TestExecutionAndCoveragePublisher implements ReportPublisherStep { @Override public void publish(ScannerReportWriter writer) { + final ScannerReport.Test.Builder testBuilder = ScannerReport.Test.newBuilder(); + final ScannerReport.CoverageDetail.Builder builder = ScannerReport.CoverageDetail.newBuilder(); + final ScannerReport.CoverageDetail.CoveredFile.Builder coveredBuilder = ScannerReport.CoverageDetail.CoveredFile.newBuilder(); for (final BatchComponent component : componentCache.all()) { final MutableTestPlan testPlan = testPlanBuilder.loadPerspective(MutableTestPlan.class, component.inputComponent()); if (testPlan == null || Iterables.isEmpty(testPlan.testCases())) { @@ -120,9 +62,56 @@ public class TestExecutionAndCoveragePublisher implements ReportPublisherStep { final Set testNamesWithCoverage = new HashSet<>(); - writer.writeTests(component.batchId(), Iterables.transform(testPlan.testCases(), new TestConverter(testNamesWithCoverage))); + writer.writeTests(component.batchId(), + StreamSupport.stream(testPlan.testCases().spliterator(), false) + .map(testCase -> toProtobufTest(testBuilder, testNamesWithCoverage, testCase)) + .collect(toList())); - writer.writeCoverageDetails(component.batchId(), Iterables.transform(testNamesWithCoverage, new TestCoverageConverter(testPlan))); + writer.writeCoverageDetails(component.batchId(), testNamesWithCoverage.stream() + .map(testName -> toProtobufCoverageDetails(builder, coveredBuilder, testPlan, testName)) + .collect(toList())); + } + } + + private CoverageDetail toProtobufCoverageDetails(final ScannerReport.CoverageDetail.Builder builder, final ScannerReport.CoverageDetail.CoveredFile.Builder coveredBuilder, + final MutableTestPlan testPlan, String testName) { + // Take first test with provided name + MutableTestCase testCase = testPlan.testCasesByName(testName).iterator().next(); + builder.clear(); + builder.setTestName(testName); + for (CoverageBlock block : testCase.coverageBlocks()) { + coveredBuilder.clear(); + coveredBuilder.setFileRef(componentCache.get(((DefaultTestable) block.testable()).inputFile().key()).batchId()); + for (int line : block.lines()) { + coveredBuilder.addCoveredLine(line); + } + builder.addCoveredFile(coveredBuilder.build()); + } + return builder.build(); + } + + private static Test toProtobufTest(final ScannerReport.Test.Builder testBuilder, final Set testNamesWithCoverage, MutableTestCase testCase) { + testBuilder.clear(); + testBuilder.setName(testCase.name()); + if (testCase.doesCover()) { + testNamesWithCoverage.add(testCase.name()); + } + Long durationInMs = testCase.durationInMs(); + if (durationInMs != null) { + testBuilder.setDurationInMs(durationInMs.longValue()); + } + String msg = testCase.message(); + if (msg != null) { + testBuilder.setMsg(msg); + } + String stack = testCase.stackTrace(); + if (stack != null) { + testBuilder.setStacktrace(stack); + } + TestCase.Status status = testCase.status(); + if (status != null) { + testBuilder.setStatus(TestStatus.valueOf(status.name())); } + return testBuilder.build(); } } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/DefaultProjectRepositoriesLoader.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/DefaultProjectRepositoriesLoader.java index cea4a21ba17..abdefcae436 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/DefaultProjectRepositoriesLoader.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/DefaultProjectRepositoriesLoader.java @@ -20,22 +20,20 @@ package org.sonar.scanner.repository; import com.google.common.base.Throwables; - import com.google.common.collect.HashBasedTable; import com.google.common.collect.Table; - import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.util.Date; import java.util.Map; - import org.apache.commons.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.api.utils.MessageException; import org.sonar.scanner.bootstrap.BatchWsClient; import org.sonar.scanner.util.BatchUtils; +import org.sonarqube.ws.WsBatch; import org.sonarqube.ws.WsBatch.WsProjectResponse; import org.sonarqube.ws.WsBatch.WsProjectResponse.FileDataByPath; import org.sonarqube.ws.WsBatch.WsProjectResponse.Settings; @@ -109,7 +107,7 @@ public class DefaultProjectRepositoriesLoader implements ProjectRepositoriesLoad Map fileDataByModuleAndPath = response.getFileDataByModuleAndPath(); for (Map.Entry e1 : fileDataByModuleAndPath.entrySet()) { - for (Map.Entry e2 : e1.getValue().getFileDataByPath().entrySet()) { + for (Map.Entry e2 : e1.getValue().getFileDataByPath().entrySet()) { FileData fd = new FileData(e2.getValue().getHash(), e2.getValue().getRevision()); fileDataTable.put(e1.getKey(), e2.getKey(), fd); } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/DefaultActiveRulesLoader.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/DefaultActiveRulesLoader.java index acff8ed90a1..7df5a23f820 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/DefaultActiveRulesLoader.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/DefaultActiveRulesLoader.java @@ -25,17 +25,17 @@ import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; - import org.apache.commons.io.IOUtils; import org.sonar.api.rule.RuleKey; import org.sonar.scanner.bootstrap.BatchWsClient; import org.sonar.scanner.util.BatchUtils; +import org.sonarqube.ws.Rules; import org.sonarqube.ws.Rules.Active; import org.sonarqube.ws.Rules.Active.Param; -import org.sonarqube.ws.client.GetRequest; import org.sonarqube.ws.Rules.ActiveList; import org.sonarqube.ws.Rules.Rule; import org.sonarqube.ws.Rules.SearchResponse; +import org.sonarqube.ws.client.GetRequest; public class DefaultActiveRulesLoader implements ActiveRulesLoader { private static final String RULES_SEARCH_URL = "/api/rules/search.protobuf?f=repo,name,severity,lang,internalKey,templateKey,params,actives&activation=true"; @@ -112,7 +112,7 @@ public class DefaultActiveRulesLoader implements ActiveRulesLoader { Map params = new HashMap<>(); - for (org.sonarqube.ws.Rules.Rule.Param param : r.getParams().getParamsList()) { + for (Rules.Rule.Param param : r.getParams().getParamsList()) { params.put(param.getKey(), param.getDefaultValue()); } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/FileIndexer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/FileIndexer.java index 75c9e927cc0..adb316b5669 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/FileIndexer.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/FileIndexer.java @@ -35,7 +35,6 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; -import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -160,22 +159,19 @@ public class FileIndexer { private void indexFile(final InputFileBuilder inputFileBuilder, final DefaultModuleFileSystem fs, final Progress status, final DefaultInputFile inputFile, final InputFile.Type type) { - tasks.add(executorService.submit(new Callable() { - @Override - public Void call() { - DefaultInputFile completedInputFile = inputFileBuilder.completeAndComputeMetadata(inputFile, type); - if (completedInputFile != null && accept(completedInputFile)) { - fs.add(completedInputFile); - status.markAsIndexed(completedInputFile); - File parentDir = completedInputFile.file().getParentFile(); - String relativePath = new PathResolver().relativePath(fs.baseDir(), parentDir); - if (relativePath != null) { - DefaultInputDir inputDir = new DefaultInputDir(fs.moduleKey(), relativePath); - fs.add(inputDir); - } + tasks.add(executorService.submit(() -> { + DefaultInputFile completedInputFile = inputFileBuilder.completeAndComputeMetadata(inputFile, type); + if (completedInputFile != null && accept(completedInputFile)) { + fs.add(completedInputFile); + status.markAsIndexed(completedInputFile); + File parentDir = completedInputFile.file().getParentFile(); + String relativePath = new PathResolver().relativePath(fs.baseDir(), parentDir); + if (relativePath != null) { + DefaultInputDir inputDir = new DefaultInputDir(fs.moduleKey(), relativePath); + fs.add(inputDir); } - return null; } + return null; })); } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/measure/DeprecatedMetricFinder.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/measure/DeprecatedMetricFinder.java index 38de10c1031..394c7d480ce 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/measure/DeprecatedMetricFinder.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/measure/DeprecatedMetricFinder.java @@ -21,13 +21,13 @@ package org.sonar.scanner.scan.measure; import com.google.common.collect.Lists; import com.google.common.collect.Maps; -import org.sonar.api.measures.Metric; -import org.sonar.api.measures.Metric.ValueType; -import org.sonar.scanner.protocol.input.GlobalRepositories; -import org.sonar.api.measures.MetricFinder; import java.util.Collection; import java.util.List; import java.util.Map; +import org.sonar.api.measures.Metric; +import org.sonar.api.measures.Metric.ValueType; +import org.sonar.api.measures.MetricFinder; +import org.sonar.scanner.protocol.input.GlobalRepositories; public final class DeprecatedMetricFinder implements MetricFinder { @@ -36,7 +36,7 @@ public final class DeprecatedMetricFinder implements MetricFinder { public DeprecatedMetricFinder(GlobalRepositories globalReferentials) { for (org.sonar.scanner.protocol.input.Metric metric : globalReferentials.metrics()) { - Metric hibernateMetric = new org.sonar.api.measures.Metric.Builder(metric.key(), metric.name(), ValueType.valueOf(metric.valueType())) + Metric hibernateMetric = new Metric.Builder(metric.key(), metric.name(), ValueType.valueOf(metric.valueType())) .create() .setDirection(metric.direction()) .setQualitative(metric.isQualitative()) @@ -47,7 +47,7 @@ public final class DeprecatedMetricFinder implements MetricFinder { .setWorstValue(metric.worstValue()) .setId(metric.id()); metricsByKey.put(metric.key(), hibernateMetric); - metricsById.put(metric.id(), new org.sonar.api.measures.Metric.Builder(metric.key(), metric.key(), ValueType.valueOf(metric.valueType())).create().setId(metric.id())); + metricsById.put(metric.id(), new Metric.Builder(metric.key(), metric.key(), ValueType.valueOf(metric.valueType())).create().setId(metric.id())); } } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultSensorStorage.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultSensorStorage.java index 908c5320e55..218754a197d 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultSensorStorage.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultSensorStorage.java @@ -20,8 +20,6 @@ package org.sonar.scanner.sensor; import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Function; -import com.google.common.collect.Iterables; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; @@ -32,7 +30,6 @@ import java.util.Set; import java.util.TreeMap; import java.util.stream.Collectors; import java.util.stream.Stream; -import javax.annotation.Nonnull; import org.sonar.api.batch.fs.InputComponent; import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.fs.TextRange; @@ -43,7 +40,6 @@ import org.sonar.api.batch.sensor.coverage.internal.DefaultCoverage; import org.sonar.api.batch.sensor.cpd.internal.DefaultCpdTokens; import org.sonar.api.batch.sensor.error.AnalysisError; import org.sonar.api.batch.sensor.highlighting.internal.DefaultHighlighting; -import org.sonar.api.batch.sensor.highlighting.internal.SyntaxHighlightingRule; import org.sonar.api.batch.sensor.internal.SensorStorage; import org.sonar.api.batch.sensor.issue.Issue; import org.sonar.api.batch.sensor.measure.Measure; @@ -70,6 +66,7 @@ import org.sonar.scanner.repository.ContextPropertiesCache; import org.sonar.scanner.scan.measure.MeasureCache; import org.sonar.scanner.sensor.coverage.CoverageExclusions; +import static java.util.stream.Collectors.toList; import static org.sonar.api.measures.CoreMetrics.BRANCH_COVERAGE; import static org.sonar.api.measures.CoreMetrics.COMMENTED_OUT_CODE_LINES_KEY; import static org.sonar.api.measures.CoreMetrics.CONDITIONS_BY_LINE; @@ -361,8 +358,20 @@ public class DefaultSensorStorage implements SensorStorage { if (writer.hasComponentData(FileStructure.Domain.SYNTAX_HIGHLIGHTINGS, componentRef)) { throw new UnsupportedOperationException("Trying to save highlighting twice for the same file is not supported: " + inputFile.absolutePath()); } + final ScannerReport.SyntaxHighlightingRule.Builder builder = ScannerReport.SyntaxHighlightingRule.newBuilder(); + final ScannerReport.TextRange.Builder rangeBuilder = ScannerReport.TextRange.newBuilder(); + writer.writeComponentSyntaxHighlighting(componentRef, - Iterables.transform(highlighting.getSyntaxHighlightingRuleSet(), new BuildSyntaxHighlighting())); + highlighting.getSyntaxHighlightingRuleSet().stream() + .map(input -> { + builder.setRange(rangeBuilder.setStartLine(input.range().start().line()) + .setStartOffset(input.range().start().lineOffset()) + .setEndLine(input.range().end().line()) + .setEndOffset(input.range().end().lineOffset()) + .build()); + builder.setType(ScannerReportUtils.toProtocolType(input.getTextType())); + return builder.build(); + }).collect(toList())); } @Override @@ -372,13 +381,11 @@ public class DefaultSensorStorage implements SensorStorage { if (writer.hasComponentData(FileStructure.Domain.SYMBOLS, componentRef)) { throw new UnsupportedOperationException("Trying to save symbol table twice for the same file is not supported: " + symbolTable.inputFile().absolutePath()); } + final ScannerReport.Symbol.Builder builder = ScannerReport.Symbol.newBuilder(); + final ScannerReport.TextRange.Builder rangeBuilder = ScannerReport.TextRange.newBuilder(); writer.writeComponentSymbols(componentRef, - Iterables.transform(symbolTable.getReferencesBySymbol().entrySet(), new Function>, ScannerReport.Symbol>() { - private ScannerReport.Symbol.Builder builder = ScannerReport.Symbol.newBuilder(); - private ScannerReport.TextRange.Builder rangeBuilder = ScannerReport.TextRange.newBuilder(); - - @Override - public ScannerReport.Symbol apply(Map.Entry> input) { + symbolTable.getReferencesBySymbol().entrySet().stream() + .map(input -> { builder.clear(); rangeBuilder.clear(); TextRange declaration = input.getKey(); @@ -395,9 +402,7 @@ public class DefaultSensorStorage implements SensorStorage { .build()); } return builder.build(); - } - - })); + }).collect(Collectors.toList())); } @Override @@ -424,22 +429,6 @@ public class DefaultSensorStorage implements SensorStorage { } } - private static class BuildSyntaxHighlighting implements Function { - private ScannerReport.SyntaxHighlightingRule.Builder builder = ScannerReport.SyntaxHighlightingRule.newBuilder(); - private ScannerReport.TextRange.Builder rangeBuilder = ScannerReport.TextRange.newBuilder(); - - @Override - public ScannerReport.SyntaxHighlightingRule apply(@Nonnull SyntaxHighlightingRule input) { - builder.setRange(rangeBuilder.setStartLine(input.range().start().line()) - .setStartOffset(input.range().start().lineOffset()) - .setEndLine(input.range().end().line()) - .setEndOffset(input.range().end().lineOffset()) - .build()); - builder.setType(ScannerReportUtils.toProtocolType(input.getTextType())); - return builder.build(); - } - } - @Override public void store(DefaultCpdTokens defaultCpdTokens) { InputFile inputFile = defaultCpdTokens.inputFile(); diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/source/DefaultHighlightable.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/source/DefaultHighlightable.java index 565525067dd..357ae80d801 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/source/DefaultHighlightable.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/source/DefaultHighlightable.java @@ -81,14 +81,14 @@ public class DefaultHighlightable implements Highlightable { @Override public HighlightingBuilder highlight(int startOffset, int endOffset, String typeOfText) { - TypeOfText type = org.sonar.api.batch.sensor.highlighting.TypeOfText.forCssClass(typeOfText); + TypeOfText type = TypeOfText.forCssClass(typeOfText); defaultHighlighting.highlight(startOffset, endOffset, type); return this; } @Override public HighlightingBuilder highlight(int startLine, int startLineOffset, int endLine, int endLineOffset, String typeOfText) { - TypeOfText type = org.sonar.api.batch.sensor.highlighting.TypeOfText.forCssClass(typeOfText); + TypeOfText type = TypeOfText.forCssClass(typeOfText); defaultHighlighting.highlight(startLine, startLineOffset, endLine, endLineOffset, type); return this; } diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/cpd/CpdExecutorTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/cpd/CpdExecutorTest.java index 24d1023ade2..621870c4c2f 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/cpd/CpdExecutorTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/cpd/CpdExecutorTest.java @@ -28,15 +28,19 @@ import java.util.List; import org.junit.Before; import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import org.junit.rules.TemporaryFolder; +import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.fs.internal.DefaultInputFile; import org.sonar.api.batch.fs.internal.DefaultInputModule; -import org.sonar.api.config.Settings; import org.sonar.api.config.MapSettings; +import org.sonar.api.config.Settings; import org.sonar.api.resources.Project; import org.sonar.api.utils.log.LogTester; import org.sonar.api.utils.log.LoggerLevel; import org.sonar.core.util.CloseableIterator; +import org.sonar.duplications.block.Block; +import org.sonar.duplications.block.ByteArray; import org.sonar.duplications.index.CloneGroup; import org.sonar.duplications.index.ClonePart; import org.sonar.scanner.cpd.index.SonarCpdBlockIndex; @@ -65,22 +69,25 @@ public class CpdExecutorTest { @Rule public TemporaryFolder temp = new TemporaryFolder(); - // private AbstractCpdEngine engine; + @Rule + public ExpectedException thrown = ExpectedException.none(); private ScannerReportReader reader; private BatchComponent batchComponent1; private BatchComponent batchComponent2; private BatchComponent batchComponent3; + private File baseDir; @Before public void setUp() throws IOException { File outputDir = temp.newFolder(); + baseDir = temp.newFolder(); settings = new MapSettings(); - index = mock(SonarCpdBlockIndex.class); publisher = mock(ReportPublisher.class); when(publisher.getWriter()).thenReturn(new ScannerReportWriter(outputDir)); componentCache = new BatchComponentCache(); + index = new SonarCpdBlockIndex(publisher, componentCache, settings); executor = new CpdExecutor(settings, index, publisher, componentCache); reader = new ScannerReportReader(outputDir); @@ -94,7 +101,10 @@ public class CpdExecutorTest { private BatchComponent createComponent(String relativePath, int lines) { org.sonar.api.resources.Resource sampleFile = org.sonar.api.resources.File.create("relativePath").setEffectiveKey("foo:" + relativePath); - return componentCache.add(sampleFile, null).setInputComponent(new DefaultInputFile("foo", relativePath).setLines(lines)); + return componentCache.add(sampleFile, null) + .setInputComponent(new DefaultInputFile("foo", relativePath) + .setModuleBaseDir(baseDir.toPath()) + .setLines(lines)); } @Test @@ -197,6 +207,39 @@ public class CpdExecutorTest { assertDuplication(dups[1], 15, 214, batchComponent3.batchId(), 15, 214); } + @Test + public void failOnMissingComponent() { + executor.runCpdAnalysis(null, "unknown", Collections.emptyList(), 1); + readDuplications(0); + assertThat(logTester.logs(LoggerLevel.ERROR)).contains("Resource not found in component cache: unknown. Skipping CPD computation for it"); + } + + @Test + public void timeout() { + for (int i = 1; i <= 2; i++) { + BatchComponent component = createComponent("src/Foo" + i + ".php", 100); + List blocks = new ArrayList<>(); + for (int j = 1; j <= 100000; j++) { + blocks.add(Block.builder() + .setResourceId(component.key()) + .setIndexInFile(j) + .setLines(j, j + 1) + .setUnit(j, j + 1) + .setBlockHash(new ByteArray("abcd1234".getBytes())) + .build()); + } + index.insert((InputFile) component.inputComponent(), blocks); + } + executor.execute(1); + + readDuplications(0); + assertThat(logTester.logs(LoggerLevel.WARN)) + .usingElementComparator((l, r) -> l.matches(r) ? 0 : 1) + .containsOnly( + "Timeout during detection of duplications for .*Foo1.php", + "Timeout during detection of duplications for .*Foo2.php"); + } + private Duplication[] readDuplications(int expected) { assertThat(reader.readComponentDuplications(batchComponent1.batchId())).hasSize(expected); Duplication[] duplications = new Duplication[expected]; -- 2.39.5