From 37926f333ecdb491679bff6d9a811dc0fae50402 Mon Sep 17 00:00:00 2001 From: Andrey Zinovyev Date: Fri, 26 Mar 2021 13:39:14 +0300 Subject: [PATCH] [lombok] Generate no-arg constructor --- .../lombok/lombok-compiler-plugin/README.md | 1 + .../LombokSyntheticJavaPartsProvider.kt | 1 + .../kotlin/lombok/config/annotationConfig.kt | 18 ++++++++++- .../processor/NoArgsConstructorProcessor.kt | 30 +++++++++++++++++++ .../kotlin/lombok/utils/LombokNames.kt | 1 + .../kotlin/lombok/utils/annotationUtils.kt | 6 ++-- .../kotlin/lombok/utils/descriptorUtils.kt | 26 +++++++++++++++- .../jetbrains/kotlin/lombok/utils/utils.kt | 2 ++ .../testData/compile/noArgsConstructor.kt | 30 +++++++++++++++++++ .../lombok/LombokCompileTestGenerated.java | 5 ++++ 10 files changed, 115 insertions(+), 5 deletions(-) create mode 100644 plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/NoArgsConstructorProcessor.kt create mode 100644 plugins/lombok/lombok-compiler-plugin/testData/compile/noArgsConstructor.kt diff --git a/plugins/lombok/lombok-compiler-plugin/README.md b/plugins/lombok/lombok-compiler-plugin/README.md index f2194bc75d1..79360a587f3 100644 --- a/plugins/lombok/lombok-compiler-plugin/README.md +++ b/plugins/lombok/lombok-compiler-plugin/README.md @@ -36,6 +36,7 @@ Features support: Other todos: - [ ] Generic classes + - [ ] Actually run compiled code - [ ] Don't generate members that already exist (if having a duplicate is a problem) - [ ] Gradle integration (as subplugin or just a way to enable lombok support) - [ ] Maven integration (as subplugin or just a way to enable lombok support) 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 ad604d3c0bf..e9bf0cb1666 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 @@ -25,6 +25,7 @@ class LombokSyntheticJavaPartsProvider(private val config: LombokConfig) : Synth GetterProcessor(config), SetterProcessor(config), WithProcessor(config), + NoArgsConstructorProcessor() ) private val partsCache: MutableMap = WeakHashMap() 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 32408149201..c05697e7031 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 @@ -8,8 +8,9 @@ package org.jetbrains.kotlin.lombok.config import org.jetbrains.kotlin.descriptors.DescriptorVisibility import org.jetbrains.kotlin.descriptors.annotations.Annotated import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor -import org.jetbrains.kotlin.lombok.utils.LombokNames +import org.jetbrains.kotlin.lombok.utils.* import org.jetbrains.kotlin.lombok.utils.getBooleanArgument +import org.jetbrains.kotlin.lombok.utils.getStringArgument import org.jetbrains.kotlin.lombok.utils.getVisibility import org.jetbrains.kotlin.name.FqName @@ -70,3 +71,18 @@ data class With(val visibility: DescriptorVisibility) { ) } } + +data class NoArgsConstructor( + val visibility: DescriptorVisibility, + val staticName: String? +) { + companion object : AnnotationCompanion() { + override val name: FqName = LombokNames.NO_ARGS_CONSTRUCTOR + + override fun extract(annotation: AnnotationDescriptor): NoArgsConstructor = + NoArgsConstructor( + visibility = getVisibility(annotation), + staticName = annotation.getStringArgument("staticName").trimToNull() + ) + } +} 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 new file mode 100644 index 00000000000..66e9967a050 --- /dev/null +++ b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/NoArgsConstructorProcessor.kt @@ -0,0 +1,30 @@ +/* + * 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.lombok.processor + +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl +import org.jetbrains.kotlin.lombok.config.NoArgsConstructor +import org.jetbrains.kotlin.lombok.utils.createConstructor + +class NoArgsConstructorProcessor : Processor { + + override fun contribute(classDescriptor: ClassDescriptor, jClass: JavaClassImpl): Parts { + val result = NoArgsConstructor.getOrNull(classDescriptor)?.let { annotation -> + if (annotation.staticName == null) { + val constructor = classDescriptor.createConstructor( + valueParameters = emptyList(), + visibility = annotation.visibility + ) + Parts(constructors = listOfNotNull(constructor)) + } else { + null + } + } + return result ?: Parts.Empty + } + +} diff --git a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/utils/LombokNames.kt b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/utils/LombokNames.kt index 42f3f1f7ba1..0f1a0840ed5 100644 --- a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/utils/LombokNames.kt +++ b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/utils/LombokNames.kt @@ -13,5 +13,6 @@ object LombokNames { val GETTER = FqName("lombok.Getter") val SETTER = FqName("lombok.Setter") val WITH = FqName("lombok.With") + val NO_ARGS_CONSTRUCTOR = FqName("lombok.NoArgsConstructor") } diff --git a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/utils/annotationUtils.kt b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/utils/annotationUtils.kt index f662f0e1ccb..55d25933ec6 100644 --- a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/utils/annotationUtils.kt +++ b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/utils/annotationUtils.kt @@ -15,7 +15,7 @@ import org.jetbrains.kotlin.resolve.constants.BooleanValue import org.jetbrains.kotlin.resolve.constants.EnumValue internal fun getVisibility(annotation: AnnotationDescriptor, field: String = "value"): DescriptorVisibility { - val value = annotation.getStringArgument(field, "PUBLIC") + val value = annotation.getStringArgument(field) ?: "PUBLIC" val visibility = when (value) { "PUBLIC" -> Visibilities.Public "PROTECTED" -> Visibilities.Protected @@ -26,9 +26,9 @@ internal fun getVisibility(annotation: AnnotationDescriptor, field: String = "va return DescriptorVisibilities.toDescriptorVisibility(visibility) } -private fun AnnotationDescriptor.getStringArgument(argumentName: String, default: String): String { +internal fun AnnotationDescriptor.getStringArgument(argumentName: String): String? { val argument = allValueArguments[Name.identifier(argumentName)] - ?: return default + ?: return null return when (argument) { is EnumValue -> argument.enumEntryName.identifier 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 318ed08d388..244ce7afe22 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,6 +7,7 @@ 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 @@ -44,7 +45,30 @@ internal fun ClassDescriptor.createFunction( return methodDescriptor } -private fun FunctionDescriptor.makeValueParameter(param: ValueParameter, index: Int): ValueParameterDescriptor { +internal fun ClassDescriptor.createConstructor( + valueParameters: List, + visibility: DescriptorVisibility = DescriptorVisibilities.PUBLIC +): ClassConstructorDescriptor { + val constructor = ClassConstructorDescriptorImpl.create( + this, + Annotations.EMPTY, + false, + this.source + ) + val paramDescriptors = valueParameters.mapIndexed { idx, param -> constructor.makeValueParameter(param, idx) } + constructor.initialize( + null, + constructor.calculateDispatchReceiverParameter(), + emptyList(), + paramDescriptors, + this.defaultType, + Modality.OPEN, + visibility + ) + return constructor +} + +private fun CallableDescriptor.makeValueParameter(param: ValueParameter, index: Int): ValueParameterDescriptor { return ValueParameterDescriptorImpl( containingDeclaration = this, original = null, 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 36cde4220ea..d11d3b7971a 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 @@ -8,3 +8,5 @@ package org.jetbrains.kotlin.lombok.utils @Suppress("UNCHECKED_CAST") internal fun Collection.collectWithNotNull(f: (E) -> R?): List> = map { it to f(it) }.filter { it.second != null } as List> + +internal fun String?.trimToNull(): String? = this?.trim()?.takeIf { it.isNotEmpty() } diff --git a/plugins/lombok/lombok-compiler-plugin/testData/compile/noArgsConstructor.kt b/plugins/lombok/lombok-compiler-plugin/testData/compile/noArgsConstructor.kt new file mode 100644 index 00000000000..178f567c46d --- /dev/null +++ b/plugins/lombok/lombok-compiler-plugin/testData/compile/noArgsConstructor.kt @@ -0,0 +1,30 @@ +//FILE: ConstructorExample.java + +import lombok.*; + +@NoArgsConstructor +public class ConstructorExample { + + public ConstructorExample(String arg) { + + } + + @Getter @Setter private int age = 10; + + @Getter(AccessLevel.PROTECTED) private String name; + + static void javaUsage() { + val existing = new ConstructorExample("existing"); + val generated = new ConstructorExample(); + } +} + + +//FILE: test.kt + +object Test { + fun usage() { + val existing = ConstructorExample("existing") + val generated = ConstructorExample() + } +} diff --git a/plugins/lombok/lombok-compiler-plugin/tests/org/jetbrains/kotlin/lombok/LombokCompileTestGenerated.java b/plugins/lombok/lombok-compiler-plugin/tests/org/jetbrains/kotlin/lombok/LombokCompileTestGenerated.java index c5780835c09..0d28bb4fed6 100644 --- a/plugins/lombok/lombok-compiler-plugin/tests/org/jetbrains/kotlin/lombok/LombokCompileTestGenerated.java +++ b/plugins/lombok/lombok-compiler-plugin/tests/org/jetbrains/kotlin/lombok/LombokCompileTestGenerated.java @@ -46,6 +46,11 @@ public class LombokCompileTestGenerated extends AbstractLombokCompileTest { runTest("plugins/lombok/lombok-compiler-plugin/testData/compile/gettersFluent.kt"); } + @TestMetadata("noArgsConstructor.kt") + public void testNoArgsConstructor() throws Exception { + runTest("plugins/lombok/lombok-compiler-plugin/testData/compile/noArgsConstructor.kt"); + } + @TestMetadata("getters.kt") public void testGetters() throws Exception { runTest("plugins/lombok/lombok-compiler-plugin/testData/compile/getters.kt");