diff --git a/detekt-cli/src/main/kotlin/io/gitlab/arturbosch/detekt/cli/CliArgs.kt b/detekt-cli/src/main/kotlin/io/gitlab/arturbosch/detekt/cli/CliArgs.kt index b223993bf1c..851f0a2ee8e 100644 --- a/detekt-cli/src/main/kotlin/io/gitlab/arturbosch/detekt/cli/CliArgs.kt +++ b/detekt-cli/src/main/kotlin/io/gitlab/arturbosch/detekt/cli/CliArgs.kt @@ -193,6 +193,13 @@ class CliArgs { ) var jvmTarget: String = JvmTarget.DEFAULT.description + @Parameter( + names = ["--jdk-home"], + description = "EXPERIMENTAL: Use a custom JDK home directory to include into the classpath", + converter = PathConverter::class + ) + var jdkHome: Path? = null + @Parameter( names = ["--version"], description = "Prints the detekt CLI version." diff --git a/detekt-cli/src/main/kotlin/io/gitlab/arturbosch/detekt/cli/Spec.kt b/detekt-cli/src/main/kotlin/io/gitlab/arturbosch/detekt/cli/Spec.kt index cc920fdd848..4d5eaa55cef 100644 --- a/detekt-cli/src/main/kotlin/io/gitlab/arturbosch/detekt/cli/Spec.kt +++ b/detekt-cli/src/main/kotlin/io/gitlab/arturbosch/detekt/cli/Spec.kt @@ -68,6 +68,7 @@ internal fun CliArgs.createSpec(output: Appendable, error: Appendable): Processi jvmTarget = args.jvmTarget languageVersion = args.languageVersion?.versionString classpath = args.classpath?.trim() + jdkHome = args.jdkHome } } } diff --git a/detekt-core/src/main/kotlin/io/gitlab/arturbosch/detekt/core/settings/EnvironmentAware.kt b/detekt-core/src/main/kotlin/io/gitlab/arturbosch/detekt/core/settings/EnvironmentAware.kt index 89fa882894c..7f671a9741f 100644 --- a/detekt-core/src/main/kotlin/io/gitlab/arturbosch/detekt/core/settings/EnvironmentAware.kt +++ b/detekt-core/src/main/kotlin/io/gitlab/arturbosch/detekt/core/settings/EnvironmentAware.kt @@ -33,7 +33,8 @@ internal class EnvironmentFacade( projectSpec.inputPaths.toList(), classpath, compilerSpec.parseLanguageVersion(), - compilerSpec.parseJvmTarget() + compilerSpec.parseJvmTarget(), + compilerSpec.jdkHome, ) createKotlinCoreEnvironment(compilerConfiguration, disposable) } diff --git a/detekt-gradle-plugin/settings.gradle.kts b/detekt-gradle-plugin/settings.gradle.kts index feb401417fd..730717cc790 100644 --- a/detekt-gradle-plugin/settings.gradle.kts +++ b/detekt-gradle-plugin/settings.gradle.kts @@ -2,6 +2,8 @@ pluginManagement { includeBuild("../build-logic") } +includeBuild("..") + dependencyResolutionManagement { versionCatalogs { create("libs") { diff --git a/detekt-gradle-plugin/src/main/kotlin/io/gitlab/arturbosch/detekt/Detekt.kt b/detekt-gradle-plugin/src/main/kotlin/io/gitlab/arturbosch/detekt/Detekt.kt index ff1876a7f01..7a7d29cb0a1 100644 --- a/detekt-gradle-plugin/src/main/kotlin/io/gitlab/arturbosch/detekt/Detekt.kt +++ b/detekt-gradle-plugin/src/main/kotlin/io/gitlab/arturbosch/detekt/Detekt.kt @@ -19,6 +19,7 @@ import io.gitlab.arturbosch.detekt.invoke.DetektInvoker import io.gitlab.arturbosch.detekt.invoke.DisableDefaultRuleSetArgument import io.gitlab.arturbosch.detekt.invoke.FailFastArgument import io.gitlab.arturbosch.detekt.invoke.InputArgument +import io.gitlab.arturbosch.detekt.invoke.JdkHomeArgument import io.gitlab.arturbosch.detekt.invoke.JvmTargetArgument import io.gitlab.arturbosch.detekt.invoke.LanguageVersionArgument import io.gitlab.arturbosch.detekt.invoke.ParallelArgument @@ -26,6 +27,7 @@ import io.gitlab.arturbosch.detekt.invoke.isDryRunEnabled import org.gradle.api.Action import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.file.Directory +import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.FileTree import org.gradle.api.file.RegularFile import org.gradle.api.file.RegularFileProperty @@ -38,6 +40,7 @@ import org.gradle.api.tasks.Classpath import org.gradle.api.tasks.Console import org.gradle.api.tasks.IgnoreEmptyDirectories import org.gradle.api.tasks.Input +import org.gradle.api.tasks.InputDirectory import org.gradle.api.tasks.InputFile import org.gradle.api.tasks.InputFiles import org.gradle.api.tasks.Internal @@ -96,6 +99,11 @@ abstract class Detekt @Inject constructor( get() = jvmTargetProp.get() set(value) = jvmTargetProp.set(value) + @get:InputDirectory + @get:PathSensitive(PathSensitivity.ABSOLUTE) + @get:Optional + abstract val jdkHome: DirectoryProperty + @get:Internal internal abstract val debugProp: Property var debug: Boolean @@ -216,6 +224,7 @@ abstract class Detekt @Inject constructor( ClasspathArgument(classpath), LanguageVersionArgument(languageVersionProp.orNull), JvmTargetArgument(jvmTargetProp.orNull), + JdkHomeArgument(jdkHome), ConfigArgument(config), BaselineArgument(baseline.orNull), DefaultReportArgument(DetektReportType.XML, xmlReportFile.orNull), diff --git a/detekt-gradle-plugin/src/main/kotlin/io/gitlab/arturbosch/detekt/DetektCreateBaselineTask.kt b/detekt-gradle-plugin/src/main/kotlin/io/gitlab/arturbosch/detekt/DetektCreateBaselineTask.kt index 37452d8e0e4..add1f5143c1 100644 --- a/detekt-gradle-plugin/src/main/kotlin/io/gitlab/arturbosch/detekt/DetektCreateBaselineTask.kt +++ b/detekt-gradle-plugin/src/main/kotlin/io/gitlab/arturbosch/detekt/DetektCreateBaselineTask.kt @@ -17,6 +17,7 @@ import io.gitlab.arturbosch.detekt.invoke.InputArgument import io.gitlab.arturbosch.detekt.invoke.JvmTargetArgument import io.gitlab.arturbosch.detekt.invoke.ParallelArgument import org.gradle.api.file.ConfigurableFileCollection +import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.FileTree import org.gradle.api.file.RegularFileProperty import org.gradle.api.provider.Property @@ -26,6 +27,7 @@ import org.gradle.api.tasks.Classpath import org.gradle.api.tasks.Console import org.gradle.api.tasks.IgnoreEmptyDirectories import org.gradle.api.tasks.Input +import org.gradle.api.tasks.InputDirectory import org.gradle.api.tasks.InputFiles import org.gradle.api.tasks.Internal import org.gradle.api.tasks.Optional @@ -113,6 +115,11 @@ abstract class DetektCreateBaselineTask : SourceTask() { get() = jvmTargetProp.get() set(value) = jvmTargetProp.set(value) + @get:InputDirectory + @get:PathSensitive(PathSensitivity.ABSOLUTE) + @get:Optional + abstract val jdkHome: DirectoryProperty + @get:Internal internal val arguments: Provider> = project.provider { listOf( diff --git a/detekt-gradle-plugin/src/main/kotlin/io/gitlab/arturbosch/detekt/internal/SharedTasks.kt b/detekt-gradle-plugin/src/main/kotlin/io/gitlab/arturbosch/detekt/internal/SharedTasks.kt index c663e448360..5997a817dc9 100644 --- a/detekt-gradle-plugin/src/main/kotlin/io/gitlab/arturbosch/detekt/internal/SharedTasks.kt +++ b/detekt-gradle-plugin/src/main/kotlin/io/gitlab/arturbosch/detekt/internal/SharedTasks.kt @@ -3,8 +3,12 @@ package io.gitlab.arturbosch.detekt.internal import io.gitlab.arturbosch.detekt.Detekt import io.gitlab.arturbosch.detekt.DetektCreateBaselineTask import io.gitlab.arturbosch.detekt.extensions.DetektExtension +import org.gradle.api.JavaVersion import org.gradle.api.Project +import org.gradle.api.plugins.JavaBasePlugin +import org.gradle.api.plugins.JavaPluginExtension import org.gradle.api.tasks.TaskProvider +import org.gradle.jvm.toolchain.JavaToolchainService internal fun Project.registerDetektTask( name: String, @@ -40,6 +44,20 @@ internal fun Project.registerDetektTask( } } + project.plugins.withType(JavaBasePlugin::class.java) { _ -> + val toolchain = project.extensions.getByType(JavaPluginExtension::class.java).toolchain + + // acquire a provider that returns the launcher for the toolchain + val service = project.extensions.getByType(JavaToolchainService::class.java) + val defaultLauncher = service.launcherFor(toolchain) + it.jdkHome.convention(defaultLauncher.map { launcher -> launcher.metadata.installationPath }) + it.jvmTargetProp.convention( + defaultLauncher.map { launcher -> + JavaVersion.toVersion(launcher.metadata.languageVersion.asInt()).toString() + } + ) + } + it.debugProp.convention(provider { extension.debug }) it.parallelProp.convention(provider { extension.parallel }) it.disableDefaultRuleSetsProp.convention(provider { extension.disableDefaultRuleSets }) @@ -59,6 +77,20 @@ internal fun Project.registerCreateBaselineTask( configuration: DetektCreateBaselineTask.() -> Unit ): TaskProvider = tasks.register(name, DetektCreateBaselineTask::class.java) { + project.plugins.withType(JavaBasePlugin::class.java) { _ -> + val toolchain = project.extensions.getByType(JavaPluginExtension::class.java).toolchain + + // acquire a provider that returns the launcher for the toolchain + val service = project.extensions.getByType(JavaToolchainService::class.java) + val defaultLauncher = service.launcherFor(toolchain) + it.jdkHome.convention(defaultLauncher.map { launcher -> launcher.metadata.installationPath }) + it.jvmTargetProp.convention( + defaultLauncher.map { launcher -> + JavaVersion.toVersion(launcher.metadata.languageVersion.asInt()).toString() + } + ) + } + it.config.setFrom(project.provider { extension.config }) it.debug.convention(project.provider { extension.debug }) it.parallel.convention(project.provider { extension.parallel }) diff --git a/detekt-gradle-plugin/src/main/kotlin/io/gitlab/arturbosch/detekt/invoke/CliArgument.kt b/detekt-gradle-plugin/src/main/kotlin/io/gitlab/arturbosch/detekt/invoke/CliArgument.kt index f44401694ae..01768b6f108 100644 --- a/detekt-gradle-plugin/src/main/kotlin/io/gitlab/arturbosch/detekt/invoke/CliArgument.kt +++ b/detekt-gradle-plugin/src/main/kotlin/io/gitlab/arturbosch/detekt/invoke/CliArgument.kt @@ -1,6 +1,7 @@ package io.gitlab.arturbosch.detekt.invoke import io.gitlab.arturbosch.detekt.extensions.DetektReportType +import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.FileCollection import org.gradle.api.file.RegularFile import java.io.File @@ -21,6 +22,7 @@ private const val CREATE_BASELINE_PARAMETER = "--create-baseline" private const val CLASSPATH_PARAMETER = "--classpath" private const val LANGUAGE_VERSION_PARAMETER = "--language-version" private const val JVM_TARGET_PARAMETER = "--jvm-target" +private const val JDK_HOME_PARAMETER = "--jdk-home" private const val BASE_PATH_PARAMETER = "--base-path" internal sealed class CliArgument { @@ -58,6 +60,10 @@ internal data class JvmTargetArgument(val jvmTarget: String?) : CliArgument() { override fun toArgument() = jvmTarget?.let { listOf(JVM_TARGET_PARAMETER, it) }.orEmpty() } +internal data class JdkHomeArgument(val jdkHome: DirectoryProperty) : CliArgument() { + override fun toArgument() = jdkHome.orNull?.let { listOf(JDK_HOME_PARAMETER, it.toString()) }.orEmpty() +} + internal data class BaselineArgument(val baseline: RegularFile?) : CliArgument() { override fun toArgument() = baseline?.let { listOf(BASELINE_PARAMETER, it.asFile.absolutePath) }.orEmpty() } diff --git a/detekt-gradle-plugin/src/test/kotlin/io/gitlab/arturbosch/detekt/cli/Main.kt b/detekt-gradle-plugin/src/test/kotlin/io/gitlab/arturbosch/detekt/cli/Main.kt index a1929b88fdb..82315f0b619 100644 --- a/detekt-gradle-plugin/src/test/kotlin/io/gitlab/arturbosch/detekt/cli/Main.kt +++ b/detekt-gradle-plugin/src/test/kotlin/io/gitlab/arturbosch/detekt/cli/Main.kt @@ -1,5 +1,5 @@ @file:JvmName("Main") -@file:Suppress("unused", "UNUSED_PARAMETER") +@file:Suppress("unused", "UNUSED_PARAMETER", "Filename") package io.gitlab.arturbosch.detekt.cli diff --git a/detekt-parser/src/main/kotlin/io/github/detekt/parser/KotlinEnvironmentUtils.kt b/detekt-parser/src/main/kotlin/io/github/detekt/parser/KotlinEnvironmentUtils.kt index cbc3d4c94f7..19370df9ae6 100644 --- a/detekt-parser/src/main/kotlin/io/github/detekt/parser/KotlinEnvironmentUtils.kt +++ b/detekt-parser/src/main/kotlin/io/github/detekt/parser/KotlinEnvironmentUtils.kt @@ -67,7 +67,8 @@ fun createCompilerConfiguration( pathsToAnalyze: List, classpath: List, languageVersion: LanguageVersion?, - jvmTarget: JvmTarget + jvmTarget: JvmTarget, + jdkHome: Path?, ): CompilerConfiguration { val javaFiles = pathsToAnalyze.flatMap { path -> path.toFile().walk() @@ -99,6 +100,8 @@ fun createCompilerConfiguration( addJavaSourceRoots(javaFiles) addKotlinSourceRoots(kotlinFiles) addJvmClasspathRoots(classpathFiles) + + jdkHome?.let { put(JVMConfigurationKeys.JDK_HOME, it.toFile()) } configureJdkClasspathRoots() } } diff --git a/detekt-tooling/api/detekt-tooling.api b/detekt-tooling/api/detekt-tooling.api index 4155a325ada..7d89ba6422e 100644 --- a/detekt-tooling/api/detekt-tooling.api +++ b/detekt-tooling/api/detekt-tooling.api @@ -116,6 +116,7 @@ public abstract interface class io/github/detekt/tooling/api/spec/BaselineSpec { public abstract interface class io/github/detekt/tooling/api/spec/CompilerSpec { public abstract fun getClasspath ()Ljava/lang/String; + public abstract fun getJdkHome ()Ljava/nio/file/Path; public abstract fun getJvmTarget ()Ljava/lang/String; public abstract fun getLanguageVersion ()Ljava/lang/String; } @@ -243,9 +244,11 @@ public final class io/github/detekt/tooling/dsl/CompilerSpecBuilder : io/github/ public fun build ()Lio/github/detekt/tooling/api/spec/CompilerSpec; public synthetic fun build ()Ljava/lang/Object; public final fun getClasspath ()Ljava/lang/String; + public final fun getJdkHome ()Ljava/nio/file/Path; public final fun getJvmTarget ()Ljava/lang/String; public final fun getLanguageVersion ()Ljava/lang/String; public final fun setClasspath (Ljava/lang/String;)V + public final fun setJdkHome (Ljava/nio/file/Path;)V public final fun setJvmTarget (Ljava/lang/String;)V public final fun setLanguageVersion (Ljava/lang/String;)V } diff --git a/detekt-tooling/src/main/kotlin/io/github/detekt/tooling/api/spec/CompilerSpec.kt b/detekt-tooling/src/main/kotlin/io/github/detekt/tooling/api/spec/CompilerSpec.kt index e924157ca7b..79c5ad9f343 100644 --- a/detekt-tooling/src/main/kotlin/io/github/detekt/tooling/api/spec/CompilerSpec.kt +++ b/detekt-tooling/src/main/kotlin/io/github/detekt/tooling/api/spec/CompilerSpec.kt @@ -1,5 +1,7 @@ package io.github.detekt.tooling.api.spec +import java.nio.file.Path + /** * All these properties are based down to the Kotlin compiler for type- and symbol resolution. */ @@ -19,4 +21,10 @@ interface CompilerSpec { * Paths to class files and jars separated by a path separator. */ val classpath: String? + + /** + * Path to custom JDK home. Includes the custom JDK from the specified location into the classpath instead of using + * the JRE from the runtime environment. + */ + val jdkHome: Path? } diff --git a/detekt-tooling/src/main/kotlin/io/github/detekt/tooling/dsl/CompilerSpecBuilder.kt b/detekt-tooling/src/main/kotlin/io/github/detekt/tooling/dsl/CompilerSpecBuilder.kt index f2cf162820a..3806b0f5c11 100644 --- a/detekt-tooling/src/main/kotlin/io/github/detekt/tooling/dsl/CompilerSpecBuilder.kt +++ b/detekt-tooling/src/main/kotlin/io/github/detekt/tooling/dsl/CompilerSpecBuilder.kt @@ -1,6 +1,7 @@ package io.github.detekt.tooling.dsl import io.github.detekt.tooling.api.spec.CompilerSpec +import java.nio.file.Path @ProcessingModelDsl class CompilerSpecBuilder : Builder { @@ -8,12 +9,14 @@ class CompilerSpecBuilder : Builder { var jvmTarget: String = "1.8" var languageVersion: String? = null var classpath: String? = null + var jdkHome: Path? = null - override fun build(): CompilerSpec = CompilerModel(jvmTarget, languageVersion, classpath) + override fun build(): CompilerSpec = CompilerModel(jvmTarget, languageVersion, classpath, jdkHome) } private data class CompilerModel( override val jvmTarget: String, override val languageVersion: String?, - override val classpath: String? + override val classpath: String?, + override val jdkHome: Path?, ) : CompilerSpec