[Parcelize] Align checker and generator on valid Parcelize classes
A previous fix to the generator made the generator and checker validation of classes which could be parcelized different. The checker would report error in cases where the generator would not generate anything. Align these checks, with improved code sharing, so errors are not reported on classes which will not have parcelize components generated. ^KT-63086 Fixed
This commit is contained in:
+3
-12
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.parcelize.ParcelizeNames.OLD_PARCELIZE_FQN
|
||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELIZE_FQN
|
||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCEL_ID
|
||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.WRITE_TO_PARCEL_NAME
|
||||
import org.jetbrains.kotlin.parcelize.fir.diagnostics.checkParcelizeClassSymbols
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||
|
||||
class FirParcelizeDeclarationGenerator(session: FirSession) : FirDeclarationGenerationExtension(session) {
|
||||
@@ -106,18 +107,8 @@ class FirParcelizeDeclarationGenerator(session: FirSession) : FirDeclarationGene
|
||||
override fun getCallableNamesForClass(classSymbol: FirClassSymbol<*>, context: MemberGenerationContext): Set<Name> {
|
||||
return when {
|
||||
classSymbol.rawStatus.modality == Modality.ABSTRACT || classSymbol.rawStatus.modality == Modality.SEALED -> emptySet()
|
||||
classSymbol in matchedClasses && classSymbol.rawStatus.modality != Modality.SEALED -> parcelizeMethodsNames
|
||||
else -> {
|
||||
val hasAnnotatedSealedSuperType = classSymbol.resolvedSuperTypeRefs.any {
|
||||
val superSymbol = it.type.fullyExpandedType(session).toRegularClassSymbol(session) ?: return@any false
|
||||
superSymbol.rawStatus.modality == Modality.SEALED && superSymbol in matchedClasses
|
||||
}
|
||||
if (hasAnnotatedSealedSuperType) {
|
||||
parcelizeMethodsNames
|
||||
} else {
|
||||
emptySet()
|
||||
}
|
||||
}
|
||||
checkParcelizeClassSymbols(classSymbol, session) { it in matchedClasses } -> parcelizeMethodsNames
|
||||
else -> emptySet()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+21
-4
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.parcelize.fir.diagnostics
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.diagnostics.SourceElementPositioningStrategies
|
||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||
@@ -14,7 +15,6 @@ import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirClassChecker
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.*
|
||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
@@ -116,13 +116,30 @@ fun FirClassSymbol<*>?.isParcelize(session: FirSession): Boolean {
|
||||
}
|
||||
|
||||
if (this == null) return false
|
||||
if (this.annotations.any { it.toAnnotationClassId(session) in PARCELIZE_CLASS_CLASS_IDS }) return true
|
||||
return resolvedSuperTypeRefs.any { superTypeRef ->
|
||||
val symbol = superTypeRef.type.fullyExpandedType(session).toRegularClassSymbol(session) ?: return@any false
|
||||
return checkParcelizeClassSymbols(this, session) { symbol ->
|
||||
symbol.annotations.any { it.toAnnotationClassId(session) in PARCELIZE_CLASS_CLASS_IDS }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check all related [FirClassSymbol]s to the provided [symbol] which are valid locations for a
|
||||
* `Parcelize` annotation to be present. This commonizes class symbol navigation between checker and
|
||||
* generator, even though [predicate] implementation is different.
|
||||
*/
|
||||
inline fun checkParcelizeClassSymbols(
|
||||
symbol: FirClassSymbol<*>,
|
||||
session: FirSession,
|
||||
predicate: (FirClassSymbol<*>) -> Boolean,
|
||||
): Boolean {
|
||||
if (predicate(symbol)) return true
|
||||
return symbol.resolvedSuperTypeRefs.any { superTypeRef ->
|
||||
val superTypeSymbol = superTypeRef.type.toRegularClassSymbol(session)
|
||||
?.takeIf { it.rawStatus.modality == Modality.SEALED }
|
||||
?: return@any false
|
||||
predicate(superTypeSymbol)
|
||||
}
|
||||
}
|
||||
|
||||
fun FirRegularClass.hasCustomParceler(session: FirSession): Boolean {
|
||||
val companion = companionObjectSymbol ?: return false
|
||||
return lookupSuperTypes(companion, lookupInterfaces = true, deep = true, useSiteSession = session).any {
|
||||
|
||||
@@ -6,6 +6,8 @@ import android.os.Parcelable
|
||||
@Parcelize
|
||||
open class Open(val foo: String) : Parcelable
|
||||
|
||||
data class Derived(val bar: String) : Open(bar)
|
||||
|
||||
@Parcelize
|
||||
class Final(val foo: String) : Parcelable
|
||||
|
||||
@@ -29,6 +31,8 @@ fun foo() {
|
||||
@Parcelize
|
||||
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED, PARCELABLE_SHOULD_BE_CLASS!>object<!> : Parcelable {}
|
||||
|
||||
object : Open("") {}
|
||||
|
||||
@Parcelize
|
||||
class <!NO_PARCELABLE_SUPERTYPE, PARCELABLE_CANT_BE_LOCAL_CLASS!>Local<!> {}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ import android.os.Parcelable
|
||||
@Parcelize
|
||||
open class Open(val foo: String) : Parcelable
|
||||
|
||||
data class Derived(val bar: String) : Open(bar)
|
||||
|
||||
@Parcelize
|
||||
class Final(val foo: String) : Parcelable
|
||||
|
||||
@@ -29,6 +31,8 @@ fun foo() {
|
||||
@Parcelize
|
||||
<!PARCELABLE_CANT_BE_LOCAL_CLASS!>object<!> : Parcelable {}
|
||||
|
||||
object : Open("") {}
|
||||
|
||||
@Parcelize
|
||||
class <!NO_PARCELABLE_SUPERTYPE, PARCELABLE_CANT_BE_LOCAL_CLASS!>Local<!> {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user