Fix reflection-based operations on compiler arguments after conversion
This commit is contained in:
@@ -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<String> convertArgumentsToStringList(@NotNull CommonToolArguments arguments)
|
||||
throws InstantiationException, IllegalAccessException {
|
||||
throws InstantiationException, IllegalAccessException, InvocationTargetException {
|
||||
List<String> result = new ArrayList<>();
|
||||
convertArgumentsToStringList(arguments, arguments.getClass().newInstance(), arguments.getClass(), result);
|
||||
Class<? extends CommonToolArguments> 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<String> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+38
-27
@@ -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 <T : Any> copyBean(bean: T) = copyFields(bean, bean::class.java.newInstance(), true, collectFieldsToCopy(bean::class.java, false))
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T : Any> copyBean(bean: T) =
|
||||
copyProperties(bean, bean::class.java.newInstance()!!, true, collectProperties(bean::class as KClass<T>, false))
|
||||
|
||||
fun <From : Any, To : From> 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<From>, false))
|
||||
}
|
||||
|
||||
fun <From : Any, To : Any> copyInheritedFields(from: From, to: To) = copyFields(from, to, true, collectFieldsToCopy(from::class.java, true))
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <From : Any, To : Any> copyInheritedFields(from: From, to: To) =
|
||||
copyProperties(from, to, true, collectProperties(from::class as KClass<From>, true))
|
||||
|
||||
fun <From : Any, To : Any> copyFieldsSatisfying(from: From, to: To, predicate: (Field) -> Boolean) =
|
||||
copyFields(from, to, true, collectFieldsToCopy(from::class.java, false).filter(predicate))
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <From : Any, To : Any> copyFieldsSatisfying(from: From, to: To, predicate: (KProperty1<From, Any?>) -> Boolean) =
|
||||
copyProperties(from, to, true, collectProperties(from::class as KClass<From>, false).filter(predicate))
|
||||
|
||||
private fun <From : Any, To : Any> copyFields(from: From, to: To, deepCopyWhenNeeded: Boolean, fieldsToCopy: List<Field>): To {
|
||||
private fun <From : Any, To : Any> copyProperties(
|
||||
from: From,
|
||||
to: To,
|
||||
deepCopyWhenNeeded: Boolean,
|
||||
propertiesToCopy: List<KProperty1<From, Any?>>
|
||||
): 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<To, Any?>
|
||||
?: 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<Field> {
|
||||
val fromFields = ArrayList<Field>()
|
||||
|
||||
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 <T : Any> collectProperties(kClass: KClass<T>, inheritedOnly: Boolean): List<KProperty1<T, Any?>> {
|
||||
val properties = ArrayList(kClass.memberProperties)
|
||||
if (inheritedOnly) {
|
||||
properties.removeAll(kClass.declaredMemberProperties)
|
||||
}
|
||||
|
||||
return fromFields
|
||||
}
|
||||
return properties.filter {
|
||||
it.visibility == KVisibility.PUBLIC && it.findAnnotation<Transient>() == null
|
||||
}
|
||||
}
|
||||
+23
-18
@@ -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 <A : CommonToolArguments> parseCommandLineArguments(args: List<String>, result: A) {
|
||||
data class ArgumentField(val field: Field, val argument: Argument)
|
||||
data class ArgumentField(val property: KMutableProperty1<A, Any?>, 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<Argument>() ?: return@mapNotNull null
|
||||
ArgumentField(property as KMutableProperty1<A, Any?>, argument)
|
||||
}
|
||||
|
||||
val errors = result.errors
|
||||
@@ -72,7 +76,7 @@ fun <A : CommonToolArguments> parseCommandLineArguments(args: List<String>, 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 <A : CommonToolArguments> parseCommandLineArguments(args: List<String>, 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 <A : CommonToolArguments> parseCommandLineArguments(args: List<String>, 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 <A : CommonToolArguments> parseCommandLineArguments(args: List<String>, 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 <A : CommonToolArguments> updateField(field: Field, result: A, value: Any, delimiter: String) {
|
||||
when (field.type) {
|
||||
Boolean::class.java, String::class.java -> field.set(result, value)
|
||||
Array<String>::class.java -> {
|
||||
private fun <A : CommonToolArguments> updateField(property: KMutableProperty1<A, Any?>, result: A, value: Any, delimiter: String) {
|
||||
when (property.returnType.classifier) {
|
||||
Boolean::class, String::class -> property.set(result, value)
|
||||
Array<String>::class -> {
|
||||
val newElements = (value as String).split(delimiter).toTypedArray()
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val oldValue = field.get(result) as Array<String>?
|
||||
field.set(result, if (oldValue != null) arrayOf(*oldValue, *newElements) else newElements)
|
||||
val oldValue = property.get(result) as Array<String>?
|
||||
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}")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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() + " <options> <source files>");
|
||||
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;
|
||||
|
||||
@@ -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 += "?"
|
||||
}
|
||||
|
||||
+4
-2
@@ -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<T : Any> protected constructor() : PersistentStateComponent<Element>, Cloneable {
|
||||
@Suppress("LeakingThis")
|
||||
@@ -40,9 +41,10 @@ abstract class BaseKotlinCompilerSettings<T : Any> protected constructor() : Per
|
||||
}
|
||||
|
||||
protected fun validateInheritedFieldsUnchanged(settings: T) {
|
||||
val inheritedFields = collectFieldsToCopy(settings.javaClass, true)
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val inheritedProperties = collectProperties<T>(settings::class as KClass<T>, 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 }}")
|
||||
}
|
||||
|
||||
@@ -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<String, Int> {
|
||||
val result = LinkedHashMap<String, Int>()
|
||||
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<Class<*>, Map<String, Int>>()
|
||||
|
||||
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<Element> { 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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -68,5 +68,6 @@
|
||||
<orderEntry type="module" module-name="frontend.script" />
|
||||
<orderEntry type="module" module-name="idea-maven" />
|
||||
<orderEntry type="module" module-name="backend.jvm" />
|
||||
<orderEntry type="library" name="kotlin-reflect" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -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<String>()
|
||||
val redundantArguments = ArrayList<String>()
|
||||
for (field in fieldsToCheck) {
|
||||
val additionalValue = field[additionalArguments]
|
||||
if (additionalValue != field[emptyArguments]) {
|
||||
val argumentInfo = field.annotations.firstIsInstanceOrNull<Argument>() ?: 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<Argument>() ?: continue
|
||||
val addTo = if (additionalValue != property.get(primaryArguments)) overridingArguments else redundantArguments
|
||||
addTo += "<strong>" + argumentInfo.value.first() + "</strong>"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<CommonCompilerArguments, Any?>) =
|
||||
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 }
|
||||
|
||||
Reference in New Issue
Block a user