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 7b34258dd63..df676fa9ce2 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 @@ -17,21 +17,27 @@ import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.jvm.SyntheticJavaPartsProvider import java.util.* -class LombokSyntheticJavaPartsProvider(private val config: LombokConfig) : SyntheticJavaPartsProvider { +/** + * Provides synthetic parts to java classes (from current compilation unit), which will be generated by lombok AnnotationProcessor + * So kotlin can reference lombok members. + */ +class LombokSyntheticJavaPartsProvider(config: LombokConfig) : SyntheticJavaPartsProvider { - private val processors = initProcessors() + private val processors = listOf( + GetterProcessor(config), + SetterProcessor(config), + WithProcessor(), + NoArgsConstructorProcessor(), + AllArgsConstructorProcessor(), + RequiredArgsConstructorProcessor() + ) - private fun initProcessors(): List = - listOf( - GetterProcessor(config), - SetterProcessor(config), - WithProcessor(), - NoArgsConstructorProcessor(), - AllArgsConstructorProcessor(), - RequiredArgsConstructorProcessor() - ) - - private val partsCache: MutableMap = WeakHashMap() + /** + * kotlin resolve references in two calls - first it gets names, then actual member descriptor + * but for us it is much easier to run full generation for class once + * hence we cache results and reuse it + */ + private val partsCache: MutableMap = WeakHashMap() override fun getMethodNames(thisDescriptor: ClassDescriptor): List = getSyntheticParts(thisDescriptor).methods.map { it.name } @@ -61,16 +67,19 @@ class LombokSyntheticJavaPartsProvider(private val config: LombokConfig) : Synth private fun extractClass(descriptor: ClassDescriptor): JavaClassImpl? = (descriptor as? LazyJavaClassDescriptor)?.jClass as? JavaClassImpl - private fun getSyntheticParts(descriptor: ClassDescriptor): Parts = + private fun getSyntheticParts(descriptor: ClassDescriptor): SyntheticParts = extractClass(descriptor)?.let { jClass -> partsCache.getOrPut(descriptor) { computeSyntheticParts(descriptor, jClass) } - } ?: Parts.Empty + } ?: SyntheticParts.Empty - private fun computeSyntheticParts(descriptor: ClassDescriptor, jClass: JavaClassImpl): Parts = - processors.map { it.contribute(descriptor, jClass) }.reduce { a, b -> a + b } + private fun computeSyntheticParts(descriptor: ClassDescriptor, jClass: JavaClassImpl): SyntheticParts = + processors.map { it.contribute(descriptor) }.reduce { a, b -> a + b } + /** + * Deduplicates generated functions using name and argument counts, as lombok does + */ private fun addNonExistent(result: MutableCollection, toAdd: List) { if (toAdd.isEmpty()) return diff --git a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/AbstractConstructorProcessor.kt b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/AbstractConstructorProcessor.kt index 1a7048c4927..38c5e213e13 100644 --- a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/AbstractConstructorProcessor.kt +++ b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/AbstractConstructorProcessor.kt @@ -7,8 +7,6 @@ package org.jetbrains.kotlin.lombok.processor import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor -import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl -import org.jetbrains.kotlin.lombok.config.AnnotationCompanion import org.jetbrains.kotlin.lombok.config.ConstructorAnnotation import org.jetbrains.kotlin.lombok.utils.ValueParameter import org.jetbrains.kotlin.lombok.utils.createJavaConstructor @@ -17,7 +15,7 @@ import org.jetbrains.kotlin.name.Name abstract class AbstractConstructorProcessor : Processor { - override fun contribute(classDescriptor: ClassDescriptor, jClass: JavaClassImpl): Parts { + override fun contribute(classDescriptor: ClassDescriptor): SyntheticParts { val valueParameters = getPropertiesForParameters(classDescriptor).map { property -> ValueParameter(property.name, property.type) } @@ -28,7 +26,7 @@ abstract class AbstractConstructorProcessor : Process valueParameters = valueParameters, visibility = annotation.visibility ) - Parts(constructors = listOfNotNull(constructor)) + SyntheticParts(constructors = listOfNotNull(constructor)) } else { val function = classDescriptor.createFunction( Name.identifier(annotation.staticName!!), @@ -38,10 +36,10 @@ abstract class AbstractConstructorProcessor : Process visibility = annotation.visibility, receiver = null ) - Parts(staticFunctions = listOf(function)) + SyntheticParts(staticFunctions = listOf(function)) } } - return result ?: Parts.Empty + return result ?: SyntheticParts.Empty } protected abstract fun getAnnotation(classDescriptor: ClassDescriptor): A? 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 a1c11b82fc9..a305c9fae1e 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 @@ -8,14 +8,13 @@ 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.* import org.jetbrains.kotlin.lombok.utils.* import org.jetbrains.kotlin.name.Name class GetterProcessor(private val config: LombokConfig) : Processor { - override fun contribute(classDescriptor: ClassDescriptor, jClass: JavaClassImpl): Parts { + override fun contribute(classDescriptor: ClassDescriptor): SyntheticParts { val globalAccessors = Accessors.get(classDescriptor, config) val clGetter = Getter.getOrNull(classDescriptor) @@ -27,7 +26,7 @@ class GetterProcessor(private val config: LombokConfig) : Processor { .collectWithNotNull { Getter.getOrNull(it) ?: clGetter } .mapNotNull { (field, annotation) -> createGetter(classDescriptor, field, annotation, globalAccessors) } - return Parts(functions) + return SyntheticParts(functions) } private fun createGetter( @@ -39,7 +38,7 @@ class GetterProcessor(private val config: LombokConfig) : Processor { if (getter.visibility == AccessLevel.NONE) return null val accessors = Accessors.getIfAnnotated(field, config) ?: globalAccessors - return field.toPropertyName(accessors)?.let { propertyName -> + return field.toAccessorBaseName(accessors)?.let { propertyName -> val functionName = if (accessors.fluent) { propertyName diff --git a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/Processor.kt b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/Processor.kt index 01990dfe94a..5ed69a52411 100644 --- a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/Processor.kt +++ b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/Processor.kt @@ -6,9 +6,11 @@ package org.jetbrains.kotlin.lombok.processor import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl +/** + * Generates synthetic parts for [ClassDescriptor] + */ interface Processor { - fun contribute(classDescriptor: ClassDescriptor, jClass: JavaClassImpl): Parts + fun contribute(classDescriptor: ClassDescriptor): SyntheticParts } 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 e8043e6cc28..cfa5d017b46 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 @@ -6,7 +6,6 @@ package org.jetbrains.kotlin.lombok.processor import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl import org.jetbrains.kotlin.lombok.config.* import org.jetbrains.kotlin.lombok.utils.* import org.jetbrains.kotlin.name.Name @@ -14,9 +13,9 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns class SetterProcessor(private val config: LombokConfig) : Processor { - override fun contribute(classDescriptor: ClassDescriptor, jClass: JavaClassImpl): Parts { + override fun contribute(classDescriptor: ClassDescriptor): SyntheticParts { //lombok doesn't generate setters for enums - if (classDescriptor.kind == ClassKind.ENUM_CLASS) return Parts.Empty + if (classDescriptor.kind == ClassKind.ENUM_CLASS) return SyntheticParts.Empty val globalAccessors = Accessors.get(classDescriptor, config) val clSetter = Setter.getOrNull(classDescriptor) ?: Data.getOrNull(classDescriptor)?.asSetter() @@ -25,7 +24,7 @@ class SetterProcessor(private val config: LombokConfig) : Processor { .getJavaFields() .collectWithNotNull { field -> Setter.getOrNull(field) ?: clSetter.takeIf { field.isVar } } .mapNotNull { (field, setter) -> createSetter(classDescriptor, field, setter, globalAccessors) } - return Parts(functions) + return SyntheticParts(functions) } private fun createSetter( @@ -37,7 +36,7 @@ class SetterProcessor(private val config: LombokConfig) : Processor { if (getter.visibility == AccessLevel.NONE) return null val accessors = Accessors.getIfAnnotated(field, config) ?: globalAccessors - return field.toPropertyName(accessors)?.let { propertyName -> + return field.toAccessorBaseName(accessors)?.let { propertyName -> val functionName = if (accessors.fluent) propertyName else AccessorNames.SET + propertyName.capitalize() diff --git a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/Parts.kt b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/SyntheticParts.kt similarity index 84% rename from plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/Parts.kt rename to plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/SyntheticParts.kt index f3858c3caba..34b394afcd9 100644 --- a/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/Parts.kt +++ b/plugins/lombok/lombok-compiler-plugin/src/org/jetbrains/kotlin/lombok/processor/SyntheticParts.kt @@ -8,19 +8,19 @@ package org.jetbrains.kotlin.lombok.processor import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor -data class Parts( +data class SyntheticParts( val methods: List = emptyList(), val staticFunctions: List = emptyList(), val constructors: List = emptyList() ) { - operator fun plus(other: Parts): Parts = Parts( + operator fun plus(other: SyntheticParts): SyntheticParts = SyntheticParts( methods + other.methods, staticFunctions + other.staticFunctions, constructors + other.constructors ) companion object { - val Empty = Parts() + val Empty = SyntheticParts() } } 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 8aff601a7f1..4ca05970b3a 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 @@ -8,14 +8,13 @@ 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.AccessLevel import org.jetbrains.kotlin.lombok.config.With import org.jetbrains.kotlin.lombok.utils.* import org.jetbrains.kotlin.name.Name class WithProcessor : Processor { - override fun contribute(classDescriptor: ClassDescriptor, jClass: JavaClassImpl): Parts { + override fun contribute(classDescriptor: ClassDescriptor): SyntheticParts { val clWith = With.getOrNull(classDescriptor) @@ -24,7 +23,7 @@ class WithProcessor : Processor { .collectWithNotNull { With.getOrNull(it) ?: clWith } .mapNotNull { (field, annotation) -> createWith(classDescriptor, field, annotation) } - return Parts(functions) + return SyntheticParts(functions) } private fun createWith( 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 67969479470..f3c11179747 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 @@ -14,7 +14,11 @@ object AccessorNames { const val SET = "set" } -fun PropertyDescriptor.toPropertyName(config: Accessors): String? { +/** + * Make property name from variable name + * Returns null in case getter/setter shouldn't be generated at all + */ +fun PropertyDescriptor.toAccessorBaseName(config: Accessors): String? { val isPrimitiveBoolean = type.isPrimitiveBoolean() return if (config.prefix.isEmpty()) { val prefixes = if (isPrimitiveBoolean) listOf(AccessorNames.IS) else emptyList() 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 8c7b2c87cb8..b8c9a807e3d 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 @@ -15,9 +15,7 @@ import org.junit.runner.RunWith; import java.io.File; import java.util.regex.Pattern; -/** - * This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY - */ +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ @SuppressWarnings("all") @TestMetadata("plugins/lombok/lombok-compiler-plugin/testData/compile") @TestDataPath("$PROJECT_ROOT") @@ -27,10 +25,6 @@ public class LombokCompileTestGenerated extends AbstractLombokCompileTest { KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); } - public void testAllFilesPresentInCompile() throws Exception { - KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/lombok/lombok-compiler-plugin/testData/compile"), Pattern.compile("^(.+)\\.kt$"), null, true); - } - @TestMetadata("accessorsStripPrefix.kt") public void testAccessorsStripPrefix() throws Exception { runTest("plugins/lombok/lombok-compiler-plugin/testData/compile/accessorsStripPrefix.kt"); @@ -51,6 +45,10 @@ public class LombokCompileTestGenerated extends AbstractLombokCompileTest { runTest("plugins/lombok/lombok-compiler-plugin/testData/compile/allArgsConstructorStatic.kt"); } + public void testAllFilesPresentInCompile() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/lombok/lombok-compiler-plugin/testData/compile"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + @TestMetadata("clashAccessors.kt") public void testClashAccessors() throws Exception { runTest("plugins/lombok/lombok-compiler-plugin/testData/compile/clashAccessors.kt"); @@ -76,6 +74,26 @@ public class LombokCompileTestGenerated extends AbstractLombokCompileTest { runTest("plugins/lombok/lombok-compiler-plugin/testData/compile/data.kt"); } + @TestMetadata("genericsAccessors.kt") + public void testGenericsAccessors() throws Exception { + runTest("plugins/lombok/lombok-compiler-plugin/testData/compile/genericsAccessors.kt"); + } + + @TestMetadata("genericsConstructors.kt") + public void testGenericsConstructors() throws Exception { + runTest("plugins/lombok/lombok-compiler-plugin/testData/compile/genericsConstructors.kt"); + } + + @TestMetadata("genericsConstructorsStatic.kt") + public void testGenericsConstructorsStatic() throws Exception { + runTest("plugins/lombok/lombok-compiler-plugin/testData/compile/genericsConstructorsStatic.kt"); + } + + @TestMetadata("getters.kt") + public void testGetters() throws Exception { + runTest("plugins/lombok/lombok-compiler-plugin/testData/compile/getters.kt"); + } + @TestMetadata("gettersClassLevel.kt") public void testGettersClassLevel() throws Exception { runTest("plugins/lombok/lombok-compiler-plugin/testData/compile/gettersClassLevel.kt"); @@ -106,26 +124,6 @@ public class LombokCompileTestGenerated extends AbstractLombokCompileTest { runTest("plugins/lombok/lombok-compiler-plugin/testData/compile/requiredArgsConstructorStatic.kt"); } - @TestMetadata("genericsAccessors.kt") - public void testGenericsAccessors() throws Exception { - runTest("plugins/lombok/lombok-compiler-plugin/testData/compile/genericsAccessors.kt"); - } - - @TestMetadata("genericsConstructors.kt") - public void testGenericsConstructors() throws Exception { - runTest("plugins/lombok/lombok-compiler-plugin/testData/compile/genericsConstructors.kt"); - } - - @TestMetadata("genericsConstructorsStatic.kt") - public void testGenericsConstructorsStatic() throws Exception { - runTest("plugins/lombok/lombok-compiler-plugin/testData/compile/genericsConstructorsStatic.kt"); - } - - @TestMetadata("getters.kt") - public void testGetters() throws Exception { - 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");