diff --git a/generators/build.gradle.kts b/generators/build.gradle.kts index 95dbee9fdc4..c8f805630db 100644 --- a/generators/build.gradle.kts +++ b/generators/build.gradle.kts @@ -58,6 +58,7 @@ dependencies { testCompile(projectTests(":plugins:android-extensions-compiler")) testCompile(projectTests(":plugins:android-extensions-ide")) testCompile(projectTests(":plugins:parcelize:parcelize-compiler")) + testCompile(projectTests(":plugins:parcelize:parcelize-ide")) testCompile(projectTests(":kotlin-annotation-processing")) testCompile(projectTests(":kotlin-annotation-processing-cli")) testCompile(projectTests(":kotlin-allopen-compiler-plugin")) diff --git a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt index d967d435a21..2db53f647e8 100644 --- a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt +++ b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt @@ -178,6 +178,8 @@ import org.jetbrains.kotlin.parcelize.test.AbstractParcelizeBoxTest import org.jetbrains.kotlin.parcelize.test.AbstractParcelizeBytecodeListingTest import org.jetbrains.kotlin.parcelize.test.AbstractParcelizeIrBoxTest import org.jetbrains.kotlin.parcelize.test.AbstractParcelizeIrBytecodeListingTest +import org.jetbrains.kotlin.pacelize.ide.test.AbstractParcelizeCheckerTest +import org.jetbrains.kotlin.pacelize.ide.test.AbstractParcelizeQuickFixTest import org.jetbrains.kotlin.psi.patternMatching.AbstractPsiUnifierTest import org.jetbrains.kotlin.samWithReceiver.AbstractSamWithReceiverScriptTest import org.jetbrains.kotlin.samWithReceiver.AbstractSamWithReceiverTest @@ -1530,6 +1532,16 @@ fun main(args: Array) { } } + testGroup("plugins/parcelize/parcelize-ide/tests", "plugins/parcelize/parcelize-ide/testData") { + testClass { + model("quickfix", pattern = "^([\\w\\-_]+)\\.kt$", filenameStartsLowerCase = true) + } + + testClass { + model("checker", extension = "kt") + } + } + testGroup("plugins/jvm-abi-gen/test", "plugins/jvm-abi-gen/testData") { testClass { model("compare", recursive = false, extension = null) diff --git a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as40 b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as40 index 84a7ec4885c..94e55acbead 100644 --- a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as40 +++ b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as40 @@ -152,6 +152,8 @@ import org.jetbrains.kotlin.parcelize.test.AbstractParcelizeBoxTest import org.jetbrains.kotlin.parcelize.test.AbstractParcelizeBytecodeListingTest import org.jetbrains.kotlin.parcelize.test.AbstractParcelizeIrBoxTest import org.jetbrains.kotlin.parcelize.test.AbstractParcelizeIrBytecodeListingTest +import org.jetbrains.kotlin.pacelize.ide.test.AbstractParcelizeCheckerTest +import org.jetbrains.kotlin.pacelize.ide.test.AbstractParcelizeQuickFixTest import org.jetbrains.kotlin.psi.patternMatching.AbstractPsiUnifierTest import org.jetbrains.kotlin.samWithReceiver.AbstractSamWithReceiverScriptTest import org.jetbrains.kotlin.samWithReceiver.AbstractSamWithReceiverTest @@ -1149,6 +1151,16 @@ fun main(args: Array) { } } + testGroup("plugins/parcelize/parcelize-ide/tests", "plugins/parcelize/parcelize-ide/testData") { + testClass { + model("quickfix", pattern = "^([\\w\\-_]+)\\.kt$", filenameStartsLowerCase = true) + } + + testClass { + model("checker", extension = "kt") + } + } + testGroup("plugins/kapt3/kapt3-compiler/test", "plugins/kapt3/kapt3-compiler/testData") { testClass { model("converter") diff --git a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as41 b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as41 index 84a7ec4885c..94e55acbead 100644 --- a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as41 +++ b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as41 @@ -152,6 +152,8 @@ import org.jetbrains.kotlin.parcelize.test.AbstractParcelizeBoxTest import org.jetbrains.kotlin.parcelize.test.AbstractParcelizeBytecodeListingTest import org.jetbrains.kotlin.parcelize.test.AbstractParcelizeIrBoxTest import org.jetbrains.kotlin.parcelize.test.AbstractParcelizeIrBytecodeListingTest +import org.jetbrains.kotlin.pacelize.ide.test.AbstractParcelizeCheckerTest +import org.jetbrains.kotlin.pacelize.ide.test.AbstractParcelizeQuickFixTest import org.jetbrains.kotlin.psi.patternMatching.AbstractPsiUnifierTest import org.jetbrains.kotlin.samWithReceiver.AbstractSamWithReceiverScriptTest import org.jetbrains.kotlin.samWithReceiver.AbstractSamWithReceiverTest @@ -1149,6 +1151,16 @@ fun main(args: Array) { } } + testGroup("plugins/parcelize/parcelize-ide/tests", "plugins/parcelize/parcelize-ide/testData") { + testClass { + model("quickfix", pattern = "^([\\w\\-_]+)\\.kt$", filenameStartsLowerCase = true) + } + + testClass { + model("checker", extension = "kt") + } + } + testGroup("plugins/kapt3/kapt3-compiler/test", "plugins/kapt3/kapt3-compiler/testData") { testClass { model("converter") diff --git a/idea/kotlin-gradle-tooling/resources/META-INF/services/org.jetbrains.plugins.gradle.tooling.ModelBuilderService b/idea/kotlin-gradle-tooling/resources/META-INF/services/org.jetbrains.plugins.gradle.tooling.ModelBuilderService index de4ba481d83..c41e4fe2b72 100644 --- a/idea/kotlin-gradle-tooling/resources/META-INF/services/org.jetbrains.plugins.gradle.tooling.ModelBuilderService +++ b/idea/kotlin-gradle-tooling/resources/META-INF/services/org.jetbrains.plugins.gradle.tooling.ModelBuilderService @@ -5,4 +5,5 @@ org.jetbrains.kotlin.gradle.KotlinCommonizerModelBuilder org.jetbrains.kotlin.allopen.ide.AllOpenModelBuilderService org.jetbrains.kotlin.kapt.idea.KaptModelBuilderService org.jetbrains.kotlin.noarg.ide.NoArgModelBuilderService -org.jetbrains.kotlin.samWithReceiver.ide.SamWithReceiverModelBuilderService \ No newline at end of file +org.jetbrains.kotlin.samWithReceiver.ide.SamWithReceiverModelBuilderService +org.jetbrains.kotlin.parcelize.ide.ParcelizeModelBuilderService \ No newline at end of file diff --git a/idea/kotlin-gradle-tooling/src/org/jetbrains/kotlin/parcelize/ide/ParcelizeModelBuilderService.kt b/idea/kotlin-gradle-tooling/src/org/jetbrains/kotlin/parcelize/ide/ParcelizeModelBuilderService.kt new file mode 100644 index 00000000000..b46ac9900ca --- /dev/null +++ b/idea/kotlin-gradle-tooling/src/org/jetbrains/kotlin/parcelize/ide/ParcelizeModelBuilderService.kt @@ -0,0 +1,33 @@ +/* + * 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.parcelize.ide + +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.jetbrains.kotlin.gradle.AbstractKotlinGradleModelBuilder +import org.jetbrains.plugins.gradle.tooling.ErrorMessageBuilder +import java.io.Serializable + +interface ParcelizeGradleModel : Serializable { + val isEnabled: Boolean +} + +class ParcelizeGradleModelImpl(override val isEnabled: Boolean) : ParcelizeGradleModel + +class ParcelizeModelBuilderService : AbstractKotlinGradleModelBuilder() { + override fun getErrorMessageBuilder(project: Project, e: Exception): ErrorMessageBuilder { + return ErrorMessageBuilder.create(project, e, "Gradle import errors") + .withDescription("Unable to build kotlin-parcelize plugin configuration") + } + + override fun canBuild(modelName: String?): Boolean = modelName == ParcelizeGradleModel::class.java.name + + override fun buildAll(modelName: String?, project: Project): Any { + val parcelizePlugin: Plugin<*>? = project.plugins.findPlugin("kotlin-parcelize") + + return ParcelizeGradleModelImpl(isEnabled = parcelizePlugin != null) + } +} \ No newline at end of file diff --git a/idea/resources-descriptors/META-INF/plugin.xml b/idea/resources-descriptors/META-INF/plugin.xml index 793d670b990..bf474888223 100644 --- a/idea/resources-descriptors/META-INF/plugin.xml +++ b/idea/resources-descriptors/META-INF/plugin.xml @@ -68,6 +68,7 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. + diff --git a/idea/resources-descriptors/META-INF/plugin.xml.193 b/idea/resources-descriptors/META-INF/plugin.xml.193 index 62ca572bebe..b61c2441261 100644 --- a/idea/resources-descriptors/META-INF/plugin.xml.193 +++ b/idea/resources-descriptors/META-INF/plugin.xml.193 @@ -68,6 +68,7 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. + diff --git a/idea/resources-descriptors/META-INF/plugin.xml.202 b/idea/resources-descriptors/META-INF/plugin.xml.202 index cb31262ec06..7d6aa6a6c86 100644 --- a/idea/resources-descriptors/META-INF/plugin.xml.202 +++ b/idea/resources-descriptors/META-INF/plugin.xml.202 @@ -68,6 +68,7 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. + diff --git a/idea/resources-descriptors/META-INF/plugin.xml.as40 b/idea/resources-descriptors/META-INF/plugin.xml.as40 index 61d3e7a6a09..f5a9bb7b99a 100644 --- a/idea/resources-descriptors/META-INF/plugin.xml.as40 +++ b/idea/resources-descriptors/META-INF/plugin.xml.as40 @@ -67,6 +67,7 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. + diff --git a/idea/resources-descriptors/META-INF/plugin.xml.as41 b/idea/resources-descriptors/META-INF/plugin.xml.as41 index 81af72f575e..7a8e09a2534 100644 --- a/idea/resources-descriptors/META-INF/plugin.xml.as41 +++ b/idea/resources-descriptors/META-INF/plugin.xml.as41 @@ -67,6 +67,7 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. + diff --git a/idea/resources/META-INF/parcelize.xml b/idea/resources/META-INF/parcelize.xml new file mode 100644 index 00000000000..9e47ccce9c9 --- /dev/null +++ b/idea/resources/META-INF/parcelize.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/idea/testData/quickfix/allowResolveInWriteAction.txt b/idea/testData/quickfix/allowResolveInWriteAction.txt index 9b1c4dbc492..cf806580272 100644 --- a/idea/testData/quickfix/allowResolveInWriteAction.txt +++ b/idea/testData/quickfix/allowResolveInWriteAction.txt @@ -76,4 +76,5 @@ org.jetbrains.kotlin.idea.quickfix.SpecifyOverrideExplicitlyFix org.jetbrains.kotlin.idea.quickfix.SpecifyTypeExplicitlyFix org.jetbrains.kotlin.idea.quickfix.SuperClassNotInitialized$AddParenthesisFix org.jetbrains.kotlin.idea.quickfix.WrapWithSafeLetCallFix -com.intellij.spring.model.highlighting.autowire.SpringUastInjectionPointsAutowiringInspection$AddSpringBeanQualifierFix \ No newline at end of file +com.intellij.spring.model.highlighting.autowire.SpringUastInjectionPointsAutowiringInspection$AddSpringBeanQualifierFix +org.jetbrains.kotlin.parcelize.ide.quickfixes.ParcelMigrateToParcelizeQuickFix \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/build.gradle.kts b/plugins/parcelize/parcelize-ide/build.gradle.kts new file mode 100644 index 00000000000..eab842eaefe --- /dev/null +++ b/plugins/parcelize/parcelize-ide/build.gradle.kts @@ -0,0 +1,63 @@ +description = "IDE support for the Parcelize compiler plugin" + +plugins { + kotlin("jvm") + id("jps-compatible") +} + +dependencies { + compile(project(":compiler:util")) + compile(project(":compiler:plugin-api")) + compile(project(":compiler:frontend")) + compile(project(":compiler:frontend.java")) + compile(project(":compiler:light-classes")) + compile(project(":idea")) + compile(project(":plugins:parcelize:parcelize-compiler")) + compile(project(":plugins:parcelize:parcelize-runtime")) + + compile(intellijDep()) + compile(intellijPluginDep("gradle")) + + Platform[191].orLower { + compileOnly(intellijDep()) { includeJars("java-api", "java-impl") } + } + + Platform[192].orHigher { + compileOnly(intellijPluginDep("java")) { includeJars("java-api", "java-impl") } + } + + testCompile(projectTests(":idea")) + testCompile(projectTests(":plugins:parcelize:parcelize-compiler")) + + testRuntime(project(":allopen-ide-plugin")) + testRuntime(project(":noarg-ide-plugin")) + testRuntime(project(":kotlin-scripting-idea")) { isTransitive = false } + testRuntime(project(":kotlin-scripting-compiler-impl")) + testRuntime(project(":sam-with-receiver-ide-plugin")) + testRuntime(project(":kotlinx-serialization-ide-plugin")) + + testRuntime(toolsJar()) + + Platform[192].orHigher { + testRuntimeOnly(intellijPluginDep("java")) + } +} + +sourceSets { + "main" { projectDefault() } + "test" { projectDefault() } +} + +runtimeJar() +javadocJar() +sourcesJar() + +testsJar {} + +projectTest(parallel = true) { + dependsOn(":dist") + workingDir = rootDir + useAndroidJar() +} + +apply(from = "$rootDir/gradle/kotlinPluginPublication.gradle.kts") diff --git a/plugins/parcelize/parcelize-ide/resources/messages/KotlinParcelizeBundle.properties b/plugins/parcelize/parcelize-ide/resources/messages/KotlinParcelizeBundle.properties new file mode 100644 index 00000000000..657459494fd --- /dev/null +++ b/plugins/parcelize/parcelize-ide/resources/messages/KotlinParcelizeBundle.properties @@ -0,0 +1,8 @@ +parcelize.fix.annotate.containing.class.with.parcelize=Annotate containing class with ''@Parcelize'' +parcelize.fix.add.ignored.on.parcel.annotation=Add ''@IgnoredOnParcel'' annotation +parcelize.fix.add.empty.primary.constructor=Add empty primary constructor +parcelize.fix.add.parcelable.supertype=Add ''Parcelable'' supertype +parcelize.fix.remove.redundant.type.parceler.annotation=Remove redundant ''@TypeParceler'' annotation +parcelize.fix.migrate.to.parceler.companion.object=Migrate to ''Parceler'' companion object +parcelize.fix.remove.custom.creator.property=Remove custom ''CREATOR'' property +parcelize.fix.remove.custom.write.to.parcel.function=Remove custom ''writeToParcel()'' function \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/IdeParcelizeCodegenExtension.kt b/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/IdeParcelizeCodegenExtension.kt new file mode 100644 index 00000000000..e3563f879b7 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/IdeParcelizeCodegenExtension.kt @@ -0,0 +1,15 @@ +/* + * 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.parcelize.ide + +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.parcelize.ParcelizeCodegenExtension + +class IdeParcelizeCodegenExtension : ParcelizeCodegenExtension() { + override fun isAvailable(element: PsiElement): Boolean { + return ParcelizeAvailability.isAvailable(element) + } +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/IdeParcelizeResolveExtension.kt b/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/IdeParcelizeResolveExtension.kt new file mode 100644 index 00000000000..2cc6e3356e4 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/IdeParcelizeResolveExtension.kt @@ -0,0 +1,15 @@ +/* + * 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.parcelize.ide + +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.parcelize.ParcelizeResolveExtension + +class IdeParcelizeResolveExtension : ParcelizeResolveExtension() { + override fun isAvailable(element: PsiElement): Boolean { + return ParcelizeAvailability.isAvailable(element) + } +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/KotlinParcelizeBundle.kt b/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/KotlinParcelizeBundle.kt new file mode 100644 index 00000000000..827ff716d22 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/KotlinParcelizeBundle.kt @@ -0,0 +1,18 @@ +/* + * 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.parcelize.ide + +import org.jetbrains.annotations.NonNls +import org.jetbrains.annotations.PropertyKey +import org.jetbrains.kotlin.util.AbstractKotlinBundle + +@NonNls +private const val BUNDLE = "messages.KotlinParcelizeBundle" + +object KotlinParcelizeBundle : AbstractKotlinBundle(BUNDLE) { + @JvmStatic + fun message(@NonNls @PropertyKey(resourceBundle = BUNDLE) key: String, vararg params: Any): String = getMessage(key, *params) +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/ParcelizeAvailability.kt b/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/ParcelizeAvailability.kt new file mode 100644 index 00000000000..90912ce5c96 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/ParcelizeAvailability.kt @@ -0,0 +1,37 @@ +/* + * 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.parcelize.ide + +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil +import com.intellij.openapi.externalSystem.util.ExternalSystemUtil +import com.intellij.openapi.module.Module +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.idea.util.module +import org.jetbrains.plugins.gradle.service.project.GradleProjectResolverUtil +import org.jetbrains.plugins.gradle.util.GradleConstants + +object ParcelizeAvailability { + fun isAvailable(element: PsiElement): Boolean { + if (ApplicationManager.getApplication().isUnitTestMode) { + return true + } + + val module = element.module ?: return false + return isAvailable(module) + } + + fun isAvailable(module: Module): Boolean { + if (ApplicationManager.getApplication().isUnitTestMode) { + return true + } + + val path = ExternalSystemApiUtil.getExternalProjectPath(module) ?: return false + val externalProjectInfo = ExternalSystemUtil.getExternalProjectInfo(module.project, GradleConstants.SYSTEM_ID, path) ?: return false + val moduleData = GradleProjectResolverUtil.findModule(externalProjectInfo.externalProjectStructure, path) ?: return false + return moduleData.getCopyableUserData(ParcelizeProjectResolverExtension.KEY).isEnabled + } +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/ParcelizeProjectResolverExtension.kt b/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/ParcelizeProjectResolverExtension.kt new file mode 100644 index 00000000000..43398895aa6 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/ParcelizeProjectResolverExtension.kt @@ -0,0 +1,33 @@ +/* + * 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.parcelize.ide + +import com.intellij.openapi.externalSystem.model.DataNode +import com.intellij.openapi.externalSystem.model.project.ModuleData +import com.intellij.openapi.util.Key +import org.gradle.tooling.model.idea.IdeaModule +import org.jetbrains.plugins.gradle.service.project.AbstractProjectResolverExtension + +@Suppress("unused") +class ParcelizeProjectResolverExtension : AbstractProjectResolverExtension() { + companion object { + val KEY = Key("ParcelizeModel") + } + + override fun getExtraProjectModelClasses() = setOf(ParcelizeGradleModel::class.java) + override fun getToolingExtensionsClasses() = setOf(ParcelizeModelBuilderService::class.java, Unit::class.java) + + override fun populateModuleExtraModels(gradleModule: IdeaModule, ideModule: DataNode) { + val parcelizeModel = resolverCtx.getExtraProject(gradleModule, ParcelizeGradleModel::class.java) + + if (parcelizeModel != null) { + ideModule.putCopyableUserData(KEY, ParcelizeGradleModelImpl(isEnabled = parcelizeModel.isEnabled)) + } + + super.populateModuleExtraModels(gradleModule, ideModule) + } +} + diff --git a/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/ParcelizeUltraLightClassModifierExtension.kt b/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/ParcelizeUltraLightClassModifierExtension.kt new file mode 100644 index 00000000000..a6c28261697 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/ParcelizeUltraLightClassModifierExtension.kt @@ -0,0 +1,95 @@ +/* + * Copyright 2010-2019 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.parcelize.ide + +import com.intellij.psi.impl.light.LightFieldBuilder +import org.jetbrains.kotlin.parcelize.serializers.ParcelizeExtensionBase +import org.jetbrains.kotlin.asJava.UltraLightClassModifierExtension +import org.jetbrains.kotlin.asJava.classes.KtUltraLightClass +import org.jetbrains.kotlin.asJava.classes.createGeneratedMethodFromDescriptor +import org.jetbrains.kotlin.asJava.elements.KtLightField +import org.jetbrains.kotlin.asJava.elements.KtLightFieldImpl +import org.jetbrains.kotlin.asJava.elements.KtLightMethod +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.idea.util.module +import org.jetbrains.kotlin.parcelize.ParcelizeSyntheticComponent +import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.util.isAnnotated +import org.jetbrains.kotlin.util.isOrdinaryClass + +class ParcelizeUltraLightClassModifierExtension : ParcelizeExtensionBase, UltraLightClassModifierExtension { + private fun tryGetParcelizeClass(declaration: KtDeclaration, descriptor: Lazy): ClassDescriptor? { + if (!declaration.isOrdinaryClass || !declaration.isAnnotated) { + return null + } + + val module = declaration.module + if (module == null || !ParcelizeAvailability.isAvailable(module)) { + return null + } + + val descriptorValue = descriptor.value ?: return null + val parcelizeClass = (descriptorValue as? ClassDescriptor) ?: descriptorValue.containingDeclaration as? ClassDescriptor + + if (parcelizeClass == null || !parcelizeClass.isParcelizeClassDescriptor) { + return null + } + + return parcelizeClass + } + + override fun interceptFieldsBuilding( + declaration: KtDeclaration, + descriptor: Lazy, + containingDeclaration: KtUltraLightClass, + fieldsList: MutableList + ) { + val parcelizeClass = tryGetParcelizeClass(declaration, descriptor) ?: return + if (parcelizeClass.hasCreatorField()) return + + val fieldWrapper = KtLightFieldImpl.KtLightFieldForSourceDeclaration( + origin = null, + computeDelegate = { + LightFieldBuilder("CREATOR", "android.os.Parcelable.Creator", containingDeclaration).also { + it.setModifiers("public", "static", "final") + } + }, + containingClass = containingDeclaration, + dummyDelegate = null + ) + + fieldsList.add(fieldWrapper) + } + + override fun interceptMethodsBuilding( + declaration: KtDeclaration, + descriptor: Lazy, + containingDeclaration: KtUltraLightClass, + methodsList: MutableList + ) { + val parcelizeClass = tryGetParcelizeClass(declaration, descriptor) ?: return + + with(parcelizeClass) { + if (hasSyntheticDescribeContents()) { + findFunction(ParcelizeSyntheticComponent.ComponentKind.DESCRIBE_CONTENTS)?.let { + methodsList.add( + containingDeclaration.createGeneratedMethodFromDescriptor(it) + ) + } + } + + if (hasSyntheticWriteToParcel()) { + findFunction(ParcelizeSyntheticComponent.ComponentKind.WRITE_TO_PARCEL)?.let { + methodsList.add( + containingDeclaration.createGeneratedMethodFromDescriptor(it) + ) + } + } + } + } + +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/quickfixes/AbstractParcelizeQuickFix.kt b/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/quickfixes/AbstractParcelizeQuickFix.kt new file mode 100644 index 00000000000..22e9210dd1e --- /dev/null +++ b/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/quickfixes/AbstractParcelizeQuickFix.kt @@ -0,0 +1,53 @@ +/* + * 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 org.jetbrains.kotlin.parcelize.ide.quickfixes + +import com.intellij.codeInsight.intention.IntentionAction +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.project.Project +import org.jetbrains.kotlin.diagnostics.Diagnostic +import org.jetbrains.kotlin.idea.core.ShortenReferences +import org.jetbrains.kotlin.idea.quickfix.KotlinQuickFixAction +import org.jetbrains.kotlin.idea.quickfix.KotlinSingleIntentionActionFactory +import org.jetbrains.kotlin.psi.KtElement +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.KtPsiFactory +import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType + +abstract class AbstractParcelizeQuickFix(element: T) : KotlinQuickFixAction(element) { + protected companion object { + fun T.shortenReferences() = ShortenReferences.DEFAULT.process(this) + } + + override fun getFamilyName() = text + + abstract fun invoke(ktPsiFactory: KtPsiFactory, element: T) + + final override fun invoke(project: Project, editor: Editor?, file: KtFile) { + val clazz = element ?: return + val ktPsiFactory = KtPsiFactory(project, markGenerated = true) + invoke(ktPsiFactory, clazz) + } + + abstract class AbstractFactory(private val f: Diagnostic.() -> IntentionAction?) : KotlinSingleIntentionActionFactory() { + companion object { + inline fun Diagnostic.findElement() = psiElement.getNonStrictParentOfType() + } + + override fun createAction(diagnostic: Diagnostic) = f(diagnostic) + } +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/quickfixes/AnnotateWithParcelizeQuickFix.kt b/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/quickfixes/AnnotateWithParcelizeQuickFix.kt new file mode 100644 index 00000000000..227d0a4a08e --- /dev/null +++ b/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/quickfixes/AnnotateWithParcelizeQuickFix.kt @@ -0,0 +1,40 @@ +/* + * 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 org.jetbrains.kotlin.parcelize.ide.quickfixes + +import kotlinx.parcelize.Parcelize +import org.jetbrains.kotlin.idea.util.addAnnotation +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.parcelize.diagnostic.ErrorsParcelize +import org.jetbrains.kotlin.parcelize.ide.KotlinParcelizeBundle +import org.jetbrains.kotlin.psi.KtClassOrObject +import org.jetbrains.kotlin.psi.KtPsiFactory + +class AnnotateWithParcelizeQuickFix(clazz: KtClassOrObject) : AbstractParcelizeQuickFix(clazz) { + object Factory : AbstractFactory( + { + val targetClass = ErrorsParcelize.CLASS_SHOULD_BE_PARCELIZE.cast(this).a + AnnotateWithParcelizeQuickFix(targetClass) + } + ) + + override fun getText() = KotlinParcelizeBundle.message("parcelize.fix.annotate.containing.class.with.parcelize") + + override fun invoke(ktPsiFactory: KtPsiFactory, element: KtClassOrObject) { + element.addAnnotation(FqName(Parcelize::class.java.name)) + } +} diff --git a/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/quickfixes/ParcelMigrateToParcelizeQuickFix.kt b/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/quickfixes/ParcelMigrateToParcelizeQuickFix.kt new file mode 100644 index 00000000000..97442c9a055 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/quickfixes/ParcelMigrateToParcelizeQuickFix.kt @@ -0,0 +1,291 @@ +/* + * 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 org.jetbrains.kotlin.parcelize.ide.quickfixes + +import com.intellij.openapi.diagnostic.Logger +import kotlinx.parcelize.Parceler +import org.jetbrains.kotlin.parcelize.ANDROID_PARCELABLE_CREATOR_CLASS_FQNAME +import org.jetbrains.kotlin.parcelize.ANDROID_PARCEL_CLASS_FQNAME +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.builtins.StandardNames +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.ConstructorDescriptor +import org.jetbrains.kotlin.idea.caches.resolve.analyze +import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall +import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny +import org.jetbrains.kotlin.idea.core.getOrCreateCompanionObject +import org.jetbrains.kotlin.idea.intentions.branchedTransformations.unwrapBlockOrParenthesis +import org.jetbrains.kotlin.idea.util.findAnnotation +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.load.java.JvmAbi.JVM_FIELD_ANNOTATION_FQ_NAME +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.parcelize.ide.KotlinParcelizeBundle +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.addRemoveModifier.setModifierList +import org.jetbrains.kotlin.psi.psiUtil.containingClass +import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject +import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType +import org.jetbrains.kotlin.psi.typeRefHelpers.setReceiverTypeReference +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe +import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperClassifiers +import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode +import org.jetbrains.kotlin.resolve.source.KotlinSourceElement +import org.jetbrains.kotlin.types.TypeUtils + +class ParcelMigrateToParcelizeQuickFix(function: KtClass) : AbstractParcelizeQuickFix(function) { + companion object { + private val PARCELER_FQNAME = FqName(Parceler::class.java.name) + private val PARCELER_WRITE_FUNCTION_NAME = Name.identifier("write") + private val PARCELER_CREATE_FUNCTION_NAME = Name.identifier("create") + private val LOG = Logger.getInstance(ParcelMigrateToParcelizeQuickFix::class.java) + + private fun KtClass.findParcelerCompanionObject(): Pair? { + for (obj in companionObjects) { + val objDescriptor = obj.resolveToDescriptorIfAny() ?: continue + for (superClassifier in objDescriptor.getAllSuperClassifiers()) { + val superClass = superClassifier as? ClassDescriptor ?: continue + if (superClass.fqNameSafe == PARCELER_FQNAME) return Pair(obj, objDescriptor) + } + } + + return null + } + + private fun KtNamedFunction.doesLookLikeWriteToParcelOverride(): Boolean { + return name == "writeToParcel" + && hasModifier(KtTokens.OVERRIDE_KEYWORD) + && receiverTypeReference == null + && valueParameters.size == 2 + && typeParameters.size == 0 + && valueParameters[0].typeReference?.getFqName() == ANDROID_PARCEL_CLASS_FQNAME.asString() + && valueParameters[1].typeReference?.getFqName() == StandardNames.FqNames._int.asString() + } + + private fun KtNamedFunction.doesLookLikeNewArrayOverride(): Boolean { + return name == "newArray" + && hasModifier(KtTokens.OVERRIDE_KEYWORD) + && receiverTypeReference == null + && valueParameters.size == 1 + && typeParameters.size == 0 + && valueParameters[0].typeReference?.getFqName() == StandardNames.FqNames._int.asString() + } + + private fun KtNamedFunction.doesLookLikeDescribeContentsOverride(): Boolean { + return name == "describeContents" + && hasModifier(KtTokens.OVERRIDE_KEYWORD) + && receiverTypeReference == null + && valueParameters.size == 0 + && typeParameters.size == 0 + && typeReference?.getFqName() == StandardNames.FqNames._int.asString() + } + + private fun KtClass.findWriteToParcelOverride() = findFunction { doesLookLikeWriteToParcelOverride() } + private fun KtClass.findDescribeContentsOverride() = findFunction { doesLookLikeDescribeContentsOverride() } + private fun KtObjectDeclaration.findNewArrayOverride() = findFunction { doesLookLikeNewArrayOverride() } + + private fun KtClass.findCreatorClass(): KtClassOrObject? { + for (companion in companionObjects) { + if (companion.name == "CREATOR") { + return companion + } + + val creatorProperty = companion.declarations.asSequence() + .filterIsInstance() + .firstOrNull { it.name == "CREATOR" } + ?: continue + + creatorProperty.findAnnotation(JVM_FIELD_ANNOTATION_FQ_NAME) ?: continue + + val initializer = creatorProperty.initializer ?: continue + when (initializer) { + is KtObjectLiteralExpression -> return initializer.objectDeclaration + is KtCallExpression -> { + val constructedClass = (initializer.resolveToCall() + ?.resultingDescriptor as? ConstructorDescriptor)?.constructedClass + if (constructedClass != null) { + val sourceElement = constructedClass.source as? KotlinSourceElement + (sourceElement?.psi as? KtClassOrObject)?.let { return it } + } + } + } + } + + return null + } + + private fun KtNamedFunction.doesLookLikeCreateFromParcelOverride(): Boolean { + return name == "createFromParcel" + && hasModifier(KtTokens.OVERRIDE_KEYWORD) + && receiverTypeReference == null + && valueParameters.size == 1 + && typeParameters.size == 0 + && valueParameters[0].typeReference?.getFqName() == ANDROID_PARCEL_CLASS_FQNAME.asString() + } + + private fun findCreateFromParcel(creator: KtClassOrObject) = creator.findFunction { doesLookLikeCreateFromParcelOverride() } + + private fun KtNamedFunction.doesLookLikeWriteImplementation(): Boolean { + val containingParcelableClassFqName = containingClassOrObject?.containingClass()?.fqName?.asString() + + return name == PARCELER_WRITE_FUNCTION_NAME.asString() + && hasModifier(KtTokens.OVERRIDE_KEYWORD) + && receiverTypeReference?.getFqName() == containingParcelableClassFqName + && valueParameters.size == 2 + && typeParameters.size == 0 + && valueParameters[0].typeReference?.getFqName() == ANDROID_PARCEL_CLASS_FQNAME.asString() + && valueParameters[1].typeReference?.getFqName() == StandardNames.FqNames._int.asString() + } + + private fun KtNamedFunction.doesLookLikeCreateImplementation(): Boolean { + return name == PARCELER_CREATE_FUNCTION_NAME.asString() + && hasModifier(KtTokens.OVERRIDE_KEYWORD) + && receiverTypeReference == null + && valueParameters.size == 1 + && typeParameters.size == 0 + && valueParameters[0].typeReference?.getFqName() == ANDROID_PARCEL_CLASS_FQNAME.asString() + } + + private fun KtObjectDeclaration.findCreateImplementation() = findFunction { doesLookLikeCreateImplementation() } + private fun KtObjectDeclaration.findWriteImplementation() = findFunction { doesLookLikeWriteImplementation() } + + private fun KtClassOrObject.findFunction(f: KtNamedFunction.() -> Boolean) = + declarations.asSequence().filterIsInstance().firstOrNull(f) + + private fun KtTypeReference.getFqName(): String? = analyze(BodyResolveMode.PARTIAL)[BindingContext.TYPE, this] + ?.constructor?.declarationDescriptor?.fqNameSafe?.asString() + } + + object FactoryForWrite : AbstractFactory({ findElement()?.let { ParcelMigrateToParcelizeQuickFix(it) } }) + + object FactoryForCREATOR : AbstractFactory({ + findElement()?.getStrictParentOfType() + ?.let { ParcelMigrateToParcelizeQuickFix(it) } + }) + + override fun getText() = KotlinParcelizeBundle.message("parcelize.fix.migrate.to.parceler.companion.object") + + @Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE") + override fun invoke(ktPsiFactory: KtPsiFactory, parcelableClass: KtClass) { + val parcelerObject = parcelableClass.findParcelerCompanionObject()?.first ?: parcelableClass.getOrCreateCompanionObject() + val bindingContext = parcelerObject.analyze(BodyResolveMode.PARTIAL) + + val parcelerTypeArg = parcelableClass.name ?: run { + LOG.error("Parceler class should not be an anonymous class") + return + } + + val parcelerObjectDescriptor = bindingContext[BindingContext.CLASS, parcelerObject] ?: run { + LOG.error("Unable to resolve parceler object for ${parcelableClass.name ?: ""}") + return + } + + if (!parcelerObjectDescriptor.getAllSuperClassifiers().any { it.fqNameSafe == PARCELER_FQNAME }) { + val entryText = PARCELER_FQNAME.asString() + "<" + parcelerTypeArg + ">" + parcelerObject.addSuperTypeListEntry(ktPsiFactory.createSuperTypeEntry(entryText)).shortenReferences() + } + + val oldWriteToParcelFunction = parcelableClass.findWriteToParcelOverride() + val oldCreateFromParcelFunction = parcelableClass.findCreatorClass()?.let { findCreateFromParcel(it) } + + for (superTypeEntry in parcelerObject.superTypeListEntries) { + val superClass = + bindingContext[BindingContext.TYPE, superTypeEntry.typeReference]?.constructor?.declarationDescriptor ?: continue + if (superClass.getAllSuperClassifiers().any { it.fqNameSafe == ANDROID_PARCELABLE_CREATOR_CLASS_FQNAME }) { + parcelerObject.removeSuperTypeListEntry(superTypeEntry) + } + } + + if (parcelerObject.name == "CREATOR") { + parcelerObject.nameIdentifier?.delete() + } + + if (oldWriteToParcelFunction != null) { + parcelerObject.findWriteImplementation()?.delete() // Remove old implementation + + val newFunction = oldWriteToParcelFunction.copy() as KtFunction + oldWriteToParcelFunction.delete() + + newFunction.setName(PARCELER_WRITE_FUNCTION_NAME.asString()) + newFunction.setModifierList(ktPsiFactory.createModifierList(KtTokens.OVERRIDE_KEYWORD)) + newFunction.setReceiverTypeReference(ktPsiFactory.createType(parcelerTypeArg)) + newFunction.valueParameterList?.apply { + assert(parameters.size == 2) + val parcelParameterName = parameters[0].name ?: "parcel" + val flagsParameterName = parameters[1].name ?: "flags" + + repeat(parameters.size) { removeParameter(0) } + addParameter(ktPsiFactory.createParameter("$parcelParameterName : ${ANDROID_PARCEL_CLASS_FQNAME.asString()}")) + addParameter(ktPsiFactory.createParameter("$flagsParameterName : Int")) + } + + parcelerObject.addDeclaration(newFunction).valueParameterList?.shortenReferences() + } else if (parcelerObject.findWriteImplementation() == null) { + val writeFunction = "fun $parcelerTypeArg.write(parcel: ${ANDROID_PARCEL_CLASS_FQNAME.asString()}, flags: Int) = TODO()" + parcelerObject.addDeclaration(ktPsiFactory.createFunction(writeFunction)).valueParameterList?.shortenReferences() + } + + if (oldCreateFromParcelFunction != null) { + parcelerObject.findCreateImplementation()?.delete() // Remove old implementation + + val newFunction = oldCreateFromParcelFunction.copy() as KtFunction + if (oldCreateFromParcelFunction.containingClassOrObject == parcelerObject) { + oldCreateFromParcelFunction.delete() + } + + newFunction.setName(PARCELER_CREATE_FUNCTION_NAME.asString()) + newFunction.setModifierList(ktPsiFactory.createModifierList(KtTokens.OVERRIDE_KEYWORD)) + newFunction.setReceiverTypeReference(null) + newFunction.valueParameterList?.apply { + assert(parameters.size == 1) + val parcelParameterName = parameters[0].name ?: "parcel" + + removeParameter(0) + addParameter(ktPsiFactory.createParameter("$parcelParameterName : ${ANDROID_PARCEL_CLASS_FQNAME.asString()}")) + } + + parcelerObject.addDeclaration(newFunction).valueParameterList?.shortenReferences() + } else if (parcelerObject.findCreateImplementation() == null) { + val createFunction = "override fun create(parcel: ${ANDROID_PARCEL_CLASS_FQNAME.asString()}): $parcelerTypeArg = TODO()" + parcelerObject.addDeclaration(ktPsiFactory.createFunction(createFunction)).valueParameterList?.shortenReferences() + } + + // Always use the default newArray() implementation + parcelerObject.findNewArrayOverride()?.delete() + + parcelableClass.findDescribeContentsOverride()?.let { describeContentsFunction -> + val returnExpr = describeContentsFunction.bodyExpression?.unwrapBlockOrParenthesis() + if (returnExpr is KtReturnExpression && returnExpr.getTargetLabel() == null) { + val returnValue = returnExpr.analyze()[BindingContext.COMPILE_TIME_VALUE, returnExpr.returnedExpression] + ?.getValue(TypeUtils.NO_EXPECTED_TYPE) + if (returnValue == 0) { + // There are no additional overrides in the hierarchy + if (bindingContext[BindingContext.FUNCTION, describeContentsFunction]?.overriddenDescriptors?.size == 1) { + describeContentsFunction.delete() + } + } + } + } + + for (property in parcelerObject.declarations.asSequence().filterIsInstance().filter { it.name == "CREATOR" }) { + if (property.findAnnotation(JVM_FIELD_ANNOTATION_FQ_NAME) != null) { + property.delete() + } + } + } +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/quickfixes/ParcelRemoveCustomCreatorProperty.kt b/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/quickfixes/ParcelRemoveCustomCreatorProperty.kt new file mode 100644 index 00000000000..fbed4497563 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/quickfixes/ParcelRemoveCustomCreatorProperty.kt @@ -0,0 +1,35 @@ +/* + * 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 org.jetbrains.kotlin.parcelize.ide.quickfixes + +import org.jetbrains.kotlin.parcelize.ide.KotlinParcelizeBundle +import org.jetbrains.kotlin.psi.KtProperty +import org.jetbrains.kotlin.psi.KtPsiFactory + +class ParcelRemoveCustomCreatorProperty(property: KtProperty) : AbstractParcelizeQuickFix(property) { + object Factory : AbstractFactory(f@ { + // KtProperty or its name identifier + psiElement as? KtProperty ?: (psiElement.parent as? KtProperty) ?: return@f null + findElement()?.let(::ParcelRemoveCustomCreatorProperty) + }) + + override fun getText() = KotlinParcelizeBundle.message("parcelize.fix.remove.custom.creator.property") + + override fun invoke(ktPsiFactory: KtPsiFactory, element: KtProperty) { + element.delete() + } +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/quickfixes/ParcelRemoveCustomWriteToParcel.kt b/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/quickfixes/ParcelRemoveCustomWriteToParcel.kt new file mode 100644 index 00000000000..ee00ff728e3 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/quickfixes/ParcelRemoveCustomWriteToParcel.kt @@ -0,0 +1,31 @@ +/* + * 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 org.jetbrains.kotlin.parcelize.ide.quickfixes + +import org.jetbrains.kotlin.parcelize.ide.KotlinParcelizeBundle +import org.jetbrains.kotlin.psi.KtFunction +import org.jetbrains.kotlin.psi.KtPsiFactory + +class ParcelRemoveCustomWriteToParcel(function: KtFunction) : AbstractParcelizeQuickFix(function) { + object Factory : AbstractFactory({ findElement()?.let(::ParcelRemoveCustomWriteToParcel) }) + + override fun getText() = KotlinParcelizeBundle.message("parcelize.fix.remove.custom.write.to.parcel.function") + + override fun invoke(ktPsiFactory: KtPsiFactory, element: KtFunction) { + element.delete() + } +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/quickfixes/ParcelizeAddIgnoreOnParcelAnnotationQuickFix.kt b/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/quickfixes/ParcelizeAddIgnoreOnParcelAnnotationQuickFix.kt new file mode 100644 index 00000000000..08a0aa6e380 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/quickfixes/ParcelizeAddIgnoreOnParcelAnnotationQuickFix.kt @@ -0,0 +1,32 @@ +/* + * 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 org.jetbrains.kotlin.parcelize.ide.quickfixes + +import kotlinx.parcelize.IgnoredOnParcel +import org.jetbrains.kotlin.parcelize.ide.KotlinParcelizeBundle +import org.jetbrains.kotlin.psi.KtProperty +import org.jetbrains.kotlin.psi.KtPsiFactory + +class ParcelizeAddIgnoreOnParcelAnnotationQuickFix(property: KtProperty) : AbstractParcelizeQuickFix(property) { + object Factory : AbstractFactory({ findElement()?.let(::ParcelizeAddIgnoreOnParcelAnnotationQuickFix) }) + + override fun getText() = KotlinParcelizeBundle.message("parcelize.fix.add.ignored.on.parcel.annotation") + + override fun invoke(ktPsiFactory: KtPsiFactory, element: KtProperty) { + element.addAnnotationEntry(ktPsiFactory.createAnnotationEntry("@" + IgnoredOnParcel::class.java.name)).shortenReferences() + } +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/quickfixes/ParcelizeAddPrimaryConstructorQuickFix.kt b/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/quickfixes/ParcelizeAddPrimaryConstructorQuickFix.kt new file mode 100644 index 00000000000..6463a9e3d64 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/quickfixes/ParcelizeAddPrimaryConstructorQuickFix.kt @@ -0,0 +1,40 @@ +/* + * 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 org.jetbrains.kotlin.parcelize.ide.quickfixes + +import org.jetbrains.kotlin.parcelize.ide.KotlinParcelizeBundle +import org.jetbrains.kotlin.psi.KtClass +import org.jetbrains.kotlin.psi.KtPsiFactory +import org.jetbrains.kotlin.psi.createPrimaryConstructorIfAbsent + +class ParcelizeAddPrimaryConstructorQuickFix(clazz: KtClass) : AbstractParcelizeQuickFix(clazz) { + object Factory : AbstractFactory({ findElement()?.let(::ParcelizeAddPrimaryConstructorQuickFix) }) + + override fun getText() = KotlinParcelizeBundle.message("parcelize.fix.add.empty.primary.constructor") + + override fun invoke(ktPsiFactory: KtPsiFactory, element: KtClass) { + element.createPrimaryConstructorIfAbsent() + + for (secondaryConstructor in element.secondaryConstructors) { + if (secondaryConstructor.getDelegationCall().isImplicit) { + val parameterList = secondaryConstructor.valueParameterList ?: return + val colon = secondaryConstructor.addAfter(ktPsiFactory.createColon(), parameterList) + secondaryConstructor.addAfter(ktPsiFactory.createExpression("this()"), colon) + } + } + } +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/quickfixes/ParcelizeAddSupertypeQuickFix.kt b/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/quickfixes/ParcelizeAddSupertypeQuickFix.kt new file mode 100644 index 00000000000..0c6bfa4357a --- /dev/null +++ b/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/quickfixes/ParcelizeAddSupertypeQuickFix.kt @@ -0,0 +1,32 @@ +/* + * 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 org.jetbrains.kotlin.parcelize.ide.quickfixes + +import org.jetbrains.kotlin.parcelize.ANDROID_PARCELABLE_CLASS_FQNAME +import org.jetbrains.kotlin.parcelize.ide.KotlinParcelizeBundle +import org.jetbrains.kotlin.psi.* + +class ParcelizeAddSupertypeQuickFix(clazz: KtClassOrObject) : AbstractParcelizeQuickFix(clazz) { + object Factory : AbstractFactory({ findElement()?.let(::ParcelizeAddSupertypeQuickFix) }) + + override fun getText() = KotlinParcelizeBundle.message("parcelize.fix.add.parcelable.supertype") + + override fun invoke(ktPsiFactory: KtPsiFactory, element: KtClassOrObject) { + val supertypeName = ANDROID_PARCELABLE_CLASS_FQNAME.asString() + element.addSuperTypeListEntry(ktPsiFactory.createSuperTypeEntry(supertypeName)).shortenReferences() + } +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/quickfixes/ParcelizeQuickFixContributor.kt b/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/quickfixes/ParcelizeQuickFixContributor.kt new file mode 100644 index 00000000000..2c6da3b93b4 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/quickfixes/ParcelizeQuickFixContributor.kt @@ -0,0 +1,45 @@ +/* + * 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 org.jetbrains.kotlin.parcelize.ide.quickfixes + +import org.jetbrains.kotlin.idea.quickfix.QuickFixContributor +import org.jetbrains.kotlin.idea.quickfix.QuickFixes +import org.jetbrains.kotlin.idea.quickfix.RemoveModifierFix +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.parcelize.diagnostic.ErrorsParcelize + +class ParcelizeQuickFixContributor : QuickFixContributor { + override fun registerQuickFixes(quickFixes: QuickFixes) { + quickFixes.register( + ErrorsParcelize.PARCELABLE_CANT_BE_INNER_CLASS, + RemoveModifierFix.createRemoveModifierFromListOwnerFactory(KtTokens.INNER_KEYWORD, false) + ) + + quickFixes.register(ErrorsParcelize.NO_PARCELABLE_SUPERTYPE, ParcelizeAddSupertypeQuickFix.Factory) + quickFixes.register(ErrorsParcelize.PARCELABLE_SHOULD_HAVE_PRIMARY_CONSTRUCTOR, ParcelizeAddPrimaryConstructorQuickFix.Factory) + quickFixes.register(ErrorsParcelize.PROPERTY_WONT_BE_SERIALIZED, ParcelizeAddIgnoreOnParcelAnnotationQuickFix.Factory) + + quickFixes.register(ErrorsParcelize.OVERRIDING_WRITE_TO_PARCEL_IS_NOT_ALLOWED, ParcelMigrateToParcelizeQuickFix.FactoryForWrite) + quickFixes.register(ErrorsParcelize.OVERRIDING_WRITE_TO_PARCEL_IS_NOT_ALLOWED, ParcelRemoveCustomWriteToParcel.Factory) + + quickFixes.register(ErrorsParcelize.CREATOR_DEFINITION_IS_NOT_ALLOWED, ParcelMigrateToParcelizeQuickFix.FactoryForCREATOR) + quickFixes.register(ErrorsParcelize.CREATOR_DEFINITION_IS_NOT_ALLOWED, ParcelRemoveCustomCreatorProperty.Factory) + + quickFixes.register(ErrorsParcelize.REDUNDANT_TYPE_PARCELER, ParcelizeRemoveDuplicatingTypeParcelerAnnotationQuickFix.Factory) + quickFixes.register(ErrorsParcelize.CLASS_SHOULD_BE_PARCELIZE, AnnotateWithParcelizeQuickFix.Factory) + } +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/quickfixes/ParcelizeRemoveDuplicatingTypeParcelerAnnotationQuickFix.kt b/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/quickfixes/ParcelizeRemoveDuplicatingTypeParcelerAnnotationQuickFix.kt new file mode 100644 index 00000000000..7489d7b038d --- /dev/null +++ b/plugins/parcelize/parcelize-ide/src/org/jetbrains/kotlin/parcelize/ide/quickfixes/ParcelizeRemoveDuplicatingTypeParcelerAnnotationQuickFix.kt @@ -0,0 +1,31 @@ +/* + * 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 org.jetbrains.kotlin.parcelize.ide.quickfixes + +import org.jetbrains.kotlin.parcelize.ide.KotlinParcelizeBundle +import org.jetbrains.kotlin.psi.KtAnnotationEntry +import org.jetbrains.kotlin.psi.KtPsiFactory + +class ParcelizeRemoveDuplicatingTypeParcelerAnnotationQuickFix(anno: KtAnnotationEntry) : AbstractParcelizeQuickFix(anno) { + object Factory : AbstractFactory({ findElement()?.let(::ParcelizeRemoveDuplicatingTypeParcelerAnnotationQuickFix) }) + + override fun getText() = KotlinParcelizeBundle.message("parcelize.fix.remove.redundant.type.parceler.annotation") + + override fun invoke(ktPsiFactory: KtPsiFactory, element: KtAnnotationEntry) { + element.delete() + } +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/testData/checker/constructors.kt b/plugins/parcelize/parcelize-ide/testData/checker/constructors.kt new file mode 100644 index 00000000000..c4339ce51e5 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/checker/constructors.kt @@ -0,0 +1,29 @@ +// WITH_RUNTIME +package test + +import kotlinx.parcelize.Parcelize +import android.os.Parcelable + +@Parcelize +class A : Parcelable + +@Parcelize +class B(val firstName: String, val secondName: String) : Parcelable + +@Parcelize +class C(val firstName: String, secondName: String) : Parcelable + +@Parcelize +class D(val firstName: String, vararg val secondName: String) : Parcelable + +@Parcelize +class E(val firstName: String, val secondName: String) : Parcelable { + constructor() : this("", "") +} + +@Parcelize +class F : Parcelable { + constructor(a: String) { + println(a) + } +} diff --git a/plugins/parcelize/parcelize-ide/testData/checker/customCreator.kt b/plugins/parcelize/parcelize-ide/testData/checker/customCreator.kt new file mode 100644 index 00000000000..99cb74e45ad --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/checker/customCreator.kt @@ -0,0 +1,25 @@ +// WITH_RUNTIME +package test + +import kotlinx.parcelize.Parcelize +import android.os.Parcelable +import android.os.Parcel + +@Parcelize +class A(val a: String) : Parcelable { + companion object { + @JvmField + val CREATOR = object : Parcelable.Creator { + override fun createFromParcel(source: Parcel): A = A("") + override fun newArray(size: Int) = arrayOfNulls(size) + } + } +} + +@Parcelize +class B(val b: String) : Parcelable { + companion object CREATOR : Parcelable.Creator { + override fun createFromParcel(source: Parcel): B = B("") + override fun newArray(size: Int) = arrayOfNulls(size) + } +} diff --git a/plugins/parcelize/parcelize-ide/testData/checker/customParcelers.kt b/plugins/parcelize/parcelize-ide/testData/checker/customParcelers.kt new file mode 100644 index 00000000000..2c6dd4f4399 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/checker/customParcelers.kt @@ -0,0 +1,45 @@ +// WITH_RUNTIME +package test + +import kotlinx.parcelize.* +import android.os.* + +object StringParceler : Parceler { + override fun create(parcel: Parcel) = TODO() + override fun String.write(parcel: Parcel, flags: Int) = TODO() +} + +object CharSequenceParceler : Parceler { + override fun create(parcel: Parcel) = TODO() + override fun CharSequence.write(parcel: Parcel, flags: Int) = TODO() +} + +class StringClassParceler : Parceler { + override fun create(parcel: Parcel) = TODO() + override fun String.write(parcel: Parcel, flags: Int) = TODO() +} + +@TypeParceler +class MissingParcelizeAnnotation(val a: @WriteWith String) + +@Parcelize +@TypeParceler +class ShouldBeClass(val a: @WriteWith String) : Parcelable + +@Parcelize +class Test( + val a: @WriteWith Int, + val b: @WriteWith String, + val c: @WriteWith<StringParceler> CharSequence, + val d: @WriteWith String, + val e: @WriteWith CharSequence +) : Parcelable + +@Parcelize +@TypeParceler +class Test2(@TypeParceler val a: String) : Parcelable + +@Parcelize +@TypeParceler<String, StringParceler> +@TypeParceler<String, CharSequenceParceler> +class Test3(val a: String) : Parcelable diff --git a/plugins/parcelize/parcelize-ide/testData/checker/customWriteToParcel.kt b/plugins/parcelize/parcelize-ide/testData/checker/customWriteToParcel.kt new file mode 100644 index 00000000000..cc58d67b9fd --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/checker/customWriteToParcel.kt @@ -0,0 +1,21 @@ +package test + +import kotlinx.parcelize.Parcelize +import android.os.Parcelable +import android.os.Parcel + +@Parcelize +class A(val a: String) : Parcelable { + override fun writeToParcel(p: Parcel?, flags: Int) {} + override fun describeContents() = 0 +} + +@Parcelize +class B(val a: String) : Parcelable { + override fun writeToParcel(p: Parcel?, flags: Int) {} +} + +@Parcelize +class C(val a: String) : Parcelable { + override fun writeToParcel(p: Parcel, flags: Int) {} +} diff --git a/plugins/parcelize/parcelize-ide/testData/checker/delegate.kt b/plugins/parcelize/parcelize-ide/testData/checker/delegate.kt new file mode 100644 index 00000000000..3180218dd08 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/checker/delegate.kt @@ -0,0 +1,13 @@ +package test + +import kotlinx.parcelize.Parcelize +import android.os.Parcelable +import android.os.Parcel + +open class Delegate : Parcelable { + override fun writeToParcel(dest: Parcel?, flags: Int) {} + override fun describeContents() = 0 +} + +@Parcelize +class Test : Parcelable by Delegate() diff --git a/plugins/parcelize/parcelize-ide/testData/checker/emptyPrimaryConstructor.kt b/plugins/parcelize/parcelize-ide/testData/checker/emptyPrimaryConstructor.kt new file mode 100644 index 00000000000..32fe413f297 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/checker/emptyPrimaryConstructor.kt @@ -0,0 +1,10 @@ +package test + +import kotlinx.parcelize.Parcelize +import android.os.Parcelable + +@Parcelize +class User : Parcelable + +@Parcelize +class User2() : Parcelable diff --git a/plugins/parcelize/parcelize-ide/testData/checker/kt20062.kt b/plugins/parcelize/parcelize-ide/testData/checker/kt20062.kt new file mode 100644 index 00000000000..ce1c60e1555 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/checker/kt20062.kt @@ -0,0 +1,20 @@ +package test + +import kotlinx.parcelize.* +import android.os.* + +class Box(val value: String) + +@Parcelize +class Foo(val box: Box): Parcelable { + companion object : Parceler { + override fun create(parcel: Parcel) = Foo(Box(parcel.readString())) + + override fun Foo.write(parcel: Parcel, flags: Int) { + parcel.writeString(box.value) + } + } +} + +@Parcelize +class Foo2(val box: Box): Parcelable diff --git a/plugins/parcelize/parcelize-ide/testData/checker/modality.kt b/plugins/parcelize/parcelize-ide/testData/checker/modality.kt new file mode 100644 index 00000000000..c600f43f6a4 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/checker/modality.kt @@ -0,0 +1,31 @@ +package test + +import kotlinx.parcelize.Parcelize +import android.os.Parcelable + +@Parcelize +open class Open(val foo: String) : Parcelable + +@Parcelize +class Final(val foo: String) : Parcelable + +@Parcelize +abstract class Abstract(val foo: String) : Parcelable + +@Parcelize +sealed class Sealed(val foo: String) : Parcelable { + class X : Sealed("") +} + +class Outer { + @Parcelize + inner class Inner(val foo: String) : Parcelable +} + +fun foo() { + @Parcelize + object : Parcelable {} + + @Parcelize + class Local {} +} diff --git a/plugins/parcelize/parcelize-ide/testData/checker/notMagicParcel.kt b/plugins/parcelize/parcelize-ide/testData/checker/notMagicParcel.kt new file mode 100644 index 00000000000..2c84e641e62 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/checker/notMagicParcel.kt @@ -0,0 +1,11 @@ +package test + +import kotlinx.parcelize.Parcelize +import android.os.Parcel +import android.os.Parcelable + +@Suppress("UNUSED_PARAMETER") +class User(firstName: String, secondName: String, val age: Int) : Parcelable { + override fun writeToParcel(p0: Parcel?, p1: Int) {} + override fun describeContents() = 0 +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/testData/checker/properties.kt b/plugins/parcelize/parcelize-ide/testData/checker/properties.kt new file mode 100644 index 00000000000..d03bad9957d --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/checker/properties.kt @@ -0,0 +1,37 @@ +// WITH_RUNTIME +package test + +import kotlinx.parcelize.* +import android.os.Parcelable + +@Parcelize +class A(val firstName: String) : Parcelable { + val secondName: String = "" + + val delegated by lazy { "" } + + lateinit var lateinit: String + + val customGetter: String + get() = "" + + var customSetter: String + get() = "" + set(v) {} +} + +@Parcelize +@Suppress("WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET") +class B(@IgnoredOnParcel val firstName: String) : Parcelable { + @IgnoredOnParcel + var a: String = "" + + @field:IgnoredOnParcel + var b: String = "" + + @get:IgnoredOnParcel + var c: String = "" + + @set:IgnoredOnParcel + var d: String = "" +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/testData/checker/simple.kt b/plugins/parcelize/parcelize-ide/testData/checker/simple.kt new file mode 100644 index 00000000000..7b58d8b8d41 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/checker/simple.kt @@ -0,0 +1,7 @@ +package test + +import kotlinx.parcelize.Parcelize +import android.os.Parcelable + +@Parcelize +class User(val firstName: String, val secondName: String, val age: Int) : Parcelable \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/testData/checker/unsupportedType.kt b/plugins/parcelize/parcelize-ide/testData/checker/unsupportedType.kt new file mode 100644 index 00000000000..df165968100 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/checker/unsupportedType.kt @@ -0,0 +1,17 @@ +package test + +import kotlinx.parcelize.Parcelize +import kotlinx.parcelize.RawValue +import android.os.Parcelable + +@Parcelize +class User( + val a: String, + val b: Any, + val c: Any?, + val d: Map, + val e: @RawValue Any?, + val f: @RawValue Map, + val g: Map, + val h: Map<@RawValue Any, List<@RawValue Any>> +) : Parcelable diff --git a/plugins/parcelize/parcelize-ide/testData/checker/withoutParcelableSupertype.kt b/plugins/parcelize/parcelize-ide/testData/checker/withoutParcelableSupertype.kt new file mode 100644 index 00000000000..2949d0edc6c --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/checker/withoutParcelableSupertype.kt @@ -0,0 +1,20 @@ +package test + +import kotlinx.parcelize.Parcelize +import android.os.Parcelable + +@Parcelize +class Without(val firstName: String, val secondName: String, val age: Int) + +@Parcelize +class With(val firstName: String, val secondName: String, val age: Int) : Parcelable + +interface MyParcelableIntf : Parcelable + +abstract class MyParcelableCl : Parcelable + +@Parcelize +class WithIntfSubtype(val firstName: String, val secondName: String, val age: Int) : MyParcelableIntf + +@Parcelize +class WithClSubtype(val firstName: String, val secondName: String, val age: Int) : MyParcelableCl() diff --git a/plugins/parcelize/parcelize-ide/testData/checker/wrongAnnotationTarget.kt b/plugins/parcelize/parcelize-ide/testData/checker/wrongAnnotationTarget.kt new file mode 100644 index 00000000000..c6a1571ad32 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/checker/wrongAnnotationTarget.kt @@ -0,0 +1,25 @@ +package test + +import kotlinx.parcelize.Parcelize +import android.os.Parcelable + +@Parcelize +interface Intf : Parcelable + +@Parcelize +object Obj + +class A { + @Parcelize + companion object { + fun foo() {} + } +} + +@Parcelize +enum class Enum { + WHITE, BLACK +} + +@Parcelize +annotation class Anno diff --git a/plugins/parcelize/parcelize-ide/testData/quickfix/addPrimaryConstructor/constructorWithDelegate.kt b/plugins/parcelize/parcelize-ide/testData/quickfix/addPrimaryConstructor/constructorWithDelegate.kt new file mode 100644 index 00000000000..53b2a7d76b6 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/quickfix/addPrimaryConstructor/constructorWithDelegate.kt @@ -0,0 +1,13 @@ +// "Add empty primary constructor" "true" +// WITH_RUNTIME + +package com.myapp.activity + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +class Test : Parcelable { + constructor(s: String) + constructor(s: String, i: Int) : this(s) +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/testData/quickfix/addPrimaryConstructor/constructorWithDelegate.kt.after b/plugins/parcelize/parcelize-ide/testData/quickfix/addPrimaryConstructor/constructorWithDelegate.kt.after new file mode 100644 index 00000000000..07786288a72 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/quickfix/addPrimaryConstructor/constructorWithDelegate.kt.after @@ -0,0 +1,13 @@ +// "Add empty primary constructor" "true" +// WITH_RUNTIME + +package com.myapp.activity + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +class Test() : Parcelable { + constructor(s: String) : this() + constructor(s: String, i: Int) : this(s) +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/testData/quickfix/addPrimaryConstructor/noQuickFix.kt b/plugins/parcelize/parcelize-ide/testData/quickfix/addPrimaryConstructor/noQuickFix.kt new file mode 100644 index 00000000000..96b2f5aa704 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/quickfix/addPrimaryConstructor/noQuickFix.kt @@ -0,0 +1,11 @@ +// "Add empty primary constructor" "false" +// IGNORE_IRRELEVANT_ACTIONS +// WITH_RUNTIME + +package com.myapp.activity + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +class Test() : Parcelable \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/testData/quickfix/addPrimaryConstructor/simple.kt b/plugins/parcelize/parcelize-ide/testData/quickfix/addPrimaryConstructor/simple.kt new file mode 100644 index 00000000000..f1935d1b494 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/quickfix/addPrimaryConstructor/simple.kt @@ -0,0 +1,12 @@ +// "Add empty primary constructor" "true" +// WITH_RUNTIME + +package com.myapp.activity + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +class Test : Parcelable { + constructor(a: Int) +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/testData/quickfix/addPrimaryConstructor/simple.kt.after b/plugins/parcelize/parcelize-ide/testData/quickfix/addPrimaryConstructor/simple.kt.after new file mode 100644 index 00000000000..f21beff2647 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/quickfix/addPrimaryConstructor/simple.kt.after @@ -0,0 +1,12 @@ +// "Add empty primary constructor" "true" +// WITH_RUNTIME + +package com.myapp.activity + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +class Test() : Parcelable { + constructor(a: Int) : this() +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/testData/quickfix/cantBeInnerClass/simple.kt b/plugins/parcelize/parcelize-ide/testData/quickfix/cantBeInnerClass/simple.kt new file mode 100644 index 00000000000..3a089ea46dd --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/quickfix/cantBeInnerClass/simple.kt @@ -0,0 +1,12 @@ +// "Remove 'inner' modifier" "true" +// WITH_RUNTIME + +package com.myapp.activity + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +class Foo { + @Parcelize + inner class Bar : Parcelable +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/testData/quickfix/cantBeInnerClass/simple.kt.after b/plugins/parcelize/parcelize-ide/testData/quickfix/cantBeInnerClass/simple.kt.after new file mode 100644 index 00000000000..05c98f07ac7 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/quickfix/cantBeInnerClass/simple.kt.after @@ -0,0 +1,12 @@ +// "Remove 'inner' modifier" "true" +// WITH_RUNTIME + +package com.myapp.activity + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +class Foo { + @Parcelize + class Bar : Parcelable +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/testData/quickfix/classShouldBeAnnotated/simple.kt b/plugins/parcelize/parcelize-ide/testData/quickfix/classShouldBeAnnotated/simple.kt new file mode 100644 index 00000000000..12c824d1d94 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/quickfix/classShouldBeAnnotated/simple.kt @@ -0,0 +1,15 @@ +// "Annotate containing class with ''@Parcelize''" "true" +// ERROR: No 'Parcelable' supertype +// WITH_RUNTIME + +package com.myapp.activity + +import android.os.* +import kotlinx.parcelize.* + +object StringParceler : Parceler { + override fun create(parcel: Parcel) = TODO() + override fun String.write(parcel: Parcel, flags: Int) = TODO() +} + +class Foo(@TypeParceler val a: String) \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/testData/quickfix/classShouldBeAnnotated/simple.kt.after b/plugins/parcelize/parcelize-ide/testData/quickfix/classShouldBeAnnotated/simple.kt.after new file mode 100644 index 00000000000..74e2c43f34a --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/quickfix/classShouldBeAnnotated/simple.kt.after @@ -0,0 +1,16 @@ +// "Annotate containing class with ''@Parcelize''" "true" +// ERROR: No 'Parcelable' supertype +// WITH_RUNTIME + +package com.myapp.activity + +import android.os.* +import kotlinx.parcelize.* + +object StringParceler : Parceler { + override fun create(parcel: Parcel) = TODO() + override fun String.write(parcel: Parcel, flags: Int) = TODO() +} + +@Parcelize +class Foo(@TypeParceler val a: String) \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/testData/quickfix/deleteIncompatible/creatorField.kt b/plugins/parcelize/parcelize-ide/testData/quickfix/deleteIncompatible/creatorField.kt new file mode 100644 index 00000000000..c84bc44e68e --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/quickfix/deleteIncompatible/creatorField.kt @@ -0,0 +1,36 @@ +// "Remove custom ''CREATOR'' property" "true" +// ERROR: Overriding 'writeToParcel' is not allowed. Use 'Parceler' companion object instead +// WITH_RUNTIME + +package com.myapp.activity + +import android.os.* +import kotlinx.parcelize.Parcelize + +@Parcelize +class Foo(val a: String) : Parcelable { + constructor(parcel: Parcel) : this(parcel.readString()) { + } + + override fun writeToParcel(parcel: Parcel, flags: Int) { + parcel.writeString(a) + } + + override fun describeContents(): Int { + return 0 + } + + companion object { + @JvmField + val CREATOR = object : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): Foo { + return Foo(parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } + } + +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/testData/quickfix/deleteIncompatible/creatorField.kt.after b/plugins/parcelize/parcelize-ide/testData/quickfix/deleteIncompatible/creatorField.kt.after new file mode 100644 index 00000000000..5490c7d01c2 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/quickfix/deleteIncompatible/creatorField.kt.after @@ -0,0 +1,26 @@ +// "Remove custom ''CREATOR'' property" "true" +// ERROR: Overriding 'writeToParcel' is not allowed. Use 'Parceler' companion object instead +// WITH_RUNTIME + +package com.myapp.activity + +import android.os.* +import kotlinx.parcelize.Parcelize + +@Parcelize +class Foo(val a: String) : Parcelable { + constructor(parcel: Parcel) : this(parcel.readString()) { + } + + override fun writeToParcel(parcel: Parcel, flags: Int) { + parcel.writeString(a) + } + + override fun describeContents(): Int { + return 0 + } + + companion object { + } + +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/testData/quickfix/deleteIncompatible/writeToParcel.kt b/plugins/parcelize/parcelize-ide/testData/quickfix/deleteIncompatible/writeToParcel.kt new file mode 100644 index 00000000000..34e5cc4e51f --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/quickfix/deleteIncompatible/writeToParcel.kt @@ -0,0 +1,33 @@ +// "Remove custom ''writeToParcel()'' function" "true" +// ERROR: 'CREATOR' definition is not allowed. Use 'Parceler' companion object instead +// WITH_RUNTIME + +package com.myapp.activity + +import android.os.* +import kotlinx.parcelize.Parcelize + +@Parcelize +class Foo(val a: String) : Parcelable { + constructor(parcel: Parcel) : this(parcel.readString()) { + } + + override fun writeToParcel(parcel: Parcel, flags: Int) { + parcel.writeString(a) + } + + override fun describeContents(): Int { + return 0 + } + + companion object CREATOR : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): Foo { + return Foo(parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } + +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/testData/quickfix/deleteIncompatible/writeToParcel.kt.after b/plugins/parcelize/parcelize-ide/testData/quickfix/deleteIncompatible/writeToParcel.kt.after new file mode 100644 index 00000000000..4e74edf965b --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/quickfix/deleteIncompatible/writeToParcel.kt.after @@ -0,0 +1,29 @@ +// "Remove custom ''writeToParcel()'' function" "true" +// ERROR: 'CREATOR' definition is not allowed. Use 'Parceler' companion object instead +// WITH_RUNTIME + +package com.myapp.activity + +import android.os.* +import kotlinx.parcelize.Parcelize + +@Parcelize +class Foo(val a: String) : Parcelable { + constructor(parcel: Parcel) : this(parcel.readString()) { + } + + override fun describeContents(): Int { + return 0 + } + + companion object CREATOR : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): Foo { + return Foo(parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } + +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/basic.kt b/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/basic.kt new file mode 100644 index 00000000000..2c4b20eb9e9 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/basic.kt @@ -0,0 +1,34 @@ +// "Migrate to ''Parceler'' companion object" "true" +// WITH_RUNTIME + +package com.myapp.activity + +import android.os.* +import kotlinx.parcelize.Parcelize + +@Parcelize +class Foo(val firstName: String, val age: Int) : Parcelable { + constructor(parcel: Parcel) : this( + parcel.readString(), + parcel.readInt()) { + } + + override fun writeToParcel(parcel: Parcel, flags: Int) { + parcel.writeString(firstName) + parcel.writeInt(age) + } + + override fun describeContents(): Int { + return 0 + } + + companion object CREATOR : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): Foo { + return Foo(parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/basic.kt.after b/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/basic.kt.after new file mode 100644 index 00000000000..5be33fb4ead --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/basic.kt.after @@ -0,0 +1,28 @@ +// "Migrate to ''Parceler'' companion object" "true" +// WITH_RUNTIME + +package com.myapp.activity + +import android.os.* +import kotlinx.parcelize.Parceler +import kotlinx.parcelize.Parcelize + +@Parcelize +class Foo(val firstName: String, val age: Int) : Parcelable { + constructor(parcel: Parcel) : this( + parcel.readString(), + parcel.readInt()) { + } + + companion object : Parceler { + + override fun Foo.write(parcel: Parcel, flags: Int) { + parcel.writeString(firstName) + parcel.writeInt(age) + } + + override fun create(parcel: Parcel): Foo { + return Foo(parcel) + } + } +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/complexCase1.kt b/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/complexCase1.kt new file mode 100644 index 00000000000..a6be983672e --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/complexCase1.kt @@ -0,0 +1,32 @@ +// "Migrate to ''Parceler'' companion object" "true" +// WITH_RUNTIME + +package com.myapp.activity + +import android.os.* +import kotlinx.parcelize.Parcelize + +@Parcelize +class Foo(val firstName: String, val age: Int) : Parcelable { + constructor(parcel: Parcel) : this(parcel.readString(), parcel.readInt()) + + override fun writeToParcel(parcel: Parcel, flags: Int) { + parcel.writeString(firstName) + parcel.writeInt(age) + } + + companion object { + @JvmField + val CREATOR: Parcelable.Creator = object : Creator() {} + } + + private abstract class Creator : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): Foo { + return Foo(parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/complexCase1.kt.after b/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/complexCase1.kt.after new file mode 100644 index 00000000000..013331da9e0 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/complexCase1.kt.after @@ -0,0 +1,32 @@ +// "Migrate to ''Parceler'' companion object" "true" +// WITH_RUNTIME + +package com.myapp.activity + +import android.os.* +import kotlinx.parcelize.Parceler +import kotlinx.parcelize.Parcelize + +@Parcelize +class Foo(val firstName: String, val age: Int) : Parcelable { + constructor(parcel: Parcel) : this(parcel.readString(), parcel.readInt()) + + companion object : Parceler { + override fun Foo.write(parcel: Parcel, flags: Int) { + parcel.writeString(firstName) + parcel.writeInt(age) + } + + override fun create(parcel: Parcel): Foo = TODO() + } + + private abstract class Creator : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): Foo { + return Foo(parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/customDescribeContents.kt b/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/customDescribeContents.kt new file mode 100644 index 00000000000..f743efc4f03 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/customDescribeContents.kt @@ -0,0 +1,34 @@ +// "Migrate to ''Parceler'' companion object" "true" +// WITH_RUNTIME + +package com.myapp.activity + +import android.os.* +import kotlinx.parcelize.Parcelize + +@Parcelize +class Foo(val firstName: String, val age: Int) : Parcelable { + constructor(parcel: Parcel) : this( + parcel.readString(), + parcel.readInt()) { + } + + override fun writeToParcel(parcel: Parcel, flags: Int) { + parcel.writeString(firstName) + parcel.writeInt(age) + } + + override fun describeContents(): Int { + return 50 + } + + companion object CREATOR : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): Foo { + return Foo(parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/customDescribeContents.kt.after b/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/customDescribeContents.kt.after new file mode 100644 index 00000000000..f80295e3ba8 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/customDescribeContents.kt.after @@ -0,0 +1,32 @@ +// "Migrate to ''Parceler'' companion object" "true" +// WITH_RUNTIME + +package com.myapp.activity + +import android.os.* +import kotlinx.parcelize.Parceler +import kotlinx.parcelize.Parcelize + +@Parcelize +class Foo(val firstName: String, val age: Int) : Parcelable { + constructor(parcel: Parcel) : this( + parcel.readString(), + parcel.readInt()) { + } + + override fun describeContents(): Int { + return 50 + } + + companion object : Parceler { + + override fun Foo.write(parcel: Parcel, flags: Int) { + parcel.writeString(firstName) + parcel.writeInt(age) + } + + override fun create(parcel: Parcel): Foo { + return Foo(parcel) + } + } +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/fromCreatorObject.kt b/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/fromCreatorObject.kt new file mode 100644 index 00000000000..85161d767c8 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/fromCreatorObject.kt @@ -0,0 +1,30 @@ +// "Migrate to ''Parceler'' companion object" "true" +// WITH_RUNTIME + +package com.myapp.activity + +import android.os.* +import kotlinx.parcelize.Parcelize + +@Parcelize +class Foo(val firstName: String, val age: Int) : Parcelable { + constructor(parcel: Parcel) : this( + parcel.readString(), + parcel.readInt()) { + } + + override fun writeToParcel(parcel: Parcel, flags: Int) { + parcel.writeString(firstName) + parcel.writeInt(age) + } + + companion object CREATOR : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): Foo { + return Foo(parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/fromCreatorObject.kt.after b/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/fromCreatorObject.kt.after new file mode 100644 index 00000000000..01017af4672 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/fromCreatorObject.kt.after @@ -0,0 +1,28 @@ +// "Migrate to ''Parceler'' companion object" "true" +// WITH_RUNTIME + +package com.myapp.activity + +import android.os.* +import kotlinx.parcelize.Parceler +import kotlinx.parcelize.Parcelize + +@Parcelize +class Foo(val firstName: String, val age: Int) : Parcelable { + constructor(parcel: Parcel) : this( + parcel.readString(), + parcel.readInt()) { + } + + companion object : Parceler { + + override fun Foo.write(parcel: Parcel, flags: Int) { + parcel.writeString(firstName) + parcel.writeInt(age) + } + + override fun create(parcel: Parcel): Foo { + return Foo(parcel) + } + } +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/innerClassFactory.kt b/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/innerClassFactory.kt new file mode 100644 index 00000000000..e437207956f --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/innerClassFactory.kt @@ -0,0 +1,32 @@ +// "Migrate to ''Parceler'' companion object" "true" +// WITH_RUNTIME + +package com.myapp.activity + +import android.os.* +import kotlinx.parcelize.Parcelize + +@Parcelize +class Foo(val firstName: String, val age: Int) : Parcelable { + constructor(parcel: Parcel) : this(parcel.readString(), parcel.readInt()) + + override fun writeToParcel(parcel: Parcel, flags: Int) { + parcel.writeString(firstName) + parcel.writeInt(age) + } + + companion object { + @JvmField + val CREATOR: Parcelable.Creator = Creator() + } + + private class Creator : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): Foo { + return Foo(parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/innerClassFactory.kt.after b/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/innerClassFactory.kt.after new file mode 100644 index 00000000000..18e10c00a13 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/innerClassFactory.kt.after @@ -0,0 +1,34 @@ +// "Migrate to ''Parceler'' companion object" "true" +// WITH_RUNTIME + +package com.myapp.activity + +import android.os.* +import kotlinx.parcelize.Parceler +import kotlinx.parcelize.Parcelize + +@Parcelize +class Foo(val firstName: String, val age: Int) : Parcelable { + constructor(parcel: Parcel) : this(parcel.readString(), parcel.readInt()) + + companion object : Parceler { + override fun Foo.write(parcel: Parcel, flags: Int) { + parcel.writeString(firstName) + parcel.writeInt(age) + } + + override fun create(parcel: Parcel): Foo { + return Foo(parcel) + } + } + + private class Creator : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): Foo { + return Foo(parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/jvmField.kt b/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/jvmField.kt new file mode 100644 index 00000000000..9de5641760c --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/jvmField.kt @@ -0,0 +1,30 @@ +// "Migrate to ''Parceler'' companion object" "true" +// WITH_RUNTIME + +package com.myapp.activity + +import android.os.* +import kotlinx.parcelize.Parcelize + +@Parcelize +class Foo(val firstName: String, val age: Int) : Parcelable { + constructor(parcel: Parcel) : this(parcel.readString(), parcel.readInt()) + + override fun writeToParcel(parcel: Parcel, flags: Int) { + parcel.writeString(firstName) + parcel.writeInt(age) + } + + companion object { + @JvmField + val CREATOR = object : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): Foo { + return Foo(parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } + } +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/jvmField.kt.after b/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/jvmField.kt.after new file mode 100644 index 00000000000..54328c156f7 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/jvmField.kt.after @@ -0,0 +1,24 @@ +// "Migrate to ''Parceler'' companion object" "true" +// WITH_RUNTIME + +package com.myapp.activity + +import android.os.* +import kotlinx.parcelize.Parceler +import kotlinx.parcelize.Parcelize + +@Parcelize +class Foo(val firstName: String, val age: Int) : Parcelable { + constructor(parcel: Parcel) : this(parcel.readString(), parcel.readInt()) + + companion object : Parceler { + override fun Foo.write(parcel: Parcel, flags: Int) { + parcel.writeString(firstName) + parcel.writeInt(age) + } + + override fun create(parcel: Parcel): Foo { + return Foo(parcel) + } + } +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/withoutDescribeContents.kt b/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/withoutDescribeContents.kt new file mode 100644 index 00000000000..471925955ee --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/withoutDescribeContents.kt @@ -0,0 +1,30 @@ +// "Migrate to ''Parceler'' companion object" "true" +// WITH_RUNTIME + +package com.myapp.activity + +import android.os.* +import kotlinx.parcelize.Parcelize + +@Parcelize +class Foo(val firstName: String, val age: Int) : Parcelable { + constructor(parcel: Parcel) : this( + parcel.readString(), + parcel.readInt()) { + } + + override fun writeToParcel(parcel: Parcel, flags: Int) { + parcel.writeString(firstName) + parcel.writeInt(age) + } + + companion object CREATOR : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): Foo { + return Foo(parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/withoutDescribeContents.kt.after b/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/withoutDescribeContents.kt.after new file mode 100644 index 00000000000..5be33fb4ead --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/quickfix/migrations/withoutDescribeContents.kt.after @@ -0,0 +1,28 @@ +// "Migrate to ''Parceler'' companion object" "true" +// WITH_RUNTIME + +package com.myapp.activity + +import android.os.* +import kotlinx.parcelize.Parceler +import kotlinx.parcelize.Parcelize + +@Parcelize +class Foo(val firstName: String, val age: Int) : Parcelable { + constructor(parcel: Parcel) : this( + parcel.readString(), + parcel.readInt()) { + } + + companion object : Parceler { + + override fun Foo.write(parcel: Parcel, flags: Int) { + parcel.writeString(firstName) + parcel.writeInt(age) + } + + override fun create(parcel: Parcel): Foo { + return Foo(parcel) + } + } +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/testData/quickfix/noParcelableSupertype/alreadyHasSupertype.kt b/plugins/parcelize/parcelize-ide/testData/quickfix/noParcelableSupertype/alreadyHasSupertype.kt new file mode 100644 index 00000000000..56a21d0caf5 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/quickfix/noParcelableSupertype/alreadyHasSupertype.kt @@ -0,0 +1,13 @@ +// "Add ''Parcelable'' supertype" "false" +// IGNORE_IRRELEVANT_ACTIONS +// WITH_RUNTIME + +package com.myapp.activity + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +abstract class AbstractParcelable : Parcelable + +@Parcelize +class Test(val s: String) : AbstractParcelable() \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/testData/quickfix/noParcelableSupertype/simple.kt b/plugins/parcelize/parcelize-ide/testData/quickfix/noParcelableSupertype/simple.kt new file mode 100644 index 00000000000..0f33c430905 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/quickfix/noParcelableSupertype/simple.kt @@ -0,0 +1,10 @@ +// "Add ''Parcelable'' supertype" "true" +// WITH_RUNTIME + +package com.myapp.activity + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +class Test(val s: String) \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/testData/quickfix/noParcelableSupertype/simple.kt.after b/plugins/parcelize/parcelize-ide/testData/quickfix/noParcelableSupertype/simple.kt.after new file mode 100644 index 00000000000..feb882c27ce --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/quickfix/noParcelableSupertype/simple.kt.after @@ -0,0 +1,10 @@ +// "Add ''Parcelable'' supertype" "true" +// WITH_RUNTIME + +package com.myapp.activity + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +class Test(val s: String) : Parcelable \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/testData/quickfix/propertyWontBeSerialized/simple.kt b/plugins/parcelize/parcelize-ide/testData/quickfix/propertyWontBeSerialized/simple.kt new file mode 100644 index 00000000000..1f4dcac1631 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/quickfix/propertyWontBeSerialized/simple.kt @@ -0,0 +1,12 @@ +// "Add ''@IgnoredOnParcel'' annotation" "true" +// WITH_RUNTIME + +package com.myapp.activity + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +class Test : Parcelable { + val a = 5 +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/testData/quickfix/propertyWontBeSerialized/simple.kt.after b/plugins/parcelize/parcelize-ide/testData/quickfix/propertyWontBeSerialized/simple.kt.after new file mode 100644 index 00000000000..d6d71e9ebf7 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/quickfix/propertyWontBeSerialized/simple.kt.after @@ -0,0 +1,14 @@ +// "Add ''@IgnoredOnParcel'' annotation" "true" +// WITH_RUNTIME + +package com.myapp.activity + +import android.os.Parcelable +import kotlinx.parcelize.IgnoredOnParcel +import kotlinx.parcelize.Parcelize + +@Parcelize +class Test : Parcelable { + @IgnoredOnParcel + val a = 5 +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/testData/quickfix/removeDuplicatingTypeParcelerAnnotation/simple.kt b/plugins/parcelize/parcelize-ide/testData/quickfix/removeDuplicatingTypeParcelerAnnotation/simple.kt new file mode 100644 index 00000000000..274ce098955 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/quickfix/removeDuplicatingTypeParcelerAnnotation/simple.kt @@ -0,0 +1,17 @@ +// "Remove redundant ''@TypeParceler'' annotation" "true" +// WARNING: This annotation duplicates the one for Class 'Foo' +// WITH_RUNTIME + +package com.myapp.activity + +import android.os.* +import kotlinx.parcelize.* + +object StringParceler : Parceler { + override fun create(parcel: Parcel) = TODO() + override fun String.write(parcel: Parcel, flags: Int) = TODO() +} + +@Parcelize +@TypeParceler +class Foo(@TypeParceler val a: String) : Parcelable \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/testData/quickfix/removeDuplicatingTypeParcelerAnnotation/simple.kt.after b/plugins/parcelize/parcelize-ide/testData/quickfix/removeDuplicatingTypeParcelerAnnotation/simple.kt.after new file mode 100644 index 00000000000..39e22ce4972 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/testData/quickfix/removeDuplicatingTypeParcelerAnnotation/simple.kt.after @@ -0,0 +1,17 @@ +// "Remove redundant ''@TypeParceler'' annotation" "true" +// WARNING: This annotation duplicates the one for Class 'Foo' +// WITH_RUNTIME + +package com.myapp.activity + +import android.os.* +import kotlinx.parcelize.* + +object StringParceler : Parceler { + override fun create(parcel: Parcel) = TODO() + override fun String.write(parcel: Parcel, flags: Int) = TODO() +} + +@Parcelize +@TypeParceler +class Foo(val a: String) : Parcelable \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/tests/org/jetbrains/kotlin/pacelize/ide/test/AbstractParcelizeCheckerTest.kt b/plugins/parcelize/parcelize-ide/tests/org/jetbrains/kotlin/pacelize/ide/test/AbstractParcelizeCheckerTest.kt new file mode 100644 index 00000000000..d028918d3b8 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/tests/org/jetbrains/kotlin/pacelize/ide/test/AbstractParcelizeCheckerTest.kt @@ -0,0 +1,27 @@ +/* + * 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 org.jetbrains.kotlin.checkers.AbstractPsiCheckerTest +import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil +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")) + } + + override fun tearDown() { + ConfigLibraryUtil.removeLibrary(module, "androidJar") + ConfigLibraryUtil.removeLibrary(module, "androidExtensionsRuntime") + + super.tearDown() + } +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/tests/org/jetbrains/kotlin/pacelize/ide/test/AbstractParcelizeQuickFixTest.kt b/plugins/parcelize/parcelize-ide/tests/org/jetbrains/kotlin/pacelize/ide/test/AbstractParcelizeQuickFixTest.kt new file mode 100644 index 00000000000..090a0708063 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/tests/org/jetbrains/kotlin/pacelize/ide/test/AbstractParcelizeQuickFixTest.kt @@ -0,0 +1,38 @@ +/* + * 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 org.jetbrains.kotlin.pacelize.ide.test + +import org.jetbrains.kotlin.idea.quickfix.AbstractQuickFixTest +import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil +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")) + } + + override fun tearDown() { + ConfigLibraryUtil.removeLibrary(module, "androidJar") + ConfigLibraryUtil.removeLibrary(module, "androidExtensionsRuntime") + + super.tearDown() + } +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-ide/tests/org/jetbrains/kotlin/pacelize/ide/test/ParcelizeCheckerTestGenerated.java b/plugins/parcelize/parcelize-ide/tests/org/jetbrains/kotlin/pacelize/ide/test/ParcelizeCheckerTestGenerated.java new file mode 100644 index 00000000000..66b4f7c25bc --- /dev/null +++ b/plugins/parcelize/parcelize-ide/tests/org/jetbrains/kotlin/pacelize/ide/test/ParcelizeCheckerTestGenerated.java @@ -0,0 +1,100 @@ +/* + * 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.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.JUnit3RunnerWithInners; +import org.jetbrains.kotlin.test.KotlinTestUtils; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.runner.RunWith; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("plugins/parcelize/parcelize-ide/testData/checker") +@TestDataPath("$PROJECT_ROOT") +@RunWith(JUnit3RunnerWithInners.class) +public class ParcelizeCheckerTestGenerated extends AbstractParcelizeCheckerTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInChecker() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/parcelize/parcelize-ide/testData/checker"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @TestMetadata("constructors.kt") + public void testConstructors() throws Exception { + runTest("plugins/parcelize/parcelize-ide/testData/checker/constructors.kt"); + } + + @TestMetadata("customCreator.kt") + public void testCustomCreator() throws Exception { + runTest("plugins/parcelize/parcelize-ide/testData/checker/customCreator.kt"); + } + + @TestMetadata("customParcelers.kt") + public void testCustomParcelers() throws Exception { + runTest("plugins/parcelize/parcelize-ide/testData/checker/customParcelers.kt"); + } + + @TestMetadata("customWriteToParcel.kt") + public void testCustomWriteToParcel() throws Exception { + runTest("plugins/parcelize/parcelize-ide/testData/checker/customWriteToParcel.kt"); + } + + @TestMetadata("delegate.kt") + public void testDelegate() throws Exception { + runTest("plugins/parcelize/parcelize-ide/testData/checker/delegate.kt"); + } + + @TestMetadata("emptyPrimaryConstructor.kt") + public void testEmptyPrimaryConstructor() throws Exception { + runTest("plugins/parcelize/parcelize-ide/testData/checker/emptyPrimaryConstructor.kt"); + } + + @TestMetadata("kt20062.kt") + public void testKt20062() throws Exception { + runTest("plugins/parcelize/parcelize-ide/testData/checker/kt20062.kt"); + } + + @TestMetadata("modality.kt") + public void testModality() throws Exception { + runTest("plugins/parcelize/parcelize-ide/testData/checker/modality.kt"); + } + + @TestMetadata("notMagicParcel.kt") + public void testNotMagicParcel() throws Exception { + runTest("plugins/parcelize/parcelize-ide/testData/checker/notMagicParcel.kt"); + } + + @TestMetadata("properties.kt") + public void testProperties() throws Exception { + runTest("plugins/parcelize/parcelize-ide/testData/checker/properties.kt"); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + runTest("plugins/parcelize/parcelize-ide/testData/checker/simple.kt"); + } + + @TestMetadata("unsupportedType.kt") + public void testUnsupportedType() throws Exception { + runTest("plugins/parcelize/parcelize-ide/testData/checker/unsupportedType.kt"); + } + + @TestMetadata("withoutParcelableSupertype.kt") + public void testWithoutParcelableSupertype() throws Exception { + runTest("plugins/parcelize/parcelize-ide/testData/checker/withoutParcelableSupertype.kt"); + } + + @TestMetadata("wrongAnnotationTarget.kt") + public void testWrongAnnotationTarget() throws Exception { + runTest("plugins/parcelize/parcelize-ide/testData/checker/wrongAnnotationTarget.kt"); + } +} diff --git a/plugins/parcelize/parcelize-ide/tests/org/jetbrains/kotlin/pacelize/ide/test/ParcelizeQuickFixTestGenerated.java b/plugins/parcelize/parcelize-ide/tests/org/jetbrains/kotlin/pacelize/ide/test/ParcelizeQuickFixTestGenerated.java new file mode 100644 index 00000000000..e609e53df82 --- /dev/null +++ b/plugins/parcelize/parcelize-ide/tests/org/jetbrains/kotlin/pacelize/ide/test/ParcelizeQuickFixTestGenerated.java @@ -0,0 +1,224 @@ +/* + * 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.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.JUnit3RunnerWithInners; +import org.jetbrains.kotlin.test.KotlinTestUtils; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.runner.RunWith; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("plugins/parcelize/parcelize-ide/testData/quickfix") +@TestDataPath("$PROJECT_ROOT") +@RunWith(JUnit3RunnerWithInners.class) +public class ParcelizeQuickFixTestGenerated extends AbstractParcelizeQuickFixTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInQuickfix() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/parcelize/parcelize-ide/testData/quickfix"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), null, true); + } + + @TestMetadata("plugins/parcelize/parcelize-ide/testData/quickfix/addPrimaryConstructor") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class AddPrimaryConstructor extends AbstractParcelizeQuickFixTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInAddPrimaryConstructor() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/parcelize/parcelize-ide/testData/quickfix/addPrimaryConstructor"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), null, true); + } + + @TestMetadata("constructorWithDelegate.kt") + public void testConstructorWithDelegate() throws Exception { + runTest("plugins/parcelize/parcelize-ide/testData/quickfix/addPrimaryConstructor/constructorWithDelegate.kt"); + } + + @TestMetadata("noQuickFix.kt") + public void testNoQuickFix() throws Exception { + runTest("plugins/parcelize/parcelize-ide/testData/quickfix/addPrimaryConstructor/noQuickFix.kt"); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + runTest("plugins/parcelize/parcelize-ide/testData/quickfix/addPrimaryConstructor/simple.kt"); + } + } + + @TestMetadata("plugins/parcelize/parcelize-ide/testData/quickfix/cantBeInnerClass") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class CantBeInnerClass extends AbstractParcelizeQuickFixTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInCantBeInnerClass() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/parcelize/parcelize-ide/testData/quickfix/cantBeInnerClass"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), null, true); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + runTest("plugins/parcelize/parcelize-ide/testData/quickfix/cantBeInnerClass/simple.kt"); + } + } + + @TestMetadata("plugins/parcelize/parcelize-ide/testData/quickfix/classShouldBeAnnotated") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ClassShouldBeAnnotated extends AbstractParcelizeQuickFixTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInClassShouldBeAnnotated() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/parcelize/parcelize-ide/testData/quickfix/classShouldBeAnnotated"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), null, true); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + runTest("plugins/parcelize/parcelize-ide/testData/quickfix/classShouldBeAnnotated/simple.kt"); + } + } + + @TestMetadata("plugins/parcelize/parcelize-ide/testData/quickfix/deleteIncompatible") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class DeleteIncompatible extends AbstractParcelizeQuickFixTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInDeleteIncompatible() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/parcelize/parcelize-ide/testData/quickfix/deleteIncompatible"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), null, true); + } + + @TestMetadata("creatorField.kt") + public void testCreatorField() throws Exception { + runTest("plugins/parcelize/parcelize-ide/testData/quickfix/deleteIncompatible/creatorField.kt"); + } + + @TestMetadata("writeToParcel.kt") + public void testWriteToParcel() throws Exception { + runTest("plugins/parcelize/parcelize-ide/testData/quickfix/deleteIncompatible/writeToParcel.kt"); + } + } + + @TestMetadata("plugins/parcelize/parcelize-ide/testData/quickfix/migrations") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Migrations extends AbstractParcelizeQuickFixTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInMigrations() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/parcelize/parcelize-ide/testData/quickfix/migrations"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), null, true); + } + + @TestMetadata("basic.kt") + public void testBasic() throws Exception { + runTest("plugins/parcelize/parcelize-ide/testData/quickfix/migrations/basic.kt"); + } + + @TestMetadata("complexCase1.kt") + public void testComplexCase1() throws Exception { + runTest("plugins/parcelize/parcelize-ide/testData/quickfix/migrations/complexCase1.kt"); + } + + @TestMetadata("customDescribeContents.kt") + public void testCustomDescribeContents() throws Exception { + runTest("plugins/parcelize/parcelize-ide/testData/quickfix/migrations/customDescribeContents.kt"); + } + + @TestMetadata("fromCreatorObject.kt") + public void testFromCreatorObject() throws Exception { + runTest("plugins/parcelize/parcelize-ide/testData/quickfix/migrations/fromCreatorObject.kt"); + } + + @TestMetadata("innerClassFactory.kt") + public void testInnerClassFactory() throws Exception { + runTest("plugins/parcelize/parcelize-ide/testData/quickfix/migrations/innerClassFactory.kt"); + } + + @TestMetadata("jvmField.kt") + public void testJvmField() throws Exception { + runTest("plugins/parcelize/parcelize-ide/testData/quickfix/migrations/jvmField.kt"); + } + + @TestMetadata("withoutDescribeContents.kt") + public void testWithoutDescribeContents() throws Exception { + runTest("plugins/parcelize/parcelize-ide/testData/quickfix/migrations/withoutDescribeContents.kt"); + } + } + + @TestMetadata("plugins/parcelize/parcelize-ide/testData/quickfix/noParcelableSupertype") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class NoParcelableSupertype extends AbstractParcelizeQuickFixTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInNoParcelableSupertype() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/parcelize/parcelize-ide/testData/quickfix/noParcelableSupertype"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), null, true); + } + + @TestMetadata("alreadyHasSupertype.kt") + public void testAlreadyHasSupertype() throws Exception { + runTest("plugins/parcelize/parcelize-ide/testData/quickfix/noParcelableSupertype/alreadyHasSupertype.kt"); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + runTest("plugins/parcelize/parcelize-ide/testData/quickfix/noParcelableSupertype/simple.kt"); + } + } + + @TestMetadata("plugins/parcelize/parcelize-ide/testData/quickfix/propertyWontBeSerialized") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class PropertyWontBeSerialized extends AbstractParcelizeQuickFixTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInPropertyWontBeSerialized() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/parcelize/parcelize-ide/testData/quickfix/propertyWontBeSerialized"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), null, true); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + runTest("plugins/parcelize/parcelize-ide/testData/quickfix/propertyWontBeSerialized/simple.kt"); + } + } + + @TestMetadata("plugins/parcelize/parcelize-ide/testData/quickfix/removeDuplicatingTypeParcelerAnnotation") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class RemoveDuplicatingTypeParcelerAnnotation extends AbstractParcelizeQuickFixTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInRemoveDuplicatingTypeParcelerAnnotation() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/parcelize/parcelize-ide/testData/quickfix/removeDuplicatingTypeParcelerAnnotation"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), null, true); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + runTest("plugins/parcelize/parcelize-ide/testData/quickfix/removeDuplicatingTypeParcelerAnnotation/simple.kt"); + } + } +} diff --git a/prepare/idea-plugin/build.gradle.kts b/prepare/idea-plugin/build.gradle.kts index 1c1cc5a6265..44fb69d28af 100644 --- a/prepare/idea-plugin/build.gradle.kts +++ b/prepare/idea-plugin/build.gradle.kts @@ -140,6 +140,7 @@ val libraryProjects = listOf( ":kotlin-noarg-compiler-plugin", ":kotlin-sam-with-receiver-compiler-plugin", ":plugins:android-extensions-compiler", + ":plugins:parcelize:parcelize-compiler", ":kotlinx-serialization-compiler-plugin", ":idea:ide-common" ) @@ -192,6 +193,7 @@ dependencies { gradleToolingModel(project(":sam-with-receiver-ide-plugin")) { isTransitive = false } gradleToolingModel(project(":plugins:kapt3-idea")) { isTransitive = false } gradleToolingModel(project(":plugins:android-extensions-ide")) { isTransitive = false } + gradleToolingModel(project(":plugins:parcelize:parcelize-ide")) { isTransitive = false } gradleToolingModel(project(":noarg-ide-plugin")) { isTransitive = false } gradleToolingModel(project(":allopen-ide-plugin")) { isTransitive = false } diff --git a/settings.gradle b/settings.gradle index 90ff89d80e5..d9f64979e9b 100644 --- a/settings.gradle +++ b/settings.gradle @@ -324,6 +324,7 @@ include ":compiler:fir:cones", include ":idea:idea-frontend-fir:idea-fir-low-level-api" include ":plugins:parcelize:parcelize-compiler", + ":plugins:parcelize:parcelize-ide", ":plugins:parcelize:parcelize-runtime", ":kotlin-parcelize-compiler"