diff --git a/plugins/lombok/lombok.k1/src/org/jetbrains/kotlin/lombok/processor/BuilderProcessor.kt b/plugins/lombok/lombok.k1/src/org/jetbrains/kotlin/lombok/processor/BuilderProcessor.kt index 4720c7bc416..a02b21882cf 100644 --- a/plugins/lombok/lombok.k1/src/org/jetbrains/kotlin/lombok/processor/BuilderProcessor.kt +++ b/plugins/lombok/lombok.k1/src/org/jetbrains/kotlin/lombok/processor/BuilderProcessor.kt @@ -152,7 +152,7 @@ class BuilderProcessor(private val config: LombokConfig) : Processor { when (typeName) { in LombokNames.SUPPORTED_COLLECTIONS -> { - val parameterType = field.parameterType(0, singular.allowNull) ?: return + val parameterType = field.parameterType(0) ?: return valueParameters = listOf( LombokValueParameter(nameInSingularForm, parameterType) ) @@ -163,28 +163,27 @@ class BuilderProcessor(private val config: LombokConfig) : Processor { else -> builtIns.collection.defaultType } - addMultipleParameterType = baseType.replace( - newArguments = listOf(TypeProjectionImpl(parameterType)) - ) + addMultipleParameterType = baseType.withProperNullability(singular.allowNull) + .replace(newArguments = listOf(TypeProjectionImpl(parameterType)),) } in LombokNames.SUPPORTED_MAPS -> { - val keyType = field.parameterType(0, singular.allowNull) ?: return - val valueType = field.parameterType(1, singular.allowNull) ?: return + val keyType = field.parameterType(0) ?: return + val valueType = field.parameterType(1) ?: return valueParameters = listOf( LombokValueParameter(Name.identifier("key"), keyType), LombokValueParameter(Name.identifier("value"), valueType), ) - addMultipleParameterType = field.module.builtIns.map.defaultType.replace( - newArguments = listOf(TypeProjectionImpl(keyType), TypeProjectionImpl(valueType)) - ) + addMultipleParameterType = field.module.builtIns.map.defaultType + .withProperNullability(singular.allowNull) + .replace(newArguments = listOf(TypeProjectionImpl(keyType), TypeProjectionImpl(valueType))) } in LombokNames.SUPPORTED_TABLES -> { - val rowKeyType = field.parameterType(0, singular.allowNull) ?: return - val columnKeyType = field.parameterType(1, singular.allowNull) ?: return - val valueType = field.parameterType(2, singular.allowNull) ?: return + val rowKeyType = field.parameterType(0) ?: return + val columnKeyType = field.parameterType(1) ?: return + val valueType = field.parameterType(2) ?: return val tableDescriptor = field.module.resolveClassByFqName(LombokNames.TABLE, NoLookupLocation.FROM_SYNTHETIC_SCOPE) ?: return @@ -194,13 +193,15 @@ class BuilderProcessor(private val config: LombokConfig) : Processor { LombokValueParameter(Name.identifier("value"), valueType), ) - addMultipleParameterType = tableDescriptor.defaultType.replace( - newArguments = listOf( - TypeProjectionImpl(rowKeyType), - TypeProjectionImpl(columnKeyType), - TypeProjectionImpl(valueType), + addMultipleParameterType = tableDescriptor.defaultType + .withProperNullability(singular.allowNull) + .replace( + newArguments = listOf( + TypeProjectionImpl(rowKeyType), + TypeProjectionImpl(columnKeyType), + TypeProjectionImpl(valueType), + ) ) - ) } else -> return @@ -242,17 +243,20 @@ class BuilderProcessor(private val config: LombokConfig) : Processor { private class BuilderData(val builder: Builder, val constructingClass: ClassDescriptor) - private fun PropertyDescriptor.parameterType(index: Int, allowNull: Boolean): KotlinType? { + private fun PropertyDescriptor.parameterType(index: Int): KotlinType? { val type = returnType?.arguments?.getOrNull(index)?.type ?: return null - val typeWithProperNullability = if (allowNull) type.makeNullable() else type.makeNotNullable() - return typeWithProperNullability.replaceAnnotations( + return type.replaceAnnotations( CompositeAnnotations( - typeWithProperNullability.annotations, + type.annotations, ENHANCED_NULLABILITY_ANNOTATIONS ) ) } + private fun KotlinType.withProperNullability(allowNull: Boolean): KotlinType { + return if (allowNull) makeNullable() else makeNotNullable() + } + private fun Name.toMethodName(builder: Builder): Name { val prefix = builder.setterPrefix return if (prefix.isNullOrBlank()) { diff --git a/plugins/lombok/lombok.k2/src/org/jetbrains/kotlin/lombok/k2/generators/BuilderGenerator.kt b/plugins/lombok/lombok.k2/src/org/jetbrains/kotlin/lombok/k2/generators/BuilderGenerator.kt index be2975f554e..4aca6836a41 100644 --- a/plugins/lombok/lombok.k2/src/org/jetbrains/kotlin/lombok/k2/generators/BuilderGenerator.kt +++ b/plugins/lombok/lombok.k2/src/org/jetbrains/kotlin/lombok/k2/generators/BuilderGenerator.kt @@ -36,7 +36,6 @@ import org.jetbrains.kotlin.fir.types.jvm.FirJavaTypeRef import org.jetbrains.kotlin.load.java.structure.JavaClass import org.jetbrains.kotlin.load.java.structure.JavaClassifierType import org.jetbrains.kotlin.load.java.structure.JavaType -import org.jetbrains.kotlin.lombok.config.LombokConfig import org.jetbrains.kotlin.lombok.k2.* import org.jetbrains.kotlin.lombok.k2.config.ConeLombokAnnotations.Builder import org.jetbrains.kotlin.lombok.k2.config.ConeLombokAnnotations.Singular @@ -189,7 +188,7 @@ class BuilderGenerator(session: FirSession) : FirDeclarationGenerationExtension( when (typeName) { in LombokNames.SUPPORTED_COLLECTIONS -> { - val parameterType = javaClassifierType.parameterType(0, singular.allowNull) ?: return + val parameterType = javaClassifierType.parameterType(0) ?: return valueParameters = listOf( ConeLombokValueParameter(nameInSingularForm, parameterType.toRef()) ) @@ -199,24 +198,28 @@ class BuilderGenerator(session: FirSession) : FirDeclarationGenerationExtension( else -> JavaClasses.Collection } - addMultipleParameterType = DummyJavaClassType(baseType, typeArguments = listOf(parameterType)).toRef() + addMultipleParameterType = DummyJavaClassType(baseType, typeArguments = listOf(parameterType)) + .withProperNullability(singular.allowNull) + .toRef() } in LombokNames.SUPPORTED_MAPS -> { - val keyType = javaClassifierType.parameterType(0, singular.allowNull) ?: return - val valueType = javaClassifierType.parameterType(1, singular.allowNull) ?: return + val keyType = javaClassifierType.parameterType(0) ?: return + val valueType = javaClassifierType.parameterType(1) ?: return valueParameters = listOf( ConeLombokValueParameter(Name.identifier("key"), keyType.toRef()), ConeLombokValueParameter(Name.identifier("value"), valueType.toRef()), ) - addMultipleParameterType = DummyJavaClassType(JavaClasses.Map, typeArguments = listOf(keyType, valueType)).toRef() + addMultipleParameterType = DummyJavaClassType(JavaClasses.Map, typeArguments = listOf(keyType, valueType)) + .withProperNullability(singular.allowNull) + .toRef() } in LombokNames.SUPPORTED_TABLES -> { - val rowKeyType = javaClassifierType.parameterType(0, singular.allowNull) ?: return - val columnKeyType = javaClassifierType.parameterType(1, singular.allowNull) ?: return - val valueType = javaClassifierType.parameterType(2, singular.allowNull) ?: return + val rowKeyType = javaClassifierType.parameterType(0) ?: return + val columnKeyType = javaClassifierType.parameterType(1) ?: return + val valueType = javaClassifierType.parameterType(2) ?: return valueParameters = listOf( ConeLombokValueParameter(Name.identifier("rowKey"), rowKeyType.toRef()), @@ -227,7 +230,7 @@ class BuilderGenerator(session: FirSession) : FirDeclarationGenerationExtension( addMultipleParameterType = DummyJavaClassType( JavaClasses.Table, typeArguments = listOf(rowKeyType, columnKeyType, valueType) - ).toRef() + ).withProperNullability(singular.allowNull).toRef() } else -> return @@ -273,9 +276,12 @@ class BuilderGenerator(session: FirSession) : FirDeclarationGenerationExtension( private val String.singularForm: String? get() = StringUtil.unpluralize(this) - private fun JavaClassifierType.parameterType(index: Int, allowNull: Boolean): JavaType? { - val type = typeArguments.getOrNull(index) ?: return null - return if (allowNull) type.makeNullable() else type.makeNotNullable() + private fun JavaClassifierType.parameterType(index: Int): JavaType? { + return typeArguments.getOrNull(index) + } + + private fun JavaType.withProperNullability(allowNull: Boolean): JavaType { + return if (allowNull) makeNullable() else makeNotNullable() } } diff --git a/plugins/lombok/testData/diagnostics/builderSingularNullability.kt b/plugins/lombok/testData/diagnostics/builderSingularNullability.kt index c9dde278d32..9796c739204 100644 --- a/plugins/lombok/testData/diagnostics/builderSingularNullability.kt +++ b/plugins/lombok/testData/diagnostics/builderSingularNullability.kt @@ -10,6 +10,7 @@ import lombok.Singular; @Data public class User { @Singular private java.util.List names; + @Singular private java.util.Map pairs; } // FILE: UserWithoutNull.java @@ -21,6 +22,7 @@ import lombok.Singular; @Data public class UserWithoutNull { @Singular(ignoreNullCollections = false) private java.util.List names; + @Singular(ignoreNullCollections = false) private java.util.Map pairs; } // FILE: UserWithNull.java @@ -32,19 +34,54 @@ import lombok.Singular; @Data public class UserWithNull { @Singular(ignoreNullCollections = true) private java.util.List names; + @Singular(ignoreNullCollections = true) private java.util.Map pairs; } // FILE: test.kt -fun test() { +fun test_1() { User.builder() .name("User") - .name(null) // error + .name(null) + .names(listOf("other")) + .names(listOf(null)) + .names(null) + .pair(null, 1) + .pair(1, null) + .pairs(mapOf(1 to 1)) + .pairs(mapOf(null to 1)) + .pairs(mapOf(1 to null)) + .pairs(mapOf(null to null)) + .pairs(null) +} +fun test_2() { UserWithoutNull.builder() .name("User") - .name(null) // error + .name(null) + .names(listOf("other")) + .names(listOf(null)) + .names(null) + .pair(null, 1) + .pair(1, null) + .pairs(mapOf(1 to 1)) + .pairs(mapOf(null to 1)) + .pairs(mapOf(1 to null)) + .pairs(mapOf(null to null)) + .pairs(null) +} +fun test_3() { UserWithNull.builder() .name("User") - .name(null) // ok + .name(null) + .names(listOf("other")) + .names(listOf(null)) + .names(null) + .pair(null, 1) + .pair(1, null) + .pairs(mapOf(1 to 1)) + .pairs(mapOf(null to 1)) + .pairs(mapOf(1 to null)) + .pairs(mapOf(null to null)) + .pairs(null) } diff --git a/plugins/lombok/testData/diagnostics/builderSingularNullability.txt b/plugins/lombok/testData/diagnostics/builderSingularNullability.txt index e439d025d85..3974d114583 100644 --- a/plugins/lombok/testData/diagnostics/builderSingularNullability.txt +++ b/plugins/lombok/testData/diagnostics/builderSingularNullability.txt @@ -1,15 +1,20 @@ package public fun assertEquals(/*0*/ a: T, /*1*/ b: T): kotlin.Unit -public fun test(): kotlin.Unit +public fun test_1(): kotlin.Unit +public fun test_2(): kotlin.Unit +public fun test_3(): kotlin.Unit @lombok.Builder @lombok.Data public open class User { public constructor User() @lombok.Singular private final var names: kotlin.collections.(Mutable)List! + @lombok.Singular private final var pairs: kotlin.collections.(Mutable)Map! public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open /*synthesized*/ fun getNames(): kotlin.collections.(Mutable)List! + public open /*synthesized*/ fun getPairs(): kotlin.collections.(Mutable)Map! public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open /*synthesized*/ fun setNames(/*0*/ names: kotlin.collections.(Mutable)List!): kotlin.Unit + public open /*synthesized*/ fun setPairs(/*0*/ pairs: kotlin.collections.(Mutable)Map!): kotlin.Unit public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String // Static members @@ -19,10 +24,13 @@ public fun test(): kotlin.Unit @lombok.Builder @lombok.Data public open class UserWithNull { public constructor UserWithNull() @lombok.Singular(ignoreNullCollections = true) private final var names: kotlin.collections.(Mutable)List! + @lombok.Singular(ignoreNullCollections = true) private final var pairs: kotlin.collections.(Mutable)Map! public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open /*synthesized*/ fun getNames(): kotlin.collections.(Mutable)List! + public open /*synthesized*/ fun getPairs(): kotlin.collections.(Mutable)Map! public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open /*synthesized*/ fun setNames(/*0*/ names: kotlin.collections.(Mutable)List!): kotlin.Unit + public open /*synthesized*/ fun setPairs(/*0*/ pairs: kotlin.collections.(Mutable)Map!): kotlin.Unit public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String // Static members @@ -32,12 +40,16 @@ public fun test(): kotlin.Unit @lombok.Builder @lombok.Data public open class UserWithoutNull { public constructor UserWithoutNull() @lombok.Singular(ignoreNullCollections = false) private final var names: kotlin.collections.(Mutable)List! + @lombok.Singular(ignoreNullCollections = false) private final var pairs: kotlin.collections.(Mutable)Map! public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open /*synthesized*/ fun getNames(): kotlin.collections.(Mutable)List! + public open /*synthesized*/ fun getPairs(): kotlin.collections.(Mutable)Map! public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open /*synthesized*/ fun setNames(/*0*/ names: kotlin.collections.(Mutable)List!): kotlin.Unit + public open /*synthesized*/ fun setPairs(/*0*/ pairs: kotlin.collections.(Mutable)Map!): kotlin.Unit public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String // Static members public final /*synthesized*/ fun builder(): UserWithoutNull.UserWithoutNullBuilder } +