diff --git a/plugins/lombok/lombok-compiler-plugin/README.md b/plugins/lombok/lombok-compiler-plugin/README.md index b60063f82cb..3af9af34056 100644 --- a/plugins/lombok/lombok-compiler-plugin/README.md +++ b/plugins/lombok/lombok-compiler-plugin/README.md @@ -25,7 +25,7 @@ Features support: [~] [@NoArgsConstructor, @RequiredArgsConstructor and @AllArgsConstructor](https://projectlombok.org/features/constructor) - [x] @NoArgsConstructor - - [ ] @AllArgsConstructor + - [x] @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 2bb2c0dfd4d..37aac5d08a7 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,7 +25,8 @@ class LombokSyntheticJavaPartsProvider(private val config: LombokConfig) : Synth GetterProcessor(config), SetterProcessor(config), WithProcessor(config), - NoArgsConstructorProcessor() + NoArgsConstructorProcessor(), + AllArgsConstructorProcessor() ) 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 c05697e7031..f0dd55c9010 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,9 +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.* +import org.jetbrains.kotlin.lombok.utils.LombokNames import org.jetbrains.kotlin.lombok.utils.getBooleanArgument -import org.jetbrains.kotlin.lombok.utils.getStringArgument +import org.jetbrains.kotlin.lombok.utils.getNonBlankStringArgument import org.jetbrains.kotlin.lombok.utils.getVisibility import org.jetbrains.kotlin.name.FqName @@ -82,7 +82,22 @@ data class NoArgsConstructor( override fun extract(annotation: AnnotationDescriptor): NoArgsConstructor = NoArgsConstructor( visibility = getVisibility(annotation), - staticName = annotation.getStringArgument("staticName").trimToNull() + staticName = annotation.getNonBlankStringArgument("staticName") + ) + } +} + +data class AllArgsConstructor( + val visibility: DescriptorVisibility, + val staticName: String? +) { + companion object : AnnotationCompanion() { + override val name: FqName = LombokNames.ALL_ARGS_CONSTRUCTOR + + override fun extract(annotation: AnnotationDescriptor): AllArgsConstructor = + AllArgsConstructor( + visibility = getVisibility(annotation), + staticName = annotation.getNonBlankStringArgument("staticName") ) } } 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 new file mode 100644 index 00000000000..cdad5931f2e --- /dev/null +++ b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/AllArgsConstructorProcessor.kt @@ -0,0 +1,46 @@ +/* + * 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.AllArgsConstructor +import org.jetbrains.kotlin.lombok.utils.ValueParameter +import org.jetbrains.kotlin.lombok.utils.createConstructor +import org.jetbrains.kotlin.lombok.utils.createFunction +import org.jetbrains.kotlin.lombok.utils.getJavaFields +import org.jetbrains.kotlin.name.Name + +class AllArgsConstructorProcessor : Processor { + + override fun contribute(classDescriptor: ClassDescriptor, jClass: JavaClassImpl): Parts { + + val valueParameters = classDescriptor.getJavaFields().map { property -> + ValueParameter(property.name, property.type) + } + + val result = AllArgsConstructor.getOrNull(classDescriptor)?.let { annotation -> + if (annotation.staticName == null) { + val constructor = classDescriptor.createConstructor( + valueParameters = valueParameters, + visibility = annotation.visibility + ) + Parts(constructors = listOfNotNull(constructor)) + } else { + val function = classDescriptor.createFunction( + Name.identifier(annotation.staticName), + valueParameters, + 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/GetterProcessor.kt b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/GetterProcessor.kt index dd98793e070..0f212cf74a2 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 @@ -14,7 +14,7 @@ import org.jetbrains.kotlin.lombok.config.Getter import org.jetbrains.kotlin.lombok.config.LombokConfig import org.jetbrains.kotlin.lombok.utils.collectWithNotNull import org.jetbrains.kotlin.lombok.utils.createFunction -import org.jetbrains.kotlin.lombok.utils.getVariables +import org.jetbrains.kotlin.lombok.utils.getJavaFields import org.jetbrains.kotlin.lombok.utils.toPreparedBase import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.types.KotlinType @@ -30,7 +30,7 @@ class GetterProcessor(private val config: LombokConfig) : Processor { val clGetter = Getter.getOrNull(classDescriptor) val functions = classDescriptor - .getVariables() + .getJavaFields() .collectWithNotNull { Getter.getOrNull(it) ?: clGetter } .mapNotNull { (field, annotation) -> createGetter(classDescriptor, field, annotation, clAccessors) } 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 00330b76df2..7ae3802a457 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 @@ -24,7 +24,7 @@ class SetterProcessor(private val config: LombokConfig) : Processor { val clSetter = Setter.getOrNull(classDescriptor) val functions = classDescriptor - .getVariables() + .getJavaFields() .collectWithNotNull { field -> Setter.getOrNull(field) ?: clSetter.takeIf { field.isVar } } .mapNotNull { (field, setter) -> createSetter(classDescriptor, field, setter, clAccessors) } return Parts(functions) 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 4e2f26463de..03602931a96 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 @@ -20,7 +20,7 @@ class WithProcessor(private val config: LombokConfig) : Processor { val clWith = With.getOrNull(classDescriptor) val functions = classDescriptor - .getVariables() + .getJavaFields() .collectWithNotNull { With.getOrNull(it) ?: clWith } .mapNotNull { (field, annotation) -> createWith(classDescriptor, field, annotation) } 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 0f1a0840ed5..ea1122252c5 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 @@ -14,5 +14,6 @@ object LombokNames { val SETTER = FqName("lombok.Setter") val WITH = FqName("lombok.With") val NO_ARGS_CONSTRUCTOR = FqName("lombok.NoArgsConstructor") + val ALL_ARGS_CONSTRUCTOR = FqName("lombok.AllArgsConstructor") } 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 137037903c9..bfa4f4262d7 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 import org.jetbrains.kotlin.resolve.constants.StringValue -internal fun getVisibility(annotation: AnnotationDescriptor, field: String = "value"): DescriptorVisibility { +fun getVisibility(annotation: AnnotationDescriptor, field: String = "value"): DescriptorVisibility { val value = annotation.getStringArgument(field) ?: "PUBLIC" val visibility = when (value) { "PUBLIC" -> Visibilities.Public @@ -27,7 +27,7 @@ internal fun getVisibility(annotation: AnnotationDescriptor, field: String = "va return DescriptorVisibilities.toDescriptorVisibility(visibility) } -internal fun AnnotationDescriptor.getStringArgument(argumentName: String): String? { +fun AnnotationDescriptor.getStringArgument(argumentName: String): String? { val argument = allValueArguments[Name.identifier(argumentName)] ?: return null @@ -38,7 +38,10 @@ internal fun AnnotationDescriptor.getStringArgument(argumentName: String): Strin } } -internal fun AnnotationDescriptor.getBooleanArgument(argumentName: String, default: Boolean = false): Boolean { +fun AnnotationDescriptor.getNonBlankStringArgument(argumentName: String): String? = + getStringArgument(argumentName).trimToNull() + +fun AnnotationDescriptor.getBooleanArgument(argumentName: String, default: Boolean = false): Boolean { val argument = allValueArguments[Name.identifier(argumentName)] ?: return default 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 34bbb807b45..3d243e34531 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 @@ -11,12 +11,13 @@ 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 +import org.jetbrains.kotlin.load.java.lazy.descriptors.isJavaField import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.types.KotlinType -internal data class ValueParameter(val name: Name, val type: KotlinType) +data class ValueParameter(val name: Name, val type: KotlinType) -internal fun ClassDescriptor.createFunction( +fun ClassDescriptor.createFunction( name: Name, valueParameters: List, returnType: KotlinType?, @@ -46,7 +47,7 @@ internal fun ClassDescriptor.createFunction( return methodDescriptor } -internal fun ClassDescriptor.createConstructor( +fun ClassDescriptor.createConstructor( valueParameters: List, visibility: DescriptorVisibility = DescriptorVisibilities.PUBLIC ): ClassConstructorDescriptor { @@ -85,8 +86,8 @@ private fun CallableDescriptor.makeValueParameter(param: ValueParameter, index: ) } -internal fun ClassDescriptor.getVariables(): List = +fun ClassDescriptor.getJavaFields(): List = this.unsubstitutedMemberScope.getVariableNames() .map { this.unsubstitutedMemberScope.getContributedVariables(it, NoLookupLocation.FROM_SYNTHETIC_SCOPE).single() - } + }.filter { it.isJavaField } 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 de816afd75e..53121836f1f 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 @@ -7,4 +7,4 @@ package org.jetbrains.kotlin.lombok.utils import org.jetbrains.kotlin.util.capitalizeDecapitalize.capitalizeAsciiOnly -internal fun toPreparedBase(name: String): String = name.capitalizeAsciiOnly() +fun toPreparedBase(name: String): String = name.capitalizeAsciiOnly() 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 d11d3b7971a..dc5bb7f8afd 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 @@ -6,7 +6,7 @@ package org.jetbrains.kotlin.lombok.utils @Suppress("UNCHECKED_CAST") -internal fun Collection.collectWithNotNull(f: (E) -> R?): List> = +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() } +fun String?.trimToNull(): String? = this?.trim()?.takeIf { it.isNotEmpty() } diff --git a/plugins/lombok/lombok-compiler-plugin/testData/compile/allArgsConstructor.kt b/plugins/lombok/lombok-compiler-plugin/testData/compile/allArgsConstructor.kt new file mode 100644 index 00000000000..bea64758af7 --- /dev/null +++ b/plugins/lombok/lombok-compiler-plugin/testData/compile/allArgsConstructor.kt @@ -0,0 +1,26 @@ +//FILE: ConstructorExample.java + +import lombok.*; + +@AllArgsConstructor +public class ConstructorExample { + + @Getter @Setter private int age = 10; + + @Getter(AccessLevel.PROTECTED) private String name; + + private boolean otherField; + + static void javaUsage() { + val generated = new ConstructorExample(12, "sdf", true); + } +} + + +//FILE: test.kt + +object Test { + fun usage() { + val generated = ConstructorExample(12, "sdf", true) + } +} diff --git a/plugins/lombok/lombok-compiler-plugin/testData/compile/allArgsConstructorStatic.kt b/plugins/lombok/lombok-compiler-plugin/testData/compile/allArgsConstructorStatic.kt new file mode 100644 index 00000000000..e1175001dba --- /dev/null +++ b/plugins/lombok/lombok-compiler-plugin/testData/compile/allArgsConstructorStatic.kt @@ -0,0 +1,32 @@ +//FILE: ConstructorExample.java + +import lombok.*; + +@AllArgsConstructor(staticName = "of") +public class ConstructorExample { + + @Getter @Setter private int age = 10; + + @Getter(AccessLevel.PROTECTED) private String name; + + private boolean otherField; + + public ConstructorExample(String arg) { + + } + + static void javaUsage() { + ConstructorExample existing = new ConstructorExample("existing"); + ConstructorExample generated = ConstructorExample.of(45, "234", false); + } +} + + +//FILE: test.kt + +object Test { + fun usage() { + val existing: ConstructorExample = ConstructorExample("existing") + val generated: ConstructorExample = ConstructorExample.of(45, "234", false) + } +} 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 33a88b32435..9f7a1709373 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 @@ -36,6 +36,16 @@ public class LombokCompileTestGenerated extends AbstractLombokCompileTest { runTest("plugins/lombok/lombok-compiler-plugin/testData/compile/configSimple.kt"); } + @TestMetadata("allArgsConstructor.kt") + public void testAllArgsConstructor() throws Exception { + runTest("plugins/lombok/lombok-compiler-plugin/testData/compile/allArgsConstructor.kt"); + } + + @TestMetadata("allArgsConstructorStatic.kt") + public void testAllArgsConstructorStatic() throws Exception { + runTest("plugins/lombok/lombok-compiler-plugin/testData/compile/allArgsConstructorStatic.kt"); + } + @TestMetadata("gettersClassLevel.kt") public void testGettersClassLevel() throws Exception { runTest("plugins/lombok/lombok-compiler-plugin/testData/compile/gettersClassLevel.kt");