[FIR] Implement checkers for FIR parcelize plugin
There is one of checks left unimplemented (FirParcelizePropertyChecker.checkParcelableClassProperty) because it requires huge commonization of detecting which type can be serialized and which not, which is not prioritized job for now
This commit is contained in:
committed by
teamcityserver
parent
eac9a9fc79
commit
8cdddbfd9d
@@ -90,6 +90,7 @@ val ConeKotlinType.isNullableBoolean: Boolean get() = isBuiltinType(StandardClas
|
||||
val ConeKotlinType.isBooleanOrNullableBoolean: Boolean get() = isAnyOfBuiltinType(setOf(StandardClassIds.Boolean))
|
||||
val ConeKotlinType.isEnum: Boolean get() = isBuiltinType(StandardClassIds.Enum, false)
|
||||
val ConeKotlinType.isString: Boolean get() = isBuiltinType(StandardClassIds.String, false)
|
||||
val ConeKotlinType.isInt: Boolean get() = isBuiltinType(StandardClassIds.Int, false)
|
||||
val ConeKotlinType.isPrimitiveOrNullablePrimitive: Boolean get() = isAnyOfBuiltinType(StandardClassIds.primitiveTypes)
|
||||
val ConeKotlinType.isPrimitive: Boolean get() = isPrimitiveOrNullablePrimitive && nullability == ConeNullability.NOT_NULL
|
||||
val ConeKotlinType.isArrayType: Boolean
|
||||
|
||||
+39
-17
@@ -420,24 +420,9 @@ object LightTreePositioningStrategies {
|
||||
val TAILREC_MODIFIER: LightTreePositioningStrategy =
|
||||
ModifierSetBasedLightTreePositioningStrategy(TokenSet.create(KtTokens.TAILREC_KEYWORD))
|
||||
|
||||
val FIELD_KEYWORD: LightTreePositioningStrategy = object : LightTreePositioningStrategy() {
|
||||
override fun mark(
|
||||
node: LighterASTNode,
|
||||
startOffset: Int,
|
||||
endOffset: Int,
|
||||
tree: FlyweightCapableTreeStructure<LighterASTNode>
|
||||
): List<TextRange> {
|
||||
val fieldKeyword = tree.fieldKeyword(node)
|
||||
if (fieldKeyword != null) {
|
||||
return markElement(fieldKeyword, startOffset, endOffset, tree, node)
|
||||
}
|
||||
return DEFAULT.mark(node, startOffset, endOffset, tree)
|
||||
}
|
||||
val OBJECT_KEYWORD: LightTreePositioningStrategy = keywordStrategy { objectKeyword(it) }
|
||||
|
||||
override fun isValid(node: LighterASTNode, tree: FlyweightCapableTreeStructure<LighterASTNode>): Boolean {
|
||||
return tree.fieldKeyword(node) != null
|
||||
}
|
||||
}
|
||||
val FIELD_KEYWORD: LightTreePositioningStrategy = keywordStrategy { fieldKeyword(it) }
|
||||
|
||||
val PROPERTY_DELEGATE: LightTreePositioningStrategy = object : LightTreePositioningStrategy() {
|
||||
override fun mark(
|
||||
@@ -1053,6 +1038,22 @@ object LightTreePositioningStrategies {
|
||||
KtTokens.SEALED_KEYWORD
|
||||
)
|
||||
)
|
||||
|
||||
val DELEGATED_SUPERTYPE_BY_KEYWORD: LightTreePositioningStrategy = object : LightTreePositioningStrategy() {
|
||||
override fun mark(
|
||||
node: LighterASTNode,
|
||||
startOffset: Int,
|
||||
endOffset: Int,
|
||||
tree: FlyweightCapableTreeStructure<LighterASTNode>
|
||||
): List<TextRange> {
|
||||
val parent = tree.getParent(node)
|
||||
if (parent == null || parent.tokenType != KtNodeTypes.DELEGATED_SUPER_TYPE_ENTRY) {
|
||||
return super.mark(node, startOffset, endOffset, tree)
|
||||
}
|
||||
val byKeyword = parent.getChildren(tree).firstOrNull { it.tokenType == KtTokens.BY_KEYWORD } ?: node
|
||||
return markElement(byKeyword, startOffset, endOffset, tree, node)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun KtSourceElement.hasValOrVar(): Boolean =
|
||||
@@ -1235,6 +1236,27 @@ private fun FlyweightCapableTreeStructure<LighterASTNode>.receiverTypeReference(
|
||||
}
|
||||
}
|
||||
|
||||
private fun keywordStrategy(
|
||||
keywordExtractor: FlyweightCapableTreeStructure<LighterASTNode>.(LighterASTNode) -> LighterASTNode?
|
||||
): LightTreePositioningStrategy = object : LightTreePositioningStrategy() {
|
||||
override fun mark(
|
||||
node: LighterASTNode,
|
||||
startOffset: Int,
|
||||
endOffset: Int,
|
||||
tree: FlyweightCapableTreeStructure<LighterASTNode>
|
||||
): List<TextRange> {
|
||||
val fieldKeyword = tree.keywordExtractor(node)
|
||||
if (fieldKeyword != null) {
|
||||
return markElement(fieldKeyword, startOffset, endOffset, tree, node)
|
||||
}
|
||||
return LightTreePositioningStrategies.DEFAULT.mark(node, startOffset, endOffset, tree)
|
||||
}
|
||||
|
||||
override fun isValid(node: LighterASTNode, tree: FlyweightCapableTreeStructure<LighterASTNode>): Boolean {
|
||||
return tree.keywordExtractor(node) != null
|
||||
}
|
||||
}
|
||||
|
||||
private fun FlyweightCapableTreeStructure<LighterASTNode>.defaultValue(node: LighterASTNode): LighterASTNode? {
|
||||
val childrenRef = Ref<Array<LighterASTNode?>>()
|
||||
getChildren(node, childrenRef)
|
||||
|
||||
+14
@@ -295,6 +295,13 @@ object PositioningStrategies {
|
||||
@JvmField
|
||||
val TAILREC_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.TAILREC_KEYWORD)
|
||||
|
||||
@JvmField
|
||||
val OBJECT_KEYWORD: PositioningStrategy<KtObjectDeclaration> = object : PositioningStrategy<KtObjectDeclaration>() {
|
||||
override fun mark(element: KtObjectDeclaration): List<TextRange> {
|
||||
return markElement(element.getObjectKeyword() ?: element)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmField
|
||||
val FIELD_KEYWORD: PositioningStrategy<KtBackingField> = object : DeclarationHeader<KtBackingField>() {
|
||||
override fun mark(element: KtBackingField): List<TextRange> {
|
||||
@@ -893,6 +900,13 @@ object PositioningStrategies {
|
||||
val NON_FINAL_MODIFIER_OR_NAME: PositioningStrategy<KtModifierListOwner> =
|
||||
ModifierSetBasedPositioningStrategy(TokenSet.create(KtTokens.ABSTRACT_KEYWORD, KtTokens.OPEN_KEYWORD, KtTokens.SEALED_KEYWORD))
|
||||
|
||||
val DELEGATED_SUPERTYPE_BY_KEYWORD: PositioningStrategy<KtTypeReference> = object : PositioningStrategy<KtTypeReference>() {
|
||||
override fun mark(element: KtTypeReference): List<TextRange> {
|
||||
val parent = element.parent as? KtDelegatedSuperTypeEntry ?: return super.mark(element)
|
||||
return markElement(parent.byKeywordNode.psi ?: element)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param locateReferencedName whether to remove any nested parentheses while locating the reference element. This is useful for
|
||||
* diagnostics on super and unresolved references. For example, with the following, only the part inside the parentheses should be
|
||||
|
||||
+10
@@ -123,6 +123,11 @@ object SourceElementPositioningStrategies {
|
||||
PositioningStrategies.DATA_MODIFIER
|
||||
)
|
||||
|
||||
val OBJECT_KEYWORD = SourceElementPositioningStrategy(
|
||||
LightTreePositioningStrategies.OBJECT_KEYWORD,
|
||||
PositioningStrategies.OBJECT_KEYWORD
|
||||
)
|
||||
|
||||
val OPERATOR = SourceElementPositioningStrategy(
|
||||
LightTreePositioningStrategies.OPERATOR,
|
||||
PositioningStrategies.OPERATOR
|
||||
@@ -344,4 +349,9 @@ object SourceElementPositioningStrategies {
|
||||
LightTreePositioningStrategies.DECLARATION_START_TO_NAME,
|
||||
PositioningStrategies.DECLARATION_START_TO_NAME
|
||||
)
|
||||
|
||||
val DELEGATED_SUPERTYPE_BY_KEYWORD = SourceElementPositioningStrategy(
|
||||
LightTreePositioningStrategies.DELEGATED_SUPERTYPE_BY_KEYWORD,
|
||||
PositioningStrategies.DELEGATED_SUPERTYPE_BY_KEYWORD
|
||||
)
|
||||
}
|
||||
|
||||
@@ -350,6 +350,8 @@ fun main(args: Array<String>) {
|
||||
}
|
||||
|
||||
generateTestGroupSuiteWithJUnit5 {
|
||||
val excludedFirTestdataPattern = "^(.+)\\.fir\\.kts?\$"
|
||||
|
||||
testGroup("plugins/parcelize/parcelize-compiler/tests-gen", "plugins/parcelize/parcelize-compiler/testData") {
|
||||
testClass<AbstractParcelizeBoxTest> {
|
||||
model("box")
|
||||
@@ -372,7 +374,11 @@ fun main(args: Array<String>) {
|
||||
}
|
||||
|
||||
testClass<AbstractParcelizeDiagnosticTest> {
|
||||
model("diagnostics")
|
||||
model("diagnostics", excludedPattern = excludedFirTestdataPattern)
|
||||
}
|
||||
|
||||
testClass<AbstractFirParcelizeDiagnosticTest> {
|
||||
model("diagnostics", excludedPattern = excludedFirTestdataPattern)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ dependencies {
|
||||
compileOnly(project(":compiler:fir:tree"))
|
||||
compileOnly(project(":compiler:fir:resolve"))
|
||||
compileOnly(project(":compiler:fir:checkers"))
|
||||
compileOnly(project(":compiler:fir:checkers:checkers.jvm"))
|
||||
compileOnly(project(":compiler:fir:fir2ir"))
|
||||
compileOnly(project(":compiler:ir.backend.common"))
|
||||
compileOnly(project(":compiler:ir.tree.impl"))
|
||||
|
||||
+29
-27
@@ -31,11 +31,7 @@ import org.jetbrains.kotlin.parcelize.ParcelizeSyntheticComponent.ComponentKind.
|
||||
import org.jetbrains.kotlin.parcelize.ParcelizeSyntheticComponent.ComponentKind.WRITE_TO_PARCEL
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperInterfaces
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.*
|
||||
import org.jetbrains.kotlin.resolve.extensions.SyntheticResolveExtension
|
||||
import org.jetbrains.kotlin.resolve.source.PsiSourceElement
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
@@ -174,33 +170,39 @@ interface ParcelizeSyntheticComponent {
|
||||
}
|
||||
}
|
||||
|
||||
val TYPE_PARCELER_FQ_NAMES = listOf(
|
||||
FqName("kotlinx.parcelize.TypeParceler"),
|
||||
FqName("kotlinx.android.parcel.TypeParceler")
|
||||
val PACKAGES_FQ_NAMES = listOf(
|
||||
FqName("kotlinx.parcelize"),
|
||||
FqName("kotlinx.android.parcel")
|
||||
)
|
||||
|
||||
val WRITE_WITH_FQ_NAMES = listOf(
|
||||
FqName("kotlinx.parcelize.WriteWith"),
|
||||
FqName("kotlinx.android.parcel.WriteWith")
|
||||
)
|
||||
private fun createClassIds(name: String): List<ClassId> {
|
||||
return PACKAGES_FQ_NAMES.map { ClassId(it, Name.identifier(name)) }
|
||||
}
|
||||
|
||||
val IGNORED_ON_PARCEL_FQ_NAMES = listOf(
|
||||
FqName("kotlinx.parcelize.IgnoredOnParcel"),
|
||||
FqName("kotlinx.android.parcel.IgnoredOnParcel")
|
||||
)
|
||||
private fun List<ClassId>.fqNames(): List<FqName> {
|
||||
return map { it.asSingleFqName() }
|
||||
}
|
||||
|
||||
val PARCELIZE_CLASS_FQ_NAMES: List<FqName> = listOf(
|
||||
FqName("kotlinx.parcelize.Parcelize"),
|
||||
FqName("kotlinx.android.parcel.Parcelize")
|
||||
)
|
||||
val TYPE_PARCELER_CLASS_IDS = createClassIds("TypeParceler")
|
||||
val TYPE_PARCELER_FQ_NAMES = TYPE_PARCELER_CLASS_IDS.fqNames()
|
||||
|
||||
val RAW_VALUE_ANNOTATION_FQ_NAMES = listOf(
|
||||
FqName("kotlinx.parcelize.RawValue"),
|
||||
FqName("kotlinx.android.parcel.RawValue")
|
||||
)
|
||||
val WRITE_WITH_CLASS_IDS = createClassIds("WriteWith")
|
||||
val WRITE_WITH_FQ_NAMES = WRITE_WITH_CLASS_IDS.fqNames()
|
||||
|
||||
internal val PARCELER_FQNAME = FqName("kotlinx.parcelize.Parceler")
|
||||
internal val OLD_PARCELER_FQNAME = FqName("kotlinx.android.parcel.Parceler")
|
||||
val IGNORED_ON_PARCEL_CLASS_IDS = createClassIds("IgnoredOnParcel")
|
||||
val IGNORED_ON_PARCEL_FQ_NAMES = IGNORED_ON_PARCEL_CLASS_IDS.fqNames()
|
||||
|
||||
val PARCELIZE_CLASS_CLASS_IDS = createClassIds("Parcelize")
|
||||
val PARCELIZE_CLASS_FQ_NAMES: List<FqName> = PARCELIZE_CLASS_CLASS_IDS.fqNames()
|
||||
|
||||
val RAW_VALUE_ANNOTATION_CLASS_IDS = createClassIds("RawValue")
|
||||
val RAW_VALUE_ANNOTATION_FQ_NAMES = RAW_VALUE_ANNOTATION_CLASS_IDS.fqNames()
|
||||
|
||||
internal val PARCELER_CLASS_ID = ClassId(FqName("kotlinx.parcelize"), Name.identifier("Parceler"))
|
||||
internal val PARCELER_FQNAME = PARCELER_CLASS_ID.asSingleFqName()
|
||||
|
||||
internal val OLD_PARCELER_CLASS_ID = ClassId(FqName("kotlinx.android.parcel"), Name.identifier("Parceler"))
|
||||
internal val OLD_PARCELER_FQNAME = OLD_PARCELER_CLASS_ID.asSingleFqName()
|
||||
|
||||
val ClassDescriptor.hasParcelizeAnnotation: Boolean
|
||||
get() = PARCELIZE_CLASS_FQ_NAMES.any(annotations::hasAnnotation)
|
||||
@@ -232,4 +234,4 @@ fun Annotated.hasAnyAnnotation(fqNames: List<FqName>): Boolean {
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.parcelize.fir
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.*
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.ExpressionCheckers
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirAnnotationCallChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.extensions.FirAdditionalCheckersExtension
|
||||
import org.jetbrains.kotlin.fir.declarations.FirPluginKey
|
||||
import org.jetbrains.kotlin.parcelize.fir.diagnostics.*
|
||||
|
||||
class FirParcelizeCheckersExtension(session: FirSession) : FirAdditionalCheckersExtension(session) {
|
||||
override val key: FirPluginKey
|
||||
get() = FirParcelizePluginKey
|
||||
|
||||
override val expressionCheckers: ExpressionCheckers = object : ExpressionCheckers() {
|
||||
override val annotationCallCheckers: Set<FirAnnotationCallChecker>
|
||||
get() = setOf(FirParcelizeAnnotationChecker)
|
||||
}
|
||||
|
||||
override val declarationCheckers: DeclarationCheckers = object : DeclarationCheckers() {
|
||||
override val classCheckers: Set<FirClassChecker>
|
||||
get() = setOf(FirParcelizeClassChecker)
|
||||
|
||||
override val propertyCheckers: Set<FirPropertyChecker>
|
||||
get() = setOf(FirParcelizePropertyChecker)
|
||||
|
||||
override val simpleFunctionCheckers: Set<FirSimpleFunctionChecker>
|
||||
get() = setOf(FirParcelizeFunctionChecker)
|
||||
|
||||
override val constructorCheckers: Set<FirConstructorChecker>
|
||||
get() = setOf(FirParcelizeConstructorChecker)
|
||||
}
|
||||
}
|
||||
+1
@@ -10,5 +10,6 @@ import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar
|
||||
class FirParcelizeExtensionRegistrar : FirExtensionRegistrar() {
|
||||
override fun ExtensionRegistrarContext.configurePlugin() {
|
||||
+::FirParcelizeDeclarationGenerator
|
||||
+::FirParcelizeCheckersExtension
|
||||
}
|
||||
}
|
||||
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.parcelize.fir.diagnostics
|
||||
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirAnnotationCallChecker
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
|
||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.parcelize.*
|
||||
|
||||
object FirParcelizeAnnotationChecker : FirAnnotationCallChecker() {
|
||||
override fun check(expression: FirAnnotationCall, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val annotationType = expression.annotationTypeRef.coneType.fullyExpandedType(context.session) as? ConeClassLikeType ?: return
|
||||
val resolvedAnnotationSymbol = annotationType.lookupTag.toFirRegularClassSymbol(context.session) ?: return
|
||||
when (val annotationClassId = resolvedAnnotationSymbol.classId) {
|
||||
in TYPE_PARCELER_CLASS_IDS -> {
|
||||
checkTypeParcelerUsage(expression, context, reporter)
|
||||
checkDeprecatedAnnotations(expression, annotationClassId, context, reporter, isForbidden = true)
|
||||
}
|
||||
in WRITE_WITH_CLASS_IDS -> {
|
||||
checkWriteWithUsage(expression, context, reporter)
|
||||
checkDeprecatedAnnotations(expression, annotationClassId, context, reporter, isForbidden = true)
|
||||
}
|
||||
in IGNORED_ON_PARCEL_CLASS_IDS -> {
|
||||
checkDeprecatedAnnotations(expression, annotationClassId, context, reporter, isForbidden = false)
|
||||
}
|
||||
in PARCELIZE_CLASS_CLASS_IDS, in RAW_VALUE_ANNOTATION_CLASS_IDS -> {
|
||||
checkDeprecatedAnnotations(expression, annotationClassId, context, reporter, isForbidden = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkDeprecatedAnnotations(
|
||||
annotationCall: FirAnnotationCall,
|
||||
annotationClassId: ClassId,
|
||||
context: CheckerContext,
|
||||
reporter: DiagnosticReporter,
|
||||
isForbidden: Boolean
|
||||
) {
|
||||
if (annotationClassId.packageFqName == ParcelizeAnnotationChecker.DEPRECATED_RUNTIME_PACKAGE) {
|
||||
val factory = if (isForbidden) KtErrorsParcelize.FORBIDDEN_DEPRECATED_ANNOTATION else KtErrorsParcelize.DEPRECATED_ANNOTATION
|
||||
reporter.reportOn(annotationCall.source, factory, context)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
private fun checkTypeParcelerUsage(annotationCall: FirAnnotationCall, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
// TODO: this check checks type arguments of annotation which are not supported in FIR
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
private fun checkWriteWithUsage(annotationCall: FirAnnotationCall, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
// TODO: this check checks type arguments of annotation which are not supported in FIR
|
||||
}
|
||||
}
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.parcelize.fir.diagnostics
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.diagnostics.SourceElementPositioningStrategies
|
||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirClassChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.withSuppressedDiagnostics
|
||||
import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.declarations.constructors
|
||||
import org.jetbrains.kotlin.fir.declarations.delegateFieldsMap
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.*
|
||||
import org.jetbrains.kotlin.fir.expressions.classId
|
||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.types.classId
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||
import org.jetbrains.kotlin.fir.types.isSubtypeOf
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.SpecialNames
|
||||
import org.jetbrains.kotlin.parcelize.OLD_PARCELER_CLASS_ID
|
||||
import org.jetbrains.kotlin.parcelize.PARCELIZE_CLASS_CLASS_IDS
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.contracts.contract
|
||||
|
||||
object FirParcelizeClassChecker : FirClassChecker() {
|
||||
private val CREATOR_NAME = Name.identifier("CREATOR")
|
||||
private val PARCELABLE_CLASS_ID = ClassId(FqName("android.os"), Name.identifier("Parcelable"))
|
||||
|
||||
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
checkParcelableClass(declaration, context, reporter)
|
||||
checkParcelerClass(declaration, context, reporter)
|
||||
}
|
||||
|
||||
private fun checkParcelableClass(klass: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val symbol = klass.symbol
|
||||
if (!symbol.isParcelize(context.session)) return
|
||||
val source = klass.source ?: return
|
||||
if (klass !is FirRegularClass) {
|
||||
reporter.reportOn(source, KtErrorsParcelize.PARCELABLE_SHOULD_BE_CLASS, context)
|
||||
return
|
||||
}
|
||||
|
||||
val classKind = klass.classKind
|
||||
if (classKind == ClassKind.ANNOTATION_CLASS || classKind == ClassKind.INTERFACE && !klass.isSealed) {
|
||||
reporter.reportOn(source, KtErrorsParcelize.PARCELABLE_SHOULD_BE_CLASS, context)
|
||||
return
|
||||
}
|
||||
|
||||
klass.companionObjectSymbol?.let { companionSymbol ->
|
||||
if (companionSymbol.classId.shortClassName == CREATOR_NAME) {
|
||||
reporter.reportOn(companionSymbol.source, KtErrorsParcelize.CREATOR_DEFINITION_IS_NOT_ALLOWED, context)
|
||||
}
|
||||
}
|
||||
|
||||
if (classKind == ClassKind.CLASS && klass.isAbstract) {
|
||||
reporter.reportOn(source, KtErrorsParcelize.PARCELABLE_SHOULD_BE_INSTANTIABLE, context)
|
||||
}
|
||||
|
||||
if (klass.isInner) {
|
||||
reporter.reportOn(source, KtErrorsParcelize.PARCELABLE_CANT_BE_INNER_CLASS, context)
|
||||
}
|
||||
|
||||
if (klass.isLocal) {
|
||||
reporter.reportOn(source, KtErrorsParcelize.PARCELABLE_CANT_BE_LOCAL_CLASS, context)
|
||||
}
|
||||
|
||||
val supertypes = lookupSuperTypes(klass, lookupInterfaces = true, deep = true, context.session, substituteTypes = false)
|
||||
if (supertypes.none { it.classId == PARCELABLE_CLASS_ID }) {
|
||||
reporter.reportOn(source, KtErrorsParcelize.NO_PARCELABLE_SUPERTYPE, context)
|
||||
}
|
||||
|
||||
klass.delegateFieldsMap?.forEach { (index, _) ->
|
||||
val superTypeRef = klass.superTypeRefs[index]
|
||||
val superType = superTypeRef.coneType
|
||||
val parcelableType = ConeClassLikeTypeImpl(
|
||||
ConeClassLikeLookupTagImpl(PARCELABLE_CLASS_ID),
|
||||
emptyArray(),
|
||||
isNullable = false
|
||||
)
|
||||
if (superType.isSubtypeOf(parcelableType, context.session)) {
|
||||
reporter.reportOn(superTypeRef.source, KtErrorsParcelize.PARCELABLE_DELEGATE_IS_NOT_ALLOWED, context)
|
||||
}
|
||||
}
|
||||
|
||||
val constructorSymbols = klass.constructors(context.session)
|
||||
val primaryConstructorSymbol = constructorSymbols.find { it.isPrimary }
|
||||
val secondaryConstructorSymbols = constructorSymbols.filterNot { it.isPrimary }
|
||||
if (primaryConstructorSymbol == null && secondaryConstructorSymbols.isNotEmpty()) {
|
||||
reporter.reportOn(source, KtErrorsParcelize.PARCELABLE_SHOULD_HAVE_PRIMARY_CONSTRUCTOR, context)
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkParcelerClass(klass: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (klass !is FirRegularClass || klass.isCompanion) return
|
||||
for (superTypeRef in klass.superTypeRefs) {
|
||||
withSuppressedDiagnostics(superTypeRef, context) {
|
||||
if (superTypeRef.coneType.classId == OLD_PARCELER_CLASS_ID) {
|
||||
val strategy = if (klass.name == SpecialNames.NO_NAME_PROVIDED) {
|
||||
SourceElementPositioningStrategies.OBJECT_KEYWORD
|
||||
} else {
|
||||
SourceElementPositioningStrategies.NAME_IDENTIFIER
|
||||
}
|
||||
reporter.reportOn(klass.source, KtErrorsParcelize.DEPRECATED_PARCELER, context, positioningStrategy = strategy)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
fun FirClassSymbol<*>?.isParcelize(session: FirSession): Boolean {
|
||||
contract {
|
||||
returns(true) implies (this@isParcelize != null)
|
||||
}
|
||||
|
||||
if (this == null) return false
|
||||
if (this.annotations.any { it.classId in PARCELIZE_CLASS_CLASS_IDS }) return true
|
||||
return resolvedSuperTypeRefs.any {
|
||||
val symbol = it.type.fullyExpandedType(session).toRegularClassSymbol(session) ?: return@any false
|
||||
symbol.annotations.any { it.classId in PARCELIZE_CLASS_CLASS_IDS }
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.parcelize.fir.diagnostics
|
||||
|
||||
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.diagnostics.hasValOrVar
|
||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirConstructorChecker
|
||||
import org.jetbrains.kotlin.fir.declarations.FirConstructor
|
||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.parcelize.fir.diagnostics.KtErrorsParcelize.PARCELABLE_CONSTRUCTOR_PARAMETER_SHOULD_BE_VAL_OR_VAR
|
||||
|
||||
object FirParcelizeConstructorChecker : FirConstructorChecker() {
|
||||
override fun check(declaration: FirConstructor, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (!declaration.isPrimary) return
|
||||
val source = declaration.source ?: return
|
||||
if (source.kind == KtFakeSourceElementKind.ImplicitConstructor) return
|
||||
val containingClass = context.containingDeclarations.last() as? FirRegularClass ?: return
|
||||
val containingClassSymbol = containingClass.symbol
|
||||
if (!containingClassSymbol.isParcelize(context.session)) return
|
||||
|
||||
if (declaration.valueParameters.isEmpty()) {
|
||||
reporter.reportOn(containingClass.source, KtErrorsParcelize.PARCELABLE_PRIMARY_CONSTRUCTOR_IS_EMPTY, context)
|
||||
} else {
|
||||
for (valueParameter in declaration.valueParameters) {
|
||||
if (valueParameter.source?.hasValOrVar() != true) {
|
||||
reporter.reportOn(valueParameter.source, PARCELABLE_CONSTRUCTOR_PARAMETER_SHOULD_BE_VAL_OR_VAR, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.parcelize.fir.diagnostics
|
||||
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirSimpleFunctionChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
|
||||
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isOverride
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.fir.types.isInt
|
||||
import org.jetbrains.kotlin.fir.types.isUnit
|
||||
|
||||
object FirParcelizeFunctionChecker : FirSimpleFunctionChecker() {
|
||||
override fun check(declaration: FirSimpleFunction, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val containingClassSymbol = declaration.dispatchReceiverType?.toRegularClassSymbol(context.session)
|
||||
if (!containingClassSymbol.isParcelize(context.session)) return
|
||||
if (declaration.origin != FirDeclarationOrigin.Source) return
|
||||
if (declaration.isWriteToParcel() && declaration.isOverride) {
|
||||
reporter.reportOn(declaration.source, KtErrorsParcelize.OVERRIDING_WRITE_TO_PARCEL_IS_NOT_ALLOWED, context)
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirSimpleFunction.isWriteToParcel(): Boolean {
|
||||
return typeParameters.isEmpty() &&
|
||||
valueParameters.size == 2 &&
|
||||
valueParameters[1].returnTypeRef.coneType.isInt &&
|
||||
returnTypeRef.coneType.isUnit
|
||||
}
|
||||
}
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.parcelize.fir.diagnostics
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirPropertyChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.declarations.FirProperty
|
||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.declarations.hasJvmFieldAnnotation
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.fromPrimaryConstructor
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.hasBackingField
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isCompanion
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
||||
import org.jetbrains.kotlin.fir.expressions.classId
|
||||
import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinErrorType
|
||||
import org.jetbrains.kotlin.fir.types.classId
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.parcelize.IGNORED_ON_PARCEL_CLASS_IDS
|
||||
import org.jetbrains.kotlin.parcelize.PARCELER_CLASS_ID
|
||||
|
||||
object FirParcelizePropertyChecker : FirPropertyChecker() {
|
||||
private val CREATOR_NAME = Name.identifier("CREATOR")
|
||||
|
||||
override fun check(declaration: FirProperty, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val containingClassSymbol = declaration.dispatchReceiverType?.toRegularClassSymbol(context.session) ?: return
|
||||
|
||||
if (containingClassSymbol.isParcelize(context.session)) {
|
||||
val fromPrimaryConstructor = declaration.fromPrimaryConstructor ?: false
|
||||
if (
|
||||
!fromPrimaryConstructor &&
|
||||
(declaration.hasBackingField || declaration.delegate != null) &&
|
||||
!declaration.hasIgnoredOnParcel()
|
||||
) {
|
||||
reporter.reportOn(declaration.source, KtErrorsParcelize.PROPERTY_WONT_BE_SERIALIZED, context)
|
||||
}
|
||||
if (fromPrimaryConstructor) {
|
||||
checkParcelableClassProperty(declaration, containingClassSymbol, context, reporter)
|
||||
checkIgnoredOnParcelUsage(declaration, context, reporter)
|
||||
}
|
||||
}
|
||||
|
||||
if (declaration.name == CREATOR_NAME && containingClassSymbol.isCompanion && declaration.hasJvmFieldAnnotation) {
|
||||
val outerClass = context.containingDeclarations.asReversed().getOrNull(1) as? FirRegularClass
|
||||
if (outerClass != null && outerClass.symbol.isParcelize(context.session)) {
|
||||
reporter.reportOn(declaration.source, KtErrorsParcelize.CREATOR_DEFINITION_IS_NOT_ALLOWED, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkIgnoredOnParcelUsage(property: FirProperty, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val illegalAnnotation = property.annotations.firstOrNull { it.classId in IGNORED_ON_PARCEL_CLASS_IDS } ?: return
|
||||
reporter.reportOn(illegalAnnotation.source, KtErrorsParcelize.INAPPLICABLE_IGNORED_ON_PARCEL_CONSTRUCTOR_PROPERTY, context)
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
private fun checkParcelableClassProperty(
|
||||
property: FirProperty,
|
||||
containingClassSymbol: FirRegularClassSymbol,
|
||||
context: CheckerContext,
|
||||
reporter: DiagnosticReporter
|
||||
) {
|
||||
val type = property.returnTypeRef.coneType
|
||||
if (type is ConeKotlinErrorType || containingClassSymbol.hasCustomParceler(context.session)) return
|
||||
/*
|
||||
* TODO: abstract code from ParcelSerializer or IrParcelSerializerFactory to avoid duplication
|
||||
* of allowed types checking
|
||||
*/
|
||||
}
|
||||
|
||||
private fun FirProperty.hasIgnoredOnParcel(): Boolean {
|
||||
return annotations.hasIgnoredOnParcel() || (getter?.annotations?.hasIgnoredOnParcel() ?: false)
|
||||
}
|
||||
|
||||
|
||||
private fun List<FirAnnotation>.hasIgnoredOnParcel(): Boolean {
|
||||
return this.any {
|
||||
if (it.annotationTypeRef.coneType.classId !in IGNORED_ON_PARCEL_CLASS_IDS) return@any false
|
||||
val target = it.useSiteTarget
|
||||
target == null || target == AnnotationUseSiteTarget.PROPERTY || target == AnnotationUseSiteTarget.PROPERTY_GETTER
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirRegularClassSymbol.hasCustomParceler(session: FirSession): Boolean {
|
||||
val companionObjectSymbol = this.companionObjectSymbol ?: return false
|
||||
return lookupSuperTypes(companionObjectSymbol, lookupInterfaces = true, deep = true, session).any {
|
||||
it.classId == PARCELER_CLASS_ID
|
||||
}
|
||||
}
|
||||
}
|
||||
+180
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.parcelize.fir.diagnostics
|
||||
|
||||
import org.jetbrains.kotlin.diagnostics.KtDiagnostic
|
||||
import org.jetbrains.kotlin.diagnostics.KtDiagnosticFactoryToRendererMap
|
||||
import org.jetbrains.kotlin.diagnostics.KtDiagnosticRenderer
|
||||
import org.jetbrains.kotlin.diagnostics.rendering.Renderers.RENDER_CLASS_OR_OBJECT
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.RENDER_TYPE
|
||||
import org.jetbrains.kotlin.parcelize.fir.diagnostics.KtErrorsParcelize.CLASS_SHOULD_BE_PARCELIZE
|
||||
import org.jetbrains.kotlin.parcelize.fir.diagnostics.KtErrorsParcelize.CREATOR_DEFINITION_IS_NOT_ALLOWED
|
||||
import org.jetbrains.kotlin.parcelize.fir.diagnostics.KtErrorsParcelize.DEPRECATED_ANNOTATION
|
||||
import org.jetbrains.kotlin.parcelize.fir.diagnostics.KtErrorsParcelize.DEPRECATED_PARCELER
|
||||
import org.jetbrains.kotlin.parcelize.fir.diagnostics.KtErrorsParcelize.DUPLICATING_TYPE_PARCELERS
|
||||
import org.jetbrains.kotlin.parcelize.fir.diagnostics.KtErrorsParcelize.FORBIDDEN_DEPRECATED_ANNOTATION
|
||||
import org.jetbrains.kotlin.parcelize.fir.diagnostics.KtErrorsParcelize.INAPPLICABLE_IGNORED_ON_PARCEL
|
||||
import org.jetbrains.kotlin.parcelize.fir.diagnostics.KtErrorsParcelize.INAPPLICABLE_IGNORED_ON_PARCEL_CONSTRUCTOR_PROPERTY
|
||||
import org.jetbrains.kotlin.parcelize.fir.diagnostics.KtErrorsParcelize.NO_PARCELABLE_SUPERTYPE
|
||||
import org.jetbrains.kotlin.parcelize.fir.diagnostics.KtErrorsParcelize.OVERRIDING_WRITE_TO_PARCEL_IS_NOT_ALLOWED
|
||||
import org.jetbrains.kotlin.parcelize.fir.diagnostics.KtErrorsParcelize.PARCELABLE_CANT_BE_INNER_CLASS
|
||||
import org.jetbrains.kotlin.parcelize.fir.diagnostics.KtErrorsParcelize.PARCELABLE_CANT_BE_LOCAL_CLASS
|
||||
import org.jetbrains.kotlin.parcelize.fir.diagnostics.KtErrorsParcelize.PARCELABLE_CONSTRUCTOR_PARAMETER_SHOULD_BE_VAL_OR_VAR
|
||||
import org.jetbrains.kotlin.parcelize.fir.diagnostics.KtErrorsParcelize.PARCELABLE_DELEGATE_IS_NOT_ALLOWED
|
||||
import org.jetbrains.kotlin.parcelize.fir.diagnostics.KtErrorsParcelize.PARCELABLE_PRIMARY_CONSTRUCTOR_IS_EMPTY
|
||||
import org.jetbrains.kotlin.parcelize.fir.diagnostics.KtErrorsParcelize.PARCELABLE_SHOULD_BE_CLASS
|
||||
import org.jetbrains.kotlin.parcelize.fir.diagnostics.KtErrorsParcelize.PARCELABLE_SHOULD_BE_INSTANTIABLE
|
||||
import org.jetbrains.kotlin.parcelize.fir.diagnostics.KtErrorsParcelize.PARCELABLE_SHOULD_HAVE_PRIMARY_CONSTRUCTOR
|
||||
import org.jetbrains.kotlin.parcelize.fir.diagnostics.KtErrorsParcelize.PARCELABLE_SHOULD_NOT_BE_ENUM_CLASS
|
||||
import org.jetbrains.kotlin.parcelize.fir.diagnostics.KtErrorsParcelize.PARCELABLE_TYPE_NOT_SUPPORTED
|
||||
import org.jetbrains.kotlin.parcelize.fir.diagnostics.KtErrorsParcelize.PARCELER_SHOULD_BE_OBJECT
|
||||
import org.jetbrains.kotlin.parcelize.fir.diagnostics.KtErrorsParcelize.PARCELER_TYPE_INCOMPATIBLE
|
||||
import org.jetbrains.kotlin.parcelize.fir.diagnostics.KtErrorsParcelize.PROPERTY_WONT_BE_SERIALIZED
|
||||
import org.jetbrains.kotlin.parcelize.fir.diagnostics.KtErrorsParcelize.REDUNDANT_TYPE_PARCELER
|
||||
|
||||
object KtDefaultErrorMessagesParcelize {
|
||||
fun getRendererForDiagnostic(diagnostic: KtDiagnostic): KtDiagnosticRenderer {
|
||||
val factory = diagnostic.factory
|
||||
return MAP[factory] ?: factory.ktRenderer
|
||||
}
|
||||
|
||||
val MAP = KtDiagnosticFactoryToRendererMap("Parcelize").also { map ->
|
||||
map.put(
|
||||
PARCELABLE_SHOULD_BE_CLASS,
|
||||
"'Parcelable' should be a class"
|
||||
)
|
||||
|
||||
map.put(
|
||||
PARCELABLE_DELEGATE_IS_NOT_ALLOWED,
|
||||
"Delegating 'Parcelable' is not allowed"
|
||||
)
|
||||
|
||||
map.put(
|
||||
PARCELABLE_SHOULD_NOT_BE_ENUM_CLASS,
|
||||
"'Parcelable' should not be a 'enum class'"
|
||||
)
|
||||
|
||||
map.put(
|
||||
PARCELABLE_SHOULD_BE_INSTANTIABLE,
|
||||
"'Parcelable' should not be an 'abstract' class"
|
||||
)
|
||||
|
||||
map.put(
|
||||
PARCELABLE_CANT_BE_INNER_CLASS,
|
||||
"'Parcelable' can't be an inner class"
|
||||
)
|
||||
|
||||
map.put(
|
||||
PARCELABLE_CANT_BE_LOCAL_CLASS,
|
||||
"'Parcelable' can't be a local class"
|
||||
)
|
||||
|
||||
map.put(
|
||||
NO_PARCELABLE_SUPERTYPE,
|
||||
"No 'Parcelable' supertype"
|
||||
)
|
||||
|
||||
map.put(
|
||||
PARCELABLE_SHOULD_HAVE_PRIMARY_CONSTRUCTOR,
|
||||
"'Parcelable' should have a primary constructor"
|
||||
)
|
||||
|
||||
map.put(
|
||||
PARCELABLE_PRIMARY_CONSTRUCTOR_IS_EMPTY,
|
||||
"The primary constructor is empty, no data will be serialized to 'Parcel'"
|
||||
)
|
||||
|
||||
map.put(
|
||||
PARCELABLE_CONSTRUCTOR_PARAMETER_SHOULD_BE_VAL_OR_VAR,
|
||||
"'Parcelable' constructor parameter should be 'val' or 'var'"
|
||||
)
|
||||
|
||||
map.put(
|
||||
PROPERTY_WONT_BE_SERIALIZED,
|
||||
"Property would not be serialized into a 'Parcel'. Add '@IgnoredOnParcel' annotation to remove the warning"
|
||||
)
|
||||
|
||||
map.put(
|
||||
OVERRIDING_WRITE_TO_PARCEL_IS_NOT_ALLOWED,
|
||||
"Overriding 'writeToParcel' is not allowed. Use 'Parceler' companion object instead"
|
||||
)
|
||||
|
||||
map.put(
|
||||
CREATOR_DEFINITION_IS_NOT_ALLOWED,
|
||||
"'CREATOR' definition is not allowed. Use 'Parceler' companion object instead"
|
||||
)
|
||||
|
||||
map.put(
|
||||
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.put(
|
||||
PARCELER_SHOULD_BE_OBJECT,
|
||||
"Parceler should be an object"
|
||||
)
|
||||
|
||||
map.put(
|
||||
PARCELER_TYPE_INCOMPATIBLE,
|
||||
"Parceler type {0} is incompatible with {1}",
|
||||
RENDER_TYPE, RENDER_TYPE
|
||||
)
|
||||
|
||||
map.put(
|
||||
DUPLICATING_TYPE_PARCELERS,
|
||||
"Duplicating ''TypeParceler'' annotations"
|
||||
)
|
||||
|
||||
map.put(
|
||||
REDUNDANT_TYPE_PARCELER,
|
||||
"This ''TypeParceler'' is already provided for {0}",
|
||||
RENDER_CLASS_OR_OBJECT
|
||||
)
|
||||
|
||||
map.put(
|
||||
CLASS_SHOULD_BE_PARCELIZE,
|
||||
"{0} should be annotated with ''@Parcelize''",
|
||||
RENDER_CLASS_OR_OBJECT
|
||||
)
|
||||
|
||||
map.put(
|
||||
INAPPLICABLE_IGNORED_ON_PARCEL,
|
||||
"'@IgnoredOnParcel' is only applicable to class properties"
|
||||
)
|
||||
|
||||
map.put(
|
||||
INAPPLICABLE_IGNORED_ON_PARCEL_CONSTRUCTOR_PROPERTY,
|
||||
"'@IgnoredOnParcel' is inapplicable to properties declared in the primary constructor"
|
||||
)
|
||||
|
||||
map.put(
|
||||
FORBIDDEN_DEPRECATED_ANNOTATION,
|
||||
"Parceler-related annotations from package 'kotlinx.android.parcel' are forbidden. Change package to 'kotlinx.parcelize'"
|
||||
)
|
||||
|
||||
map.put(
|
||||
DEPRECATED_ANNOTATION,
|
||||
"Parcelize annotations from package 'kotlinx.android.parcel' are deprecated. Change package to 'kotlinx.parcelize'"
|
||||
)
|
||||
|
||||
map.put(
|
||||
DEPRECATED_PARCELER,
|
||||
"'kotlinx.android.parcel.Parceler' is deprecated. Use 'kotlinx.parcelize.Parceler' instead"
|
||||
)
|
||||
}
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.kotlin.parcelize.fir.diagnostics
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.diagnostics.*
|
||||
import org.jetbrains.kotlin.diagnostics.SourceElementPositioningStrategies.ABSTRACT_MODIFIER
|
||||
import org.jetbrains.kotlin.diagnostics.SourceElementPositioningStrategies.DELEGATED_SUPERTYPE_BY_KEYWORD
|
||||
import org.jetbrains.kotlin.diagnostics.SourceElementPositioningStrategies.INNER_MODIFIER
|
||||
import org.jetbrains.kotlin.diagnostics.SourceElementPositioningStrategies.NAME_IDENTIFIER
|
||||
import org.jetbrains.kotlin.diagnostics.SourceElementPositioningStrategies.OVERRIDE_MODIFIER
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
|
||||
object KtErrorsParcelize {
|
||||
val PARCELABLE_SHOULD_BE_CLASS by error0<PsiElement>(NAME_IDENTIFIER)
|
||||
val PARCELABLE_DELEGATE_IS_NOT_ALLOWED by error0<PsiElement>(DELEGATED_SUPERTYPE_BY_KEYWORD)
|
||||
val PARCELABLE_SHOULD_NOT_BE_ENUM_CLASS by error0<PsiElement>()
|
||||
val PARCELABLE_SHOULD_BE_INSTANTIABLE by error0<PsiElement>(ABSTRACT_MODIFIER)
|
||||
val PARCELABLE_CANT_BE_INNER_CLASS by error0<PsiElement>(INNER_MODIFIER)
|
||||
val PARCELABLE_CANT_BE_LOCAL_CLASS by error0<PsiElement>(NAME_IDENTIFIER)
|
||||
val NO_PARCELABLE_SUPERTYPE by error0<PsiElement>(NAME_IDENTIFIER)
|
||||
val PARCELABLE_SHOULD_HAVE_PRIMARY_CONSTRUCTOR by error0<PsiElement>(NAME_IDENTIFIER)
|
||||
val PARCELABLE_PRIMARY_CONSTRUCTOR_IS_EMPTY by warning0<PsiElement>(NAME_IDENTIFIER)
|
||||
val PARCELABLE_CONSTRUCTOR_PARAMETER_SHOULD_BE_VAL_OR_VAR by error0<PsiElement>(NAME_IDENTIFIER)
|
||||
val PROPERTY_WONT_BE_SERIALIZED by warning0<PsiElement>(NAME_IDENTIFIER)
|
||||
val OVERRIDING_WRITE_TO_PARCEL_IS_NOT_ALLOWED by error0<PsiElement>(OVERRIDE_MODIFIER)
|
||||
val CREATOR_DEFINITION_IS_NOT_ALLOWED by error0<PsiElement>(NAME_IDENTIFIER)
|
||||
val PARCELABLE_TYPE_NOT_SUPPORTED by error0<PsiElement>()
|
||||
val PARCELER_SHOULD_BE_OBJECT by error0<PsiElement>()
|
||||
val PARCELER_TYPE_INCOMPATIBLE by error2<PsiElement, ConeKotlinType, ConeKotlinType>()
|
||||
val DUPLICATING_TYPE_PARCELERS by error0<PsiElement>()
|
||||
val REDUNDANT_TYPE_PARCELER by warning1<PsiElement, KtClassOrObject>()
|
||||
val CLASS_SHOULD_BE_PARCELIZE by error1<PsiElement, KtClassOrObject>()
|
||||
val FORBIDDEN_DEPRECATED_ANNOTATION by error0<PsiElement>()
|
||||
val DEPRECATED_ANNOTATION by warning0<PsiElement>()
|
||||
val DEPRECATED_PARCELER by error0<PsiElement>()
|
||||
val INAPPLICABLE_IGNORED_ON_PARCEL by warning0<PsiElement>()
|
||||
val INAPPLICABLE_IGNORED_ON_PARCEL_CONSTRUCTOR_PROPERTY by warning0<PsiElement>()
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// WITH_STDLIB
|
||||
package test
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// WITH_STDLIB
|
||||
package test
|
||||
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
// WITH_STDLIB
|
||||
package test
|
||||
|
||||
import kotlinx.parcelize.*
|
||||
import android.os.*
|
||||
|
||||
object StringParceler : Parceler<String> {
|
||||
override fun create(parcel: Parcel) = TODO()
|
||||
override fun String.write(parcel: Parcel, flags: Int) = TODO()
|
||||
}
|
||||
|
||||
object CharSequenceParceler : Parceler<CharSequence> {
|
||||
override fun create(parcel: Parcel) = TODO()
|
||||
override fun CharSequence.write(parcel: Parcel, flags: Int) = TODO()
|
||||
}
|
||||
|
||||
class StringClassParceler : Parceler<String> {
|
||||
override fun create(parcel: Parcel) = TODO()
|
||||
override fun String.write(parcel: Parcel, flags: Int) = TODO()
|
||||
}
|
||||
|
||||
@<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER, NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>TypeParceler<!><String, StringParceler>
|
||||
class MissingParcelizeAnnotation(val a: @<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>WriteWith<!><StringParceler> String)
|
||||
|
||||
@Parcelize
|
||||
@<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER, NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>TypeParceler<!><String, StringClassParceler>
|
||||
class ShouldBeClass(val a: @<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>WriteWith<!><StringClassParceler> String) : Parcelable
|
||||
|
||||
@Parcelize
|
||||
class Test(
|
||||
val a: @<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>WriteWith<!><StringParceler> Int,
|
||||
val b: @<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>WriteWith<!><StringParceler> String,
|
||||
val c: @<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>WriteWith<!><StringParceler> CharSequence,
|
||||
val d: @<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>WriteWith<!><CharSequenceParceler> String,
|
||||
val e: @<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>WriteWith<!><CharSequenceParceler> CharSequence
|
||||
) : Parcelable
|
||||
|
||||
@Parcelize
|
||||
@<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER, NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>TypeParceler<!><String, StringParceler>
|
||||
class Test2(@<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER, NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER, NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER, NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>TypeParceler<!><String, StringParceler> val a: String) : Parcelable
|
||||
|
||||
@Parcelize
|
||||
@<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER, NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>TypeParceler<!><String, StringParceler>
|
||||
@<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER, NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>TypeParceler<!><String, CharSequenceParceler>
|
||||
class Test3(val a: String) : Parcelable
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
package test
|
||||
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
package test
|
||||
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
// WITH_STDLIB
|
||||
package test
|
||||
|
||||
import kotlinx.android.parcel.*
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
|
||||
object <!DEPRECATED_PARCELER!>Parceler1<!> : Parceler<String> {
|
||||
override fun create(parcel: Parcel) = parcel.readInt().toString()
|
||||
|
||||
override fun String.write(parcel: Parcel, flags: Int) {
|
||||
parcel.writeInt(length)
|
||||
}
|
||||
}
|
||||
|
||||
object <!DEPRECATED_PARCELER!>Parceler2<!> : Parceler<List<String>> {
|
||||
override fun create(parcel: Parcel) = listOf(parcel.readString()!!)
|
||||
|
||||
override fun List<String>.write(parcel: Parcel, flags: Int) {
|
||||
parcel.writeString(this.joinToString(","))
|
||||
}
|
||||
}
|
||||
|
||||
<!DEPRECATED_ANNOTATION!>@Parcelize<!>
|
||||
<!FORBIDDEN_DEPRECATED_ANNOTATION!>@<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER, NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>TypeParceler<!><String, Parceler2><!>
|
||||
data class Test(
|
||||
val a: String,
|
||||
val b: <!FORBIDDEN_DEPRECATED_ANNOTATION!>@<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>WriteWith<!><Parceler1><!> String,
|
||||
val c: <!FORBIDDEN_DEPRECATED_ANNOTATION!>@<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>WriteWith<!><Parceler2><!> List<<!FORBIDDEN_DEPRECATED_ANNOTATION!>@<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>WriteWith<!><Parceler1><!> String>
|
||||
) : Parcelable {
|
||||
<!DEPRECATED_ANNOTATION!>@IgnoredOnParcel<!>
|
||||
val x by lazy { "foo" }
|
||||
}
|
||||
|
||||
interface <!DEPRECATED_PARCELER!>ParcelerForUser<!>: Parceler<User>
|
||||
|
||||
<!DEPRECATED_ANNOTATION!>@Parcelize<!>
|
||||
class User(val name: String) : Parcelable {
|
||||
private companion object : ParcelerForUser {
|
||||
override fun User.write(parcel: Parcel, flags: Int) {
|
||||
parcel.writeString(name)
|
||||
}
|
||||
|
||||
override fun create(parcel: Parcel) = User(parcel.readString()!!)
|
||||
}
|
||||
}
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
package test
|
||||
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package test
|
||||
|
||||
import kotlinx.parcelize.*
|
||||
import android.os.*
|
||||
|
||||
class Box(val value: String)
|
||||
|
||||
@Parcelize
|
||||
class Foo(val box: Box): Parcelable {
|
||||
companion object : Parceler<Foo> {
|
||||
override fun create(parcel: Parcel) = Foo(Box(parcel.readString()))
|
||||
|
||||
override fun Foo.write(parcel: Parcel, flags: Int) {
|
||||
parcel.writeString(box.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Parcelize
|
||||
class Foo2(val box: Box): Parcelable
|
||||
@@ -0,0 +1,31 @@
|
||||
package test
|
||||
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import android.os.Parcelable
|
||||
|
||||
@Parcelize
|
||||
open class Open(val foo: String) : Parcelable
|
||||
|
||||
@Parcelize
|
||||
class Final(val foo: String) : Parcelable
|
||||
|
||||
@Parcelize
|
||||
<!PARCELABLE_SHOULD_BE_INSTANTIABLE!>abstract<!> class Abstract(val foo: String) : Parcelable
|
||||
|
||||
@Parcelize
|
||||
sealed class Sealed(val foo: String) : Parcelable {
|
||||
class X : Sealed("")
|
||||
}
|
||||
|
||||
class Outer {
|
||||
@Parcelize
|
||||
<!PARCELABLE_CANT_BE_INNER_CLASS!>inner<!> class Inner(val foo: String) : Parcelable
|
||||
}
|
||||
|
||||
fun foo() {
|
||||
@Parcelize
|
||||
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED, PARCELABLE_SHOULD_BE_CLASS!>object<!> : Parcelable {}
|
||||
|
||||
@Parcelize
|
||||
class <!NO_PARCELABLE_SUPERTYPE, PARCELABLE_CANT_BE_LOCAL_CLASS!>Local<!> {}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
package test
|
||||
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// WITH_STDLIB
|
||||
package test
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
package test
|
||||
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package test
|
||||
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import kotlinx.parcelize.RawValue
|
||||
import android.os.Parcelable
|
||||
|
||||
@Parcelize
|
||||
class User(
|
||||
val a: String,
|
||||
val b: Any,
|
||||
val c: Any?,
|
||||
val d: Map<Any, String>,
|
||||
val e: @RawValue Any?,
|
||||
val f: @RawValue Map<String, Any>,
|
||||
val g: Map<String, @RawValue Any>,
|
||||
val h: Map<@RawValue Any, List<@RawValue Any>>
|
||||
) : Parcelable
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
package test
|
||||
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
package test
|
||||
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.parcelize.test.runners;
|
||||
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import org.jetbrains.kotlin.test.TestMetadata;
|
||||
import org.jetbrains.kotlin.test.util.KtTestUtil;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/** This class is generated by {@link GenerateNewCompilerTests.kt}. DO NOT MODIFY MANUALLY */
|
||||
@SuppressWarnings("all")
|
||||
@TestMetadata("plugins/parcelize/parcelize-compiler/testData/diagnostics")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class FirParcelizeDiagnosticTestGenerated extends AbstractFirParcelizeDiagnosticTest {
|
||||
@Test
|
||||
public void testAllFilesPresentInDiagnostics() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/parcelize/parcelize-compiler/testData/diagnostics"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("constructors.kt")
|
||||
public void testConstructors() throws Exception {
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/diagnostics/constructors.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("customCreator.kt")
|
||||
public void testCustomCreator() throws Exception {
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/diagnostics/customCreator.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("customParcelers.kt")
|
||||
public void testCustomParcelers() throws Exception {
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/diagnostics/customParcelers.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("customWriteToParcel.kt")
|
||||
public void testCustomWriteToParcel() throws Exception {
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/diagnostics/customWriteToParcel.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("delegate.kt")
|
||||
public void testDelegate() throws Exception {
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/diagnostics/delegate.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("deprecatedAnnotations.kt")
|
||||
public void testDeprecatedAnnotations() throws Exception {
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/diagnostics/deprecatedAnnotations.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("emptyPrimaryConstructor.kt")
|
||||
public void testEmptyPrimaryConstructor() throws Exception {
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/diagnostics/emptyPrimaryConstructor.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt20062.kt")
|
||||
public void testKt20062() throws Exception {
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/diagnostics/kt20062.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("modality.kt")
|
||||
public void testModality() throws Exception {
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/diagnostics/modality.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("notMagicParcel.kt")
|
||||
public void testNotMagicParcel() throws Exception {
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/diagnostics/notMagicParcel.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("properties.kt")
|
||||
public void testProperties() throws Exception {
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/diagnostics/properties.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/diagnostics/simple.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("unsupportedType.kt")
|
||||
public void testUnsupportedType() throws Exception {
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/diagnostics/unsupportedType.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("withoutParcelableSupertype.kt")
|
||||
public void testWithoutParcelableSupertype() throws Exception {
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/diagnostics/withoutParcelableSupertype.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("wrongAnnotationTarget.kt")
|
||||
public void testWrongAnnotationTarget() throws Exception {
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/diagnostics/wrongAnnotationTarget.kt");
|
||||
}
|
||||
}
|
||||
+2
-3
@@ -6,9 +6,8 @@
|
||||
package org.jetbrains.kotlin.parcelize.test.runners;
|
||||
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import org.jetbrains.kotlin.test.util.KtTestUtil;
|
||||
import org.jetbrains.kotlin.test.TestMetadata;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.jetbrains.kotlin.test.util.KtTestUtil;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.File;
|
||||
@@ -21,7 +20,7 @@ import java.util.regex.Pattern;
|
||||
public class ParcelizeDiagnosticTestGenerated extends AbstractParcelizeDiagnosticTest {
|
||||
@Test
|
||||
public void testAllFilesPresentInDiagnostics() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/parcelize/parcelize-compiler/testData/diagnostics"), Pattern.compile("^(.+)\\.kt$"), null, true);
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/parcelize/parcelize-compiler/testData/diagnostics"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.parcelize.test.runners
|
||||
|
||||
import org.jetbrains.kotlin.parcelize.test.services.FirFacadeWithParcelizeExtension
|
||||
import org.jetbrains.kotlin.parcelize.test.services.ParcelizeEnvironmentConfigurator
|
||||
import org.jetbrains.kotlin.test.bind
|
||||
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
|
||||
import org.jetbrains.kotlin.test.directives.FirDiagnosticsDirectives
|
||||
import org.jetbrains.kotlin.test.frontend.fir.FirFailingTestSuppressor
|
||||
import org.jetbrains.kotlin.test.frontend.fir.handlers.FirIdenticalChecker
|
||||
import org.jetbrains.kotlin.test.runners.AbstractKotlinCompilerTest
|
||||
import org.jetbrains.kotlin.test.runners.baseFirDiagnosticTestConfiguration
|
||||
import org.jetbrains.kotlin.test.services.fir.FirOldFrontendMetaConfigurator
|
||||
|
||||
abstract class AbstractFirParcelizeDiagnosticTest : AbstractKotlinCompilerTest() {
|
||||
override fun TestConfigurationBuilder.configuration() {
|
||||
baseFirDiagnosticTestConfiguration(frontendFacade = FirFacadeWithParcelizeExtension)
|
||||
|
||||
defaultDirectives {
|
||||
+FirDiagnosticsDirectives.ENABLE_PLUGIN_PHASES
|
||||
}
|
||||
|
||||
useConfigurators(::ParcelizeEnvironmentConfigurator.bind(true))
|
||||
|
||||
useAfterAnalysisCheckers(
|
||||
::FirIdenticalChecker,
|
||||
::FirFailingTestSuppressor,
|
||||
)
|
||||
useMetaTestConfigurators(::FirOldFrontendMetaConfigurator)
|
||||
}
|
||||
}
|
||||
+2
-14
@@ -5,11 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.parcelize.test.runners
|
||||
|
||||
import org.jetbrains.kotlin.parcelize.fir.FirParcelizeExtensionRegistrar
|
||||
import org.jetbrains.kotlin.parcelize.test.services.ParcelizeEnvironmentConfigurator
|
||||
import org.jetbrains.kotlin.parcelize.test.services.ParcelizeMainClassProvider
|
||||
import org.jetbrains.kotlin.parcelize.test.services.ParcelizeRuntimeClasspathProvider
|
||||
import org.jetbrains.kotlin.parcelize.test.services.ParcelizeUtilSourcesProvider
|
||||
import org.jetbrains.kotlin.parcelize.test.services.*
|
||||
import org.jetbrains.kotlin.test.Constructor
|
||||
import org.jetbrains.kotlin.test.TargetBackend
|
||||
import org.jetbrains.kotlin.test.backend.BlackBoxCodegenSuppressor
|
||||
@@ -20,9 +16,6 @@ import org.jetbrains.kotlin.test.backend.ir.IrBackendInput
|
||||
import org.jetbrains.kotlin.test.backend.ir.JvmIrBackendFacade
|
||||
import org.jetbrains.kotlin.test.bind
|
||||
import org.jetbrains.kotlin.test.builders.*
|
||||
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
|
||||
import org.jetbrains.kotlin.test.builders.configureClassicFrontendHandlersStep
|
||||
import org.jetbrains.kotlin.test.builders.configureFirHandlersStep
|
||||
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.REQUIRES_SEPARATE_PROCESS
|
||||
import org.jetbrains.kotlin.test.directives.DiagnosticsDirectives.DIAGNOSTICS
|
||||
import org.jetbrains.kotlin.test.directives.DiagnosticsDirectives.REPORT_ONLY_EXPLICITLY_DEFINED_DEBUG_INFO
|
||||
@@ -33,7 +26,6 @@ import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontendFacade
|
||||
import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontendOutputArtifact
|
||||
import org.jetbrains.kotlin.test.frontend.classic.handlers.ClassicDiagnosticsHandler
|
||||
import org.jetbrains.kotlin.test.frontend.fir.Fir2IrResultsConverter
|
||||
import org.jetbrains.kotlin.test.frontend.fir.FirFrontendFacade
|
||||
import org.jetbrains.kotlin.test.frontend.fir.FirOutputArtifact
|
||||
import org.jetbrains.kotlin.test.frontend.fir.handlers.FirDiagnosticsHandler
|
||||
import org.jetbrains.kotlin.test.model.*
|
||||
@@ -124,11 +116,7 @@ open class AbstractParcelizeFirBoxTest : AbstractParcelizeBoxTestBase<FirOutputA
|
||||
TargetBackend.JVM_IR
|
||||
) {
|
||||
override val frontendFacade: Constructor<FrontendFacade<FirOutputArtifact>>
|
||||
get() = { testServices ->
|
||||
FirFrontendFacade(testServices) {
|
||||
it.registerExtensions(FirParcelizeExtensionRegistrar().configure())
|
||||
}
|
||||
}
|
||||
get() = FirFacadeWithParcelizeExtension
|
||||
|
||||
override val frontendToBackendConverter: Constructor<Frontend2BackendConverter<FirOutputArtifact, IrBackendInput>>
|
||||
get() = ::Fir2IrResultsConverter
|
||||
|
||||
+3
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.test.directives.DiagnosticsDirectives.DIAGNOSTICS
|
||||
import org.jetbrains.kotlin.test.directives.DiagnosticsDirectives.REPORT_JVM_DIAGNOSTICS_ON_FRONTEND
|
||||
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.USE_PSI_CLASS_FILES_READING
|
||||
import org.jetbrains.kotlin.test.frontend.classic.handlers.ClassicDiagnosticsHandler
|
||||
import org.jetbrains.kotlin.test.frontend.classic.handlers.FirTestDataConsistencyHandler
|
||||
import org.jetbrains.kotlin.test.model.DependencyKind
|
||||
import org.jetbrains.kotlin.test.model.FrontendKinds
|
||||
import org.jetbrains.kotlin.test.runners.AbstractKotlinCompilerTest
|
||||
@@ -48,5 +49,7 @@ abstract class AbstractParcelizeDiagnosticTest : AbstractKotlinCompilerTest() {
|
||||
classicFrontendHandlersStep {
|
||||
useHandlers(::ClassicDiagnosticsHandler)
|
||||
}
|
||||
|
||||
useAfterAnalysisCheckers(::FirTestDataConsistencyHandler)
|
||||
}
|
||||
}
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.parcelize.test.services
|
||||
|
||||
import org.jetbrains.kotlin.parcelize.fir.FirParcelizeExtensionRegistrar
|
||||
import org.jetbrains.kotlin.test.Constructor
|
||||
import org.jetbrains.kotlin.test.frontend.fir.FirFrontendFacade
|
||||
|
||||
val FirFacadeWithParcelizeExtension: Constructor<FirFrontendFacade> = { testServices ->
|
||||
FirFrontendFacade(testServices) {
|
||||
it.registerExtensions(FirParcelizeExtensionRegistrar().configure())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user