Parcelize: Use @Parcelize annotations from Android Extensions instead of the copied&deprecated ones (KT-42342, KT-43150)

Dex can't merge class files from both android-extensions-runtime and parcelize-runtime, so we have to keep only one copy of each class.
Instead of @Deprecated annotations, there are new diagnostics (without quick-fixes yet).
The goal is to allow simple usages (@Parcelize alone) but forbid kotlinx.android.synthetic.Parceler usage.
This commit is contained in:
Yan Zhulanow
2020-11-07 02:01:10 +09:00
parent fa42a6ba58
commit e83a3c3f27
36 changed files with 182 additions and 629 deletions
@@ -36,6 +36,8 @@ object PathUtil {
const val SAM_WITH_RECEIVER_PLUGIN_JAR_NAME = "$SAM_WITH_RECEIVER_PLUGIN_NAME.jar"
const val SERIALIZATION_PLUGIN_NAME = "kotlinx-serialization-compiler-plugin"
const val SERIALIZATION_PLUGIN_JAR_NAME = "$SERIALIZATION_PLUGIN_NAME.jar"
const val ANDROID_EXTENSIONS_RUNTIME_PLUGIN_JAR_NAME = "android-extensions-runtime.jar"
const val PARCELIZE_RUNTIME_PLUGIN_JAR_NAME = "parcelize-runtime.jar"
const val JS_LIB_SRC_JAR_NAME = "kotlin-stdlib-js-sources.jar"
const val KOTLIN_JAVA_RUNTIME_JRE7_NAME = "kotlin-stdlib-jre7"
@@ -26,4 +26,5 @@ android {
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
compile "org.jetbrains.kotlin:kotlin-android-extensions-runtime:$kotlin_version"
}
@@ -20,6 +20,7 @@ dependencies {
compileOnly(project(":compiler:backend.jvm"))
compileOnly(project(":compiler:ir.tree.impl"))
compileOnly(project(":plugins:parcelize:parcelize-runtime"))
compileOnly(project(":kotlin-android-extensions-runtime"))
compileOnly(intellijCoreDep()) { includeJars("intellij-core") }
compileOnly(intellijDep()) { includeJars("asm-all", rootProject = rootProject) }
@@ -29,6 +30,7 @@ dependencies {
testCompile(project(":compiler:backend.jvm"))
testCompile(project(":compiler:cli"))
testCompile(project(":plugins:parcelize:parcelize-runtime"))
testCompile(project(":kotlin-android-extensions-runtime"))
testCompile(projectTests(":compiler:tests-common"))
testCompile(project(":kotlin-test:kotlin-test-jvm"))
testCompile(commonDep("junit:junit"))
@@ -38,10 +40,13 @@ dependencies {
robolectricClasspath(commonDep("org.robolectric", "robolectric"))
robolectricClasspath("org.robolectric:android-all:4.4_r1-robolectric-1")
robolectricClasspath(project(":plugins:parcelize:parcelize-runtime")) { isTransitive = false }
robolectricClasspath(project(":kotlin-android-extensions-runtime")) { isTransitive = false }
embedded(project(":plugins:parcelize:parcelize-runtime")) { isTransitive = false }
embedded(project(":kotlin-android-extensions-runtime")) { isTransitive = false }
parcelizeRuntimeForTests(project(":plugins:parcelize:parcelize-runtime")) { isTransitive = false }
parcelizeRuntimeForTests(project(":kotlin-android-extensions-runtime")) { isTransitive = false }
}
sourceSets {
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.parcelize
import com.intellij.psi.PsiElement
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.backend.common.serialization.findPackage
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
@@ -39,20 +40,7 @@ import org.jetbrains.kotlin.types.typeUtil.supertypes
class ParcelizeAnnotationChecker : CallChecker {
@Suppress("DEPRECATION")
companion object {
val TYPE_PARCELER_FQ_NAMES = listOf(
FqName(kotlinx.parcelize.TypeParceler::class.java.name),
FqName(kotlinx.android.parcel.TypeParceler::class.java.name)
)
val WRITE_WITH_FQ_NAMES = listOf(
FqName(kotlinx.parcelize.WriteWith::class.java.name),
FqName(kotlinx.android.parcel.WriteWith::class.java.name)
)
val IGNORED_ON_PARCEL_FQ_NAMES = listOf(
FqName(kotlinx.parcelize.IgnoredOnParcel::class.java.name),
FqName(kotlinx.android.parcel.IgnoredOnParcel::class.java.name)
)
val DEPRECATED_RUNTIME_PACKAGE = FqName("kotlinx.android.parcel")
}
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
@@ -64,14 +52,34 @@ class ParcelizeAnnotationChecker : CallChecker {
if (annotationClass.fqNameSafe in TYPE_PARCELER_FQ_NAMES) {
checkTypeParcelerUsage(resolvedCall, annotationEntry, context, annotationOwner)
checkDeprecatedAnnotations(resolvedCall, annotationEntry, context, isForbidden = true)
}
if (annotationClass.fqNameSafe in WRITE_WITH_FQ_NAMES) {
checkWriteWithUsage(resolvedCall, annotationEntry, context, annotationOwner)
checkDeprecatedAnnotations(resolvedCall, annotationEntry, context, isForbidden = true)
}
if (annotationClass.fqNameSafe in IGNORED_ON_PARCEL_FQ_NAMES) {
checkIgnoredOnParcelUsage(annotationEntry, context, annotationOwner)
checkDeprecatedAnnotations(resolvedCall, annotationEntry, context, isForbidden = false)
}
if (annotationClass.fqNameSafe in PARCELIZE_CLASS_FQ_NAMES || annotationClass.fqNameSafe in RAW_VALUE_ANNOTATION_FQ_NAMES) {
checkDeprecatedAnnotations(resolvedCall, annotationEntry, context, isForbidden = false)
}
}
private fun checkDeprecatedAnnotations(
resolvedCall: ResolvedCall<*>,
annotationEntry: KtAnnotationEntry,
context: CallCheckerContext,
isForbidden: Boolean
) {
val descriptorPackage = resolvedCall.resultingDescriptor.findPackage()
if (descriptorPackage.fqName == DEPRECATED_RUNTIME_PACKAGE) {
val factory = if (isForbidden) ErrorsParcelize.FORBIDDEN_DEPRECATED_ANNOTATION else ErrorsParcelize.DEPRECATED_ANNOTATION
context.trace.report(factory.on(annotationEntry))
}
}
@@ -17,7 +17,6 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.parcelize.ParcelizeAnnotationChecker.Companion.TYPE_PARCELER_FQ_NAMES
import org.jetbrains.kotlin.parcelize.ParcelizeResolveExtension.Companion.createMethod
import org.jetbrains.kotlin.parcelize.ParcelizeSyntheticComponent.ComponentKind.*
import org.jetbrains.kotlin.parcelize.serializers.*
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.parcelize
import org.jetbrains.kotlin.backend.common.serialization.findPackage
import org.jetbrains.kotlin.codegen.ClassBuilderMode
import org.jetbrains.kotlin.codegen.FrameMap
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
@@ -17,6 +18,7 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.parcelize.ParcelizeAnnotationChecker.Companion.DEPRECATED_RUNTIME_PACKAGE
import org.jetbrains.kotlin.parcelize.diagnostic.ErrorsParcelize
import org.jetbrains.kotlin.parcelize.serializers.ParcelSerializer
import org.jetbrains.kotlin.parcelize.serializers.isParcelable
@@ -29,6 +31,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.jvm.annotations.findJvmFieldAnnotation
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.isError
import org.jetbrains.kotlin.types.typeUtil.supertypes
val ANDROID_PARCELABLE_CLASS_FQNAME = FqName("android.os.Parcelable")
val ANDROID_PARCELABLE_CREATOR_CLASS_FQNAME = FqName("android.os.Parcelable.Creator")
@@ -48,6 +51,7 @@ class ParcelizeDeclarationChecker : DeclarationChecker {
when (descriptor) {
is ClassDescriptor -> {
checkParcelableClass(descriptor, declaration, trace, trace.bindingContext, context.languageVersionSettings)
checkParcelerClass(descriptor, declaration, trace)
}
is SimpleFunctionDescriptor -> {
val containingClass = descriptor.containingDeclaration as? ClassDescriptor
@@ -116,6 +120,24 @@ class ParcelizeDeclarationChecker : DeclarationChecker {
}
}
private fun checkParcelerClass(
descriptor: ClassDescriptor,
declaration: KtDeclaration,
diagnosticHolder: DiagnosticSink,
) {
if (!descriptor.isCompanionObject || declaration !is KtObjectDeclaration) {
return
}
for (type in descriptor.defaultType.supertypes()) {
if (type.constructor.declarationDescriptor?.fqNameSafe == OLD_PARCELER_FQNAME) {
val reportElement = declaration.nameIdentifier ?: declaration.getObjectKeyword() ?: declaration
diagnosticHolder.report(ErrorsParcelize.DEPRECATED_PARCELER.on(reportElement))
break
}
}
}
private fun checkParcelableClass(
descriptor: ClassDescriptor,
declaration: KtDeclaration,
@@ -169,13 +169,35 @@ interface ParcelizeSyntheticComponent {
}
}
val TYPE_PARCELER_FQ_NAMES = listOf(
FqName(kotlinx.parcelize.TypeParceler::class.java.name),
FqName(kotlinx.android.parcel.TypeParceler::class.java.name)
)
val WRITE_WITH_FQ_NAMES = listOf(
FqName(kotlinx.parcelize.WriteWith::class.java.name),
FqName(kotlinx.android.parcel.WriteWith::class.java.name)
)
val IGNORED_ON_PARCEL_FQ_NAMES = listOf(
FqName(kotlinx.parcelize.IgnoredOnParcel::class.java.name),
FqName(kotlinx.android.parcel.IgnoredOnParcel::class.java.name)
)
val PARCELIZE_CLASS_FQ_NAMES: List<FqName> = listOf(
FqName(kotlinx.parcelize.Parcelize::class.java.canonicalName),
@Suppress("DEPRECATION") FqName(kotlinx.android.parcel.Parcelize::class.java.canonicalName)
FqName(kotlinx.android.parcel.Parcelize::class.java.canonicalName)
)
val RAW_VALUE_ANNOTATION_FQ_NAMES = listOf(
FqName(kotlinx.parcelize.RawValue::class.java.name),
@Suppress("DEPRECATION") FqName(kotlinx.android.parcel.RawValue::class.java.name)
)
internal val PARCELER_FQNAME = FqName(kotlinx.parcelize.Parceler::class.java.canonicalName)
internal val OLD_PARCELER_FQNAME = FqName(kotlinx.android.parcel.Parceler::class.java.canonicalName)
val ClassDescriptor.isParcelize: Boolean
get() {
for (fqName in PARCELIZE_CLASS_FQ_NAMES) {
@@ -134,5 +134,20 @@ object DefaultErrorMessagesParcelize : DefaultErrorMessages.Extension {
ErrorsParcelize.INAPPLICABLE_IGNORED_ON_PARCEL_CONSTRUCTOR_PROPERTY,
"'@IgnoredOnParcel' is inapplicable to properties declared in the primary constructor"
)
MAP.put(
ErrorsParcelize.FORBIDDEN_DEPRECATED_ANNOTATION,
"Parceler-related annotations from package 'kotlinx.android.parcel' are forbidden. Change package to 'kotlinx.parcelize'"
)
MAP.put(
ErrorsParcelize.DEPRECATED_ANNOTATION,
"Parcelize annotations from package 'kotlinx.android.parcel' are deprecated. Change package to 'kotlin.parcelize'"
)
MAP.put(
ErrorsParcelize.DEPRECATED_PARCELER,
"'kotlinx.android.parcel.Parceler' is deprecated. Use 'kotlinx.parcelize.Parceler' instead"
)
}
}
@@ -47,6 +47,9 @@ public interface ErrorsParcelize {
DiagnosticFactory0<PsiElement> DUPLICATING_TYPE_PARCELERS = DiagnosticFactory0.create(ERROR);
DiagnosticFactory1<PsiElement, KtClassOrObject> REDUNDANT_TYPE_PARCELER = DiagnosticFactory1.create(WARNING);
DiagnosticFactory1<PsiElement, KtClassOrObject> CLASS_SHOULD_BE_PARCELIZE = DiagnosticFactory1.create(ERROR);
DiagnosticFactory0<PsiElement> FORBIDDEN_DEPRECATED_ANNOTATION = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> DEPRECATED_ANNOTATION = DiagnosticFactory0.create(WARNING);
DiagnosticFactory0<PsiElement> DEPRECATED_PARCELER = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> INAPPLICABLE_IGNORED_ON_PARCEL = DiagnosticFactory0.create(WARNING);
DiagnosticFactory0<PsiElement> INAPPLICABLE_IGNORED_ON_PARCEL_CONSTRUCTOR_PROPERTY = DiagnosticFactory0.create(WARNING);
@@ -11,7 +11,7 @@ import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.parcelize.serializers.RAW_VALUE_ANNOTATION_FQ_NAMES
import org.jetbrains.kotlin.parcelize.RAW_VALUE_ANNOTATION_FQ_NAMES
class IrParcelSerializerFactory(symbols: AndroidSymbols) {
/**
@@ -14,6 +14,8 @@ import org.jetbrains.kotlin.ir.types.typeOrNull
import org.jetbrains.kotlin.ir.util.constructedClass
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
import org.jetbrains.kotlin.parcelize.ParcelizeAnnotationChecker
import org.jetbrains.kotlin.parcelize.TYPE_PARCELER_FQ_NAMES
import org.jetbrains.kotlin.parcelize.WRITE_WITH_FQ_NAMES
// Keep track of all custom parcelers which are currently in scope.
// Note that custom parcelers are resolved in *reverse* lexical order.
@@ -29,7 +31,7 @@ class IrParcelerScope(private val parent: IrParcelerScope? = null) {
}
fun IrParcelerScope?.getCustomSerializer(irType: IrType): IrClass? {
return irType.getAnyAnnotation(ParcelizeAnnotationChecker.WRITE_WITH_FQ_NAMES)?.let { writeWith ->
return irType.getAnyAnnotation(WRITE_WITH_FQ_NAMES)?.let { writeWith ->
(writeWith.type as IrSimpleType).arguments.single().typeOrNull!!.getClass()!!
} ?: this?.get(irType)
}
@@ -40,7 +42,7 @@ fun IrParcelerScope?.hasCustomSerializer(irType: IrType): Boolean {
fun IrAnnotationContainer.getParcelerScope(parent: IrParcelerScope? = null): IrParcelerScope? {
val typeParcelerAnnotations = annotations.filterTo(mutableListOf()) {
it.symbol.owner.constructedClass.fqNameWhenAvailable in ParcelizeAnnotationChecker.TYPE_PARCELER_FQ_NAMES
it.symbol.owner.constructedClass.fqNameWhenAvailable in TYPE_PARCELER_FQ_NAMES
}
if (typeParcelerAnnotations.isEmpty())
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.parcelize.RAW_VALUE_ANNOTATION_FQ_NAMES
import org.jetbrains.kotlin.parcelize.findAnyAnnotation
import org.jetbrains.kotlin.parcelize.hasAnyAnnotation
import org.jetbrains.kotlin.parcelize.isParcelize
@@ -43,11 +44,6 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
import java.util.*
import java.util.concurrent.ConcurrentHashMap
val RAW_VALUE_ANNOTATION_FQ_NAMES = listOf(
FqName(kotlinx.parcelize.RawValue::class.java.name),
@Suppress("DEPRECATION") FqName(kotlinx.android.parcel.RawValue::class.java.name)
)
internal typealias TypeParcelerMapping = Pair<KotlinType, KotlinType>
interface ParcelSerializer {
@@ -1,38 +0,0 @@
// IGNORE_BACKEND: JVM
// See KT-38105
// Throws IllegalAccessError, since the code tries to access the private companion field directly from the generated User$Creator class.
// WITH_RUNTIME
@file:JvmName("TestKt")
package test
import kotlinx.android.parcel.*
import android.os.Parcel
import android.os.Parcelable
data class User(val name: String, val age: Int)
@Parcelize
data class UserParcelable(val user: User) : Parcelable {
private companion object : Parceler<UserParcelable> {
override fun UserParcelable.write(parcel: Parcel, flags: Int) {
parcel.writeString(user.name)
}
override fun create(parcel: Parcel) = UserParcelable(User(parcel.readString(), 0))
}
}
fun box() = parcelTest { parcel ->
val userParcelable = UserParcelable(User("John", 20))
userParcelable.writeToParcel(parcel, 0)
val bytes = parcel.marshall()
parcel.unmarshall(bytes, 0, bytes.size)
parcel.setDataPosition(0)
val userParcelable2 = readFromParcel<UserParcelable>(parcel)
assert(userParcelable.user.name == userParcelable2.user.name)
assert(userParcelable2.user.age == 0)
}
@@ -1,49 +0,0 @@
// WITH_RUNTIME
@file:JvmName("TestKt")
package test
import kotlinx.android.parcel.*
import android.os.Parcel
import android.os.Parcelable
object Parceler1 : Parceler<String> {
override fun create(parcel: Parcel) = parcel.readInt().toString()
override fun String.write(parcel: Parcel, flags: Int) {
parcel.writeInt(length)
}
}
typealias Parceler2 = Parceler1
object Parceler3 : Parceler<String> {
override fun create(parcel: Parcel) = parcel.readString().toUpperCase()
override fun String.write(parcel: Parcel, flags: Int) {
parcel.writeString(this)
}
}
@Parcelize
@TypeParceler<String, Parceler2>
data class Test(
val a: String,
@TypeParceler<String, Parceler1> val b: String,
@TypeParceler<String, Parceler3> val c: CharSequence,
val d: @WriteWith<Parceler3> String
) : Parcelable
fun box() = parcelTest { parcel ->
val test = Test("Abc", "Abc", "Abc", "Abc")
test.writeToParcel(parcel, 0)
val bytes = parcel.marshall()
parcel.unmarshall(bytes, 0, bytes.size)
parcel.setDataPosition(0)
val test2 = readFromParcel<Test>(parcel)
assert(test.a == "Abc" && test.b == "Abc" && test.c == "Abc" && test.d == "Abc")
assert(test2.a == "3" && test2.b == "3" && test2.c == "Abc" && test2.d == "ABC")
}
@@ -1,55 +0,0 @@
// IGNORE_BACKEND: JVM
// See KT-38107
// The JVM backend is missing support for custom parcelers in List<String>
// WITH_RUNTIME
@file:JvmName("TestKt")
package test
import kotlinx.android.parcel.*
import android.os.Parcel
import android.os.Parcelable
object Parceler1 : Parceler<String> {
override fun create(parcel: Parcel) = parcel.readInt().toString()
override fun String.write(parcel: Parcel, flags: Int) {
parcel.writeInt(length)
}
}
object Parceler2 : Parceler<List<String>> {
override fun create(parcel: Parcel) = listOf(parcel.readString())
override fun List<String>.write(parcel: Parcel, flags: Int) {
parcel.writeString(this.joinToString(","))
}
}
@Parcelize
data class Test(
val a: String,
val b: @WriteWith<Parceler1> String,
val c: List<@WriteWith<Parceler1> String>,
val d: @WriteWith<Parceler2> List<String>,
val e: @WriteWith<Parceler2> List<@WriteWith<Parceler1> String>
) : Parcelable
fun box() = parcelTest { parcel ->
val test = Test("Abc", "Abc", listOf("A", "bc"), listOf("A", "bc"), listOf("A", "bc"))
test.writeToParcel(parcel, 0)
val bytes = parcel.marshall()
parcel.unmarshall(bytes, 0, bytes.size)
parcel.setDataPosition(0)
val test2 = readFromParcel<Test>(parcel)
with (test) {
assert(a == "Abc" && b == "Abc" && c == listOf("A", "bc") && d == listOf("A", "bc") && e == listOf("A", "bc"))
}
with (test2) {
assert(a == "Abc" && b == "3" && c == listOf("1", "2") && d == listOf("A,bc") && e == listOf("A,bc"))
}
}
@@ -1,117 +0,0 @@
final class User$Companion : java/lang/Object, kotlinx/android/parcel/Parceler {
private void <init>()
public void <init>(kotlin.jvm.internal.DefaultConstructorMarker $constructor_marker)
public User create(android.os.Parcel parcel)
public java.lang.Object create(android.os.Parcel parcel)
public User[] newArray(int size) {
LABEL (L0)
LINENUMBER (10)
ALOAD (0)
CHECKCAST
ILOAD (1)
INVOKESTATIC (kotlinx/android/parcel/Parceler$DefaultImpls, newArray, (Lkotlinx/android/parcel/Parceler;I)[Ljava/lang/Object;)
CHECKCAST
ARETURN
LABEL (L1)
}
public java.lang.Object[] newArray(int size) {
LABEL (L0)
LINENUMBER (10)
ALOAD (0)
ILOAD (1)
INVOKEVIRTUAL (User$Companion, newArray, (I)[LUser;)
ARETURN
LABEL (L1)
}
public void write(User $this$write, android.os.Parcel parcel, int flags)
public void write(java.lang.Object $this$write, android.os.Parcel parcel, int flags)
}
public final class User$Creator : java/lang/Object, android/os/Parcelable$Creator {
public void <init>()
public final User createFromParcel(android.os.Parcel parcel) {
LABEL (L0)
ALOAD (1)
LDC (parcel)
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkNotNullParameter, (Ljava/lang/Object;Ljava/lang/String;)V)
INVOKESTATIC (User, access$getCompanion$p$s2645995, ()LUser$Companion;)
ALOAD (1)
INVOKEVIRTUAL (User$Companion, create, (Landroid/os/Parcel;)LUser;)
ARETURN
LABEL (L1)
}
public java.lang.Object createFromParcel(android.os.Parcel source) {
LABEL (L0)
ALOAD (0)
ALOAD (1)
INVOKEVIRTUAL (User$Creator, createFromParcel, (Landroid/os/Parcel;)LUser;)
ARETURN
LABEL (L1)
}
public final User[] newArray(int size) {
LABEL (L0)
ILOAD (1)
ANEWARRAY
ARETURN
LABEL (L1)
}
public java.lang.Object[] newArray(int size) {
LABEL (L0)
ALOAD (0)
ILOAD (1)
INVOKEVIRTUAL (User$Creator, newArray, (I)[LUser;)
ARETURN
LABEL (L1)
}
}
public final class User : java/lang/Object, android/os/Parcelable {
public final static android.os.Parcelable$Creator CREATOR
private final static User$Companion Companion
private final int age
private final java.lang.String firstName
private final java.lang.String lastName
static void <clinit>()
public void <init>(java.lang.String firstName, java.lang.String lastName, int age)
public final static User$Companion access$getCompanion$p$s2645995()
public int describeContents()
public final int getAge()
public final java.lang.String getFirstName()
public final java.lang.String getLastName()
public void writeToParcel(android.os.Parcel out, int flags) {
LABEL (L0)
ALOAD (1)
LDC (out)
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkNotNullParameter, (Ljava/lang/Object;Ljava/lang/String;)V)
GETSTATIC (Companion, LUser$Companion;)
ALOAD (0)
ALOAD (1)
ILOAD (2)
INVOKEVIRTUAL (User$Companion, write, (LUser;Landroid/os/Parcel;I)V)
RETURN
LABEL (L1)
}
}
@@ -1,19 +0,0 @@
// CURIOUS_ABOUT writeToParcel, createFromParcel, newArray
// WITH_RUNTIME
import kotlinx.android.parcel.*
import android.os.Parcel
import android.os.Parcelable
@Parcelize
class User(val firstName: String, val lastName: String, val age: Int) : Parcelable {
private companion object : Parceler<User> {
override fun User.write(parcel: Parcel, flags: Int) {
parcel.writeString(firstName)
parcel.writeString(lastName)
parcel.writeInt(age)
}
override fun create(parcel: Parcel) = User(parcel.readString(), parcel.readString(), parcel.readInt())
}
}
@@ -1,113 +0,0 @@
final class User$Companion : java/lang/Object, kotlinx/android/parcel/Parceler {
private void <init>()
public void <init>(kotlin.jvm.internal.DefaultConstructorMarker $constructor_marker)
public User create(android.os.Parcel parcel)
public java.lang.Object create(android.os.Parcel p0)
public User[] newArray(int size) {
LABEL (L0)
LINENUMBER (10)
ALOAD (0)
ILOAD (1)
INVOKESTATIC (kotlinx/android/parcel/Parceler$DefaultImpls, newArray, (Lkotlinx/android/parcel/Parceler;I)[Ljava/lang/Object;)
CHECKCAST
ARETURN
LABEL (L1)
}
public java.lang.Object[] newArray(int p0) {
LABEL (L0)
LINENUMBER (10)
ALOAD (0)
ILOAD (1)
INVOKEVIRTUAL (User$Companion, newArray, (I)[LUser;)
ARETURN
}
public void write(User $this$write, android.os.Parcel parcel, int flags)
public void write(java.lang.Object p0, android.os.Parcel p1, int p2)
}
public final class User$Creator : java/lang/Object, android/os/Parcelable$Creator {
public void <init>()
public final User createFromParcel(android.os.Parcel in) {
LABEL (L0)
ALOAD (1)
LDC (in)
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkNotNullParameter, (Ljava/lang/Object;Ljava/lang/String;)V)
GETSTATIC (Companion, LUser$Companion;)
ALOAD (1)
INVOKEVIRTUAL (User$Companion, create, (Landroid/os/Parcel;)LUser;)
ARETURN
LABEL (L1)
}
public java.lang.Object createFromParcel(android.os.Parcel p0) {
LABEL (L0)
LINENUMBER (9)
ALOAD (0)
ALOAD (1)
INVOKEVIRTUAL (User$Creator, createFromParcel, (Landroid/os/Parcel;)LUser;)
ARETURN
}
public final User[] newArray(int size) {
LABEL (L0)
ILOAD (1)
ANEWARRAY
ARETURN
LABEL (L1)
}
public java.lang.Object[] newArray(int p0) {
LABEL (L0)
LINENUMBER (9)
ALOAD (0)
ILOAD (1)
INVOKEVIRTUAL (User$Creator, newArray, (I)[LUser;)
ARETURN
}
}
public final class User : java/lang/Object, android/os/Parcelable {
public final static android.os.Parcelable$Creator CREATOR
private final static User$Companion Companion
private final int age
private final java.lang.String firstName
private final java.lang.String lastName
static void <clinit>()
public void <init>(java.lang.String firstName, java.lang.String lastName, int age)
public int describeContents()
public final int getAge()
public final java.lang.String getFirstName()
public final java.lang.String getLastName()
public void writeToParcel(android.os.Parcel parcel, int flags) {
LABEL (L0)
ALOAD (1)
LDC (parcel)
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkNotNullParameter, (Ljava/lang/Object;Ljava/lang/String;)V)
GETSTATIC (Companion, LUser$Companion;)
ALOAD (0)
ALOAD (1)
ILOAD (2)
INVOKEVIRTUAL (User$Companion, write, (LUser;Landroid/os/Parcel;I)V)
RETURN
LABEL (L1)
}
}
@@ -157,7 +157,7 @@ abstract class AbstractParcelizeBoxTest : CodegenTestCase() {
javaExe.absolutePath,
"-ea",
"-classpath",
(libraryClasspath + dirForTestClasses).joinToString(File.pathSeparator),
(libraryClasspath + dirForTestClasses).joinToString(File.pathSeparator) { it.absolutePath },
JUnitCore::class.java.name,
JUNIT_GENERATED_TEST_CLASS_FQNAME
).start()
@@ -74,11 +74,6 @@ public class ParcelizeBoxTestGenerated extends AbstractParcelizeBoxTest {
runTest("plugins/parcelize/parcelize-compiler/testData/box/customParcelable.kt");
}
@TestMetadata("customParcelableDeprecated.kt")
public void testCustomParcelableDeprecated() throws Exception {
runTest("plugins/parcelize/parcelize-compiler/testData/box/customParcelableDeprecated.kt");
}
@TestMetadata("customParcelerScoping.kt")
public void testCustomParcelerScoping() throws Exception {
runTest("plugins/parcelize/parcelize-compiler/testData/box/customParcelerScoping.kt");
@@ -94,21 +89,11 @@ public class ParcelizeBoxTestGenerated extends AbstractParcelizeBoxTest {
runTest("plugins/parcelize/parcelize-compiler/testData/box/customSerializerSimple.kt");
}
@TestMetadata("customSerializerSimpleDeprecated.kt")
public void testCustomSerializerSimpleDeprecated() throws Exception {
runTest("plugins/parcelize/parcelize-compiler/testData/box/customSerializerSimpleDeprecated.kt");
}
@TestMetadata("customSerializerWriteWith.kt")
public void testCustomSerializerWriteWith() throws Exception {
runTest("plugins/parcelize/parcelize-compiler/testData/box/customSerializerWriteWith.kt");
}
@TestMetadata("customSerializerWriteWithDeprecated.kt")
public void testCustomSerializerWriteWithDeprecated() throws Exception {
runTest("plugins/parcelize/parcelize-compiler/testData/box/customSerializerWriteWithDeprecated.kt");
}
@TestMetadata("customSimple.kt")
public void testCustomSimple() throws Exception {
runTest("plugins/parcelize/parcelize-compiler/testData/box/customSimple.kt");
@@ -49,11 +49,6 @@ public class ParcelizeBytecodeListingTestGenerated extends AbstractParcelizeByte
runTest("plugins/parcelize/parcelize-compiler/testData/codegen/customSimple.kt");
}
@TestMetadata("customSimpleDeprecated.kt")
public void testCustomSimpleDeprecated() throws Exception {
runTest("plugins/parcelize/parcelize-compiler/testData/codegen/customSimpleDeprecated.kt");
}
@TestMetadata("customSimpleWithNewArray.kt")
public void testCustomSimpleWithNewArray() throws Exception {
runTest("plugins/parcelize/parcelize-compiler/testData/codegen/customSimpleWithNewArray.kt");
@@ -74,11 +74,6 @@ public class ParcelizeIrBoxTestGenerated extends AbstractParcelizeIrBoxTest {
runTest("plugins/parcelize/parcelize-compiler/testData/box/customParcelable.kt");
}
@TestMetadata("customParcelableDeprecated.kt")
public void testCustomParcelableDeprecated() throws Exception {
runTest("plugins/parcelize/parcelize-compiler/testData/box/customParcelableDeprecated.kt");
}
@TestMetadata("customParcelerScoping.kt")
public void testCustomParcelerScoping() throws Exception {
runTest("plugins/parcelize/parcelize-compiler/testData/box/customParcelerScoping.kt");
@@ -94,21 +89,11 @@ public class ParcelizeIrBoxTestGenerated extends AbstractParcelizeIrBoxTest {
runTest("plugins/parcelize/parcelize-compiler/testData/box/customSerializerSimple.kt");
}
@TestMetadata("customSerializerSimpleDeprecated.kt")
public void testCustomSerializerSimpleDeprecated() throws Exception {
runTest("plugins/parcelize/parcelize-compiler/testData/box/customSerializerSimpleDeprecated.kt");
}
@TestMetadata("customSerializerWriteWith.kt")
public void testCustomSerializerWriteWith() throws Exception {
runTest("plugins/parcelize/parcelize-compiler/testData/box/customSerializerWriteWith.kt");
}
@TestMetadata("customSerializerWriteWithDeprecated.kt")
public void testCustomSerializerWriteWithDeprecated() throws Exception {
runTest("plugins/parcelize/parcelize-compiler/testData/box/customSerializerWriteWithDeprecated.kt");
}
@TestMetadata("customSimple.kt")
public void testCustomSimple() throws Exception {
runTest("plugins/parcelize/parcelize-compiler/testData/box/customSimple.kt");
@@ -49,11 +49,6 @@ public class ParcelizeIrBytecodeListingTestGenerated extends AbstractParcelizeIr
runTest("plugins/parcelize/parcelize-compiler/testData/codegen/customSimple.kt");
}
@TestMetadata("customSimpleDeprecated.kt")
public void testCustomSimpleDeprecated() throws Exception {
runTest("plugins/parcelize/parcelize-compiler/testData/codegen/customSimpleDeprecated.kt");
}
@TestMetadata("customSimpleWithNewArray.kt")
public void testCustomSimpleWithNewArray() throws Exception {
runTest("plugins/parcelize/parcelize-compiler/testData/codegen/customSimpleWithNewArray.kt");
@@ -12,8 +12,9 @@ import org.jetbrains.kotlin.utils.PathUtil
import java.io.File
fun addParcelizeRuntimeLibrary(environment: KotlinCoreEnvironment) {
val runtimeLibrary = File(PathUtil.kotlinPathsForCompiler.libPath, "parcelize-runtime.jar")
environment.updateClasspath(listOf(JvmClasspathRoot(runtimeLibrary)))
val runtimeLibrary = File(PathUtil.kotlinPathsForCompiler.libPath, PathUtil.PARCELIZE_RUNTIME_PLUGIN_JAR_NAME)
val androidExtensionsRuntimeLibrary = File(PathUtil.kotlinPathsForCompiler.libPath, PathUtil.ANDROID_EXTENSIONS_RUNTIME_PLUGIN_JAR_NAME)
environment.updateClasspath(listOf(JvmClasspathRoot(runtimeLibrary), JvmClasspathRoot(androidExtensionsRuntimeLibrary)))
}
fun addAndroidJarLibrary(environment: KotlinCoreEnvironment) {
@@ -0,0 +1,46 @@
// WITH_RUNTIME
package test
import kotlinx.android.parcel.*
import android.os.Parcel
import android.os.Parcelable
object Parceler1 : Parceler<String> {
override fun create(parcel: Parcel) = parcel.readInt().toString()
override fun String.write(parcel: Parcel, flags: Int) {
parcel.writeInt(length)
}
}
object Parceler2 : Parceler<List<String>> {
override fun create(parcel: Parcel) = listOf(parcel.readString()!!)
override fun List<String>.write(parcel: Parcel, flags: Int) {
parcel.writeString(this.joinToString(","))
}
}
<warning descr="[DEPRECATED_ANNOTATION] Parcelize annotations from package 'kotlinx.android.parcel' are deprecated. Change package to 'kotlin.parcelize'">@Parcelize</warning>
<error descr="[FORBIDDEN_DEPRECATED_ANNOTATION] Parceler-related annotations from package 'kotlinx.android.parcel' are forbidden. Change package to 'kotlinx.parcelize'">@TypeParceler<String, <error descr="[UPPER_BOUND_VIOLATED] Type argument is not within its bounds: should be subtype of 'Parceler<in String>'">Parceler2</error>></error>
data class Test(
val a: String,
val b: <error descr="[FORBIDDEN_DEPRECATED_ANNOTATION] Parceler-related annotations from package 'kotlinx.android.parcel' are forbidden. Change package to 'kotlinx.parcelize'">@WriteWith<Parceler1></error> String,
val c: <error descr="[FORBIDDEN_DEPRECATED_ANNOTATION] Parceler-related annotations from package 'kotlinx.android.parcel' are forbidden. Change package to 'kotlinx.parcelize'">@WriteWith<Parceler2></error> List<<error descr="[FORBIDDEN_DEPRECATED_ANNOTATION] Parceler-related annotations from package 'kotlinx.android.parcel' are forbidden. Change package to 'kotlinx.parcelize'">@WriteWith<Parceler1></error> String>
) : Parcelable {
<warning descr="[DEPRECATED_ANNOTATION] Parcelize annotations from package 'kotlinx.android.parcel' are deprecated. Change package to 'kotlin.parcelize'">@IgnoredOnParcel</warning>
val x by lazy { "foo" }
}
interface ParcelerForUser: Parceler<User>
<warning descr="[DEPRECATED_ANNOTATION] Parcelize annotations from package 'kotlinx.android.parcel' are deprecated. Change package to 'kotlin.parcelize'">@Parcelize</warning>
class User(val name: String) : Parcelable {
private companion <error descr="[DEPRECATED_PARCELER] 'kotlinx.android.parcel.Parceler' is deprecated. Use 'kotlinx.parcelize.Parceler' instead">object</error> : ParcelerForUser {
override fun User.write(parcel: Parcel, flags: Int) {
parcel.writeString(name)
}
override fun create(parcel: Parcel) = User(parcel.readString()!!)
}
}
@@ -12,16 +12,11 @@ import org.jetbrains.kotlin.test.KotlinTestUtils
abstract class AbstractParcelizeCheckerTest : AbstractPsiCheckerTest() {
override fun setUp() {
super.setUp()
val androidJar = KotlinTestUtils.findAndroidApiJar()
ConfigLibraryUtil.addLibrary(module, "androidJar", androidJar.parentFile.absolutePath, arrayOf(androidJar.name))
ConfigLibraryUtil.addLibrary(module, "androidExtensionsRuntime", "dist/kotlinc/lib", arrayOf("parcelize-runtime.jar"))
addParcelizeLibraries(module)
}
override fun tearDown() {
ConfigLibraryUtil.removeLibrary(module, "androidJar")
ConfigLibraryUtil.removeLibrary(module, "androidExtensionsRuntime")
removeParcelizeLibraries(module)
super.tearDown()
}
}
@@ -23,16 +23,11 @@ import org.jetbrains.kotlin.test.KotlinTestUtils
abstract class AbstractParcelizeQuickFixTest : AbstractQuickFixTest() {
override fun setUp() {
super.setUp()
val androidJar = KotlinTestUtils.findAndroidApiJar()
ConfigLibraryUtil.addLibrary(module, "androidJar", androidJar.parentFile.absolutePath, arrayOf(androidJar.name))
ConfigLibraryUtil.addLibrary(module, "androidExtensionsRuntime", "dist/kotlinc/lib", arrayOf("parcelize-runtime.jar"))
addParcelizeLibraries(module)
}
override fun tearDown() {
ConfigLibraryUtil.removeLibrary(module, "androidJar")
ConfigLibraryUtil.removeLibrary(module, "androidExtensionsRuntime")
removeParcelizeLibraries(module)
super.tearDown()
}
}
@@ -53,6 +53,11 @@ public class ParcelizeCheckerTestGenerated extends AbstractParcelizeCheckerTest
runTest("plugins/parcelize/parcelize-ide/testData/checker/delegate.kt");
}
@TestMetadata("deprecatedAnnotations.kt")
public void testDeprecatedAnnotations() throws Exception {
runTest("plugins/parcelize/parcelize-ide/testData/checker/deprecatedAnnotations.kt");
}
@TestMetadata("emptyPrimaryConstructor.kt")
public void testEmptyPrimaryConstructor() throws Exception {
runTest("plugins/parcelize/parcelize-ide/testData/checker/emptyPrimaryConstructor.kt");
@@ -0,0 +1,23 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.pacelize.ide.test
import com.intellij.openapi.module.Module
import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil
import org.jetbrains.kotlin.test.KotlinTestUtils
fun addParcelizeLibraries(module: Module) {
val androidJar = KotlinTestUtils.findAndroidApiJar()
ConfigLibraryUtil.addLibrary(module, "androidJar", androidJar.parentFile.absolutePath, arrayOf(androidJar.name))
ConfigLibraryUtil.addLibrary(module, "parcelizeRuntime", "dist/kotlinc/lib", arrayOf("parcelize-runtime.jar"))
ConfigLibraryUtil.addLibrary(module, "androidExtensionsRuntime", "dist/kotlinc/lib", arrayOf("android-extensions-runtime.jar"))
}
fun removeParcelizeLibraries(module: Module) {
ConfigLibraryUtil.removeLibrary(module, "androidJar")
ConfigLibraryUtil.removeLibrary(module, "parcelizeRuntime")
ConfigLibraryUtil.removeLibrary(module, "androidExtensionsRuntime")
}
@@ -9,6 +9,7 @@ jvmTarget = "1.6"
dependencies {
compile(kotlinStdlib())
compile(project(":kotlin-android-extensions-runtime"))
compileOnly(commonDep("com.google.android", "android"))
}
@@ -1,25 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kotlinx.android.parcel
/**
* The property annotated with [IgnoredOnParcel] will not be stored into parcel.
*/
@Target(AnnotationTarget.PROPERTY)
@Retention(AnnotationRetention.SOURCE)
@Deprecated("Use kotlinx.parcelize.IgnoredOnParcel instead.", ReplaceWith("kotlinx.parcelize.IgnoredOnParcel"))
annotation class IgnoredOnParcel
@@ -1,24 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@file:Suppress("unused")
package kotlinx.android.parcel
/**
* The base interface for custom [Parcelize] serializers.
*/
@Deprecated("Use kotlinx.parcelize.Parceler instead.", ReplaceWith("kotlinx.parcelize.Parceler"))
interface Parceler<T> : kotlinx.parcelize.Parceler<T>
@@ -1,29 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kotlinx.android.parcel
/**
* Instructs the Kotlin compiler to generate `writeToParcel()`, `describeContents()` [android.os.Parcelable] methods,
* as well as a `CREATOR` factory class automatically.
*
* The annotation is applicable only to classes that implements [android.os.Parcelable] (directly or indirectly).
* Note that only the primary constructor properties will be serialized.
*/
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.BINARY)
@Deprecated("Use kotlinx.parcelize.Parcelize instead.", ReplaceWith("kotlinx.parcelize.Parcelize"))
annotation class Parcelize
@@ -1,26 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kotlinx.android.parcel
/**
* Write the corresponding property value with [android.os.Parcel.writeValue].
* Serialization may fail at runtime, depending on actual property value type.
*/
@Target(AnnotationTarget.TYPE)
@Retention(AnnotationRetention.BINARY)
@Deprecated("Use kotlinx.parcelize.RawValue instead.", ReplaceWith("kotlinx.parcelize.RawValue"))
annotation class RawValue
@@ -1,28 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kotlinx.android.parcel
import kotlinx.parcelize.Parceler
/**
* Specifies what [Parceler] should be used for a particular type [T].
*/
@Retention(AnnotationRetention.SOURCE)
@Repeatable
@Target(AnnotationTarget.CLASS, AnnotationTarget.PROPERTY)
@Deprecated("Use kotlinx.parcelize.TypeParceler instead.", ReplaceWith("kotlinx.parcelize.TypeParceler"))
annotation class TypeParceler<T, P : @Suppress("DEPRECATION_ERROR") Parceler<in T>>
@@ -1,25 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kotlinx.android.parcel
/**
* Specifies what [Parceler] should be used for the annotated type.
*/
@Retention(AnnotationRetention.SOURCE)
@Target(AnnotationTarget.TYPE)
@Deprecated("Use kotlinx.parcelize.WriteWith instead.", ReplaceWith("kotlinx.parcelize.WriteWith"))
annotation class WriteWith<P : @Suppress("DEPRECATION") Parceler<*>>