Kotlin: Fix fake raw type symbols used by the Parcelize plugin

This commit is contained in:
Tamas Vajk
2022-06-01 16:09:56 +02:00
parent 0a861ff616
commit ba5cf5b1b2

View File

@@ -419,31 +419,35 @@ open class KotlinUsesExtractor(
// `typeArgs` can be null to describe a raw generic type. // `typeArgs` can be null to describe a raw generic type.
// For non-generic types it will be zero-length list. // For non-generic types it will be zero-length list.
fun addClassLabel(cBeforeReplacement: IrClass, argsIncludingOuterClasses: List<IrTypeArgument>?, inReceiverContext: Boolean = false): TypeResult<DbClassorinterface> { private fun addClassLabel(cBeforeReplacement: IrClass, argsIncludingOuterClasses: List<IrTypeArgument>?, inReceiverContext: Boolean = false): TypeResult<DbClassorinterface> {
val c = tryReplaceAndroidSyntheticClass(cBeforeReplacement) val c = tryReplaceAndroidSyntheticClass(cBeforeReplacement)
val classLabelResult = getClassLabel(c, argsIncludingOuterClasses) val p = tryReplaceParcelizeRawType(c)
val replacedClass = p?.first ?: c
val replacedArgsIncludingOuterClasses = p?.second ?: argsIncludingOuterClasses
val classLabelResult = getClassLabel(replacedClass, replacedArgsIncludingOuterClasses)
var instanceSeenBefore = true var instanceSeenBefore = true
val classLabel : Label<out DbClassorinterface> = tw.getLabelFor(classLabelResult.classLabel, { val classLabel : Label<out DbClassorinterface> = tw.getLabelFor(classLabelResult.classLabel) {
instanceSeenBefore = false instanceSeenBefore = false
extractClassLaterIfExternal(c) extractClassLaterIfExternal(replacedClass)
}) }
if (argsIncludingOuterClasses == null || argsIncludingOuterClasses.isNotEmpty()) { if (replacedArgsIncludingOuterClasses == null || replacedArgsIncludingOuterClasses.isNotEmpty()) {
// If this is a generic type instantiation or a raw type then it has no // If this is a generic type instantiation or a raw type then it has no
// source entity, so we need to extract it here // source entity, so we need to extract it here
val extractorWithCSource by lazy { this.withFileOfClass(c) } val extractorWithCSource by lazy { this.withFileOfClass(replacedClass) }
if (!instanceSeenBefore) { if (!instanceSeenBefore) {
extractorWithCSource.extractClassInstance(c, argsIncludingOuterClasses) extractorWithCSource.extractClassInstance(replacedClass, replacedArgsIncludingOuterClasses)
} }
if (inReceiverContext && tw.lm.genericSpecialisationsExtracted.add(classLabelResult.classLabel)) { if (inReceiverContext && tw.lm.genericSpecialisationsExtracted.add(classLabelResult.classLabel)) {
val supertypeMode = if (argsIncludingOuterClasses == null) ExtractSupertypesMode.Raw else ExtractSupertypesMode.Specialised(argsIncludingOuterClasses) val supertypeMode = if (replacedArgsIncludingOuterClasses == null) ExtractSupertypesMode.Raw else ExtractSupertypesMode.Specialised(replacedArgsIncludingOuterClasses)
extractorWithCSource.extractClassSupertypes(c, classLabel, supertypeMode, true) extractorWithCSource.extractClassSupertypes(replacedClass, classLabel, supertypeMode, true)
extractorWithCSource.extractNonPrivateMemberPrototypes(c, argsIncludingOuterClasses, classLabel) extractorWithCSource.extractNonPrivateMemberPrototypes(replacedClass, replacedArgsIncludingOuterClasses, classLabel)
} }
} }
@@ -453,6 +457,35 @@ open class KotlinUsesExtractor(
classLabelResult.shortName) classLabelResult.shortName)
} }
private fun tryReplaceParcelizeRawType(c: IrClass): Pair<IrClass, List<IrTypeArgument>?>? {
if (c.superTypes.isNotEmpty() ||
c.origin != IrDeclarationOrigin.DEFINED ||
c.hasEqualFqName(FqName("java.lang.Object"))) {
return null
}
fun tryGetPair(arity: Int): Pair<IrClass, List<IrTypeArgument>?>? {
val replaced = pluginContext.referenceClass(c.fqNameWhenAvailable!!)?.owner ?: return null
return Pair(replaced, List(arity) { makeTypeProjection(pluginContext.irBuiltIns.anyNType, Variance.INVARIANT) })
}
// The list of types handled here match https://github.com/JetBrains/kotlin/blob/d7c7d1efd2c0983c13b175e9e4b1cda979521159/plugins/parcelize/parcelize-compiler/src/org/jetbrains/kotlin/parcelize/ir/AndroidSymbols.kt
// Specifically, types are added for generic types created in AndroidSymbols.kt.
// This replacement is from a raw type to its matching parameterized type with `Object` type arguments.
return when (c.fqNameWhenAvailable?.asString()) {
"java.util.ArrayList" -> tryGetPair(1)
"java.util.LinkedHashMap" -> tryGetPair(2)
"java.util.LinkedHashSet" -> tryGetPair(1)
"java.util.List" -> tryGetPair(1)
"java.util.TreeMap" -> tryGetPair(2)
"java.util.TreeSet" -> tryGetPair(1)
"java.lang.Class" -> tryGetPair(1)
else -> null
}
}
fun useAnonymousClass(c: IrClass) = fun useAnonymousClass(c: IrClass) =
tw.lm.anonymousTypeMapping.getOrPut(c) { tw.lm.anonymousTypeMapping.getOrPut(c) {
TypeResults( TypeResults(
@@ -721,7 +754,15 @@ open class KotlinUsesExtractor(
} else { } else {
extractFileClass(dp) extractFileClass(dp)
} }
is IrClass -> if (classTypeArguments != null && !dp.isAnonymousObject) useClassInstance(dp, classTypeArguments, inReceiverContext).typeResult.id else useClassSource(dp) is IrClass ->
if (classTypeArguments != null && !dp.isAnonymousObject) {
useClassInstance(dp, classTypeArguments, inReceiverContext).typeResult.id
} else {
// `inReceiverContext == false` is used unless we have identified that we're dealing with a raw type
// produced by the Parcelize plugin. In that case we're using the original `inReceiverContext`. Note
// that the type in this case is being replaced later in `addClassLabel` to a non-raw type.
useClassSource(dp, inReceiverContext && tryReplaceParcelizeRawType(dp) != null)
}
is IrFunction -> useFunction(dp) is IrFunction -> useFunction(dp)
is IrExternalPackageFragment -> { is IrExternalPackageFragment -> {
// TODO // TODO
@@ -1281,13 +1322,13 @@ open class KotlinUsesExtractor(
unquotedLabel.shortName) unquotedLabel.shortName)
} }
fun useClassSource(c: IrClass): Label<out DbClassorinterface> { fun useClassSource(c: IrClass, inReceiverContext: Boolean = false): Label<out DbClassorinterface> {
if (c.isAnonymousObject) { if (c.isAnonymousObject) {
return useAnonymousClass(c).javaResult.id.cast<DbClass>() return useAnonymousClass(c).javaResult.id.cast<DbClass>()
} }
// For source classes, the label doesn't include and type arguments // For source classes, the label doesn't include and type arguments
val classTypeResult = addClassLabel(c, listOf()) val classTypeResult = addClassLabel(c, listOf(), inReceiverContext)
return classTypeResult.id return classTypeResult.id
} }