[lombok] Use config values as default in annotation parsing

This commit is contained in:
Andrey Zinovyev
2021-03-30 15:52:45 +03:00
committed by TeamCityServer
parent c7b2c731af
commit 8a2279de2b
8 changed files with 144 additions and 26 deletions
@@ -13,7 +13,13 @@ Features support:
- [x] Basic support
- [x] Class-level
- [x] @Accessors config support: chain and fluent
- [ ] Config support (_lombok.getter.noIsPrefix_ only supported atm)
- [~] Config support
- [x] lombok.getter.noIsPrefix
- [x] lombok.accessors.fluent
- [x] lombok.accessors.chain
- [ ] lombok.accessors.prefix
- [ ] lombok.noArgsConstructor.extraPrivate
- [ ] lombok.copyableAnnotations
- [ ] Copy annotations
- [ ] Strip defined prefixes - in config and @Accessors
- [ ] Skip generation with AccessLevel.NONE
@@ -15,6 +15,14 @@ import org.jetbrains.kotlin.lombok.utils.getNonBlankStringArgument
import org.jetbrains.kotlin.lombok.utils.getVisibility
import org.jetbrains.kotlin.name.FqName
/*
* Lombok has two ways of configuration - lombok.config file and directly in annotations. Annotations has priority.
* Not all things can be configured in annotations
* So to make things easier I put all configuration in 'annotations' classes, but populate them from config too. So far it allows
* keeping processors' code unaware about configuration origin.
*
*/
abstract class AnnotationCompanion<T> {
abstract val name: FqName
@@ -25,19 +33,44 @@ abstract class AnnotationCompanion<T> {
annotated.annotations.findAnnotation(name)?.let(this::extract)
}
abstract class AnnotationAndConfigCompanion<T> {
abstract val annotationName: FqName
abstract fun extract(annotation: AnnotationDescriptor?, config: LombokConfig): T
/**
* Get from annotation or config or default
*/
fun get(annotated: Annotated, config: LombokConfig): T =
extract(annotated.annotations.findAnnotation(annotationName), config)
/**
* If element is annotated, get from it or config or default
*/
fun getIfAnnotated(annotated: Annotated, config: LombokConfig): T? =
annotated.annotations.findAnnotation(annotationName)?.let { annotation ->
extract(annotation, config)
}
}
data class Accessors(val fluent: Boolean = false, val chain: Boolean = false) {
companion object : AnnotationCompanion<Accessors>() {
companion object : AnnotationAndConfigCompanion<Accessors>() {
val default = Accessors()
override val annotationName: FqName = LombokNames.ACCESSORS
override val name: FqName = LombokNames.ACCESSORS
override fun extract(annotation: AnnotationDescriptor): Accessors {
val fluent = annotation.getBooleanArgument("fluent")
return Accessors(
fluent = fluent,
chain = annotation.getBooleanArgument("chain", default = fluent)
)
override fun extract(annotation: AnnotationDescriptor?, config: LombokConfig): Accessors {
val fluent =
annotation?.getBooleanArgument("fluent")
?: config.getBoolean("lombok.accessors.fluent")
?: false
val chain =
annotation?.getBooleanArgument("chain")
?: config.getBoolean("lombok.accessors.chain")
?: fluent
return Accessors(fluent, chain)
}
}
}
@@ -24,7 +24,7 @@ class GetterProcessor(private val config: LombokConfig) : Processor {
private val noIsPrefix by lazy { config.getBooleanOrDefault("lombok.getter.noIsPrefix") }
override fun contribute(classDescriptor: ClassDescriptor, jClass: JavaClassImpl): Parts {
val clAccessors = Accessors.getOrNull(classDescriptor)
val globalAccessors = Accessors.get(classDescriptor, config)
val clGetter =
Getter.getOrNull(classDescriptor)
?: Data.getOrNull(classDescriptor)?.asGetter()
@@ -33,7 +33,7 @@ class GetterProcessor(private val config: LombokConfig) : Processor {
val functions = classDescriptor
.getJavaFields()
.collectWithNotNull { Getter.getOrNull(it) ?: clGetter }
.mapNotNull { (field, annotation) -> createGetter(classDescriptor, field, annotation, clAccessors) }
.mapNotNull { (field, annotation) -> createGetter(classDescriptor, field, annotation, globalAccessors) }
return Parts(functions)
}
@@ -42,9 +42,9 @@ class GetterProcessor(private val config: LombokConfig) : Processor {
classDescriptor: ClassDescriptor,
field: PropertyDescriptor,
getter: Getter,
classLevelAccessors: Accessors?
globalAccessors: Accessors
): SimpleFunctionDescriptor? {
val accessors = Accessors.getOrNull(field) ?: classLevelAccessors ?: Accessors.default
val accessors = Accessors.getIfAnnotated(field, config) ?: globalAccessors
val functionName =
if (accessors.fluent) {
@@ -21,13 +21,13 @@ class SetterProcessor(private val config: LombokConfig) : Processor {
//lombok doesn't generate setters for enums
if (classDescriptor.kind == ClassKind.ENUM_CLASS) return Parts.Empty
val clAccessors = Accessors.getOrNull(classDescriptor)
val globalAccessors = Accessors.get(classDescriptor, config)
val clSetter = Setter.getOrNull(classDescriptor) ?: Data.getOrNull(classDescriptor)?.asSetter()
val functions = classDescriptor
.getJavaFields()
.collectWithNotNull { field -> Setter.getOrNull(field) ?: clSetter.takeIf { field.isVar } }
.mapNotNull { (field, setter) -> createSetter(classDescriptor, field, setter, clAccessors) }
.mapNotNull { (field, setter) -> createSetter(classDescriptor, field, setter, globalAccessors) }
return Parts(functions)
}
@@ -35,9 +35,9 @@ class SetterProcessor(private val config: LombokConfig) : Processor {
classDescriptor: ClassDescriptor,
field: PropertyDescriptor,
getter: Setter,
classLevelAccessors: Accessors?
globalAccessors: Accessors
): SimpleFunctionDescriptor? {
val accessors = Accessors.getOrNull(field) ?: classLevelAccessors ?: Accessors.default
val accessors = Accessors.getIfAnnotated(field, config) ?: globalAccessors
val functionName =
if (accessors.fluent) {
@@ -42,9 +42,9 @@ fun AnnotationDescriptor.getStringArgument(argumentName: String): String? {
fun AnnotationDescriptor.getNonBlankStringArgument(argumentName: String): String? =
getStringArgument(argumentName).trimToNull()
fun AnnotationDescriptor.getBooleanArgument(argumentName: String, default: Boolean = false): Boolean {
fun AnnotationDescriptor.getBooleanArgument(argumentName: String): Boolean? {
val argument = allValueArguments[Name.identifier(argumentName)]
?: return default
?: return null
return when (argument) {
is BooleanValue -> argument.value
@@ -0,0 +1,33 @@
//FILE: GetterTest.java
import lombok.*;
@Getter @Setter
public class GetterTest {
private String name;
private int age;
static void test() {
val obj = new GetterTest();
GetterTest ref = obj.name("some").age(34);
obj.name();
obj.age();
}
}
//FILE: test.kt
class Test {
fun run() {
val obj = GetterTest()
val ref: GetterTest = obj.name("some").age(34)
obj.name()
obj.age()
}
}
//FILE: lombok.config
lombok.accessors.fluent=true
//lombok.accessors.chain=false
@@ -0,0 +1,36 @@
//FILE: GetterTest.java
import lombok.*;
import lombok.experimental.*;
@Getter @Setter
public class GetterTest {
private String name;
private int age;
@Accessors(chain = true)
private boolean fluent;
static void test() {
val obj = new GetterTest();
GetterTest ref = obj.fluent(true);
obj.name();
obj.age();
}
}
//FILE: test.kt
class Test {
fun run() {
val obj = GetterTest()
val ref: GetterTest = obj.fluent(true)
obj.name()
obj.age()
}
}
//FILE: lombok.config
lombok.accessors.fluent=true
lombok.accessors.chain=false
@@ -31,11 +31,6 @@ public class LombokCompileTestGenerated extends AbstractLombokCompileTest {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/lombok/lombok-compiler-plugin/testData/compile"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@TestMetadata("configSimple.kt")
public void testConfigSimple() throws Exception {
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");
@@ -51,6 +46,21 @@ public class LombokCompileTestGenerated extends AbstractLombokCompileTest {
runTest("plugins/lombok/lombok-compiler-plugin/testData/compile/clashAccessors.kt");
}
@TestMetadata("configAccessors.kt")
public void testConfigAccessors() throws Exception {
runTest("plugins/lombok/lombok-compiler-plugin/testData/compile/configAccessors.kt");
}
@TestMetadata("configAccessorsOverride.kt")
public void testConfigAccessorsOverride() throws Exception {
runTest("plugins/lombok/lombok-compiler-plugin/testData/compile/configAccessorsOverride.kt");
}
@TestMetadata("configSimple.kt")
public void testConfigSimple() throws Exception {
runTest("plugins/lombok/lombok-compiler-plugin/testData/compile/configSimple.kt");
}
@TestMetadata("data.kt")
public void testData() throws Exception {
runTest("plugins/lombok/lombok-compiler-plugin/testData/compile/data.kt");