[Parcelize] Detect redundant TypeParceler when type aliases are used
Make sure redundancies between class and property TypeParceler annotations are detected when a type alias is used. This requires checking the expanded type arguments of the annotation, as just comparing the cone types is not sufficient because the type arguments are not expanded. ^KT-64979 Fixed
This commit is contained in:
@@ -122,10 +122,6 @@ private val USE_SITE_TARGET_NAME_MAP = mapOf(
|
|||||||
private val DEFAULT_USE_SITE_TARGETS: Set<AnnotationUseSiteTarget> =
|
private val DEFAULT_USE_SITE_TARGETS: Set<AnnotationUseSiteTarget> =
|
||||||
USE_SITE_TARGET_NAME_MAP.values.fold(setOf<AnnotationUseSiteTarget>()) { a, b -> a + b } - setOf(AnnotationUseSiteTarget.FILE)
|
USE_SITE_TARGET_NAME_MAP.values.fold(setOf<AnnotationUseSiteTarget>()) { a, b -> a + b } - setOf(AnnotationUseSiteTarget.FILE)
|
||||||
|
|
||||||
fun FirDeclaration.hasAnnotation(type: ConeClassLikeType, session: FirSession): Boolean {
|
|
||||||
return annotations.hasAnnotation(type, session)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun FirDeclaration.hasAnnotation(classId: ClassId, session: FirSession): Boolean {
|
fun FirDeclaration.hasAnnotation(classId: ClassId, session: FirSession): Boolean {
|
||||||
return annotations.hasAnnotation(classId, session)
|
return annotations.hasAnnotation(classId, session)
|
||||||
}
|
}
|
||||||
@@ -142,10 +138,6 @@ fun FirAnnotationContainer.hasAnnotation(classId: ClassId, session: FirSession):
|
|||||||
return annotations.hasAnnotation(classId, session)
|
return annotations.hasAnnotation(classId, session)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun List<FirAnnotation>.hasAnnotation(type: ConeClassLikeType, session: FirSession): Boolean {
|
|
||||||
return this.any { it.toAnnotationClassLikeType(session) == type }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun List<FirAnnotation>.hasAnnotation(classId: ClassId, session: FirSession): Boolean {
|
fun List<FirAnnotation>.hasAnnotation(classId: ClassId, session: FirSession): Boolean {
|
||||||
return this.any { it.toAnnotationClassId(session) == classId }
|
return this.any { it.toAnnotationClassId(session) == classId }
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-5
@@ -11,10 +11,7 @@ import org.jetbrains.kotlin.diagnostics.reportOn
|
|||||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirAnnotationCallChecker
|
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirAnnotationCallChecker
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.findClosestClassOrObject
|
import org.jetbrains.kotlin.fir.analysis.checkers.findClosestClassOrObject
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirProperty
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
import org.jetbrains.kotlin.fir.declarations.hasAnnotation
|
|
||||||
import org.jetbrains.kotlin.fir.declarations.toAnnotationClassId
|
|
||||||
import org.jetbrains.kotlin.fir.declarations.toAnnotationClassLikeType
|
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.fromPrimaryConstructor
|
import org.jetbrains.kotlin.fir.declarations.utils.fromPrimaryConstructor
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
|
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
|
||||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||||
@@ -94,13 +91,27 @@ object FirParcelizeAnnotationChecker : FirAnnotationCallChecker() {
|
|||||||
val enclosingClass = context.findClosestClassOrObject() ?: return
|
val enclosingClass = context.findClosestClassOrObject() ?: return
|
||||||
|
|
||||||
val annotationType = annotationCall.toAnnotationClassLikeType(context.session) ?: return
|
val annotationType = annotationCall.toAnnotationClassLikeType(context.session) ?: return
|
||||||
if (enclosingClass.hasAnnotation(annotationType, context.session)) {
|
if (checkForRedundantTypeParceler(enclosingClass, annotationType, context)) {
|
||||||
val reportElement = annotationCall.calleeReference.source ?: annotationCall.source
|
val reportElement = annotationCall.calleeReference.source ?: annotationCall.source
|
||||||
reporter.reportOn(reportElement, KtErrorsParcelize.REDUNDANT_TYPE_PARCELER, enclosingClass.symbol, context)
|
reporter.reportOn(reportElement, KtErrorsParcelize.REDUNDANT_TYPE_PARCELER, enclosingClass.symbol, context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun checkForRedundantTypeParceler(
|
||||||
|
enclosingClass: FirClass,
|
||||||
|
annotationType: ConeClassLikeType,
|
||||||
|
context: CheckerContext,
|
||||||
|
): Boolean {
|
||||||
|
return enclosingClass.annotations
|
||||||
|
.mapNotNull { it.toAnnotationClassLikeType(context.session) }
|
||||||
|
.filter { it.classId == annotationType.classId && it.typeArguments.size == annotationType.typeArguments.size }
|
||||||
|
.any {
|
||||||
|
it.typeArguments.zip(annotationType.typeArguments)
|
||||||
|
.all { (first, second) -> first.type?.fullyExpandedType(context.session) == second.type?.fullyExpandedType(context.session) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun checkWriteWithUsage(annotationCall: FirAnnotationCall, context: CheckerContext, reporter: DiagnosticReporter) {
|
private fun checkWriteWithUsage(annotationCall: FirAnnotationCall, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
checkIfTheContainingClassIsParcelize(annotationCall, context, reporter)
|
checkIfTheContainingClassIsParcelize(annotationCall, context, reporter)
|
||||||
|
|
||||||
|
|||||||
+2
-4
@@ -1,6 +1,4 @@
|
|||||||
// WITH_STDLIB
|
// WITH_STDLIB
|
||||||
// fir doesn't support annotations with type arguments
|
|
||||||
// IGNORE_BACKEND_K2: JVM_IR
|
|
||||||
|
|
||||||
@file:JvmName("TestKt")
|
@file:JvmName("TestKt")
|
||||||
package test
|
package test
|
||||||
@@ -32,8 +30,8 @@ object Parceler3 : Parceler<String> {
|
|||||||
data class Test(
|
data class Test(
|
||||||
val a: String,
|
val a: String,
|
||||||
@<!REDUNDANT_TYPE_PARCELER!>TypeParceler<!><String, Parceler1> val b: String,
|
@<!REDUNDANT_TYPE_PARCELER!>TypeParceler<!><String, Parceler1> val b: String,
|
||||||
@TypeParceler<String, Parceler3> val c: CharSequence,
|
@TypeParceler<String, Parceler3> val c: CharSequence,
|
||||||
val d: @WriteWith<Parceler3> String
|
val d: @WriteWith<Parceler3> String,
|
||||||
) : Parcelable
|
) : Parcelable
|
||||||
|
|
||||||
fun box() = parcelTest { parcel ->
|
fun box() = parcelTest { parcel ->
|
||||||
|
|||||||
Reference in New Issue
Block a user