aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJacek <jacek.poreda@sonarsource.com>2022-08-04 10:43:44 +0200
committersonartech <sonartech@sonarsource.com>2022-08-04 20:03:08 +0000
commit05711eb23f12d08abc53e3722921f906a56ba35b (patch)
tree8004c6b5751fea188692f2d0088be5a803e2edcc
parenta4f68e401d861e24eacc9f761561ad2288b9b364 (diff)
downloadsonarqube-05711eb23f12d08abc53e3722921f906a56ba35b.tar.gz
sonarqube-05711eb23f12d08abc53e3722921f906a56ba35b.zip
SONAR-16583 Fix NPE in case location is in the same file
-rw-r--r--server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/ComputeLocationHashesVisitor.java9
-rw-r--r--server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/ComputeLocationHashesVisitorTest.java34
2 files changed, 40 insertions, 3 deletions
diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/ComputeLocationHashesVisitor.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/ComputeLocationHashesVisitor.java
index 7a9f4fdf220..b85ccaeff92 100644
--- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/ComputeLocationHashesVisitor.java
+++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/ComputeLocationHashesVisitor.java
@@ -34,6 +34,8 @@ import org.sonar.db.protobuf.DbCommons;
import org.sonar.db.protobuf.DbIssues;
import org.sonar.server.issue.TaintChecker;
+import static org.apache.commons.lang.StringUtils.defaultIfEmpty;
+
/**
* This visitor will update the locations field of issues, by filling the hashes for all locations.
* It only applies to issues that are taint vulnerabilities and that are new or were changed.
@@ -75,7 +77,7 @@ public class ComputeLocationHashesVisitor extends IssueVisitor {
}
DbIssues.Locations.Builder primaryLocationBuilder = ((DbIssues.Locations) issue.getLocations()).toBuilder();
- boolean hasTextRange = addLocations(component, locationsByComponent, primaryLocationBuilder);
+ boolean hasTextRange = addLocations(component, issue, locationsByComponent, primaryLocationBuilder);
// If any location was added (because it had a text range), we'll need to update the issue at the end with the new object containing the hashes
if (hasTextRange) {
@@ -95,7 +97,7 @@ public class ComputeLocationHashesVisitor extends IssueVisitor {
issues.clear();
}
- private boolean addLocations(Component component, Map<Component, List<Location>> locationsByComponent, DbIssues.Locations.Builder primaryLocationBuilder) {
+ private boolean addLocations(Component component, DefaultIssue issue, Map<Component, List<Location>> locationsByComponent, DbIssues.Locations.Builder primaryLocationBuilder) {
boolean hasTextRange = false;
// Add primary location
@@ -110,7 +112,8 @@ public class ComputeLocationHashesVisitor extends IssueVisitor {
for (DbIssues.Location.Builder locationBuilder : flowBuilder.getLocationBuilderList()) {
if (locationBuilder.hasTextRange()) {
hasTextRange = true;
- Component locationComponent = treeRootHolder.getComponentByUuid(locationBuilder.getComponentId());
+ var componentUuid = defaultIfEmpty(locationBuilder.getComponentId(), issue.componentUuid());
+ Component locationComponent = treeRootHolder.getComponentByUuid(componentUuid);
locationsByComponent.computeIfAbsent(locationComponent, c -> new LinkedList<>()).add(new SecondaryLocation(locationBuilder));
}
}
diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/ComputeLocationHashesVisitorTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/ComputeLocationHashesVisitorTest.java
index 5fdb62f1238..24c3ee84534 100644
--- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/ComputeLocationHashesVisitorTest.java
+++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/ComputeLocationHashesVisitorTest.java
@@ -52,6 +52,7 @@ import static org.mockito.Mockito.when;
public class ComputeLocationHashesVisitorTest {
private static final String EXAMPLE_LINE_OF_CODE_FORMAT = "int example = line + of + code + %d; ";
private static final String LINE_IN_THE_MAIN_FILE = "String string = 'line-in-the-main-file';";
+ private static final String ANOTHER_LINE_IN_THE_MAIN_FILE = "String string = 'another-line-in-the-main-file';";
private static final String LINE_IN_ANOTHER_FILE = "String string = 'line-in-the-another-file';";
private static final RuleKey RULE_KEY = RuleKey.of("javasecurity", "S001");
@@ -215,6 +216,35 @@ public class ComputeLocationHashesVisitorTest {
assertThat(locations.getFlow(0).getLocation(1).getChecksum()).isEqualTo(DigestUtils.md5Hex("Stringstring='line-in-the-another-file';"));
}
+ @Test
+ public void calculates_hash_for_multiple_locations_in_same_file() {
+ DefaultIssue issue = createIssue()
+ .setComponentUuid(FILE_1.getUuid())
+ .setLocations(DbIssues.Locations.newBuilder()
+ .setTextRange(createRange(1, 0, 1, LINE_IN_THE_MAIN_FILE.length()))
+ .addFlow(DbIssues.Flow.newBuilder()
+ .addLocation(DbIssues.Location.newBuilder()
+ .setComponentId(FILE_1.getUuid())
+ .setTextRange(createRange(1, 0, 1, LINE_IN_THE_MAIN_FILE.length()))
+ .build())
+ .addLocation(DbIssues.Location.newBuilder()
+ // component id can be empty if location is in the same file
+ .setTextRange(createRange(2, 0, 2, ANOTHER_LINE_IN_THE_MAIN_FILE.length()))
+ .build())
+ .build())
+ .build());
+
+ when(sourceLinesRepository.readLines(FILE_1)).thenReturn(manyLinesIterator(LINE_IN_THE_MAIN_FILE, ANOTHER_LINE_IN_THE_MAIN_FILE));
+
+ underTest.onIssue(FILE_1, issue);
+ underTest.afterComponent(FILE_1);
+
+ DbIssues.Locations locations = issue.getLocations();
+
+ assertThat(locations.getFlow(0).getLocation(0).getChecksum()).isEqualTo(DigestUtils.md5Hex("Stringstring='line-in-the-main-file';"));
+ assertThat(locations.getFlow(0).getLocation(1).getChecksum()).isEqualTo(DigestUtils.md5Hex("Stringstring='another-line-in-the-main-file';"));
+ }
+
private DbCommons.TextRange createRange(int startLine, int startOffset, int endLine, int endOffset) {
return DbCommons.TextRange.newBuilder()
.setStartLine(startLine).setStartOffset(startOffset)
@@ -240,6 +270,10 @@ public class ComputeLocationHashesVisitorTest {
return CloseableIterator.from(List.of(lineContent).iterator());
}
+ private CloseableIterator<String> manyLinesIterator(String... lines) {
+ return CloseableIterator.from(List.of(lines).iterator());
+ }
+
private static class MutableConfiguration implements Configuration {
private final Map<String, String> keyValues = new HashMap<>();