[lombok] Generate no-arg constructor

This commit is contained in:
Andrey Zinovyev
2021-03-26 13:39:14 +03:00
committed by TeamCityServer
parent e9a33e0335
commit 37926f333e
10 changed files with 115 additions and 5 deletions
@@ -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)
@@ -25,6 +25,7 @@ class LombokSyntheticJavaPartsProvider(private val config: LombokConfig) : Synth
GetterProcessor(config),
SetterProcessor(config),
WithProcessor(config),
NoArgsConstructorProcessor()
)
private val partsCache: MutableMap<ClassDescriptor, Parts> = WeakHashMap()
@@ -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<NoArgsConstructor>() {
override val name: FqName = LombokNames.NO_ARGS_CONSTRUCTOR
override fun extract(annotation: AnnotationDescriptor): NoArgsConstructor =
NoArgsConstructor(
visibility = getVisibility(annotation),
staticName = annotation.getStringArgument("staticName").trimToNull()
)
}
}
@@ -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
}
}
@@ -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")
}
@@ -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
@@ -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<ValueParameter>,
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,
@@ -8,3 +8,5 @@ package org.jetbrains.kotlin.lombok.utils
@Suppress("UNCHECKED_CAST")
internal 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() }
@@ -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()
}
}
@@ -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");