From 2984a5a19f2da52d52f3811f041194a5f800af2e Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Thu, 27 Jul 2017 15:20:57 +0300 Subject: [PATCH] Fix reflection-based operations on compiler arguments after conversion --- .../kotlin/compilerRunner/ArgumentUtils.java | 49 +++++++------- .../cli/common/arguments/argumentUtils.kt | 65 +++++++++++-------- .../arguments/parseCommandLineArguments.kt | 41 +++++++----- .../jetbrains/kotlin/cli/common/Usage.java | 10 +-- .../arguments/GenerateGradleOptions.kt | 4 +- .../BaseKotlinCompilerSettings.kt | 6 +- .../kotlin/config/facetSerialization.kt | 61 ++++++++++++++--- idea/idea.iml | 1 + .../idea/facet/KotlinFacetEditorGeneralTab.kt | 15 +++-- .../jetbrains/kotlin/idea/facet/facetUtils.kt | 5 +- 10 files changed, 162 insertions(+), 95 deletions(-) diff --git a/build-common/src/org/jetbrains/kotlin/compilerRunner/ArgumentUtils.java b/build-common/src/org/jetbrains/kotlin/compilerRunner/ArgumentUtils.java index 7e1cb66b7a9..0c4d6bc86ba 100644 --- a/build-common/src/org/jetbrains/kotlin/compilerRunner/ArgumentUtils.java +++ b/build-common/src/org/jetbrains/kotlin/compilerRunner/ArgumentUtils.java @@ -16,13 +16,21 @@ package org.jetbrains.kotlin.compilerRunner; +import com.intellij.util.containers.ContainerUtil; +import kotlin.jvm.JvmClassMappingKt; +import kotlin.reflect.KClass; +import kotlin.reflect.KProperty1; +import kotlin.reflect.KVisibility; +import kotlin.reflect.full.KClasses; +import kotlin.reflect.jvm.ReflectJvmMapping; import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.cli.common.arguments.Argument; import org.jetbrains.kotlin.cli.common.arguments.CommonToolArguments; import org.jetbrains.kotlin.cli.common.arguments.ParseCommandLineArgumentsKt; import org.jetbrains.kotlin.utils.StringsKt; -import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -33,39 +41,35 @@ public class ArgumentUtils { @NotNull public static List convertArgumentsToStringList(@NotNull CommonToolArguments arguments) - throws InstantiationException, IllegalAccessException { + throws InstantiationException, IllegalAccessException, InvocationTargetException { List result = new ArrayList<>(); - convertArgumentsToStringList(arguments, arguments.getClass().newInstance(), arguments.getClass(), result); + Class argumentsClass = arguments.getClass(); + convertArgumentsToStringList(arguments, argumentsClass.newInstance(), JvmClassMappingKt.getKotlinClass(argumentsClass), result); result.addAll(arguments.getFreeArgs()); return result; } + @SuppressWarnings("unchecked") private static void convertArgumentsToStringList( @NotNull CommonToolArguments arguments, @NotNull CommonToolArguments defaultArguments, - @NotNull Class clazz, + @NotNull KClass clazz, @NotNull List result - ) throws IllegalAccessException, InstantiationException { - for (Field field : clazz.getDeclaredFields()) { - Argument argument = field.getAnnotation(Argument.class); + ) throws IllegalAccessException, InstantiationException, InvocationTargetException { + for (KProperty1 property : KClasses.getMemberProperties(clazz)) { + Argument argument = ContainerUtil.findInstance(property.getAnnotations(), Argument.class); if (argument == null) continue; - Object value; - Object defaultValue; - try { - value = field.get(arguments); - defaultValue = field.get(defaultArguments); - } - catch (IllegalAccessException ignored) { - // skip this field - continue; - } + if (property.getVisibility() != KVisibility.PUBLIC) continue; + + Object value = property.get(arguments); + Object defaultValue = property.get(defaultArguments); if (value == null || Objects.equals(value, defaultValue)) continue; - Class fieldType = field.getType(); + Type propertyJavaType = ReflectJvmMapping.getJavaType(property.getReturnType()); - if (fieldType.isArray()) { + if (propertyJavaType instanceof Class && ((Class) propertyJavaType).isArray()) { Object[] values = (Object[]) value; if (values.length == 0) continue; value = StringsKt.join(Arrays.asList(values), ","); @@ -73,7 +77,7 @@ public class ArgumentUtils { result.add(argument.value()); - if (fieldType == boolean.class || fieldType == Boolean.class) continue; + if (propertyJavaType == boolean.class || propertyJavaType == Boolean.class) continue; if (ParseCommandLineArgumentsKt.isAdvanced(argument)) { result.set(result.size() - 1, argument.value() + "=" + value.toString()); @@ -82,10 +86,5 @@ public class ArgumentUtils { result.add(value.toString()); } } - - Class superClazz = clazz.getSuperclass(); - if (superClazz != null) { - convertArgumentsToStringList(arguments, defaultArguments, superClazz, result); - } } } diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/argumentUtils.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/argumentUtils.kt index f903bbc41a9..6b239043c73 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/argumentUtils.kt +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/argumentUtils.kt @@ -16,29 +16,47 @@ package org.jetbrains.kotlin.cli.common.arguments -import java.lang.reflect.Field -import java.lang.reflect.Modifier import java.util.* +import kotlin.reflect.KClass +import kotlin.reflect.KMutableProperty1 +import kotlin.reflect.KProperty1 +import kotlin.reflect.KVisibility +import kotlin.reflect.full.declaredMemberProperties +import kotlin.reflect.full.findAnnotation +import kotlin.reflect.full.memberProperties -fun copyBean(bean: T) = copyFields(bean, bean::class.java.newInstance(), true, collectFieldsToCopy(bean::class.java, false)) +@Suppress("UNCHECKED_CAST") +fun copyBean(bean: T) = + copyProperties(bean, bean::class.java.newInstance()!!, true, collectProperties(bean::class as KClass, false)) fun mergeBeans(from: From, to: To): To { // TODO: rewrite when updated version of com.intellij.util.xmlb is available on TeamCity - return copyFields(from, to, false, collectFieldsToCopy(from::class.java, false)) + @Suppress("UNCHECKED_CAST") + return copyProperties(from, to, false, collectProperties(from::class as KClass, false)) } -fun copyInheritedFields(from: From, to: To) = copyFields(from, to, true, collectFieldsToCopy(from::class.java, true)) +@Suppress("UNCHECKED_CAST") +fun copyInheritedFields(from: From, to: To) = + copyProperties(from, to, true, collectProperties(from::class as KClass, true)) -fun copyFieldsSatisfying(from: From, to: To, predicate: (Field) -> Boolean) = - copyFields(from, to, true, collectFieldsToCopy(from::class.java, false).filter(predicate)) +@Suppress("UNCHECKED_CAST") +fun copyFieldsSatisfying(from: From, to: To, predicate: (KProperty1) -> Boolean) = + copyProperties(from, to, true, collectProperties(from::class as KClass, false).filter(predicate)) -private fun copyFields(from: From, to: To, deepCopyWhenNeeded: Boolean, fieldsToCopy: List): To { +private fun copyProperties( + from: From, + to: To, + deepCopyWhenNeeded: Boolean, + propertiesToCopy: List> +): To { if (from == to) return to - for (fromField in fieldsToCopy) { - val toField = to::class.java.getField(fromField.name) - val fromValue = fromField.get(from) - toField.set(to, if (deepCopyWhenNeeded) fromValue?.copyValueIfNeeded() else fromValue) + for (fromProperty in propertiesToCopy) { + @Suppress("UNCHECKED_CAST") + val toProperty = to::class.memberProperties.firstOrNull { it.name == fromProperty.name } as? KMutableProperty1 + ?: continue + val fromValue = fromProperty.get(from) + toProperty.set(to, if (deepCopyWhenNeeded) fromValue?.copyValueIfNeeded() else fromValue) } return to } @@ -72,19 +90,12 @@ private fun Any.copyValueIfNeeded(): Any { } } -fun collectFieldsToCopy(clazz: Class<*>, inheritedOnly: Boolean): List { - val fromFields = ArrayList() - - var currentClass: Class<*>? = if (inheritedOnly) clazz.superclass else clazz - while (currentClass != null) { - for (field in currentClass.declaredFields) { - val modifiers = field.modifiers - if (!Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers) && !Modifier.isTransient(modifiers)) { - fromFields.add(field) - } - } - currentClass = currentClass.superclass +fun collectProperties(kClass: KClass, inheritedOnly: Boolean): List> { + val properties = ArrayList(kClass.memberProperties) + if (inheritedOnly) { + properties.removeAll(kClass.declaredMemberProperties) } - - return fromFields -} + return properties.filter { + it.visibility == KVisibility.PUBLIC && it.findAnnotation() == null + } +} \ No newline at end of file diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/parseCommandLineArguments.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/parseCommandLineArguments.kt index b7a65526bce..0525f3bfca5 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/parseCommandLineArguments.kt +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/parseCommandLineArguments.kt @@ -17,7 +17,9 @@ package org.jetbrains.kotlin.cli.common.arguments import com.intellij.util.SmartList -import java.lang.reflect.Field +import kotlin.reflect.KMutableProperty1 +import kotlin.reflect.full.findAnnotation +import kotlin.reflect.full.memberProperties annotation class Argument( val value: String, @@ -54,11 +56,13 @@ data class ArgumentParseErrors( // Parses arguments into the passed [result] object. Errors related to the parsing will be collected into [CommonToolArguments.errors]. fun parseCommandLineArguments(args: List, result: A) { - data class ArgumentField(val field: Field, val argument: Argument) + data class ArgumentField(val property: KMutableProperty1, val argument: Argument) - val fields = result::class.java.fields.mapNotNull { field -> - val argument = field.getAnnotation(Argument::class.java) - if (argument != null) ArgumentField(field, argument) else null + @Suppress("UNCHECKED_CAST") + val properties = result::class.memberProperties.mapNotNull { property -> + if (property !is KMutableProperty1<*, *>) return@mapNotNull null + val argument = property.findAnnotation() ?: return@mapNotNull null + ArgumentField(property as KMutableProperty1, argument) } val errors = result.errors @@ -72,7 +76,7 @@ fun parseCommandLineArguments(args: List, resu } if (argument.value == arg) { - if (argument.isAdvanced && field.type != Boolean::class.java) { + if (argument.isAdvanced && property.returnType.classifier != Boolean::class) { errors.extraArgumentsPassedInObsoleteForm.add(arg) } return true @@ -95,7 +99,7 @@ fun parseCommandLineArguments(args: List, resu continue } - val argumentField = fields.firstOrNull { it.matches(arg) } + val argumentField = properties.firstOrNull { it.matches(arg) } if (argumentField == null) { when { arg.startsWith(ADVANCED_ARGUMENT_PREFIX) -> errors.unknownExtraFlags.add(arg) @@ -105,9 +109,9 @@ fun parseCommandLineArguments(args: List, resu continue } - val (field, argument) = argumentField + val (property, argument) = argumentField val value: Any = when { - field.type == Boolean::class.java -> true + argumentField.property.returnType.classifier == Boolean::class -> true argument.isAdvanced && arg.startsWith(argument.value + "=") -> { arg.substring(argument.value.length + 1) } @@ -120,24 +124,25 @@ fun parseCommandLineArguments(args: List, resu } } - if (!field.type.isArray && !visitedArgs.add(argument.value) && value is String && field.get(result) != value) { + if (argumentField.property.returnType.classifier?.javaClass?.isArray == false + && !visitedArgs.add(argument.value) && value is String && property.get(result) != value) { errors.duplicateArguments.put(argument.value, value) } - updateField(field, result, value, argument.delimiter) + updateField(property, result, value, argument.delimiter) } } -private fun updateField(field: Field, result: A, value: Any, delimiter: String) { - when (field.type) { - Boolean::class.java, String::class.java -> field.set(result, value) - Array::class.java -> { +private fun updateField(property: KMutableProperty1, result: A, value: Any, delimiter: String) { + when (property.returnType.classifier) { + Boolean::class, String::class -> property.set(result, value) + Array::class -> { val newElements = (value as String).split(delimiter).toTypedArray() @Suppress("UNCHECKED_CAST") - val oldValue = field.get(result) as Array? - field.set(result, if (oldValue != null) arrayOf(*oldValue, *newElements) else newElements) + val oldValue = property.get(result) as Array? + property.set(result, if (oldValue != null) arrayOf(*oldValue, *newElements) else newElements) } - else -> throw IllegalStateException("Unsupported argument type: ${field.type}") + else -> throw IllegalStateException("Unsupported argument type: ${property.returnType}") } } diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/common/Usage.java b/compiler/cli/src/org/jetbrains/kotlin/cli/common/Usage.java index 95f98d300e5..7864f296a57 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/common/Usage.java +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/common/Usage.java @@ -22,7 +22,7 @@ import org.jetbrains.kotlin.cli.common.arguments.Argument; import org.jetbrains.kotlin.cli.common.arguments.CommonToolArguments; import org.jetbrains.kotlin.cli.common.arguments.ParseCommandLineArgumentsKt; -import java.lang.reflect.Field; +import java.lang.reflect.Method; public class Usage { // The magic number 29 corresponds to the similar padding width in javac and scalac command line compilers @@ -34,8 +34,8 @@ public class Usage { appendln(sb, "Usage: " + tool.executableScriptFileName() + " "); appendln(sb, "where " + (arguments.getExtraHelp() ? "advanced" : "possible") + " options include:"); for (Class clazz = arguments.getClass(); clazz != null; clazz = clazz.getSuperclass()) { - for (Field field : clazz.getDeclaredFields()) { - fieldUsage(sb, field, arguments.getExtraHelp()); + for (Method method : clazz.getDeclaredMethods()) { + propertyUsage(sb, method, arguments.getExtraHelp()); } } @@ -47,8 +47,8 @@ public class Usage { return sb.toString(); } - private static void fieldUsage(@NotNull StringBuilder sb, @NotNull Field field, boolean extraHelp) { - Argument argument = field.getAnnotation(Argument.class); + private static void propertyUsage(@NotNull StringBuilder sb, @NotNull Method method, boolean extraHelp) { + Argument argument = method.getAnnotation(Argument.class); if (argument == null) return; if (extraHelp != ParseCommandLineArgumentsKt.isAdvanced(argument)) return; diff --git a/generators/src/org/jetbrains/kotlin/generators/arguments/GenerateGradleOptions.kt b/generators/src/org/jetbrains/kotlin/generators/arguments/GenerateGradleOptions.kt index 4c482cdf1d2..b6e83100149 100644 --- a/generators/src/org/jetbrains/kotlin/generators/arguments/GenerateGradleOptions.kt +++ b/generators/src/org/jetbrains/kotlin/generators/arguments/GenerateGradleOptions.kt @@ -24,6 +24,7 @@ import java.io.PrintStream import kotlin.reflect.KAnnotatedElement import kotlin.reflect.KProperty1 import kotlin.reflect.full.declaredMemberProperties +import kotlin.reflect.full.withNullability // Additional properties that should be included in interface @Suppress("unused") @@ -271,7 +272,8 @@ private val KProperty1<*, *>.gradleDefaultValue: String private val KProperty1<*, *>.gradleReturnType: String get() { - var type = returnType.toString().substringBeforeLast("!") + // Set nullability based on Gradle default value + var type = returnType.withNullability(false).toString().substringBeforeLast("!") if (gradleDefaultValue == "null") { type += "?" } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/compiler/configuration/BaseKotlinCompilerSettings.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/compiler/configuration/BaseKotlinCompilerSettings.kt index 1116546d5de..3b7cf2e7bc6 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/compiler/configuration/BaseKotlinCompilerSettings.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/compiler/configuration/BaseKotlinCompilerSettings.kt @@ -23,6 +23,7 @@ import com.intellij.util.xmlb.XmlSerializer import org.jdom.Element import org.jetbrains.kotlin.cli.common.arguments.* import org.jetbrains.kotlin.config.SettingConstants +import kotlin.reflect.KClass abstract class BaseKotlinCompilerSettings protected constructor() : PersistentStateComponent, Cloneable { @Suppress("LeakingThis") @@ -40,9 +41,10 @@ abstract class BaseKotlinCompilerSettings protected constructor() : Per } protected fun validateInheritedFieldsUnchanged(settings: T) { - val inheritedFields = collectFieldsToCopy(settings.javaClass, true) + @Suppress("UNCHECKED_CAST") + val inheritedProperties = collectProperties(settings::class as KClass, true) val defaultInstance = createSettings() - val invalidFields = inheritedFields.filter { it.get(settings) != it.get(defaultInstance) } + val invalidFields = inheritedProperties.filter { it.get(settings) != it.get(defaultInstance) } if (invalidFields.isNotEmpty()) { throw IllegalArgumentException("Following fields are expected to be left unchanged in ${settings.javaClass}: ${invalidFields.joinToString { it.name }}") } diff --git a/idea/idea-jps-common/src/org/jetbrains/kotlin/config/facetSerialization.kt b/idea/idea-jps-common/src/org/jetbrains/kotlin/config/facetSerialization.kt index fc597ec0ea6..b542815b054 100644 --- a/idea/idea-jps-common/src/org/jetbrains/kotlin/config/facetSerialization.kt +++ b/idea/idea-jps-common/src/org/jetbrains/kotlin/config/facetSerialization.kt @@ -17,11 +17,18 @@ package org.jetbrains.kotlin.config import com.intellij.util.PathUtil +import com.intellij.util.xmlb.SerializationFilter import com.intellij.util.xmlb.SkipDefaultsSerializationFilter import com.intellij.util.xmlb.XmlSerializer import org.jdom.DataConversionException import org.jdom.Element import org.jetbrains.kotlin.cli.common.arguments.* +import org.jetbrains.kotlin.load.java.JvmAbi +import org.jetbrains.kotlin.load.java.propertyNameByGetMethodName +import org.jetbrains.kotlin.name.Name +import java.lang.reflect.Modifier +import kotlin.reflect.KClass +import kotlin.reflect.full.superclasses fun Element.getOption(name: String) = getChildren("option").firstOrNull { it.getAttribute("name").value == name } @@ -166,6 +173,50 @@ fun CompilerSettings.convertPathsToSystemIndependent() { outputDirectoryForJsLibraryFiles = PathUtil.toSystemIndependentName(outputDirectoryForJsLibraryFiles) } +private fun KClass<*>.superClass() = superclasses.firstOrNull { !it.java.isInterface } + +private fun Class<*>.computeNormalPropertyOrdering(): Map { + val result = LinkedHashMap() + var count = 0 + generateSequence(this) { it.superclass }.forEach { clazz -> + for (method in clazz.declaredMethods) { + if (method.modifiers and Modifier.STATIC != 0) continue + + val name = method.name + if (!JvmAbi.isGetterName(name)) continue + + val propertyName = propertyNameByGetMethodName(Name.identifier(name))?.asString() ?: continue + + result[propertyName] = count++ + } + } + return result +} + +private val allNormalOrderings = HashMap, Map>() + +private val Class<*>.normalOrdering + get() = allNormalOrderings.getOrPut(this) { computeNormalPropertyOrdering() } + +// Replacing fields with delegated properties leads to unexpected reordering of entries in facet configuration XML +// It happens due to XmlSerializer using different orderings for field- and method-based accessors +// This code restores the original ordering +private fun Element.restoreNormalOrdering(bean: Any) { + val normalOrdering = bean.javaClass.normalOrdering + val elementsToReorder = this.getContent { it is Element && it.getAttribute("name")?.value in normalOrdering } + elementsToReorder + .sortedBy { normalOrdering[it.getAttribute("name")?.value!!] } + .forEachIndexed { index, element -> elementsToReorder[index] = element.clone() } +} + +private fun buildChildElement(element: Element, tag: String, bean: Any, filter: SerializationFilter) { + Element(tag).apply { + XmlSerializer.serializeInto(bean, this, filter) + restoreNormalOrdering(bean) + element.addContent(this) + } +} + private fun KotlinFacetSettings.writeLatestConfig(element: Element) { val filter = SkipDefaultsSerializationFilter() @@ -177,17 +228,11 @@ private fun KotlinFacetSettings.writeLatestConfig(element: Element) { } compilerSettings?.let { copyBean(it) }?.let { it.convertPathsToSystemIndependent() - Element("compilerSettings").apply { - XmlSerializer.serializeInto(it, this, filter) - element.addContent(this) - } + buildChildElement(element, "compilerSettings", it, filter) } compilerArguments?.let { copyBean(it) }?.let { it.convertPathsToSystemIndependent() - Element("compilerArguments").apply { - XmlSerializer.serializeInto(it, this, filter) - element.addContent(this) - } + buildChildElement(element, "compilerArguments", it, filter) } } diff --git a/idea/idea.iml b/idea/idea.iml index eaeff0831f1..9509225f80d 100644 --- a/idea/idea.iml +++ b/idea/idea.iml @@ -68,5 +68,6 @@ + \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/facet/KotlinFacetEditorGeneralTab.kt b/idea/src/org/jetbrains/kotlin/idea/facet/KotlinFacetEditorGeneralTab.kt index 0daeed94064..cfc5d9cbf10 100644 --- a/idea/src/org/jetbrains/kotlin/idea/facet/KotlinFacetEditorGeneralTab.kt +++ b/idea/src/org/jetbrains/kotlin/idea/facet/KotlinFacetEditorGeneralTab.kt @@ -31,11 +31,11 @@ import org.jetbrains.kotlin.config.TargetPlatformKind import org.jetbrains.kotlin.config.createCompilerArguments import org.jetbrains.kotlin.config.splitArgumentString import org.jetbrains.kotlin.idea.compiler.configuration.* -import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import java.awt.BorderLayout import javax.swing.* import javax.swing.border.EmptyBorder import javax.swing.event.DocumentEvent +import kotlin.reflect.full.findAnnotation class KotlinFacetEditorGeneralTab( private val configuration: KotlinFacetConfiguration, @@ -172,14 +172,15 @@ class KotlinFacetEditorGeneralTab( is TargetPlatformKind.JavaScript -> jsUIExposedFields else -> commonUIExposedFields } - val fieldsToCheck = collectFieldsToCopy(argumentClass, false).filter { it.name in fieldNamesToCheck } + + val propertiesToCheck = collectProperties(argumentClass.kotlin, false).filter { it.name in fieldNamesToCheck } val overridingArguments = ArrayList() val redundantArguments = ArrayList() - for (field in fieldsToCheck) { - val additionalValue = field[additionalArguments] - if (additionalValue != field[emptyArguments]) { - val argumentInfo = field.annotations.firstIsInstanceOrNull() ?: continue - val addTo = if (additionalValue != field[primaryArguments]) overridingArguments else redundantArguments + for (property in propertiesToCheck) { + val additionalValue = property.get(additionalArguments) + if (additionalValue != property.get(emptyArguments)) { + val argumentInfo = property.findAnnotation() ?: continue + val addTo = if (additionalValue != property.get(primaryArguments)) overridingArguments else redundantArguments addTo += "" + argumentInfo.value.first() + "" } } diff --git a/idea/src/org/jetbrains/kotlin/idea/facet/facetUtils.kt b/idea/src/org/jetbrains/kotlin/idea/facet/facetUtils.kt index 099ff4bd454..ed49a1cfedf 100644 --- a/idea/src/org/jetbrains/kotlin/idea/facet/facetUtils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/facet/facetUtils.kt @@ -35,7 +35,7 @@ import org.jetbrains.kotlin.idea.compiler.configuration.KotlinCommonCompilerArgu import org.jetbrains.kotlin.idea.compiler.configuration.KotlinCompilerSettings import org.jetbrains.kotlin.idea.util.application.runWriteAction import org.jetbrains.kotlin.idea.versions.* -import java.lang.reflect.Field +import kotlin.reflect.KProperty1 private fun getDefaultTargetPlatform(module: Module, rootModel: ModuleRootModel?): TargetPlatformKind<*> { if (getRuntimeLibraryVersions(module, rootModel, TargetPlatformKind.JavaScript).isNotEmpty()) { @@ -221,7 +221,8 @@ fun parseCompilerArgumentsToFacet( val primaryFields = compilerArguments.primaryFields val ignoredFields = compilerArguments.ignoredFields - fun exposeAsAdditionalArgument(field: Field) = field.name !in primaryFields && field.get(compilerArguments) != field.get(defaultCompilerArguments) + fun exposeAsAdditionalArgument(property: KProperty1) = + property.name !in primaryFields && property.get(compilerArguments) != property.get(defaultCompilerArguments) val additionalArgumentsString = with(compilerArguments::class.java.newInstance()) { copyFieldsSatisfying(compilerArguments, this) { exposeAsAdditionalArgument(it) && it.name !in ignoredFields }