From 00431799f91fa3b5e7b28d4379991e2456a41ea4 Mon Sep 17 00:00:00 2001 From: Duarte Meneses Date: Tue, 6 Sep 2022 16:28:00 -0500 Subject: [PATCH] SONAR-17287 Scanner supports flow types and description --- .../issue/internal/AbstractDefaultIssue.java | 29 +++-- .../issue/internal/DefaultIssueFlow.java | 57 +++++++++ .../issue/internal/DefaultIssueTest.java | 44 ++++--- .../sonar/scanner/issue/IssuePublisher.java | 23 +++- .../sonar/scanner/report/ReportPublisher.java | 6 +- .../scanner/issue/IssuePublisherTest.java | 109 ++++++++++-------- .../src/main/protobuf/scanner_report.proto | 8 ++ 7 files changed, 192 insertions(+), 84 deletions(-) create mode 100644 sonar-plugin-api-impl/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueFlow.java diff --git a/sonar-plugin-api-impl/src/main/java/org/sonar/api/batch/sensor/issue/internal/AbstractDefaultIssue.java b/sonar-plugin-api-impl/src/main/java/org/sonar/api/batch/sensor/issue/internal/AbstractDefaultIssue.java index dc07a5f6393..1c0f1464f82 100644 --- a/sonar-plugin-api-impl/src/main/java/org/sonar/api/batch/sensor/issue/internal/AbstractDefaultIssue.java +++ b/sonar-plugin-api-impl/src/main/java/org/sonar/api/batch/sensor/issue/internal/AbstractDefaultIssue.java @@ -27,30 +27,24 @@ import java.util.Objects; import java.util.Optional; import javax.annotation.Nullable; import org.sonar.api.batch.fs.InputComponent; -import org.sonar.api.batch.sensor.internal.SensorStorage; -import org.sonar.api.batch.sensor.issue.Issue.Flow; -import org.sonar.api.batch.sensor.issue.IssueLocation; -import org.sonar.api.batch.sensor.issue.NewIssueLocation; import org.sonar.api.batch.fs.internal.DefaultInputDir; import org.sonar.api.batch.fs.internal.DefaultInputModule; import org.sonar.api.batch.fs.internal.DefaultInputProject; import org.sonar.api.batch.sensor.internal.DefaultStorable; +import org.sonar.api.batch.sensor.internal.SensorStorage; +import org.sonar.api.batch.sensor.issue.Issue.Flow; +import org.sonar.api.batch.sensor.issue.IssueLocation; +import org.sonar.api.batch.sensor.issue.NewIssueLocation; import org.sonar.api.utils.PathUtils; -import static java.util.Collections.unmodifiableList; -import static java.util.stream.Collectors.toList; import static org.sonar.api.utils.Preconditions.checkArgument; import static org.sonar.api.utils.Preconditions.checkState; public abstract class AbstractDefaultIssue extends DefaultStorable { protected IssueLocation primaryLocation; - protected List> flows = new ArrayList<>(); + protected List flows = new ArrayList<>(); protected DefaultInputProject project; - protected AbstractDefaultIssue(DefaultInputProject project) { - this(project, null); - } - public AbstractDefaultIssue(DefaultInputProject project, @Nullable SensorStorage storage) { super(storage); this.project = project; @@ -61,9 +55,7 @@ public abstract class AbstractDefaultIssue exten } public List flows() { - return this.flows.stream() - .map(l -> () -> unmodifiableList(new ArrayList<>(l))) - .collect(toList()); + return Collections.unmodifiableList(flows); } public NewIssueLocation newLocation() { @@ -79,16 +71,21 @@ public abstract class AbstractDefaultIssue exten } public T addLocation(NewIssueLocation secondaryLocation) { - flows.add(Collections.singletonList(rewriteLocation((DefaultIssueLocation) secondaryLocation))); + flows.add(new DefaultIssueFlow(List.of(rewriteLocation((DefaultIssueLocation) secondaryLocation)), DefaultIssueFlow.Type.UNDEFINED, null)); return (T) this; } public T addFlow(Iterable locations) { + return addFlow(locations, DefaultIssueFlow.Type.UNDEFINED, null); + } + + public T addFlow(Iterable locations, DefaultIssueFlow.Type type, @Nullable String description) { + checkArgument(type != null, "Type can't be null"); List flowAsList = new ArrayList<>(); for (NewIssueLocation issueLocation : locations) { flowAsList.add(rewriteLocation((DefaultIssueLocation) issueLocation)); } - flows.add(flowAsList); + flows.add(new DefaultIssueFlow(flowAsList, type, description)); return (T) this; } diff --git a/sonar-plugin-api-impl/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueFlow.java b/sonar-plugin-api-impl/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueFlow.java new file mode 100644 index 00000000000..e4aabcc85da --- /dev/null +++ b/sonar-plugin-api-impl/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueFlow.java @@ -0,0 +1,57 @@ +/* + * SonarQube + * Copyright (C) 2009-2022 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.api.batch.sensor.issue.internal; + +import java.util.List; +import javax.annotation.CheckForNull; +import javax.annotation.Nullable; +import org.sonar.api.batch.sensor.issue.Issue; +import org.sonar.api.batch.sensor.issue.IssueLocation; + +public class DefaultIssueFlow implements Issue.Flow { + private final List locations; + private final Type type; + @Nullable + private final String description; + + public DefaultIssueFlow(List locations, Type type, @Nullable String description) { + this.locations = locations; + this.type = type; + this.description = description; + } + + @Override + public List locations() { + return locations; + } + + public Type getType() { + return type; + } + + @CheckForNull + public String getDescription() { + return description; + } + + public enum Type { + UNDEFINED, DATA, EXECUTION; + } +} diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueTest.java index 686f804812e..085ba25f645 100644 --- a/sonar-plugin-api-impl/src/test/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueTest.java +++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueTest.java @@ -21,34 +21,39 @@ package org.sonar.api.batch.sensor.issue.internal; import java.io.File; import java.io.IOException; +import java.util.List; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.sonar.api.batch.bootstrap.ProjectDefinition; +import org.sonar.api.batch.fs.TextRange; import org.sonar.api.batch.fs.internal.DefaultInputDir; import org.sonar.api.batch.fs.internal.DefaultInputFile; import org.sonar.api.batch.fs.internal.DefaultInputModule; import org.sonar.api.batch.fs.internal.DefaultInputProject; +import org.sonar.api.batch.fs.internal.DefaultTextPointer; +import org.sonar.api.batch.fs.internal.DefaultTextRange; import org.sonar.api.batch.fs.internal.TestInputFileBuilder; import org.sonar.api.batch.rule.Severity; import org.sonar.api.batch.sensor.internal.SensorStorage; import org.sonar.api.rule.RuleKey; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.tuple; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; public class DefaultIssueTest { - + private static final RuleKey RULE_KEY = RuleKey.of("repo", "rule"); @Rule public TemporaryFolder temp = new TemporaryFolder(); - private DefaultInputProject project; - - private DefaultInputFile inputFile = new TestInputFileBuilder("foo", "src/Foo.php") + private final SensorStorage storage = mock(SensorStorage.class); + private final DefaultInputFile inputFile = new TestInputFileBuilder("foo", "src/Foo.php") .initMetadata("Foo\nBar\n") .build(); + private DefaultInputProject project; @Before public void prepare() throws IOException { @@ -60,13 +65,12 @@ public class DefaultIssueTest { @Test public void build_file_issue() { - SensorStorage storage = mock(SensorStorage.class); DefaultIssue issue = new DefaultIssue(project, storage) .at(new DefaultIssueLocation() .on(inputFile) .at(inputFile.selectLine(1)) .message("Wrong way!")) - .forRule(RuleKey.of("repo", "rule")) + .forRule(RULE_KEY) .gap(10.0) .setRuleDescriptionContextKey("spring"); @@ -82,9 +86,27 @@ public class DefaultIssueTest { verify(storage).store(issue); } + @Test + public void build_issue_with_flows() { + TextRange range1 = new DefaultTextRange(new DefaultTextPointer(1, 1), new DefaultTextPointer(1, 2)); + TextRange range2 = new DefaultTextRange(new DefaultTextPointer(2, 1), new DefaultTextPointer(2, 2)); + + DefaultIssue issue = new DefaultIssue(project, storage) + .at(new DefaultIssueLocation().on(inputFile)) + .addFlow(List.of(new DefaultIssueLocation().message("loc1").on(inputFile)), DefaultIssueFlow.Type.DATA, "desc") + .addFlow(List.of(new DefaultIssueLocation().message("loc1").on(inputFile).at(range1), new DefaultIssueLocation().message("loc1").on(inputFile).at(range2))) + .forRule(RULE_KEY); + + assertThat(issue.flows) + .extracting(DefaultIssueFlow::getType, DefaultIssueFlow::getDescription) + .containsExactly(tuple(DefaultIssueFlow.Type.DATA, "desc"), tuple(DefaultIssueFlow.Type.UNDEFINED, null)); + + assertThat(issue.flows.get(0).locations()).hasSize(1); + assertThat(issue.flows.get(1).locations()).hasSize(2); + } + @Test public void move_directory_issue_to_project_root() { - SensorStorage storage = mock(SensorStorage.class); DefaultIssue issue = new DefaultIssue(project, storage) .at(new DefaultIssueLocation() .on(new DefaultInputDir("foo", "src/main").setModuleBaseDir(project.getBaseDir())) @@ -115,12 +137,11 @@ public class DefaultIssueTest { project.definition().addSubProject(subModuleDefinition); DefaultInputModule subModule = new DefaultInputModule(subModuleDefinition); - SensorStorage storage = mock(SensorStorage.class); DefaultIssue issue = new DefaultIssue(project, storage) .at(new DefaultIssueLocation() .on(subModule) .message("Wrong way!")) - .forRule(RuleKey.of("repo", "rule")) + .forRule(RULE_KEY) .overrideSeverity(Severity.BLOCKER); assertThat(issue.primaryLocation().inputComponent()).isEqualTo(project); @@ -136,13 +157,12 @@ public class DefaultIssueTest { @Test public void build_project_issue() throws IOException { - SensorStorage storage = mock(SensorStorage.class); DefaultInputModule inputModule = new DefaultInputModule(ProjectDefinition.create().setKey("foo").setBaseDir(temp.newFolder()).setWorkDir(temp.newFolder())); DefaultIssue issue = new DefaultIssue(project, storage) .at(new DefaultIssueLocation() .on(inputModule) .message("Wrong way!")) - .forRule(RuleKey.of("repo", "rule")) + .forRule(RULE_KEY) .gap(10.0); assertThat(issue.primaryLocation().inputComponent()).isEqualTo(inputModule); @@ -158,7 +178,6 @@ public class DefaultIssueTest { @Test public void default_issue_has_no_quickfix() { - SensorStorage storage = mock(SensorStorage.class); DefaultIssue issue = new DefaultIssue(project, storage); assertThat(issue.isQuickFixAvailable()).isFalse(); @@ -166,7 +185,6 @@ public class DefaultIssueTest { @Test public void issue_can_have_quickfix() { - SensorStorage storage = mock(SensorStorage.class); DefaultIssue issue = new DefaultIssue(project, storage).setQuickFixAvailable(true); assertThat(issue.isQuickFixAvailable()).isTrue(); diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/IssuePublisher.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/IssuePublisher.java index 48ac551dd1c..f9b38d860cb 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/IssuePublisher.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/IssuePublisher.java @@ -25,13 +25,14 @@ import javax.annotation.Nullable; import javax.annotation.concurrent.ThreadSafe; import org.apache.commons.lang.StringUtils; import org.sonar.api.batch.fs.TextRange; +import org.sonar.api.batch.fs.internal.DefaultInputComponent; +import org.sonar.api.batch.fs.internal.DefaultInputFile; import org.sonar.api.batch.rule.ActiveRule; import org.sonar.api.batch.rule.ActiveRules; import org.sonar.api.batch.sensor.issue.ExternalIssue; import org.sonar.api.batch.sensor.issue.Issue; import org.sonar.api.batch.sensor.issue.Issue.Flow; -import org.sonar.api.batch.fs.internal.DefaultInputComponent; -import org.sonar.api.batch.fs.internal.DefaultInputFile; +import org.sonar.api.batch.sensor.issue.internal.DefaultIssueFlow; import org.sonar.scanner.protocol.Constants.Severity; import org.sonar.scanner.protocol.output.ScannerReport; import org.sonar.scanner.protocol.output.ScannerReport.IssueLocation; @@ -160,7 +161,8 @@ public class IssuePublisher { private static void applyFlows(Consumer consumer, ScannerReport.IssueLocation.Builder locationBuilder, ScannerReport.TextRange.Builder textRangeBuilder, Collection flows) { ScannerReport.Flow.Builder flowBuilder = ScannerReport.Flow.newBuilder(); - for (Flow flow : flows) { + for (Flow f : flows) { + DefaultIssueFlow flow = (DefaultIssueFlow) f; if (flow.locations().isEmpty()) { return; } @@ -179,10 +181,25 @@ public class IssuePublisher { } flowBuilder.addLocation(locationBuilder.build()); } + if (flow.getDescription() != null) { + flowBuilder.setDescription(flow.getDescription()); + } + flowBuilder.setType(toProtobufFlowType(flow.getType())); consumer.accept(flowBuilder.build()); } } + private static ScannerReport.FlowType toProtobufFlowType(DefaultIssueFlow.Type flowType) { + switch (flowType) { + case EXECUTION: + return ScannerReport.FlowType.EXECUTION; + case DATA: + return ScannerReport.FlowType.DATA; + default: + return ScannerReport.FlowType.UNDEFINED; + } + } + private static ScannerReport.TextRange toProtobufTextRange(ScannerReport.TextRange.Builder textRangeBuilder, TextRange primaryTextRange) { textRangeBuilder.clear(); textRangeBuilder.setStartLine(primaryTextRange.start().line()); diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ReportPublisher.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ReportPublisher.java index 574fdd1e2a1..0fc66aa1c5f 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ReportPublisher.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ReportPublisher.java @@ -79,9 +79,9 @@ public class ReportPublisher implements Startable { private final ScanProperties properties; private final CeTaskReportDataHolder ceTaskReportDataHolder; - private Path reportDir; - private ScannerReportWriter writer; - private ScannerReportReader reader; + private final Path reportDir; + private final ScannerReportWriter writer; + private final ScannerReportReader reader; public ReportPublisher(ScanProperties properties, DefaultScannerWsClient wsClient, Server server, AnalysisContextReportPublisher contextPublisher, InputModuleHierarchy moduleHierarchy, GlobalAnalysisMode analysisMode, TempFolder temp, ReportPublisherStep[] publishers, BranchConfiguration branchConfiguration, diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/IssuePublisherTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/IssuePublisherTest.java index f55559e9100..daca66ffacd 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/IssuePublisherTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/IssuePublisherTest.java @@ -22,32 +22,34 @@ package org.sonar.scanner.issue; import java.io.IOException; import java.util.Collections; import java.util.HashSet; +import java.util.List; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; -import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import org.sonar.api.batch.bootstrap.ProjectDefinition; import org.sonar.api.batch.fs.InputComponent; -import org.sonar.api.batch.rule.internal.NewActiveRule; -import org.sonar.api.batch.rule.internal.RulesBuilder; import org.sonar.api.batch.fs.internal.DefaultInputFile; import org.sonar.api.batch.fs.internal.DefaultInputProject; import org.sonar.api.batch.fs.internal.TestInputFileBuilder; +import org.sonar.api.batch.rule.internal.ActiveRulesBuilder; +import org.sonar.api.batch.rule.internal.NewActiveRule; +import org.sonar.api.batch.sensor.issue.internal.DefaultExternalIssue; import org.sonar.api.batch.sensor.issue.internal.DefaultIssue; +import org.sonar.api.batch.sensor.issue.internal.DefaultIssueFlow; import org.sonar.api.batch.sensor.issue.internal.DefaultIssueLocation; -import org.sonar.api.batch.sensor.issue.internal.DefaultExternalIssue; import org.sonar.api.rule.RuleKey; import org.sonar.api.rule.Severity; import org.sonar.api.rules.RuleType; import org.sonar.scanner.protocol.output.ScannerReport; +import org.sonar.scanner.protocol.output.ScannerReport.FlowType; import org.sonar.scanner.report.ReportPublisher; -import org.sonar.api.batch.rule.internal.ActiveRulesBuilder; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.tuple; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.RETURNS_DEEP_STUBS; @@ -58,26 +60,19 @@ import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.class) public class IssuePublisherTest { - static final RuleKey JAVA_RULE_KEY = RuleKey.of("java", "AvoidCycle"); - static final String JAVA_RULE_NAME = "Avoid Cycle"; private static final RuleKey NOSONAR_RULE_KEY = RuleKey.of("java", "NoSonarCheck"); private DefaultInputProject project; @Rule public TemporaryFolder temp = new TemporaryFolder(); + public IssueFilters filters = mock(IssueFilters.class); - @Mock - IssueFilters filters; - - ActiveRulesBuilder activeRulesBuilder = new ActiveRulesBuilder(); - RulesBuilder ruleBuilder = new RulesBuilder(); - - IssuePublisher moduleIssues; - - DefaultInputFile file = new TestInputFileBuilder("foo", "src/Foo.php").initMetadata("Foo\nBar\nBiz\n").build(); - ReportPublisher reportPublisher = mock(ReportPublisher.class, RETURNS_DEEP_STUBS); + private final ActiveRulesBuilder activeRulesBuilder = new ActiveRulesBuilder(); + private IssuePublisher moduleIssues; + private final DefaultInputFile file = new TestInputFileBuilder("foo", "src/Foo.php").initMetadata("Foo\nBar\nBiz\n").build(); + private final ReportPublisher reportPublisher = mock(ReportPublisher.class, RETURNS_DEEP_STUBS); @Before public void prepare() throws IOException { @@ -85,15 +80,22 @@ public class IssuePublisherTest { .setKey("foo") .setBaseDir(temp.newFolder()) .setWorkDir(temp.newFolder())); + + activeRulesBuilder.addRule(new NewActiveRule.Builder() + .setRuleKey(JAVA_RULE_KEY) + .setSeverity(Severity.INFO) + .setQProfileKey("qp-1") + .build()); + initModuleIssues(); } @Test public void ignore_null_active_rule() { - ruleBuilder.add(JAVA_RULE_KEY).setName(JAVA_RULE_NAME); + RuleKey INACTIVE_RULE_KEY = RuleKey.of("repo", "inactive"); initModuleIssues(); DefaultIssue issue = new DefaultIssue(project) .at(new DefaultIssueLocation().on(file).at(file.selectLine(3)).message("Foo")) - .forRule(JAVA_RULE_KEY); + .forRule(INACTIVE_RULE_KEY); boolean added = moduleIssues.initAndAddIssue(issue); assertThat(added).isFalse(); @@ -102,8 +104,6 @@ public class IssuePublisherTest { @Test public void ignore_null_rule_of_active_rule() { - ruleBuilder.add(JAVA_RULE_KEY).setName(JAVA_RULE_NAME); - activeRulesBuilder.addRule(new NewActiveRule.Builder().setRuleKey(JAVA_RULE_KEY).setQProfileKey("qp-1").build()); initModuleIssues(); DefaultIssue issue = new DefaultIssue(project) @@ -117,12 +117,6 @@ public class IssuePublisherTest { @Test public void add_issue_to_cache() { - ruleBuilder.add(JAVA_RULE_KEY).setName(JAVA_RULE_NAME); - activeRulesBuilder.addRule(new NewActiveRule.Builder() - .setRuleKey(JAVA_RULE_KEY) - .setSeverity(Severity.INFO) - .setQProfileKey("qp-1") - .build()); initModuleIssues(); final String ruleDescriptionContextKey = "spring"; @@ -145,9 +139,47 @@ public class IssuePublisherTest { assertThat(argument.getValue().getRuleDescriptionContextKey()).isEqualTo(ruleDescriptionContextKey); } + @Test + public void add_issue_flows_to_cache() { + initModuleIssues(); + + DefaultIssue issue = new DefaultIssue(project) + .at(new DefaultIssueLocation().on(file)) + // Flow without type + .addFlow(List.of(new DefaultIssueLocation().on(file).at(file.selectLine(1)).message("Foo1"), new DefaultIssueLocation().on(file).at(file.selectLine(2)).message("Foo2"))) + // Flow with type and description + .addFlow(List.of(new DefaultIssueLocation().on(file)), DefaultIssueFlow.Type.DATA, "description") + // Flow with execution type and no description + .addFlow(List.of(new DefaultIssueLocation().on(file)), DefaultIssueFlow.Type.EXECUTION, null) + .forRule(JAVA_RULE_KEY); + + when(filters.accept(any(InputComponent.class), any(ScannerReport.Issue.class))).thenReturn(true); + moduleIssues.initAndAddIssue(issue); + + ArgumentCaptor argument = ArgumentCaptor.forClass(ScannerReport.Issue.class); + verify(reportPublisher.getWriter()).appendComponentIssue(eq(file.scannerId()), argument.capture()); + List writtenFlows = argument.getValue().getFlowList(); + + assertThat(writtenFlows) + .extracting(ScannerReport.Flow::getDescription, ScannerReport.Flow::getType) + .containsExactly(tuple("", FlowType.UNDEFINED), tuple("description", FlowType.DATA), tuple("", FlowType.EXECUTION)); + + assertThat(writtenFlows.get(0).getLocationCount()).isEqualTo(2); + assertThat(writtenFlows.get(0).getLocationList()).containsExactly( + ScannerReport.IssueLocation.newBuilder() + .setComponentRef(file.scannerId()) + .setMsg("Foo1") + .setTextRange(ScannerReport.TextRange.newBuilder().setStartLine(1).setEndLine(1).setEndOffset(3).build()) + .build(), + ScannerReport.IssueLocation.newBuilder() + .setComponentRef(file.scannerId()) + .setMsg("Foo2") + .setTextRange(ScannerReport.TextRange.newBuilder().setStartLine(2).setEndLine(2).setEndOffset(3).build()) + .build()); + } + @Test public void add_external_issue_to_cache() { - ruleBuilder.add(JAVA_RULE_KEY).setName(JAVA_RULE_NAME); initModuleIssues(); DefaultExternalIssue issue = new DefaultExternalIssue(project) @@ -165,12 +197,6 @@ public class IssuePublisherTest { @Test public void use_severity_from_active_rule_if_no_severity_on_issue() { - ruleBuilder.add(JAVA_RULE_KEY).setName(JAVA_RULE_NAME); - activeRulesBuilder.addRule(new NewActiveRule.Builder() - .setRuleKey(JAVA_RULE_KEY) - .setSeverity(Severity.INFO) - .setQProfileKey("qp-1") - .build()); initModuleIssues(); DefaultIssue issue = new DefaultIssue(project) @@ -186,14 +212,6 @@ public class IssuePublisherTest { @Test public void filter_issue() { - ruleBuilder.add(JAVA_RULE_KEY).setName(JAVA_RULE_NAME); - activeRulesBuilder.addRule(new NewActiveRule.Builder() - .setRuleKey(JAVA_RULE_KEY) - .setSeverity(Severity.INFO) - .setQProfileKey("qp-1") - .build()); - initModuleIssues(); - DefaultIssue issue = new DefaultIssue(project) .at(new DefaultIssueLocation().on(file).at(file.selectLine(3)).message("")) .forRule(JAVA_RULE_KEY); @@ -208,12 +226,6 @@ public class IssuePublisherTest { @Test public void should_ignore_lines_commented_with_nosonar() { - ruleBuilder.add(JAVA_RULE_KEY).setName(JAVA_RULE_NAME); - activeRulesBuilder.addRule(new NewActiveRule.Builder() - .setRuleKey(JAVA_RULE_KEY) - .setSeverity(Severity.INFO) - .setQProfileKey("qp-1") - .build()); initModuleIssues(); DefaultIssue issue = new DefaultIssue(project) @@ -231,7 +243,6 @@ public class IssuePublisherTest { @Test public void should_accept_issues_on_no_sonar_rules() { // The "No Sonar" rule logs violations on the lines that are flagged with "NOSONAR" !! - ruleBuilder.add(NOSONAR_RULE_KEY).setName("No Sonar"); activeRulesBuilder.addRule(new NewActiveRule.Builder() .setRuleKey(NOSONAR_RULE_KEY) .setSeverity(Severity.INFO) diff --git a/sonar-scanner-protocol/src/main/protobuf/scanner_report.proto b/sonar-scanner-protocol/src/main/protobuf/scanner_report.proto index 4870c034282..da7c32d0cfc 100644 --- a/sonar-scanner-protocol/src/main/protobuf/scanner_report.proto +++ b/sonar-scanner-protocol/src/main/protobuf/scanner_report.proto @@ -236,6 +236,14 @@ message IssueLocation { message Flow { repeated IssueLocation location = 1; + string description = 2; + FlowType type = 3; +} + +enum FlowType { + DATA = 0; + EXECUTION = 1; + UNKNOWN = 2; } message Changesets { -- 2.39.5