Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
/*
* SonarLint for Eclipse
* Copyright (C) SonarSource Sàrl
* sonarlint@sonarsource.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.sonarlint.eclipse.jdt.internal;

import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.JavaCore;
import org.junit.After;
import org.junit.Test;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class SuppressWarningsQuickFixTest {
private static final SuppressWarningsQuickFixGenerator generator = new SuppressWarningsQuickFixGenerator();

@After
public void after() {
var options = JavaCore.getOptions();
options.put(JavaCore.COMPILER_PB_UNHANDLED_WARNING_TOKEN, JavaCore.WARNING);
JavaCore.setOptions(options);
}

@Test
public void testIrrelevantMarkers() throws CoreException {
var marker = mock(IMarker.class);
when(marker.getType()).thenReturn("noJavaProblem");

assertThat(generator.hasResolutions(marker)).isFalse();
assertThat(generator.getResolutions(marker)).isEmpty();

when(marker.getType()).thenReturn(SuppressWarningsQuickFixGenerator.JAVA_PROBLEM_TYPE);
when(marker.getAttribute(IMarker.MESSAGE)).thenReturn(null);

assertThat(generator.hasResolutions(marker)).isFalse();

when(marker.getAttribute(IMarker.MESSAGE)).thenReturn(SuppressWarningsQuickFixGenerator.MARKER_MESSAGE_GENERAL);

assertThat(generator.hasResolutions(marker)).isFalse();
}

@Test
public void testRelevantMarkers() throws CoreException {
var marker = getRelevantMarker();
assertThat(generator.hasResolutions(marker)).isTrue();

when(marker.getAttribute(IMarker.MESSAGE)).thenReturn(SuppressWarningsQuickFixGenerator.MARKER_MESSAGE_GENERAL
+ SuppressWarningsQuickFixGenerator.MARKER_MESSAGE_JAVA_SECURITY_ISSUE);
assertThat(generator.hasResolutions(marker)).isTrue();

when(marker.getAttribute(IMarker.MESSAGE)).thenReturn(SuppressWarningsQuickFixGenerator.MARKER_MESSAGE_GENERAL
+ SuppressWarningsQuickFixGenerator.MARKER_MESSAGE_JAVA_BUGS_ISSUE);
assertThat(generator.hasResolutions(marker)).isTrue();

when(marker.getAttribute(IMarker.MESSAGE)).thenReturn(SuppressWarningsQuickFixGenerator.MARKER_MESSAGE_GENERAL
+ SuppressWarningsQuickFixGenerator.MARKER_MESSAGE_JAVA_ARCHITECTURE_ISSUE);
assertThat(generator.hasResolutions(marker)).isTrue();
}

@Test
public void testQuickFix() throws CoreException {
var marker = getRelevantMarker();

var quickFix = getQuickFix(marker);
assertThat(quickFix.getLabel()).contains("SonarQube");
assertThat(quickFix.getDescription()).contains("SonarQube");

quickFix.run(marker);
assertThat(JavaCore.getOption(JavaCore.COMPILER_PB_UNHANDLED_WARNING_TOKEN)).isEqualTo(JavaCore.IGNORE);
}

/**
* This tests the conditions to check whether the project related resource has a project and therefore can delegate
* it to the JDT logic to create a Java project. As there is no project, it is not possible.
*/
@Test
public void testWithoutProjectMarker() throws CoreException {
var resourceWithoutProject = mock(IResource.class);
when(resourceWithoutProject.getProject()).thenReturn(null);

var markerWithResource = getRelevantMarker();
when(markerWithResource.getResource()).thenReturn(resourceWithoutProject);

var quickFix = getQuickFix(markerWithResource);
quickFix.run(markerWithResource);
assertThat(JavaCore.getOption(JavaCore.COMPILER_PB_UNHANDLED_WARNING_TOKEN)).isEqualTo(JavaCore.IGNORE);
}

/**
* This tests the marker with a project, but the JavaModel cannot be mocked and therefore the Java project created
* by JDT logic is closed. The quickfix therefore falls back to the global options.
*
* The JavaModel and the related logic can only be tested by an integration test which is quite costly.
*/
@Test
public void testClosedJavaProjectMarker() throws CoreException {
var closedProject = mock(IProject.class);
when(closedProject.getType()).thenReturn(IResource.PROJECT);

var resourceWithProject = mock(IResource.class);
when(resourceWithProject.getProject()).thenReturn(closedProject);

var markerWithResource = getRelevantMarker();
when(markerWithResource.getResource()).thenReturn(resourceWithProject);

var quickFix = getQuickFix(markerWithResource);
quickFix.run(markerWithResource);

// This means the option is not applied on the project but global level.
assertThat(JavaCore.getOption(JavaCore.COMPILER_PB_UNHANDLED_WARNING_TOKEN)).isEqualTo(JavaCore.IGNORE);
}

