diff --git a/org.sonarlint.eclipse.core.tests/src/test/java/org/sonarlint/eclipse/core/internal/markers/MarkerUtilsTest.java b/org.sonarlint.eclipse.core.tests/src/test/java/org/sonarlint/eclipse/core/internal/markers/MarkerUtilsTest.java index 3b05a724a..b69c76b1c 100644 --- a/org.sonarlint.eclipse.core.tests/src/test/java/org/sonarlint/eclipse/core/internal/markers/MarkerUtilsTest.java +++ b/org.sonarlint.eclipse.core.tests/src/test/java/org/sonarlint/eclipse/core/internal/markers/MarkerUtilsTest.java @@ -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; @@ -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 diff --git a/org.sonarlint.eclipse.core.tests/src/test/java/org/sonarlint/eclipse/core/internal/tracking/SonarLintMarkerUpdaterTest.java b/org.sonarlint.eclipse.core.tests/src/test/java/org/sonarlint/eclipse/core/internal/tracking/SonarLintMarkerUpdaterTest.java index 19a8270ed..0aab26797 100644 --- a/org.sonarlint.eclipse.core.tests/src/test/java/org/sonarlint/eclipse/core/internal/tracking/SonarLintMarkerUpdaterTest.java +++ b/org.sonarlint.eclipse.core.tests/src/test/java/org/sonarlint/eclipse/core/internal/tracking/SonarLintMarkerUpdaterTest.java @@ -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; @@ -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); @@ -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); @@ -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); @@ -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); @@ -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); @@ -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); diff --git a/org.sonarlint.eclipse.core/META-INF/MANIFEST.MF b/org.sonarlint.eclipse.core/META-INF/MANIFEST.MF index 5ab83311e..3f6b36e58 100644 --- a/org.sonarlint.eclipse.core/META-INF/MANIFEST.MF +++ b/org.sonarlint.eclipse.core/META-INF/MANIFEST.MF @@ -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 diff --git a/org.sonarlint.eclipse.core/src/org/sonarlint/eclipse/core/internal/backend/SonarLintBackendService.java b/org.sonarlint.eclipse.core/src/org/sonarlint/eclipse/core/internal/backend/SonarLintBackendService.java index 353797f43..f5437f566 100644 --- a/org.sonarlint.eclipse.core/src/org/sonarlint/eclipse/core/internal/backend/SonarLintBackendService.java +++ b/org.sonarlint.eclipse.core/src/org/sonarlint/eclipse/core/internal/backend/SonarLintBackendService.java @@ -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; @@ -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(); } diff --git a/org.sonarlint.eclipse.core/src/org/sonarlint/eclipse/core/internal/jobs/SonarLintMarkerUpdater.java b/org.sonarlint.eclipse.core/src/org/sonarlint/eclipse/core/internal/jobs/SonarLintMarkerUpdater.java index cc9a9ff89..5b4b2b1ee 100644 --- a/org.sonarlint.eclipse.core/src/org/sonarlint/eclipse/core/internal/jobs/SonarLintMarkerUpdater.java +++ b/org.sonarlint.eclipse.core/src/org/sonarlint/eclipse/core/internal/jobs/SonarLintMarkerUpdater.java @@ -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 { @@ -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()); @@ -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()); @@ -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(); @@ -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()); @@ -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; @@ -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(); diff --git a/org.sonarlint.eclipse.core/src/org/sonarlint/eclipse/core/internal/markers/MarkerUtils.java b/org.sonarlint.eclipse.core/src/org/sonarlint/eclipse/core/internal/markers/MarkerUtils.java index 7a3c51278..5d0622137 100644 --- a/org.sonarlint.eclipse.core/src/org/sonarlint/eclipse/core/internal/markers/MarkerUtils.java +++ b/org.sonarlint.eclipse.core/src/org/sonarlint/eclipse/core/internal/markers/MarkerUtils.java @@ -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; @@ -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 { @@ -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"; @@ -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(); @@ -144,29 +144,6 @@ public static ImpactSeverity decodeHighestImpact(@Nullable String encoded) { return encoded == null ? null : ImpactSeverity.valueOf(encoded); } - @Nullable - public static String encodeImpacts(List 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 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 * diff --git a/org.sonarlint.eclipse.ui/META-INF/MANIFEST.MF b/org.sonarlint.eclipse.ui/META-INF/MANIFEST.MF index 8b04402e3..d1321ecce 100644 --- a/org.sonarlint.eclipse.ui/META-INF/MANIFEST.MF +++ b/org.sonarlint.eclipse.ui/META-INF/MANIFEST.MF @@ -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", diff --git a/org.sonarlint.eclipse.ui/src/org/sonarlint/eclipse/ui/internal/job/DisplayProjectRuleDescriptionJob.java b/org.sonarlint.eclipse.ui/src/org/sonarlint/eclipse/ui/internal/job/DisplayProjectRuleDescriptionJob.java index b793828d2..8c9893179 100644 --- a/org.sonarlint.eclipse.ui/src/org/sonarlint/eclipse/ui/internal/job/DisplayProjectRuleDescriptionJob.java +++ b/org.sonarlint.eclipse.ui/src/org/sonarlint/eclipse/ui/internal/job/DisplayProjectRuleDescriptionJob.java @@ -19,45 +19,27 @@ */ package org.sonarlint.eclipse.ui.internal.job; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; +import java.util.UUID; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; -import org.eclipse.jdt.annotation.Nullable; import org.eclipse.swt.widgets.Display; import org.sonarlint.eclipse.core.SonarLintLogger; import org.sonarlint.eclipse.core.internal.backend.SonarLintBackendService; import org.sonarlint.eclipse.core.internal.jobs.AbstractSonarProjectJob; import org.sonarlint.eclipse.core.resource.ISonarLintProject; import org.sonarlint.eclipse.ui.internal.rule.RuleDetailsPanel; -import org.sonarsource.sonarlint.core.rpc.protocol.backend.rules.EffectiveRuleDetailsDto; -import org.sonarsource.sonarlint.core.rpc.protocol.backend.rules.ImpactDto; -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; /** Update "web browser" view for the project rule description (maybe context based on connection) in a separate thread */ public class DisplayProjectRuleDescriptionJob extends AbstractSonarProjectJob { - private final String ruleKey; - private final RuleType issueType; - private final IssueSeverity issueSeverity; - private final Map issueImpacts; - private final String contextKey; + private final UUID issueId; private final RuleDetailsPanel ruleDetailsPanel; - public DisplayProjectRuleDescriptionJob(ISonarLintProject project, String ruleKey, @Nullable RuleType issueType, - @Nullable IssueSeverity issueSeverity, Map issueImpacts, - @Nullable String contextKey, RuleDetailsPanel ruleDetailsPanel) { - super("Fetching rule description for rule '" + ruleKey + "'...", project); - this.ruleKey = ruleKey; - this.issueType = issueType; - this.issueSeverity = issueSeverity; - this.issueImpacts = issueImpacts; - this.contextKey = contextKey; + public DisplayProjectRuleDescriptionJob(ISonarLintProject project, UUID issueId, + RuleDetailsPanel ruleDetailsPanel) { + super("Fetching rule description for issue '" + issueId + "'...", project); + this.issueId = issueId; this.ruleDetailsPanel = ruleDetailsPanel; } @@ -65,26 +47,19 @@ public DisplayProjectRuleDescriptionJob(ISonarLintProject project, String ruleKe protected IStatus doRun(IProgressMonitor monitor) throws CoreException { try { Display.getDefault().syncExec(ruleDetailsPanel::displayLoadingIndicator); - // Getting the CompletableFuture<...> object before running the UI update to not block the UI thread - var ruleDetails = SonarLintBackendService.get().getEffectiveRuleDetails(getProject(), ruleKey, contextKey).details(); - // Add the actual issue type / severity / impacts - var actualDetails = new EffectiveRuleDetailsDto(ruleKey, ruleDetails.getName(), - issueSeverity != null ? issueSeverity : ruleDetails.getSeverity(), - issueType != null ? issueType : ruleDetails.getType(), ruleDetails.getCleanCodeAttribute(), ruleDetails.getCleanCodeAttributeCategory(), - convert(issueImpacts), ruleDetails.getDescription(), ruleDetails.getParams(), ruleDetails.getLanguage(), null); + // Getting the CompletableFuture<...> object before running the UI update to not block the UI thread + var details = SonarLintBackendService.get() + .getEffectiveIssueDetails(getProject(), issueId) + .getDetails(); - Display.getDefault().syncExec(() -> ruleDetailsPanel.updateRule(actualDetails, actualDetails.getDescription())); + Display.getDefault().syncExec(() -> ruleDetailsPanel.updateRule(details)); } catch (Exception e) { - SonarLintLogger.get().error("Unable to display project rule description for rule " + ruleKey, e); + SonarLintLogger.get().error("Unable to display project rule description for issue " + issueId, e); Display.getDefault().syncExec(ruleDetailsPanel::clearRule); return Status.error(e.getMessage(), e); } return Status.OK_STATUS; } - - private static List convert(Map issueImpacts) { - return issueImpacts.entrySet().stream().map(e -> new ImpactDto(e.getKey(), e.getValue())).collect(Collectors.toList()); - } } diff --git a/org.sonarlint.eclipse.ui/src/org/sonarlint/eclipse/ui/internal/rule/AbstractRuleHeaderPanel.java b/org.sonarlint.eclipse.ui/src/org/sonarlint/eclipse/ui/internal/rule/AbstractRuleHeaderPanel.java index 49305c924..c7aef8287 100644 --- a/org.sonarlint.eclipse.ui/src/org/sonarlint/eclipse/ui/internal/rule/AbstractRuleHeaderPanel.java +++ b/org.sonarlint.eclipse.ui/src/org/sonarlint/eclipse/ui/internal/rule/AbstractRuleHeaderPanel.java @@ -25,15 +25,17 @@ import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.sonarlint.eclipse.core.internal.utils.StringUtils; -import org.sonarsource.sonarlint.core.rpc.protocol.backend.rules.AbstractRuleDto; public abstract class AbstractRuleHeaderPanel extends Composite { - protected AbstractRuleHeaderPanel(Composite parent, int numColumns) { + protected final String ruleKey; + + protected AbstractRuleHeaderPanel(Composite parent, int numColumns, String ruleKey) { super(parent, SWT.NONE); setLayout(new GridLayout(numColumns, false)); + this.ruleKey = ruleKey; } - public abstract void updateRule(AbstractRuleDto ruleInformation); + public abstract void updateRule(); protected static String clean(@Nullable String txt) { return txt == null diff --git a/org.sonarlint.eclipse.ui/src/org/sonarlint/eclipse/ui/internal/rule/LegacyRuleHeaderPanel.java b/org.sonarlint.eclipse.ui/src/org/sonarlint/eclipse/ui/internal/rule/LegacyRuleHeaderPanel.java index 27c0c41d2..129228874 100644 --- a/org.sonarlint.eclipse.ui/src/org/sonarlint/eclipse/ui/internal/rule/LegacyRuleHeaderPanel.java +++ b/org.sonarlint.eclipse.ui/src/org/sonarlint/eclipse/ui/internal/rule/LegacyRuleHeaderPanel.java @@ -24,7 +24,7 @@ import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; import org.sonarlint.eclipse.ui.internal.SonarLintImages; -import org.sonarsource.sonarlint.core.rpc.protocol.backend.rules.AbstractRuleDto; +import org.sonarsource.sonarlint.core.rpc.protocol.common.StandardModeDetails; /** Rule header for the old CCT */ public class LegacyRuleHeaderPanel extends AbstractRuleHeaderPanel { @@ -34,8 +34,10 @@ public class LegacyRuleHeaderPanel extends AbstractRuleHeaderPanel { private final Label ruleSeverityLabel; private final Label ruleKeyLabel; - public LegacyRuleHeaderPanel(Composite parent) { - super(parent, 5); + private final StandardModeDetails details; + + public LegacyRuleHeaderPanel(Composite parent, StandardModeDetails details, String ruleKey) { + super(parent, 5, ruleKey); ruleTypeIcon = new Label(this, SWT.NONE); ruleTypeLabel = new Label(this, SWT.NONE); @@ -43,19 +45,20 @@ public LegacyRuleHeaderPanel(Composite parent) { ruleSeverityLabel = new Label(this, SWT.LEFT); ruleKeyLabel = new Label(this, SWT.LEFT); ruleKeyLabel.setLayoutData(new GridData(SWT.END, SWT.FILL, true, true)); + this.details = details; } @Override - public void updateRule(AbstractRuleDto ruleInformation) { - var type = ruleInformation.getType(); + public void updateRule() { + var type = details.getType(); ruleTypeIcon.setImage(SonarLintImages.getTypeImage(type)); ruleTypeLabel.setText(clean(type.toString())); - var severity = ruleInformation.getSeverity(); + var severity = details.getSeverity(); ruleSeverityIcon.setImage(SonarLintImages.getSeverityImage(severity)); ruleSeverityLabel.setText(clean(severity.toString())); - ruleKeyLabel.setText(ruleInformation.getKey()); + ruleKeyLabel.setText(ruleKey); layout(); } } diff --git a/org.sonarlint.eclipse.ui/src/org/sonarlint/eclipse/ui/internal/rule/RuleDetailsPanel.java b/org.sonarlint.eclipse.ui/src/org/sonarlint/eclipse/ui/internal/rule/RuleDetailsPanel.java index 74b7cdbdf..74af6993c 100644 --- a/org.sonarlint.eclipse.ui/src/org/sonarlint/eclipse/ui/internal/rule/RuleDetailsPanel.java +++ b/org.sonarlint.eclipse.ui/src/org/sonarlint/eclipse/ui/internal/rule/RuleDetailsPanel.java @@ -40,9 +40,9 @@ import org.eclipse.swt.widgets.Link; import org.eclipse.ui.dialogs.PreferencesUtil; import org.sonarlint.eclipse.ui.internal.properties.RulesConfigurationPage; -import org.sonarsource.sonarlint.core.rpc.protocol.backend.rules.AbstractRuleDto; -import org.sonarsource.sonarlint.core.rpc.protocol.backend.rules.EffectiveRuleDetailsDto; +import org.sonarsource.sonarlint.core.rpc.protocol.backend.issue.EffectiveIssueDetailsDto; import org.sonarsource.sonarlint.core.rpc.protocol.backend.rules.EffectiveRuleParamDto; +import org.sonarsource.sonarlint.core.rpc.protocol.backend.rules.RuleDefinitionDto; import org.sonarsource.sonarlint.core.rpc.protocol.backend.rules.RuleMonolithicDescriptionDto; import org.sonarsource.sonarlint.core.rpc.protocol.backend.rules.RuleSplitDescriptionDto; import org.sonarsource.sonarlint.core.rpc.protocol.common.Either; @@ -104,22 +104,28 @@ private void updateScrollCompositeMinSize() { scrollComposite.setMinSize(scrolledContent.computeSize(width, SWT.DEFAULT)); } - public void updateRule(AbstractRuleDto ruleInformation, Either description) { + public void updateRule(EffectiveIssueDetailsDto details) { try { - ruleNameLabel.setText(ruleInformation.getName()); + ruleNameLabel.setText(details.getName()); ruleNameLabel.requestLayout(); - updateHeader(ruleInformation); - - updateHtmlDescription(description, ruleInformation.getLanguage()); + updateHeader(details); + updateHtmlDescription(details.getDescription(), details.getLanguage()); + updateParameters(details.getParams()); + } catch (SWTException ignored) { + // There might be a race condition between the background job running late and the view already being closed + } + } - if (ruleInformation instanceof EffectiveRuleDetailsDto) { - updateParameters(((EffectiveRuleDetailsDto) ruleInformation).getParams()); - } + public void updateRule(RuleDefinitionDto definition, + Either description) { + try { + ruleNameLabel.setText(definition.getName()); + ruleNameLabel.requestLayout(); - requestLayout(); - updateScrollCompositeMinSize(); - } catch (SWTException ignored) { + updateHeader(definition); + updateHtmlDescription(description, definition.getLanguage()); + } catch (SWTException ignroed) { // There might be a race condition between the background job running late and the view already being closed } } @@ -133,28 +139,40 @@ private void updateHtmlDescription(Either params) { if (ruleParamsPanel != null && !ruleParamsPanel.isDisposed()) { ruleParamsPanel.dispose(); } + if (!params.isEmpty()) { ruleParamsPanel = new Group(scrolledContent, SWT.NONE); ruleParamsPanel.setText("Parameters"); @@ -178,7 +196,11 @@ public void widgetSelected(SelectionEvent e) { for (var param : params) { var paramDefaultValue = param.getDefaultValue(); var defaultValue = paramDefaultValue != null ? paramDefaultValue : "(none)"; - var currentValue = param.getValue(); + + // When in Connected Mode the rules configuration from the server applies and therefore also the parameters. + // When in Standalone Mode this information is saved locally and must be retrieved for the specific parameter! + var currentValue = param.getValue() != null ? param.getValue() : param.getDefaultValue(); + var paramName = new Label(ruleParamsPanel, SWT.BOLD); paramName.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 1, 1)); paramName.setFont(JFaceResources.getFontRegistry().getBold( diff --git a/org.sonarlint.eclipse.ui/src/org/sonarlint/eclipse/ui/internal/rule/RuleHeaderPanel.java b/org.sonarlint.eclipse.ui/src/org/sonarlint/eclipse/ui/internal/rule/RuleHeaderPanel.java index 8960e3c0b..beaed9194 100644 --- a/org.sonarlint.eclipse.ui/src/org/sonarlint/eclipse/ui/internal/rule/RuleHeaderPanel.java +++ b/org.sonarlint.eclipse.ui/src/org/sonarlint/eclipse/ui/internal/rule/RuleHeaderPanel.java @@ -19,17 +19,17 @@ */ package org.sonarlint.eclipse.ui.internal.rule; +import java.util.List; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; import org.sonarlint.eclipse.ui.internal.SonarLintImages; -import org.sonarsource.sonarlint.core.client.utils.CleanCodeAttribute; import org.sonarsource.sonarlint.core.client.utils.ImpactSeverity; import org.sonarsource.sonarlint.core.client.utils.SoftwareQuality; -import org.sonarsource.sonarlint.core.rpc.protocol.backend.rules.AbstractRuleDto; import org.sonarsource.sonarlint.core.rpc.protocol.backend.rules.ImpactDto; +import org.sonarsource.sonarlint.core.rpc.protocol.common.CleanCodeAttribute; /** Rule header for the new CCT */ public class RuleHeaderPanel extends AbstractRuleHeaderPanel { @@ -38,9 +38,11 @@ public class RuleHeaderPanel extends AbstractRuleHeaderPanel { private final SoftwareQualityImpactPanel secondSoftwareQualityImpact; private final SoftwareQualityImpactPanel thirdSoftwareQualityImpact; private final Label ruleKeyLabel; + private final CleanCodeAttribute cleanCodeAttribute; + private final List impacts; - public RuleHeaderPanel(Composite parent) { - super(parent, 5); + public RuleHeaderPanel(Composite parent, CleanCodeAttribute cleanCodeAttribute, List impacts, String ruleKey) { + super(parent, 5, ruleKey); ruleCleanCodeAttributeLabel = new Label(this, SWT.NONE); firstSoftwareQualityImpact = new SoftwareQualityImpactPanel(this, SWT.NONE); @@ -48,20 +50,18 @@ public RuleHeaderPanel(Composite parent) { thirdSoftwareQualityImpact = new SoftwareQualityImpactPanel(this, SWT.LEFT); ruleKeyLabel = new Label(this, SWT.LEFT); ruleKeyLabel.setLayoutData(new GridData(SWT.END, SWT.FILL, true, true)); + this.cleanCodeAttribute = cleanCodeAttribute; + this.impacts = impacts; } @Override - public void updateRule(AbstractRuleDto ruleInformation) { - /** INFO: We assume that the Optional#isPresent() check was already done */ - var cca = ruleInformation.getCleanCodeAttribute(); - var ccaWithLabel = CleanCodeAttribute.fromDto(cca); + public void updateRule() { + var ccaWithLabel = org.sonarsource.sonarlint.core.client.utils.CleanCodeAttribute.fromDto(cleanCodeAttribute); ruleCleanCodeAttributeLabel.setText( clean(ccaWithLabel.getCategory().getLabel()) + " | " + clean(ccaWithLabel.getLabel())); ruleCleanCodeAttributeLabel.setToolTipText( "Clean Code attributes are characteristics code needs to have to be considered clean."); - var impacts = ruleInformation.getDefaultImpacts(); - firstSoftwareQualityImpact.updateImpact(impacts.get(0)); if (impacts.size() > 1) { secondSoftwareQualityImpact.updateImpact(impacts.get(1)); @@ -70,7 +70,7 @@ public void updateRule(AbstractRuleDto ruleInformation) { } } - ruleKeyLabel.setText(ruleInformation.getKey()); + ruleKeyLabel.setText(ruleKey); layout(); } diff --git a/org.sonarlint.eclipse.ui/src/org/sonarlint/eclipse/ui/internal/views/RuleDescriptionWebView.java b/org.sonarlint.eclipse.ui/src/org/sonarlint/eclipse/ui/internal/views/RuleDescriptionWebView.java index bc54761c9..23f81d1b1 100644 --- a/org.sonarlint.eclipse.ui/src/org/sonarlint/eclipse/ui/internal/views/RuleDescriptionWebView.java +++ b/org.sonarlint.eclipse.ui/src/org/sonarlint/eclipse/ui/internal/views/RuleDescriptionWebView.java @@ -141,22 +141,14 @@ private void showRuleDescription(IMarker element) { return; } - var issueType = MarkerUtils.decodeRuleType(element.getAttribute(MarkerUtils.SONAR_MARKER_ISSUE_TYPE_ATTR, null)); - var issueSeverity = MarkerUtils.decodeSeverity( - element.getAttribute(MarkerUtils.SONAR_MARKER_ISSUE_SEVERITY_ATTR, null)); - var issueImpacts = MarkerUtils.decodeImpacts( - element.getAttribute(MarkerUtils.SONAR_MARKER_ISSUE_IMPACTS_ATTR, null)); + var issueId = MarkerUtils.decodeUuid(element.getAttribute(MarkerUtils.SONAR_MARKER_TRACKED_ISSUE_ID_ATTR, null)); // Update project rule description asynchronous var slIssuable = SonarLintUtils.adapt(element.getResource(), ISonarLintIssuable.class, "[RuleDescriptionWebView#showRuleDescription] Try get issueable from marker '" + element.toString() + "'"); if (slIssuable != null) { - new DisplayProjectRuleDescriptionJob( - slIssuable.getProject(), - ruleKey, issueType, issueSeverity, issueImpacts, - element.getAttribute(MarkerUtils.SONAR_MARKER_RULE_DESC_CONTEXT_KEY_ATTR, null), - ruleDetailsPanel) - .schedule(); + new DisplayProjectRuleDescriptionJob(slIssuable.getProject(), issueId, ruleDetailsPanel) + .schedule(); } } diff --git a/pom.xml b/pom.xml index 28977d36c..7f96a9c2f 100644 --- a/pom.xml +++ b/pom.xml @@ -76,7 +76,7 @@ 4.0.8 - 10.7.2.79501 + 10.10.0.79544 11 diff --git a/target-platforms/commons-build.target b/target-platforms/commons-build.target index bc712087b..545ffcba1 100644 --- a/target-platforms/commons-build.target +++ b/target-platforms/commons-build.target @@ -12,7 +12,7 @@ org.sonarsource.sonarlint.core sonarlint-java-client-osgi - 10.7.2.79501 + 10.10.0.79544 jar