[lombok] Support @AllArgsConstructor

This commit is contained in:
Andrey Zinovyev
2021-03-26 15:33:10 +03:00
committed by TeamCityServer
parent 59f936fdef
commit b336a335bf
15 changed files with 155 additions and 20 deletions
@@ -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)
@@ -25,7 +25,8 @@ class LombokSyntheticJavaPartsProvider(private val config: LombokConfig) : Synth
GetterProcessor(config),
SetterProcessor(config),
WithProcessor(config),
NoArgsConstructorProcessor()
NoArgsConstructorProcessor(),
AllArgsConstructorProcessor()
)
private val partsCache: MutableMap<ClassDescriptor, Parts> = WeakHashMap()
@@ -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<AllArgsConstructor>() {
override val name: FqName = LombokNames.ALL_ARGS_CONSTRUCTOR
override fun extract(annotation: AnnotationDescriptor): AllArgsConstructor =
AllArgsConstructor(
visibility = getVisibility(annotation),
staticName = annotation.getNonBlankStringArgument("staticName")
)
}
}
@@ -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
}
}
@@ -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) }
@@ -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)
@@ -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) }
@@ -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")
}
@@ -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
@@ -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<ValueParameter>,
returnType: KotlinType?,
@@ -46,7 +47,7 @@ internal fun ClassDescriptor.createFunction(
return methodDescriptor
}
internal fun ClassDescriptor.createConstructor(
fun ClassDescriptor.createConstructor(
valueParameters: List<ValueParameter>,
visibility: DescriptorVisibility = DescriptorVisibilities.PUBLIC
): ClassConstructorDescriptor {
@@ -85,8 +86,8 @@ private fun CallableDescriptor.makeValueParameter(param: ValueParameter, index:
)
}
internal fun ClassDescriptor.getVariables(): List<PropertyDescriptor> =
fun ClassDescriptor.getJavaFields(): List<PropertyDescriptor> =
this.unsubstitutedMemberScope.getVariableNames()
.map {
this.unsubstitutedMemberScope.getContributedVariables(it, NoLookupLocation.FROM_SYNTHETIC_SCOPE).single()
}
}.filter { it.isJavaField }
@@ -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()
@@ -6,7 +6,7 @@
package org.jetbrains.kotlin.lombok.utils
@Suppress("UNCHECKED_CAST")
internal fun <E, R> Collection<E>.collectWithNotNull(f: (E) -> R?): List<Pair<E, R>> =
fun <E, R> Collection<E>.collectWithNotNull(f: (E) -> R?): List<Pair<E, R>> =
map { it to f(it) }.filter { it.second != null } as List<Pair<E, R>>
internal fun String?.trimToNull(): String? = this?.trim()?.takeIf { it.isNotEmpty() }
fun String?.trimToNull(): String? = this?.trim()?.takeIf { it.isNotEmpty() }
@@ -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)
}
}
@@ -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)
}
}
@@ -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");