Skip to content

Commit ba5cf5b

Browse files
committed
Kotlin: Fix fake raw type symbols used by the Parcelize plugin
1 parent 0a861ff commit ba5cf5b

File tree

1 file changed

+55
-14
lines changed

1 file changed

+55
-14
lines changed

java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt

Lines changed: 55 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -419,31 +419,35 @@ open class KotlinUsesExtractor(
419419

420420
// `typeArgs` can be null to describe a raw generic type.
421421
// For non-generic types it will be zero-length list.
422-
fun addClassLabel(cBeforeReplacement: IrClass, argsIncludingOuterClasses: List<IrTypeArgument>?, inReceiverContext: Boolean = false): TypeResult<DbClassorinterface> {
422+
private fun addClassLabel(cBeforeReplacement: IrClass, argsIncludingOuterClasses: List<IrTypeArgument>?, inReceiverContext: Boolean = false): TypeResult<DbClassorinterface> {
423423
val c = tryReplaceAndroidSyntheticClass(cBeforeReplacement)
424-
val classLabelResult = getClassLabel(c, argsIncludingOuterClasses)
424+
val p = tryReplaceParcelizeRawType(c)
425+
val replacedClass = p?.first ?: c
426+
val replacedArgsIncludingOuterClasses = p?.second ?: argsIncludingOuterClasses
427+
428+
val classLabelResult = getClassLabel(replacedClass, replacedArgsIncludingOuterClasses)
425429

426430
var instanceSeenBefore = true
427431

428-
val classLabel : Label<out DbClassorinterface> = tw.getLabelFor(classLabelResult.classLabel, {
432+
val classLabel : Label<out DbClassorinterface> = tw.getLabelFor(classLabelResult.classLabel) {
429433
instanceSeenBefore = false
430434

431-
extractClassLaterIfExternal(c)
432-
})
435+
extractClassLaterIfExternal(replacedClass)
436+
}
433437

434-
if (argsIncludingOuterClasses == null || argsIncludingOuterClasses.isNotEmpty()) {
438+
if (replacedArgsIncludingOuterClasses == null || replacedArgsIncludingOuterClasses.isNotEmpty()) {
435439
// If this is a generic type instantiation or a raw type then it has no
436440
// source entity, so we need to extract it here
437-
val extractorWithCSource by lazy { this.withFileOfClass(c) }
441+
val extractorWithCSource by lazy { this.withFileOfClass(replacedClass) }
438442

439443
if (!instanceSeenBefore) {
440-
extractorWithCSource.extractClassInstance(c, argsIncludingOuterClasses)
444+
extractorWithCSource.extractClassInstance(replacedClass, replacedArgsIncludingOuterClasses)
441445
}
442446

443447
if (inReceiverContext && tw.lm.genericSpecialisationsExtracted.add(classLabelResult.classLabel)) {
444-
val supertypeMode = if (argsIncludingOuterClasses == null) ExtractSupertypesMode.Raw else ExtractSupertypesMode.Specialised(argsIncludingOuterClasses)
445-
extractorWithCSource.extractClassSupertypes(c, classLabel, supertypeMode, true)
446-
extractorWithCSource.extractNonPrivateMemberPrototypes(c, argsIncludingOuterClasses, classLabel)
448+
val supertypeMode = if (replacedArgsIncludingOuterClasses == null) ExtractSupertypesMode.Raw else ExtractSupertypesMode.Specialised(replacedArgsIncludingOuterClasses)
449+
extractorWithCSource.extractClassSupertypes(replacedClass, classLabel, supertypeMode, true)
450+
extractorWithCSource.extractNonPrivateMemberPrototypes(replacedClass, replacedArgsIncludingOuterClasses, classLabel)
447451
}
448452
}
449453

@@ -453,6 +457,35 @@ open class KotlinUsesExtractor(
453457
classLabelResult.shortName)
454458
}
455459

460+
private fun tryReplaceParcelizeRawType(c: IrClass): Pair<IrClass, List<IrTypeArgument>?>? {
461+
if (c.superTypes.isNotEmpty() ||
462+
c.origin != IrDeclarationOrigin.DEFINED ||
463+
c.hasEqualFqName(FqName("java.lang.Object"))) {
464+
return null
465+
}
466+
467+
fun tryGetPair(arity: Int): Pair<IrClass, List<IrTypeArgument>?>? {
468+
val replaced = pluginContext.referenceClass(c.fqNameWhenAvailable!!)?.owner ?: return null
469+
return Pair(replaced, List(arity) { makeTypeProjection(pluginContext.irBuiltIns.anyNType, Variance.INVARIANT) })
470+
}
471+
472+
// 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
473+
// Specifically, types are added for generic types created in AndroidSymbols.kt.
474+
// This replacement is from a raw type to its matching parameterized type with `Object` type arguments.
475+
return when (c.fqNameWhenAvailable?.asString()) {
476+
"java.util.ArrayList" -> tryGetPair(1)
477+
"java.util.LinkedHashMap" -> tryGetPair(2)
478+
"java.util.LinkedHashSet" -> tryGetPair(1)
479+
"java.util.List" -> tryGetPair(1)
480+
"java.util.TreeMap" -> tryGetPair(2)
481+
"java.util.TreeSet" -> tryGetPair(1)
482+
483+
"java.lang.Class" -> tryGetPair(1)
484+
485+
else -> null
486+
}
487+
}
488+
456489
fun useAnonymousClass(c: IrClass) =
457490
tw.lm.anonymousTypeMapping.getOrPut(c) {
458491
TypeResults(
@@ -721,7 +754,15 @@ open class KotlinUsesExtractor(
721754
} else {
722755
extractFileClass(dp)
723756
}
724-
is IrClass -> if (classTypeArguments != null && !dp.isAnonymousObject) useClassInstance(dp, classTypeArguments, inReceiverContext).typeResult.id else useClassSource(dp)
757+
is IrClass ->
758+
if (classTypeArguments != null && !dp.isAnonymousObject) {
759+
useClassInstance(dp, classTypeArguments, inReceiverContext).typeResult.id
760+
} else {
761+
// `inReceiverContext == false` is used unless we have identified that we're dealing with a raw type
762+
// produced by the Parcelize plugin. In that case we're using the original `inReceiverContext`. Note
763+
// that the type in this case is being replaced later in `addClassLabel` to a non-raw type.
764+
useClassSource(dp, inReceiverContext && tryReplaceParcelizeRawType(dp) != null)
765+
}
725766
is IrFunction -> useFunction(dp)
726767
is IrExternalPackageFragment -> {
727768
// TODO
@@ -1281,13 +1322,13 @@ open class KotlinUsesExtractor(
12811322
unquotedLabel.shortName)
12821323
}
12831324

1284-
fun useClassSource(c: IrClass): Label<out DbClassorinterface> {
1325+
fun useClassSource(c: IrClass, inReceiverContext: Boolean = false): Label<out DbClassorinterface> {
12851326
if (c.isAnonymousObject) {
12861327
return useAnonymousClass(c).javaResult.id.cast<DbClass>()
12871328
}
12881329

12891330
// For source classes, the label doesn't include and type arguments
1290-
val classTypeResult = addClassLabel(c, listOf())
1331+
val classTypeResult = addClassLabel(c, listOf(), inReceiverContext)
12911332
return classTypeResult.id
12921333
}
12931334

0 commit comments

Comments
 (0)