aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-scanner-engine/src/main/java
diff options
context:
space:
mode:
authorJulien HENRY <julien.henry@sonarsource.com>2024-07-25 16:04:01 +0200
committersonartech <sonartech@sonarsource.com>2024-07-26 20:02:48 +0000
commit1cc9d9b40e1bd6643aa9ebc3b031ccfe8f696cc4 (patch)
tree71018b6620d13d5e5bb5d925eb67b6c9ca7f7eba /sonar-scanner-engine/src/main/java
parenta03200b5b3dc0f175756a6b3b814888d019f8ce8 (diff)
downloadsonarqube-1cc9d9b40e1bd6643aa9ebc3b031ccfe8f696cc4.tar.gz
sonarqube-1cc9d9b40e1bd6643aa9ebc3b031ccfe8f696cc4.zip
SONAR-22541 Import SARIF stacks as issue flows
Diffstat (limited to 'sonar-scanner-engine/src/main/java')
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/externalissue/sarif/LocationMapper.java21
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/externalissue/sarif/ResultMapper.java95
2 files changed, 85 insertions, 31 deletions
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/externalissue/sarif/LocationMapper.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/externalissue/sarif/LocationMapper.java
index df816a466d7..4b668c90d56 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/externalissue/sarif/LocationMapper.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/externalissue/sarif/LocationMapper.java
@@ -30,7 +30,6 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
-import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.jetbrains.annotations.NotNull;
import org.sonar.api.batch.fs.InputFile;
@@ -41,9 +40,7 @@ import org.sonar.api.scanner.ScannerSide;
import org.sonar.sarif.pojo.ArtifactLocation;
import org.sonar.sarif.pojo.Location;
import org.sonar.sarif.pojo.PhysicalLocation;
-import org.sonar.sarif.pojo.Result;
-import static java.util.Objects.requireNonNull;
import static org.sonar.api.utils.Preconditions.checkArgument;
@ScannerSide
@@ -65,31 +62,23 @@ public class LocationMapper {
this.regionMapper = regionMapper;
}
- NewIssueLocation fillIssueInProjectLocation(Result result, NewIssueLocation newIssueLocation) {
- return newIssueLocation
- .message(getResultMessageOrThrow(result))
+ void fillIssueInProjectLocation(NewIssueLocation newIssueLocation) {
+ newIssueLocation
.on(sensorContext.project());
}
- @CheckForNull
- NewIssueLocation fillIssueInFileLocation(Result result, NewIssueLocation newIssueLocation, Location location) {
- newIssueLocation.message(getResultMessageOrThrow(result));
+ boolean fillIssueInFileLocation(NewIssueLocation newIssueLocation, Location location) {
PhysicalLocation physicalLocation = location.getPhysicalLocation();
String fileUri = getFileUriOrThrow(location);
Optional<InputFile> file = findFile(fileUri);
if (file.isEmpty()) {
- return null;
+ return false;
}
InputFile inputFile = file.get();
newIssueLocation.on(inputFile);
regionMapper.mapRegion(physicalLocation.getRegion(), inputFile).ifPresent(newIssueLocation::at);
- return newIssueLocation;
- }
-
- private static String getResultMessageOrThrow(Result result) {
- requireNonNull(result.getMessage(), "No messages found for issue thrown by rule " + result.getRuleId());
- return requireNonNull(result.getMessage().getText(), "No text found for messages in issue thrown by rule " + result.getRuleId());
+ return true;
}
private static String getFileUriOrThrow(Location location) {
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/externalissue/sarif/ResultMapper.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/externalissue/sarif/ResultMapper.java
index 21e85505172..05f8fa09b6e 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/externalissue/sarif/ResultMapper.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/externalissue/sarif/ResultMapper.java
@@ -20,10 +20,13 @@
package org.sonar.scanner.externalissue.sarif;
import com.google.common.collect.ImmutableMap;
+import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Optional;
import java.util.Set;
+import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.sonar.api.batch.rule.Severity;
import org.sonar.api.batch.sensor.SensorContext;
@@ -34,7 +37,9 @@ import org.sonar.api.rules.CleanCodeAttribute;
import org.sonar.api.rules.RuleType;
import org.sonar.api.scanner.ScannerSide;
import org.sonar.sarif.pojo.Location;
+import org.sonar.sarif.pojo.Message;
import org.sonar.sarif.pojo.Result;
+import org.sonar.sarif.pojo.Stack;
import static java.util.Objects.requireNonNull;
import static org.sonar.api.issue.impact.Severity.HIGH;
@@ -96,29 +101,89 @@ public class ResultMapper {
}
private void mapLocations(Result result, NewExternalIssue newExternalIssue) {
- NewIssueLocation newIssueLocation = newExternalIssue.newLocation();
- List<Location> locations = result.getLocations();
- if (locations == null || locations.isEmpty()) {
- newExternalIssue.at(locationMapper.fillIssueInProjectLocation(result, newIssueLocation));
- } else {
- Location firstLocation = locations.iterator().next();
- NewIssueLocation primaryLocation = fillFileOrProjectLocation(result, newIssueLocation, firstLocation);
- newExternalIssue.at(primaryLocation);
+ createPrimaryLocation(newExternalIssue, result);
+ createSecondaryLocations(result, newExternalIssue);
+ createFlows(result, newExternalIssue);
+ }
+
+ private void createFlows(Result result, NewExternalIssue newExternalIssue) {
+ Set<Stack> stacks = Optional.ofNullable(result.getStacks()).orElse(Set.of());
+ if (!stacks.isEmpty()) {
+ stacks.forEach(stack -> {
+ var frames = Optional.ofNullable(stack.getFrames()).orElse(List.of());
+ if (!frames.isEmpty()) {
+ List<NewIssueLocation> flow = new ArrayList<>();
+ frames.forEach(frame -> {
+ var frameLocation = frame.getLocation();
+ if (frameLocation != null) {
+ var newFrameLocation = createIssueLocation(newExternalIssue, frameLocation);
+ flow.add(newFrameLocation);
+ }
+ });
+ newExternalIssue.addFlow(flow);
+ }
+ });
}
+ }
- Set<Location> relatedLocations = result.getRelatedLocations();
- if (relatedLocations != null && !relatedLocations.isEmpty()) {
+ private void createSecondaryLocations(Result result, NewExternalIssue newExternalIssue) {
+ Set<Location> relatedLocations = Optional.ofNullable(result.getRelatedLocations()).orElse(Set.of());
+ if (!relatedLocations.isEmpty()) {
relatedLocations.forEach(relatedLocation -> {
- NewIssueLocation newRelatedLocation = newExternalIssue.newLocation();
- fillFileOrProjectLocation(result, newRelatedLocation, relatedLocation);
+ var newRelatedLocation = createIssueLocation(newExternalIssue, relatedLocation);
newExternalIssue.addLocation(newRelatedLocation);
});
}
}
- private NewIssueLocation fillFileOrProjectLocation(Result result, NewIssueLocation newIssueLocation, Location firstLocation) {
- return Optional.ofNullable(locationMapper.fillIssueInFileLocation(result, newIssueLocation, firstLocation))
- .orElseGet(() -> locationMapper.fillIssueInProjectLocation(result, newIssueLocation));
+ private NewIssueLocation createIssueLocation(NewExternalIssue newExternalIssue, Location sarifLocation) {
+ NewIssueLocation newRelatedLocation = newExternalIssue.newLocation();
+ var locationMessageText = getTextMessageOrNull(sarifLocation.getMessage());
+ if (locationMessageText != null) {
+ newRelatedLocation.message(locationMessageText);
+ }
+ fillFileOrProjectLocation(newRelatedLocation, sarifLocation);
+ return newRelatedLocation;
+ }
+
+ private void createPrimaryLocation(NewExternalIssue newExternalIssue, Result result) {
+ NewIssueLocation sonarLocation = newExternalIssue.newLocation();
+ List<Location> sarifLocations = Optional.ofNullable(result.getLocations()).orElse(List.of());
+ var primaryMessage = computePrimaryMessage(result, sarifLocations);
+ sonarLocation.message(primaryMessage);
+ if (sarifLocations.isEmpty()) {
+ locationMapper.fillIssueInProjectLocation(sonarLocation);
+ } else {
+ Location firstSarifLocation = sarifLocations.get(0);
+ fillFileOrProjectLocation(sonarLocation, firstSarifLocation);
+ }
+ newExternalIssue.at(sonarLocation);
+ }
+
+ private static String computePrimaryMessage(Result result, List<Location> locations) {
+ String resultMessage = Objects.requireNonNull(result.getMessage().getText(), "Message text is required on result");
+ if (!locations.isEmpty()) {
+ Location firstLocation = locations.get(0);
+ var locationMessageText = getTextMessageOrNull(firstLocation.getMessage());
+ if (locationMessageText != null) {
+ return resultMessage + " - " + locationMessageText;
+ }
+ }
+ return resultMessage;
+ }
+
+ @CheckForNull
+ private static String getTextMessageOrNull(@Nullable Message message) {
+ if (message == null) {
+ return null;
+ }
+ return message.getText();
+ }
+
+ private void fillFileOrProjectLocation(NewIssueLocation newIssueLocation, Location firstLocation) {
+ if (!locationMapper.fillIssueInFileLocation(newIssueLocation, firstLocation)) {
+ locationMapper.fillIssueInProjectLocation(newIssueLocation);
+ }
}
}