From 634c8522a127ec9f2c05912ad7605175ddeb57d6 Mon Sep 17 00:00:00 2001 From: Yaroslav Chernyshev Date: Mon, 1 Mar 2021 11:02:20 +0300 Subject: [PATCH] Fix `jvmTarget` default divergence between KGP & IDE after change to 1.8 --- .../kotlin/compilerRunner/ArgumentUtils.java | 32 +++++++++++-- .../idea/explicitDefaultSubstitutors.kt | 46 +++++++++++++++++++ .../gradle/GradleFacetImportTest.kt | 4 +- .../jetbrains/kotlin/idea/facet/facetUtils.kt | 13 ++++-- 4 files changed, 84 insertions(+), 11 deletions(-) create mode 100644 build-common/src/org/jetbrains/kotlin/idea/explicitDefaultSubstitutors.kt diff --git a/build-common/src/org/jetbrains/kotlin/compilerRunner/ArgumentUtils.java b/build-common/src/org/jetbrains/kotlin/compilerRunner/ArgumentUtils.java index e224b9ba79c..ce3749f8b6a 100644 --- a/build-common/src/org/jetbrains/kotlin/compilerRunner/ArgumentUtils.java +++ b/build-common/src/org/jetbrains/kotlin/compilerRunner/ArgumentUtils.java @@ -29,21 +29,43 @@ import org.jetbrains.kotlin.cli.common.arguments.Argument; import org.jetbrains.kotlin.cli.common.arguments.CommonToolArguments; import org.jetbrains.kotlin.cli.common.arguments.InternalArgument; import org.jetbrains.kotlin.cli.common.arguments.ParseCommandLineArgumentsKt; +import org.jetbrains.kotlin.idea.ExplicitDefaultSubstitutor; +import org.jetbrains.kotlin.idea.ExplicitDefaultSubstitutorsKt; import org.jetbrains.kotlin.utils.StringsKt; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; +import java.util.*; public class ArgumentUtils { - private ArgumentUtils() {} + private ArgumentUtils() { + } @NotNull public static List convertArgumentsToStringList(@NotNull CommonToolArguments arguments) throws InstantiationException, IllegalAccessException, InvocationTargetException { + List convertedArguments = convertArgumentsToStringListInternal(arguments); + + Map, Collection> defaultSubstitutorsMap = + ExplicitDefaultSubstitutorsKt.getDefaultSubstitutors(); + KClass argumentsKClass = JvmClassMappingKt.getKotlinClass(arguments.getClass()); + Collection defaultSubstitutors = defaultSubstitutorsMap.get(argumentsKClass); + if (defaultSubstitutors != null) { + for (ExplicitDefaultSubstitutor substitutor : defaultSubstitutors) { + if (substitutor.isSubstitutable(convertedArguments)) convertedArguments.addAll(substitutor.getNewSubstitution()); + } + } + return convertedArguments; + } + + @NotNull + public static List convertArgumentsToStringListNoDefaults(@NotNull CommonToolArguments arguments) + throws InstantiationException, IllegalAccessException, InvocationTargetException { + return convertArgumentsToStringListInternal(arguments); + } + + private static List convertArgumentsToStringListInternal(@NotNull CommonToolArguments arguments) + throws InstantiationException, IllegalAccessException, InvocationTargetException { List result = new ArrayList<>(); Class argumentsClass = arguments.getClass(); convertArgumentsToStringList(arguments, argumentsClass.newInstance(), JvmClassMappingKt.getKotlinClass(argumentsClass), result); diff --git a/build-common/src/org/jetbrains/kotlin/idea/explicitDefaultSubstitutors.kt b/build-common/src/org/jetbrains/kotlin/idea/explicitDefaultSubstitutors.kt new file mode 100644 index 00000000000..218969ed677 --- /dev/null +++ b/build-common/src/org/jetbrains/kotlin/idea/explicitDefaultSubstitutors.kt @@ -0,0 +1,46 @@ +/* + * Copyright 2010-2021 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. + */ + +package org.jetbrains.kotlin.idea + +import org.jetbrains.kotlin.cli.common.arguments.Argument +import org.jetbrains.kotlin.cli.common.arguments.CommonToolArguments +import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments +import org.jetbrains.kotlin.config.JvmTarget +import kotlin.reflect.KClass +import kotlin.reflect.KProperty1 +import kotlin.reflect.full.findAnnotation + +val defaultSubstitutors: Map, Collection> = + mapOf(K2JVMCompilerArguments::class to listOf(JvmTargetDefaultSubstitutor)) + +sealed class ExplicitDefaultSubstitutor { + abstract val substitutedProperty: KProperty1 + abstract val oldSubstitution: List + abstract val newSubstitution: List + abstract fun isSubstitutable(args: List): Boolean + + protected val argument: Argument by lazy { + substitutedProperty.findAnnotation() ?: error("Property \"${substitutedProperty.name}\" has no Argument annotation") + } +} + +object JvmTargetDefaultSubstitutor : ExplicitDefaultSubstitutor() { + override val substitutedProperty + get() = K2JVMCompilerArguments::jvmTarget + private val oldDefault: String + get() = JvmTarget.JVM_1_6.description + private val newDefault: String + get() = JvmTarget.JVM_1_8.description + + private fun prepareSubstitution(default: String): List = listOf(argument.value, default) + + override val oldSubstitution: List + get() = prepareSubstitution(oldDefault) + override val newSubstitution: List + get() = prepareSubstitution(newDefault) + + override fun isSubstitutable(args: List): Boolean = argument.value !in args +} diff --git a/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleFacetImportTest.kt b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleFacetImportTest.kt index a043149a357..7e318a4ba72 100644 --- a/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleFacetImportTest.kt +++ b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleFacetImportTest.kt @@ -104,7 +104,7 @@ class GradleFacetImportTest : GradleImportingTestCase() { Assert.assertFalse(compilerArguments!!.autoAdvanceLanguageVersion) Assert.assertFalse(compilerArguments!!.autoAdvanceApiVersion) Assert.assertEquals(JvmPlatforms.jvm16, targetPlatform) - Assert.assertEquals("1.8", (compilerArguments as K2JVMCompilerArguments).jvmTarget) + Assert.assertEquals("1.6", (compilerArguments as K2JVMCompilerArguments).jvmTarget) Assert.assertEquals( "-Xallow-no-source-files -Xdump-declarations-to=tmpTest", compilerSettings!!.additionalArguments @@ -158,7 +158,7 @@ class GradleFacetImportTest : GradleImportingTestCase() { Assert.assertEquals("1.3", languageLevel!!.versionString) Assert.assertEquals("1.0", apiLevel!!.versionString) Assert.assertEquals(JvmPlatforms.jvm16, targetPlatform) - Assert.assertEquals("1.8", (compilerArguments as K2JVMCompilerArguments).jvmTarget) + Assert.assertEquals("1.6", (compilerArguments as K2JVMCompilerArguments).jvmTarget) Assert.assertEquals( "-Xallow-no-source-files -Xdump-declarations-to=tmpTest", compilerSettings!!.additionalArguments diff --git a/idea/src/org/jetbrains/kotlin/idea/facet/facetUtils.kt b/idea/src/org/jetbrains/kotlin/idea/facet/facetUtils.kt index 488e613b09b..2e0fb63b6e9 100644 --- a/idea/src/org/jetbrains/kotlin/idea/facet/facetUtils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/facet/facetUtils.kt @@ -27,10 +27,10 @@ import org.jetbrains.kotlin.idea.configuration.externalCompilerVersion import org.jetbrains.kotlin.idea.core.isAndroidModule import org.jetbrains.kotlin.idea.framework.KotlinSdkType import org.jetbrains.kotlin.idea.platform.tooling +import org.jetbrains.kotlin.idea.defaultSubstitutors import org.jetbrains.kotlin.idea.util.application.runWriteAction import org.jetbrains.kotlin.idea.util.getProjectJdkTableSafe import org.jetbrains.kotlin.platform.* -import org.jetbrains.kotlin.platform.compat.toNewPlatform import org.jetbrains.kotlin.platform.impl.JvmIdePlatformKind import org.jetbrains.kotlin.platform.jvm.JvmPlatforms import org.jetbrains.kotlin.psi.NotNullableUserDataProperty @@ -298,6 +298,9 @@ private fun Module.configureSdkIfPossible(compilerArguments: CommonCompilerArgum private fun Module.hasNonOverriddenExternalSdkConfiguration(compilerArguments: CommonCompilerArguments): Boolean = hasExternalSdkConfiguration && (compilerArguments !is K2JVMCompilerArguments || compilerArguments.jdkHome == null) +private fun substituteDefaults(args: List, compilerArguments: CommonCompilerArguments): List = + args + defaultSubstitutors[compilerArguments::class]?.filter { it.isSubstitutable(args) }?.flatMap { it.oldSubstitution }.orEmpty() + fun parseCompilerArgumentsToFacet( arguments: List, defaultArguments: List, @@ -307,8 +310,10 @@ fun parseCompilerArgumentsToFacet( val compilerArgumentsClass = kotlinFacet.configuration.settings.compilerArguments?.javaClass ?: return val currentArgumentsBean = compilerArgumentsClass.newInstance() val defaultArgumentsBean = compilerArgumentsClass.newInstance() - parseCommandLineArguments(defaultArguments, defaultArgumentsBean) - parseCommandLineArguments(arguments, currentArgumentsBean) + val defaultArgumentWithDefaults = substituteDefaults(defaultArguments, defaultArgumentsBean) + val currentArgumentWithDefaults = substituteDefaults(arguments, currentArgumentsBean) + parseCommandLineArguments(defaultArgumentWithDefaults, defaultArgumentsBean) + parseCommandLineArguments(currentArgumentWithDefaults, currentArgumentsBean) applyCompilerArgumentsToFacet(currentArgumentsBean, defaultArgumentsBean, kotlinFacet, modelsProvider) } @@ -352,7 +357,7 @@ fun applyCompilerArgumentsToFacet( val additionalArgumentsString = with(compilerArguments::class.java.newInstance()) { copyFieldsSatisfying(compilerArguments, this) { exposeAsAdditionalArgument(it) && it.name !in ignoredFields } - ArgumentUtils.convertArgumentsToStringList(this).joinToString(separator = " ") { + ArgumentUtils.convertArgumentsToStringListNoDefaults(this).joinToString(separator = " ") { if (StringUtil.containsWhitespaces(it) || it.startsWith('"')) { StringUtil.wrapWithDoubleQuote(StringUtil.escapeQuotes(it)) } else it