K2: introduce even more readable renderer for types in messages
#KT-53343 Fixed
This commit is contained in:
+1
-1
@@ -9,5 +9,5 @@ public class Sample {
|
|||||||
// FILE: test.kt
|
// FILE: test.kt
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
Sample.foo(<!ARGUMENT_TYPE_MISMATCH("ft<kotlin/collections/MutableList<ft<kotlin/collections/MutableList<kotlin/String!>, kotlin/collections/List<kotlin/String!>?>>, kotlin/collections/List<ft<kotlin/collections/MutableList<kotlin/String!>, kotlin/collections/List<kotlin/String!>?>>?>; kotlin/String")!>"123"<!>)
|
Sample.foo(<!ARGUMENT_TYPE_MISMATCH("kotlin/collections/(Mutable)List<kotlin/collections/(Mutable)List<kotlin/String!>!>!; kotlin/String")!>"123"<!>)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,12 +15,6 @@ open class ConeTypeRenderer() {
|
|||||||
lateinit var builder: StringBuilder
|
lateinit var builder: StringBuilder
|
||||||
lateinit var idRenderer: ConeIdRenderer
|
lateinit var idRenderer: ConeIdRenderer
|
||||||
|
|
||||||
constructor(builder: StringBuilder, idRenderer: ConeIdRenderer) : this() {
|
|
||||||
this.builder = builder
|
|
||||||
this.idRenderer = idRenderer
|
|
||||||
idRenderer.builder = builder
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun renderAsPossibleFunctionType(
|
open fun renderAsPossibleFunctionType(
|
||||||
type: ConeKotlinType, renderType: ConeTypeProjection.() -> Unit = { render() }
|
type: ConeKotlinType, renderType: ConeTypeProjection.() -> Unit = { render() }
|
||||||
) {
|
) {
|
||||||
@@ -83,30 +77,38 @@ open class ConeTypeRenderer() {
|
|||||||
builder.append(type.lookupTag.name)
|
builder.append(type.lookupTag.name)
|
||||||
builder.append(")")
|
builder.append(")")
|
||||||
}
|
}
|
||||||
|
|
||||||
is ConeDefinitelyNotNullType -> {
|
is ConeDefinitelyNotNullType -> {
|
||||||
render(type.original)
|
render(type.original)
|
||||||
builder.append(" & Any")
|
builder.append(" & Any")
|
||||||
}
|
}
|
||||||
|
|
||||||
is ConeErrorType -> {
|
is ConeErrorType -> {
|
||||||
builder.append("ERROR CLASS: ${type.diagnostic.reason}")
|
builder.append("ERROR CLASS: ${type.diagnostic.reason}")
|
||||||
}
|
}
|
||||||
|
|
||||||
is ConeCapturedType -> {
|
is ConeCapturedType -> {
|
||||||
builder.append("CapturedType(")
|
builder.append("CapturedType(")
|
||||||
type.constructor.projection.render()
|
type.constructor.projection.render()
|
||||||
builder.append(")")
|
builder.append(")")
|
||||||
}
|
}
|
||||||
|
|
||||||
is ConeClassLikeType -> {
|
is ConeClassLikeType -> {
|
||||||
type.render()
|
type.render()
|
||||||
}
|
}
|
||||||
|
|
||||||
is ConeLookupTagBasedType -> {
|
is ConeLookupTagBasedType -> {
|
||||||
builder.append(type.lookupTag.name.asString())
|
builder.append(type.lookupTag.name.asString())
|
||||||
}
|
}
|
||||||
|
|
||||||
is ConeDynamicType -> {
|
is ConeDynamicType -> {
|
||||||
builder.append("dynamic")
|
builder.append("dynamic")
|
||||||
}
|
}
|
||||||
|
|
||||||
is ConeFlexibleType -> {
|
is ConeFlexibleType -> {
|
||||||
type.render()
|
render(type)
|
||||||
}
|
}
|
||||||
|
|
||||||
is ConeIntersectionType -> {
|
is ConeIntersectionType -> {
|
||||||
builder.append("it(")
|
builder.append("it(")
|
||||||
for ((index, intersected) in type.intersectedTypes.withIndex()) {
|
for ((index, intersected) in type.intersectedTypes.withIndex()) {
|
||||||
@@ -117,18 +119,23 @@ open class ConeTypeRenderer() {
|
|||||||
}
|
}
|
||||||
builder.append(")")
|
builder.append(")")
|
||||||
}
|
}
|
||||||
|
|
||||||
is ConeStubTypeForSyntheticFixation -> {
|
is ConeStubTypeForSyntheticFixation -> {
|
||||||
builder.append("Stub (fixation): ${type.constructor.variable}")
|
builder.append("Stub (fixation): ${type.constructor.variable}")
|
||||||
}
|
}
|
||||||
|
|
||||||
is ConeStubTypeForChainInference -> {
|
is ConeStubTypeForChainInference -> {
|
||||||
builder.append("Stub (chain inference): ${type.constructor.variable}")
|
builder.append("Stub (chain inference): ${type.constructor.variable}")
|
||||||
}
|
}
|
||||||
|
|
||||||
is ConeStubType -> {
|
is ConeStubType -> {
|
||||||
builder.append("Stub (subtyping): ${type.constructor.variable}")
|
builder.append("Stub (subtyping): ${type.constructor.variable}")
|
||||||
}
|
}
|
||||||
|
|
||||||
is ConeIntegerLiteralConstantType -> {
|
is ConeIntegerLiteralConstantType -> {
|
||||||
builder.append("ILT: ${type.value}")
|
builder.append("ILT: ${type.value}")
|
||||||
}
|
}
|
||||||
|
|
||||||
is ConeIntegerConstantOperatorType -> {
|
is ConeIntegerConstantOperatorType -> {
|
||||||
builder.append("IOT")
|
builder.append("IOT")
|
||||||
}
|
}
|
||||||
@@ -151,9 +158,7 @@ open class ConeTypeRenderer() {
|
|||||||
builder.append(">")
|
builder.append(">")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ConeFlexibleType.render() {
|
private fun ConeFlexibleType.renderForSameLookupTags(): Boolean {
|
||||||
val lowerBound = lowerBound
|
|
||||||
val upperBound = upperBound
|
|
||||||
if (lowerBound is ConeLookupTagBasedType && upperBound is ConeLookupTagBasedType &&
|
if (lowerBound is ConeLookupTagBasedType && upperBound is ConeLookupTagBasedType &&
|
||||||
lowerBound.lookupTag == upperBound.lookupTag &&
|
lowerBound.lookupTag == upperBound.lookupTag &&
|
||||||
lowerBound.nullability == ConeNullability.NOT_NULL && upperBound.nullability == ConeNullability.NULLABLE
|
lowerBound.nullability == ConeNullability.NOT_NULL && upperBound.nullability == ConeNullability.NULLABLE
|
||||||
@@ -162,14 +167,21 @@ open class ConeTypeRenderer() {
|
|||||||
if (upperBound !is ConeClassLikeType || upperBound.typeArguments.isEmpty()) {
|
if (upperBound !is ConeClassLikeType || upperBound.typeArguments.isEmpty()) {
|
||||||
render(lowerBound)
|
render(lowerBound)
|
||||||
builder.append("!")
|
builder.append("!")
|
||||||
return
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open fun render(flexibleType: ConeFlexibleType) {
|
||||||
|
if (flexibleType.renderForSameLookupTags()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
builder.append("ft<")
|
builder.append("ft<")
|
||||||
render(lowerBound)
|
render(flexibleType.lowerBound)
|
||||||
builder.append(", ")
|
builder.append(", ")
|
||||||
render(upperBound)
|
render(flexibleType.upperBound)
|
||||||
builder.append(">")
|
builder.append(">")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,18 +195,22 @@ open class ConeTypeRenderer() {
|
|||||||
ConeStarProjection -> {
|
ConeStarProjection -> {
|
||||||
builder.append("*")
|
builder.append("*")
|
||||||
}
|
}
|
||||||
|
|
||||||
is ConeKotlinTypeConflictingProjection -> {
|
is ConeKotlinTypeConflictingProjection -> {
|
||||||
builder.append("CONFLICTING-PROJECTION ")
|
builder.append("CONFLICTING-PROJECTION ")
|
||||||
render(type)
|
render(type)
|
||||||
}
|
}
|
||||||
|
|
||||||
is ConeKotlinTypeProjectionIn -> {
|
is ConeKotlinTypeProjectionIn -> {
|
||||||
builder.append("in ")
|
builder.append("in ")
|
||||||
render(type)
|
render(type)
|
||||||
}
|
}
|
||||||
|
|
||||||
is ConeKotlinTypeProjectionOut -> {
|
is ConeKotlinTypeProjectionOut -> {
|
||||||
builder.append("out ")
|
builder.append("out ")
|
||||||
render(type)
|
render(type)
|
||||||
}
|
}
|
||||||
|
|
||||||
is ConeKotlinType -> {
|
is ConeKotlinType -> {
|
||||||
render(this)
|
render(this)
|
||||||
}
|
}
|
||||||
|
|||||||
+76
@@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2022 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.fir.renderer
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.builtins.StandardNames
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeFlexibleType
|
||||||
|
import org.jetbrains.kotlin.renderer.replacePrefixesInTypeRepresentations
|
||||||
|
import org.jetbrains.kotlin.renderer.typeStringsDifferOnlyInNullability
|
||||||
|
|
||||||
|
class ConeTypeRendererWithJavaFlexibleTypes : ConeTypeRenderer {
|
||||||
|
|
||||||
|
private val idRendererCreator: () -> ConeIdRenderer
|
||||||
|
|
||||||
|
@Suppress("ConvertSecondaryConstructorToPrimary")
|
||||||
|
constructor(builder: StringBuilder, idRendererCreator: () -> ConeIdRenderer) : super() {
|
||||||
|
this.builder = builder
|
||||||
|
this.idRendererCreator = idRendererCreator
|
||||||
|
this.idRenderer = idRendererCreator()
|
||||||
|
idRenderer.builder = builder
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun render(flexibleType: ConeFlexibleType) {
|
||||||
|
val lowerRenderer = ConeTypeRendererWithJavaFlexibleTypes(StringBuilder(), idRendererCreator)
|
||||||
|
lowerRenderer.render(flexibleType.lowerBound)
|
||||||
|
val upperRenderer = ConeTypeRendererWithJavaFlexibleTypes(StringBuilder(), idRendererCreator)
|
||||||
|
upperRenderer.render(flexibleType.upperBound)
|
||||||
|
builder.append(renderFlexibleType(lowerRenderer.builder.toString(), upperRenderer.builder.toString()))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun renderFlexibleType(lowerRendered: String, upperRendered: String): String {
|
||||||
|
if (typeStringsDifferOnlyInNullability(lowerRendered, upperRendered)) {
|
||||||
|
if (upperRendered.startsWith("(")) {
|
||||||
|
// the case of complex type, e.g. (() -> Unit)?
|
||||||
|
return "($lowerRendered)!"
|
||||||
|
}
|
||||||
|
return "$lowerRendered!"
|
||||||
|
}
|
||||||
|
|
||||||
|
val kotlinCollectionsPrefix = StandardNames.COLLECTIONS_PACKAGE_FQ_NAME.asString().replace(".", "/") + "/"
|
||||||
|
val mutablePrefix = "Mutable"
|
||||||
|
// java.util.List<Foo> -> (Mutable)List<Foo!>!
|
||||||
|
val simpleCollection = replacePrefixesInTypeRepresentations(
|
||||||
|
lowerRendered,
|
||||||
|
kotlinCollectionsPrefix + mutablePrefix,
|
||||||
|
upperRendered,
|
||||||
|
kotlinCollectionsPrefix,
|
||||||
|
"$kotlinCollectionsPrefix($mutablePrefix)"
|
||||||
|
)
|
||||||
|
if (simpleCollection != null) return simpleCollection
|
||||||
|
// java.util.Map.Entry<Foo, Bar> -> (Mutable)Map.(Mutable)Entry<Foo!, Bar!>!
|
||||||
|
val mutableEntry = replacePrefixesInTypeRepresentations(
|
||||||
|
lowerRendered,
|
||||||
|
kotlinCollectionsPrefix + "MutableMap.MutableEntry",
|
||||||
|
upperRendered,
|
||||||
|
kotlinCollectionsPrefix + "Map.Entry",
|
||||||
|
"$kotlinCollectionsPrefix(Mutable)Map.(Mutable)Entry"
|
||||||
|
)
|
||||||
|
if (mutableEntry != null) return mutableEntry
|
||||||
|
|
||||||
|
val kotlinPrefix = StandardNames.BUILT_INS_PACKAGE_FQ_NAME.asString() + "/"
|
||||||
|
// Foo[] -> Array<(out) Foo!>!
|
||||||
|
val array = replacePrefixesInTypeRepresentations(
|
||||||
|
lowerRendered = lowerRendered,
|
||||||
|
lowerPrefix = kotlinPrefix + "Array<",
|
||||||
|
upperRendered = upperRendered,
|
||||||
|
upperPrefix = kotlinPrefix + "Array<out ",
|
||||||
|
foldedPrefix = kotlinPrefix + "Array<(out) "
|
||||||
|
)
|
||||||
|
if (array != null) return array
|
||||||
|
|
||||||
|
return "ft<$lowerRendered, $upperRendered>"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,6 +28,7 @@ fun ConeKotlinType.forEachType(action: (ConeKotlinType) -> Unit) {
|
|||||||
lowerBound.forEachType(action)
|
lowerBound.forEachType(action)
|
||||||
upperBound.forEachType(action)
|
upperBound.forEachType(action)
|
||||||
}
|
}
|
||||||
|
|
||||||
is ConeDefinitelyNotNullType -> original.forEachType(action)
|
is ConeDefinitelyNotNullType -> original.forEachType(action)
|
||||||
is ConeIntersectionType -> intersectedTypes.forEach { it.forEachType(action) }
|
is ConeIntersectionType -> intersectedTypes.forEach { it.forEachType(action) }
|
||||||
else -> typeArguments.forEach { if (it is ConeKotlinTypeProjection) it.type.forEachType(action) }
|
else -> typeArguments.forEach { if (it is ConeKotlinTypeProjection) it.type.forEachType(action) }
|
||||||
@@ -126,13 +127,13 @@ fun ConeKotlinType.renderForDebugging(): String {
|
|||||||
|
|
||||||
fun ConeKotlinType.renderReadable(): String {
|
fun ConeKotlinType.renderReadable(): String {
|
||||||
val builder = StringBuilder()
|
val builder = StringBuilder()
|
||||||
ConeTypeRenderer(builder, idRenderer = ConeIdShortRenderer()).render(this)
|
ConeTypeRendererWithJavaFlexibleTypes(builder) { ConeIdShortRenderer() }.render(this)
|
||||||
return builder.toString()
|
return builder.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ConeKotlinType.renderReadableWithFqNames(): String {
|
fun ConeKotlinType.renderReadableWithFqNames(): String {
|
||||||
val builder = StringBuilder()
|
val builder = StringBuilder()
|
||||||
ConeTypeRenderer(builder, idRenderer = ConeIdRendererForDebugging()).render(this)
|
ConeTypeRendererWithJavaFlexibleTypes(builder) { ConeIdRendererForDebugging() }.render(this)
|
||||||
return builder.toString()
|
return builder.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-29
@@ -15,7 +15,6 @@ import org.jetbrains.kotlin.fir.expressions.*
|
|||||||
import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
|
import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
|
||||||
import org.jetbrains.kotlin.fir.references.*
|
import org.jetbrains.kotlin.fir.references.*
|
||||||
import org.jetbrains.kotlin.fir.renderer.ConeTypeRendererForDebugging
|
import org.jetbrains.kotlin.fir.renderer.ConeTypeRendererForDebugging
|
||||||
import org.jetbrains.kotlin.fir.renderer.FirPrinter
|
|
||||||
import org.jetbrains.kotlin.fir.resolve.defaultType
|
import org.jetbrains.kotlin.fir.resolve.defaultType
|
||||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||||
import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol
|
import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol
|
||||||
@@ -31,6 +30,7 @@ import org.jetbrains.kotlin.psi
|
|||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getChildOfType
|
import org.jetbrains.kotlin.psi.psiUtil.getChildOfType
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getChildrenOfType
|
import org.jetbrains.kotlin.psi.psiUtil.getChildrenOfType
|
||||||
|
import org.jetbrains.kotlin.renderer.replacePrefixesInTypeRepresentations
|
||||||
import org.jetbrains.kotlin.types.AbstractStrictEqualityTypeChecker
|
import org.jetbrains.kotlin.types.AbstractStrictEqualityTypeChecker
|
||||||
import org.jetbrains.kotlin.types.ConstantValueKind
|
import org.jetbrains.kotlin.types.ConstantValueKind
|
||||||
import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly
|
import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly
|
||||||
@@ -342,33 +342,8 @@ class FirVisualizer(private val firFile: FirFile) : BaseRenderer() {
|
|||||||
builder.append(projectionBuilder.toString().removeCurrentFilePackage())
|
builder.append(projectionBuilder.toString().removeCurrentFilePackage())
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO rewrite or extract in common utils
|
|
||||||
private fun replacePrefixes(
|
|
||||||
lowerRendered: String,
|
|
||||||
lowerPrefix: String,
|
|
||||||
upperRendered: String,
|
|
||||||
upperPrefix: String,
|
|
||||||
foldedPrefix: String
|
|
||||||
): String? {
|
|
||||||
if (lowerRendered.startsWith(lowerPrefix) && upperRendered.startsWith(upperPrefix)) {
|
|
||||||
val lowerWithoutPrefix = lowerRendered.substring(lowerPrefix.length)
|
|
||||||
val upperWithoutPrefix = upperRendered.substring(upperPrefix.length)
|
|
||||||
val flexibleCollectionName = foldedPrefix + lowerWithoutPrefix
|
|
||||||
|
|
||||||
if (lowerWithoutPrefix == upperWithoutPrefix) return flexibleCollectionName
|
|
||||||
|
|
||||||
if (differsOnlyInNullability(lowerWithoutPrefix, upperWithoutPrefix)) {
|
|
||||||
return "$flexibleCollectionName!"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun differsOnlyInNullability(lower: String, upper: String) =
|
|
||||||
lower == upper.replace("?", "") || upper.endsWith("?") && ("$lower?") == upper || "($lower)?" == upper
|
|
||||||
|
|
||||||
private fun tryToSquashFlexibleType(lowerRendered: String, upperRendered: String): String? {
|
private fun tryToSquashFlexibleType(lowerRendered: String, upperRendered: String): String? {
|
||||||
val simpleCollection = replacePrefixes(
|
val simpleCollection = replacePrefixesInTypeRepresentations(
|
||||||
lowerRendered,
|
lowerRendered,
|
||||||
"kotlin/collections/Mutable",
|
"kotlin/collections/Mutable",
|
||||||
upperRendered,
|
upperRendered,
|
||||||
@@ -377,7 +352,7 @@ class FirVisualizer(private val firFile: FirFile) : BaseRenderer() {
|
|||||||
)
|
)
|
||||||
if (simpleCollection != null) return simpleCollection
|
if (simpleCollection != null) return simpleCollection
|
||||||
|
|
||||||
val mutableEntry = replacePrefixes(
|
val mutableEntry = replacePrefixesInTypeRepresentations(
|
||||||
lowerRendered,
|
lowerRendered,
|
||||||
"kotlin/collections/MutableMap.MutableEntry",
|
"kotlin/collections/MutableMap.MutableEntry",
|
||||||
upperRendered,
|
upperRendered,
|
||||||
@@ -386,7 +361,7 @@ class FirVisualizer(private val firFile: FirFile) : BaseRenderer() {
|
|||||||
)
|
)
|
||||||
if (mutableEntry != null) return mutableEntry
|
if (mutableEntry != null) return mutableEntry
|
||||||
|
|
||||||
val array = replacePrefixes(
|
val array = replacePrefixesInTypeRepresentations(
|
||||||
lowerRendered,
|
lowerRendered,
|
||||||
"kotlin/Array<",
|
"kotlin/Array<",
|
||||||
upperRendered,
|
upperRendered,
|
||||||
|
|||||||
@@ -48,3 +48,27 @@ fun renderFqName(pathSegments: List<Name>): String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun replacePrefixesInTypeRepresentations(
|
||||||
|
lowerRendered: String,
|
||||||
|
lowerPrefix: String,
|
||||||
|
upperRendered: String,
|
||||||
|
upperPrefix: String,
|
||||||
|
foldedPrefix: String
|
||||||
|
): String? {
|
||||||
|
if (lowerRendered.startsWith(lowerPrefix) && upperRendered.startsWith(upperPrefix)) {
|
||||||
|
val lowerWithoutPrefix = lowerRendered.substring(lowerPrefix.length)
|
||||||
|
val upperWithoutPrefix = upperRendered.substring(upperPrefix.length)
|
||||||
|
val flexibleCollectionName = foldedPrefix + lowerWithoutPrefix
|
||||||
|
|
||||||
|
if (lowerWithoutPrefix == upperWithoutPrefix) return flexibleCollectionName
|
||||||
|
|
||||||
|
if (typeStringsDifferOnlyInNullability(lowerWithoutPrefix, upperWithoutPrefix)) {
|
||||||
|
return "$flexibleCollectionName!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun typeStringsDifferOnlyInNullability(lower: String, upper: String) =
|
||||||
|
lower == upper.replace("?", "") || upper.endsWith("?") && ("$lower?") == upper || "($lower)?" == upper
|
||||||
|
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ internal class DescriptorRendererImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun renderFlexibleType(lowerRendered: String, upperRendered: String, builtIns: KotlinBuiltIns): String {
|
override fun renderFlexibleType(lowerRendered: String, upperRendered: String, builtIns: KotlinBuiltIns): String {
|
||||||
if (differsOnlyInNullability(lowerRendered, upperRendered)) {
|
if (typeStringsDifferOnlyInNullability(lowerRendered, upperRendered)) {
|
||||||
if (upperRendered.startsWith("(")) {
|
if (upperRendered.startsWith("(")) {
|
||||||
// the case of complex type, e.g. (() -> Unit)?
|
// the case of complex type, e.g. (() -> Unit)?
|
||||||
return "($lowerRendered)!"
|
return "($lowerRendered)!"
|
||||||
@@ -195,7 +195,7 @@ internal class DescriptorRendererImpl(
|
|||||||
val kotlinCollectionsPrefix = classifierNamePolicy.renderClassifier(builtIns.collection, this).substringBefore("Collection")
|
val kotlinCollectionsPrefix = classifierNamePolicy.renderClassifier(builtIns.collection, this).substringBefore("Collection")
|
||||||
val mutablePrefix = "Mutable"
|
val mutablePrefix = "Mutable"
|
||||||
// java.util.List<Foo> -> (Mutable)List<Foo!>!
|
// java.util.List<Foo> -> (Mutable)List<Foo!>!
|
||||||
val simpleCollection = replacePrefixes(
|
val simpleCollection = replacePrefixesInTypeRepresentations(
|
||||||
lowerRendered,
|
lowerRendered,
|
||||||
kotlinCollectionsPrefix + mutablePrefix,
|
kotlinCollectionsPrefix + mutablePrefix,
|
||||||
upperRendered,
|
upperRendered,
|
||||||
@@ -204,7 +204,7 @@ internal class DescriptorRendererImpl(
|
|||||||
)
|
)
|
||||||
if (simpleCollection != null) return simpleCollection
|
if (simpleCollection != null) return simpleCollection
|
||||||
// java.util.Map.Entry<Foo, Bar> -> (Mutable)Map.(Mutable)Entry<Foo!, Bar!>!
|
// java.util.Map.Entry<Foo, Bar> -> (Mutable)Map.(Mutable)Entry<Foo!, Bar!>!
|
||||||
val mutableEntry = replacePrefixes(
|
val mutableEntry = replacePrefixesInTypeRepresentations(
|
||||||
lowerRendered,
|
lowerRendered,
|
||||||
kotlinCollectionsPrefix + "MutableMap.MutableEntry",
|
kotlinCollectionsPrefix + "MutableMap.MutableEntry",
|
||||||
upperRendered,
|
upperRendered,
|
||||||
@@ -215,7 +215,7 @@ internal class DescriptorRendererImpl(
|
|||||||
|
|
||||||
val kotlinPrefix = classifierNamePolicy.renderClassifier(builtIns.array, this).substringBefore("Array")
|
val kotlinPrefix = classifierNamePolicy.renderClassifier(builtIns.array, this).substringBefore("Array")
|
||||||
// Foo[] -> Array<(out) Foo!>!
|
// Foo[] -> Array<(out) Foo!>!
|
||||||
val array = replacePrefixes(
|
val array = replacePrefixesInTypeRepresentations(
|
||||||
lowerRendered,
|
lowerRendered,
|
||||||
kotlinPrefix + escape("Array<"),
|
kotlinPrefix + escape("Array<"),
|
||||||
upperRendered,
|
upperRendered,
|
||||||
@@ -227,12 +227,13 @@ internal class DescriptorRendererImpl(
|
|||||||
return "($lowerRendered..$upperRendered)"
|
return "($lowerRendered..$upperRendered)"
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun renderTypeArguments(typeArguments: List<TypeProjection>): String = if (typeArguments.isEmpty()) ""
|
override fun renderTypeArguments(typeArguments: List<TypeProjection>): String =
|
||||||
else buildString {
|
if (typeArguments.isEmpty()) ""
|
||||||
append(lt())
|
else buildString {
|
||||||
this.appendTypeProjections(typeArguments)
|
append(lt())
|
||||||
append(gt())
|
this.appendTypeProjections(typeArguments)
|
||||||
}
|
append(gt())
|
||||||
|
}
|
||||||
|
|
||||||
private fun StringBuilder.renderDefaultType(type: KotlinType) {
|
private fun StringBuilder.renderDefaultType(type: KotlinType) {
|
||||||
this.renderAnnotations(type)
|
this.renderAnnotations(type)
|
||||||
@@ -1198,29 +1199,5 @@ internal class DescriptorRendererImpl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun replacePrefixes(
|
|
||||||
lowerRendered: String,
|
|
||||||
lowerPrefix: String,
|
|
||||||
upperRendered: String,
|
|
||||||
upperPrefix: String,
|
|
||||||
foldedPrefix: String
|
|
||||||
): String? {
|
|
||||||
if (lowerRendered.startsWith(lowerPrefix) && upperRendered.startsWith(upperPrefix)) {
|
|
||||||
val lowerWithoutPrefix = lowerRendered.substring(lowerPrefix.length)
|
|
||||||
val upperWithoutPrefix = upperRendered.substring(upperPrefix.length)
|
|
||||||
val flexibleCollectionName = foldedPrefix + lowerWithoutPrefix
|
|
||||||
|
|
||||||
if (lowerWithoutPrefix == upperWithoutPrefix) return flexibleCollectionName
|
|
||||||
|
|
||||||
if (differsOnlyInNullability(lowerWithoutPrefix, upperWithoutPrefix)) {
|
|
||||||
return "$flexibleCollectionName!"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun differsOnlyInNullability(lower: String, upper: String) =
|
|
||||||
lower == upper.replace("?", "") || upper.endsWith("?") && ("$lower?") == upper || "($lower)?" == upper
|
|
||||||
|
|
||||||
private fun overridesSomething(callable: CallableMemberDescriptor) = !callable.overriddenDescriptors.isEmpty()
|
private fun overridesSomething(callable: CallableMemberDescriptor) = !callable.overriddenDescriptors.isEmpty()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user