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
|
if (containingClass.isParcelize
|
||||||
&& (declaration.hasDelegate() || bindingContext[BindingContext.BACKING_FIELD_REQUIRED, property] == true)
|
&& (declaration.hasDelegate() || bindingContext[BindingContext.BACKING_FIELD_REQUIRED, property] == true)
|
||||||
&& !hasIgnoredOnParcel()
|
&& !hasIgnoredOnParcel()
|
||||||
|
&& !containingClass.hasCustomParceler()
|
||||||
) {
|
) {
|
||||||
val reportElement = declaration.nameIdentifier ?: declaration
|
val reportElement = declaration.nameIdentifier ?: declaration
|
||||||
diagnosticHolder.report(ErrorsParcelize.PROPERTY_WONT_BE_SERIALIZED.on(reportElement))
|
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
|
val primaryConstructor = declaration.primaryConstructor
|
||||||
if (primaryConstructor == null && declaration.secondaryConstructors.isNotEmpty()) {
|
if (primaryConstructor == null && declaration.secondaryConstructors.isNotEmpty()) {
|
||||||
val reportElement = declaration.nameIdentifier ?: declaration
|
val reportElement = declaration.nameIdentifier ?: declaration
|
||||||
@@ -234,7 +240,7 @@ open class ParcelizeDeclarationChecker : DeclarationChecker {
|
|||||||
|
|
||||||
val type = descriptor.type
|
val type = descriptor.type
|
||||||
|
|
||||||
if (!type.isError && !containerClass.hasCustomParceler()) {
|
if (!type.isError) {
|
||||||
val asmType = typeMapper.mapType(type, mode = TypeMappingMode.CLASS_DECLARATION)
|
val asmType = typeMapper.mapType(type, mode = TypeMappingMode.CLASS_DECLARATION)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
+1
@@ -32,6 +32,7 @@ object ParcelizeNames {
|
|||||||
val TYPE_PARCELER_CLASS_IDS = createClassIds("TypeParceler")
|
val TYPE_PARCELER_CLASS_IDS = createClassIds("TypeParceler")
|
||||||
val WRITE_WITH_CLASS_IDS = createClassIds("WriteWith")
|
val WRITE_WITH_CLASS_IDS = createClassIds("WriteWith")
|
||||||
val IGNORED_ON_PARCEL_CLASS_IDS = createClassIds("IgnoredOnParcel")
|
val IGNORED_ON_PARCEL_CLASS_IDS = createClassIds("IgnoredOnParcel")
|
||||||
|
val PARCELER_CLASS_IDS = createClassIds("Parceler")
|
||||||
val PARCELIZE_CLASS_CLASS_IDS = createClassIds("Parcelize")
|
val PARCELIZE_CLASS_CLASS_IDS = createClassIds("Parcelize")
|
||||||
val RAW_VALUE_ANNOTATION_CLASS_IDS = createClassIds("RawValue")
|
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.CREATOR_NAME
|
||||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.OLD_PARCELER_ID
|
import org.jetbrains.kotlin.parcelize.ParcelizeNames.OLD_PARCELER_ID
|
||||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELABLE_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 org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELIZE_CLASS_CLASS_IDS
|
||||||
import kotlin.contracts.ExperimentalContracts
|
import kotlin.contracts.ExperimentalContracts
|
||||||
import kotlin.contracts.contract
|
import kotlin.contracts.contract
|
||||||
@@ -131,3 +132,10 @@ fun FirClassSymbol<*>?.isParcelize(session: FirSession): Boolean {
|
|||||||
symbol.annotations.any { it.classId in PARCELIZE_CLASS_CLASS_IDS }
|
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
|
if (source.kind == KtFakeSourceElementKind.ImplicitConstructor) return
|
||||||
val containingClass = context.containingDeclarations.last() as? FirRegularClass ?: return
|
val containingClass = context.containingDeclarations.last() as? FirRegularClass ?: return
|
||||||
val containingClassSymbol = containingClass.symbol
|
val containingClassSymbol = containingClass.symbol
|
||||||
if (!containingClassSymbol.isParcelize(context.session)) return
|
if (!containingClassSymbol.isParcelize(context.session) || containingClass.hasCustomParceler(context.session)) return
|
||||||
|
|
||||||
if (declaration.valueParameters.isEmpty()) {
|
if (declaration.valueParameters.isEmpty()) {
|
||||||
reporter.reportOn(containingClass.source, KtErrorsParcelize.PARCELABLE_PRIMARY_CONSTRUCTOR_IS_EMPTY, context)
|
reporter.reportOn(containingClass.source, KtErrorsParcelize.PARCELABLE_PRIMARY_CONSTRUCTOR_IS_EMPTY, context)
|
||||||
|
|||||||
+2
-1
@@ -38,7 +38,8 @@ object FirParcelizePropertyChecker : FirPropertyChecker() {
|
|||||||
if (
|
if (
|
||||||
!fromPrimaryConstructor &&
|
!fromPrimaryConstructor &&
|
||||||
(declaration.hasBackingField || declaration.delegate != null) &&
|
(declaration.hasBackingField || declaration.delegate != null) &&
|
||||||
!declaration.hasIgnoredOnParcel()
|
!declaration.hasIgnoredOnParcel() &&
|
||||||
|
!containingClassSymbol.hasCustomParceler(context.session)
|
||||||
) {
|
) {
|
||||||
reporter.reportOn(declaration.source, KtErrorsParcelize.PROPERTY_WONT_BE_SERIALIZED, context)
|
reporter.reportOn(declaration.source, KtErrorsParcelize.PROPERTY_WONT_BE_SERIALIZED, context)
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -184,8 +184,8 @@ abstract class ParcelizeIrTransformerBase(
|
|||||||
val topLevelScope = getParcelerScope()
|
val topLevelScope = getParcelerScope()
|
||||||
|
|
||||||
return constructor.valueParameters.map { parameter ->
|
return constructor.valueParameters.map { parameter ->
|
||||||
val property = properties.first { it.name == parameter.name }
|
val property = properties.firstOrNull { it.name == parameter.name }
|
||||||
if (property.hasAnyAnnotation(IGNORED_ON_PARCEL_FQ_NAMES)) {
|
if (property == null || property.hasAnyAnnotation(IGNORED_ON_PARCEL_FQ_NAMES)) {
|
||||||
null
|
null
|
||||||
} else {
|
} else {
|
||||||
val localScope = property.getParcelerScope(topLevelScope)
|
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");
|
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
|
@Test
|
||||||
@TestMetadata("customNewArray.kt")
|
@TestMetadata("customNewArray.kt")
|
||||||
public void testCustomNewArray() throws Exception {
|
public void testCustomNewArray() throws Exception {
|
||||||
@@ -85,6 +91,12 @@ public class ParcelizeBoxTestGenerated extends AbstractParcelizeBoxTest {
|
|||||||
runTest("plugins/parcelize/parcelize-compiler/testData/box/customParcelable.kt");
|
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
|
@Test
|
||||||
@TestMetadata("customParcelerScoping.kt")
|
@TestMetadata("customParcelerScoping.kt")
|
||||||
public void testCustomParcelerScoping() throws Exception {
|
public void testCustomParcelerScoping() throws Exception {
|
||||||
|
|||||||
+12
@@ -73,6 +73,12 @@ public class ParcelizeFirBoxTestGenerated extends AbstractParcelizeFirBoxTest {
|
|||||||
runTest("plugins/parcelize/parcelize-compiler/testData/box/charSequence.kt");
|
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
|
@Test
|
||||||
@TestMetadata("customNewArray.kt")
|
@TestMetadata("customNewArray.kt")
|
||||||
public void testCustomNewArray() throws Exception {
|
public void testCustomNewArray() throws Exception {
|
||||||
@@ -85,6 +91,12 @@ public class ParcelizeFirBoxTestGenerated extends AbstractParcelizeFirBoxTest {
|
|||||||
runTest("plugins/parcelize/parcelize-compiler/testData/box/customParcelable.kt");
|
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
|
@Test
|
||||||
@TestMetadata("customParcelerScoping.kt")
|
@TestMetadata("customParcelerScoping.kt")
|
||||||
public void testCustomParcelerScoping() throws Exception {
|
public void testCustomParcelerScoping() throws Exception {
|
||||||
|
|||||||
+12
@@ -73,6 +73,12 @@ public class ParcelizeIrBoxTestGenerated extends AbstractParcelizeIrBoxTest {
|
|||||||
runTest("plugins/parcelize/parcelize-compiler/testData/box/charSequence.kt");
|
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
|
@Test
|
||||||
@TestMetadata("customNewArray.kt")
|
@TestMetadata("customNewArray.kt")
|
||||||
public void testCustomNewArray() throws Exception {
|
public void testCustomNewArray() throws Exception {
|
||||||
@@ -85,6 +91,12 @@ public class ParcelizeIrBoxTestGenerated extends AbstractParcelizeIrBoxTest {
|
|||||||
runTest("plugins/parcelize/parcelize-compiler/testData/box/customParcelable.kt");
|
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
|
@Test
|
||||||
@TestMetadata("customParcelerScoping.kt")
|
@TestMetadata("customParcelerScoping.kt")
|
||||||
public void testCustomParcelerScoping() throws Exception {
|
public void testCustomParcelerScoping() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user