瀏覽代碼

Fix quality flaws

tags/6.3-RC1
Julien HENRY 7 年之前
父節點
當前提交
bd28d90a20
共有 31 個檔案被更改,包括 271 行新增355 行删除
  1. 1
    7
      server/sonar-server/src/main/java/org/sonar/server/issue/SetSeverityAction.java
  2. 2
    8
      server/sonar-server/src/main/java/org/sonar/server/notification/DefaultNotificationManager.java
  3. 16
    8
      sonar-core/src/main/java/org/sonar/core/issue/DefaultIssue.java
  4. 1
    7
      sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/AbstractFilePredicate.java
  5. 1
    18
      sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultFileSystem.java
  6. 1
    0
      sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/FileMetadata.java
  7. 5
    9
      sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/highlighting/internal/DefaultHighlighting.java
  8. 4
    15
      sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssue.java
  9. 1
    7
      sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/symbol/internal/DefaultSymbolTable.java
  10. 5
    10
      sonar-scanner-engine/src/main/java/org/sonar/scanner/DefaultFileLinesContext.java
  11. 19
    16
      sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/CpdExecutor.java
  12. 10
    14
      sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/index/SonarCpdBlockIndex.java
  13. 1
    1
      sonar-scanner-engine/src/main/java/org/sonar/scanner/index/DefaultIndex.java
  14. 5
    15
      sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/tracking/FileHashes.java
  15. 1
    1
      sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/InitializerExecutionEvent.java
  16. 2
    3
      sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/InitializersPhaseEvent.java
  17. 1
    1
      sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/PostJobExecutionEvent.java
  18. 2
    3
      sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/PostJobPhaseEvent.java
  19. 1
    1
      sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/ProjectAnalysisEvent.java
  20. 1
    1
      sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/SensorExecutionEvent.java
  21. 2
    9
      sonar-scanner-engine/src/main/java/org/sonar/scanner/profiling/AbstractTimeProfiling.java
  22. 12
    19
      sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ActiveRulesPublisher.java
  23. 32
    52
      sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MeasuresPublisher.java
  24. 55
    66
      sonar-scanner-engine/src/main/java/org/sonar/scanner/report/TestExecutionAndCoveragePublisher.java
  25. 2
    4
      sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/DefaultProjectRepositoriesLoader.java
  26. 3
    3
      sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/DefaultActiveRulesLoader.java
  27. 11
    15
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/FileIndexer.java
  28. 6
    6
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/measure/DeprecatedMetricFinder.java
  29. 19
    30
      sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultSensorStorage.java
  30. 2
    2
      sonar-scanner-engine/src/main/java/org/sonar/scanner/source/DefaultHighlightable.java
  31. 47
    4
      sonar-scanner-engine/src/test/java/org/sonar/scanner/cpd/CpdExecutorTest.java

