[lombok] @Setter support
This commit is contained in:
committed by
TeamCityServer
parent
70e3877efc
commit
7fd8f7b3bc
+5
-4
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.lombok.config.LombokConfig
|
|||||||
import org.jetbrains.kotlin.lombok.processor.GetterProcessor
|
import org.jetbrains.kotlin.lombok.processor.GetterProcessor
|
||||||
import org.jetbrains.kotlin.lombok.processor.Parts
|
import org.jetbrains.kotlin.lombok.processor.Parts
|
||||||
import org.jetbrains.kotlin.lombok.processor.Processor
|
import org.jetbrains.kotlin.lombok.processor.Processor
|
||||||
|
import org.jetbrains.kotlin.lombok.processor.SetterProcessor
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.resolve.jvm.SyntheticJavaPartsProvider
|
import org.jetbrains.kotlin.resolve.jvm.SyntheticJavaPartsProvider
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@@ -23,7 +24,8 @@ class LombokSyntheticJavaPartsProvider(private val config: LombokConfig) : Synth
|
|||||||
|
|
||||||
private fun initProcessors(): List<Processor> =
|
private fun initProcessors(): List<Processor> =
|
||||||
listOf(
|
listOf(
|
||||||
GetterProcessor(config)
|
GetterProcessor(config),
|
||||||
|
SetterProcessor(config)
|
||||||
)
|
)
|
||||||
|
|
||||||
private val partsCache: MutableMap<ClassDescriptor, Parts> = WeakHashMap()
|
private val partsCache: MutableMap<ClassDescriptor, Parts> = WeakHashMap()
|
||||||
@@ -36,9 +38,8 @@ class LombokSyntheticJavaPartsProvider(private val config: LombokConfig) : Synth
|
|||||||
name: Name,
|
name: Name,
|
||||||
result: MutableCollection<SimpleFunctionDescriptor>
|
result: MutableCollection<SimpleFunctionDescriptor>
|
||||||
) {
|
) {
|
||||||
getSyntheticParts(thisDescriptor).methods.find { it.name == name }?.let {
|
val methods = getSyntheticParts(thisDescriptor).methods.filter { it.name == name }
|
||||||
result.add(it)
|
result.addAll(methods)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun extractClass(descriptor: ClassDescriptor): JavaClassImpl? =
|
private fun extractClass(descriptor: ClassDescriptor): JavaClassImpl? =
|
||||||
|
|||||||
+11
@@ -48,3 +48,14 @@ data class Getter(val visibility: DescriptorVisibility) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class Setter(val visibility: DescriptorVisibility) {
|
||||||
|
companion object : AnnotationCompanion<Setter>() {
|
||||||
|
override val name: FqName = LombokNames.SETTER
|
||||||
|
|
||||||
|
override fun extract(annotation: AnnotationDescriptor): Setter =
|
||||||
|
Setter(
|
||||||
|
visibility = getVisibility(annotation)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+6
-11
@@ -8,12 +8,13 @@ package org.jetbrains.kotlin.lombok.processor
|
|||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
|
||||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
|
||||||
import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl
|
import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl
|
||||||
import org.jetbrains.kotlin.lombok.config.Accessors
|
import org.jetbrains.kotlin.lombok.config.Accessors
|
||||||
import org.jetbrains.kotlin.lombok.config.Getter
|
import org.jetbrains.kotlin.lombok.config.Getter
|
||||||
import org.jetbrains.kotlin.lombok.config.LombokConfig
|
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.createFunction
|
||||||
|
import org.jetbrains.kotlin.lombok.utils.getVariables
|
||||||
import org.jetbrains.kotlin.lombok.utils.toPreparedBase
|
import org.jetbrains.kotlin.lombok.utils.toPreparedBase
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
@@ -28,10 +29,9 @@ class GetterProcessor(private val config: LombokConfig) : Processor {
|
|||||||
val clAccessors = Accessors.getOrNull(classDescriptor)
|
val clAccessors = Accessors.getOrNull(classDescriptor)
|
||||||
val clGetter = Getter.getOrNull(classDescriptor)
|
val clGetter = Getter.getOrNull(classDescriptor)
|
||||||
|
|
||||||
val functions = classDescriptor.unsubstitutedMemberScope.getVariableNames()
|
val functions = classDescriptor
|
||||||
.map {
|
.getVariables()
|
||||||
classDescriptor.unsubstitutedMemberScope.getContributedVariables(it, NoLookupLocation.FROM_SYNTHETIC_SCOPE).single()
|
.collectWithNotNull { Getter.getOrNull(it) ?: clGetter }
|
||||||
}.collectWithNotNull { Getter.getOrNull(it) ?: clGetter }
|
|
||||||
.mapNotNull { (field, annotation) -> createGetter(classDescriptor, field, annotation, clAccessors) }
|
.mapNotNull { (field, annotation) -> createGetter(classDescriptor, field, annotation, clAccessors) }
|
||||||
|
|
||||||
return Parts(functions)
|
return Parts(functions)
|
||||||
@@ -52,8 +52,7 @@ class GetterProcessor(private val config: LombokConfig) : Processor {
|
|||||||
val prefix = if (field.type.isPrimitiveBoolean() && !noIsPrefix) "is" else "get"
|
val prefix = if (field.type.isPrimitiveBoolean() && !noIsPrefix) "is" else "get"
|
||||||
prefix + toPreparedBase(field.name.identifier)
|
prefix + toPreparedBase(field.name.identifier)
|
||||||
}
|
}
|
||||||
return createFunction(
|
return classDescriptor.createFunction(
|
||||||
classDescriptor,
|
|
||||||
Name.identifier(functionName),
|
Name.identifier(functionName),
|
||||||
emptyList(),
|
emptyList(),
|
||||||
field.returnType,
|
field.returnType,
|
||||||
@@ -61,10 +60,6 @@ class GetterProcessor(private val config: LombokConfig) : Processor {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@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>>
|
|
||||||
|
|
||||||
private fun KotlinType.isPrimitiveBoolean(): Boolean = this is SimpleTypeMarker && isBoolean() //todo
|
private fun KotlinType.isPrimitiveBoolean(): Boolean = this is SimpleTypeMarker && isBoolean() //todo
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+56
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* 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.descriptors.PropertyDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
|
||||||
|
import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl
|
||||||
|
import org.jetbrains.kotlin.lombok.config.Accessors
|
||||||
|
import org.jetbrains.kotlin.lombok.config.LombokConfig
|
||||||
|
import org.jetbrains.kotlin.lombok.config.Setter
|
||||||
|
import org.jetbrains.kotlin.lombok.utils.*
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||||
|
|
||||||
|
class SetterProcessor(private val config: LombokConfig) : Processor {
|
||||||
|
|
||||||
|
override fun contribute(classDescriptor: ClassDescriptor, jClass: JavaClassImpl): Parts {
|
||||||
|
val clAccessors = Accessors.getOrNull(classDescriptor)
|
||||||
|
val clSetter = Setter.getOrNull(classDescriptor)
|
||||||
|
|
||||||
|
val functions = classDescriptor
|
||||||
|
.getVariables()
|
||||||
|
.collectWithNotNull { field -> Setter.getOrNull(field) ?: clSetter.takeIf { field.isVar } }
|
||||||
|
.mapNotNull { (field, setter) -> createSetter(classDescriptor, field, setter, clAccessors) }
|
||||||
|
return Parts(functions)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createSetter(
|
||||||
|
classDescriptor: ClassDescriptor,
|
||||||
|
field: PropertyDescriptor,
|
||||||
|
getter: Setter,
|
||||||
|
classLevelAccessors: Accessors?
|
||||||
|
): SimpleFunctionDescriptor? {
|
||||||
|
val accessors = Accessors.getOrNull(field) ?: classLevelAccessors ?: Accessors.default
|
||||||
|
|
||||||
|
val functionName =
|
||||||
|
if (accessors.fluent) {
|
||||||
|
field.name.identifier
|
||||||
|
} else {
|
||||||
|
"set" + toPreparedBase(field.name.identifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
val returnType = if (accessors.chain) classDescriptor.defaultType else classDescriptor.builtIns.unitType
|
||||||
|
|
||||||
|
return classDescriptor.createFunction(
|
||||||
|
Name.identifier(functionName),
|
||||||
|
listOf(ValueParameter(field.name, field.type)),
|
||||||
|
returnType,
|
||||||
|
visibility = getter.visibility
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
+35
-7
@@ -8,32 +8,60 @@ package org.jetbrains.kotlin.lombok.utils
|
|||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
|
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.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
internal fun createFunction(
|
internal data class ValueParameter(val name: Name, val type: KotlinType)
|
||||||
containingClass: ClassDescriptor,
|
|
||||||
|
internal fun ClassDescriptor.createFunction(
|
||||||
name: Name,
|
name: Name,
|
||||||
valueParameters: List<ValueParameterDescriptor>,
|
valueParameters: List<ValueParameter>,
|
||||||
returnType: KotlinType?,
|
returnType: KotlinType?,
|
||||||
modality: Modality? = Modality.OPEN,
|
modality: Modality? = Modality.OPEN,
|
||||||
visibility: DescriptorVisibility = DescriptorVisibilities.PUBLIC
|
visibility: DescriptorVisibility = DescriptorVisibilities.PUBLIC
|
||||||
): SimpleFunctionDescriptor {
|
): SimpleFunctionDescriptor {
|
||||||
val methodDescriptor = SimpleFunctionDescriptorImpl.create(
|
val methodDescriptor = SimpleFunctionDescriptorImpl.create(
|
||||||
containingClass,
|
this,
|
||||||
Annotations.EMPTY,
|
Annotations.EMPTY,
|
||||||
name,
|
name,
|
||||||
CallableMemberDescriptor.Kind.SYNTHESIZED,
|
CallableMemberDescriptor.Kind.SYNTHESIZED,
|
||||||
containingClass.source
|
this.source
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val paramDescriptors = valueParameters.mapIndexed { idx, param -> methodDescriptor.makeValueParameter(param, idx) }
|
||||||
|
|
||||||
methodDescriptor.initialize(
|
methodDescriptor.initialize(
|
||||||
null,
|
null,
|
||||||
containingClass.thisAsReceiverParameter,
|
this.thisAsReceiverParameter,
|
||||||
mutableListOf(),
|
mutableListOf(),
|
||||||
valueParameters,
|
paramDescriptors,
|
||||||
returnType,
|
returnType,
|
||||||
modality,
|
modality,
|
||||||
visibility
|
visibility
|
||||||
)
|
)
|
||||||
return methodDescriptor
|
return methodDescriptor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun FunctionDescriptor.makeValueParameter(param: ValueParameter, index: Int): ValueParameterDescriptor {
|
||||||
|
return ValueParameterDescriptorImpl(
|
||||||
|
containingDeclaration = this,
|
||||||
|
original = null,
|
||||||
|
index = index,
|
||||||
|
annotations = Annotations.EMPTY,
|
||||||
|
name = param.name,
|
||||||
|
outType = param.type,
|
||||||
|
declaresDefaultValue = false,
|
||||||
|
isCrossinline = false,
|
||||||
|
isNoinline = false,
|
||||||
|
varargElementType = null,
|
||||||
|
source = this.source
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun ClassDescriptor.getVariables(): List<PropertyDescriptor> =
|
||||||
|
this.unsubstitutedMemberScope.getVariableNames()
|
||||||
|
.map {
|
||||||
|
this.unsubstitutedMemberScope.getContributedVariables(it, NoLookupLocation.FROM_SYNTHETIC_SCOPE).single()
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
/*
|
||||||
|
* 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.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>>
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
//FILE: SetterTest.java
|
||||||
|
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
public class SetterTest {
|
||||||
|
@Getter @Setter private int age = 10;
|
||||||
|
|
||||||
|
@Setter(AccessLevel.PROTECTED) private String name;
|
||||||
|
|
||||||
|
@Setter private boolean primitiveBoolean;
|
||||||
|
|
||||||
|
void test() {
|
||||||
|
setAge(12);
|
||||||
|
setPrimitiveBoolean(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//FILE: test.kt
|
||||||
|
|
||||||
|
object Test {
|
||||||
|
fun usage() {
|
||||||
|
val obj = SetterTest()
|
||||||
|
obj.setAge(42)
|
||||||
|
obj.age = 42
|
||||||
|
|
||||||
|
//synthetic property generated only when there is a getter
|
||||||
|
// obj.primitiveBoolean = false
|
||||||
|
obj.setPrimitiveBoolean(true)
|
||||||
|
|
||||||
|
//shouldn't be accesible from here
|
||||||
|
// obj.setName("abc")
|
||||||
|
}
|
||||||
|
|
||||||
|
class OverridenGetterTest : SetterTest() {
|
||||||
|
fun usage() {
|
||||||
|
setName("abc")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
//FILE: SetterTest.java
|
||||||
|
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter @Setter
|
||||||
|
public class SetterTest {
|
||||||
|
private int age = 10;
|
||||||
|
|
||||||
|
private final String finalName = "zzz";
|
||||||
|
|
||||||
|
private boolean primitiveBoolean;
|
||||||
|
|
||||||
|
void test() {
|
||||||
|
setAge(12);
|
||||||
|
setPrimitiveBoolean(true);
|
||||||
|
//no setters generated for final variable
|
||||||
|
// setFinalName("adsf");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//FILE: test.kt
|
||||||
|
|
||||||
|
object Test {
|
||||||
|
fun usage() {
|
||||||
|
val obj = SetterTest()
|
||||||
|
obj.setAge(42)
|
||||||
|
obj.age = 42
|
||||||
|
|
||||||
|
obj.setPrimitiveBoolean(true)
|
||||||
|
|
||||||
|
|
||||||
|
// no setters generated for final variable
|
||||||
|
// obj.setFinalName("error")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
//FILE: SetterTest.java
|
||||||
|
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
public class SetterTest {
|
||||||
|
@Accessors(fluent = true) private int fluent;
|
||||||
|
|
||||||
|
@Accessors(chain = true) private String chained;
|
||||||
|
|
||||||
|
@Accessors(chain = true, fluent = true) private String whyNotBoth;
|
||||||
|
|
||||||
|
|
||||||
|
void test() {
|
||||||
|
fluent(12);
|
||||||
|
setChained("zz").getChained();
|
||||||
|
whyNotBoth("zzz").whyNotBoth();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//FILE: test.kt
|
||||||
|
|
||||||
|
object Test {
|
||||||
|
fun usage() {
|
||||||
|
val obj = SetterTest()
|
||||||
|
obj.fluent(12);
|
||||||
|
obj.setChained("zz").getChained()
|
||||||
|
obj.whyNotBoth("zzz").whyNotBoth()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+15
@@ -51,6 +51,21 @@ public class LombokCompileTestGenerated extends AbstractLombokCompileTest {
|
|||||||
runTest("plugins/lombok/lombok-compiler-plugin/testData/compile/getters.kt");
|
runTest("plugins/lombok/lombok-compiler-plugin/testData/compile/getters.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("setters.kt")
|
||||||
|
public void testSetters() throws Exception {
|
||||||
|
runTest("plugins/lombok/lombok-compiler-plugin/testData/compile/setters.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("settersClassLevel.kt")
|
||||||
|
public void testSettersClassLevel() throws Exception {
|
||||||
|
runTest("plugins/lombok/lombok-compiler-plugin/testData/compile/settersClassLevel.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("settersVariations.kt")
|
||||||
|
public void testSettersVariations() throws Exception {
|
||||||
|
runTest("plugins/lombok/lombok-compiler-plugin/testData/compile/settersVariations.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("simple.kt")
|
@TestMetadata("simple.kt")
|
||||||
public void testSimple() throws Exception {
|
public void testSimple() throws Exception {
|
||||||
runTest("plugins/lombok/lombok-compiler-plugin/testData/compile/simple.kt");
|
runTest("plugins/lombok/lombok-compiler-plugin/testData/compile/simple.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user