private IMarker getRelevantMarker() throws CoreException {
var marker = mock(IMarker.class);
when(marker.getType()).thenReturn(SuppressWarningsQuickFixGenerator.JAVA_PROBLEM_TYPE);
when(marker.getAttribute(IMarker.MESSAGE)).thenReturn(SuppressWarningsQuickFixGenerator.MARKER_MESSAGE_GENERAL
+ SuppressWarningsQuickFixGenerator.MARKER_MESSAGE_JAVA_ISSUE);
return marker;
}

private SuppressWarningsQuickFix getQuickFix(IMarker marker) {
var quickFixes = generator.getResolutions(marker);
assertThat(quickFixes).hasSize(1);
return (SuppressWarningsQuickFix) quickFixes[0];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,16 @@ protected IStatus run(IProgressMonitor monitor) {
embeddedPlugins.put("web", requireNonNull(PluginPathHelper.findEmbeddedHtmlPlugin(), "HTML plugin not found"));
embeddedPlugins.put("xml", requireNonNull(PluginPathHelper.findEmbeddedXmlPlugin(), "XML plugin not found"));
embeddedPlugins.put("text", requireNonNull(PluginPathHelper.findEmbeddedSecretsPlugin(), "Secrets plugin not found"));
embeddedPlugins.put("cpp", requireNonNull(PluginPathHelper.findEmbeddedCFamilyPlugin(), "CFamily plugin not found"));

// In forks of SonarQube for Eclipse the CFamily analyzer is not available (Maven option
// "-Dskip-sonarsource-repo"). In this case the plug-in would not start when it is
// required, we therefore keep this not strictly required.
var cFamilyPlugin = PluginPathHelper.findEmbeddedCFamilyPlugin();
if (cFamilyPlugin != null) {
embeddedPlugins.put("cpp", cFamilyPlugin);
} else {
SonarLintLogger.get().info("CFamily plug-in not found - C/C++ analysis will not be available");
}
Comment thread
thahnen marked this conversation as resolved.

var sqConnections = ConnectionSynchronizer.buildSqConnectionDtos();
var scConnections = ConnectionSynchronizer.buildScConnectionDtos();
Expand Down
11 changes: 11 additions & 0 deletions org.sonarlint.eclipse.jdt/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,15 @@
class="org.sonarlint.eclipse.jdt.internal.JavaProjectConfiguratorExtension">
</enhancer>
</extension>

<!--
This custom Quick Fix provider is added to all markers set by Eclipse JDT (Java Problem) for
"@SuppressWarnings(...)" annotations for SonarQube issues that are not known to JDT itself,
therefore the marker.
-->
<extension point="org.eclipse.ui.ide.markerResolution">
<markerResolutionGenerator
markerType="org.eclipse.jdt.core.problem"
class="org.sonarlint.eclipse.jdt.internal.SuppressWarningsQuickFixGenerator" />
</extension>
</plugin>
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public JavaProjectConfiguratorExtension() {
javaProjectConfigurator = jdtPresent ? new JdtUtils() : null;
}

private static boolean isJdtPresent() {
static boolean isJdtPresent() {
return isClassPresentAtRuntime("org.eclipse.jdt.core.JavaCore");
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* SonarLint for Eclipse
* Copyright (C) SonarSource Sàrl
* sonarlint@sonarsource.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.sonarlint.eclipse.jdt.internal;

import org.eclipse.core.resources.IMarker;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.swt.graphics.Image;
import org.eclipse.ui.IMarkerResolution2;
import org.sonarlint.eclipse.ui.internal.SonarLintImages;

public class SuppressWarningsQuickFix implements IMarkerResolution2 {
@Override
public String getLabel() {
return "Disable warnings on \"@SuppressWarnings(...)\" for SonarQube issues";
}

@Override
public String getDescription() {
return "SonarQube uses custom ids that can be set in \"@SuppressWarnings\" to be picked up by the language "
+ "analyzers to suppress potential rule violations. Eclipse JDT does not recognize these IDs and reports them "
+ "as unsupported. This quick fix will disable this compiler warning on the project level if project specific "
+ "Eclipse JDT configurations are available, otherwise on the workspace level.";
}

@Override
public Image getImage() {
return SonarLintImages.RESOLUTION_QUICKFIX_CHANGE;
}

@Override
public void run(IMarker marker) {
var resource = marker.getResource();
if (resource != null) {
var javaProject = JavaCore.create(resource.getProject());
Comment thread
thahnen marked this conversation as resolved.
if (javaProject != null && javaProject.exists()) {
var projectOptions = javaProject.getOptions(false);
if (!projectOptions.isEmpty()) {
projectOptions.put(JavaCore.COMPILER_PB_UNHANDLED_WARNING_TOKEN, JavaCore.IGNORE);
javaProject.setOptions(projectOptions);
return;
}
}
}

var options = JavaCore.getOptions();
options.put(JavaCore.COMPILER_PB_UNHANDLED_WARNING_TOKEN, JavaCore.IGNORE);
JavaCore.setOptions(options);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* SonarLint for Eclipse
* Copyright (C) SonarSource Sàrl
* sonarlint@sonarsource.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.sonarlint.eclipse.jdt.internal;

import org.eclipse.core.resources.IMarker;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.ui.IMarkerResolution;
import org.eclipse.ui.IMarkerResolutionGenerator2;
import org.sonarlint.eclipse.core.SonarLintLogger;

/**
* Generator for the Quick Fox on the "Unsupported @SuppressWarnings(...)" marker that is added when the value(s)
* provided is one indicating a SonarQube-related rule - these are unknown to Eclipse JDT.
*/
public class SuppressWarningsQuickFixGenerator implements IMarkerResolutionGenerator2 {
static final String JAVA_PROBLEM_TYPE = "org.eclipse.jdt.core.problem"; //$NON-NLS-1$
static final String MARKER_MESSAGE_GENERAL = "Unsupported @SuppressWarnings"; //$NON-NLS-1$
static final String MARKER_MESSAGE_JAVA_ISSUE = "java:"; //$NON-NLS-1$
static final String MARKER_MESSAGE_JAVA_SECURITY_ISSUE = "javasecurity:"; //$NON-NLS-1$
static final String MARKER_MESSAGE_JAVA_BUGS_ISSUE = "javabugs:"; //$NON-NLS-1$
static final String MARKER_MESSAGE_JAVA_ARCHITECTURE_ISSUE = "javaarchitecture:"; //$NON-NLS-1$

@Override
public IMarkerResolution[] getResolutions(IMarker marker) {
if (isSuppressWarningsJavaProblem(marker)) {
return new IMarkerResolution[] {new SuppressWarningsQuickFix()};
}
return new IMarkerResolution[0];
}

@Override
public boolean hasResolutions(IMarker marker) {
return isSuppressWarningsJavaProblem(marker);
}

private boolean isSuppressWarningsJavaProblem(IMarker marker) {
if (!JavaProjectConfiguratorExtension.isJdtPresent()) {
return false;
}

try {
var isJavaProblem = marker.getType().equals(JAVA_PROBLEM_TYPE);
var message = (String) marker.getAttribute(IMarker.MESSAGE);
Comment thread
thahnen marked this conversation as resolved.
return isJavaProblem && message != null && message.contains(MARKER_MESSAGE_GENERAL)
&& (message.toLowerCase().contains(MARKER_MESSAGE_JAVA_ISSUE)
|| message.toLowerCase().contains(MARKER_MESSAGE_JAVA_SECURITY_ISSUE)
|| message.toLowerCase().contains(MARKER_MESSAGE_JAVA_BUGS_ISSUE)
|| message.toLowerCase().contains(MARKER_MESSAGE_JAVA_ARCHITECTURE_ISSUE));
} catch (CoreException err) {
SonarLintLogger.get().error(err.getMessage(), err);
return false;
}
}
}
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.compare,
org.eclipse.core.expressions,
org.sonarsource.sonarlint.core.sonarlint-java-client-osgi;bundle-version="[11.2.0,11.3.0)"
Export-Package: org.sonarlint.eclipse.ui.internal;x-friends:="org.sonarlint.eclipse.core.tests",
Export-Package: org.sonarlint.eclipse.ui.internal;x-friends:="org.sonarlint.eclipse.core.tests,org.sonarlint.eclipse.jdt",
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",
org.sonarlint.eclipse.ui.internal.popup;x-friends:="org.sonarlint.eclipse.core.tests",
Expand Down
Loading