From 0f5f4fd8fa8449d040c637504235817471a3bc0b Mon Sep 17 00:00:00 2001 From: Sebastian Sellmair Date: Thu, 13 Apr 2023 10:58:21 +0200 Subject: [PATCH] [Gradle] Overwrite setupCompilerArgs methods in compile tasks... ... to ensure compatibility with reflection code in IDEs < 2023.2 which is looking for setupCompilerArgs methods with specific compiler arguments type instead of a generic function KTIJ-25227 --- .../targets/native/tasks/KotlinNativeTasks.kt | 7 ++ .../kotlin/gradle/tasks/Kotlin2JsCompile.kt | 9 +- .../kotlin/gradle/tasks/KotlinCompile.kt | 9 +- .../gradle/tasks/KotlinCompileCommon.kt | 7 ++ .../kotlin/gradle/tasks/KotlinJsDce.kt | 11 ++- ...27CompilerArgumentsIdeCompatibilityTest.kt | 88 +++++++++++++++++++ 6 files changed, 126 insertions(+), 5 deletions(-) create mode 100644 libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/regressionTests/KTIJ25227CompilerArgumentsIdeCompatibilityTest.kt diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt index 2bb481023d4..35dfb456260 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt @@ -419,6 +419,13 @@ internal constructor( private val isAllowCommonizer: Boolean by lazy { project.isAllowCommonizer() } // endregion. + @Suppress("DeprecatedCallableAddReplaceWith") + @Deprecated("KTIJ-25227: Necessary override for IDEs < 2023.2", level = DeprecationLevel.ERROR) + override fun setupCompilerArgs(args: K2NativeCompilerArguments, defaultsOnly: Boolean, ignoreClasspathResolutionErrors: Boolean) { + @Suppress("DEPRECATION_ERROR") + super.setupCompilerArgs(args, defaultsOnly, ignoreClasspathResolutionErrors) + } + override fun createCompilerArguments(context: CreateCompilerArgumentsContext) = context.create { val sharedCompilationData = createSharedCompilationDataOrNull() diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/Kotlin2JsCompile.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/Kotlin2JsCompile.kt index f98ef4308d7..814d06f87e9 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/Kotlin2JsCompile.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/Kotlin2JsCompile.kt @@ -126,6 +126,13 @@ abstract class Kotlin2JsCompile @Inject constructor( @get:Nested override val multiplatformStructure: K2MultiplatformStructure = objectFactory.newInstance() + @Suppress("DeprecatedCallableAddReplaceWith") + @Deprecated("KTIJ-25227: Necessary override for IDEs < 2023.2", level = DeprecationLevel.ERROR) + override fun setupCompilerArgs(args: K2JSCompilerArguments, defaultsOnly: Boolean, ignoreClasspathResolutionErrors: Boolean) { + @Suppress("DEPRECATION_ERROR") + super.setupCompilerArgs(args, defaultsOnly, ignoreClasspathResolutionErrors) + } + override fun createCompilerArguments(context: CreateCompilerArgumentsContext) = context.create { primitive { args -> args.multiPlatform = multiPlatformEnabled.get() @@ -359,4 +366,4 @@ abstract class Kotlin2JsCompile @Inject constructor( ) } } -} \ No newline at end of file +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinCompile.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinCompile.kt index 321ff664fe2..43695cf73f8 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinCompile.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinCompile.kt @@ -223,6 +223,13 @@ abstract class KotlinCompile @Inject constructor( @get:Internal internal var executionTimeFreeCompilerArgs: List? = null + @Suppress("DeprecatedCallableAddReplaceWith") + @Deprecated("KTIJ-25227: Necessary override for IDEs < 2023.2", level = DeprecationLevel.ERROR) + override fun setupCompilerArgs(args: K2JVMCompilerArguments, defaultsOnly: Boolean, ignoreClasspathResolutionErrors: Boolean) { + @Suppress("DEPRECATION_ERROR") + super.setupCompilerArgs(args, defaultsOnly, ignoreClasspathResolutionErrors) + } + override fun createCompilerArguments( context: KotlinCompilerArgumentsProducer.CreateCompilerArgumentsContext ): K2JVMCompilerArguments = context.create { @@ -500,4 +507,4 @@ abstract class KotlinCompile @Inject constructor( } } } -} \ No newline at end of file +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinCompileCommon.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinCompileCommon.kt index 563d6c2d12c..2638bd0e03d 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinCompileCommon.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinCompileCommon.kt @@ -66,6 +66,13 @@ abstract class KotlinCompileCommon @Inject constructor( @get:Internal internal var executionTimeFreeCompilerArgs: List? = null + @Suppress("DeprecatedCallableAddReplaceWith") + @Deprecated("KTIJ-25227: Necessary override for IDEs < 2023.2", level = DeprecationLevel.ERROR) + override fun setupCompilerArgs(args: K2MetadataCompilerArguments, defaultsOnly: Boolean, ignoreClasspathResolutionErrors: Boolean) { + @Suppress("DEPRECATION_ERROR") + super.setupCompilerArgs(args, defaultsOnly, ignoreClasspathResolutionErrors) + } + override fun createCompilerArguments(context: CreateCompilerArgumentsContext) = context.create { primitive { args -> args.multiPlatform = multiPlatformEnabled.get() diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinJsDce.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinJsDce.kt index be29b0543d4..93ed28ec392 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinJsDce.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinJsDce.kt @@ -31,9 +31,7 @@ import org.jetbrains.kotlin.compilerRunner.ArgumentUtils import org.jetbrains.kotlin.compilerRunner.runToolInSeparateProcess import org.jetbrains.kotlin.gradle.dsl.* import org.jetbrains.kotlin.gradle.dsl.KotlinJsDce -import org.jetbrains.kotlin.gradle.dsl.KotlinJsDceCompilerToolOptionsDefault import org.jetbrains.kotlin.gradle.logging.GradleKotlinLogger -import org.jetbrains.kotlin.gradle.plugin.KotlinCompilerArgumentsProducer import org.jetbrains.kotlin.gradle.plugin.KotlinCompilerArgumentsProducer.CreateCompilerArgumentsContext import org.jetbrains.kotlin.gradle.plugin.KotlinCompilerArgumentsProducer.CreateCompilerArgumentsContext.Companion.create import org.jetbrains.kotlin.gradle.utils.absolutePathWithoutExtension @@ -158,4 +156,11 @@ abstract class KotlinJsDce @Inject constructor( const val strategyAllArg = "-Xdev-mode-overwriting-strategy=${DevModeOverwritingStrategies.ALL}" const val strategyOlderArg = "-Xdev-mode-overwriting-strategy=${DevModeOverwritingStrategies.OLDER}" } -} \ No newline at end of file + + @Suppress("DeprecatedCallableAddReplaceWith") + @Deprecated("KTIJ-25227: Necessary override for IDEs < 2023.2", level = DeprecationLevel.ERROR) + override fun setupCompilerArgs(args: K2JSDceArguments, defaultsOnly: Boolean, ignoreClasspathResolutionErrors: Boolean) { + @Suppress("DEPRECATION_ERROR") + super.setupCompilerArgs(args, defaultsOnly, ignoreClasspathResolutionErrors) + } +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/regressionTests/KTIJ25227CompilerArgumentsIdeCompatibilityTest.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/regressionTests/KTIJ25227CompilerArgumentsIdeCompatibilityTest.kt new file mode 100644 index 00000000000..1dcb1067131 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/regressionTests/KTIJ25227CompilerArgumentsIdeCompatibilityTest.kt @@ -0,0 +1,88 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +@file:Suppress("FunctionName") + +package org.jetbrains.kotlin.gradle.regressionTests + +import org.gradle.api.Task +import org.jetbrains.kotlin.gradle.dsl.kotlinJvmExtension +import org.jetbrains.kotlin.gradle.regressionTests.KTIJ25227CompilerArgumentsIdeCompatibilityTest.IdePluginCodeMock.IdeReflectionCodeMock.get +import org.jetbrains.kotlin.gradle.regressionTests.KTIJ25227CompilerArgumentsIdeCompatibilityTest.IdePluginCodeMock.IdeReflectionCodeMock.getMethodOrNull +import org.jetbrains.kotlin.gradle.regressionTests.KTIJ25227CompilerArgumentsIdeCompatibilityTest.IdePluginCodeMock.checkExtractCompilerArgumentsFromTask +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile +import org.jetbrains.kotlin.gradle.util.buildProjectWithJvm +import org.jetbrains.kotlin.gradle.util.main +import org.junit.Test +import java.lang.reflect.Method +import kotlin.test.fail + +class KTIJ25227CompilerArgumentsIdeCompatibilityTest { + + @Test + fun `test - jvm compile task - is compatible with old CompilerArgumentsExtractor in older IDEs`() { + val project = buildProjectWithJvm() + project.evaluate() + + val kotlin = project.kotlinJvmExtension + val mainCompilation = kotlin.target.compilations.main + val mainCompileTask = mainCompilation.compileTaskProvider.get() as KotlinCompile + checkExtractCompilerArgumentsFromTask(mainCompileTask) + } + + + /* + Code from CompilerArgumentsExtractor inside intellij.git with injected asssertions + */ + private object IdePluginCodeMock { + const val CREATE_COMPILER_ARGS = "createCompilerArgs" + const val SETUP_COMPILER_ARGS = "setupCompilerArgs" + + fun checkExtractCompilerArgumentsFromTask(compileTask: Task, defaultsOnly: Boolean = false): Any { + val compileTaskClass = compileTask.javaClass + val compilerArguments = compileTask[CREATE_COMPILER_ARGS] ?: fail("Missing $CREATE_COMPILER_ARGS method") + compileTaskClass.getMethodOrNull(SETUP_COMPILER_ARGS, compilerArguments::class.java, Boolean::class.java, Boolean::class.java) + ?.doSetupCompilerArgs(compileTask, compilerArguments, defaultsOnly, false) ?: compileTaskClass + .getMethodOrNull(SETUP_COMPILER_ARGS, compilerArguments::class.java, Boolean::class.java) + ?.doSetupCompilerArgs(compileTask, compilerArguments, defaultsOnly) + ?: fail("Missing $SETUP_COMPILER_ARGS method") + return compilerArguments + } + + private fun Method.doSetupCompilerArgs( + compileTask: Task, + compilerArgs: Any, + defaultsOnly: Boolean, + ignoreClasspathIssues: Boolean? = null + ) { + try { + ignoreClasspathIssues?.also { invoke(compileTask, compilerArgs, defaultsOnly, it) } + ?: invoke(compileTask, compilerArgs, defaultsOnly) + } catch (e: Exception) { + ignoreClasspathIssues?.also { if (!it) doSetupCompilerArgs(compileTask, compilerArgs, defaultsOnly, true) } + } + } + + private object IdeReflectionCodeMock { + operator fun Any?.get(methodName: String, vararg params: Any): Any? { + return this[methodName, params.map { it.javaClass }, params.toList()] + } + + operator fun Any?.get(methodName: String, paramTypes: List>, params: List): Any? { + if (this == null) return null + return this::class.java.getMethodOrNull(methodName, *paramTypes.toTypedArray()) + ?.invoke(this, *params.toTypedArray()) + } + + fun Class<*>.getMethodOrNull(name: String, vararg parameterTypes: Class<*>) = + try { + getMethod(name, *parameterTypes) + } catch (e: Exception) { + null + } + } + } +} +