Parcelable: Add quick fixes

This commit is contained in:
Yan Zhulanow
2017-09-07 23:52:39 +03:00
committed by Yan Zhulanow
parent 8eeed17b65
commit e6171dc4c5
58 changed files with 1607 additions and 27 deletions
@@ -16,6 +16,9 @@
package org.jetbrains.kotlin.diagnostics package org.jetbrains.kotlin.diagnostics
import com.intellij.mock.MockApplication
import com.intellij.openapi.application.Application
import com.intellij.openapi.application.ApplicationManager
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.builtins.isFunctionType import org.jetbrains.kotlin.builtins.isFunctionType
import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.CallableDescriptor
@@ -164,6 +167,10 @@ inline fun <reified T : KtDeclaration> reportOnDeclarationAs(trace: BindingTrace
} }
fun <D : Diagnostic> DiagnosticSink.reportFromPlugin(diagnostic: D, ext: DefaultErrorMessages.Extension) { fun <D : Diagnostic> DiagnosticSink.reportFromPlugin(diagnostic: D, ext: DefaultErrorMessages.Extension) {
if (ApplicationManager.getApplication() !is MockApplication) {
return this.report(diagnostic)
}
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
val renderer = ext.map[diagnostic.factory] as? DiagnosticRenderer<D> val renderer = ext.map[diagnostic.factory] as? DiagnosticRenderer<D>
?: error("Renderer not found for diagnostic ${diagnostic.factory.name}") ?: error("Renderer not found for diagnostic ${diagnostic.factory.name}")
@@ -25,6 +25,8 @@ import org.jetbrains.kotlin.resolve.constants.ErrorValue
private val JVM_STATIC_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.JvmStatic") private val JVM_STATIC_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.JvmStatic")
val JVM_FIELD_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.JvmField")
fun DeclarationDescriptor.hasJvmStaticAnnotation(): Boolean { fun DeclarationDescriptor.hasJvmStaticAnnotation(): Boolean {
return annotations.findAnnotation(JVM_STATIC_ANNOTATION_FQ_NAME) != null return annotations.findAnnotation(JVM_STATIC_ANNOTATION_FQ_NAME) != null
} }
@@ -1406,6 +1406,10 @@ fun main(args: Array<String>) {
testClass<AbstractParcelCheckerTest> { testClass<AbstractParcelCheckerTest> {
model("android/parcel/checker", excludeParentDirs = true) model("android/parcel/checker", excludeParentDirs = true)
} }
testClass<AbstractParcelQuickFixTest> {
model("android/parcel/quickfix", pattern = """^(\w+)\.((before\.Main\.\w+)|(test))$""", testMethod = "doTestWithExtraFile")
}
} }
testGroup("idea/idea-android/tests", "idea/testData") { testGroup("idea/idea-android/tests", "idea/testData") {
@@ -49,6 +49,10 @@ object DirectiveBasedActionUtils {
UsefulTestCase.assertEmpty("Irrelevant actions should not be specified in ACTION directive for they are not checked anyway", UsefulTestCase.assertEmpty("Irrelevant actions should not be specified in ACTION directive for they are not checked anyway",
expectedActions.filter { isIrrelevantAction(it) }) expectedActions.filter { isIrrelevantAction(it) })
if (InTextDirectivesUtils.findLinesWithPrefixesRemoved(file.text, "// IGNORE_IRRELEVANT_ACTIONS").isNotEmpty()) {
return
}
val actualActions = availableActions.map { it.text }.sorted() val actualActions = availableActions.map { it.text }.sorted()
UsefulTestCase.assertOrderedEquals("Some unexpected actions available at current position. Use // ACTION: directive", UsefulTestCase.assertOrderedEquals("Some unexpected actions available at current position. Use // ACTION: directive",
+1
View File
@@ -96,6 +96,7 @@
<expressionCodegenExtension implementation="org.jetbrains.kotlin.android.parcel.IDEParcelableCodegenExtension"/> <expressionCodegenExtension implementation="org.jetbrains.kotlin.android.parcel.IDEParcelableCodegenExtension"/>
<syntheticResolveExtension implementation="org.jetbrains.kotlin.android.parcel.IDEParcelableResolveExtension"/> <syntheticResolveExtension implementation="org.jetbrains.kotlin.android.parcel.IDEParcelableResolveExtension"/>
<classBuilderFactoryInterceptorExtension implementation="org.jetbrains.kotlin.android.synthetic.codegen.ParcelableClinitClassBuilderInterceptorExtension"/> <classBuilderFactoryInterceptorExtension implementation="org.jetbrains.kotlin.android.synthetic.codegen.ParcelableClinitClassBuilderInterceptorExtension"/>
<quickFixContributor implementation="org.jetbrains.kotlin.android.parcel.quickfixes.ParcelableQuickFixContributor"/>
<androidDexer implementation="org.jetbrains.kotlin.android.debugger.AndroidDexerImpl"/> <androidDexer implementation="org.jetbrains.kotlin.android.debugger.AndroidDexerImpl"/>
@@ -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.android.parcel.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 AbstractParcelableQuickFix<T: KtElement>(element: T) : KotlinQuickFixAction<T>(element) {
protected companion object {
fun <T : KtElement> 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 <reified T: KtElement> Diagnostic.findElement() = psiElement.getNonStrictParentOfType<T>()
}
override fun createAction(diagnostic: Diagnostic) = f(diagnostic)
}
}
@@ -0,0 +1,287 @@
/*
* 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.android.parcel.quickfixes
import com.intellij.openapi.diagnostic.Logger
import kotlinx.android.parcel.Parceler
import org.jetbrains.kotlin.android.parcel.ANDROID_PARCELABLE_CREATOR_CLASS_FQNAME
import org.jetbrains.kotlin.android.parcel.ANDROID_PARCEL_CLASS_FQNAME
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
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.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.name.FqName
import org.jetbrains.kotlin.name.Name
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.annotations.JVM_FIELD_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
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) : AbstractParcelableQuickFix<KtClass>(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<KtObjectDeclaration, ClassDescriptor>? {
for (obj in companionObjects) {
val bindingContext = obj.analyze(BodyResolveMode.PARTIAL)
val objDescriptor = bindingContext[BindingContext.CLASS, obj] ?: 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() == KotlinBuiltIns.FQ_NAMES._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() == KotlinBuiltIns.FQ_NAMES._int.asString()
}
private fun KtNamedFunction.doesLookLikeDescribeContentsOverride(): Boolean {
return name == "describeContents"
&& hasModifier(KtTokens.OVERRIDE_KEYWORD)
&& receiverTypeReference == null
&& valueParameters.size == 0
&& typeParameters.size == 0
&& typeReference?.getFqName() == KotlinBuiltIns.FQ_NAMES._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<KtProperty>()
.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.getResolvedCall(initializer.analyze(BodyResolveMode.PARTIAL))
?.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() == KotlinBuiltIns.FQ_NAMES._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<KtNamedFunction>().firstOrNull(f)
private fun KtTypeReference.getFqName(): String? = analyze(BodyResolveMode.PARTIAL)[BindingContext.TYPE, this]
?.constructor?.declarationDescriptor?.fqNameSafe?.asString()
}
object FactoryForWrite : AbstractFactory({ findElement<KtClass>()?.let { ParcelMigrateToParcelizeQuickFix(it) } })
object FactoryForCREATOR : AbstractFactory({
findElement<KtObjectDeclaration>()?.getStrictParentOfType<KtClass>()?.let { ParcelMigrateToParcelizeQuickFix(it) }
})
override fun getText() = "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 ?: "<unnamed Parcelable class>"}")
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<KtProperty>().filter { it.name == "CREATOR" }) {
if (property.findAnnotation(JVM_FIELD_ANNOTATION_FQ_NAME) != null) {
property.delete()
}
}
}
}
@@ -0,0 +1,34 @@
/*
* 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.android.parcel.quickfixes
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.KtPsiFactory
class ParcelRemoveCustomCreatorProperty(property: KtProperty) : AbstractParcelableQuickFix<KtProperty>(property) {
object Factory : AbstractFactory(f@ {
// KtProperty or its name identifier
psiElement as? KtProperty ?: (psiElement.parent as? KtProperty) ?: return@f null
findElement<KtProperty>()?.let(::ParcelRemoveCustomCreatorProperty)
})
override fun getText() = "Remove custom ''CREATOR'' property"
override fun invoke(ktPsiFactory: KtPsiFactory, element: KtProperty) {
element.delete()
}
}
@@ -0,0 +1,29 @@
/*
* 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.android.parcel.quickfixes
import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.KtPsiFactory
class ParcelRemoveCustomWriteToParcel(function: KtFunction) : AbstractParcelableQuickFix<KtFunction>(function) {
object Factory : AbstractFactory({ findElement<KtFunction>()?.let(::ParcelRemoveCustomWriteToParcel) })
override fun getText() = "Remove custom ''writeToParcel()'' function"
override fun invoke(ktPsiFactory: KtPsiFactory, element: KtFunction) {
element.delete()
}
}
@@ -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.android.parcel.quickfixes
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.createPrimaryConstructorIfAbsent
class ParcelableAddPrimaryConstructorQuickfix(clazz: KtClass) : AbstractParcelableQuickFix<KtClass>(clazz) {
object Factory : AbstractFactory({ findElement<KtClass>()?.let(::ParcelableAddPrimaryConstructorQuickfix) })
override fun getText() = "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)
}
}
}
}
@@ -0,0 +1,29 @@
/*
* 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.android.parcel.quickfixes
import com.android.SdkConstants.CLASS_PARCELABLE
import org.jetbrains.kotlin.psi.*
class ParcelableAddSupertypeQuickfix(clazz: KtClassOrObject) : AbstractParcelableQuickFix<KtClassOrObject>(clazz) {
object Factory : AbstractFactory({ findElement<KtClassOrObject>()?.let(::ParcelableAddSupertypeQuickfix) })
override fun getText() = "Add ''Parcelable'' supertype"
override fun invoke(ktPsiFactory: KtPsiFactory, element: KtClassOrObject) {
element.addSuperTypeListEntry(ktPsiFactory.createSuperTypeEntry(CLASS_PARCELABLE)).shortenReferences()
}
}
@@ -0,0 +1,29 @@
/*
* 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.android.parcel.quickfixes
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.KtPsiFactory
class ParcelableAddTransientAnnotationQuickfix(property: KtProperty) : AbstractParcelableQuickFix<KtProperty>(property) {
object Factory : AbstractFactory({ findElement<KtProperty>()?.let(::ParcelableAddTransientAnnotationQuickfix) })
override fun getText() = "Add ''@Transient'' annotation"
override fun invoke(ktPsiFactory: KtPsiFactory, element: KtProperty) {
element.addAnnotationEntry(ktPsiFactory.createAnnotationEntry("@" + Transient::class.java.name)).shortenReferences()
}
}
@@ -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.android.parcel.quickfixes
import org.jetbrains.kotlin.android.synthetic.diagnostic.ErrorsAndroid
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
class ParcelableQuickFixContributor : QuickFixContributor {
override fun registerQuickFixes(quickFixes: QuickFixes) {
quickFixes.register(ErrorsAndroid.PARCELABLE_CANT_BE_INNER_CLASS,
RemoveModifierFix.createRemoveModifierFromListOwnerFactory(KtTokens.INNER_KEYWORD, false))
quickFixes.register(ErrorsAndroid.NO_PARCELABLE_SUPERTYPE, ParcelableAddSupertypeQuickfix.Factory)
quickFixes.register(ErrorsAndroid.PARCELABLE_SHOULD_HAVE_PRIMARY_CONSTRUCTOR, ParcelableAddPrimaryConstructorQuickfix.Factory)
quickFixes.register(ErrorsAndroid.PROPERTY_WONT_BE_SERIALIZED, ParcelableAddTransientAnnotationQuickfix.Factory)
quickFixes.register(ErrorsAndroid.OVERRIDING_WRITE_TO_PARCEL_IS_NOT_ALLOWED, ParcelMigrateToParcelizeQuickFix.FactoryForWrite)
quickFixes.register(ErrorsAndroid.OVERRIDING_WRITE_TO_PARCEL_IS_NOT_ALLOWED, ParcelRemoveCustomWriteToParcel.Factory)
quickFixes.register(ErrorsAndroid.CREATOR_DEFINITION_IS_NOT_ALLOWED, ParcelMigrateToParcelizeQuickFix.FactoryForCREATOR)
quickFixes.register(ErrorsAndroid.CREATOR_DEFINITION_IS_NOT_ALLOWED, ParcelRemoveCustomCreatorProperty.Factory)
}
}
@@ -10,7 +10,7 @@ class A : Parcelable
class B(val firstName: String, val secondName: String) : Parcelable class B(val firstName: String, val secondName: String) : Parcelable
@Parcelize @Parcelize
class C(val firstName: String, <error descr="[PLUGIN_ERROR] PARCELABLE_CONSTRUCTOR_PARAMETER_SHOULD_BE_VAL_OR_VAR: 'Parcelable' constructor parameter should be 'val' or 'var'">secondName</error>: String) : Parcelable class C(val firstName: String, <error descr="[PARCELABLE_CONSTRUCTOR_PARAMETER_SHOULD_BE_VAL_OR_VAR] 'Parcelable' constructor parameter should be 'val' or 'var'">secondName</error>: String) : Parcelable
@Parcelize @Parcelize
class D(val firstName: String, vararg val secondName: String) : Parcelable class D(val firstName: String, vararg val secondName: String) : Parcelable
@@ -21,7 +21,7 @@ class E(val firstName: String, val secondName: String) : Parcelable {
} }
@Parcelize @Parcelize
class <error descr="[PLUGIN_ERROR] PARCELABLE_SHOULD_HAVE_PRIMARY_CONSTRUCTOR: 'Parcelable' should have a primary constructor">F</error> : Parcelable { class <error descr="[PARCELABLE_SHOULD_HAVE_PRIMARY_CONSTRUCTOR] 'Parcelable' should have a primary constructor">F</error> : Parcelable {
constructor(a: String) { constructor(a: String) {
println(a) println(a)
} }
@@ -6,16 +6,16 @@ import android.os.Parcel
@Parcelize @Parcelize
class A(val a: String) : Parcelable { class A(val a: String) : Parcelable {
<error descr="[PLUGIN_ERROR] OVERRIDING_WRITE_TO_PARCEL_IS_NOT_ALLOWED: Overriding 'writeToParcel' is not allowed. Use 'Parceler' companion object instead.">override</error> fun writeToParcel(p: Parcel?, flags: Int) {} <error descr="[OVERRIDING_WRITE_TO_PARCEL_IS_NOT_ALLOWED] Overriding 'writeToParcel' is not allowed. Use 'Parceler' companion object instead.">override</error> fun writeToParcel(p: Parcel?, flags: Int) {}
override fun describeContents() = 0 override fun describeContents() = 0
} }
@Parcelize @Parcelize
class B(val a: String) : Parcelable { class B(val a: String) : Parcelable {
<error descr="[PLUGIN_ERROR] OVERRIDING_WRITE_TO_PARCEL_IS_NOT_ALLOWED: Overriding 'writeToParcel' is not allowed. Use 'Parceler' companion object instead.">override</error> fun writeToParcel(p: Parcel?, flags: Int) {} <error descr="[OVERRIDING_WRITE_TO_PARCEL_IS_NOT_ALLOWED] Overriding 'writeToParcel' is not allowed. Use 'Parceler' companion object instead.">override</error> fun writeToParcel(p: Parcel?, flags: Int) {}
} }
@Parcelize @Parcelize
class C(val a: String) : Parcelable { class C(val a: String) : Parcelable {
<error descr="[PLUGIN_ERROR] OVERRIDING_WRITE_TO_PARCEL_IS_NOT_ALLOWED: Overriding 'writeToParcel' is not allowed. Use 'Parceler' companion object instead.">override</error> fun writeToParcel(p: Parcel, flags: Int) {} <error descr="[OVERRIDING_WRITE_TO_PARCEL_IS_NOT_ALLOWED] Overriding 'writeToParcel' is not allowed. Use 'Parceler' companion object instead.">override</error> fun writeToParcel(p: Parcel, flags: Int) {}
} }
@@ -10,4 +10,4 @@ open class Delegate : Parcelable {
} }
@Parcelize @Parcelize
class Test : Parcelable <error descr="[PLUGIN_ERROR] PARCELABLE_DELEGATE_IS_NOT_ALLOWED: Delegating 'Parcelable' is now allowed">by</error> Delegate() class Test : Parcelable <error descr="[PARCELABLE_DELEGATE_IS_NOT_ALLOWED] Delegating 'Parcelable' is now allowed">by</error> Delegate()
@@ -7,4 +7,4 @@ import android.os.Parcelable
class User : Parcelable class User : Parcelable
@Parcelize @Parcelize
class <warning descr="[PLUGIN_WARNING] PARCELABLE_PRIMARY_CONSTRUCTOR_IS_EMPTY: The primary constructor is empty, no data will be serialized to 'Parcel'">User2</warning>() : Parcelable class <warning descr="[PARCELABLE_PRIMARY_CONSTRUCTOR_IS_EMPTY] The primary constructor is empty, no data will be serialized to 'Parcel'">User2</warning>() : Parcelable
@@ -17,4 +17,4 @@ class Foo(val box: Box): Parcelable {
} }
@Parcelize @Parcelize
class Foo2(val box: <error descr="[PLUGIN_ERROR] PARCELABLE_TYPE_NOT_SUPPORTED: Type is not directly supported by 'Parcelize'. Annotate the parameter type with '@RawValue' if you want it to be serialized using 'writeValue()'">Box</error>): Parcelable class Foo2(val box: <error descr="[PARCELABLE_TYPE_NOT_SUPPORTED] Type is not directly supported by 'Parcelize'. Annotate the parameter type with '@RawValue' if you want it to be serialized using 'writeValue()'">Box</error>): Parcelable
@@ -10,22 +10,22 @@ open class Open(val foo: String) : Parcelable
class Final(val foo: String) : Parcelable class Final(val foo: String) : Parcelable
@Parcelize @Parcelize
<error descr="[PLUGIN_ERROR] PARCELABLE_SHOULD_BE_INSTANTIABLE: 'Parcelable' should not be a 'sealed' or 'abstract' class">abstract</error> class Abstract(val foo: String) : Parcelable <error descr="[PARCELABLE_SHOULD_BE_INSTANTIABLE] 'Parcelable' should not be a 'sealed' or 'abstract' class">abstract</error> class Abstract(val foo: String) : Parcelable
@Parcelize @Parcelize
<error descr="[PLUGIN_ERROR] PARCELABLE_SHOULD_BE_INSTANTIABLE: 'Parcelable' should not be a 'sealed' or 'abstract' class">sealed</error> class Sealed(val foo: String) : Parcelable { <error descr="[PARCELABLE_SHOULD_BE_INSTANTIABLE] 'Parcelable' should not be a 'sealed' or 'abstract' class">sealed</error> class Sealed(val foo: String) : Parcelable {
class X : Sealed("") class X : Sealed("")
} }
class Outer { class Outer {
@Parcelize @Parcelize
<error descr="[PLUGIN_ERROR] PARCELABLE_CANT_BE_INNER_CLASS: 'Parcelable' can't be an inner class">inner</error> class Inner(val foo: String) : Parcelable <error descr="[PARCELABLE_CANT_BE_INNER_CLASS] 'Parcelable' can't be an inner class">inner</error> class Inner(val foo: String) : Parcelable
} }
fun foo() { fun foo() {
@Parcelize @Parcelize
<error descr="[PLUGIN_ERROR] PARCELABLE_SHOULD_BE_CLASS: 'Parcelable' should be a class">object</error> : Parcelable {} <error descr="[PARCELABLE_SHOULD_BE_CLASS] 'Parcelable' should be a class">object</error> : Parcelable {}
@Parcelize @Parcelize
class <error descr="[PLUGIN_ERROR] NO_PARCELABLE_SUPERTYPE: No 'Parcelable' supertype"><error descr="[PLUGIN_ERROR] PARCELABLE_CANT_BE_LOCAL_CLASS: 'Parcelable' can't be a local class">Local</error></error> {} class <error descr="[NO_PARCELABLE_SUPERTYPE] No 'Parcelable' supertype"><error descr="[PARCELABLE_CANT_BE_LOCAL_CLASS] 'Parcelable' can't be a local class">Local</error></error> {}
} }
@@ -5,11 +5,11 @@ import android.os.Parcelable
@Parcelize @Parcelize
class A(val firstName: String) : Parcelable { class A(val firstName: String) : Parcelable {
val <warning descr="[PLUGIN_WARNING] PROPERTY_WONT_BE_SERIALIZED: Property would not be serialized into a 'Parcel'. Add '@Transient' annotation to remove the warning">secondName</warning>: String = "" val <warning descr="[PROPERTY_WONT_BE_SERIALIZED] Property would not be serialized into a 'Parcel'. Add '@Transient' annotation to remove the warning">secondName</warning>: String = ""
val <warning descr="[PLUGIN_WARNING] PROPERTY_WONT_BE_SERIALIZED: Property would not be serialized into a 'Parcel'. Add '@Transient' annotation to remove the warning">delegated</warning> by lazy { "" } val <warning descr="[PROPERTY_WONT_BE_SERIALIZED] Property would not be serialized into a 'Parcel'. Add '@Transient' annotation to remove the warning">delegated</warning> by lazy { "" }
lateinit var <warning descr="[PLUGIN_WARNING] PROPERTY_WONT_BE_SERIALIZED: Property would not be serialized into a 'Parcel'. Add '@Transient' annotation to remove the warning">lateinit</warning>: String lateinit var <warning descr="[PROPERTY_WONT_BE_SERIALIZED] Property would not be serialized into a 'Parcel'. Add '@Transient' annotation to remove the warning">lateinit</warning>: String
val customGetter: String val customGetter: String
get() = "" get() = ""
@@ -7,9 +7,9 @@ import android.os.Parcelable
@Parcelize @Parcelize
class User( class User(
val a: String, val a: String,
val b: <error descr="[PLUGIN_ERROR] PARCELABLE_TYPE_NOT_SUPPORTED: Type is not directly supported by 'Parcelize'. Annotate the parameter type with '@RawValue' if you want it to be serialized using 'writeValue()'">Any</error>, val b: <error descr="[PARCELABLE_TYPE_NOT_SUPPORTED] Type is not directly supported by 'Parcelize'. Annotate the parameter type with '@RawValue' if you want it to be serialized using 'writeValue()'">Any</error>,
val c: <error descr="[PLUGIN_ERROR] PARCELABLE_TYPE_NOT_SUPPORTED: Type is not directly supported by 'Parcelize'. Annotate the parameter type with '@RawValue' if you want it to be serialized using 'writeValue()'">Any?</error>, val c: <error descr="[PARCELABLE_TYPE_NOT_SUPPORTED] Type is not directly supported by 'Parcelize'. Annotate the parameter type with '@RawValue' if you want it to be serialized using 'writeValue()'">Any?</error>,
val d: <error descr="[PLUGIN_ERROR] PARCELABLE_TYPE_NOT_SUPPORTED: Type is not directly supported by 'Parcelize'. Annotate the parameter type with '@RawValue' if you want it to be serialized using 'writeValue()'">Map<Any, String></error>, val d: <error descr="[PARCELABLE_TYPE_NOT_SUPPORTED] Type is not directly supported by 'Parcelize'. Annotate the parameter type with '@RawValue' if you want it to be serialized using 'writeValue()'">Map<Any, String></error>,
val e: @RawValue Any?, val e: @RawValue Any?,
val f: @RawValue Map<String, Any>, val f: @RawValue Map<String, Any>,
val g: Map<String, @RawValue Any>, val g: Map<String, @RawValue Any>,
@@ -4,7 +4,7 @@ import kotlinx.android.parcel.Parcelize
import android.os.Parcelable import android.os.Parcelable
@Parcelize @Parcelize
class <error descr="[PLUGIN_ERROR] NO_PARCELABLE_SUPERTYPE: No 'Parcelable' supertype">Without</error>(val firstName: String, val secondName: String, val age: Int) class <error descr="[NO_PARCELABLE_SUPERTYPE] No 'Parcelable' supertype">Without</error>(val firstName: String, val secondName: String, val age: Int)
@Parcelize @Parcelize
class With(val firstName: String, val secondName: String, val age: Int) : Parcelable class With(val firstName: String, val secondName: String, val age: Int) : Parcelable
@@ -4,22 +4,22 @@ import kotlinx.android.parcel.Parcelize
import android.os.Parcelable import android.os.Parcelable
@Parcelize @Parcelize
interface <error descr="[PLUGIN_ERROR] PARCELABLE_SHOULD_BE_CLASS: 'Parcelable' should be a class">Intf</error> : Parcelable interface <error descr="[PARCELABLE_SHOULD_BE_CLASS] 'Parcelable' should be a class">Intf</error> : Parcelable
@Parcelize @Parcelize
object <error descr="[PLUGIN_ERROR] PARCELABLE_SHOULD_BE_CLASS: 'Parcelable' should be a class">Obj</error> object <error descr="[PARCELABLE_SHOULD_BE_CLASS] 'Parcelable' should be a class">Obj</error>
class A { class A {
@Parcelize @Parcelize
companion <error descr="[PLUGIN_ERROR] PARCELABLE_SHOULD_BE_CLASS: 'Parcelable' should be a class">object</error> { companion <error descr="[PARCELABLE_SHOULD_BE_CLASS] 'Parcelable' should be a class">object</error> {
fun foo() {} fun foo() {}
} }
} }
@Parcelize @Parcelize
enum class <error descr="[PLUGIN_ERROR] PARCELABLE_SHOULD_BE_CLASS: 'Parcelable' should be a class">Enum</error> { enum class <error descr="[PARCELABLE_SHOULD_BE_CLASS] 'Parcelable' should be a class">Enum</error> {
WHITE, BLACK WHITE, BLACK
} }
@Parcelize @Parcelize
annotation class <error descr="[PLUGIN_ERROR] PARCELABLE_SHOULD_BE_CLASS: 'Parcelable' should be a class">Anno</error> annotation class <error descr="[PARCELABLE_SHOULD_BE_CLASS] 'Parcelable' should be a class">Anno</error>
@@ -0,0 +1,14 @@
// "Add empty primary constructor" "true"
// ERROR: 'Parcelable' should have a primary constructor
// WITH_RUNTIME
package com.myapp.activity
import android.os.Parcelable
import kotlinx.android.parcel.Parcelize
@Parcelize
class <caret>Test() : Parcelable {
constructor(s: String) : this()
constructor(s: String, i: Int) : this(s)
}
@@ -0,0 +1,14 @@
// "Add empty primary constructor" "true"
// ERROR: 'Parcelable' should have a primary constructor
// WITH_RUNTIME
package com.myapp.activity
import android.os.Parcelable
import kotlinx.android.parcel.Parcelize
@Parcelize
class <caret>Test : Parcelable {
constructor(s: String)
constructor(s: String, i: Int) : this(s)
}
@@ -0,0 +1,11 @@
// "Add empty primary constructor" "false"
// IGNORE_IRRELEVANT_ACTIONS
// WITH_RUNTIME
package com.myapp.activity
import android.os.Parcelable
import kotlinx.android.parcel.Parcelize
@Parcelize
class <caret>Test() : Parcelable
@@ -0,0 +1,13 @@
// "Add empty primary constructor" "true"
// ERROR: 'Parcelable' should have a primary constructor
// WITH_RUNTIME
package com.myapp.activity
import android.os.Parcelable
import kotlinx.android.parcel.Parcelize
@Parcelize
class <caret>Test() : Parcelable {
constructor(a: Int) : this()
}
@@ -0,0 +1,13 @@
// "Add empty primary constructor" "true"
// ERROR: 'Parcelable' should have a primary constructor
// WITH_RUNTIME
package com.myapp.activity
import android.os.Parcelable
import kotlinx.android.parcel.Parcelize
@Parcelize
class <caret>Test : Parcelable {
constructor(a: Int)
}
@@ -0,0 +1,13 @@
// "Remove 'inner' modifier" "true"
// ERROR: 'Parcelable' can't be an inner class
// WITH_RUNTIME
package com.myapp.activity
import android.os.Parcelable
import kotlinx.android.parcel.Parcelize
class Foo {
@Parcelize<caret>
class Bar : Parcelable
}
@@ -0,0 +1,13 @@
// "Remove 'inner' modifier" "true"
// ERROR: 'Parcelable' can't be an inner class
// WITH_RUNTIME
package com.myapp.activity
import android.os.Parcelable
import kotlinx.android.parcel.Parcelize
class Foo {
@Parcelize
<caret>inner class Bar : Parcelable
}
@@ -0,0 +1,24 @@
// "Remove custom ''CREATOR'' property" "true"
// ERROR: 'CREATOR' definition is not allowed. Use 'Parceler' companion object instead.
// ERROR: Overriding 'writeToParcel' is not allowed. Use 'Parceler' companion object instead.
// WITH_RUNTIME
package com.myapp.activity
import android.os.*
import kotlinx.android.parcel.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
}
<caret>}
@@ -0,0 +1,37 @@
// "Remove custom ''CREATOR'' property" "true"
// ERROR: 'CREATOR' definition is not allowed. Use 'Parceler' companion object instead.
// ERROR: Overriding 'writeToParcel' is not allowed. Use 'Parceler' companion object instead.
// WITH_RUNTIME
package com.myapp.activity
import android.os.*
import kotlinx.android.parcel.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 <caret>CREATOR = object : Parcelable.Creator<Foo> {
override fun createFromParcel(parcel: Parcel): Foo {
return Foo(parcel)
}
override fun newArray(size: Int): Array<Foo?> {
return arrayOfNulls(size)
}
}
}
}
@@ -0,0 +1,30 @@
// "Remove custom ''writeToParcel()'' function" "true"
// ERROR: 'CREATOR' definition is not allowed. Use 'Parceler' companion object instead.
// ERROR: Overriding 'writeToParcel' is not allowed. Use 'Parceler' companion object instead.
// WITH_RUNTIME
package com.myapp.activity
import android.os.*
import kotlinx.android.parcel.Parcelize
@Parcelize
class Foo(val a: String) : Parcelable {
constructor(parcel: Parcel) : this(parcel.readString()) {
}
<caret>override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<Foo> {
override fun createFromParcel(parcel: Parcel): Foo {
return Foo(parcel)
}
override fun newArray(size: Int): Array<Foo?> {
return arrayOfNulls(size)
}
}
}
@@ -0,0 +1,34 @@
// "Remove custom ''writeToParcel()'' function" "true"
// ERROR: 'CREATOR' definition is not allowed. Use 'Parceler' companion object instead.
// ERROR: Overriding 'writeToParcel' is not allowed. Use 'Parceler' companion object instead.
// WITH_RUNTIME
package com.myapp.activity
import android.os.*
import kotlinx.android.parcel.Parcelize
@Parcelize
class Foo(val a: String) : Parcelable {
constructor(parcel: Parcel) : this(parcel.readString()) {
}
<caret>override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(a)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<Foo> {
override fun createFromParcel(parcel: Parcel): Foo {
return Foo(parcel)
}
override fun newArray(size: Int): Array<Foo?> {
return arrayOfNulls(size)
}
}
}
@@ -0,0 +1,30 @@
// "Migrate to ''Parceler'' companion object" "true"
// ERROR: 'CREATOR' definition is not allowed. Use 'Parceler' companion object instead.
// ERROR: Overriding 'writeToParcel' is not allowed. Use 'Parceler' companion object instead.
// WITH_RUNTIME
package com.myapp.activity
import android.os.*
import kotlinx.android.parcel.Parceler
import kotlinx.android.parcel.Parcelize
@Parcelize
class Foo(val firstName: String, val age: Int) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString(),
parcel.readInt()) {
}
<caret>companion object : Parceler<Foo> {
override fun Foo.write(parcel: Parcel, flags: Int) {
parcel.writeString(firstName)
parcel.writeInt(age)
}
override fun create(parcel: Parcel): Foo {
return Foo(parcel)
}
}
}
@@ -0,0 +1,36 @@
// "Migrate to ''Parceler'' companion object" "true"
// ERROR: 'CREATOR' definition is not allowed. Use 'Parceler' companion object instead.
// ERROR: Overriding 'writeToParcel' is not allowed. Use 'Parceler' companion object instead.
// WITH_RUNTIME
package com.myapp.activity
import android.os.*
import kotlinx.android.parcel.Parcelize
@Parcelize
class Foo(val firstName: String, val age: Int) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString(),
parcel.readInt()) {
}
<caret>override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(firstName)
parcel.writeInt(age)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<Foo> {
override fun createFromParcel(parcel: Parcel): Foo {
return Foo(parcel)
}
override fun newArray(size: Int): Array<Foo?> {
return arrayOfNulls(size)
}
}
}
@@ -0,0 +1,34 @@
// "Migrate to ''Parceler'' companion object" "true"
// ERROR: 'CREATOR' definition is not allowed. Use 'Parceler' companion object instead.
// ERROR: Overriding 'writeToParcel' is not allowed. Use 'Parceler' companion object instead.
// WITH_RUNTIME
package com.myapp.activity
import android.os.*
import kotlinx.android.parcel.Parceler
import kotlinx.android.parcel.Parcelize
@Parcelize
class Foo(val firstName: String, val age: Int) : Parcelable {
constructor(parcel: Parcel) : this(parcel.readString(), parcel.readInt())
companion object : Parceler<Foo> {
<caret>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<Foo> {
override fun createFromParcel(parcel: Parcel): Foo {
return Foo(parcel)
}
override fun newArray(size: Int): Array<Foo?> {
return arrayOfNulls(size)
}
}
}
@@ -0,0 +1,34 @@
// "Migrate to ''Parceler'' companion object" "true"
// ERROR: 'CREATOR' definition is not allowed. Use 'Parceler' companion object instead.
// ERROR: Overriding 'writeToParcel' is not allowed. Use 'Parceler' companion object instead.
// WITH_RUNTIME
package com.myapp.activity
import android.os.*
import kotlinx.android.parcel.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 <caret>CREATOR: Parcelable.Creator<Foo> = object : Creator() {}
}
private abstract class Creator : Parcelable.Creator<Foo> {
override fun createFromParcel(parcel: Parcel): Foo {
return Foo(parcel)
}
override fun newArray(size: Int): Array<Foo?> {
return arrayOfNulls(size)
}
}
}
@@ -0,0 +1,34 @@
// "Migrate to ''Parceler'' companion object" "true"
// ERROR: 'CREATOR' definition is not allowed. Use 'Parceler' companion object instead.
// ERROR: Overriding 'writeToParcel' is not allowed. Use 'Parceler' companion object instead.
// WITH_RUNTIME
package com.myapp.activity
import android.os.*
import kotlinx.android.parcel.Parceler
import kotlinx.android.parcel.Parcelize
@Parcelize
class Foo(val firstName: String, val age: Int) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString(),
parcel.readInt()) {
}
<caret>override fun describeContents(): Int {
return 50
}
companion object : Parceler<Foo> {
override fun Foo.write(parcel: Parcel, flags: Int) {
parcel.writeString(firstName)
parcel.writeInt(age)
}
override fun create(parcel: Parcel): Foo {
return Foo(parcel)
}
}
}
@@ -0,0 +1,36 @@
// "Migrate to ''Parceler'' companion object" "true"
// ERROR: 'CREATOR' definition is not allowed. Use 'Parceler' companion object instead.
// ERROR: Overriding 'writeToParcel' is not allowed. Use 'Parceler' companion object instead.
// WITH_RUNTIME
package com.myapp.activity
import android.os.*
import kotlinx.android.parcel.Parcelize
@Parcelize
class Foo(val firstName: String, val age: Int) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString(),
parcel.readInt()) {
}
<caret>override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(firstName)
parcel.writeInt(age)
}
override fun describeContents(): Int {
return 50
}
companion object CREATOR : Parcelable.Creator<Foo> {
override fun createFromParcel(parcel: Parcel): Foo {
return Foo(parcel)
}
override fun newArray(size: Int): Array<Foo?> {
return arrayOfNulls(size)
}
}
}
@@ -0,0 +1,30 @@
// "Migrate to ''Parceler'' companion object" "true"
// ERROR: 'CREATOR' definition is not allowed. Use 'Parceler' companion object instead.
// ERROR: Overriding 'writeToParcel' is not allowed. Use 'Parceler' companion object instead.
// WITH_RUNTIME
package com.myapp.activity
import android.os.*
import kotlinx.android.parcel.Parceler
import kotlinx.android.parcel.Parcelize
@Parcelize
class Foo(val firstName: String, val age: Int) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString(),
parcel.readInt()) {
}
companion object <caret>: Parceler<Foo> {
override fun Foo.write(parcel: Parcel, flags: Int) {
parcel.writeString(firstName)
parcel.writeInt(age)
}
override fun create(parcel: Parcel): Foo {
return Foo(parcel)
}
}
}
@@ -0,0 +1,32 @@
// "Migrate to ''Parceler'' companion object" "true"
// ERROR: 'CREATOR' definition is not allowed. Use 'Parceler' companion object instead.
// ERROR: Overriding 'writeToParcel' is not allowed. Use 'Parceler' companion object instead.
// WITH_RUNTIME
package com.myapp.activity
import android.os.*
import kotlinx.android.parcel.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 <caret>CREATOR : Parcelable.Creator<Foo> {
override fun createFromParcel(parcel: Parcel): Foo {
return Foo(parcel)
}
override fun newArray(size: Int): Array<Foo?> {
return arrayOfNulls(size)
}
}
}
@@ -0,0 +1,36 @@
// "Migrate to ''Parceler'' companion object" "true"
// ERROR: 'CREATOR' definition is not allowed. Use 'Parceler' companion object instead.
// ERROR: Overriding 'writeToParcel' is not allowed. Use 'Parceler' companion object instead.
// WITH_RUNTIME
package com.myapp.activity
import android.os.*
import kotlinx.android.parcel.Parceler
import kotlinx.android.parcel.Parcelize
@Parcelize
class Foo(val firstName: String, val age: Int) : Parcelable {
constructor(parcel: Parcel) : this(parcel.readString(), parcel.readInt())
companion object : Parceler<Foo> {
<caret>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<Foo> {
override fun createFromParcel(parcel: Parcel): Foo {
return Foo(parcel)
}
override fun newArray(size: Int): Array<Foo?> {
return arrayOfNulls(size)
}
}
}
@@ -0,0 +1,34 @@
// "Migrate to ''Parceler'' companion object" "true"
// ERROR: 'CREATOR' definition is not allowed. Use 'Parceler' companion object instead.
// ERROR: Overriding 'writeToParcel' is not allowed. Use 'Parceler' companion object instead.
// WITH_RUNTIME
package com.myapp.activity
import android.os.*
import kotlinx.android.parcel.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 <caret>CREATOR: Parcelable.Creator<Foo> = Creator()
}
private class Creator : Parcelable.Creator<Foo> {
override fun createFromParcel(parcel: Parcel): Foo {
return Foo(parcel)
}
override fun newArray(size: Int): Array<Foo?> {
return arrayOfNulls(size)
}
}
}
@@ -0,0 +1,26 @@
// "Migrate to ''Parceler'' companion object" "true"
// ERROR: 'CREATOR' definition is not allowed. Use 'Parceler' companion object instead.
// ERROR: Overriding 'writeToParcel' is not allowed. Use 'Parceler' companion object instead.
// WITH_RUNTIME
package com.myapp.activity
import android.os.*
import kotlinx.android.parcel.Parceler
import kotlinx.android.parcel.Parcelize
@Parcelize
class Foo(val firstName: String, val age: Int) : Parcelable {
constructor(parcel: Parcel) : this(parcel.readString(), parcel.readInt())
companion object : Parceler<Foo> {
<caret>override fun Foo.write(parcel: Parcel, flags: Int) {
parcel.writeString(firstName)
parcel.writeInt(age)
}
override fun create(parcel: Parcel): Foo {
return Foo(parcel)
}
}
}
@@ -0,0 +1,32 @@
// "Migrate to ''Parceler'' companion object" "true"
// ERROR: 'CREATOR' definition is not allowed. Use 'Parceler' companion object instead.
// ERROR: Overriding 'writeToParcel' is not allowed. Use 'Parceler' companion object instead.
// WITH_RUNTIME
package com.myapp.activity
import android.os.*
import kotlinx.android.parcel.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 <caret>CREATOR = object : Parcelable.Creator<Foo> {
override fun createFromParcel(parcel: Parcel): Foo {
return Foo(parcel)
}
override fun newArray(size: Int): Array<Foo?> {
return arrayOfNulls(size)
}
}
}
}
@@ -0,0 +1,25 @@
// "Migrate to ''Parceler'' companion object" "true"
// ERROR: 'CREATOR' definition is not allowed. Use 'Parceler' companion object instead.
// WITH_RUNTIME
package com.myapp.activity
import android.os.*
import kotlinx.android.parcel.Parceler
import kotlinx.android.parcel.Parcelize
@Parcelize
class Foo(val firstName: String, val age: Int) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString(),
parcel.readInt()) {
}
companion object <caret>: Parceler<Foo> {
fun Foo.write(parcel: Parcel, flags: Int) = TODO()
override fun create(parcel: Parcel): Foo {
return Foo(parcel)
}
}
}
@@ -0,0 +1,30 @@
// "Migrate to ''Parceler'' companion object" "true"
// ERROR: 'CREATOR' definition is not allowed. Use 'Parceler' companion object instead.
// WITH_RUNTIME
package com.myapp.activity
import android.os.*
import kotlinx.android.parcel.Parcelize
@Parcelize
class Foo(val firstName: String, val age: Int) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString(),
parcel.readInt()) {
}
override fun describeContents(): Int {
return 0
}
companion object <caret>CREATOR : Parcelable.Creator<Foo> {
override fun createFromParcel(parcel: Parcel): Foo {
return Foo(parcel)
}
override fun newArray(size: Int): Array<Foo?> {
return arrayOfNulls(size)
}
}
}
@@ -0,0 +1,30 @@
// "Migrate to ''Parceler'' companion object" "true"
// ERROR: 'CREATOR' definition is not allowed. Use 'Parceler' companion object instead.
// ERROR: Overriding 'writeToParcel' is not allowed. Use 'Parceler' companion object instead.
// WITH_RUNTIME
package com.myapp.activity
import android.os.*
import kotlinx.android.parcel.Parceler
import kotlinx.android.parcel.Parcelize
@Parcelize
class Foo(val firstName: String, val age: Int) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString(),
parcel.readInt()) {
}
<caret>companion object : Parceler<Foo> {
override fun Foo.write(parcel: Parcel, flags: Int) {
parcel.writeString(firstName)
parcel.writeInt(age)
}
override fun create(parcel: Parcel): Foo {
return Foo(parcel)
}
}
}
@@ -0,0 +1,32 @@
// "Migrate to ''Parceler'' companion object" "true"
// ERROR: 'CREATOR' definition is not allowed. Use 'Parceler' companion object instead.
// ERROR: Overriding 'writeToParcel' is not allowed. Use 'Parceler' companion object instead.
// WITH_RUNTIME
package com.myapp.activity
import android.os.*
import kotlinx.android.parcel.Parcelize
@Parcelize
class Foo(val firstName: String, val age: Int) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString(),
parcel.readInt()) {
}
<caret>override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(firstName)
parcel.writeInt(age)
}
companion object CREATOR : Parcelable.Creator<Foo> {
override fun createFromParcel(parcel: Parcel): Foo {
return Foo(parcel)
}
override fun newArray(size: Int): Array<Foo?> {
return arrayOfNulls(size)
}
}
}
@@ -0,0 +1,13 @@
// "Add ''Parcelable'' supertype" "false"
// IGNORE_IRRELEVANT_ACTIONS
// WITH_RUNTIME
package com.myapp.activity
import android.os.Parcelable
import kotlinx.android.parcel.Parcelize
abstract class AbstractParcelable : Parcelable
@Parcelize
class <caret>Test(val s: String) : AbstractParcelable()
@@ -0,0 +1,11 @@
// "Add ''Parcelable'' supertype" "true"
// ERROR: No 'Parcelable' supertype
// WITH_RUNTIME
package com.myapp.activity
import android.os.Parcelable
import kotlinx.android.parcel.Parcelize
@Parcelize
class <caret>Test(val s: String) : Parcelable
@@ -0,0 +1,11 @@
// "Add ''Parcelable'' supertype" "true"
// ERROR: No 'Parcelable' supertype
// WITH_RUNTIME
package com.myapp.activity
import android.os.Parcelable
import kotlinx.android.parcel.Parcelize
@Parcelize
class <caret>Test(val s: String)
@@ -0,0 +1,13 @@
// "Add ''@Transient'' annotation" "true"
// WITH_RUNTIME
package com.myapp.activity
import android.os.Parcelable
import kotlinx.android.parcel.Parcelize
@Parcelize
class Test : Parcelable {
@Transient
val <caret>a = 5
}
@@ -0,0 +1,12 @@
// "Add ''@Transient'' annotation" "true"
// WITH_RUNTIME
package com.myapp.activity
import android.os.Parcelable
import kotlinx.android.parcel.Parcelize
@Parcelize
class Test : Parcelable {
val <caret>a = 5
}
@@ -0,0 +1,39 @@
/*
* 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.android
import org.jetbrains.kotlin.android.quickfix.AbstractAndroidQuickFixMultiFileTest
import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil
import java.io.File
open class AbstractParcelQuickFixTest : AbstractAndroidQuickFixMultiFileTest() {
override fun setUp() {
super.setUp()
val androidJarDir = File("dependencies/androidSDK/platforms").listFiles().first { it.name.startsWith("android-") }
ConfigLibraryUtil.addLibrary(myModule, "androidJar", androidJarDir.absolutePath, arrayOf("android.jar"))
ConfigLibraryUtil.addLibrary(myModule, "androidExtensionsRuntime", "dist/kotlinc/lib", arrayOf("android-extensions-runtime.jar"))
}
override fun tearDown() {
ConfigLibraryUtil.removeLibrary(myModule, "androidJar")
ConfigLibraryUtil.removeLibrary(myModule, "androidExtensionsRuntime")
super.tearDown()
}
}
@@ -0,0 +1,194 @@
/*
* 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.android;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.TargetBackend;
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/android-extensions/android-extensions-idea/testData/android/parcel/quickfix")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public class ParcelQuickFixTestGenerated extends AbstractParcelQuickFixTest {
public void testAllFilesPresentInQuickfix() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("plugins/android-extensions/android-extensions-idea/testData/android/parcel/quickfix"), Pattern.compile("^(\\w+)\\.((before\\.Main\\.\\w+)|(test))$"), TargetBackend.ANY, true);
}
@TestMetadata("plugins/android-extensions/android-extensions-idea/testData/android/parcel/quickfix/addPrimaryConstructor")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class AddPrimaryConstructor extends AbstractParcelQuickFixTest {
public void testAllFilesPresentInAddPrimaryConstructor() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("plugins/android-extensions/android-extensions-idea/testData/android/parcel/quickfix/addPrimaryConstructor"), Pattern.compile("^(\\w+)\\.((before\\.Main\\.\\w+)|(test))$"), TargetBackend.ANY, true);
}
@TestMetadata("constructorWithDelegate.before.Main.kt")
public void testConstructorWithDelegate() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/android-extensions/android-extensions-idea/testData/android/parcel/quickfix/addPrimaryConstructor/constructorWithDelegate.before.Main.kt");
doTestWithExtraFile(fileName);
}
@TestMetadata("noQuickFix.before.Main.kt")
public void testNoQuickFix() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/android-extensions/android-extensions-idea/testData/android/parcel/quickfix/addPrimaryConstructor/noQuickFix.before.Main.kt");
doTestWithExtraFile(fileName);
}
@TestMetadata("simple.before.Main.kt")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/android-extensions/android-extensions-idea/testData/android/parcel/quickfix/addPrimaryConstructor/simple.before.Main.kt");
doTestWithExtraFile(fileName);
}
}
@TestMetadata("plugins/android-extensions/android-extensions-idea/testData/android/parcel/quickfix/cantBeInnerClass")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class CantBeInnerClass extends AbstractParcelQuickFixTest {
public void testAllFilesPresentInCantBeInnerClass() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("plugins/android-extensions/android-extensions-idea/testData/android/parcel/quickfix/cantBeInnerClass"), Pattern.compile("^(\\w+)\\.((before\\.Main\\.\\w+)|(test))$"), TargetBackend.ANY, true);
}
@TestMetadata("simple.before.Main.kt")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/android-extensions/android-extensions-idea/testData/android/parcel/quickfix/cantBeInnerClass/simple.before.Main.kt");
doTestWithExtraFile(fileName);
}
}
@TestMetadata("plugins/android-extensions/android-extensions-idea/testData/android/parcel/quickfix/deleteIncompatible")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class DeleteIncompatible extends AbstractParcelQuickFixTest {
public void testAllFilesPresentInDeleteIncompatible() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("plugins/android-extensions/android-extensions-idea/testData/android/parcel/quickfix/deleteIncompatible"), Pattern.compile("^(\\w+)\\.((before\\.Main\\.\\w+)|(test))$"), TargetBackend.ANY, true);
}
@TestMetadata("creatorField.before.Main.kt")
public void testCreatorField() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/android-extensions/android-extensions-idea/testData/android/parcel/quickfix/deleteIncompatible/creatorField.before.Main.kt");
doTestWithExtraFile(fileName);
}
@TestMetadata("writeToParcel.before.Main.kt")
public void testWriteToParcel() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/android-extensions/android-extensions-idea/testData/android/parcel/quickfix/deleteIncompatible/writeToParcel.before.Main.kt");
doTestWithExtraFile(fileName);
}
}
@TestMetadata("plugins/android-extensions/android-extensions-idea/testData/android/parcel/quickfix/migrations")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Migrations extends AbstractParcelQuickFixTest {
public void testAllFilesPresentInMigrations() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("plugins/android-extensions/android-extensions-idea/testData/android/parcel/quickfix/migrations"), Pattern.compile("^(\\w+)\\.((before\\.Main\\.\\w+)|(test))$"), TargetBackend.ANY, true);
}
@TestMetadata("basic.before.Main.kt")
public void testBasic() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/android-extensions/android-extensions-idea/testData/android/parcel/quickfix/migrations/basic.before.Main.kt");
doTestWithExtraFile(fileName);
}
@TestMetadata("complexCase1.before.Main.kt")
public void testComplexCase1() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/android-extensions/android-extensions-idea/testData/android/parcel/quickfix/migrations/complexCase1.before.Main.kt");
doTestWithExtraFile(fileName);
}
@TestMetadata("customDescribeContents.before.Main.kt")
public void testCustomDescribeContents() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/android-extensions/android-extensions-idea/testData/android/parcel/quickfix/migrations/customDescribeContents.before.Main.kt");
doTestWithExtraFile(fileName);
}
@TestMetadata("fromCreatorObject.before.Main.kt")
public void testFromCreatorObject() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/android-extensions/android-extensions-idea/testData/android/parcel/quickfix/migrations/fromCreatorObject.before.Main.kt");
doTestWithExtraFile(fileName);
}
@TestMetadata("innerClassFactory.before.Main.kt")
public void testInnerClassFactory() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/android-extensions/android-extensions-idea/testData/android/parcel/quickfix/migrations/innerClassFactory.before.Main.kt");
doTestWithExtraFile(fileName);
}
@TestMetadata("jvmField.before.Main.kt")
public void testJvmField() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/android-extensions/android-extensions-idea/testData/android/parcel/quickfix/migrations/jvmField.before.Main.kt");
doTestWithExtraFile(fileName);
}
@TestMetadata("noWriteToParcel.before.Main.kt")
public void testNoWriteToParcel() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/android-extensions/android-extensions-idea/testData/android/parcel/quickfix/migrations/noWriteToParcel.before.Main.kt");
doTestWithExtraFile(fileName);
}
@TestMetadata("withoutDescribeContents.before.Main.kt")
public void testWithoutDescribeContents() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/android-extensions/android-extensions-idea/testData/android/parcel/quickfix/migrations/withoutDescribeContents.before.Main.kt");
doTestWithExtraFile(fileName);
}
}
@TestMetadata("plugins/android-extensions/android-extensions-idea/testData/android/parcel/quickfix/noParcelableSupertype")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class NoParcelableSupertype extends AbstractParcelQuickFixTest {
public void testAllFilesPresentInNoParcelableSupertype() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("plugins/android-extensions/android-extensions-idea/testData/android/parcel/quickfix/noParcelableSupertype"), Pattern.compile("^(\\w+)\\.((before\\.Main\\.\\w+)|(test))$"), TargetBackend.ANY, true);
}
@TestMetadata("alreadyHasSupertype.before.Main.kt")
public void testAlreadyHasSupertype() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/android-extensions/android-extensions-idea/testData/android/parcel/quickfix/noParcelableSupertype/alreadyHasSupertype.before.Main.kt");
doTestWithExtraFile(fileName);
}
@TestMetadata("simple.before.Main.kt")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/android-extensions/android-extensions-idea/testData/android/parcel/quickfix/noParcelableSupertype/simple.before.Main.kt");
doTestWithExtraFile(fileName);
}
}
@TestMetadata("plugins/android-extensions/android-extensions-idea/testData/android/parcel/quickfix/propertyWontBeSerialized")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class PropertyWontBeSerialized extends AbstractParcelQuickFixTest {
public void testAllFilesPresentInPropertyWontBeSerialized() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("plugins/android-extensions/android-extensions-idea/testData/android/parcel/quickfix/propertyWontBeSerialized"), Pattern.compile("^(\\w+)\\.((before\\.Main\\.\\w+)|(test))$"), TargetBackend.ANY, true);
}
@TestMetadata("simple.before.Main.kt")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/android-extensions/android-extensions-idea/testData/android/parcel/quickfix/propertyWontBeSerialized/simple.before.Main.kt");
doTestWithExtraFile(fileName);
}
}
}
@@ -21,6 +21,7 @@ import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.android.util.AndroidBundle import org.jetbrains.android.util.AndroidBundle
import org.jetbrains.kotlin.android.canAddParcelable import org.jetbrains.kotlin.android.canAddParcelable
import org.jetbrains.kotlin.android.implementParcelable import org.jetbrains.kotlin.android.implementParcelable
import org.jetbrains.kotlin.android.isParcelize
import org.jetbrains.kotlin.psi.KtClass import org.jetbrains.kotlin.psi.KtClass
@@ -29,8 +30,10 @@ class ParcelableQuickFix : AndroidLintQuickFix {
startElement.getTargetClass()?.implementParcelable() startElement.getTargetClass()?.implementParcelable()
} }
override fun isApplicable(startElement: PsiElement, endElement: PsiElement, contextType: AndroidQuickfixContexts.ContextType): Boolean = override fun isApplicable(startElement: PsiElement, endElement: PsiElement, contextType: AndroidQuickfixContexts.ContextType): Boolean {
startElement.getTargetClass()?.canAddParcelable() ?: false val targetClass = startElement.getTargetClass() ?: return false
return targetClass.canAddParcelable() && !targetClass.isParcelize()
}
override fun getName(): String = AndroidBundle.message("implement.parcelable.intention.text") override fun getName(): String = AndroidBundle.message("implement.parcelable.intention.text")