org.jetbrains.kotlin.lombok.LombokSyntheticJavaPartsProvider.kt Maven / Gradle / Ivy
/*
* 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
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
import org.jetbrains.kotlin.lombok.config.LombokConfig
import org.jetbrains.kotlin.lombok.processor.*
import org.jetbrains.kotlin.lombok.utils.getJavaClass
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.jvm.SyntheticJavaPartsProvider
import java.util.*
/**
* 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 = listOf(
GetterProcessor(config),
SetterProcessor(config),
WithProcessor(),
NoArgsConstructorProcessor(),
AllArgsConstructorProcessor(),
RequiredArgsConstructorProcessor()
)
/**
* 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 = HashMap()
override fun getMethodNames(thisDescriptor: ClassDescriptor): List =
getSyntheticParts(thisDescriptor).methods.map { it.name }
override fun generateMethods(
thisDescriptor: ClassDescriptor,
name: Name,
result: MutableCollection
) {
val methods = getSyntheticParts(thisDescriptor).methods.filter { it.name == name }
addNonExistent(result, methods)
}
override fun getStaticFunctionNames(thisDescriptor: ClassDescriptor): List =
getSyntheticParts(thisDescriptor).staticFunctions.map { it.name }
override fun generateStaticFunctions(thisDescriptor: ClassDescriptor, name: Name, result: MutableCollection) {
val functions = getSyntheticParts(thisDescriptor).staticFunctions.filter { it.name == name }
addNonExistent(result, functions)
}
override fun generateConstructors(thisDescriptor: ClassDescriptor, result: MutableList) {
val constructors = getSyntheticParts(thisDescriptor).constructors
addNonExistent(result, constructors)
}
private fun getSyntheticParts(descriptor: ClassDescriptor): SyntheticParts =
descriptor.getJavaClass()?.let { _ ->
partsCache.getOrPut(descriptor) {
computeSyntheticParts(descriptor)
}
} ?: SyntheticParts.Empty
private fun computeSyntheticParts(descriptor: ClassDescriptor): SyntheticParts {
val builder = SyntheticPartsBuilder()
processors.forEach { it.contribute(descriptor, builder) }
return builder.build()
}
/**
* Deduplicates generated functions using name and argument counts, as lombok does
*/
private fun addNonExistent(result: MutableCollection, toAdd: List) {
toAdd.forEach { f ->
if (result.none { sameSignature(it, f) }) {
result += f
}
}
}
companion object {
/**
* Lombok treat functions as having the same signature by arguments count only
* Corresponding code in lombok - https://github.com/projectlombok/lombok/blob/v1.18.20/src/core/lombok/javac/handlers/JavacHandlerUtil.java#L752
*/
private fun sameSignature(a: FunctionDescriptor, b: FunctionDescriptor): Boolean {
val aVararg = a.valueParameters.any { it.varargElementType != null }
val bVararg = b.valueParameters.any { it.varargElementType != null }
return aVararg && bVararg ||
aVararg && b.valueParameters.size >= (a.valueParameters.size - 1) ||
bVararg && a.valueParameters.size >= (b.valueParameters.size - 1) ||
a.valueParameters.size == b.valueParameters.size
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy