diff --git a/idea/idea-frontend-fir/idea-frontend-fir-generator/src/org/jetbrains/kotlin/idea/frontend/api/fir/generator/HLDiagnosticConverter.kt b/idea/idea-frontend-fir/idea-frontend-fir-generator/src/org/jetbrains/kotlin/idea/frontend/api/fir/generator/HLDiagnosticConverter.kt index e890cfe76c6..595594f0f9b 100644 --- a/idea/idea-frontend-fir/idea-frontend-fir-generator/src/org/jetbrains/kotlin/idea/frontend/api/fir/generator/HLDiagnosticConverter.kt +++ b/idea/idea-frontend-fir/idea-frontend-fir-generator/src/org/jetbrains/kotlin/idea/frontend/api/fir/generator/HLDiagnosticConverter.kt @@ -98,14 +98,32 @@ private object FirToKtConversionCreator { return null } + private fun KType.toParameterName(): String { + return kClass.simpleName!!.replaceFirstChar(Char::lowercaseChar) + } + private fun tryMapPlatformType(type: KType, kClass: KClass<*>): HLParameterConversion? { if (kClass.isSubclassOf(Collection::class)) { val elementType = type.arguments.single().type ?: return HLIdParameterConversion - return HLMapParameterConversion( - parameterName = elementType.kClass.simpleName!!.replaceFirstChar(Char::lowercaseChar), + return HLCollectionParameterConversion( + parameterName = elementType.toParameterName(), mappingConversion = createConversion(elementType) ) } + if (kClass.isSubclassOf(Map::class)) { + val keyType = type.arguments.getOrNull(0)?.type + val valueType = type.arguments.getOrNull(1)?.type + + val keyConversion = keyType?.let { createConversion(it) } ?: HLIdParameterConversion + val valueConversion = valueType?.let { createConversion(it) } ?: HLIdParameterConversion + if (keyConversion.isTrivial && valueConversion.isTrivial) return HLIdParameterConversion + return HLMapParameterConversion( + keyName = keyType?.toParameterName() ?: "key", + valueName = valueType?.toParameterName() ?: "value", + mappingConversionForKeys = keyConversion, + mappingConversionForValues = valueConversion + ) + } if (kClass.isSubclassOf(Pair::class)) { val first = type.arguments.getOrNull(0)?.type ?: return HLIdParameterConversion val second = type.arguments.getOrNull(1)?.type ?: return HLIdParameterConversion diff --git a/idea/idea-frontend-fir/idea-frontend-fir-generator/src/org/jetbrains/kotlin/idea/frontend/api/fir/generator/HLParameterConversion.kt b/idea/idea-frontend-fir/idea-frontend-fir-generator/src/org/jetbrains/kotlin/idea/frontend/api/fir/generator/HLParameterConversion.kt index 74f8beb8184..d3773bed22a 100644 --- a/idea/idea-frontend-fir/idea-frontend-fir-generator/src/org/jetbrains/kotlin/idea/frontend/api/fir/generator/HLParameterConversion.kt +++ b/idea/idea-frontend-fir/idea-frontend-fir-generator/src/org/jetbrains/kotlin/idea/frontend/api/fir/generator/HLParameterConversion.kt @@ -21,7 +21,7 @@ object HLIdParameterConversion : HLParameterConversion() { override fun convertType(type: KType): KType = type } -class HLMapParameterConversion( +class HLCollectionParameterConversion( private val parameterName: String, private val mappingConversion: HLParameterConversion, ) : HLParameterConversion() { @@ -47,6 +47,45 @@ class HLMapParameterConversion( override val importsToAdd get() = mappingConversion.importsToAdd } +class HLMapParameterConversion( + private val keyName: String, + private val valueName: String, + private val mappingConversionForKeys: HLParameterConversion, + private val mappingConversionForValues: HLParameterConversion, +) : HLParameterConversion() { + override fun convertExpression(expression: String, context: ConversionContext): String { + val keyTransformation = mappingConversionForKeys.convertExpression(keyName, context.increaseIndent()) + val valueTransformation = mappingConversionForValues.convertExpression(valueName, context.increaseIndent()) + return buildString { + appendLine("$expression.mapKeys { ($keyName, _) ->") + appendLine(keyTransformation.withIndent(context.increaseIndent())) + appendLine("}.mapValues { (_, $valueName) -> ".withIndent(context)) + appendLine(valueTransformation.withIndent(context.increaseIndent())) + append("}".withIndent(context)) + } + } + + override fun convertType(type: KType): KType { + val keyArgument = type.arguments[0] + val valueArgument = type.arguments[1] + return Map::class.createType( + arguments = listOf( + KTypeProjection( + variance = KVariance.INVARIANT, + type = keyArgument.type?.let(mappingConversionForKeys::convertType) + ), + KTypeProjection( + variance = KVariance.INVARIANT, + type = valueArgument.type?.let(mappingConversionForValues::convertType) + ) + ) + ) + } + + override val importsToAdd: List + get() = (mappingConversionForKeys.importsToAdd + mappingConversionForValues.importsToAdd).distinct() +} + class HLPairParameterConversion( private val mappingConversionFirst: HLParameterConversion, private val mappingConversionSecond: HLParameterConversion, @@ -93,3 +132,6 @@ private fun String.withIndent(context: ConversionContext): String { val newIndent = " ".repeat(context.currentIndent * context.indentUnitValue) return replaceIndent(newIndent) } + +val HLParameterConversion.isTrivial: Boolean + get() = this is HLIdParameterConversion