+ 1
- 7
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) {

+ 2
- 8
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> notification) {
notificationQueueDao.insert(Lists.transform(notification, new Function<Notification, NotificationQueueDto>() {
@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<String, NotificationChannel> findSubscribedRecipientsForDispatcher(NotificationDispatcher dispatcher,
@Nullable String projectUuid) {
@Nullable String projectUuid) {
String dispatcherKey = dispatcher.getKey();

SetMultimap<String, NotificationChannel> recipients = HashMultimap.create();

+ 16
- 8
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> T getLocations() {
return (T)locations;
return (T) locations;
}

public DefaultIssue setLocations(@Nullable Object locations) {

+ 1
- 7
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<InputFile> filter(Iterable<InputFile> target) {
return Iterables.filter(target, new Predicate<InputFile>() {
@Override
public boolean apply(InputFile input) {
return AbstractFilePredicate.this.apply(input);
}
});
return Iterables.filter(target, this::apply);
}

@Override

+ 1
- 18
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<File> files(FilePredicate predicate) {
doPreloadFiles();
return Iterables.transform(inputFiles(predicate), new Function<InputFile, File>() {
@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<InputFile> inputFiles();

@Override
@CheckForNull
public abstract InputFile inputFile(String relativePath);

@Override
@CheckForNull
public abstract InputDir inputDir(String relativePath);

protected abstract void doAdd(InputFile inputFile);


+ 1
- 0
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);

+ 5
- 9
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<SyntaxHighlightingRule>() {
@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);

+ 4
- 15
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<List<IssueLocation>, Flow> {
@Override
public Flow apply(final List<IssueLocation> input) {
return new Flow() {
@Override
public List<IssueLocation> 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<Flow> flows() {
return Lists.transform(this.flows, new ToFlow());
return this.flows.stream()
.<Flow>map(l -> () -> ImmutableList.copyOf(l))
.collect(toList());
}

@Override

+ 1
- 7
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<TextRange> references = new TreeSet<>(new Comparator<TextRange>() {
@Override
public int compare(TextRange o1, TextRange o2) {
return o1.start().compareTo(o2.start());
}
});
TreeSet<TextRange> references = new TreeSet<>((o1, o2) -> o1.start().compareTo(o2.start()));
referencesBySymbol.put(range, references);
return new DefaultSymbol(inputFile, range, references);
}

+ 5
- 10
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<Object> LINES_WITH_NON_ZERO_VALUE = new Predicate<Object>() {
@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<Integer, Object> 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<Integer, Object>::getKey, Entry<Integer, Object>::getValue));
}
return lines;
}

+ 19
- 16
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<ResourceBlocks> 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<Block> fileBlocks) {
LOG.debug("Detection of duplications for {}", resource);

BatchComponent component = batchComponentCache.get(resource);
@VisibleForTesting
void runCpdAnalysis(ExecutorService executorService, String componentKey, final Collection<Block> 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<CloneGroup> duplications;
Future<List<CloneGroup>> futureResult = null;
Future<List<CloneGroup>> 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<org.sonar.scanner.protocol.output.ScannerReport.Duplication> reportDuplications = from(duplications)
Iterable<ScannerReport.Duplication> reportDuplications = from(duplications)
.limit(MAX_CLONE_GROUP_PER_FILE)
.transform(
new Function<CloneGroup, ScannerReport.Duplication>() {

+ 10
- 14
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<Block, ScannerReport.CpdTextBlock>() {
@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);

+ 1
- 1
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;
}

+ 5
- 15
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<String, Integer> linesByHash = LinkedHashMultimap.create();
@@ -84,7 +74,7 @@ public final class FileHashes {
public Collection<Integer> getLinesForHash(String hash) {
return linesByHash.get(hash);
}
public String[] hashes() {
return hashes;
}

+ 1
- 1
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<InitializerExecutionHandler>
implements org.sonar.api.batch.events.InitializerExecutionHandler.InitializerExecutionEvent {
implements InitializerExecutionHandler.InitializerExecutionEvent {

private final Initializer initializer;


+ 2
- 3
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<InitializersPhaseHandler>
implements org.sonar.api.batch.events.InitializersPhaseHandler.InitializersPhaseEvent {
implements InitializersPhaseHandler.InitializersPhaseEvent {

private final List<Initializer> initializers;


+ 1
- 1
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<PostJobExecutionHandler>
implements org.sonar.api.batch.events.PostJobExecutionHandler.PostJobExecutionEvent {
implements PostJobExecutionHandler.PostJobExecutionEvent {

private final PostJob postJob;


+ 2
- 3
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<PostJobsPhaseHandler>
implements org.sonar.api.batch.events.PostJobsPhaseHandler.PostJobsPhaseEvent {
implements PostJobsPhaseHandler.PostJobsPhaseEvent {

private final List<PostJob> postJobs;


+ 1
- 1
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<ProjectAnalysisHandler>
implements org.sonar.api.batch.events.ProjectAnalysisHandler.ProjectAnalysisEvent {
implements ProjectAnalysisHandler.ProjectAnalysisEvent {

private final Project project;


+ 1
- 1
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<SensorExecutionHandler>
implements org.sonar.api.batch.events.SensorExecutionHandler.SensorExecutionEvent {
implements SensorExecutionHandler.SensorExecutionEvent {

private final Sensor sensor;


+ 2
- 9
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 <G extends AbstractTimeProfiling> Map<Object, G> sortByDescendingTotalTime(Map<?, G> unsorted) {
List<Map.Entry<?, G>> entries =
new ArrayList<Map.Entry<?, G>>(unsorted.entrySet());
Collections.sort(entries, new Comparator<Map.Entry<?, G>>() {
@Override
public int compare(Map.Entry<?, G> o1, Map.Entry<?, G> o2) {
return Long.valueOf(o2.getValue().totalTime()).compareTo(o1.getValue().totalTime());
}
});
List<Map.Entry<?, G>> entries = new ArrayList<>(unsorted.entrySet());
Collections.sort(entries, (o1, o2) -> Long.valueOf(o2.getValue().totalTime()).compareTo(o1.getValue().totalTime()));
Map<Object, G> sortedMap = new LinkedHashMap<>();
for (Map.Entry<?, G> entry : entries) {
sortedMap.put(entry.getKey(), entry.getValue());

+ 12
- 19
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<ScannerReport.ActiveRule> 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<ActiveRule, ScannerReport.ActiveRule> {
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();
}
}
}

+ 32
- 52
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<DefaultMeasure, ScannerReport.Measure> {
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<DefaultMeasure<?>> scannerMeasures = measureCache.byComponentKey(component.key());
Iterable<ScannerReport.Measure> 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());
}
}


+ 55
- 66
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<MutableTestCase, ScannerReport.Test> {
private final Set<String> testNamesWithCoverage;
private ScannerReport.Test.Builder builder = ScannerReport.Test.newBuilder();

private TestConverter(Set<String> 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<String, CoverageDetail> {
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<String> 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<String> 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();
}
}

+ 2
- 4
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<String, FileDataByPath> fileDataByModuleAndPath = response.getFileDataByModuleAndPath();
for (Map.Entry<String, FileDataByPath> e1 : fileDataByModuleAndPath.entrySet()) {
for (Map.Entry<String, org.sonarqube.ws.WsBatch.WsProjectResponse.FileData> e2 : e1.getValue().getFileDataByPath().entrySet()) {
for (Map.Entry<String, WsBatch.WsProjectResponse.FileData> e2 : e1.getValue().getFileDataByPath().entrySet()) {
FileData fd = new FileData(e2.getValue().getHash(), e2.getValue().getRevision());
fileDataTable.put(e1.getKey(), e2.getKey(), fd);
}

+ 3
- 3
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<String, String> 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());
}


+ 11
- 15
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<Void>() {
@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;
}));

}

+ 6
- 6
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()));
}
}


+ 19
- 30
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<Map.Entry<TextRange, Set<TextRange>>, 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<TextRange, Set<TextRange>> 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<SyntaxHighlightingRule, ScannerReport.SyntaxHighlightingRule> {
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();

+ 2
- 2
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;
}

+ 47
- 4
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<Block> 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];

Loading…
取消
儲存