diff options
author | Julien HENRY <julien.henry@sonarsource.com> | 2024-07-25 16:04:01 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2024-07-26 20:02:48 +0000 |
commit | 1cc9d9b40e1bd6643aa9ebc3b031ccfe8f696cc4 (patch) | |
tree | 71018b6620d13d5e5bb5d925eb67b6c9ca7f7eba /sonar-scanner-engine/src/main/java | |
parent | a03200b5b3dc0f175756a6b3b814888d019f8ce8 (diff) | |
download | sonarqube-1cc9d9b40e1bd6643aa9ebc3b031ccfe8f696cc4.tar.gz sonarqube-1cc9d9b40e1bd6643aa9ebc3b031ccfe8f696cc4.zip |
SONAR-22541 Import SARIF stacks as issue flows
Diffstat (limited to 'sonar-scanner-engine/src/main/java')
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); + } } } |