diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/extensions/SyntheticJavaResolveExtension.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/extensions/SyntheticJavaResolveExtension.kt index a9b3dbbfa4e..c81db8e98ce 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/extensions/SyntheticJavaResolveExtension.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/extensions/SyntheticJavaResolveExtension.kt @@ -17,7 +17,7 @@ interface SyntheticJavaResolveExtension { ) { fun getProvider(project: Project): SyntheticJavaPartsProvider { val instances = getInstances(project) - val providers = instances.map { it.getProvider() } + val providers = instances.map { it.buildProvider() } return if (providers.isEmpty()) { SyntheticJavaPartsProvider.EMPTY } else { @@ -26,7 +26,7 @@ interface SyntheticJavaResolveExtension { } } - fun getProvider(): SyntheticJavaPartsProvider + fun buildProvider(): SyntheticJavaPartsProvider } diff --git a/license/third_party/lombok_LICENSE.txt b/license/third_party/lombok_LICENSE.txt new file mode 100644 index 00000000000..dd1c24c15f2 --- /dev/null +++ b/license/third_party/lombok_LICENSE.txt @@ -0,0 +1,19 @@ +Copyright (C) 2009-2021 The Project Lombok Authors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/LombokResolveExtension.kt b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/LombokResolveExtension.kt index ea83023f234..6094ceca56f 100644 --- a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/LombokResolveExtension.kt +++ b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/LombokResolveExtension.kt @@ -13,5 +13,5 @@ class LombokResolveExtension(pluginConfig: LombokPluginConfig) : SyntheticJavaRe private val config = pluginConfig.configFile?.let(LombokConfig::parse) ?: LombokConfig.Empty - override fun getProvider(): SyntheticJavaPartsProvider = LombokSyntheticJavaPartsProvider(config) + override fun buildProvider(): SyntheticJavaPartsProvider = LombokSyntheticJavaPartsProvider(config) } diff --git a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/LombokSyntheticJavaPartsProvider.kt b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/LombokSyntheticJavaPartsProvider.kt index 80476d1f221..4021b6f0d85 100644 --- a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/LombokSyntheticJavaPartsProvider.kt +++ b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/LombokSyntheticJavaPartsProvider.kt @@ -37,7 +37,7 @@ class LombokSyntheticJavaPartsProvider(config: LombokConfig) : SyntheticJavaPart * but for us it is much easier to run full generation for class once * hence we cache results and reuse it */ - private val partsCache: MutableMap = WeakHashMap() + private val partsCache: MutableMap = HashMap() override fun getMethodNames(thisDescriptor: ClassDescriptor): List = getSyntheticParts(thisDescriptor).methods.map { it.name } @@ -75,28 +75,19 @@ class LombokSyntheticJavaPartsProvider(config: LombokConfig) : SyntheticJavaPart } } ?: SyntheticParts.Empty - private fun computeSyntheticParts(descriptor: ClassDescriptor): SyntheticParts = - processors.map { it.contribute(descriptor) }.reduce { a, b -> a + b } + private fun computeSyntheticParts(descriptor: ClassDescriptor): SyntheticParts { + val builder = SyntheticPartsBuilder() + processors.forEach { it.contribute(descriptor, builder) } + return builder.build() + } /** * Deduplicates generated functions using name and argument counts, as lombok does */ private fun addNonExistent(result: MutableCollection, toAdd: List) { - if (toAdd.isEmpty()) return - - val index = mutableMapOf>() - - fun addToIndex(f: T) { - index.merge(f.name, listOf(f)) { a, b -> a + b} - } - - result.forEach(::addToIndex) - toAdd.forEach { f -> - val existing = index.getOrDefault(f.name, emptyList()) - if (existing.none { sameSignature (it, f) } ) { + if (result.none { sameSignature(it, f) }) { result += f - addToIndex(f) } } } @@ -106,6 +97,7 @@ class LombokSyntheticJavaPartsProvider(config: LombokConfig) : SyntheticJavaPart /** * Lombok treat functions as having the same signature by arguments count only + * Corresponding code in lombok - https://github.com/projectlombok/lombok/blob/v1.18.20/src/core/lombok/javac/handlers/JavacHandlerUtil.java#L752 */ private fun sameSignature(a: FunctionDescriptor, b: FunctionDescriptor): Boolean { val aVararg = a.valueParameters.any { it.varargElementType != null } diff --git a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/config/annotationConfig.kt b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/config/annotationConfig.kt index 9bda346a17a..430264c3ffc 100644 --- a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/config/annotationConfig.kt +++ b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/config/annotationConfig.kt @@ -20,9 +20,7 @@ import org.jetbrains.kotlin.name.FqName * */ -abstract class AnnotationCompanion { - - abstract val name: FqName +abstract class AnnotationCompanion(val name: FqName) { abstract fun extract(annotation: AnnotationDescriptor): T @@ -30,10 +28,7 @@ abstract class AnnotationCompanion { annotated.annotations.findAnnotation(name)?.let(this::extract) } -abstract class AnnotationAndConfigCompanion { - - abstract val annotationName: FqName - +abstract class AnnotationAndConfigCompanion(private val annotationName: FqName) { abstract fun extract(annotation: AnnotationDescriptor?, config: LombokConfig): T @@ -53,155 +48,148 @@ abstract class AnnotationAndConfigCompanion { } -data class Accessors( - val fluent: Boolean = false, - val chain: Boolean = false, - val noIsPrefix: Boolean = false, - val prefix: List = emptyList() -) { - companion object : AnnotationAndConfigCompanion() { +object LombokAnnotations { + class Accessors( + val fluent: Boolean = false, + val chain: Boolean = false, + val noIsPrefix: Boolean = false, + val prefix: List = emptyList() + ) { + companion object : AnnotationAndConfigCompanion(LombokNames.ACCESSORS) { - override val annotationName: FqName = LombokNames.ACCESSORS + override fun extract(annotation: AnnotationDescriptor?, config: LombokConfig): Accessors { + val fluent = + annotation?.getBooleanArgument("fluent") + ?: config.getBoolean("lombok.accessors.fluent") + ?: false + val chain = + annotation?.getBooleanArgument("chain") + ?: config.getBoolean("lombok.accessors.chain") + ?: fluent + val noIsPrefix = config.getBoolean("lombok.getter.noIsPrefix") ?: false + val prefix = + annotation?.getStringArrayArgument("prefix") + ?: config.getMultiString("lombok.accessors.prefix") + ?: emptyList() - override fun extract(annotation: AnnotationDescriptor?, config: LombokConfig): Accessors { - val fluent = - annotation?.getBooleanArgument("fluent") - ?: config.getBoolean("lombok.accessors.fluent") - ?: false - val chain = - annotation?.getBooleanArgument("chain") - ?: config.getBoolean("lombok.accessors.chain") - ?: fluent - val noIsPrefix = config.getBoolean("lombok.getter.noIsPrefix") ?: false - val prefix = - annotation?.getStringArrayArgument("prefix") - ?: config.getMultiString("lombok.accessors.prefix") - ?: emptyList() + return Accessors(fluent, chain, noIsPrefix, prefix) + } + } + } + + class Getter(val visibility: AccessLevel = AccessLevel.PUBLIC) { + companion object : AnnotationCompanion(LombokNames.GETTER) { + + override fun extract(annotation: AnnotationDescriptor): Getter = + Getter( + visibility = getAccessLevel(annotation) + ) + } + } + + class Setter(val visibility: AccessLevel = AccessLevel.PUBLIC) { + companion object : AnnotationCompanion( LombokNames.SETTER) { + + override fun extract(annotation: AnnotationDescriptor): Setter = + Setter( + visibility = getAccessLevel(annotation) + ) + } + } + + class With(val visibility: AccessLevel = AccessLevel.PUBLIC) { + companion object : AnnotationCompanion(LombokNames.WITH) { + + override fun extract(annotation: AnnotationDescriptor): With = + With( + visibility = getAccessLevel(annotation) + ) + } + } + + interface ConstructorAnnotation { + val visibility: DescriptorVisibility + val staticName: String? + } + + class NoArgsConstructor( + override val visibility: DescriptorVisibility, + override val staticName: String? + ) : ConstructorAnnotation { + companion object : AnnotationCompanion( LombokNames.NO_ARGS_CONSTRUCTOR) { + + override fun extract(annotation: AnnotationDescriptor): NoArgsConstructor = + NoArgsConstructor( + visibility = getVisibility(annotation, "access"), + staticName = annotation.getNonBlankStringArgument("staticName") + ) + } + } + + class AllArgsConstructor( + override val visibility: DescriptorVisibility = DescriptorVisibilities.PUBLIC, + override val staticName: String? = null + ) : ConstructorAnnotation { + companion object : AnnotationCompanion(LombokNames.ALL_ARGS_CONSTRUCTOR) { + + override fun extract(annotation: AnnotationDescriptor): AllArgsConstructor = + AllArgsConstructor( + visibility = getVisibility(annotation, "access"), + staticName = annotation.getNonBlankStringArgument("staticName") + ) + } + } + + class RequiredArgsConstructor( + override val visibility: DescriptorVisibility = DescriptorVisibilities.PUBLIC, + override val staticName: String? = null + ) : ConstructorAnnotation { + companion object : AnnotationCompanion(LombokNames.REQUIRED_ARGS_CONSTRUCTOR) { + + override fun extract(annotation: AnnotationDescriptor): RequiredArgsConstructor = + RequiredArgsConstructor( + visibility = getVisibility(annotation, "access"), + staticName = annotation.getNonBlankStringArgument("staticName") + ) + } + } + + class Data(val staticConstructor: String?) { + + fun asSetter(): Setter = Setter() + + fun asGetter(): Getter = Getter() + + fun asRequiredArgsConstructor(): RequiredArgsConstructor = RequiredArgsConstructor( + staticName = staticConstructor + ) + + companion object : AnnotationCompanion(LombokNames.DATA) { + override fun extract(annotation: AnnotationDescriptor): Data = + Data( + staticConstructor = annotation.getNonBlankStringArgument("staticConstructor") + ) + + } + } + + class Value(val staticConstructor: String?) { + + fun asGetter(): Getter = Getter() + + fun asAllArgsConstructor(): AllArgsConstructor = AllArgsConstructor( + staticName = staticConstructor + ) + + companion object : AnnotationCompanion(LombokNames.VALUE) { + + override fun extract(annotation: AnnotationDescriptor): Value = + Value( + staticConstructor = annotation.getNonBlankStringArgument("staticConstructor") + ) - return Accessors(fluent, chain, noIsPrefix, prefix) } } } -data class Getter(val visibility: AccessLevel = AccessLevel.PUBLIC) { - companion object : AnnotationCompanion() { - override val name: FqName = LombokNames.GETTER - override fun extract(annotation: AnnotationDescriptor): Getter = - Getter( - visibility = getAccessLevel(annotation) - ) - } -} - -data class Setter(val visibility: AccessLevel = AccessLevel.PUBLIC) { - companion object : AnnotationCompanion() { - override val name: FqName = LombokNames.SETTER - - override fun extract(annotation: AnnotationDescriptor): Setter = - Setter( - visibility = getAccessLevel(annotation) - ) - } -} - -data class With(val visibility: AccessLevel = AccessLevel.PUBLIC) { - companion object : AnnotationCompanion() { - override val name: FqName = LombokNames.WITH - - override fun extract(annotation: AnnotationDescriptor): With = - With( - visibility = getAccessLevel(annotation) - ) - } -} - -interface ConstructorAnnotation { - val visibility: DescriptorVisibility - val staticName: String? -} - -data class NoArgsConstructor( - override val visibility: DescriptorVisibility, - override val staticName: String? -) : ConstructorAnnotation { - companion object : AnnotationCompanion() { - override val name: FqName = LombokNames.NO_ARGS_CONSTRUCTOR - - override fun extract(annotation: AnnotationDescriptor): NoArgsConstructor = - NoArgsConstructor( - visibility = getVisibility(annotation, "access"), - staticName = annotation.getNonBlankStringArgument("staticName") - ) - } -} - -data class AllArgsConstructor( - override val visibility: DescriptorVisibility = DescriptorVisibilities.PUBLIC, - override val staticName: String? = null -) : ConstructorAnnotation { - companion object : AnnotationCompanion() { - override val name: FqName = LombokNames.ALL_ARGS_CONSTRUCTOR - - override fun extract(annotation: AnnotationDescriptor): AllArgsConstructor = - AllArgsConstructor( - visibility = getVisibility(annotation, "access"), - staticName = annotation.getNonBlankStringArgument("staticName") - ) - } -} - -data class RequiredArgsConstructor( - override val visibility: DescriptorVisibility = DescriptorVisibilities.PUBLIC, - override val staticName: String? = null -) : ConstructorAnnotation { - companion object : AnnotationCompanion() { - override val name: FqName = LombokNames.REQUIRED_ARGS_CONSTRUCTOR - - override fun extract(annotation: AnnotationDescriptor): RequiredArgsConstructor = - RequiredArgsConstructor( - visibility = getVisibility(annotation, "access"), - staticName = annotation.getNonBlankStringArgument("staticName") - ) - } -} - -data class Data(val staticConstructor: String?) { - - fun asSetter(): Setter = Setter() - - fun asGetter(): Getter = Getter() - - fun asRequiredArgsConstructor(): RequiredArgsConstructor = RequiredArgsConstructor( - staticName = staticConstructor - ) - - companion object : AnnotationCompanion() { - override val name: FqName = LombokNames.DATA - - override fun extract(annotation: AnnotationDescriptor): Data = - Data( - staticConstructor = annotation.getNonBlankStringArgument("staticConstructor") - ) - - } -} - -data class Value(val staticConstructor: String?) { - - fun asGetter(): Getter = Getter() - - fun asAllArgsConstructor(): AllArgsConstructor = AllArgsConstructor( - staticName = staticConstructor - ) - - companion object : AnnotationCompanion() { - override val name: FqName = LombokNames.VALUE - - override fun extract(annotation: AnnotationDescriptor): Value = - Value( - staticConstructor = annotation.getNonBlankStringArgument("staticConstructor") - ) - - } -} diff --git a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/AbstractConstructorProcessor.kt b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/AbstractConstructorProcessor.kt index 38c5e213e13..9b100f7e0e3 100644 --- a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/AbstractConstructorProcessor.kt +++ b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/AbstractConstructorProcessor.kt @@ -7,26 +7,26 @@ package org.jetbrains.kotlin.lombok.processor import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor -import org.jetbrains.kotlin.lombok.config.ConstructorAnnotation -import org.jetbrains.kotlin.lombok.utils.ValueParameter -import org.jetbrains.kotlin.lombok.utils.createJavaConstructor +import org.jetbrains.kotlin.lombok.config.LombokAnnotations.ConstructorAnnotation +import org.jetbrains.kotlin.lombok.utils.LombokValueParameter import org.jetbrains.kotlin.lombok.utils.createFunction +import org.jetbrains.kotlin.lombok.utils.createJavaConstructor import org.jetbrains.kotlin.name.Name abstract class AbstractConstructorProcessor : Processor { - override fun contribute(classDescriptor: ClassDescriptor): SyntheticParts { + override fun contribute(classDescriptor: ClassDescriptor, partsBuilder: SyntheticPartsBuilder) { val valueParameters = getPropertiesForParameters(classDescriptor).map { property -> - ValueParameter(property.name, property.type) + LombokValueParameter(property.name, property.type) } - val result = getAnnotation(classDescriptor)?.let { annotation -> + getAnnotation(classDescriptor)?.let { annotation -> if (annotation.staticName == null) { val constructor = classDescriptor.createJavaConstructor( valueParameters = valueParameters, visibility = annotation.visibility ) - SyntheticParts(constructors = listOfNotNull(constructor)) + partsBuilder.addConstructor(constructor) } else { val function = classDescriptor.createFunction( Name.identifier(annotation.staticName!!), @@ -36,10 +36,9 @@ abstract class AbstractConstructorProcessor : Process visibility = annotation.visibility, receiver = null ) - SyntheticParts(staticFunctions = listOf(function)) + partsBuilder.addStaticFunction(function) } } - return result ?: SyntheticParts.Empty } protected abstract fun getAnnotation(classDescriptor: ClassDescriptor): A? diff --git a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/AllArgsConstructorProcessor.kt b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/AllArgsConstructorProcessor.kt index ef4f5cf81b8..8b6c30c896d 100644 --- a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/AllArgsConstructorProcessor.kt +++ b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/AllArgsConstructorProcessor.kt @@ -7,8 +7,8 @@ package org.jetbrains.kotlin.lombok.processor import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor -import org.jetbrains.kotlin.lombok.config.AllArgsConstructor -import org.jetbrains.kotlin.lombok.config.Value +import org.jetbrains.kotlin.lombok.config.LombokAnnotations.AllArgsConstructor +import org.jetbrains.kotlin.lombok.config.LombokAnnotations.Value import org.jetbrains.kotlin.lombok.utils.getJavaFields class AllArgsConstructorProcessor : AbstractConstructorProcessor() { diff --git a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/GetterProcessor.kt b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/GetterProcessor.kt index a305c9fae1e..961632f1874 100644 --- a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/GetterProcessor.kt +++ b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/GetterProcessor.kt @@ -9,24 +9,27 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor import org.jetbrains.kotlin.lombok.config.* +import org.jetbrains.kotlin.lombok.config.LombokAnnotations.Accessors +import org.jetbrains.kotlin.lombok.config.LombokAnnotations.Getter +import org.jetbrains.kotlin.lombok.config.LombokAnnotations.Data +import org.jetbrains.kotlin.lombok.config.LombokAnnotations.Value import org.jetbrains.kotlin.lombok.utils.* import org.jetbrains.kotlin.name.Name class GetterProcessor(private val config: LombokConfig) : Processor { - override fun contribute(classDescriptor: ClassDescriptor): SyntheticParts { + override fun contribute(classDescriptor: ClassDescriptor, partsBuilder: SyntheticPartsBuilder) { val globalAccessors = Accessors.get(classDescriptor, config) val clGetter = Getter.getOrNull(classDescriptor) ?: Data.getOrNull(classDescriptor)?.asGetter() ?: Value.getOrNull(classDescriptor)?.asGetter() - val functions = classDescriptor + classDescriptor .getJavaFields() .collectWithNotNull { Getter.getOrNull(it) ?: clGetter } .mapNotNull { (field, annotation) -> createGetter(classDescriptor, field, annotation, globalAccessors) } - - return SyntheticParts(functions) + .forEach(partsBuilder::addMethod) } private fun createGetter( diff --git a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/NoArgsConstructorProcessor.kt b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/NoArgsConstructorProcessor.kt index 474c5bb343e..df2da8836db 100644 --- a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/NoArgsConstructorProcessor.kt +++ b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/NoArgsConstructorProcessor.kt @@ -7,7 +7,7 @@ package org.jetbrains.kotlin.lombok.processor import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor -import org.jetbrains.kotlin.lombok.config.NoArgsConstructor +import org.jetbrains.kotlin.lombok.config.LombokAnnotations.NoArgsConstructor class NoArgsConstructorProcessor : AbstractConstructorProcessor() { diff --git a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/Processor.kt b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/Processor.kt index 5ed69a52411..245331581dd 100644 --- a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/Processor.kt +++ b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/Processor.kt @@ -12,5 +12,6 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor */ interface Processor { - fun contribute(classDescriptor: ClassDescriptor): SyntheticParts + fun contribute(classDescriptor: ClassDescriptor, partsBuilder: SyntheticPartsBuilder) + } diff --git a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/RequiredArgsConstructorProcessor.kt b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/RequiredArgsConstructorProcessor.kt index 1c1d91e01df..50c4b500a5c 100644 --- a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/RequiredArgsConstructorProcessor.kt +++ b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/RequiredArgsConstructorProcessor.kt @@ -9,8 +9,8 @@ import com.intellij.psi.PsiField import com.intellij.psi.PsiModifier import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor -import org.jetbrains.kotlin.lombok.config.Data -import org.jetbrains.kotlin.lombok.config.RequiredArgsConstructor +import org.jetbrains.kotlin.lombok.config.LombokAnnotations.Data +import org.jetbrains.kotlin.lombok.config.LombokAnnotations.RequiredArgsConstructor import org.jetbrains.kotlin.lombok.utils.LombokNames import org.jetbrains.kotlin.lombok.utils.getJavaFields import org.jetbrains.kotlin.resolve.source.getPsi diff --git a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/SetterProcessor.kt b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/SetterProcessor.kt index cfa5d017b46..5267709b353 100644 --- a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/SetterProcessor.kt +++ b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/SetterProcessor.kt @@ -9,22 +9,25 @@ import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.lombok.config.* import org.jetbrains.kotlin.lombok.utils.* import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.lombok.config.LombokAnnotations.Accessors +import org.jetbrains.kotlin.lombok.config.LombokAnnotations.Setter +import org.jetbrains.kotlin.lombok.config.LombokAnnotations.Data import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns class SetterProcessor(private val config: LombokConfig) : Processor { - override fun contribute(classDescriptor: ClassDescriptor): SyntheticParts { + override fun contribute(classDescriptor: ClassDescriptor, partsBuilder: SyntheticPartsBuilder) { //lombok doesn't generate setters for enums - if (classDescriptor.kind == ClassKind.ENUM_CLASS) return SyntheticParts.Empty + if (classDescriptor.kind == ClassKind.ENUM_CLASS) return val globalAccessors = Accessors.get(classDescriptor, config) val clSetter = Setter.getOrNull(classDescriptor) ?: Data.getOrNull(classDescriptor)?.asSetter() - val functions = classDescriptor + classDescriptor .getJavaFields() .collectWithNotNull { field -> Setter.getOrNull(field) ?: clSetter.takeIf { field.isVar } } .mapNotNull { (field, setter) -> createSetter(classDescriptor, field, setter, globalAccessors) } - return SyntheticParts(functions) + .forEach(partsBuilder::addMethod) } private fun createSetter( @@ -45,7 +48,7 @@ class SetterProcessor(private val config: LombokConfig) : Processor { classDescriptor.createFunction( Name.identifier(functionName), - listOf(ValueParameter(field.name, field.type)), + listOf(LombokValueParameter(field.name, field.type)), returnType, visibility = getter.visibility.toDescriptorVisibility() ) diff --git a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/SyntheticParts.kt b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/SyntheticParts.kt index 34b394afcd9..f2bf846a49a 100644 --- a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/SyntheticParts.kt +++ b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/SyntheticParts.kt @@ -8,7 +8,7 @@ package org.jetbrains.kotlin.lombok.processor import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor -data class SyntheticParts( +class SyntheticParts( val methods: List = emptyList(), val staticFunctions: List = emptyList(), val constructors: List = emptyList() @@ -24,3 +24,23 @@ data class SyntheticParts( val Empty = SyntheticParts() } } + +class SyntheticPartsBuilder { + private val methods = mutableListOf() + private val staticFunctions = mutableListOf() + private val constructors = mutableListOf() + + fun addMethod(method: SimpleFunctionDescriptor) { + methods += method + } + + fun addStaticFunction(function: SimpleFunctionDescriptor) { + staticFunctions += function + } + + fun addConstructor(constructor: ClassConstructorDescriptor) { + constructors += constructor + } + + fun build(): SyntheticParts = SyntheticParts(methods, staticFunctions, constructors) +} diff --git a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/WithProcessor.kt b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/WithProcessor.kt index 4ca05970b3a..7248ed6abf4 100644 --- a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/WithProcessor.kt +++ b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/WithProcessor.kt @@ -9,21 +9,19 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor import org.jetbrains.kotlin.lombok.config.AccessLevel -import org.jetbrains.kotlin.lombok.config.With +import org.jetbrains.kotlin.lombok.config.LombokAnnotations.With import org.jetbrains.kotlin.lombok.utils.* import org.jetbrains.kotlin.name.Name class WithProcessor : Processor { - override fun contribute(classDescriptor: ClassDescriptor): SyntheticParts { - + override fun contribute(classDescriptor: ClassDescriptor, partsBuilder: SyntheticPartsBuilder) { val clWith = With.getOrNull(classDescriptor) - val functions = classDescriptor + classDescriptor .getJavaFields() .collectWithNotNull { With.getOrNull(it) ?: clWith } .mapNotNull { (field, annotation) -> createWith(classDescriptor, field, annotation) } - - return SyntheticParts(functions) + .forEach(partsBuilder::addMethod) } private fun createWith( @@ -37,7 +35,7 @@ class WithProcessor : Processor { return classDescriptor.createFunction( Name.identifier(functionName), - listOf(ValueParameter(field.name, field.type)), + listOf(LombokValueParameter(field.name, field.type)), classDescriptor.defaultType, visibility = with.visibility.toDescriptorVisibility() ) diff --git a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/utils/descriptorUtils.kt b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/utils/descriptorUtils.kt index 8aaf79d9838..4f2c2d24746 100644 --- a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/utils/descriptorUtils.kt +++ b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/utils/descriptorUtils.kt @@ -7,7 +7,6 @@ package org.jetbrains.kotlin.lombok.utils import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations -import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl import org.jetbrains.kotlin.incremental.components.NoLookupLocation @@ -18,11 +17,11 @@ import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.model.SimpleTypeMarker import org.jetbrains.kotlin.types.typeUtil.isBoolean -data class ValueParameter(val name: Name, val type: KotlinType) +data class LombokValueParameter(val name: Name, val type: KotlinType) fun ClassDescriptor.createFunction( name: Name, - valueParameters: List, + valueParameters: List, returnType: KotlinType?, typeParameters: List = emptyList(), modality: Modality? = Modality.OPEN, @@ -52,7 +51,7 @@ fun ClassDescriptor.createFunction( } fun ClassDescriptor.createJavaConstructor( - valueParameters: List, + valueParameters: List, visibility: DescriptorVisibility = DescriptorVisibilities.PUBLIC ): ClassConstructorDescriptor { val constructor = JavaClassConstructorDescriptor.create( @@ -74,7 +73,7 @@ fun ClassDescriptor.createJavaConstructor( return constructor } -private fun CallableDescriptor.makeValueParameter(param: ValueParameter, index: Int): ValueParameterDescriptor { +private fun CallableDescriptor.makeValueParameter(param: LombokValueParameter, index: Int): ValueParameterDescriptor { return ValueParameterDescriptorImpl( containingDeclaration = this, original = null, diff --git a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/utils/nameUtils.kt b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/utils/nameUtils.kt index f3c11179747..af9a46851cb 100644 --- a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/utils/nameUtils.kt +++ b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/utils/nameUtils.kt @@ -6,7 +6,7 @@ package org.jetbrains.kotlin.lombok.utils import org.jetbrains.kotlin.descriptors.PropertyDescriptor -import org.jetbrains.kotlin.lombok.config.Accessors +import org.jetbrains.kotlin.lombok.config.LombokAnnotations.Accessors object AccessorNames { const val IS = "is" diff --git a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/utils/utils.kt b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/utils/utils.kt index dc5bb7f8afd..7857f17c314 100644 --- a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/utils/utils.kt +++ b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/utils/utils.kt @@ -5,8 +5,15 @@ package org.jetbrains.kotlin.lombok.utils +import java.util.* + @Suppress("UNCHECKED_CAST") fun Collection.collectWithNotNull(f: (E) -> R?): List> = map { it to f(it) }.filter { it.second != null } as List> fun String?.trimToNull(): String? = this?.trim()?.takeIf { it.isNotEmpty() } + +//because capitalize from stdlib is deprecated +fun String.capitalize(): String = replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() } + +fun String.decapitalize(): String = replaceFirstChar { if (it.isUpperCase()) it.lowercase(Locale.getDefault()) else it.toString() } diff --git a/plugins/lombok/lombok-compiler-plugin/testData/common.kt b/plugins/lombok/lombok-compiler-plugin/testData/common.kt new file mode 100644 index 00000000000..6d043ea4f42 --- /dev/null +++ b/plugins/lombok/lombok-compiler-plugin/testData/common.kt @@ -0,0 +1,3 @@ +fun assertEquals(a: T, b: T) { + if (a != b) throw RuntimeException("'$a' was not equal to '$b'") +} diff --git a/plugins/lombok/lombok-compiler-plugin/testData/compile/data.kt b/plugins/lombok/lombok-compiler-plugin/testData/compile/data.kt index a8e1676d504..d74f6d861be 100644 --- a/plugins/lombok/lombok-compiler-plugin/testData/compile/data.kt +++ b/plugins/lombok/lombok-compiler-plugin/testData/compile/data.kt @@ -31,11 +31,13 @@ class Test { fun run() { val obj = DataExample("name") obj.getName() - val name = obj.name + assertEquals(obj.name, "name") obj.getTags() val tags = obj.tags obj.setScore(1.5) + assertEquals(obj.score, 1.5) obj.score = 2.5 + assertEquals(obj.score, 2.5) val ex: DataExample.Exercise = DataExample.Exercise.of("name", 12) } diff --git a/plugins/lombok/lombok-compiler-plugin/testData/compile/genericsConstructorsStatic.kt b/plugins/lombok/lombok-compiler-plugin/testData/compile/genericsConstructorsStatic.kt index 2b8f7b17d60..95b117c309b 100644 --- a/plugins/lombok/lombok-compiler-plugin/testData/compile/genericsConstructorsStatic.kt +++ b/plugins/lombok/lombok-compiler-plugin/testData/compile/genericsConstructorsStatic.kt @@ -24,6 +24,8 @@ public class ConstructorExample { class Test { fun run() { val generated: ConstructorExample = ConstructorExample.of(12, 42L, true) - val generatedReq: ConstructorExample = ConstructorExample.of("234"); + assertEquals(generated.name, 42L) + val generatedReq: ConstructorExample = ConstructorExample.of("234") + assertEquals(generatedReq.name, "234") } } diff --git a/plugins/lombok/lombok-compiler-plugin/testData/compile/gettersFluent.kt b/plugins/lombok/lombok-compiler-plugin/testData/compile/gettersFluent.kt index 4057b62f5f7..325fc39f19b 100644 --- a/plugins/lombok/lombok-compiler-plugin/testData/compile/gettersFluent.kt +++ b/plugins/lombok/lombok-compiler-plugin/testData/compile/gettersFluent.kt @@ -30,7 +30,7 @@ public class FluentTest { class Test { fun run() { val obj = FluentTest() - val getter = obj.age() + assertEquals(obj.age(), 10) obj.primitiveBoolean() diff --git a/plugins/lombok/lombok-compiler-plugin/testData/compile/requiredArgsConstructor.kt b/plugins/lombok/lombok-compiler-plugin/testData/compile/requiredArgsConstructor.kt index c4b7f868fb0..4de574249de 100644 --- a/plugins/lombok/lombok-compiler-plugin/testData/compile/requiredArgsConstructor.kt +++ b/plugins/lombok/lombok-compiler-plugin/testData/compile/requiredArgsConstructor.kt @@ -36,5 +36,6 @@ public class ConstructorExample { class Test { fun run() { val generated = ConstructorExample("foo", true) + assertEquals(generated.foo, "foo") } } diff --git a/plugins/lombok/lombok-compiler-plugin/testData/compile/requiredArgsConstructorStatic.kt b/plugins/lombok/lombok-compiler-plugin/testData/compile/requiredArgsConstructorStatic.kt index c343dec6a83..4c37176c4ac 100644 --- a/plugins/lombok/lombok-compiler-plugin/testData/compile/requiredArgsConstructorStatic.kt +++ b/plugins/lombok/lombok-compiler-plugin/testData/compile/requiredArgsConstructorStatic.kt @@ -38,5 +38,6 @@ public class ConstructorExample { class Test { fun run() { val generated = ConstructorExample.build("foo", true, 12) + assertEquals(generated.foo, "foo") } } diff --git a/plugins/lombok/lombok-compiler-plugin/testData/compile/settersClassLevel.kt b/plugins/lombok/lombok-compiler-plugin/testData/compile/settersClassLevel.kt index 7b1a5632095..824dcd01557 100644 --- a/plugins/lombok/lombok-compiler-plugin/testData/compile/settersClassLevel.kt +++ b/plugins/lombok/lombok-compiler-plugin/testData/compile/settersClassLevel.kt @@ -27,7 +27,9 @@ class Test { fun run() { val obj = SetterTest() obj.setAge(42) - obj.age = 42 + assertEquals(obj.age, 42) + obj.age = 43 + assertEquals(obj.age, 43) obj.setPrimitiveBoolean(true) diff --git a/plugins/lombok/lombok-compiler-plugin/testData/compile/settersVariations.kt b/plugins/lombok/lombok-compiler-plugin/testData/compile/settersVariations.kt index f9210b2c279..787f055f2a7 100644 --- a/plugins/lombok/lombok-compiler-plugin/testData/compile/settersVariations.kt +++ b/plugins/lombok/lombok-compiler-plugin/testData/compile/settersVariations.kt @@ -29,8 +29,11 @@ class Test { fun run() { val obj = SetterTest() obj.fluent(12) + assertEquals(obj.fluent(), 12) obj.setChained("zz").getChained() + assertEquals(obj.getChained(), "zz") obj.whyNotBoth("zzz").whyNotBoth() + assertEquals(obj.whyNotBoth(), "zzz") } } diff --git a/plugins/lombok/lombok-compiler-plugin/testData/compile/value.kt b/plugins/lombok/lombok-compiler-plugin/testData/compile/value.kt index a3ef5c52372..08df7bc2686 100644 --- a/plugins/lombok/lombok-compiler-plugin/testData/compile/value.kt +++ b/plugins/lombok/lombok-compiler-plugin/testData/compile/value.kt @@ -31,12 +31,14 @@ import lombok.*; class Test { fun run() { val obj = ValueExample("name", 12, 4.5) - obj.getName() - val name = obj.name - obj.getAge() - val age = obj.age - val score = obj.score + assertEquals(obj.getName(), "name") + assertEquals(obj.name, "name") + assertEquals(obj.getAge(), 12) + assertEquals(obj.age, 12) + assertEquals(obj.score, 4.5) - val ex: ValueExample.Exercise = ValueExample.Exercise.of("name", 12) + val ex: ValueExample.Exercise = ValueExample.Exercise.of("nam1e", 42) + assertEquals(ex.name, "nam1e") + assertEquals(ex.value, 42) } } diff --git a/plugins/lombok/lombok-compiler-plugin/testData/compile/with.kt b/plugins/lombok/lombok-compiler-plugin/testData/compile/with.kt index 779771176c8..4bcbe5fd970 100644 --- a/plugins/lombok/lombok-compiler-plugin/testData/compile/with.kt +++ b/plugins/lombok/lombok-compiler-plugin/testData/compile/with.kt @@ -1,25 +1,17 @@ //FILE: WithExample.java -import lombok.AccessLevel; -import lombok.With; +import lombok.*; +@AllArgsConstructor +@NoArgsConstructor public class WithExample { - //todo replace constructors with annotations when supported - public WithExample() { + @Getter @With private int age = 10; - } + @Getter @With private String name; - public WithExample(int age, String name) { - - } - - @With private int age = 10; - - @With private String name; - - static void test() { - WithExample obj = new WithExample().withAge(16).withName("fooo"); + public static WithExample test() { + return new WithExample().withAge(16).withName("fooo"); } } @@ -27,7 +19,10 @@ public class WithExample { //FILE: test.kt class Test { + fun run() { val obj: WithExample = WithExample().withAge(16).withName("fooo") + assertEquals(obj.getName(), "fooo") + assertEquals(obj.age, 16) } } diff --git a/plugins/lombok/lombok-compiler-plugin/tests/org/jetbrains/kotlin/lombok/AbstractLombokCompileTest.kt b/plugins/lombok/lombok-compiler-plugin/tests/org/jetbrains/kotlin/lombok/AbstractLombokCompileTest.kt index 239a6dca7b9..090101e63cb 100644 --- a/plugins/lombok/lombok-compiler-plugin/tests/org/jetbrains/kotlin/lombok/AbstractLombokCompileTest.kt +++ b/plugins/lombok/lombok-compiler-plugin/tests/org/jetbrains/kotlin/lombok/AbstractLombokCompileTest.kt @@ -18,9 +18,13 @@ import java.net.URLClassLoader abstract class AbstractLombokCompileTest : CodegenTestCase() { private val commonClassLoader = URLClassLoader(arrayOf(getLombokJar().toURI().toURL())) + private val commonSourceFile = TestFile( + "common.kt", + File("plugins/lombok/lombok-compiler-plugin/testData/common.kt").readText() + ) override fun doMultiFileTest(wholeFile: File, files: List) { - compile(files, true, true) + compile(files + commonSourceFile, true, true) } override fun setupEnvironment(environment: KotlinCoreEnvironment) {