org.jetbrains.kotlin.lombok.LombokSyntheticJavaPartsProvider.kt Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2010-2022 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.*
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext
import org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaClassDescriptor
import org.jetbrains.kotlin.load.java.lazy.descriptors.SyntheticJavaClassDescriptor
import org.jetbrains.kotlin.lombok.config.LombokConfig
import org.jetbrains.kotlin.lombok.processor.*
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.
*/
@Suppress("IncorrectFormatting") // KTIJ-22227
class LombokSyntheticJavaPartsProvider(config: LombokConfig) : SyntheticJavaPartsProvider {
private val processors = listOf(
GetterProcessor(config),
SetterProcessor(config),
WithProcessor(),
NoArgsConstructorProcessor(),
AllArgsConstructorProcessor(),
RequiredArgsConstructorProcessor(),
BuilderProcessor(config)
)
private val valueFieldModifier = ValueFieldModifier(config)
/**
* 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, c: LazyJavaResolverContext): List =
c.getSyntheticParts(thisDescriptor).methods.map { it.name }
override fun generateMethods(
thisDescriptor: ClassDescriptor,
name: Name,
result: MutableCollection,
c: LazyJavaResolverContext,
) {
val methods = c.getSyntheticParts(thisDescriptor).methods.filter { it.name == name }
addNonExistent(result, methods)
}
override fun getStaticFunctionNames(thisDescriptor: ClassDescriptor, c: LazyJavaResolverContext): List =
c.getSyntheticParts(thisDescriptor).staticFunctions.map { it.name }
override fun generateStaticFunctions(
thisDescriptor: ClassDescriptor,
name: Name,
result: MutableCollection,
c: LazyJavaResolverContext,
) {
val functions = c.getSyntheticParts(thisDescriptor).staticFunctions.filter { it.name == name }
addNonExistent(result, functions)
}
override fun generateConstructors(
thisDescriptor: ClassDescriptor,
result: MutableList,
c: LazyJavaResolverContext,
) {
val constructors = c.getSyntheticParts(thisDescriptor).constructors
addNonExistent(result, constructors)
}
override fun getNestedClassNames(thisDescriptor: ClassDescriptor, c: LazyJavaResolverContext): List {
return c.getSyntheticParts(thisDescriptor).classes.map { it.name }
}
override fun generateNestedClass(
thisDescriptor: ClassDescriptor,
name: Name,
result: MutableList,
c: LazyJavaResolverContext,
) {
result += c.getSyntheticParts(thisDescriptor).classes.filter { it.name == name }
}
private fun LazyJavaResolverContext.getSyntheticParts(descriptor: ClassDescriptor): SyntheticParts {
if (descriptor !is LazyJavaClassDescriptor && descriptor !is SyntheticJavaClassDescriptor) return SyntheticParts.Empty
return partsCache.getOrPut(descriptor) {
computeSyntheticParts(descriptor)
}
}
private fun LazyJavaResolverContext.computeSyntheticParts(descriptor: ClassDescriptor): SyntheticParts {
val builder = SyntheticPartsBuilder()
processors.forEach { it.contribute(descriptor, builder, this) }
return builder.build()
}
override fun modifyField(
thisDescriptor: ClassDescriptor,
propertyDescriptor: PropertyDescriptorImpl,
c: LazyJavaResolverContext
): PropertyDescriptorImpl {
return valueFieldModifier.modifyField(thisDescriptor, propertyDescriptor) ?: propertyDescriptor
}
/**
* 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 - 2024 Weber Informatics LLC | Privacy Policy