Parcelize: Skip constructor checks when used with custom Parceler
See https://issuetracker.google.com/177850558
This commit is contained in:
committed by
Alexander Udalov
parent
58c687e42d
commit
16a2aec296
+7
-1
@@ -99,6 +99,7 @@ open class ParcelizeDeclarationChecker : DeclarationChecker {
|
||||
if (containingClass.isParcelize
|
||||
&& (declaration.hasDelegate() || bindingContext[BindingContext.BACKING_FIELD_REQUIRED, property] == true)
|
||||
&& !hasIgnoredOnParcel()
|
||||
&& !containingClass.hasCustomParceler()
|
||||
) {
|
||||
val reportElement = declaration.nameIdentifier ?: declaration
|
||||
diagnosticHolder.report(ErrorsParcelize.PROPERTY_WONT_BE_SERIALIZED.on(reportElement))
|
||||
@@ -192,6 +193,11 @@ open class ParcelizeDeclarationChecker : DeclarationChecker {
|
||||
}
|
||||
}
|
||||
|
||||
// The constructor checks are irrelevant for custom parcelers
|
||||
if (descriptor.hasCustomParceler()) {
|
||||
return
|
||||
}
|
||||
|
||||
val primaryConstructor = declaration.primaryConstructor
|
||||
if (primaryConstructor == null && declaration.secondaryConstructors.isNotEmpty()) {
|
||||
val reportElement = declaration.nameIdentifier ?: declaration
|
||||
@@ -234,7 +240,7 @@ open class ParcelizeDeclarationChecker : DeclarationChecker {
|
||||
|
||||
val type = descriptor.type
|
||||
|
||||
if (!type.isError && !containerClass.hasCustomParceler()) {
|
||||
if (!type.isError) {
|
||||
val asmType = typeMapper.mapType(type, mode = TypeMappingMode.CLASS_DECLARATION)
|
||||
|
||||
try {
|
||||
|
||||
+1
@@ -32,6 +32,7 @@ object ParcelizeNames {
|
||||
val TYPE_PARCELER_CLASS_IDS = createClassIds("TypeParceler")
|
||||
val WRITE_WITH_CLASS_IDS = createClassIds("WriteWith")
|
||||
val IGNORED_ON_PARCEL_CLASS_IDS = createClassIds("IgnoredOnParcel")
|
||||
val PARCELER_CLASS_IDS = createClassIds("Parceler")
|
||||
val PARCELIZE_CLASS_CLASS_IDS = createClassIds("Parcelize")
|
||||
val RAW_VALUE_ANNOTATION_CLASS_IDS = createClassIds("RawValue")
|
||||
|
||||
|
||||
+8
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.name.SpecialNames
|
||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.CREATOR_NAME
|
||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.OLD_PARCELER_ID
|
||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELABLE_ID
|
||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELER_CLASS_IDS
|
||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELIZE_CLASS_CLASS_IDS
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.contracts.contract
|
||||
@@ -131,3 +132,10 @@ fun FirClassSymbol<*>?.isParcelize(session: FirSession): Boolean {
|
||||
symbol.annotations.any { it.classId in PARCELIZE_CLASS_CLASS_IDS }
|
||||
}
|
||||
}
|
||||
|
||||
fun FirRegularClass.hasCustomParceler(session: FirSession): Boolean {
|
||||
val companion = companionObjectSymbol ?: return false
|
||||
return lookupSuperTypes(companion, lookupInterfaces = true, deep = true, useSiteSession = session).any {
|
||||
it.classId in PARCELER_CLASS_IDS
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ object FirParcelizeConstructorChecker : FirConstructorChecker() {
|
||||
if (source.kind == KtFakeSourceElementKind.ImplicitConstructor) return
|
||||
val containingClass = context.containingDeclarations.last() as? FirRegularClass ?: return
|
||||
val containingClassSymbol = containingClass.symbol
|
||||
if (!containingClassSymbol.isParcelize(context.session)) return
|
||||
if (!containingClassSymbol.isParcelize(context.session) || containingClass.hasCustomParceler(context.session)) return
|
||||
|
||||
if (declaration.valueParameters.isEmpty()) {
|
||||
reporter.reportOn(containingClass.source, KtErrorsParcelize.PARCELABLE_PRIMARY_CONSTRUCTOR_IS_EMPTY, context)
|
||||
|
||||
+2
-1
@@ -38,7 +38,8 @@ object FirParcelizePropertyChecker : FirPropertyChecker() {
|
||||
if (
|
||||
!fromPrimaryConstructor &&
|
||||
(declaration.hasBackingField || declaration.delegate != null) &&
|
||||
!declaration.hasIgnoredOnParcel()
|
||||
!declaration.hasIgnoredOnParcel() &&
|
||||
!containingClassSymbol.hasCustomParceler(context.session)
|
||||
) {
|
||||
reporter.reportOn(declaration.source, KtErrorsParcelize.PROPERTY_WONT_BE_SERIALIZED, context)
|
||||
}
|
||||
|
||||
+2
-2
@@ -184,8 +184,8 @@ abstract class ParcelizeIrTransformerBase(
|
||||
val topLevelScope = getParcelerScope()
|
||||
|
||||
return constructor.valueParameters.map { parameter ->
|
||||
val property = properties.first { it.name == parameter.name }
|
||||
if (property.hasAnyAnnotation(IGNORED_ON_PARCEL_FQ_NAMES)) {
|
||||
val property = properties.firstOrNull { it.name == parameter.name }
|
||||
if (property == null || property.hasAnyAnnotation(IGNORED_ON_PARCEL_FQ_NAMES)) {
|
||||
null
|
||||
} else {
|
||||
val localScope = property.getParcelerScope(topLevelScope)
|
||||
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
// WITH_STDLIB
|
||||
|
||||
@file:JvmName("TestKt")
|
||||
package test
|
||||
|
||||
import kotlinx.parcelize.*
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
|
||||
@Parcelize
|
||||
class A(_a: String) : Parcelable {
|
||||
var a: String = _a
|
||||
private set
|
||||
|
||||
companion object : Parceler<A> {
|
||||
override fun A.write(parcel: Parcel, flags: Int) {
|
||||
parcel.writeString(a)
|
||||
}
|
||||
|
||||
override fun create(parcel: Parcel) = A(parcel.readString())
|
||||
}
|
||||
}
|
||||
|
||||
fun box() = parcelTest { parcel ->
|
||||
val test = A("OK")
|
||||
test.writeToParcel(parcel, 0)
|
||||
|
||||
val bytes = parcel.marshall()
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val test2 = parcelableCreator<A>().createFromParcel(parcel)
|
||||
|
||||
assert(test.a == test2.a)
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
// WITH_STDLIB
|
||||
|
||||
@file:JvmName("TestKt")
|
||||
package test
|
||||
|
||||
import kotlinx.parcelize.*
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
|
||||
class T(val value: String)
|
||||
|
||||
// There's no warnings on empty constructors, secondary constructors, or
|
||||
// non-parcelable types if there is a custom parceler.
|
||||
@Parcelize
|
||||
class A() : Parcelable {
|
||||
var a: T = T("Fail")
|
||||
|
||||
constructor(value: String) : this() {
|
||||
a = T(value)
|
||||
}
|
||||
|
||||
companion object : Parceler<A> {
|
||||
override fun A.write(parcel: Parcel, flags: Int) {
|
||||
parcel.writeString(a.value)
|
||||
}
|
||||
|
||||
override fun create(parcel: Parcel) = A(parcel.readString())
|
||||
}
|
||||
}
|
||||
|
||||
fun box() = parcelTest { parcel ->
|
||||
val test = A("OK")
|
||||
test.writeToParcel(parcel, 0)
|
||||
|
||||
val bytes = parcel.marshall()
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val test2 = parcelableCreator<A>().createFromParcel(parcel)
|
||||
|
||||
assert(test.a.value == test2.a.value)
|
||||
}
|
||||
+12
@@ -73,6 +73,12 @@ public class ParcelizeBoxTestGenerated extends AbstractParcelizeBoxTest {
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/box/charSequence.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("constructorWithoutValOrVar.kt")
|
||||
public void testConstructorWithoutValOrVar() throws Exception {
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/box/constructorWithoutValOrVar.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("customNewArray.kt")
|
||||
public void testCustomNewArray() throws Exception {
|
||||
@@ -85,6 +91,12 @@ public class ParcelizeBoxTestGenerated extends AbstractParcelizeBoxTest {
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/box/customParcelable.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("customParcelerChecks.kt")
|
||||
public void testCustomParcelerChecks() throws Exception {
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/box/customParcelerChecks.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("customParcelerScoping.kt")
|
||||
public void testCustomParcelerScoping() throws Exception {
|
||||
|
||||
+12
@@ -73,6 +73,12 @@ public class ParcelizeFirBoxTestGenerated extends AbstractParcelizeFirBoxTest {
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/box/charSequence.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("constructorWithoutValOrVar.kt")
|
||||
public void testConstructorWithoutValOrVar() throws Exception {
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/box/constructorWithoutValOrVar.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("customNewArray.kt")
|
||||
public void testCustomNewArray() throws Exception {
|
||||
@@ -85,6 +91,12 @@ public class ParcelizeFirBoxTestGenerated extends AbstractParcelizeFirBoxTest {
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/box/customParcelable.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("customParcelerChecks.kt")
|
||||
public void testCustomParcelerChecks() throws Exception {
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/box/customParcelerChecks.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("customParcelerScoping.kt")
|
||||
public void testCustomParcelerScoping() throws Exception {
|
||||
|
||||
+12
@@ -73,6 +73,12 @@ public class ParcelizeIrBoxTestGenerated extends AbstractParcelizeIrBoxTest {
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/box/charSequence.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("constructorWithoutValOrVar.kt")
|
||||
public void testConstructorWithoutValOrVar() throws Exception {
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/box/constructorWithoutValOrVar.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("customNewArray.kt")
|
||||
public void testCustomNewArray() throws Exception {
|
||||
@@ -85,6 +91,12 @@ public class ParcelizeIrBoxTestGenerated extends AbstractParcelizeIrBoxTest {
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/box/customParcelable.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("customParcelerChecks.kt")
|
||||
public void testCustomParcelerChecks() throws Exception {
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/box/customParcelerChecks.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("customParcelerScoping.kt")
|
||||
public void testCustomParcelerScoping() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user