Skip to content

Commit

Permalink
SLE-983: Handle Standard and MQR mode correctly
Browse files Browse the repository at this point in the history
For SQ-S 10.8+ handle the different modes correctly in Connected Mode.
For SQ-S 9.9 LTA handle the Standard mode correctly as there hasn't been any MQR mode yet.
For SQ-S 10.0-10.7 handle the MQR mode as it was the default for that time.
For Standalone Mode handle MQR mode.
  • Loading branch information
thahnen committed Nov 15, 2024
1 parent ada9a52 commit 1e16c5d
Show file tree
Hide file tree
Showing 15 changed files with 187 additions and 158 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
*/
package org.sonarlint.eclipse.core.internal.markers;

import java.util.Collections;
import java.util.List;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ProjectScope;
Expand Down Expand Up @@ -59,8 +58,6 @@ public void test_MarkerAttributesEncodingDecoding() {
assertThat(MarkerUtils.decodeCleanCodeAttribute(null)).isNull();
assertThat(MarkerUtils.decodeCleanCodeAttribute(CleanCodeAttribute.CLEAR.name()).name()).isEqualTo(CleanCodeAttribute.CLEAR.name());
assertThat(MarkerUtils.encodeHighestImpact(List.of())).isNull();
assertThat(MarkerUtils.encodeImpacts(List.of())).isNull();
assertThat(MarkerUtils.decodeImpacts(null)).isEqualTo(Collections.emptyMap());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,16 @@
import org.sonarlint.eclipse.core.internal.resources.DefaultSonarLintProjectAdapter;
import org.sonarlint.eclipse.core.internal.utils.StringUtils;
import org.sonarlint.eclipse.tests.common.SonarTestCase;
import org.sonarsource.sonarlint.core.rpc.protocol.backend.rules.ImpactDto;
import org.sonarsource.sonarlint.core.rpc.protocol.client.issue.RaisedIssueDto;
import org.sonarsource.sonarlint.core.rpc.protocol.common.CleanCodeAttribute;
import org.sonarsource.sonarlint.core.rpc.protocol.common.Either;
import org.sonarsource.sonarlint.core.rpc.protocol.common.ImpactSeverity;
import org.sonarsource.sonarlint.core.rpc.protocol.common.IssueSeverity;
import org.sonarsource.sonarlint.core.rpc.protocol.common.MQRModeDetails;
import org.sonarsource.sonarlint.core.rpc.protocol.common.RuleType;
import org.sonarsource.sonarlint.core.rpc.protocol.common.SoftwareQuality;
import org.sonarsource.sonarlint.core.rpc.protocol.common.StandardModeDetails;
import org.sonarsource.sonarlint.core.rpc.protocol.common.TextRangeDto;

import static org.assertj.core.api.Assertions.assertThat;
Expand Down Expand Up @@ -127,8 +135,10 @@ public void test_marker_of_ordinary_trackable() throws Exception {

var priority = 2;
var severity = IssueSeverity.BLOCKER;
var type = RuleType.BUG;
var eclipseSeverity = 0;
when(issue.getSeverity()).thenReturn(severity);

when(issue.getSeverityMode()).thenReturn(Either.forLeft(new StandardModeDetails(severity, type)));

var message = "Self assignment of field";
when(issue.getPrimaryMessage()).thenReturn(message);
Expand Down Expand Up @@ -159,6 +169,10 @@ public void test_marker_of_ordinary_trackable() throws Exception {
public void test_marker_of_trackable_with_text_range() throws Exception {
var issue = newMockRaisedIssueDto();

var severity = IssueSeverity.MINOR;
var type = RuleType.BUG;
when(issue.getSeverityMode()).thenReturn(Either.forLeft(new StandardModeDetails(severity, type)));

when(issue.getTextRange()).thenReturn(new TextRangeDto(5, 4, 5, 14));

var markers = processRaisedIssueDto(issue);
Expand All @@ -173,6 +187,10 @@ public void test_marker_of_trackable_with_text_range() throws Exception {
public void test_marker_of_trackable_with_rule_context() throws Exception {
var issue = newMockRaisedIssueDto();

var severity = IssueSeverity.BLOCKER;
var type = RuleType.BUG;
when(issue.getSeverityMode()).thenReturn(Either.forLeft(new StandardModeDetails(severity, type)));

when(issue.getRuleDescriptionContextKey()).thenReturn("struts");

var markers = processRaisedIssueDto(issue);
Expand All @@ -185,6 +203,12 @@ public void test_marker_of_trackable_with_rule_context() throws Exception {
public void test_marker_of_trackable_with_line() throws Exception {
var issue = newMockRaisedIssueDto();

var cleanCodeAttribute = CleanCodeAttribute.CLEAR;
var impacts = List.of(new ImpactDto(SoftwareQuality.MAINTAINABILITY, ImpactSeverity.INFO),
new ImpactDto(SoftwareQuality.RELIABILITY, ImpactSeverity.MEDIUM));

when(issue.getSeverityMode()).thenReturn(Either.forRight(new MQRModeDetails(cleanCodeAttribute, impacts)));

when(issue.getTextRange()).thenReturn(new TextRangeDto(5, 4, 5, 14));

var markers = processRaisedIssueDto(issue);
Expand All @@ -198,6 +222,12 @@ public void test_marker_of_trackable_with_line() throws Exception {
@Test
public void test_marker_of_trackable_without_line() throws Exception {
var issue = newMockRaisedIssueDto();

var cleanCodeAttribute = CleanCodeAttribute.CLEAR;
var impacts = List.of(new ImpactDto(SoftwareQuality.MAINTAINABILITY, ImpactSeverity.INFO));

when(issue.getSeverityMode()).thenReturn(Either.forRight(new MQRModeDetails(cleanCodeAttribute, impacts)));

var markers = processRaisedIssueDto(issue);
assertThat(markers).hasSize(1);
assertThat(markers[0].getAttribute(IMarker.LINE_NUMBER)).isEqualTo(1);
Expand All @@ -207,6 +237,12 @@ public void test_marker_of_trackable_without_line() throws Exception {
public void test_marker_of_trackable_with_creation_date() throws Exception {
var issue = newMockRaisedIssueDto();

var cleanCodeAttribute = CleanCodeAttribute.CLEAR;
var impacts = List.of(new ImpactDto(SoftwareQuality.MAINTAINABILITY, ImpactSeverity.INFO),
new ImpactDto(SoftwareQuality.RELIABILITY, ImpactSeverity.HIGH));

when(issue.getSeverityMode()).thenReturn(Either.forRight(new MQRModeDetails(cleanCodeAttribute, impacts)));

var introduction = Instant.now();
when(issue.getIntroductionDate()).thenReturn(introduction);

Expand Down
2 changes: 1 addition & 1 deletion org.sonarlint.eclipse.core/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,6 @@ Require-Bundle: org.eclipse.equinox.security,
org.eclipse.team.core,
org.eclipse.jdt.annotation;resolution:=optional,
org.eclipse.text,
org.sonarsource.sonarlint.core.sonarlint-java-client-osgi;bundle-version="[10.7.0,10.8.0)"
org.sonarsource.sonarlint.core.sonarlint-java-client-osgi;bundle-version="[10.10.0,10.11.0)"
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-11
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,13 @@
import org.sonarsource.sonarlint.core.rpc.protocol.backend.issue.ChangeIssueStatusParams;
import org.sonarsource.sonarlint.core.rpc.protocol.backend.issue.CheckAnticipatedStatusChangeSupportedParams;
import org.sonarsource.sonarlint.core.rpc.protocol.backend.issue.CheckAnticipatedStatusChangeSupportedResponse;
import org.sonarsource.sonarlint.core.rpc.protocol.backend.issue.GetEffectiveIssueDetailsParams;
import org.sonarsource.sonarlint.core.rpc.protocol.backend.issue.GetEffectiveIssueDetailsResponse;
import org.sonarsource.sonarlint.core.rpc.protocol.backend.issue.ReopenIssueParams;
import org.sonarsource.sonarlint.core.rpc.protocol.backend.issue.ReopenIssueResponse;
import org.sonarsource.sonarlint.core.rpc.protocol.backend.issue.ResolutionStatus;
import org.sonarsource.sonarlint.core.rpc.protocol.backend.newcode.GetNewCodeDefinitionParams;
import org.sonarsource.sonarlint.core.rpc.protocol.backend.newcode.GetNewCodeDefinitionResponse;
import org.sonarsource.sonarlint.core.rpc.protocol.backend.rules.GetEffectiveRuleDetailsParams;
import org.sonarsource.sonarlint.core.rpc.protocol.backend.rules.GetEffectiveRuleDetailsResponse;
import org.sonarsource.sonarlint.core.rpc.protocol.backend.rules.GetStandaloneRuleDescriptionParams;
import org.sonarsource.sonarlint.core.rpc.protocol.backend.rules.GetStandaloneRuleDescriptionResponse;
import org.sonarsource.sonarlint.core.rpc.protocol.backend.rules.ListAllStandaloneRulesDefinitionsResponse;
Expand Down Expand Up @@ -336,12 +336,12 @@ public GetStandaloneRuleDescriptionResponse getStandaloneRuleDetails(String rule
.get();
}

/** Get the rules details (project configuration, maybe connected mode) */
public GetEffectiveRuleDetailsResponse getEffectiveRuleDetails(ISonarLintProject project, String ruleKey, @Nullable String contextKey)
/** Get the issue details (project configuration, maybe connected mode) */
public GetEffectiveIssueDetailsResponse getEffectiveIssueDetails(ISonarLintProject project, UUID issueId)
throws InterruptedException, ExecutionException {
return getBackend()
.getRulesService()
.getEffectiveRuleDetails(new GetEffectiveRuleDetailsParams(ConfigScopeSynchronizer.getConfigScopeId(project), ruleKey, contextKey))
.getIssueService()
.getEffectiveIssueDetails(new GetEffectiveIssueDetailsParams(ConfigScopeSynchronizer.getConfigScopeId(project), issueId))
.get();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,13 @@
import org.sonarlint.eclipse.core.resource.ISonarLintFile;
import org.sonarlint.eclipse.core.resource.ISonarLintIssuable;
import org.sonarlint.eclipse.core.resource.ISonarLintProject;
import org.sonarsource.sonarlint.core.client.utils.ImpactSeverity;
import org.sonarsource.sonarlint.core.rpc.protocol.backend.tracking.TaintVulnerabilityDto;
import org.sonarsource.sonarlint.core.rpc.protocol.backend.tracking.TaintVulnerabilityDto.FlowDto.LocationDto;
import org.sonarsource.sonarlint.core.rpc.protocol.backend.tracking.TextRangeWithHashDto;
import org.sonarsource.sonarlint.core.rpc.protocol.client.issue.QuickFixDto;
import org.sonarsource.sonarlint.core.rpc.protocol.client.issue.RaisedIssueDto;
import org.sonarsource.sonarlint.core.rpc.protocol.common.IssueSeverity;
import org.sonarsource.sonarlint.core.rpc.protocol.common.TextRangeDto;

public class SonarLintMarkerUpdater {
Expand Down Expand Up @@ -251,6 +253,7 @@ private static void createTaintMarker(IDocument document, ISonarLintIssuable iss

setMarkerViewUtilsAttributes(issuable, marker);

marker.setAttribute(MarkerUtils.SONAR_MARKER_TRACKED_ISSUE_ID_ATTR, MarkerUtils.encodeUuid(taintIssue.getId()));
marker.setAttribute(MarkerUtils.SONAR_MARKER_RULE_KEY_ATTR, taintIssue.getRuleKey());
marker.setAttribute(MarkerUtils.SONAR_MARKER_RULE_DESC_CONTEXT_KEY_ATTR, taintIssue.getRuleDescriptionContextKey());
marker.setAttribute(IMarker.SEVERITY, SonarLintGlobalConfiguration.getMarkerSeverity());
Expand All @@ -268,9 +271,21 @@ private static void createTaintMarker(IDocument document, ISonarLintIssuable iss
SonarLintLogger.get().debug("Position cannot be set for taint issue '" + taintIssue.getId() + "' in '" + taintIssue.getIdeFilePath() + "'");
}

marker.setAttribute(IMarker.PRIORITY, getPriority(taintIssue.getSeverity()));
marker.setAttribute(MarkerUtils.SONAR_MARKER_ISSUE_SEVERITY_ATTR, taintIssue.getSeverity().name());
marker.setAttribute(MarkerUtils.SONAR_MARKER_ISSUE_TYPE_ATTR, taintIssue.getType().name());
var severityModeEither = taintIssue.getSeverityMode();
if (severityModeEither.isLeft()) {
var standardModeDetails = severityModeEither.getLeft();
marker.setAttribute(IMarker.PRIORITY, getPriority(standardModeDetails.getSeverity()));
marker.setAttribute(MarkerUtils.SONAR_MARKER_ISSUE_SEVERITY_ATTR, standardModeDetails.getSeverity().name());
marker.setAttribute(MarkerUtils.SONAR_MARKER_ISSUE_TYPE_ATTR, standardModeDetails.getType().name());
} else {
var mqrModeDetails = severityModeEither.getRight();
marker.setAttribute(MarkerUtils.SONAR_MARKER_ISSUE_ATTRIBUTE_ATTR, mqrModeDetails.getCleanCodeAttribute());
var highestImpactSeverityEncoded = MarkerUtils.encodeHighestImpact(mqrModeDetails.getImpacts());
marker.setAttribute(MarkerUtils.SONAR_MARKER_ISSUE_HIGHEST_IMPACT_ATTR,
highestImpactSeverityEncoded);
marker.setAttribute(IMarker.PRIORITY, highestImpactSeverityEncoded);
}

marker.setAttribute(MarkerUtils.SONAR_MARKER_SERVER_ISSUE_KEY_ATTR, taintIssue.getSonarServerKey());
marker.setAttribute(MarkerUtils.SONAR_MARKER_RESOLVED_ATTR, taintIssue.isResolved());

Expand All @@ -297,8 +312,6 @@ private static void updateMarkerAttributes(IDocument document, RaisedIssueDto is
setMarkerAttributeIfDifferent(marker, existingAttributes, MarkerUtils.SONAR_MARKER_RULE_DESC_CONTEXT_KEY_ATTR,
issue.getRuleDescriptionContextKey());
setMarkerAttributeIfDifferent(marker, existingAttributes, IMarker.SEVERITY, SonarLintGlobalConfiguration.getMarkerSeverity());
setMarkerAttributeIfDifferent(marker, existingAttributes, IMarker.PRIORITY, getPriority(issue.getSeverity()));

setMarkerAttributeIfDifferent(marker, existingAttributes, IMarker.MESSAGE, issue.getPrimaryMessage());

var textRange = issue.getTextRange();
Expand All @@ -310,17 +323,25 @@ private static void updateMarkerAttributes(IDocument document, RaisedIssueDto is
setMarkerAttributeIfDifferent(marker, existingAttributes, IMarker.CHAR_START, position != null ? position.getOffset() : null);
setMarkerAttributeIfDifferent(marker, existingAttributes, IMarker.CHAR_END, position != null ? (position.getOffset() + position.getLength()) : null);

setMarkerAttributeIfDifferent(marker, existingAttributes, MarkerUtils.SONAR_MARKER_ISSUE_SEVERITY_ATTR,
issue.getSeverity());
setMarkerAttributeIfDifferent(marker, existingAttributes, MarkerUtils.SONAR_MARKER_ISSUE_TYPE_ATTR,
issue.getType());

setMarkerAttributeIfDifferent(marker, existingAttributes, MarkerUtils.SONAR_MARKER_ISSUE_ATTRIBUTE_ATTR,
issue.getCleanCodeAttribute());
setMarkerAttributeIfDifferent(marker, existingAttributes, MarkerUtils.SONAR_MARKER_ISSUE_IMPACTS_ATTR,
MarkerUtils.encodeImpacts(issue.getImpacts()));
setMarkerAttributeIfDifferent(marker, existingAttributes, MarkerUtils.SONAR_MARKER_ISSUE_HIGHEST_IMPACT_ATTR,
MarkerUtils.encodeHighestImpact(issue.getImpacts()));
var severityModeEither = issue.getSeverityMode();
if (severityModeEither.isLeft()) {
var standardModeDetails = severityModeEither.getLeft();
setMarkerAttributeIfDifferent(marker, existingAttributes, IMarker.PRIORITY,
getPriority(standardModeDetails.getSeverity()));
setMarkerAttributeIfDifferent(marker, existingAttributes, MarkerUtils.SONAR_MARKER_ISSUE_SEVERITY_ATTR,
standardModeDetails.getSeverity());
setMarkerAttributeIfDifferent(marker, existingAttributes, MarkerUtils.SONAR_MARKER_ISSUE_TYPE_ATTR,
standardModeDetails.getType());
} else {
var mqrModeDetails = severityModeEither.getRight();
setMarkerAttributeIfDifferent(marker, existingAttributes, MarkerUtils.SONAR_MARKER_ISSUE_ATTRIBUTE_ATTR,
mqrModeDetails.getCleanCodeAttribute());
var highestImpactSeverityEncoded = MarkerUtils.encodeHighestImpact(mqrModeDetails.getImpacts());
setMarkerAttributeIfDifferent(marker, existingAttributes, IMarker.PRIORITY,
getPriority(highestImpactSeverityEncoded));
setMarkerAttributeIfDifferent(marker, existingAttributes, MarkerUtils.SONAR_MARKER_ISSUE_HIGHEST_IMPACT_ATTR,
highestImpactSeverityEncoded);
}

setMarkerAttributeIfDifferent(marker, existingAttributes, MarkerUtils.SONAR_MARKER_SERVER_ISSUE_KEY_ATTR,
issue.getServerKey());
Expand Down Expand Up @@ -501,15 +522,8 @@ private static void setMarkerAttributeIfDifferent(IMarker marker, @Nullable Map<
}
}

/**
* @return Priority marker attribute. A number from the set of high, normal and low priorities defined by the platform.
*
* @see IMarker.PRIORITY_HIGH
* @see IMarker.PRIORITY_NORMAL
* @see IMarker.PRIORITY_LOW
*/
private static int getPriority(final org.sonarsource.sonarlint.core.rpc.protocol.common.@Nullable IssueSeverity severity) {
switch (severity != null ? severity : org.sonarsource.sonarlint.core.rpc.protocol.common.IssueSeverity.INFO) {
private static int getPriority(final IssueSeverity severity) {
switch (severity) {
case BLOCKER:
case CRITICAL:
return IMarker.PRIORITY_HIGH;
Expand All @@ -522,6 +536,17 @@ private static int getPriority(final org.sonarsource.sonarlint.core.rpc.protocol
}
}

private static int getPriority(@Nullable String highestImpactSeverityEncoded) {
if (highestImpactSeverityEncoded == null
|| ImpactSeverity.INFO.getLabel().equals(highestImpactSeverityEncoded)
|| ImpactSeverity.LOW.getLabel().equals(highestImpactSeverityEncoded)) {
return IMarker.PRIORITY_LOW;
} else if (ImpactSeverity.MEDIUM.getLabel().equals(highestImpactSeverityEncoded)) {
return IMarker.PRIORITY_NORMAL;
}
return IMarker.PRIORITY_HIGH;
}

/** Markers should not be set / should be removed for issues already resolved when preference is set */
private static boolean shouldHideResolvedIssueMarker(RaisedIssueDto issue, final boolean issuesIncludingResolved) {
return !issuesIncludingResolved && issue.isResolved();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,8 @@
*/
package org.sonarlint.eclipse.core.internal.markers;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;
Expand Down Expand Up @@ -52,7 +50,6 @@
import org.sonarsource.sonarlint.core.rpc.protocol.common.ImpactSeverity;
import org.sonarsource.sonarlint.core.rpc.protocol.common.IssueSeverity;
import org.sonarsource.sonarlint.core.rpc.protocol.common.RuleType;
import org.sonarsource.sonarlint.core.rpc.protocol.common.SoftwareQuality;
import org.sonarsource.sonarlint.core.rpc.protocol.common.TextRangeDto;

public final class MarkerUtils {
Expand All @@ -61,8 +58,6 @@ public final class MarkerUtils {
public static final String SONAR_MARKER_ISSUE_TYPE_ATTR = "issuetype";
public static final String SONAR_MARKER_CREATION_DATE_ATTR = "creationdate";
public static final String SONAR_MARKER_ISSUE_ATTRIBUTE_ATTR = "sonarattribute";
public static final String SONAR_MARKER_ISSUE_IMPACTS_ATTR = "sonarimpacts";

// This is used for grouping and has to be set additionally to all impacts
public static final String SONAR_MARKER_ISSUE_HIGHEST_IMPACT_ATTR = "sonarhighestimpact";

Expand Down Expand Up @@ -103,6 +98,11 @@ public static void updateAllSonarMarkerSeverity() throws CoreException {
}
}

@Nullable
public static UUID decodeUuid(@Nullable String encoded) {
return encoded == null ? null : UUID.fromString(encoded);
}

@Nullable
public static String encodeUuid(@Nullable UUID uuid) {
return uuid == null ? null : uuid.toString();
Expand Down Expand Up @@ -144,29 +144,6 @@ public static ImpactSeverity decodeHighestImpact(@Nullable String encoded) {
return encoded == null ? null : ImpactSeverity.valueOf(encoded);
}

@Nullable
public static String encodeImpacts(List<ImpactDto> impacts) {
if (impacts.isEmpty()) {
return null;
}

var mapAsString = new StringBuilder();
for (var impact : impacts) {
mapAsString.append(impact.getSoftwareQuality() + "=" + impact.getImpactSeverity() + ",");
}
return mapAsString.delete(mapAsString.length() - 1, mapAsString.length()).toString();
}

public static Map<SoftwareQuality, ImpactSeverity> decodeImpacts(@Nullable String encoded) {
if (encoded == null) {
return Collections.emptyMap();
}

return Arrays.stream(encoded.split(","))
.map(entry -> entry.split("="))
.collect(Collectors.toMap(entry -> SoftwareQuality.valueOf(entry[0]), entry -> ImpactSeverity.valueOf(entry[1])));
}

/**
* Get the matching status of a specific markers' issue by id
*
Expand Down
2 changes: 1 addition & 1 deletion org.sonarlint.eclipse.ui/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Require-Bundle: org.eclipse.core.runtime,
org.eclipse.text,
org.eclipse.compare,
org.eclipse.core.expressions,
org.sonarsource.sonarlint.core.sonarlint-java-client-osgi;bundle-version="[10.7.0,10.8.0)"
org.sonarsource.sonarlint.core.sonarlint-java-client-osgi;bundle-version="[10.10.0,10.11.0)"
Export-Package: org.sonarlint.eclipse.ui.internal;x-friends:="org.sonarlint.eclipse.core.tests",
org.sonarlint.eclipse.ui.internal.backend;x-friends:="org.sonarlint.eclipse.core.tests",
org.sonarlint.eclipse.ui.internal.notifications;x-friends:="org.sonarlint.eclipse.core.tests",
Expand Down
Loading

0 comments on commit 1e16c5d

Please sign in to comment.