Add intentions Add/Remove/Redo parcelable implementation

#KT-17465 Fixed
#KT-12049 Fixed
This commit is contained in:
Vyacheslav Gerasimov
2017-04-18 18:53:51 +03:00
parent 37c3d8f204
commit 5b58a6f9e8
71 changed files with 2583 additions and 2 deletions
@@ -1040,6 +1040,10 @@ public abstract class KotlinBuiltIns {
return descriptor.getContainingDeclaration() == getAny();
}
public static boolean isCharSequence(@Nullable KotlinType type) {
return type != null && isNotNullConstructedFromGivenClass(type, FQ_NAMES.charSequence);
}
public static boolean isString(@Nullable KotlinType type) {
return type != null && isNotNullConstructedFromGivenClass(type, FQ_NAMES.string);
}
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.allopen.AbstractBytecodeListingTestForAllOpen
import org.jetbrains.kotlin.android.*
import org.jetbrains.kotlin.android.configure.AbstractConfigureProjectTest
import org.jetbrains.kotlin.android.folding.AbstractAndroidResourceFoldingTest
import org.jetbrains.kotlin.android.intention.AbstractAndroidIntentionTest
import org.jetbrains.kotlin.android.intention.AbstractAndroidResourceIntentionTest
import org.jetbrains.kotlin.android.lint.AbstractKotlinLintTest
import org.jetbrains.kotlin.android.quickfix.AbstractAndroidLintQuickfixTest
@@ -1232,6 +1233,10 @@ fun main(args: Array<String>) {
model("configuration/android-gradle", pattern = """(\w+)_before\.gradle$""", testMethod = "doTestAndroidGradle")
}
testClass<AbstractAndroidIntentionTest> {
model("android/intention", pattern = "^([\\w\\-_]+)\\.kt$")
}
testClass<AbstractAndroidResourceIntentionTest> {
model("android/resourceIntention", extension = "test", singleClass = true)
}
@@ -0,0 +1,22 @@
/*
* 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.idea.editor.fixers.range
import org.jetbrains.kotlin.psi.KtClass
internal fun KtClass.insideBody(offset: Int): Boolean = getBody()?.range?.contains(offset) ?: false
@@ -0,0 +1,470 @@
/*
* 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.android.SdkConstants.CLASS_PARCEL
import com.android.SdkConstants.CLASS_PARCELABLE
import com.intellij.openapi.fileEditor.FileDocumentManager
import com.intellij.psi.PsiDocumentManager
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.codeInsight.shorten.addToShorteningWaitSet
import org.jetbrains.kotlin.idea.codeInsight.shorten.performDelayedRefactoringRequests
import org.jetbrains.kotlin.idea.intentions.getLeftMostReceiverExpression
import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor
import org.jetbrains.kotlin.idea.search.usagesSearch.propertyDescriptor
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.types.KotlinType
private val CREATOR_NAME = "CREATOR"
private val PARCEL_NAME = "parcel"
private val CREATOR_TEXT =
"companion object $CREATOR_NAME : android.os.Parcelable.Creator<%1\$s> {\n" +
" override fun createFromParcel($PARCEL_NAME: $CLASS_PARCEL): %1\$s {\n" +
" return %1\$s($PARCEL_NAME)\n" +
" }\n\n" +
" override fun newArray(size: Int): Array<%1\$s?> {\n" +
" return arrayOfNulls(size)\n" +
" }\n" +
"}"
private val WRITE_TO_PARCEL_TEXT = "override fun writeToParcel($PARCEL_NAME: $CLASS_PARCEL, flags: Int) {\n}"
private val WRITE_TO_PARCEL_SUPER_CALL_TEXT = "super.writeToParcel($PARCEL_NAME, flags)"
private val WRITE_TO_PARCEL_WITH_SUPER_TEXT =
"override fun writeToParcel($PARCEL_NAME: $CLASS_PARCEL, flags: Int) {\n$WRITE_TO_PARCEL_SUPER_CALL_TEXT\n}"
private val DESCRIBE_CONTENTS_TEXT = "override fun describeContents(): Int {\nreturn 0\n}"
private val CONSTRUCTOR_TEXT = "constructor($PARCEL_NAME: $CLASS_PARCEL)"
fun KtClass.canAddParcelable(): Boolean =
findParcelableSupertype() == null
|| findCreator() == null
|| findConstructorFromParcel() == null
|| findWriteToParcel() == null
|| findDescribeContents() == null
fun KtClass.canRedoParcelable(): Boolean = canRemoveParcelable()
fun KtClass.canRemoveParcelable(): Boolean =
findParcelableSupertype()?.takeIf { it.typeReference?.isParcelableReference() ?: false }
?: findCreator()
?: findConstructorFromParcel()
?: findWriteToParcel()
?: findDescribeContents() != null
fun KtClass.implementParcelable() {
val factory = KtPsiFactory(this)
val superExtendsParcelable = superExtendsParcelable()
findOrCreateParcelableSupertype(factory)
val constructor = findOrCreateConstructor(factory)
addFieldReads(constructor, factory)
val writeToParcel = findOrCreateWriteToParcel(factory, superExtendsParcelable)
addFieldWrites(writeToParcel, factory, superExtendsParcelable)
findOrCreateDescribeContents(factory)
findOrCreateCreator(factory)
performDelayedRefactoringRequests(project)
save()
}
fun KtClass.removeParcelableImplementation() {
findParcelableSupertype()?.takeIf { it.typeReference?.isParcelableReference() ?: false }?.let {
removeSuperTypeListEntry(it)
}
findConstructorFromParcel()?.let {
if (it is KtPrimaryConstructor) {
tryDeleteInitBlock()
}
it.delete()
}
findWriteToParcel()?.delete()
findDescribeContents()?.delete()
findCreator()?.delete()
save()
}
fun KtClass.reimplementParcelable() {
removeParcelableImplementation()
implementParcelable()
}
private fun KtClass.findCreator(): KtObjectDeclaration? = companionObjects.find { it.name == CREATOR_NAME }
private fun KtClass.findParcelableSupertype(): KtSuperTypeListEntry? = getSuperTypeList()?.findParcelable()
private fun KtSuperTypeList.findParcelable() = entries?.find { it.typeReference?.isParcelableSuccessorReference() ?: false }
private fun KtTypeReference.isParcelableSuccessorReference() =
analyze(BodyResolveMode.PARTIAL)[BindingContext.TYPE, this]?.isSubclassOfParcelable() ?: false
private fun KtClass.superExtendsParcelable() = superTypeListEntries.find { it.typeReference?.extendsParcelable() ?: false } != null
private fun KtClass.tryDeleteInitBlock() {
getAnonymousInitializers().forEach { initializer ->
val block = initializer.body as? KtBlockExpression
if (block != null) {
block.statements.forEach { statement ->
if (statement.isReadFromParcelPropertyAssignment()) {
statement.delete()
}
}
if (block.statements.isEmpty()) {
initializer.delete()
}
}
}
}
private fun KtExpression.isReadFromParcelPropertyAssignment(): Boolean {
if (this !is KtBinaryExpression || this.operationToken != KtTokens.EQ) {
return false
}
return this.right?.isReadFromParcel() ?: false
}
private fun KtExpression.isReadFromParcel(): Boolean {
val reference = firstChild as? KtReferenceExpression
?: (firstChild as? KtDotQualifiedExpression)?.getLeftMostReceiverExpression() as? KtReferenceExpression ?: return false
val target = reference.analyze(BodyResolveMode.PARTIAL)[BindingContext.REFERENCE_TARGET, reference] ?: return false
return (target as? ParameterDescriptor)?.type?.fqNameEquals(CLASS_PARCEL) ?: false
}
private fun KtClass.addFieldWrites(function: KtFunction, factory: KtPsiFactory, callSuper: Boolean) {
val bodyExpression = function.bodyExpression
if (bodyExpression !is KtBlockExpression || !bodyExpression.isEmptyWriteToParcel(callSuper)) {
return
}
val propertyParameterDescriptors = primaryConstructor?.valueParameters?.mapNotNull { it.propertyDescriptor } ?: emptyList()
val propertyDescriptors = declarations
.filter { it.isParcelableProperty() }
.mapNotNull { it.descriptor as? PropertyDescriptor }
val parcelName = function.valueParameters[0].name ?: return
val flagsName = function.valueParameters[1].name ?: return
val blockText =
(propertyParameterDescriptors + propertyDescriptors)
.mapNotNull { it.formatWriteToParcel(parcelName, flagsName) }
.joinToString(separator = "\n")
val block = factory.createBlock(
if (callSuper)
WRITE_TO_PARCEL_SUPER_CALL_TEXT + if (blockText.isNotBlank()) "\n$blockText" else ""
else blockText
)
bodyExpression.replace(block)
}
private fun KtClass.addFieldReads(constructor: KtConstructor<*>, factory: KtPsiFactory) {
val bodyExpression = constructor.getBodyExpression()
if (bodyExpression != null && bodyExpression.statements.isNotEmpty()) {
return
}
val parcelName = constructor.getValueParameters().firstOrNull()?.name ?: return
val parcelableProperties = declarations
.filter { it.isParcelableProperty() }
.mapNotNull { it.descriptor as? PropertyDescriptor }
if (parcelableProperties.isEmpty()) {
return
}
val blockText = parcelableProperties
.mapNotNull { descriptor -> descriptor.formatReadFromParcel(parcelName)?.let { "${descriptor.name} = $it" } }
.joinToString(separator = "\n")
val block = factory.createBlock(blockText)
if (constructor is KtPrimaryConstructor) {
val initializer = factory.createAnonymousInitializer()
initializer.body?.replace(block)
addDeclaration(initializer).apply {
addNewLineBeforeDeclaration()
addToShorteningWaitSet()
}
}
else {
bodyExpression?.replace(block) ?: constructor.add(block)
}
}
private fun KtDeclaration.isParcelableProperty(): Boolean =
this is KtProperty && isVar && !hasDelegate() && !isTransient() && getter == null && setter == null
private fun KtProperty.isTransient() = annotationEntries.find { it.isTransientAnnotation() } != null
private fun KtAnnotationEntry.isTransientAnnotation(): Boolean =
typeReference?.analyze(BodyResolveMode.PARTIAL)?.get(BindingContext.TYPE, typeReference)?.fqNameEquals("kotlin.jvm.Transient") ?: false
private fun KtExpression.isCallToSuperWriteToParcel() =
this is KtDotQualifiedExpression
&& receiverExpression is KtSuperExpression
&& (selectorExpression as? KtCallExpression)?.calleeExpression?.text == "writeToParcel"
private fun KtBlockExpression.isEmptyWriteToParcel(callSuper: Boolean): Boolean =
if (callSuper) {
statements.isEmpty() || statements.size == 1 && statements.first().isCallToSuperWriteToParcel()
}
else {
statements.isEmpty()
}
private fun PropertyDescriptor.formatReadFromParcel(parcelName: String): String? {
val type = returnType ?: return null
fun KotlinType.formatJavaClassloader() = "${this.constructor.declarationDescriptor?.fqNameSafe}::class.java.classLoader"
// There is no read/write short array methods
if (KotlinBuiltIns.isPrimitiveArray(type) && KotlinBuiltIns.getPrimitiveArrayElementType(type) != PrimitiveType.SHORT) {
return "$parcelName.create${type.getName()}()"
}
if (type.isMarkedNullable && KotlinBuiltIns.isPrimitiveTypeOrNullablePrimitiveType(type)) {
return "$parcelName.readValue(${type.formatJavaClassloader()}) as? ${type.getName()}"
}
if (KotlinBuiltIns.isPrimitiveType(type)) {
return when {
KotlinBuiltIns.isBoolean(type) -> "$parcelName.readByte() != 0.toByte()"
KotlinBuiltIns.isShort(type) -> "$parcelName.readInt().toShort()"
KotlinBuiltIns.isChar(type) -> "$parcelName.readInt().toChar()"
else -> "$parcelName.read${type.getName()}()"
}
}
return when {
KotlinBuiltIns.isCharSequenceOrNullableCharSequence(type) -> "$parcelName.readString()"
KotlinBuiltIns.isStringOrNullableString(type) -> "$parcelName.readString()"
type.isArrayOfParcelable() -> "$parcelName.createTypedArray(${type.arguments.single().type.getName()}.CREATOR)"
type.isListOfParcelable() -> "$parcelName.createTypedArrayList(${type.arguments.single().type.getName()}.CREATOR)"
type.isArrayOfIBinder() -> "$parcelName.createBinderArray()"
type.isListOfIBinder() -> "$parcelName.createBinderArrayList()"
type.isArrayOfString() -> "$parcelName.createStringArray()"
type.isListOfString() -> "$parcelName.createStringArrayList()"
type.isSparseBooleanArray() -> "$parcelName.readSparseBooleanArray()"
type.isBundle() -> "$parcelName.readBundle(${type.formatJavaClassloader()})"
type.isIBinder() -> "$parcelName.readStrongBinder()"
type.isSubclassOfParcelable(true) -> "$parcelName.readParcelable(${type.formatJavaClassloader()})" // This one should go last
else -> null
}
}
private fun PropertyDescriptor.formatWriteToParcel(parcelName: String, flagsName: String): String? {
val type = returnType ?: return null
// There is no read/write short array methods
if (KotlinBuiltIns.isPrimitiveArray(type) && KotlinBuiltIns.getPrimitiveArrayElementType(type) != PrimitiveType.SHORT) {
return "$parcelName.write${type.getName()}($name)"
}
if (type.isMarkedNullable) {
if (KotlinBuiltIns.isPrimitiveTypeOrNullablePrimitiveType(type)) {
return "$parcelName.writeValue($name)"
}
else if (KotlinBuiltIns.isCharSequenceOrNullableCharSequence(type)) {
return "$parcelName.writeString($name?.toString())"
}
}
if (KotlinBuiltIns.isPrimitiveType(type)) {
return when {
KotlinBuiltIns.isBoolean(type) -> "$parcelName.writeByte(if ($name) 1 else 0)"
KotlinBuiltIns.isShort(type) -> "$parcelName.writeInt($name.toInt())"
KotlinBuiltIns.isChar(type) -> "$parcelName.writeInt($name.toInt())"
else -> "$parcelName.write${type.getName()}($name)"
}
}
return when {
KotlinBuiltIns.isCharSequence(type) -> "$parcelName.writeString($name.toString())"
KotlinBuiltIns.isStringOrNullableString(type) -> "$parcelName.writeString($name)"
type.isArrayOfParcelable() -> "$parcelName.writeTypedArray($name, $flagsName)"
type.isListOfParcelable() -> "$parcelName.writeTypedList($name)"
type.isArrayOfIBinder() -> "$parcelName.writeBinderArray($name)"
type.isListOfIBinder() -> "$parcelName.writeBinderList($name)"
type.isArrayOfString() -> "$parcelName.writeStringArray($name)"
type.isListOfString() -> "$parcelName.writeStringList($name)"
type.isSparseBooleanArray() -> "$parcelName.writeSparseBooleanArray($name)"
type.isBundle() -> "$parcelName.writeBundle($name)"
type.isIBinder() -> "$parcelName.writeStrongBinder($name)"
type.isSubclassOfParcelable(true) -> "$parcelName.writeParcelable($name, $flagsName)" // This one should go last
else -> null
}
}
private fun KtClass.findOrCreateCreator(factory: KtPsiFactory): KtClassOrObject {
findCreator()?.let {
return it
}
val creator = factory.createObject(CREATOR_TEXT.format(name))
return addDeclaration(creator).apply { addToShorteningWaitSet() }
}
private fun KtClass.findOrCreateParcelableSupertype(factory: KtPsiFactory): KtSuperTypeListEntry? {
findParcelableSupertype()?.let {
return it
}
val supertypeEntry = factory.createSuperTypeEntry(CLASS_PARCELABLE)
return addSuperTypeListEntry(supertypeEntry).apply { addToShorteningWaitSet() }
}
private fun KtClass.save() = FileDocumentManager.getInstance().getDocument(containingFile.virtualFile)?.let {
PsiDocumentManager.getInstance(project).commitDocument(it)
}
private fun KtClass.findOrCreateConstructor(factory: KtPsiFactory): KtConstructor<*> {
findConstructorFromParcel()?.let {
return it
}
createPrimaryConstructorIfAbsent()
return createSecondaryConstructor(factory).apply {
addToShorteningWaitSet()
}
}
private fun KtClass.createSecondaryConstructor(factory: KtPsiFactory): KtConstructor<*> {
val constructorText = primaryConstructor?.let { constructor ->
val arguments = constructor.valueParameters.map {
it?.propertyDescriptor?.formatReadFromParcel(PARCEL_NAME) ?: "TODO(\"${it?.name}\")"
}
val argumentList = arguments.joinToString(
prefix = if (arguments.size > 1) "(\n" else "(",
postfix = ")",
separator = if (arguments.size > 1) ",\n" else ", ")
"$CONSTRUCTOR_TEXT :this$argumentList {\n}"
} ?: "$CONSTRUCTOR_TEXT {\n}"
val constructor = factory.createSecondaryConstructor(constructorText)
val lastProperty = declarations.findLast { it is KtProperty }
if (lastProperty != null) {
return addDeclarationAfter(constructor, lastProperty).apply { addNewLineBeforeDeclaration() }
}
else {
val firstFunction = declarations.find { it is KtFunction }
return addDeclarationBefore(constructor, firstFunction).apply { addNewLineBeforeDeclaration() }
}
}
private fun KtTypeReference.extendsParcelable(): Boolean =
analyze(BodyResolveMode.PARTIAL)[BindingContext.TYPE, this]?.isSubclassOfParcelable(true) ?: false
private fun KtClass.findWriteToParcel() = declarations.find { it.isWriteToParcel() }
private fun KtDeclaration.isWriteToParcel(): Boolean = this is KtFunction && name == "writeToParcel" && valueParameters.let {
it.size == 2 && it[0].isParcelParameter() && (it[1].typeReference?.fqNameEquals("kotlin.Int") ?: false)
}
private fun KtClass.findOrCreateWriteToParcel(factory: KtPsiFactory, callSuper: Boolean): KtFunction {
findWriteToParcel()?.let {
return it as KtFunction
}
val writeToParcel = factory.createFunction(if (callSuper) WRITE_TO_PARCEL_WITH_SUPER_TEXT else WRITE_TO_PARCEL_TEXT)
return addDeclaration(writeToParcel).apply {
addNewLineBeforeDeclaration()
addToShorteningWaitSet()
}
}
private fun KtClass.findDescribeContents() = declarations.find { it.isDescribeContents() }
private fun KtDeclaration.isDescribeContents(): Boolean = this is KtFunction &&
name == "describeContents" &&
valueParameters.isEmpty()
private fun KtClass.findOrCreateDescribeContents(factory: KtPsiFactory): KtFunction {
findDescribeContents()?.let {
return it as KtFunction
}
val describeContents = factory.createFunction(DESCRIBE_CONTENTS_TEXT)
return addDeclaration(describeContents).apply {
addNewLineBeforeDeclaration()
addToShorteningWaitSet()
}
}
private fun KtClass.findConstructorFromParcel(): KtConstructor<*>? =
primaryConstructor?.takeIf { it.isConstructorFromParcel() } ?: secondaryConstructors.find { it.isConstructorFromParcel() }
private fun KtConstructor<*>.isConstructorFromParcel(): Boolean = getValueParameters().let {
it.size == 1 && it.single().isParcelParameter()
}
private fun KtParameter.isParcelParameter(): Boolean = typeReference?.fqNameEquals(CLASS_PARCEL) ?: false
private fun KtTypeReference.isParcelableReference() = fqNameEquals(CLASS_PARCELABLE)
private fun KtTypeReference.fqNameEquals(fqName: String) =
analyze(BodyResolveMode.PARTIAL)[BindingContext.TYPE, this]?.fqNameEquals(fqName) ?: false
private fun KotlinType.getName() = constructor.declarationDescriptor?.name
private fun KotlinType.fqNameEquals(fqName: String) = constructor.declarationDescriptor?.fqNameSafe?.asString() == fqName
private fun KotlinType.isSubclassOfParcelable(strict: Boolean = false): Boolean = isSubclassOf(FqName(CLASS_PARCELABLE), strict)
private fun KotlinType.isIBinder(): Boolean = fqNameEquals("android.os.IBinder")
private fun KotlinType.isArrayOfParcelable(): Boolean =
KotlinBuiltIns.isArray(this) && arguments.singleOrNull()?.type?.isSubclassOfParcelable(true) ?: false
private fun KotlinType.isArrayOfIBinder(): Boolean =
KotlinBuiltIns.isArray(this) && arguments.singleOrNull()?.type?.isIBinder() ?: false
private fun KotlinType.isArrayOfString(): Boolean =
KotlinBuiltIns.isArray(this) && KotlinBuiltIns.isStringOrNullableString(arguments.singleOrNull()?.type)
private fun KotlinType.isListOfString(): Boolean =
KotlinBuiltIns.isListOrNullableList(this) && KotlinBuiltIns.isStringOrNullableString(arguments.singleOrNull()?.type)
private fun KotlinType.isListOfParcelable(): Boolean =
KotlinBuiltIns.isListOrNullableList(this) && arguments.singleOrNull()?.type?.isSubclassOfParcelable(true) ?: false
private fun KotlinType.isListOfIBinder(): Boolean =
KotlinBuiltIns.isListOrNullableList(this) && arguments.singleOrNull()?.type?.isIBinder() ?: false
private fun KotlinType.isSparseBooleanArray(): Boolean = fqNameEquals("android.util.SparseBooleanArray")
private fun KotlinType.isBundle(): Boolean = fqNameEquals("android.os.Bundle")
private fun <T: KtDeclaration> T.addNewLineBeforeDeclaration() = parent.addBefore(KtPsiFactory(this).createNewLine(), this)
@@ -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.android
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.types.KotlinType
/*
* 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.
*/
internal fun KotlinType.fqNameSafe() = constructor.declarationDescriptor?.fqNameSafe
internal fun KotlinType.isSubclassOf(className: FqName, strict: Boolean = false): Boolean =
(!strict && fqNameSafe() == className) || constructor.supertypes.any {
className == it.fqNameSafe() || it.isSubclassOf(className, true)
}
@@ -0,0 +1,43 @@
/*
* 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.intention
import com.intellij.codeInsight.intention.HighPriorityAction
import com.intellij.openapi.editor.Editor
import org.jetbrains.android.facet.AndroidFacet
import org.jetbrains.android.util.AndroidBundle
import org.jetbrains.kotlin.android.canAddParcelable
import org.jetbrains.kotlin.android.implementParcelable
import org.jetbrains.kotlin.android.insideBody
import org.jetbrains.kotlin.idea.intentions.SelfTargetingIntention
import org.jetbrains.kotlin.psi.KtClass
class ImplementParcelableAction :
SelfTargetingIntention<KtClass>(KtClass::class.java, AndroidBundle.message("implement.parcelable.intention.text")),
HighPriorityAction {
override fun isApplicableTo(element: KtClass, caretOffset: Int): Boolean =
AndroidFacet.getInstance(element) != null &&
!element.insideBody(caretOffset) &&
element.canAddParcelable()
override fun applyTo(element: KtClass, editor: Editor?) {
element.implementParcelable()
}
override fun startInWriteAction(): Boolean = true
}
@@ -0,0 +1,43 @@
/*
* 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.intention
import com.intellij.codeInsight.intention.HighPriorityAction
import com.intellij.openapi.editor.Editor
import org.jetbrains.android.facet.AndroidFacet
import org.jetbrains.android.util.AndroidBundle
import org.jetbrains.kotlin.android.canRedoParcelable
import org.jetbrains.kotlin.android.insideBody
import org.jetbrains.kotlin.android.reimplementParcelable
import org.jetbrains.kotlin.idea.intentions.SelfTargetingIntention
import org.jetbrains.kotlin.psi.KtClass
class RedoParcelableAction :
SelfTargetingIntention<KtClass>(KtClass::class.java, AndroidBundle.message("redo.parcelable.intention.text")),
HighPriorityAction {
override fun isApplicableTo(element: KtClass, caretOffset: Int): Boolean =
AndroidFacet.getInstance(element) != null &&
!element.insideBody(caretOffset) &&
element.canRedoParcelable()
override fun applyTo(element: KtClass, editor: Editor?) {
element.reimplementParcelable()
}
override fun startInWriteAction(): Boolean = true
}
@@ -0,0 +1,43 @@
/*
* 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.intention
import com.intellij.codeInsight.intention.HighPriorityAction
import com.intellij.openapi.editor.Editor
import org.jetbrains.android.facet.AndroidFacet
import org.jetbrains.android.util.AndroidBundle
import org.jetbrains.kotlin.android.canRemoveParcelable
import org.jetbrains.kotlin.android.insideBody
import org.jetbrains.kotlin.android.removeParcelableImplementation
import org.jetbrains.kotlin.idea.intentions.SelfTargetingIntention
import org.jetbrains.kotlin.psi.KtClass
class RemoveParcelableAction :
SelfTargetingIntention<KtClass>(KtClass::class.java, AndroidBundle.message("remove.parcelable.intention.text")),
HighPriorityAction {
override fun isApplicableTo(element: KtClass, caretOffset: Int): Boolean =
AndroidFacet.getInstance(element) != null &&
!element.insideBody(caretOffset) &&
element.canRemoveParcelable()
override fun applyTo(element: KtClass, editor: Editor?) {
element.removeParcelableImplementation()
}
override fun startInWriteAction(): Boolean = true
}
@@ -0,0 +1,73 @@
/*
* 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.intention
import com.android.SdkConstants
import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.openapi.util.io.FileUtil
import com.intellij.util.PathUtil
import org.jetbrains.kotlin.android.KotlinAndroidTestCase
import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
import org.jetbrains.kotlin.test.InTextDirectivesUtils
import org.jetbrains.kotlin.test.KotlinTestUtils
import java.io.File
abstract class AbstractAndroidIntentionTest : KotlinAndroidTestCase() {
fun doTest(path: String) {
val testFile = File(path)
val testFileText = FileUtil.loadFile(testFile)
val intentionClassName = InTextDirectivesUtils.findStringWithPrefixes(testFileText, "// INTENTION_CLASS: ")
?: error("Intention class not found!")
val notAvailable = InTextDirectivesUtils.isDirectiveDefined(testFileText, "// NOT_AVAILABLE")
val withRuntime = InTextDirectivesUtils.isDirectiveDefined(testFileText, "// WITH_RUNTIME")
try {
if (withRuntime) {
ConfigLibraryUtil.configureKotlinRuntime(myFixture.module)
}
val sourceFile = myFixture.copyFileToProject(path, "src/${PathUtil.getFileName(path)}")
myFixture.configureFromExistingVirtualFile(sourceFile)
val intention = Class.forName(intentionClassName).newInstance() as? IntentionAction ?: error("Failed to create intention!")
if (!intention.isAvailable(myFixture.project, myFixture.editor, myFixture.file)) {
if (notAvailable) {
return
}
error("Intention is not available!")
}
myFixture.launchAction(intention)
myFixture.checkResultByFile("$path.expected")
}
finally {
if (withRuntime) {
ConfigLibraryUtil.unConfigureKotlinRuntime(myFixture.module)
}
}
}
override fun createManifest() {
myFixture.copyFileToProject("idea/testData/android/AndroidManifest.xml", SdkConstants.FN_ANDROID_MANIFEST_XML)
}
override fun getTestDataPath() = KotlinTestUtils.getHomeDirectory()
}
@@ -0,0 +1,197 @@
/*
* 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.intention;
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("idea/testData/android/intention")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public class AndroidIntentionTestGenerated extends AbstractAndroidIntentionTest {
public void testAllFilesPresentInIntention() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/android/intention"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("idea/testData/android/intention/implementParcelable")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class ImplementParcelable extends AbstractAndroidIntentionTest {
public void testAllFilesPresentInImplementParcelable() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/android/intention/implementParcelable"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("allNullableTypes.kt")
public void testAllNullableTypes() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/intention/implementParcelable/allNullableTypes.kt");
doTest(fileName);
}
@TestMetadata("allTypes.kt")
public void testAllTypes() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/intention/implementParcelable/allTypes.kt");
doTest(fileName);
}
@TestMetadata("alreadyImplemented.kt")
public void testAlreadyImplemented() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/intention/implementParcelable/alreadyImplemented.kt");
doTest(fileName);
}
@TestMetadata("constructorProperties.kt")
public void testConstructorProperties() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/intention/implementParcelable/constructorProperties.kt");
doTest(fileName);
}
@TestMetadata("constructorPropertiesWithParameters.kt")
public void testConstructorPropertiesWithParameters() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/intention/implementParcelable/constructorPropertiesWithParameters.kt");
doTest(fileName);
}
@TestMetadata("missingConstructor.kt")
public void testMissingConstructor() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/intention/implementParcelable/missingConstructor.kt");
doTest(fileName);
}
@TestMetadata("missingDescribeContents.kt")
public void testMissingDescribeContents() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/intention/implementParcelable/missingDescribeContents.kt");
doTest(fileName);
}
@TestMetadata("missingWriteToParcel.kt")
public void testMissingWriteToParcel() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/intention/implementParcelable/missingWriteToParcel.kt");
doTest(fileName);
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/intention/implementParcelable/simple.kt");
doTest(fileName);
}
@TestMetadata("withTransient.kt")
public void testWithTransient() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/intention/implementParcelable/withTransient.kt");
doTest(fileName);
}
}
@TestMetadata("idea/testData/android/intention/redoParcelable")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class RedoParcelable extends AbstractAndroidIntentionTest {
public void testAllFilesPresentInRedoParcelable() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/android/intention/redoParcelable"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("indirectParcelable.kt")
public void testIndirectParcelable() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/intention/redoParcelable/indirectParcelable.kt");
doTest(fileName);
}
@TestMetadata("init.kt")
public void testInit() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/intention/redoParcelable/init.kt");
doTest(fileName);
}
@TestMetadata("initWithExtraStatements.kt")
public void testInitWithExtraStatements() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/intention/redoParcelable/initWithExtraStatements.kt");
doTest(fileName);
}
@TestMetadata("noParcelable.kt")
public void testNoParcelable() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/intention/redoParcelable/noParcelable.kt");
doTest(fileName);
}
@TestMetadata("oldField.kt")
public void testOldField() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/intention/redoParcelable/oldField.kt");
doTest(fileName);
}
@TestMetadata("oldFieldSecondary.kt")
public void testOldFieldSecondary() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/intention/redoParcelable/oldFieldSecondary.kt");
doTest(fileName);
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/intention/redoParcelable/simple.kt");
doTest(fileName);
}
}
@TestMetadata("idea/testData/android/intention/removeParcelable")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class RemoveParcelable extends AbstractAndroidIntentionTest {
public void testAllFilesPresentInRemoveParcelable() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/android/intention/removeParcelable"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("inderectParcelable.kt")
public void testInderectParcelable() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/intention/removeParcelable/inderectParcelable.kt");
doTest(fileName);
}
@TestMetadata("init.kt")
public void testInit() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/intention/removeParcelable/init.kt");
doTest(fileName);
}
@TestMetadata("initWithExtraStatements.kt")
public void testInitWithExtraStatements() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/intention/removeParcelable/initWithExtraStatements.kt");
doTest(fileName);
}
@TestMetadata("noParcelable.kt")
public void testNoParcelable() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/intention/removeParcelable/noParcelable.kt");
doTest(fileName);
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/intention/removeParcelable/simple.kt");
doTest(fileName);
}
}
}
@@ -58,7 +58,7 @@ abstract class AbstractAndroidLintQuickfixTest : KotlinAndroidTestCase() {
myFixture.checkResultByFile(path + ".expected")
}
else {
assertNull("Intention should not be availabale", myFixture.availableIntentions.find { it.text == intentionText })
assertNull("Intention should not be available", myFixture.availableIntentions.find { it.text == intentionText })
}
}
@@ -36,6 +36,27 @@ public class AndroidLintQuickfixTestGenerated extends AbstractAndroidLintQuickfi
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/android/lintQuickfix"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("idea/testData/android/lintQuickfix/parcelable")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Parcelable extends AbstractAndroidLintQuickfixTest {
public void testAllFilesPresentInParcelable() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/android/lintQuickfix/parcelable"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("missingCreator.kt")
public void testMissingCreator() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/lintQuickfix/parcelable/missingCreator.kt");
doTest(fileName);
}
@TestMetadata("noImplementation.kt")
public void testNoImplementation() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/lintQuickfix/parcelable/noImplementation.kt");
doTest(fileName);
}
}
@TestMetadata("idea/testData/android/lintQuickfix/requiresApi")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -0,0 +1,27 @@
class SomeData(val number: Int, val text: String, val flag: Boolean) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readInt(),
parcel.readString(),
parcel.readByte() != 0.toByte()) {
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeInt(number)
parcel.writeString(text)
parcel.writeByte(if (flag) 1 else 0)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<SomeData> {
override fun createFromParcel(parcel: Parcel): SomeData {
return SomeData(parcel)
}
override fun newArray(size: Int): Array<SomeData?> {
return arrayOfNulls(size)
}
}
}
@@ -0,0 +1 @@
class SomeData(val number: Int, val text: String, val flag: Boolean)
@@ -0,0 +1,4 @@
<html>
<body>
This intention implements the methods and the CREATOR object needed for Parcelable.</body>
</html>
@@ -0,0 +1,27 @@
class SomeData(val number: Int, val text: String, val flag: Boolean) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readInt(),
parcel.readString(),
parcel.readByte() != 0.toByte()) {
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeInt(number)
parcel.writeString(text)
parcel.writeByte(if (flag) 1 else 0)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<SomeData> {
override fun createFromParcel(parcel: Parcel): SomeData {
return SomeData(parcel)
}
override fun newArray(size: Int): Array<SomeData?> {
return arrayOfNulls(size)
}
}
}
@@ -0,0 +1,23 @@
class SomeData(val number: Int, val text: String, val flag: Boolean) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString()) {
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeInt(oldField)
}
override fun describeContents(): Int {
return 42
}
companion object CREATOR : Parcelable.Creator<SomeData> {
override fun createFromParcel(parcel: Parcel): SomeData {
return SomeData(parcel)
}
override fun newArray(size: Int): Array<SomeData?> {
return arrayOfNulls(size)
}
}
}
@@ -0,0 +1,5 @@
<html>
<body>
This intention regenerates the methods and the CREATOR object which implements Parcelable. <b>Warning:</b> Your custom code will be removed.
</body>
</html>
@@ -0,0 +1,3 @@
class SomeData(val number: Int, val text: String, val flag: Boolean) {
}
@@ -0,0 +1,27 @@
class SomeData(val number: Int, val text: String, val flag: Boolean) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readInt(),
parcel.readString(),
parcel.readByte() != 0.toByte()) {
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeInt(number)
parcel.writeString(text)
parcel.writeByte(if (flag) 1 else 0)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<SomeData> {
override fun createFromParcel(parcel: Parcel): SomeData {
return SomeData(parcel)
}
override fun newArray(size: Int): Array<SomeData?> {
return arrayOfNulls(size)
}
}
}
@@ -0,0 +1,5 @@
<html>
<body>
This intention removes the methods and the CREATOR object which implements Parcelable. <b>Warning:</b> Your custom code will be removed.
</body>
</html>
+14
View File
@@ -23,6 +23,20 @@
<category>Kotlin Android</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.kotlin.android.intention.ImplementParcelableAction</className>
<category>Kotlin Android</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.kotlin.android.intention.RemoveParcelableAction</className>
<category>Kotlin Android</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.kotlin.android.intention.RedoParcelableAction</className>
<category>Kotlin Android</category>
</intentionAction>
<codeInsight.unresolvedReferenceQuickFixProvider
implementation="org.jetbrains.kotlin.android.inspection.KotlinAndroidResourceQuickFixProvider"/>
@@ -0,0 +1,86 @@
// INTENTION_CLASS: org.jetbrains.kotlin.android.intention.ImplementParcelableAction
import android.os.Bundle
import android.os.IBinder
import android.os.Parcel
import android.os.Parcelable
import android.util.SparseBooleanArray
import android.util.SparseIntArray
open class BaseParcelable(parcel: Parcel) : Parcelable {
override fun writeToParcel(parcel: Parcel, flags: Int) {
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<BaseParcelable> {
override fun createFromParcel(parcel: Parcel): BaseParcelable {
return BaseParcelable(parcel)
}
override fun newArray(size: Int): Array<BaseParcelable?> {
return arrayOfNulls(size)
}
}
}
class <caret>MyData {
val delegated by lazy { 0 }
val readonlyField = true
var listOfStrings: List<String?>? = null
var listOfIBinder: List<IBinder?>? = null
var arrayfield1: IntArray? = null
var arrayfield2: Array<String>? = null
var arrayfield3: LongArray? = null
var arrayfield4: ByteArray? = null
var arrayfield5: CharArray? = null
var arrayfield6: ShortArray? = null // No method for Short
var arrayfield7: FloatArray? = null
var arrayfield8: DoubleArray? = null
var arrayfield9: BooleanArray? = null
var arrayfield10: Array<CharSequence>? = null // No method for CharSequence
var arrayfield11: Array<IBinder>? = null
var field1: Int? = 0
var field2: String? = ""
var field3: Long? = 0
var field4: Byte? = 0
var field5: Char? = '\u0000'
var field6: Short? = 0
var field7: Float? = 0.0f
var field8: Double? = 0.0
var field9: Boolean? = false
var field10: CharSequence? = ""
var field11: SparseBooleanArray? = null
var field12: SparseIntArray? = null // read/write methods will be available starting from android O
var field13: Bundle? = null
var field14: IBinder? = null
var goodArray: Array<BaseParcelable?>? = emptyArray()
var badArray: Array<Parcelable?>? = emptyArray()
var goodList: List<BaseParcelable?>? = emptyList()
var badList: List<Parcelable?>? = emptyList()
var parcelableProperty: BaseParcelable?
val uninitializedVal: Int?
val fieldWIthGetter: Int?
get() {
return 0
}
var fieldWithCustomGetterAndSetter: Int? = 0
get() {
return field
}
set(value: Int?) {
field = value
}
}
@@ -0,0 +1,160 @@
// INTENTION_CLASS: org.jetbrains.kotlin.android.intention.ImplementParcelableAction
import android.os.Bundle
import android.os.IBinder
import android.os.Parcel
import android.os.Parcelable
import android.util.SparseBooleanArray
import android.util.SparseIntArray
open class BaseParcelable(parcel: Parcel) : Parcelable {
override fun writeToParcel(parcel: Parcel, flags: Int) {
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<BaseParcelable> {
override fun createFromParcel(parcel: Parcel): BaseParcelable {
return BaseParcelable(parcel)
}
override fun newArray(size: Int): Array<BaseParcelable?> {
return arrayOfNulls(size)
}
}
}
class MyData() : Parcelable {
val delegated by lazy { 0 }
val readonlyField = true
var listOfStrings: List<String?>? = null
var listOfIBinder: List<IBinder?>? = null
var arrayfield1: IntArray? = null
var arrayfield2: Array<String>? = null
var arrayfield3: LongArray? = null
var arrayfield4: ByteArray? = null
var arrayfield5: CharArray? = null
var arrayfield6: ShortArray? = null // No method for Short
var arrayfield7: FloatArray? = null
var arrayfield8: DoubleArray? = null
var arrayfield9: BooleanArray? = null
var arrayfield10: Array<CharSequence>? = null // No method for CharSequence
var arrayfield11: Array<IBinder>? = null
var field1: Int? = 0
var field2: String? = ""
var field3: Long? = 0
var field4: Byte? = 0
var field5: Char? = '\u0000'
var field6: Short? = 0
var field7: Float? = 0.0f
var field8: Double? = 0.0
var field9: Boolean? = false
var field10: CharSequence? = ""
var field11: SparseBooleanArray? = null
var field12: SparseIntArray? = null // read/write methods will be available starting from android O
var field13: Bundle? = null
var field14: IBinder? = null
var goodArray: Array<BaseParcelable?>? = emptyArray()
var badArray: Array<Parcelable?>? = emptyArray()
var goodList: List<BaseParcelable?>? = emptyList()
var badList: List<Parcelable?>? = emptyList()
var parcelableProperty: BaseParcelable?
val uninitializedVal: Int?
val fieldWIthGetter: Int?
get() {
return 0
}
var fieldWithCustomGetterAndSetter: Int? = 0
get() {
return field
}
set(value: Int?) {
field = value
}
constructor(parcel: Parcel) : this() {
listOfStrings = parcel.createStringArrayList()
listOfIBinder = parcel.createBinderArrayList()
arrayfield1 = parcel.createIntArray()
arrayfield2 = parcel.createStringArray()
arrayfield3 = parcel.createLongArray()
arrayfield4 = parcel.createByteArray()
arrayfield5 = parcel.createCharArray()
arrayfield7 = parcel.createFloatArray()
arrayfield8 = parcel.createDoubleArray()
arrayfield9 = parcel.createBooleanArray()
arrayfield11 = parcel.createBinderArray()
field1 = parcel.readValue(Int::class.java.classLoader) as? Int
field2 = parcel.readString()
field3 = parcel.readValue(Long::class.java.classLoader) as? Long
field4 = parcel.readValue(Byte::class.java.classLoader) as? Byte
field5 = parcel.readValue(Char::class.java.classLoader) as? Char
field6 = parcel.readValue(Short::class.java.classLoader) as? Short
field7 = parcel.readValue(Float::class.java.classLoader) as? Float
field8 = parcel.readValue(Double::class.java.classLoader) as? Double
field9 = parcel.readValue(Boolean::class.java.classLoader) as? Boolean
field10 = parcel.readString()
field11 = parcel.readSparseBooleanArray()
field13 = parcel.readBundle(Bundle::class.java.classLoader)
field14 = parcel.readStrongBinder()
goodArray = parcel.createTypedArray(BaseParcelable)
goodList = parcel.createTypedArrayList(BaseParcelable)
parcelableProperty = parcel.readParcelable(BaseParcelable::class.java.classLoader)
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeStringList(listOfStrings)
parcel.writeBinderList(listOfIBinder)
parcel.writeIntArray(arrayfield1)
parcel.writeStringArray(arrayfield2)
parcel.writeLongArray(arrayfield3)
parcel.writeByteArray(arrayfield4)
parcel.writeCharArray(arrayfield5)
parcel.writeFloatArray(arrayfield7)
parcel.writeDoubleArray(arrayfield8)
parcel.writeBooleanArray(arrayfield9)
parcel.writeBinderArray(arrayfield11)
parcel.writeValue(field1)
parcel.writeString(field2)
parcel.writeValue(field3)
parcel.writeValue(field4)
parcel.writeValue(field5)
parcel.writeValue(field6)
parcel.writeValue(field7)
parcel.writeValue(field8)
parcel.writeValue(field9)
parcel.writeString(field10?.toString())
parcel.writeSparseBooleanArray(field11)
parcel.writeBundle(field13)
parcel.writeStrongBinder(field14)
parcel.writeTypedArray(goodArray, flags)
parcel.writeTypedList(goodList)
parcel.writeParcelable(parcelableProperty, flags)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<MyData> {
override fun createFromParcel(parcel: Parcel): MyData {
return MyData(parcel)
}
override fun newArray(size: Int): Array<MyData?> {
return arrayOfNulls(size)
}
}
}
@@ -0,0 +1,74 @@
// INTENTION_CLASS: org.jetbrains.kotlin.android.intention.ImplementParcelableAction
import android.os.Parcel
import android.os.Parcelable
open class BaseParcelable(parcel: Parcel) : Parcelable {
override fun writeToParcel(parcel: Parcel, flags: Int) {
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<BaseParcelable> {
override fun createFromParcel(parcel: Parcel): BaseParcelable {
return BaseParcelable(parcel)
}
override fun newArray(size: Int): Array<BaseParcelable?> {
return arrayOfNulls(size)
}
}
}
class <caret>MyData {
val delegated by lazy { 0 }
val readonlyField = true
var field1: Int = 0
var field2: String = ""
var field3: Long = 0
var field4: Byte = 0
var field5: Char = '\u0000'
var field6: Short = 0
var field7: Float = 0.0f
var field8: Double = 0.0
var field9: Boolean = false
var field10: CharSequence = ""
var arrayfield1: IntArray
var arrayfield2: Array<String>
var arrayfield3: LongArray
var arrayfield4: ByteArray
var arrayfield5: CharArray
var arrayfield6: ShortArray // No method for Short
var arrayfield7: FloatArray
var arrayfield8: DoubleArray
var arrayfield9: BooleanArray
var arrayfield10: Array<CharSequence> // No method for CharSequence
var goodArray: Array<BaseParcelable> = emptyArray()
var badArray: Array<Parcelable> = emptyArray()
var goodList: List<BaseParcelable> = emptyList()
var badList: List<Parcelable> = emptyList()
var parcelableProperty: BaseParcelable
val uninitializedVal: Int
val fieldWIthGetter: Int
get() {
return 0
}
var fieldWithCustomGetterAndSetter: Int = 0
get() {
return field
}
set(value: Int) {
field = value
}
}
@@ -0,0 +1,136 @@
// INTENTION_CLASS: org.jetbrains.kotlin.android.intention.ImplementParcelableAction
import android.os.Parcel
import android.os.Parcelable
open class BaseParcelable(parcel: Parcel) : Parcelable {
override fun writeToParcel(parcel: Parcel, flags: Int) {
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<BaseParcelable> {
override fun createFromParcel(parcel: Parcel): BaseParcelable {
return BaseParcelable(parcel)
}
override fun newArray(size: Int): Array<BaseParcelable?> {
return arrayOfNulls(size)
}
}
}
class MyData() : Parcelable {
val delegated by lazy { 0 }
val readonlyField = true
var field1: Int = 0
var field2: String = ""
var field3: Long = 0
var field4: Byte = 0
var field5: Char = '\u0000'
var field6: Short = 0
var field7: Float = 0.0f
var field8: Double = 0.0
var field9: Boolean = false
var field10: CharSequence = ""
var arrayfield1: IntArray
var arrayfield2: Array<String>
var arrayfield3: LongArray
var arrayfield4: ByteArray
var arrayfield5: CharArray
var arrayfield6: ShortArray // No method for Short
var arrayfield7: FloatArray
var arrayfield8: DoubleArray
var arrayfield9: BooleanArray
var arrayfield10: Array<CharSequence> // No method for CharSequence
var goodArray: Array<BaseParcelable> = emptyArray()
var badArray: Array<Parcelable> = emptyArray()
var goodList: List<BaseParcelable> = emptyList()
var badList: List<Parcelable> = emptyList()
var parcelableProperty: BaseParcelable
val uninitializedVal: Int
val fieldWIthGetter: Int
get() {
return 0
}
var fieldWithCustomGetterAndSetter: Int = 0
get() {
return field
}
set(value: Int) {
field = value
}
constructor(parcel: Parcel) : this() {
field1 = parcel.readInt()
field2 = parcel.readString()
field3 = parcel.readLong()
field4 = parcel.readByte()
field5 = parcel.readInt().toChar()
field6 = parcel.readInt().toShort()
field7 = parcel.readFloat()
field8 = parcel.readDouble()
field9 = parcel.readByte() != 0.toByte()
field10 = parcel.readString()
arrayfield1 = parcel.createIntArray()
arrayfield2 = parcel.createStringArray()
arrayfield3 = parcel.createLongArray()
arrayfield4 = parcel.createByteArray()
arrayfield5 = parcel.createCharArray()
arrayfield7 = parcel.createFloatArray()
arrayfield8 = parcel.createDoubleArray()
arrayfield9 = parcel.createBooleanArray()
goodArray = parcel.createTypedArray(BaseParcelable)
goodList = parcel.createTypedArrayList(BaseParcelable)
parcelableProperty = parcel.readParcelable(BaseParcelable::class.java.classLoader)
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeInt(field1)
parcel.writeString(field2)
parcel.writeLong(field3)
parcel.writeByte(field4)
parcel.writeInt(field5.toInt())
parcel.writeInt(field6.toInt())
parcel.writeFloat(field7)
parcel.writeDouble(field8)
parcel.writeByte(if (field9) 1 else 0)
parcel.writeString(field10.toString())
parcel.writeIntArray(arrayfield1)
parcel.writeStringArray(arrayfield2)
parcel.writeLongArray(arrayfield3)
parcel.writeByteArray(arrayfield4)
parcel.writeCharArray(arrayfield5)
parcel.writeFloatArray(arrayfield7)
parcel.writeDoubleArray(arrayfield8)
parcel.writeBooleanArray(arrayfield9)
parcel.writeTypedArray(goodArray, flags)
parcel.writeTypedList(goodList)
parcel.writeParcelable(parcelableProperty, flags)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<MyData> {
override fun createFromParcel(parcel: Parcel): MyData {
return MyData(parcel)
}
override fun newArray(size: Int): Array<MyData?> {
return arrayOfNulls(size)
}
}
}
@@ -0,0 +1,25 @@
// INTENTION_CLASS: org.jetbrains.kotlin.android.intention.ImplementParcelableAction
// NOT_AVAILABLE
import android.os.Parcel
import android.os.Parcelable
class <caret>Simple(parcel: Parcel) : Parcelable {
override fun writeToParcel(parcel: Parcel, flags: Int) {
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<Simple> {
override fun createFromParcel(parcel: Parcel): Simple {
return Simple(parcel)
}
override fun newArray(size: Int): Array<Simple?> {
return arrayOfNulls(size)
}
}
}
@@ -0,0 +1,5 @@
// INTENTION_CLASS: org.jetbrains.kotlin.android.intention.ImplementParcelableAction
class <caret>MyData(val number: Int, val text: String, val flag: Boolean) {
var count = 0
}
@@ -0,0 +1,36 @@
import android.os.Parcel
import android.os.Parcelable
// INTENTION_CLASS: org.jetbrains.kotlin.android.intention.ImplementParcelableAction
class MyData(val number: Int, val text: String, val flag: Boolean) : Parcelable {
var count = 0
constructor(parcel: Parcel) : this(
parcel.readInt(),
parcel.readString(),
parcel.readByte() != 0.toByte()) {
count = parcel.readInt()
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeInt(number)
parcel.writeString(text)
parcel.writeByte(if (flag) 1 else 0)
parcel.writeInt(count)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<MyData> {
override fun createFromParcel(parcel: Parcel): MyData {
return MyData(parcel)
}
override fun newArray(size: Int): Array<MyData?> {
return arrayOfNulls(size)
}
}
}
@@ -0,0 +1,3 @@
// INTENTION_CLASS: org.jetbrains.kotlin.android.intention.ImplementParcelableAction
class <caret>MyData(val number: Int, val text: String, flag: Boolean)
@@ -0,0 +1,31 @@
import android.os.Parcel
import android.os.Parcelable
// INTENTION_CLASS: org.jetbrains.kotlin.android.intention.ImplementParcelableAction
class MyData(val number: Int, val text: String, flag: Boolean) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readInt(),
parcel.readString(),
TODO("flag")) {
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeInt(number)
parcel.writeString(text)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<MyData> {
override fun createFromParcel(parcel: Parcel): MyData {
return MyData(parcel)
}
override fun newArray(size: Int): Array<MyData?> {
return arrayOfNulls(size)
}
}
}
@@ -0,0 +1,23 @@
// INTENTION_CLASS: org.jetbrains.kotlin.android.intention.ImplementParcelableAction
import android.os.Parcel
import android.os.Parcelable
class <caret>Simple : Parcelable {
override fun writeToParcel(parcel: Parcel, flags: Int) {
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<Simple> {
override fun createFromParcel(parcel: Parcel): Simple {
return Simple(parcel)
}
override fun newArray(size: Int): Array<Simple?> {
return arrayOfNulls(size)
}
}
}
@@ -0,0 +1,26 @@
// INTENTION_CLASS: org.jetbrains.kotlin.android.intention.ImplementParcelableAction
import android.os.Parcel
import android.os.Parcelable
class Simple() : Parcelable {
constructor(parcel: Parcel) : this() {
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<Simple> {
override fun createFromParcel(parcel: Parcel): Simple {
return Simple(parcel)
}
override fun newArray(size: Int): Array<Simple?> {
return arrayOfNulls(size)
}
}
}
@@ -0,0 +1,20 @@
// INTENTION_CLASS: org.jetbrains.kotlin.android.intention.ImplementParcelableAction
import android.os.Parcel
import android.os.Parcelable
class <caret>Simple(parcel: Parcel) : Parcelable {
override fun writeToParcel(parcel: Parcel, flags: Int) {
}
companion object CREATOR : Parcelable.Creator<Simple> {
override fun createFromParcel(parcel: Parcel): Simple {
return Simple(parcel)
}
override fun newArray(size: Int): Array<Simple?> {
return arrayOfNulls(size)
}
}
}
@@ -0,0 +1,24 @@
// INTENTION_CLASS: org.jetbrains.kotlin.android.intention.ImplementParcelableAction
import android.os.Parcel
import android.os.Parcelable
class Simple(parcel: Parcel) : Parcelable {
override fun writeToParcel(parcel: Parcel, flags: Int) {
}
companion object CREATOR : Parcelable.Creator<Simple> {
override fun createFromParcel(parcel: Parcel): Simple {
return Simple(parcel)
}
override fun newArray(size: Int): Array<Simple?> {
return arrayOfNulls(size)
}
}
override fun describeContents(): Int {
return 0
}
}
@@ -0,0 +1,19 @@
// INTENTION_CLASS: org.jetbrains.kotlin.android.intention.ImplementParcelableAction
import android.os.Parcel
import android.os.Parcelable
class <caret>Simple(parcel: Parcel) : Parcelable {
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<Simple> {
override fun createFromParcel(parcel: Parcel): Simple {
return Simple(parcel)
}
override fun newArray(size: Int): Array<Simple?> {
return arrayOfNulls(size)
}
}
}
@@ -0,0 +1,23 @@
// INTENTION_CLASS: org.jetbrains.kotlin.android.intention.ImplementParcelableAction
import android.os.Parcel
import android.os.Parcelable
class Simple(parcel: Parcel) : Parcelable {
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<Simple> {
override fun createFromParcel(parcel: Parcel): Simple {
return Simple(parcel)
}
override fun newArray(size: Int): Array<Simple?> {
return arrayOfNulls(size)
}
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
}
}
@@ -0,0 +1,3 @@
// INTENTION_CLASS: org.jetbrains.kotlin.android.intention.ImplementParcelableAction
class <caret>Simple
@@ -0,0 +1,27 @@
import android.os.Parcel
import android.os.Parcelable
// INTENTION_CLASS: org.jetbrains.kotlin.android.intention.ImplementParcelableAction
class Simple() : Parcelable {
constructor(parcel: Parcel) : this() {
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<Simple> {
override fun createFromParcel(parcel: Parcel): Simple {
return Simple(parcel)
}
override fun newArray(size: Int): Array<Simple?> {
return arrayOfNulls(size)
}
}
}
@@ -0,0 +1,7 @@
// INTENTION_CLASS: org.jetbrains.kotlin.android.intention.ImplementParcelableAction
// WITH_RUNTIME
class <caret>WithTransient() {
@Transient var transientText: String = ""
var text: String = ""
}
@@ -0,0 +1,32 @@
import android.os.Parcel
import android.os.Parcelable
// INTENTION_CLASS: org.jetbrains.kotlin.android.intention.ImplementParcelableAction
// WITH_RUNTIME
class WithTransient() : Parcelable {
@Transient var transientText: String = ""
var text: String = ""
constructor(parcel: Parcel) : this() {
text = parcel.readString()
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(text)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<WithTransient> {
override fun createFromParcel(parcel: Parcel): WithTransient {
return WithTransient(parcel)
}
override fun newArray(size: Int): Array<WithTransient?> {
return arrayOfNulls(size)
}
}
}
@@ -0,0 +1,44 @@
// INTENTION_CLASS: org.jetbrains.kotlin.android.intention.RedoParcelableAction
import android.os.Parcel
import android.os.Parcelable
open class BaseParcelable(parcel: Parcel) : Parcelable {
override fun writeToParcel(parcel: Parcel, flags: Int) {
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<BaseParcelable> {
override fun createFromParcel(parcel: Parcel): BaseParcelable {
return BaseParcelable(parcel)
}
override fun newArray(size: Int): Array<BaseParcelable?> {
return arrayOfNulls(size)
}
}
}
class <caret>MyData(prcl: Parcel) : BaseParcelable(prcl) {
override fun writeToParcel(parcel: Parcel, flags: Int) {
super.writeToParcel(parcel, flags)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<MyData> {
override fun createFromParcel(parcel: Parcel): MyData {
return MyData(parcel)
}
override fun newArray(size: Int): Array<MyData?> {
return arrayOfNulls(size)
}
}
}
@@ -0,0 +1,48 @@
// INTENTION_CLASS: org.jetbrains.kotlin.android.intention.RedoParcelableAction
import android.os.Parcel
import android.os.Parcelable
open class BaseParcelable(parcel: Parcel) : Parcelable {
override fun writeToParcel(parcel: Parcel, flags: Int) {
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<BaseParcelable> {
override fun createFromParcel(parcel: Parcel): BaseParcelable {
return BaseParcelable(parcel)
}
override fun newArray(size: Int): Array<BaseParcelable?> {
return arrayOfNulls(size)
}
}
}
class MyData() : BaseParcelable(prcl) {
constructor(parcel: Parcel) : this() {
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
super.writeToParcel(parcel, flags)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<MyData> {
override fun createFromParcel(parcel: Parcel): MyData {
return MyData(parcel)
}
override fun newArray(size: Int): Array<MyData?> {
return arrayOfNulls(size)
}
}
}
+35
View File
@@ -0,0 +1,35 @@
// INTENTION_CLASS: org.jetbrains.kotlin.android.intention.RedoParcelableAction
import android.os.Parcel
import android.os.Parcelable
class <caret>MyData(parcel: Parcel) : Parcelable {
var count: Int = 0
var text: String = ""
init {
count = parcel.readInt()
text = parcel.readString()
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeInt(count)
parcel.writeString(text)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<MyData> {
override fun createFromParcel(parcel: Parcel): MyData {
return MyData(parcel)
}
override fun newArray(size: Int): Array<MyData?> {
return arrayOfNulls(size)
}
}
}
@@ -0,0 +1,36 @@
// INTENTION_CLASS: org.jetbrains.kotlin.android.intention.RedoParcelableAction
import android.os.Parcel
import android.os.Parcelable
class MyData() : Parcelable {
var count: Int = 0
var text: String = ""
constructor(parcel: Parcel) : this() {
count = parcel.readInt()
text = parcel.readString()
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeInt(count)
parcel.writeString(text)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<MyData> {
override fun createFromParcel(parcel: Parcel): MyData {
return MyData(parcel)
}
override fun newArray(size: Int): Array<MyData?> {
return arrayOfNulls(size)
}
}
}
@@ -0,0 +1,40 @@
// INTENTION_CLASS: org.jetbrains.kotlin.android.intention.RedoParcelableAction
import android.os.Parcel
import android.os.Parcelable
class <caret>MyData(parcel: Parcel) : Parcelable {
var count: Int = 0
var text: String = ""
fun initialize() {
}
init {
initialize()
count = parcel.readInt()
text = parcel.readString()
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeInt(count)
parcel.writeString(text)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<MyData> {
override fun createFromParcel(parcel: Parcel): MyData {
return MyData(parcel)
}
override fun newArray(size: Int): Array<MyData?> {
return arrayOfNulls(size)
}
}
}
@@ -0,0 +1,44 @@
// INTENTION_CLASS: org.jetbrains.kotlin.android.intention.RedoParcelableAction
import android.os.Parcel
import android.os.Parcelable
class MyData() : Parcelable {
var count: Int = 0
var text: String = ""
constructor(parcel: Parcel) : this() {
count = parcel.readInt()
text = parcel.readString()
}
fun initialize() {
}
init {
initialize()
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeInt(count)
parcel.writeString(text)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<MyData> {
override fun createFromParcel(parcel: Parcel): MyData {
return MyData(parcel)
}
override fun newArray(size: Int): Array<MyData?> {
return arrayOfNulls(size)
}
}
}
@@ -0,0 +1,6 @@
// INTENTION_CLASS: org.jetbrains.kotlin.android.intention.RedoParcelableAction
// NOT_AVAILABLE
class <caret>Simple {
}
@@ -0,0 +1,37 @@
// INTENTION_CLASS: org.jetbrains.kotlin.android.intention.RedoParcelableAction
import android.os.Parcel
import android.os.Parcelable
class <caret>SomeData(parcel: Parcel) : Parcelable {
var count = 0
init {
oldField = parcel.readInt()
field9 = parcel.readByte() != 0.toByte()
goodArray = parcel.createTypedArray(SuperParcelable)
goodList = parcel.createTypedArrayList(SuperParcelable)
parcelableProperty = parcel.readParcelable(SuperParcelable::class.java.classLoader)
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeInt(oldField)
parcel.writeByte(if (field9) 1 else 0)
parcel.writeTypedArray(goodArray, flags)
parcel.writeTypedList(goodList)
parcel.writeParcelable(parcelableProperty, flags)
}
override fun describeContents(): Int {
return 42
}
companion object CREATOR : Parcelable.Creator<SomeData> {
override fun createFromParcel(parcel: Parcel): SomeData {
return SomeData(parcel)
}
override fun newArray(size: Int): Array<SomeData?> {
return arrayOfNulls(size)
}
}
}
@@ -0,0 +1,30 @@
// INTENTION_CLASS: org.jetbrains.kotlin.android.intention.RedoParcelableAction
import android.os.Parcel
import android.os.Parcelable
class SomeData() : Parcelable {
var count = 0
constructor(parcel: Parcel) : this() {
count = parcel.readInt()
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeInt(count)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<SomeData> {
override fun createFromParcel(parcel: Parcel): SomeData {
return SomeData(parcel)
}
override fun newArray(size: Int): Array<SomeData?> {
return arrayOfNulls(size)
}
}
}
@@ -0,0 +1,28 @@
// INTENTION_CLASS: org.jetbrains.kotlin.android.intention.RedoParcelableAction
import android.os.Parcel
import android.os.Parcelable
class <caret>SomeData(val number: Int, val text: String, val flag: Boolean) : Parcelable {
constructor(parcel: Parcel) : this(parcel.readString()) {
someOtherField = parcel.readInt()
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(oldField)
parcel.writeInt(someOtherField)
}
override fun describeContents(): Int {
return 42
}
companion object CREATOR : Parcelable.Creator<SomeData> {
override fun createFromParcel(parcel: Parcel): SomeData {
return SomeData(parcel)
}
override fun newArray(size: Int): Array<SomeData?> {
return arrayOfNulls(size)
}
}
}
@@ -0,0 +1,32 @@
// INTENTION_CLASS: org.jetbrains.kotlin.android.intention.RedoParcelableAction
import android.os.Parcel
import android.os.Parcelable
class SomeData(val number: Int, val text: String, val flag: Boolean) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readInt(),
parcel.readString(),
parcel.readByte() != 0.toByte()) {
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeInt(number)
parcel.writeString(text)
parcel.writeByte(if (flag) 1 else 0)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<SomeData> {
override fun createFromParcel(parcel: Parcel): SomeData {
return SomeData(parcel)
}
override fun newArray(size: Int): Array<SomeData?> {
return arrayOfNulls(size)
}
}
}
@@ -0,0 +1,4 @@
// INTENTION_CLASS: org.jetbrains.kotlin.android.intention.RedoParcelableAction
import android.os.Parcelable
class <caret>Simple : Parcelable
@@ -0,0 +1,26 @@
// INTENTION_CLASS: org.jetbrains.kotlin.android.intention.RedoParcelableAction
import android.os.Parcel
import android.os.Parcelable
class Simple() : Parcelable {
constructor(parcel: Parcel) : this() {
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<Simple> {
override fun createFromParcel(parcel: Parcel): Simple {
return Simple(parcel)
}
override fun newArray(size: Int): Array<Simple?> {
return arrayOfNulls(size)
}
}
}
@@ -0,0 +1,44 @@
// INTENTION_CLASS: org.jetbrains.kotlin.android.intention.RemoveParcelableAction
import android.os.Parcel
import android.os.Parcelable
open class BaseParcelable(parcel: Parcel) : Parcelable {
override fun writeToParcel(parcel: Parcel, flags: Int) {
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<BaseParcelable> {
override fun createFromParcel(parcel: Parcel): BaseParcelable {
return BaseParcelable(parcel)
}
override fun newArray(size: Int): Array<BaseParcelable?> {
return arrayOfNulls(size)
}
}
}
class <caret>MyData(parcel: Parcel) : BaseParcelable(parcel) {
override fun writeToParcel(parcel: Parcel, flags: Int) {
super.writeToParcel(parcel, flags)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<MyData> {
override fun createFromParcel(parcel: Parcel): MyData {
return MyData(parcel)
}
override fun newArray(size: Int): Array<MyData?> {
return arrayOfNulls(size)
}
}
}
@@ -0,0 +1,28 @@
// INTENTION_CLASS: org.jetbrains.kotlin.android.intention.RemoveParcelableAction
import android.os.Parcel
import android.os.Parcelable
open class BaseParcelable(parcel: Parcel) : Parcelable {
override fun writeToParcel(parcel: Parcel, flags: Int) {
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<BaseParcelable> {
override fun createFromParcel(parcel: Parcel): BaseParcelable {
return BaseParcelable(parcel)
}
override fun newArray(size: Int): Array<BaseParcelable?> {
return arrayOfNulls(size)
}
}
}
class MyData : BaseParcelable(parcel) {
}
@@ -0,0 +1,35 @@
// INTENTION_CLASS: org.jetbrains.kotlin.android.intention.RemoveParcelableAction
import android.os.Parcel
import android.os.Parcelable
class <caret>MyData(parcel: Parcel) : Parcelable {
var count: Int = 0
var text: String = ""
init {
count = parcel.readInt()
text = parcel.readString()
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeInt(count)
parcel.writeString(text)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<MyData> {
override fun createFromParcel(parcel: Parcel): MyData {
return MyData(parcel)
}
override fun newArray(size: Int): Array<MyData?> {
return arrayOfNulls(size)
}
}
}
@@ -0,0 +1,12 @@
// INTENTION_CLASS: org.jetbrains.kotlin.android.intention.RemoveParcelableAction
import android.os.Parcel
import android.os.Parcelable
class MyData {
var count: Int = 0
var text: String = ""
}
@@ -0,0 +1,40 @@
// INTENTION_CLASS: org.jetbrains.kotlin.android.intention.RemoveParcelableAction
import android.os.Parcel
import android.os.Parcelable
class <caret>MyData(parcel: Parcel) : Parcelable {
var count: Int = 0
var text: String = ""
fun initialize() {
}
init {
initialize()
count = parcel.readInt()
text = parcel.readString()
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeInt(count)
parcel.writeString(text)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<MyData> {
override fun createFromParcel(parcel: Parcel): MyData {
return MyData(parcel)
}
override fun newArray(size: Int): Array<MyData?> {
return arrayOfNulls(size)
}
}
}
@@ -0,0 +1,20 @@
// INTENTION_CLASS: org.jetbrains.kotlin.android.intention.RemoveParcelableAction
import android.os.Parcel
import android.os.Parcelable
class MyData {
var count: Int = 0
var text: String = ""
fun initialize() {
}
init {
initialize()
}
}
@@ -0,0 +1,6 @@
// INTENTION_CLASS: org.jetbrains.kotlin.android.intention.RemoveParcelableAction
// NOT_AVAILABLE
class <caret>Simple {
}
@@ -0,0 +1,4 @@
// INTENTION_CLASS: org.jetbrains.kotlin.android.intention.RemoveParcelableAction
import android.os.Parcelable
class <caret>Simple : Parcelable
@@ -0,0 +1,4 @@
// INTENTION_CLASS: org.jetbrains.kotlin.android.intention.RemoveParcelableAction
import android.os.Parcelable
class Simple
@@ -0,0 +1,14 @@
// INTENTION_TEXT: Add Parcelable Implementation
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintParcelCreatorInspection
import android.os.Parcel
import android.os.Parcelable
class <caret>MissingCreator : Parcelable {
override fun writeToParcel(dest: Parcel?, flags: Int) {
TODO("not implemented")
}
override fun describeContents(): Int {
TODO("not implemented")
}
}
@@ -0,0 +1,27 @@
// INTENTION_TEXT: Add Parcelable Implementation
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintParcelCreatorInspection
import android.os.Parcel
import android.os.Parcelable
class MissingCreator() : Parcelable {
constructor(parcel: Parcel) : this() {
}
override fun writeToParcel(dest: Parcel?, flags: Int) {
TODO("not implemented")
}
override fun describeContents(): Int {
TODO("not implemented")
}
companion object CREATOR : Parcelable.Creator<MissingCreator> {
override fun createFromParcel(parcel: Parcel): MissingCreator {
return MissingCreator(parcel)
}
override fun newArray(size: Int): Array<MissingCreator?> {
return arrayOfNulls(size)
}
}
}
@@ -0,0 +1,5 @@
// INTENTION_TEXT: Add Parcelable Implementation
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintParcelCreatorInspection
import android.os.Parcelable
class <caret>NoImplementation : Parcelable
@@ -0,0 +1,27 @@
// INTENTION_TEXT: Add Parcelable Implementation
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintParcelCreatorInspection
import android.os.Parcel
import android.os.Parcelable
class NoImplementation() : Parcelable {
constructor(parcel: Parcel) : this() {
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<NoImplementation> {
override fun createFromParcel(parcel: Parcel): NoImplementation {
return NoImplementation(parcel)
}
override fun newArray(size: Int): Array<NoImplementation?> {
return arrayOfNulls(size)
}
}
}
+1
View File
@@ -19,5 +19,6 @@
<orderEntry type="module" module-name="idea-analysis" />
<orderEntry type="module" module-name="idea-core" />
<orderEntry type="module" module-name="idea" />
<orderEntry type="module" module-name="idea-android" />
</component>
</module>
@@ -255,7 +255,11 @@ public class AndroidLintInspectionToolProvider {
public AndroidKLintParcelCreatorInspection() {
super(AndroidBundle.message("android.lint.inspections.parcel.creator"), ParcelDetector.ISSUE);
}
@NotNull
@Override
public AndroidLintQuickFix[] getQuickFixes(@NotNull String message) {
return new AndroidLintQuickFix[]{ new ParcelableQuickFix() };
}
}
public static class AndroidKLintPluralsCandidateInspection extends AndroidLintInspectionBase {
@@ -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.android.inspections.klint
import com.intellij.psi.PsiElement
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.android.util.AndroidBundle
import org.jetbrains.kotlin.android.canAddParcelable
import org.jetbrains.kotlin.android.implementParcelable
import org.jetbrains.kotlin.psi.KtClass
class ParcelableQuickFix : AndroidLintQuickFix {
override fun apply(startElement: PsiElement, endElement: PsiElement, context: AndroidQuickfixContexts.Context) {
startElement.getTargetClass()?.implementParcelable()
}
override fun isApplicable(startElement: PsiElement, endElement: PsiElement, contextType: AndroidQuickfixContexts.ContextType): Boolean =
startElement.getTargetClass()?.canAddParcelable() ?: false
override fun getName(): String = AndroidBundle.message("implement.parcelable.intention.text")
private fun PsiElement.getTargetClass(): KtClass? = PsiTreeUtil.getParentOfType(this, KtClass::class.java, false)
}