import java.util.Comparator;
import java.util.Date;
import java.util.HashSet;
+import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Supplier;
if (pluginKey == null) {
return false;
}
-
+
ScannerPlugin scannerPlugin = Optional.ofNullable(analysisMetadataHolder.getScannerPluginsByKey().get(pluginKey))
.orElseThrow(illegalStateException("The rule %s is declared to come from plugin %s, but this plugin was not used by scanner.", activeRule.getRuleKey(), pluginKey));
return pluginIsNew(scannerPlugin, lastAnalysisDate)
private Optional<Date> getScmChangeDate(Component component, DefaultIssue issue) {
return getScmInfo(component)
- .flatMap(scmInfo -> getChangeset(scmInfo, issue))
+ .flatMap(scmInfo -> getChangeset(component, scmInfo, issue))
.map(IssueCreationDateCalculator::getChangeDate);
}
return toJavaUtilOptional(scmInfoRepository.getScmInfo(component));
}
- private static Optional<Changeset> getChangeset(ScmInfo scmInfo, DefaultIssue issue) {
+ private static Optional<Changeset> getChangeset(Component component, ScmInfo scmInfo, DefaultIssue issue) {
Set<Integer> involvedLines = new HashSet<>();
DbIssues.Locations locations = issue.getLocations();
if (locations != null) {
}
for (Flow f : locations.getFlowList()) {
for (Location l : f.getLocationList()) {
- addLines(involvedLines, l.getTextRange());
+ if (Objects.equals(l.getComponentId(), component.getUuid())) {
+ // Ignore locations in other files, since it is currently not very common, and this is hard to load SCM by component UUID.
+ addLines(involvedLines, l.getTextRange());
+ }
}
}
if (!involvedLines.isEmpty()) {
import static org.mockito.Mockito.when;
public class IssueCreationDateCalculatorTest {
+ private static final String COMPONENT_UUID = "ab12";
+
@Rule
public AnalysisMetadataHolderRule analysisMetadataHolder = new AnalysisMetadataHolderRule();
issueUpdater = mock(IssueFieldsSetter.class);
activeRulesHolder = mock(ActiveRulesHolder.class);
component = mock(Component.class);
+ when(component.getUuid()).thenReturn(COMPONENT_UUID);
ruleKey = RuleKey.of("reop", "rule");
issue = mock(DefaultIssue.class);
activeRule = mock(ActiveRule.class);
Flow.Builder secondary = Flow.newBuilder().addLocation(Location.newBuilder().setTextRange(range(4, 5)));
builder.addFlow(secondary).build();
Flow.Builder flow = Flow.newBuilder()
- .addLocation(Location.newBuilder().setTextRange(range(6, 7)))
- .addLocation(Location.newBuilder().setTextRange(range(8, 9)));
+ .addLocation(Location.newBuilder().setTextRange(range(6, 7)).setComponentId(COMPONENT_UUID))
+ .addLocation(Location.newBuilder().setTextRange(range(8, 9)).setComponentId(COMPONENT_UUID));
builder.addFlow(flow).build();
when(issue.getLocations()).thenReturn(builder.build());
withScmAt(2, 1200L);
assertChangeOfCreationDateTo(1900L);
}
+ @Test
+ public void should_ignore_flows_location_outside_current_file_when_backdating() {
+ analysisMetadataHolder.setBaseAnalysis(null);
+ currentAnalysisIs(3000L);
+
+ newIssue();
+ Builder builder = DbIssues.Locations.newBuilder()
+ .setTextRange(range(2, 3));
+ Flow.Builder secondary = Flow.newBuilder().addLocation(Location.newBuilder().setTextRange(range(4, 5)));
+ builder.addFlow(secondary).build();
+ Flow.Builder flow = Flow.newBuilder()
+ .addLocation(Location.newBuilder().setTextRange(range(6, 7)).setComponentId(COMPONENT_UUID))
+ .addLocation(Location.newBuilder().setTextRange(range(8, 9)).setComponentId("another"));
+ builder.addFlow(flow).build();
+ when(issue.getLocations()).thenReturn(builder.build());
+ withScmAt(2, 1200L);
+ withScmAt(3, 1300L);
+ withScmAt(4, 1400L);
+ withScmAt(5, 1500L);
+ withScmAt(6, 1600L);
+ withScmAt(7, 1700L);
+ withScmAt(8, 1800L);
+ withScmAt(9, 1900L);
+
+ run();
+
+ assertChangeOfCreationDateTo(1700L);
+ }
+
private org.sonar.db.protobuf.DbCommons.TextRange.Builder range(int startLine, int endLine) {
return TextRange.newBuilder().setStartLine(startLine).setEndLine(endLine);
}