diff --git a/integration-test/pom.xml b/integration-test/pom.xml
index 52bb43cf..cdad522a 100644
--- a/integration-test/pom.xml
+++ b/integration-test/pom.xml
@@ -105,6 +105,8 @@
Integration Test PmdExtensionPlugin
pmd
+ java:8.0.0.0,kotlin:2.0.0.0
+ java,kotlin
diff --git a/integration-test/projects/pmd-kotlin-rules/pom.xml b/integration-test/projects/pmd-kotlin-rules/pom.xml
new file mode 100644
index 00000000..81e8e9a2
--- /dev/null
+++ b/integration-test/projects/pmd-kotlin-rules/pom.xml
@@ -0,0 +1,63 @@
+
+ 4.0.0
+
+ com.sonarsource.it.projects
+ pmd-kotlin-rules
+ 1.0-SNAPSHOT
+
+ 1.9.0
+ UTF-8
+
+
+
+
+ org.jetbrains.kotlin
+ kotlin-stdlib
+ ${kotlin.version}
+
+
+
+
+ ${project.basedir}/src/main/kotlin
+
+
+ org.jetbrains.kotlin
+ kotlin-maven-plugin
+ ${kotlin.version}
+
+
+ compile
+
+ compile
+
+
+
+
+
+
+
+
+ org.sonarsource.scanner.maven
+ sonar-maven-plugin
+ 5.2.0.4988
+
+
+
+
+
+
+
+ skipSonar
+
+
+ skipTestProjects
+ true
+
+
+
+ true
+
+
+
+
diff --git a/integration-test/projects/pmd-kotlin-rules/src/main/kotlin/com/example/KotlinErrors.kt b/integration-test/projects/pmd-kotlin-rules/src/main/kotlin/com/example/KotlinErrors.kt
new file mode 100644
index 00000000..5d8881cd
--- /dev/null
+++ b/integration-test/projects/pmd-kotlin-rules/src/main/kotlin/com/example/KotlinErrors.kt
@@ -0,0 +1,19 @@
+package com.example
+
+class KotlinErrors {
+ // This function name is too short, which will trigger the FunctionNameTooShort rule
+ fun fn() {
+ println("This function name is too short")
+ }
+}
+
+// This class overrides equals but not hashCode, which will trigger the OverrideBothEqualsAndHashcode rule
+class EqualsOnly {
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (javaClass != other?.javaClass) return false
+ return true
+ }
+
+ // Missing hashCode() override
+}
\ No newline at end of file
diff --git a/integration-test/src/test/java/com/sonar/it/java/suite/PmdIT.java b/integration-test/src/test/java/com/sonar/it/java/suite/PmdIT.java
index 4fe12f6f..6405efcb 100644
--- a/integration-test/src/test/java/com/sonar/it/java/suite/PmdIT.java
+++ b/integration-test/src/test/java/com/sonar/it/java/suite/PmdIT.java
@@ -71,7 +71,7 @@ void testPmdExtensionsWithDifferentJavaVersions(DefinedJavaVersion version) {
.contains("Start MaximumMethodsCountCheck")
.contains("End MaximumMethodsCountCheck");
- final List issues = retrieveIssues(keyFor(projectName, "pmd/", "Errors"));
+ final List issues = retrieveIssues(keyFor(projectName, "src/main/java", "pmd", "Errors", ".java"));
final List messages = issues
.stream()
@@ -116,13 +116,15 @@ void testJunitRules() {
ORCHESTRATOR.executeBuild(build);
// then
- String testComponentKey = keyFor("pmd-junit-rules", "src/test/java/", "", "ProductionCodeTest" + ".java");
+ // (component -> com.sonarsource.it.projects:pmd-junit-rules:src/test/java/ProductionCodeTest.java)
+ String testComponentKey = keyFor("pmd-junit-rules", "src/test/java", "", "ProductionCodeTest", ".java");
final List testIssues = retrieveIssues(testComponentKey);
assertThat(testIssues).hasSize(1);
assertThat(testIssues.get(0).message()).isEqualTo("Unit tests should not contain more than 1 assert(s).");
assertThat(testIssues.get(0).ruleKey()).isEqualTo("pmd:UnitTestContainsTooManyAsserts");
- final List prodIssues = retrieveIssues(keyFor(projectName, "", "ProductionCode"));
+ // component -> com.sonarsource.it.projects:pmd-junit-rules:src/main/java/ProductionCode.java
+ final List prodIssues = retrieveIssues(keyFor(projectName, "src/main/java", "", "ProductionCode", ".java"));
assertThat(prodIssues).hasSize(1);
assertThat(prodIssues.get(0).message()).contains("Avoid unused private fields such as 'unused'.");
assertThat(prodIssues.get(0).ruleKey()).isEqualTo("pmd:UnusedPrivateField");
@@ -150,11 +152,11 @@ void testRuleAvoidDuplicateLiterals() {
ORCHESTRATOR.executeBuild(build);
// then
+ String avoidDuplicateLiteralsKey = keyFor(projectName, "src/main/java", "", "AvoidDuplicateLiterals", ".java");
final List issues = ORCHESTRATOR.retrieveIssues(
IssueQuery.create()
.rules("pmd:AvoidDuplicateLiterals")
- .components(keyFor(projectName, "", "AvoidDuplicateLiterals")
- )
+ .components(avoidDuplicateLiteralsKey)
);
assertThat(issues)
@@ -191,9 +193,10 @@ void pmdShouldHaveAccessToExternalLibrariesInItsClasspath() {
// then
// PMD7-MIGRATION: added to force one violation in pmdShouldHaveAccessToExternalLibrariesInItsClasspath: is this testing the correct thing?
- final List issues = retrieveIssues(keyFor(projectName, "pmd/", "Bar"));
+ final List issues = retrieveIssues(keyFor(projectName, "src/main/java/", "pmd/", "Errors", ".java"));
+
assertThat(issues)
- .hasSize(1);
+ .hasSize(3);
} catch (HttpException e) {
System.out.println("Failed to associate Project To Quality Profile: " + e.getMessage() + " body: " + e.getBody());
@@ -219,7 +222,8 @@ void pmdShouldRunWithAllRulesEnabled() {
ORCHESTRATOR.executeBuild(build);
// then
- final List issues = retrieveIssues(keyFor(projectName, "pmd/", "Bar"));
+ final List issues = retrieveIssues(keyFor(projectName, "src/main/java", "pmd", "Bar", ".java"));
+
assertThat(issues)
.isNotEmpty();
diff --git a/integration-test/src/test/java/com/sonar/it/java/suite/PmdKotlinIT.java b/integration-test/src/test/java/com/sonar/it/java/suite/PmdKotlinIT.java
new file mode 100644
index 00000000..0ce6f891
--- /dev/null
+++ b/integration-test/src/test/java/com/sonar/it/java/suite/PmdKotlinIT.java
@@ -0,0 +1,128 @@
+/*
+ * SonarQube PMD7 Plugin Integration Test
+ * Copyright (C) 2013-2021 SonarSource SA and others
+ * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl
+ *
+ * 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 com.sonar.it.java.suite;
+
+import com.sonar.it.java.suite.orchestrator.PmdTestOrchestrator;
+import com.sonar.orchestrator.build.BuildResult;
+import com.sonar.orchestrator.build.MavenBuild;
+import com.sonar.orchestrator.http.HttpException;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.sonar.wsclient.issue.Issue;
+import org.sonar.wsclient.issue.IssueQuery;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static com.sonar.it.java.suite.TestUtils.keyFor;
+import static org.assertj.core.api.Assertions.assertThat;
+
+class PmdKotlinIT {
+
+ private static PmdTestOrchestrator orchestrator;
+
+ @BeforeAll
+ static void startSonar() {
+ orchestrator = PmdTestOrchestrator.init();
+ orchestrator.start();
+ }
+
+ @Test
+ void testKotlinRules() {
+ // given
+ final String projectName = "pmd-kotlin-rules";
+ final String suffix = ".kt";
+ final String srcDir = "src/main/kotlin";
+
+ final MavenBuild build = MavenBuild
+ .create(TestUtils.projectPom(projectName))
+ .setCleanSonarGoals();
+
+ try {
+ orchestrator.associateProjectToQualityProfile("pmd-kotlin-profile", projectName, "kotlin");
+
+ // when
+ final BuildResult buildResult = orchestrator.executeBuild(build);
+
+ // then
+ final String log = buildResult.getLogs();
+ assertThat(log).contains("Kotlin");
+
+ final List issues = retrieveIssues(keyFor(projectName, srcDir, "com/example", "KotlinErrors", suffix));
+
+ final List messages = issues
+ .stream()
+ .map(Issue::message)
+ .collect(Collectors.toList());
+
+ assertThat(issues).hasSize(2);
+
+ assertThat(messages)
+ .contains(
+ "Function names should have non-cryptic and clear names.",
+ "Ensure you override both equals() and hashCode()"
+ );
+ } catch (HttpException e) {
+ System.out.println("Failed to associate Project To Quality Profile: " + e.getMessage() + " body: " + e.getBody());
+ throw e;
+ } finally {
+ // Cleanup
+ orchestrator.resetData(projectName);
+ }
+ }
+
+ @Test
+ void pmdKotlinShouldRunWithAllRulesEnabled() {
+ // given
+ final String projectName = "pmd-kotlin-rules";
+ final MavenBuild build = MavenBuild
+ .create(TestUtils.projectPom(projectName))
+ .setCleanPackageSonarGoals();
+ try {
+ orchestrator.associateProjectToQualityProfile("pmd-kotlin-all-rules", projectName, "kotlin");
+
+ // when
+ final BuildResult buildResult = orchestrator.executeBuild(build);
+
+ // then
+ final String log = buildResult.getLogs();
+ assertThat(log).contains("Kotlin");
+
+ final List issues = retrieveIssues(keyFor(projectName, "src/main/kotlin", "com/example", "KotlinErrors", ".kt"));
+
+ assertThat(issues).hasSize(2);
+ Issue functionNameTooShort = issues.stream().filter(i -> i.ruleKey().equals("pmd-kotlin:FunctionNameTooShort")).findFirst().orElseThrow();
+ assertThat(functionNameTooShort.severity()).isEqualTo("MAJOR");
+
+ } catch (HttpException e) {
+ System.err.println("Failed to associate Project To Quality Profile: " + e.getMessage() + " body: " + e.getBody());
+ throw e;
+ } finally {
+ // Cleanup
+ orchestrator.resetData(projectName);
+ }
+ }
+
+ private List retrieveIssues(String componentKey) {
+ final IssueQuery issueQuery = IssueQuery.create();
+ issueQuery.urlParams().put("componentKeys", componentKey);
+ return orchestrator.retrieveIssues(issueQuery);
+ }
+}
diff --git a/integration-test/src/test/java/com/sonar/it/java/suite/SanitySonarVersionsIT.java b/integration-test/src/test/java/com/sonar/it/java/suite/SanitySonarVersionsIT.java
new file mode 100644
index 00000000..d9f0f4b8
--- /dev/null
+++ b/integration-test/src/test/java/com/sonar/it/java/suite/SanitySonarVersionsIT.java
@@ -0,0 +1,74 @@
+/*
+ * SonarQube PMD7 Plugin Integration Test
+ */
+package com.sonar.it.java.suite;
+
+import com.sonar.it.java.suite.orchestrator.PmdTestOrchestrator;
+import com.sonar.orchestrator.build.MavenBuild;
+import com.sonar.orchestrator.build.BuildResult;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Sanity check that our integration test suite can start and run against both
+ * the lowest and highest supported SonarQube versions.
+ */
+class SanitySonarVersionsIT {
+
+ private static final String SONAR_VERSION_KEY = "test.sonar.version";
+
+ @ParameterizedTest(name = "sanity on SonarQube {0}")
+ @ValueSource(strings = {
+ // Lowest supported SonarQube LTS line
+ "LATEST_RELEASE[9.9]",
+ // Highest supported SonarQube current line (see README table)
+ "LATEST_RELEASE[25.6]"
+ })
+ void sanity_runs_on_lowest_and_highest_supported_versions(String sonarqubeVersion) {
+ final String previous = System.getProperty(SONAR_VERSION_KEY);
+ System.setProperty(SONAR_VERSION_KEY, sonarqubeVersion);
+
+ PmdTestOrchestrator orchestrator = null;
+ try {
+ orchestrator = PmdTestOrchestrator.init();
+ orchestrator.start();
+
+ final String projectName = "pmd-extensions";
+ final MavenBuild build = MavenBuild
+ .create(TestUtils.projectPom(projectName))
+ .setCleanSonarGoals()
+ // keep analysis minimal for sanity run
+ .setProperty("sonar.java.binaries", ".");
+
+ orchestrator.associateProjectToQualityProfile("pmd-extensions-profile", projectName);
+ final BuildResult result = orchestrator.executeBuild(build); // will throw if analysis fails
+ assertThat(result.getLogs()).contains("[INFO] Sensor PmdSensor [pmd]");
+
+ // Additionally run a minimal Kotlin project analysis to ensure Kotlin support works
+ final String kotlinProject = "pmd-kotlin-rules";
+ final MavenBuild kotlinBuild = MavenBuild
+ .create(TestUtils.projectPom(kotlinProject))
+ .setCleanSonarGoals();
+ orchestrator.associateProjectToQualityProfile("pmd-kotlin-profile", kotlinProject, "kotlin");
+ final BuildResult kotlinResult = orchestrator.executeBuild(kotlinBuild);
+ assertThat(kotlinResult.getLogs()).contains("[INFO] Sensor PmdSensor [pmd]");
+ }
+ finally {
+ // restore previous property to not affect other tests
+ if (previous != null) {
+ System.setProperty(SONAR_VERSION_KEY, previous);
+ } else {
+ System.clearProperty(SONAR_VERSION_KEY);
+ }
+ if (orchestrator != null) {
+ try {
+ orchestrator.stop();
+ } catch (Throwable ignored) {
+ // ignore
+ }
+ }
+ }
+ }
+}
diff --git a/integration-test/src/test/java/com/sonar/it/java/suite/TestUtils.java b/integration-test/src/test/java/com/sonar/it/java/suite/TestUtils.java
index 1928f415..a003069e 100644
--- a/integration-test/src/test/java/com/sonar/it/java/suite/TestUtils.java
+++ b/integration-test/src/test/java/com/sonar/it/java/suite/TestUtils.java
@@ -22,6 +22,7 @@
import java.io.File;
import org.apache.commons.io.FileUtils;
+import org.jetbrains.annotations.NotNull;
class TestUtils {
@@ -40,12 +41,28 @@ static File projectPom(String projectName) {
return new File(HOME, "projects/" + projectName + "/pom.xml");
}
+ static String keyFor(String projectKey) {
+ return "com.sonarsource.it.projects:" + projectKey;
+ }
+
static String keyFor(String projectKey, String srcDir, String pkgDir, String cls) {
- return "com.sonarsource.it.projects:" + projectKey + ":" + srcDir + pkgDir + cls;
+ srcDir = ensureEndsWithSlash(srcDir);
+ pkgDir = ensureEndsWithSlash(pkgDir);
+ return keyFor(projectKey) + ":" + srcDir + pkgDir + cls;
+ }
+
+ private static @NotNull String ensureEndsWithSlash(String srcDir) {
+ if (!srcDir.isEmpty() && !srcDir.endsWith("/")) {
+ srcDir = srcDir + "/";
+ }
+ return srcDir;
}
- static String keyFor(String projectKey, String pkgDir, String cls) {
- return keyFor(projectKey, "src/main/java/", pkgDir, cls + ".java");
+ static String keyFor(String projectKey, String srcDir, String pkgDir, String cls, String suffix) {
+ if (!suffix.isEmpty() && !suffix.startsWith(".")) {
+ suffix = "." + suffix;
+ }
+ return keyFor(projectKey, srcDir, pkgDir, cls + suffix);
}
}
diff --git a/integration-test/src/test/java/com/sonar/it/java/suite/orchestrator/PmdTestOrchestrator.java b/integration-test/src/test/java/com/sonar/it/java/suite/orchestrator/PmdTestOrchestrator.java
index 2b6f5673..a46d7ff6 100644
--- a/integration-test/src/test/java/com/sonar/it/java/suite/orchestrator/PmdTestOrchestrator.java
+++ b/integration-test/src/test/java/com/sonar/it/java/suite/orchestrator/PmdTestOrchestrator.java
@@ -41,6 +41,7 @@
public class PmdTestOrchestrator {
private static final String SONAR_JAVA_PLUGIN_VERSION_KEY = "test.sonar.plugin.version.java";
+ private static final String SONAR_KOTLIN_PLUGIN_VERSION_KEY = "test.sonar.plugin.version.kotlin";
private static final String SONAR_VERSION_KEY = "test.sonar.version";
private static final String LANGUAGE_KEY = "java";
private static final String CENTRAL_MAVEN = "https://repo1.maven.org/maven2";
@@ -75,7 +76,23 @@ public void start() {
delegate.start();
}
+ public void stop() {
+ try {
+ // OrchestratorRule typically exposes stop(); if not, close() will be called by JUnit rule, but here we drive it manually.
+ delegate.stop();
+ } catch (Throwable t) {
+ // ignore stop failures to avoid masking test results
+ System.out.println("WARN: Failed to stop orchestrator cleanly: " + t.getMessage());
+ }
+ }
+
public BuildResult executeBuild(MavenBuild build) {
+ // use this to enable debug: build.setDebugLogs(true)
+ // avoid this: [DEBUG] Plugins not loaded because they are optional: [java, pmd]
+ // and the following: Cannot invoke "org.sonar.core.platform.ExplodedPlugin.getPluginInfo()" because the return value of "java.util.Map.get(Object)" is null
+ // sonar.plugins.downloadOnlyRequired turned to default "true" in SonarQube 10.5": https://sonarsource.atlassian.net/browse/SONAR-22074
+ // update: fixed by specifying required plugins in the plugin manifests!
+ // use this to override: build.setProperty("sonar.plugins.downloadOnlyRequired", "false")
return delegate.executeBuild(build);
}
@@ -87,27 +104,39 @@ public List retrieveIssues(IssueQuery query) {
}
public void associateProjectToQualityProfile(String profile, String project) {
+ associateProjectToQualityProfile(profile, project, LANGUAGE_KEY);
+ }
+
+ public void associateProjectToQualityProfile(String profile, String project, String language) {
final String projectKey = deriveProjectKey(project);
delegate.getServer().provisionProject(projectKey, project);
- delegate.getServer().associateProjectToQualityProfile(projectKey, LANGUAGE_KEY, profile);
+ delegate.getServer().associateProjectToQualityProfile(projectKey, language, profile);
}
public static PmdTestOrchestrator init() {
try {
final OrchestratorRule orchestrator = OrchestratorRule
- .builderEnv().useDefaultAdminCredentialsForBuilds(true)
+ .builderEnv()
+ .useDefaultAdminCredentialsForBuilds(true)
.setSonarVersion(determineSonarqubeVersion())
.addPlugin(MavenLocation.create(
"org.sonarsource.java",
"sonar-java-plugin",
determineJavaPluginVersion()
))
+ .addPlugin(MavenLocation.create(
+ "org.sonarsource.kotlin",
+ "sonar-kotlin-plugin",
+ determineKotlinPluginVersion()
+ ))
.addPlugin(byWildcardMavenFilename(new File("../sonar-pmd-plugin/target"), "sonar-pmd-plugin-*.jar"))
.addPlugin(byWildcardMavenFilename(new File("./target"), "integration-test-*.jar"))
.restoreProfileAtStartup(ofClasspath("/com/sonar/it/java/PmdTest/pmd-extensions-profile.xml"))
.restoreProfileAtStartup(ofClasspath("/com/sonar/it/java/PmdTest/pmd-backup.xml"))
.restoreProfileAtStartup(ofClasspath("/com/sonar/it/java/PmdTest/pmd-all-rules.xml"))
.restoreProfileAtStartup(ofClasspath("/com/sonar/it/java/PmdTest/pmd-test-rule.xml"))
+ .restoreProfileAtStartup(ofClasspath("/com/sonar/it/java/PmdTest/pmd-kotlin-profile.xml"))
+ .restoreProfileAtStartup(ofClasspath("/com/sonar/it/java/PmdTest/pmd-kotlin-all-rules.xml"))
.build();
return new PmdTestOrchestrator(orchestrator);
@@ -123,10 +152,14 @@ private static String deriveProjectKey(String projectName) {
}
private static String determineJavaPluginVersion() {
- return System.getProperty(SONAR_JAVA_PLUGIN_VERSION_KEY, "LATEST_RELEASE[8.15]"); // use 8.9 to test with SQ 9.9
+ return System.getProperty(SONAR_JAVA_PLUGIN_VERSION_KEY, "LATEST_RELEASE[8.9]"); // use 8.9 to test with SQ 9.9
+ }
+
+ private static String determineKotlinPluginVersion() {
+ return System.getProperty(SONAR_KOTLIN_PLUGIN_VERSION_KEY, "LATEST_RELEASE[2.23]");
}
private static String determineSonarqubeVersion() {
- return System.getProperty(SONAR_VERSION_KEY, "LATEST_RELEASE[25.6]"); // use SQ 9.9.4 to test with old version
+ return System.getProperty(SONAR_VERSION_KEY, "LATEST_RELEASE[25.3]"); // use SQ 9.9.4 to test with old version
}
}
diff --git a/integration-test/src/test/resources/com/sonar/it/java/PmdTest/pmd-kotlin-all-rules.xml b/integration-test/src/test/resources/com/sonar/it/java/PmdTest/pmd-kotlin-all-rules.xml
new file mode 100644
index 00000000..ea1391c6
--- /dev/null
+++ b/integration-test/src/test/resources/com/sonar/it/java/PmdTest/pmd-kotlin-all-rules.xml
@@ -0,0 +1,17 @@
+
+
+ pmd-kotlin-all-rules
+ kotlin
+
+
+ pmd-kotlin
+ FunctionNameTooShort
+ MAJOR
+
+
+ pmd-kotlin
+ OverrideBothEqualsAndHashcode
+ MAJOR
+
+
+
diff --git a/integration-test/src/test/resources/com/sonar/it/java/PmdTest/pmd-kotlin-profile.xml b/integration-test/src/test/resources/com/sonar/it/java/PmdTest/pmd-kotlin-profile.xml
new file mode 100644
index 00000000..c50b5369
--- /dev/null
+++ b/integration-test/src/test/resources/com/sonar/it/java/PmdTest/pmd-kotlin-profile.xml
@@ -0,0 +1,17 @@
+
+
+ pmd-kotlin-profile
+ kotlin
+
+
+ pmd-kotlin
+ FunctionNameTooShort
+ CRITICAL
+
+
+ pmd-kotlin
+ OverrideBothEqualsAndHashcode
+ MAJOR
+
+
+
diff --git a/pom.xml b/pom.xml
index 9bfb0c81..c28d85e8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -74,15 +74,14 @@
3.27.6
3.18.0
2.0.1
- 8.18.0.40025
33.5.0-jre
- 2.7.1.392
2.0.6.1
1.23.0.740
- 25.9.0.112764
- 13.0.0.3026
- 8.17.1.39878
+ 25.6.0.109173
+ 13.2.0.3137
+ 8.18.0.40025
+ 2.7.1.392
5.6.2.2625
5.1
diff --git a/sonar-pmd-plugin/pom.xml b/sonar-pmd-plugin/pom.xml
index 21585246..6d684ec6 100644
--- a/sonar-pmd-plugin/pom.xml
+++ b/sonar-pmd-plugin/pom.xml
@@ -183,6 +183,7 @@
org.sonar.plugins.pmd.PmdPlugin
Analyze Java and Kotlin code with PMD.
java,kotlin
+ java:8.0.0.0,kotlin:2.0.0.0
diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdConstants.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdConstants.java
index d8bb5323..56a5c1a4 100644
--- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdConstants.java
+++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdConstants.java
@@ -29,6 +29,7 @@ public final class PmdConstants {
public static final String MAIN_KOTLIN_REPOSITORY_KEY = "pmd-kotlin";
public static final String REPOSITORY_NAME = "PMD";
public static final String REPOSITORY_KOTLIN_NAME = "PMD Kotlin";
+
public static final String XPATH_CLASS = "net.sourceforge.pmd.lang.rule.xpath.XPathRule";
public static final String XPATH_EXPRESSION_PARAM = "xpath";
public static final String XPATH_MESSAGE_PARAM = "message";
diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdPlugin.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdPlugin.java
index 0936dcc1..9c516dfb 100644
--- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdPlugin.java
+++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdPlugin.java
@@ -37,7 +37,6 @@ public void define(Context context) {
.name("Generate XML Report")
.hidden()
.build(),
-
PmdSensor.class,
PmdConfiguration.class,
PmdJavaExecutor.class,