Parcelize: Check @IgnoredOnParcel annotation usage (#KT-24459)

This commit is contained in:
Yan Zhulanow
2018-05-22 01:54:01 +03:00
parent ee37bcf14b
commit 3c1c776cdb
4 changed files with 43 additions and 1 deletions
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.android.parcel
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.PsiTreeUtil
import kotlinx.android.parcel.IgnoredOnParcel
import kotlinx.android.parcel.TypeParceler import kotlinx.android.parcel.TypeParceler
import kotlinx.android.parcel.WriteWith import kotlinx.android.parcel.WriteWith
import org.jetbrains.kotlin.android.synthetic.diagnostic.DefaultErrorMessagesAndroid import org.jetbrains.kotlin.android.synthetic.diagnostic.DefaultErrorMessagesAndroid
@@ -44,6 +45,7 @@ class ParcelableAnnotationChecker : CallChecker {
companion object { companion object {
val TYPE_PARCELER_FQNAME = FqName(TypeParceler::class.java.name) val TYPE_PARCELER_FQNAME = FqName(TypeParceler::class.java.name)
val WRITE_WITH_FQNAME = FqName(WriteWith::class.java.name) val WRITE_WITH_FQNAME = FqName(WriteWith::class.java.name)
val IGNORED_ON_PARCEL_FQNAME = FqName(IgnoredOnParcel::class.java.name)
} }
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) { override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
@@ -60,6 +62,21 @@ class ParcelableAnnotationChecker : CallChecker {
if (annotationClass.fqNameSafe == WRITE_WITH_FQNAME) { if (annotationClass.fqNameSafe == WRITE_WITH_FQNAME) {
checkWriteWithUsage(resolvedCall, annotationEntry, context, annotationOwner) checkWriteWithUsage(resolvedCall, annotationEntry, context, annotationOwner)
} }
if (annotationClass.fqNameSafe == IGNORED_ON_PARCEL_FQNAME) {
checkIgnoredOnParcelUsage(annotationEntry, context, annotationOwner)
}
}
private fun checkIgnoredOnParcelUsage(annotationEntry: KtAnnotationEntry, context: CallCheckerContext, element: KtModifierListOwner) {
if (element is KtParameter && PsiTreeUtil.getParentOfType(element, KtDeclaration::class.java) is KtPrimaryConstructor) {
context.trace.reportFromPlugin(
ErrorsAndroid.INAPPLICABLE_IGNORED_ON_PARCEL_CONSTRUCTOR_PROPERTY.on(annotationEntry),
DefaultErrorMessagesAndroid
)
} else if (element !is KtProperty || PsiTreeUtil.getParentOfType(element, KtDeclaration::class.java) !is KtClass) {
context.trace.reportFromPlugin(ErrorsAndroid.INAPPLICABLE_IGNORED_ON_PARCEL.on(annotationEntry), DefaultErrorMessagesAndroid)
}
} }
private fun checkTypeParcelerUsage( private fun checkTypeParcelerUsage(
@@ -101,5 +101,11 @@ object DefaultErrorMessagesAndroid : DefaultErrorMessages.Extension {
MAP.put(ErrorsAndroid.CLASS_SHOULD_BE_PARCELIZE, MAP.put(ErrorsAndroid.CLASS_SHOULD_BE_PARCELIZE,
"{0} should be annotated with ''@Parcelize''", "{0} should be annotated with ''@Parcelize''",
RENDER_CLASS_OR_OBJECT) RENDER_CLASS_OR_OBJECT)
MAP.put(ErrorsAndroid.INAPPLICABLE_IGNORED_ON_PARCEL,
"'@IgnoredOnParcel' is only applicable to class properties")
MAP.put(ErrorsAndroid.INAPPLICABLE_IGNORED_ON_PARCEL_CONSTRUCTOR_PROPERTY,
"'@IgnoredOnParcel' is inapplicable to properties declared in the primary constructor")
} }
} }
@@ -56,6 +56,9 @@ public interface ErrorsAndroid {
DiagnosticFactory1<PsiElement, KtClassOrObject> REDUNDANT_TYPE_PARCELER = DiagnosticFactory1.create(WARNING); DiagnosticFactory1<PsiElement, KtClassOrObject> REDUNDANT_TYPE_PARCELER = DiagnosticFactory1.create(WARNING);
DiagnosticFactory1<PsiElement, KtClassOrObject> CLASS_SHOULD_BE_PARCELIZE = DiagnosticFactory1.create(ERROR); DiagnosticFactory1<PsiElement, KtClassOrObject> CLASS_SHOULD_BE_PARCELIZE = DiagnosticFactory1.create(ERROR);
DiagnosticFactory0<PsiElement> INAPPLICABLE_IGNORED_ON_PARCEL = DiagnosticFactory0.create(WARNING);
DiagnosticFactory0<PsiElement> INAPPLICABLE_IGNORED_ON_PARCEL_CONSTRUCTOR_PROPERTY = DiagnosticFactory0.create(WARNING);
@SuppressWarnings("UnusedDeclaration") @SuppressWarnings("UnusedDeclaration")
Object _initializer = new Object() { Object _initializer = new Object() {
{ {
@@ -1,6 +1,6 @@
package test package test
import kotlinx.android.parcel.Parcelize import kotlinx.android.parcel.*
import android.os.Parcelable import android.os.Parcelable
@Parcelize @Parcelize
@@ -18,3 +18,19 @@ class A(val firstName: String) : Parcelable {
get() = "" get() = ""
set(<warning descr="[UNUSED_PARAMETER] Parameter 'v' is never used">v</warning>) {} set(<warning descr="[UNUSED_PARAMETER] Parameter 'v' is never used">v</warning>) {}
} }
@Parcelize
@Suppress("WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET")
class B(<warning descr="[PLUGIN_WARNING] '@IgnoredOnParcel' is inapplicable to properties declared in the primary constructor">@IgnoredOnParcel</warning> val firstName: String) : Parcelable {
@IgnoredOnParcel
var a: String = ""
@field:IgnoredOnParcel
var <warning descr="[PLUGIN_WARNING] Property would not be serialized into a 'Parcel'. Add '@IgnoredOnParcel' annotation to remove the warning">b</warning>: String = ""
@get:IgnoredOnParcel
var <warning descr="[PLUGIN_WARNING] Property would not be serialized into a 'Parcel'. Add '@IgnoredOnParcel' annotation to remove the warning">c</warning>: String = ""
@set:IgnoredOnParcel
var <warning descr="[PLUGIN_WARNING] Property would not be serialized into a 'Parcel'. Add '@IgnoredOnParcel' annotation to remove the warning">d</warning>: String = ""
}