From 59f936fdef1592084eec8e0d12f29c6bdd1e1380 Mon Sep 17 00:00:00 2001 From: Andrey Zinovyev Date: Fri, 26 Mar 2021 15:14:55 +0300 Subject: [PATCH] [lombok] Generate no-arg static factory method --- .../descriptors/LazyJavaClassMemberScope.kt | 6 ++-- .../descriptors/LazyJavaStaticClassScope.kt | 5 +++ .../resolve/jvm/SyntheticJavaPartsProvider.kt | 33 ++++++++++++++----- .../lombok/lombok-compiler-plugin/README.md | 7 ++-- .../LombokSyntheticJavaPartsProvider.kt | 14 ++++++-- .../processor/NoArgsConstructorProcessor.kt | 11 ++++++- .../kotlin/lombok/processor/Parts.kt | 7 +++- .../kotlin/lombok/utils/annotationUtils.kt | 2 ++ .../kotlin/lombok/utils/descriptorUtils.kt | 5 +-- .../compile/noArgsConstructorStatic.kt | 30 +++++++++++++++++ .../lombok/LombokCompileTestGenerated.java | 5 +++ 11 files changed, 103 insertions(+), 22 deletions(-) create mode 100644 plugins/lombok/lombok-compiler-plugin/testData/compile/noArgsConstructorStatic.kt diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaClassMemberScope.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaClassMemberScope.kt index f9bdc02a5e8..817a7a65d35 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaClassMemberScope.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaClassMemberScope.kt @@ -78,7 +78,7 @@ class LazyJavaClassMemberScope( addAll(declaredMemberIndex().getMethodNames()) addAll(declaredMemberIndex().getRecordComponentNames()) addAll(computeClassNames(kindFilter, nameFilter)) - addAll(c.components.syntheticPartsProvider.getSyntheticFunctionNames(ownerDescriptor)) + addAll(c.components.syntheticPartsProvider.getMethodNames(ownerDescriptor)) } internal val constructors = c.storageManager.createLazyValue { @@ -99,7 +99,7 @@ class LazyJavaClassMemberScope( } } - c.components.syntheticPartsProvider.generateSyntheticConstructors(ownerDescriptor, result) + c.components.syntheticPartsProvider.generateConstructors(ownerDescriptor, result) c.components.signatureEnhancement.enhanceSignatures( c, @@ -500,7 +500,7 @@ class LazyJavaClassMemberScope( result.add(resolveRecordComponentToFunctionDescriptor(declaredMemberIndex().findRecordComponentByName(name)!!)) } - c.components.syntheticPartsProvider.generateSyntheticMethods(ownerDescriptor, name, result) + c.components.syntheticPartsProvider.generateMethods(ownerDescriptor, name, result) } private fun resolveRecordComponentToFunctionDescriptor(recordComponent: JavaRecordComponent): JavaMethodDescriptor { diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaStaticClassScope.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaStaticClassScope.kt index 7990760972b..446b891e887 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaStaticClassScope.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaStaticClassScope.kt @@ -48,6 +48,7 @@ class LazyJavaStaticClassScope( if (jClass.isEnum) { addAll(listOf(StandardNames.ENUM_VALUE_OF, StandardNames.ENUM_VALUES)) } + addAll(c.components.syntheticPartsProvider.getStaticFunctionNames(ownerDescriptor)) } override fun computePropertyNames(kindFilter: DescriptorKindFilter, nameFilter: ((Name) -> Boolean)?) = @@ -81,6 +82,10 @@ class LazyJavaStaticClassScope( } } + override fun computeImplicitlyDeclaredFunctions(result: MutableCollection, name: Name) { + c.components.syntheticPartsProvider.generateStaticFunctions(ownerDescriptor, name, result) + } + override fun computeNonDeclaredProperties(name: Name, result: MutableCollection) { val propertiesFromSupertypes = flatMapJavaStaticSupertypesScopes(ownerDescriptor, mutableSetOf()) { it.getContributedVariables(name, NoLookupLocation.WHEN_GET_SUPER_MEMBERS) diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/resolve/jvm/SyntheticJavaPartsProvider.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/resolve/jvm/SyntheticJavaPartsProvider.kt index dd320280096..8a1465a4a7c 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/resolve/jvm/SyntheticJavaPartsProvider.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/resolve/jvm/SyntheticJavaPartsProvider.kt @@ -16,31 +16,46 @@ interface SyntheticJavaPartsProvider { val EMPTY = CompositeSyntheticJavaPartsProvider(emptyList()) } - fun getSyntheticFunctionNames(thisDescriptor: ClassDescriptor): List + fun getMethodNames(thisDescriptor: ClassDescriptor): List - fun generateSyntheticMethods( + fun generateMethods( thisDescriptor: ClassDescriptor, name: Name, result: MutableCollection ) - fun generateSyntheticConstructors(thisDescriptor: ClassDescriptor, result: MutableList) + fun getStaticFunctionNames(thisDescriptor: ClassDescriptor): List + + fun generateStaticFunctions( + thisDescriptor: ClassDescriptor, + name: Name, + result: MutableCollection + ) + + fun generateConstructors(thisDescriptor: ClassDescriptor, result: MutableList) } class CompositeSyntheticJavaPartsProvider(private val inner: List) : SyntheticJavaPartsProvider { - override fun getSyntheticFunctionNames(thisDescriptor: ClassDescriptor): List = - inner.flatMap { it.getSyntheticFunctionNames(thisDescriptor) } + override fun getMethodNames(thisDescriptor: ClassDescriptor): List = + inner.flatMap { it.getMethodNames(thisDescriptor) } - override fun generateSyntheticMethods( + override fun generateMethods( thisDescriptor: ClassDescriptor, name: Name, result: MutableCollection ) { - inner.forEach { it.generateSyntheticMethods(thisDescriptor, name, result) } + inner.forEach { it.generateMethods(thisDescriptor, name, result) } } - override fun generateSyntheticConstructors(thisDescriptor: ClassDescriptor, result: MutableList) { - inner.forEach { it.generateSyntheticConstructors(thisDescriptor, result) } + override fun getStaticFunctionNames(thisDescriptor: ClassDescriptor): List = + inner.flatMap { it.getStaticFunctionNames(thisDescriptor) } + + override fun generateStaticFunctions(thisDescriptor: ClassDescriptor, name: Name, result: MutableCollection) { + inner.forEach { it.generateStaticFunctions(thisDescriptor, name, result) } + } + + override fun generateConstructors(thisDescriptor: ClassDescriptor, result: MutableList) { + inner.forEach { it.generateConstructors(thisDescriptor, result) } } } diff --git a/plugins/lombok/lombok-compiler-plugin/README.md b/plugins/lombok/lombok-compiler-plugin/README.md index 79360a587f3..b60063f82cb 100644 --- a/plugins/lombok/lombok-compiler-plugin/README.md +++ b/plugins/lombok/lombok-compiler-plugin/README.md @@ -23,9 +23,10 @@ Features support: - [x] Basic support - [ ] Copy annotations -[ ] [@NoArgsConstructor, @RequiredArgsConstructor and @AllArgsConstructor](https://projectlombok.org/features/constructor) - - [ ] Generate constructors - - [ ] Generate static factory method +[~] [@NoArgsConstructor, @RequiredArgsConstructor and @AllArgsConstructor](https://projectlombok.org/features/constructor) + - [x] @NoArgsConstructor + - [ ] @AllArgsConstructor + - [ ] @RequiredArgsConstructor [ ] [@Data](https://projectlombok.org/features/Data) 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 e9bf0cb1666..2bb2c0dfd4d 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 @@ -30,10 +30,10 @@ class LombokSyntheticJavaPartsProvider(private val config: LombokConfig) : Synth private val partsCache: MutableMap = WeakHashMap() - override fun getSyntheticFunctionNames(thisDescriptor: ClassDescriptor): List = + override fun getMethodNames(thisDescriptor: ClassDescriptor): List = getSyntheticParts(thisDescriptor).methods.map { it.name } - override fun generateSyntheticMethods( + override fun generateMethods( thisDescriptor: ClassDescriptor, name: Name, result: MutableCollection @@ -42,7 +42,15 @@ class LombokSyntheticJavaPartsProvider(private val config: LombokConfig) : Synth result.addAll(methods) } - override fun generateSyntheticConstructors(thisDescriptor: ClassDescriptor, result: MutableList) { + override fun getStaticFunctionNames(thisDescriptor: ClassDescriptor): List = + getSyntheticParts(thisDescriptor).staticFunctions.map { it.name } + + override fun generateStaticFunctions(thisDescriptor: ClassDescriptor, name: Name, result: MutableCollection) { + val functions = getSyntheticParts(thisDescriptor).staticFunctions.filter { it.name == name } + result.addAll(functions) + } + + override fun generateConstructors(thisDescriptor: ClassDescriptor, result: MutableList) { val constructors = getSyntheticParts(thisDescriptor).constructors result.addAll(constructors) } 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 66e9967a050..a9054689552 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 @@ -9,6 +9,8 @@ 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 +import org.jetbrains.kotlin.lombok.utils.createFunction +import org.jetbrains.kotlin.name.Name class NoArgsConstructorProcessor : Processor { @@ -21,7 +23,14 @@ class NoArgsConstructorProcessor : Processor { ) Parts(constructors = listOfNotNull(constructor)) } else { - null + val function = classDescriptor.createFunction( + Name.identifier(annotation.staticName), + emptyList(), + classDescriptor.defaultType, + visibility = annotation.visibility, + receiver = null + ) + Parts(staticFunctions = listOf(function)) } } return result ?: Parts.Empty diff --git a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/Parts.kt b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/Parts.kt index 7273dcfded9..f3858c3caba 100644 --- a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/Parts.kt +++ b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/Parts.kt @@ -10,10 +10,15 @@ import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor data class Parts( val methods: List = emptyList(), + val staticFunctions: List = emptyList(), val constructors: List = emptyList() ) { - operator fun plus(other: Parts): Parts = Parts(methods + other.methods, constructors + other.constructors) + operator fun plus(other: Parts): Parts = Parts( + methods + other.methods, + staticFunctions + other.staticFunctions, + constructors + other.constructors + ) companion object { val Empty = Parts() 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 55d25933ec6..137037903c9 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 @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.descriptors.java.JavaVisibilities import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.constants.BooleanValue import org.jetbrains.kotlin.resolve.constants.EnumValue +import org.jetbrains.kotlin.resolve.constants.StringValue internal fun getVisibility(annotation: AnnotationDescriptor, field: String = "value"): DescriptorVisibility { val value = annotation.getStringArgument(field) ?: "PUBLIC" @@ -32,6 +33,7 @@ internal fun AnnotationDescriptor.getStringArgument(argumentName: String): Strin return when (argument) { is EnumValue -> argument.enumEntryName.identifier + is StringValue -> argument.value else -> throw RuntimeException("Argument $argument is not supported") } } 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 244ce7afe22..34bbb807b45 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 @@ -21,7 +21,8 @@ internal fun ClassDescriptor.createFunction( valueParameters: List, returnType: KotlinType?, modality: Modality? = Modality.OPEN, - visibility: DescriptorVisibility = DescriptorVisibilities.PUBLIC + visibility: DescriptorVisibility = DescriptorVisibilities.PUBLIC, + receiver: ReceiverParameterDescriptor? = this.thisAsReceiverParameter ): SimpleFunctionDescriptor { val methodDescriptor = SimpleFunctionDescriptorImpl.create( this, @@ -35,7 +36,7 @@ internal fun ClassDescriptor.createFunction( methodDescriptor.initialize( null, - this.thisAsReceiverParameter, + receiver, mutableListOf(), paramDescriptors, returnType, diff --git a/plugins/lombok/lombok-compiler-plugin/testData/compile/noArgsConstructorStatic.kt b/plugins/lombok/lombok-compiler-plugin/testData/compile/noArgsConstructorStatic.kt new file mode 100644 index 00000000000..ce8985dd7b7 --- /dev/null +++ b/plugins/lombok/lombok-compiler-plugin/testData/compile/noArgsConstructorStatic.kt @@ -0,0 +1,30 @@ +//FILE: ConstructorExample.java + +import lombok.*; + +@NoArgsConstructor(staticName = "make") +public class ConstructorExample { + + public ConstructorExample(String arg) { + + } + + @Getter @Setter private int age = 10; + + @Getter(AccessLevel.PROTECTED) private String name; + + static void javaUsage() { + ConstructorExample existing = new ConstructorExample("existing"); + ConstructorExample generated = ConstructorExample.make(); + } +} + + +//FILE: test.kt + +object Test { + fun usage() { + val existing: ConstructorExample = ConstructorExample("existing") + val generated: ConstructorExample = ConstructorExample.make() + } +} 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 0d28bb4fed6..33a88b32435 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 @@ -51,6 +51,11 @@ public class LombokCompileTestGenerated extends AbstractLombokCompileTest { runTest("plugins/lombok/lombok-compiler-plugin/testData/compile/noArgsConstructor.kt"); } + @TestMetadata("noArgsConstructorStatic.kt") + public void testNoArgsConstructorStatic() throws Exception { + runTest("plugins/lombok/lombok-compiler-plugin/testData/compile/noArgsConstructorStatic.kt"); + } + @TestMetadata("getters.kt") public void testGetters() throws Exception { runTest("plugins/lombok/lombok-compiler-plugin/testData/compile/getters.kt");