[Lombok K2] Support @Builder and @Singular annotations
^KT-46959 Fixed
This commit is contained in:
@@ -125,7 +125,7 @@ class FirJavaClass @FirImplementationDetail internal constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@FirBuilderDsl
|
@FirBuilderDsl
|
||||||
internal class FirJavaClassBuilder : FirRegularClassBuilder(), FirAnnotationContainerBuilder {
|
class FirJavaClassBuilder : FirRegularClassBuilder(), FirAnnotationContainerBuilder {
|
||||||
lateinit var visibility: Visibility
|
lateinit var visibility: Visibility
|
||||||
var modality: Modality? = null
|
var modality: Modality? = null
|
||||||
var isFromSource: Boolean by Delegates.notNull()
|
var isFromSource: Boolean by Delegates.notNull()
|
||||||
@@ -174,6 +174,6 @@ internal class FirJavaClassBuilder : FirRegularClassBuilder(), FirAnnotationCont
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal inline fun buildJavaClass(init: FirJavaClassBuilder.() -> Unit): FirJavaClass {
|
inline fun buildJavaClass(init: FirJavaClassBuilder.() -> Unit): FirJavaClass {
|
||||||
return FirJavaClassBuilder().apply(init).build()
|
return FirJavaClassBuilder().apply(init).build()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ object LombokNames {
|
|||||||
val WITH_ID = ClassId.topLevel(WITH)
|
val WITH_ID = ClassId.topLevel(WITH)
|
||||||
val DATA_ID = ClassId.topLevel(DATA)
|
val DATA_ID = ClassId.topLevel(DATA)
|
||||||
val VALUE_ID = ClassId.topLevel(VALUE)
|
val VALUE_ID = ClassId.topLevel(VALUE)
|
||||||
|
val BUILDER_ID = ClassId.topLevel(BUILDER)
|
||||||
|
val SINGULAR_ID = ClassId.topLevel(SINGULAR)
|
||||||
val NO_ARGS_CONSTRUCTOR_ID = ClassId.topLevel(NO_ARGS_CONSTRUCTOR)
|
val NO_ARGS_CONSTRUCTOR_ID = ClassId.topLevel(NO_ARGS_CONSTRUCTOR)
|
||||||
val ALL_ARGS_CONSTRUCTOR_ID = ClassId.topLevel(ALL_ARGS_CONSTRUCTOR)
|
val ALL_ARGS_CONSTRUCTOR_ID = ClassId.topLevel(ALL_ARGS_CONSTRUCTOR)
|
||||||
val REQUIRED_ARGS_CONSTRUCTOR_ID = ClassId.topLevel(REQUIRED_ARGS_CONSTRUCTOR)
|
val REQUIRED_ARGS_CONSTRUCTOR_ID = ClassId.topLevel(REQUIRED_ARGS_CONSTRUCTOR)
|
||||||
|
|||||||
@@ -17,5 +17,6 @@ class FirLombokRegistrar(private val lombokConfigFile: File?) : FirExtensionRegi
|
|||||||
+::SetterGenerator
|
+::SetterGenerator
|
||||||
+::WithGenerator
|
+::WithGenerator
|
||||||
+::LombokConstructorsGenerator
|
+::LombokConstructorsGenerator
|
||||||
|
+::BuilderGenerator
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-1
@@ -17,11 +17,13 @@ import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
|||||||
import org.jetbrains.kotlin.lombok.config.LombokConfig
|
import org.jetbrains.kotlin.lombok.config.LombokConfig
|
||||||
import org.jetbrains.kotlin.lombok.k2.config.ConeLombokAnnotations.Accessors
|
import org.jetbrains.kotlin.lombok.k2.config.ConeLombokAnnotations.Accessors
|
||||||
import org.jetbrains.kotlin.lombok.k2.config.ConeLombokAnnotations.AllArgsConstructor
|
import org.jetbrains.kotlin.lombok.k2.config.ConeLombokAnnotations.AllArgsConstructor
|
||||||
|
import org.jetbrains.kotlin.lombok.k2.config.ConeLombokAnnotations.Builder
|
||||||
import org.jetbrains.kotlin.lombok.k2.config.ConeLombokAnnotations.Data
|
import org.jetbrains.kotlin.lombok.k2.config.ConeLombokAnnotations.Data
|
||||||
import org.jetbrains.kotlin.lombok.k2.config.ConeLombokAnnotations.Getter
|
import org.jetbrains.kotlin.lombok.k2.config.ConeLombokAnnotations.Getter
|
||||||
import org.jetbrains.kotlin.lombok.k2.config.ConeLombokAnnotations.NoArgsConstructor
|
import org.jetbrains.kotlin.lombok.k2.config.ConeLombokAnnotations.NoArgsConstructor
|
||||||
import org.jetbrains.kotlin.lombok.k2.config.ConeLombokAnnotations.RequiredArgsConstructor
|
import org.jetbrains.kotlin.lombok.k2.config.ConeLombokAnnotations.RequiredArgsConstructor
|
||||||
import org.jetbrains.kotlin.lombok.k2.config.ConeLombokAnnotations.Setter
|
import org.jetbrains.kotlin.lombok.k2.config.ConeLombokAnnotations.Setter
|
||||||
|
import org.jetbrains.kotlin.lombok.k2.config.ConeLombokAnnotations.Singular
|
||||||
import org.jetbrains.kotlin.lombok.k2.config.ConeLombokAnnotations.Value
|
import org.jetbrains.kotlin.lombok.k2.config.ConeLombokAnnotations.Value
|
||||||
import org.jetbrains.kotlin.lombok.k2.config.ConeLombokAnnotations.With
|
import org.jetbrains.kotlin.lombok.k2.config.ConeLombokAnnotations.With
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@@ -34,7 +36,7 @@ class LombokService(session: FirSession, configFile: File?) : FirExtensionSessio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val config = configFile?.let(LombokConfig::parse) ?: LombokConfig.Empty
|
val config = configFile?.let(LombokConfig::parse) ?: LombokConfig.Empty
|
||||||
private val cachesFactory = session.firCachesFactory
|
private val cachesFactory = session.firCachesFactory
|
||||||
|
|
||||||
private val accessorsCache: Cache<Accessors> = cachesFactory.createCache { symbol ->
|
private val accessorsCache: Cache<Accessors> = cachesFactory.createCache { symbol ->
|
||||||
@@ -77,6 +79,14 @@ class LombokService(session: FirSession, configFile: File?) : FirExtensionSessio
|
|||||||
Value.getOrNull(symbol.fir)
|
Value.getOrNull(symbol.fir)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val builderCache: Cache<Builder?> = cachesFactory.createCache { symbol ->
|
||||||
|
Builder.getIfAnnotated(symbol.fir, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val singularCache: Cache<Singular?> = cachesFactory.createCache { symbol ->
|
||||||
|
Singular.getOrNull(symbol.fir)
|
||||||
|
}
|
||||||
|
|
||||||
fun getAccessors(symbol: FirBasedSymbol<*>): Accessors = accessorsCache.getValue(symbol)
|
fun getAccessors(symbol: FirBasedSymbol<*>): Accessors = accessorsCache.getValue(symbol)
|
||||||
fun getAccessorsIfAnnotated(symbol: FirBasedSymbol<*>): Accessors? = accessorsIfAnnotatedCache.getValue(symbol)
|
fun getAccessorsIfAnnotated(symbol: FirBasedSymbol<*>): Accessors? = accessorsIfAnnotatedCache.getValue(symbol)
|
||||||
fun getGetter(symbol: FirBasedSymbol<*>): Getter? = getterCache.getValue(symbol)
|
fun getGetter(symbol: FirBasedSymbol<*>): Getter? = getterCache.getValue(symbol)
|
||||||
@@ -87,6 +97,8 @@ class LombokService(session: FirSession, configFile: File?) : FirExtensionSessio
|
|||||||
fun getRequiredArgsConstructor(symbol: FirBasedSymbol<*>): RequiredArgsConstructor? = requiredArgsConstructorCache.getValue(symbol)
|
fun getRequiredArgsConstructor(symbol: FirBasedSymbol<*>): RequiredArgsConstructor? = requiredArgsConstructorCache.getValue(symbol)
|
||||||
fun getData(symbol: FirBasedSymbol<*>): Data? = dataCache.getValue(symbol)
|
fun getData(symbol: FirBasedSymbol<*>): Data? = dataCache.getValue(symbol)
|
||||||
fun getValue(symbol: FirBasedSymbol<*>): Value? = valueCache.getValue(symbol)
|
fun getValue(symbol: FirBasedSymbol<*>): Value? = valueCache.getValue(symbol)
|
||||||
|
fun getBuilder(symbol: FirBasedSymbol<*>): Builder? = builderCache.getValue(symbol)
|
||||||
|
fun getSingular(symbol: FirBasedSymbol<*>): Singular? = singularCache.getValue(symbol)
|
||||||
}
|
}
|
||||||
|
|
||||||
private typealias Cache<T> = FirCache<FirBasedSymbol<*>, T, Nothing?>
|
private typealias Cache<T> = FirCache<FirBasedSymbol<*>, T, Nothing?>
|
||||||
|
|||||||
+56
-3
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.descriptors.Visibilities
|
|||||||
import org.jetbrains.kotlin.descriptors.Visibility
|
import org.jetbrains.kotlin.descriptors.Visibility
|
||||||
import org.jetbrains.kotlin.fir.FirAnnotationContainer
|
import org.jetbrains.kotlin.fir.FirAnnotationContainer
|
||||||
import org.jetbrains.kotlin.fir.declarations.getBooleanArgument
|
import org.jetbrains.kotlin.fir.declarations.getBooleanArgument
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.getStringArgument
|
||||||
import org.jetbrains.kotlin.fir.declarations.getStringArrayArgument
|
import org.jetbrains.kotlin.fir.declarations.getStringArrayArgument
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
||||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||||
@@ -16,15 +17,23 @@ import org.jetbrains.kotlin.fir.types.coneTypeSafe
|
|||||||
import org.jetbrains.kotlin.lombok.config.AccessLevel
|
import org.jetbrains.kotlin.lombok.config.AccessLevel
|
||||||
import org.jetbrains.kotlin.lombok.config.LombokConfig
|
import org.jetbrains.kotlin.lombok.config.LombokConfig
|
||||||
import org.jetbrains.kotlin.lombok.k2.config.LombokConfigNames.ACCESS
|
import org.jetbrains.kotlin.lombok.k2.config.LombokConfigNames.ACCESS
|
||||||
|
import org.jetbrains.kotlin.lombok.k2.config.LombokConfigNames.BUILDER_CLASS_NAME
|
||||||
|
import org.jetbrains.kotlin.lombok.k2.config.LombokConfigNames.BUILDER_CLASS_NAME_CONFIG
|
||||||
|
import org.jetbrains.kotlin.lombok.k2.config.LombokConfigNames.BUILDER_METHOD_NAME
|
||||||
|
import org.jetbrains.kotlin.lombok.k2.config.LombokConfigNames.BUILD_METHOD_NAME
|
||||||
import org.jetbrains.kotlin.lombok.k2.config.LombokConfigNames.CHAIN
|
import org.jetbrains.kotlin.lombok.k2.config.LombokConfigNames.CHAIN
|
||||||
import org.jetbrains.kotlin.lombok.k2.config.LombokConfigNames.CHAIN_CONFIG
|
import org.jetbrains.kotlin.lombok.k2.config.LombokConfigNames.CHAIN_CONFIG
|
||||||
import org.jetbrains.kotlin.lombok.k2.config.LombokConfigNames.FLUENT
|
import org.jetbrains.kotlin.lombok.k2.config.LombokConfigNames.FLUENT
|
||||||
import org.jetbrains.kotlin.lombok.k2.config.LombokConfigNames.FLUENT_CONFIG
|
import org.jetbrains.kotlin.lombok.k2.config.LombokConfigNames.FLUENT_CONFIG
|
||||||
|
import org.jetbrains.kotlin.lombok.k2.config.LombokConfigNames.IGNORE_NULL_COLLECTIONS
|
||||||
import org.jetbrains.kotlin.lombok.k2.config.LombokConfigNames.NO_IS_PREFIX_CONFIG
|
import org.jetbrains.kotlin.lombok.k2.config.LombokConfigNames.NO_IS_PREFIX_CONFIG
|
||||||
import org.jetbrains.kotlin.lombok.k2.config.LombokConfigNames.PREFIX
|
import org.jetbrains.kotlin.lombok.k2.config.LombokConfigNames.PREFIX
|
||||||
import org.jetbrains.kotlin.lombok.k2.config.LombokConfigNames.PREFIX_CONFIG
|
import org.jetbrains.kotlin.lombok.k2.config.LombokConfigNames.PREFIX_CONFIG
|
||||||
|
import org.jetbrains.kotlin.lombok.k2.config.LombokConfigNames.SETTER_PREFIX
|
||||||
import org.jetbrains.kotlin.lombok.k2.config.LombokConfigNames.STATIC_CONSTRUCTOR
|
import org.jetbrains.kotlin.lombok.k2.config.LombokConfigNames.STATIC_CONSTRUCTOR
|
||||||
import org.jetbrains.kotlin.lombok.k2.config.LombokConfigNames.STATIC_NAME
|
import org.jetbrains.kotlin.lombok.k2.config.LombokConfigNames.STATIC_NAME
|
||||||
|
import org.jetbrains.kotlin.lombok.k2.config.LombokConfigNames.TO_BUILDER
|
||||||
|
import org.jetbrains.kotlin.lombok.k2.config.LombokConfigNames.VALUE
|
||||||
import org.jetbrains.kotlin.lombok.utils.LombokNames
|
import org.jetbrains.kotlin.lombok.utils.LombokNames
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
|
|
||||||
@@ -97,7 +106,7 @@ object ConeLombokAnnotations {
|
|||||||
class Getter(val visibility: AccessLevel = AccessLevel.PUBLIC) {
|
class Getter(val visibility: AccessLevel = AccessLevel.PUBLIC) {
|
||||||
companion object : ConeAnnotationCompanion<Getter>(LombokNames.GETTER_ID) {
|
companion object : ConeAnnotationCompanion<Getter>(LombokNames.GETTER_ID) {
|
||||||
override fun extract(annotation: FirAnnotation): Getter = Getter(
|
override fun extract(annotation: FirAnnotation): Getter = Getter(
|
||||||
visibility = getAccessLevel(annotation)
|
visibility = annotation.getAccessLevel()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -105,7 +114,7 @@ object ConeLombokAnnotations {
|
|||||||
class Setter(val visibility: AccessLevel = AccessLevel.PUBLIC) {
|
class Setter(val visibility: AccessLevel = AccessLevel.PUBLIC) {
|
||||||
companion object : ConeAnnotationCompanion<Setter>(LombokNames.SETTER_ID) {
|
companion object : ConeAnnotationCompanion<Setter>(LombokNames.SETTER_ID) {
|
||||||
override fun extract(annotation: FirAnnotation): Setter = Setter(
|
override fun extract(annotation: FirAnnotation): Setter = Setter(
|
||||||
visibility = getAccessLevel(annotation)
|
visibility = annotation.getAccessLevel()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -113,7 +122,7 @@ object ConeLombokAnnotations {
|
|||||||
class With(val visibility: AccessLevel = AccessLevel.PUBLIC) {
|
class With(val visibility: AccessLevel = AccessLevel.PUBLIC) {
|
||||||
companion object : ConeAnnotationCompanion<With>(LombokNames.WITH_ID) {
|
companion object : ConeAnnotationCompanion<With>(LombokNames.WITH_ID) {
|
||||||
override fun extract(annotation: FirAnnotation): With = With(
|
override fun extract(annotation: FirAnnotation): With = With(
|
||||||
visibility = getAccessLevel(annotation)
|
visibility = annotation.getAccessLevel()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -188,6 +197,50 @@ object ConeLombokAnnotations {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Builder(
|
||||||
|
val builderClassName: String,
|
||||||
|
val buildMethodName: String,
|
||||||
|
val builderMethodName: String,
|
||||||
|
val requiresToBuilder: Boolean,
|
||||||
|
val visibility: AccessLevel,
|
||||||
|
val setterPrefix: String?
|
||||||
|
) {
|
||||||
|
companion object : ConeAnnotationAndConfigCompanion<Builder>(LombokNames.BUILDER_ID) {
|
||||||
|
private const val DEFAULT_BUILDER_CLASS_NAME = "*Builder"
|
||||||
|
private const val DEFAULT_BUILD_METHOD_NAME = "build"
|
||||||
|
private const val DEFAULT_BUILDER_METHOD_NAME = "builder"
|
||||||
|
private const val DEFAULT_REQUIRES_TO_BUILDER = false
|
||||||
|
|
||||||
|
|
||||||
|
override fun extract(annotation: FirAnnotation?, config: LombokConfig): Builder {
|
||||||
|
return Builder(
|
||||||
|
builderClassName = annotation?.getStringArgument(BUILDER_CLASS_NAME)
|
||||||
|
?: config.getString(BUILDER_CLASS_NAME_CONFIG)
|
||||||
|
?: DEFAULT_BUILDER_CLASS_NAME,
|
||||||
|
buildMethodName = annotation?.getStringArgument(BUILD_METHOD_NAME) ?: DEFAULT_BUILD_METHOD_NAME,
|
||||||
|
builderMethodName = annotation?.getStringArgument(BUILDER_METHOD_NAME) ?: DEFAULT_BUILDER_METHOD_NAME,
|
||||||
|
requiresToBuilder = annotation?.getBooleanArgument(TO_BUILDER) ?: DEFAULT_REQUIRES_TO_BUILDER,
|
||||||
|
visibility = annotation?.getAccessLevel(ACCESS) ?: AccessLevel.PUBLIC,
|
||||||
|
setterPrefix = annotation?.getStringArgument(SETTER_PREFIX)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Singular(
|
||||||
|
val singularName: String?,
|
||||||
|
val allowNull: Boolean,
|
||||||
|
) {
|
||||||
|
companion object : ConeAnnotationCompanion<Singular>(LombokNames.SINGULAR_ID) {
|
||||||
|
override fun extract(annotation: FirAnnotation): Singular {
|
||||||
|
return Singular(
|
||||||
|
singularName = annotation.getStringArgument(VALUE),
|
||||||
|
allowNull = annotation.getBooleanArgument(IGNORE_NULL_COLLECTIONS) ?: false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+11
-3
@@ -17,8 +17,8 @@ import org.jetbrains.kotlin.lombok.config.AccessLevel
|
|||||||
import org.jetbrains.kotlin.lombok.utils.trimToNull
|
import org.jetbrains.kotlin.lombok.utils.trimToNull
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
fun getAccessLevel(annotation: FirAnnotation, field: Name = LombokConfigNames.VALUE): AccessLevel {
|
fun FirAnnotation.getAccessLevel(field: Name = LombokConfigNames.VALUE): AccessLevel {
|
||||||
val value = annotation.getArgumentAsString(field) ?: return AccessLevel.PUBLIC
|
val value = getArgumentAsString(field) ?: return AccessLevel.PUBLIC
|
||||||
return AccessLevel.valueOf(value)
|
return AccessLevel.valueOf(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ private fun FirAnnotation.getArgumentAsString(field: Name): String? {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getVisibility(annotation: FirAnnotation, field: Name = LombokConfigNames.VALUE): Visibility {
|
fun getVisibility(annotation: FirAnnotation, field: Name = LombokConfigNames.VALUE): Visibility {
|
||||||
return getAccessLevel(annotation, field).toVisibility()
|
return annotation.getAccessLevel(field).toVisibility()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun FirAnnotation.getNonBlankStringArgument(name: Name): String? = getStringArgument(name)?.trimToNull()
|
fun FirAnnotation.getNonBlankStringArgument(name: Name): String? = getStringArgument(name)?.trimToNull()
|
||||||
@@ -53,9 +53,17 @@ object LombokConfigNames {
|
|||||||
val STATIC_NAME = Name.identifier("staticName")
|
val STATIC_NAME = Name.identifier("staticName")
|
||||||
val STATIC_CONSTRUCTOR = Name.identifier("staticConstructor")
|
val STATIC_CONSTRUCTOR = Name.identifier("staticConstructor")
|
||||||
|
|
||||||
|
val BUILDER_CLASS_NAME = Name.identifier("builderClassName")
|
||||||
|
val BUILD_METHOD_NAME = Name.identifier("buildMethodName")
|
||||||
|
val BUILDER_METHOD_NAME = Name.identifier("builderMethodName")
|
||||||
|
val TO_BUILDER = Name.identifier("toBuilder")
|
||||||
|
val SETTER_PREFIX = Name.identifier("setterPrefix")
|
||||||
|
val IGNORE_NULL_COLLECTIONS = Name.identifier("ignoreNullCollections")
|
||||||
|
|
||||||
|
|
||||||
const val FLUENT_CONFIG = "lombok.accessors.fluent"
|
const val FLUENT_CONFIG = "lombok.accessors.fluent"
|
||||||
const val CHAIN_CONFIG = "lombok.accessors.chain"
|
const val CHAIN_CONFIG = "lombok.accessors.chain"
|
||||||
const val PREFIX_CONFIG = "lombok.accessors.prefix"
|
const val PREFIX_CONFIG = "lombok.accessors.prefix"
|
||||||
const val NO_IS_PREFIX_CONFIG = "lombok.getter.noIsPrefix"
|
const val NO_IS_PREFIX_CONFIG = "lombok.getter.noIsPrefix"
|
||||||
|
const val BUILDER_CLASS_NAME_CONFIG = "lombok.builder.className"
|
||||||
}
|
}
|
||||||
|
|||||||
+384
@@ -0,0 +1,384 @@
|
|||||||
|
/*
|
||||||
|
* 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.k2.generators
|
||||||
|
|
||||||
|
import com.intellij.openapi.util.text.StringUtil
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
|
import org.jetbrains.kotlin.descriptors.Visibility
|
||||||
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
|
import org.jetbrains.kotlin.fir.caches.FirCache
|
||||||
|
import org.jetbrains.kotlin.fir.caches.createCache
|
||||||
|
import org.jetbrains.kotlin.fir.caches.firCachesFactory
|
||||||
|
import org.jetbrains.kotlin.fir.caches.getValue
|
||||||
|
import org.jetbrains.kotlin.fir.containingClassForStaticMemberAttr
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.builder.buildConstructedClassTypeParameterRef
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.builder.buildOuterClassTypeParameterRef
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.utils.classId
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.utils.effectiveVisibility
|
||||||
|
import org.jetbrains.kotlin.fir.extensions.FirDeclarationGenerationExtension
|
||||||
|
import org.jetbrains.kotlin.fir.extensions.MemberGenerationContext
|
||||||
|
import org.jetbrains.kotlin.fir.java.JavaScopeProvider
|
||||||
|
import org.jetbrains.kotlin.fir.java.declarations.*
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.defaultType
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||||
|
import org.jetbrains.kotlin.fir.toEffectiveVisibility
|
||||||
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
|
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||||
|
import org.jetbrains.kotlin.fir.types.jvm.FirJavaTypeRef
|
||||||
|
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||||
|
import org.jetbrains.kotlin.load.java.structure.JavaClassifierType
|
||||||
|
import org.jetbrains.kotlin.load.java.structure.JavaType
|
||||||
|
import org.jetbrains.kotlin.lombok.config.LombokConfig
|
||||||
|
import org.jetbrains.kotlin.lombok.k2.*
|
||||||
|
import org.jetbrains.kotlin.lombok.k2.config.ConeLombokAnnotations.Builder
|
||||||
|
import org.jetbrains.kotlin.lombok.k2.config.ConeLombokAnnotations.Singular
|
||||||
|
import org.jetbrains.kotlin.lombok.k2.config.LombokService
|
||||||
|
import org.jetbrains.kotlin.lombok.k2.config.lombokService
|
||||||
|
import org.jetbrains.kotlin.lombok.k2.java.*
|
||||||
|
import org.jetbrains.kotlin.lombok.utils.LombokNames
|
||||||
|
import org.jetbrains.kotlin.lombok.utils.capitalize
|
||||||
|
import org.jetbrains.kotlin.name.CallableId
|
||||||
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
|
class BuilderGenerator(session: FirSession) : FirDeclarationGenerationExtension(session) {
|
||||||
|
companion object {
|
||||||
|
private const val TO_BUILDER = "toBuilder"
|
||||||
|
}
|
||||||
|
|
||||||
|
private val lombokService: LombokService
|
||||||
|
get() = session.lombokService
|
||||||
|
|
||||||
|
private val builderClassCache: FirCache<FirClassSymbol<*>, FirJavaClass?, Nothing?> =
|
||||||
|
session.firCachesFactory.createCache(::createBuilderClass)
|
||||||
|
|
||||||
|
private val functionsCache: FirCache<FirClassSymbol<*>, Map<Name, List<FirJavaMethod>>?, Nothing?> =
|
||||||
|
session.firCachesFactory.createCache(::createFunctions)
|
||||||
|
|
||||||
|
override fun getCallableNamesForClass(classSymbol: FirClassSymbol<*>): Set<Name> {
|
||||||
|
if (!classSymbol.isSuitableJavaClass()) return emptySet()
|
||||||
|
return functionsCache.getValue(classSymbol)?.keys.orEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getNestedClassifiersNames(classSymbol: FirClassSymbol<*>): Set<Name> {
|
||||||
|
if (!classSymbol.isSuitableJavaClass()) return emptySet()
|
||||||
|
val name = builderClassCache.getValue(classSymbol)?.name ?: return emptySet()
|
||||||
|
return setOf(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun generateFunctions(callableId: CallableId, context: MemberGenerationContext?): List<FirNamedFunctionSymbol> {
|
||||||
|
val classSymbol = context?.owner ?: return emptyList()
|
||||||
|
return functionsCache.getValue(classSymbol)?.get(callableId.callableName).orEmpty().map { it.symbol }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun generateClassLikeDeclaration(classId: ClassId): FirClassLikeSymbol<*>? {
|
||||||
|
val outerClassId = classId.outerClassId ?: return null
|
||||||
|
val outerClassSymbol = session.symbolProvider.getClassLikeSymbolByClassId(outerClassId) as? FirClassSymbol<*> ?: return null
|
||||||
|
if (!outerClassSymbol.isSuitableJavaClass()) return null
|
||||||
|
return builderClassCache.getValue(outerClassSymbol)?.symbol
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createFunctions(classSymbol: FirClassSymbol<*>): Map<Name, List<FirJavaMethod>>? {
|
||||||
|
val builder = lombokService.getBuilder(classSymbol) ?: return null
|
||||||
|
val functions = mutableListOf<FirJavaMethod>()
|
||||||
|
val classId = classSymbol.classId
|
||||||
|
val builderClassName = builder.builderClassName.replace("*", classId.shortClassName.asString())
|
||||||
|
val builderClassId = classId.createNestedClassId(Name.identifier(builderClassName))
|
||||||
|
|
||||||
|
val builderType = builderClassId.constructClassLikeType(emptyArray(), isNullable = false)
|
||||||
|
val visibility = builder.visibility.toVisibility()
|
||||||
|
functions += classSymbol.createJavaMethod(
|
||||||
|
Name.identifier(builder.builderMethodName),
|
||||||
|
valueParameters = emptyList(),
|
||||||
|
returnTypeRef = builderType.toFirResolvedTypeRef(),
|
||||||
|
visibility = visibility,
|
||||||
|
modality = Modality.FINAL,
|
||||||
|
dispatchReceiverType = null,
|
||||||
|
isStatic = true
|
||||||
|
)
|
||||||
|
|
||||||
|
if (builder.requiresToBuilder) {
|
||||||
|
functions += classSymbol.createJavaMethod(
|
||||||
|
Name.identifier(TO_BUILDER),
|
||||||
|
valueParameters = emptyList(),
|
||||||
|
returnTypeRef = builderType.toFirResolvedTypeRef(),
|
||||||
|
visibility = visibility,
|
||||||
|
modality = Modality.FINAL,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return functions.groupBy { it.name }
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(SymbolInternals::class)
|
||||||
|
private fun createBuilderClass(classSymbol: FirClassSymbol<*>): FirJavaClass? {
|
||||||
|
val javaClass = classSymbol.fir as? FirJavaClass ?: return null
|
||||||
|
val builder = lombokService.getBuilder(classSymbol) ?: return null
|
||||||
|
val builderName = Name.identifier(builder.builderClassName.replace("*", classSymbol.name.asString()))
|
||||||
|
val visibility = builder.visibility.toVisibility()
|
||||||
|
val builderClass = classSymbol.createJavaClass(
|
||||||
|
session,
|
||||||
|
builderName,
|
||||||
|
visibility,
|
||||||
|
Modality.FINAL,
|
||||||
|
isStatic = true,
|
||||||
|
superTypeRefs = listOf(session.builtinTypes.anyType)
|
||||||
|
)?.apply {
|
||||||
|
declarations += symbol.createDefaultJavaConstructor(visibility)
|
||||||
|
declarations += symbol.createJavaMethod(
|
||||||
|
Name.identifier(builder.buildMethodName),
|
||||||
|
valueParameters = emptyList(),
|
||||||
|
returnTypeRef = classSymbol.defaultType().toFirResolvedTypeRef(),
|
||||||
|
visibility = visibility,
|
||||||
|
modality = Modality.FINAL
|
||||||
|
)
|
||||||
|
val fields = javaClass.declarations.filterIsInstance<FirJavaField>()
|
||||||
|
for (field in fields) {
|
||||||
|
when (val singular = lombokService.getSingular(field.symbol)) {
|
||||||
|
null -> createSetterMethod(builder, field, symbol, declarations)
|
||||||
|
else -> createMethodsForSingularFields(builder, singular, field, symbol, declarations)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} ?: return null
|
||||||
|
|
||||||
|
|
||||||
|
return builderClass
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createSetterMethod(
|
||||||
|
builder: Builder,
|
||||||
|
field: FirJavaField,
|
||||||
|
builderClassSymbol: FirRegularClassSymbol,
|
||||||
|
destination: MutableList<FirDeclaration>
|
||||||
|
) {
|
||||||
|
val fieldName = field.name
|
||||||
|
val setterName = fieldName.toMethodName(builder)
|
||||||
|
destination += builderClassSymbol.createJavaMethod(
|
||||||
|
name = setterName,
|
||||||
|
valueParameters = listOf(ConeLombokValueParameter(fieldName, field.returnTypeRef)),
|
||||||
|
returnTypeRef = builderClassSymbol.defaultType().toFirResolvedTypeRef(),
|
||||||
|
modality = Modality.FINAL,
|
||||||
|
visibility = builder.visibility.toVisibility()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createMethodsForSingularFields(
|
||||||
|
builder: Builder,
|
||||||
|
singular: Singular,
|
||||||
|
field: FirJavaField,
|
||||||
|
builderClassSymbol: FirRegularClassSymbol,
|
||||||
|
destination: MutableList<FirDeclaration>
|
||||||
|
) {
|
||||||
|
val fieldJavaTypeRef = field.returnTypeRef as? FirJavaTypeRef ?: return
|
||||||
|
val javaClassifierType = fieldJavaTypeRef.type as? JavaClassifierType ?: return
|
||||||
|
val typeName = (javaClassifierType.classifier as? JavaClass)?.fqName?.asString() ?: return
|
||||||
|
|
||||||
|
val nameInSingularForm = (singular.singularName ?: field.name.identifier.singularForm)?.let(Name::identifier) ?: return
|
||||||
|
|
||||||
|
val useGuava = lombokService.config.useGuava
|
||||||
|
val supportedCollections = LombokNames.getSupportedCollectionsForSingular(useGuava)
|
||||||
|
val supportedMaps = LombokNames.getSupportedMapsForSingular(useGuava)
|
||||||
|
|
||||||
|
val addMultipleParameterType: FirTypeRef
|
||||||
|
val valueParameters: List<ConeLombokValueParameter>
|
||||||
|
|
||||||
|
when (typeName) {
|
||||||
|
in supportedCollections -> {
|
||||||
|
val parameterType = javaClassifierType.parameterType(0, singular.allowNull) ?: return
|
||||||
|
valueParameters = listOf(
|
||||||
|
ConeLombokValueParameter(nameInSingularForm, parameterType.toRef())
|
||||||
|
)
|
||||||
|
|
||||||
|
addMultipleParameterType = DummyJavaClassType(JavaClasses.Collection, typeArguments = listOf(parameterType)).toRef()
|
||||||
|
}
|
||||||
|
|
||||||
|
in supportedMaps -> {
|
||||||
|
val keyType = javaClassifierType.parameterType(0, singular.allowNull) ?: return
|
||||||
|
val valueType = javaClassifierType.parameterType(1, singular.allowNull) ?: return
|
||||||
|
valueParameters = listOf(
|
||||||
|
ConeLombokValueParameter(Name.identifier("key"), keyType.toRef()),
|
||||||
|
ConeLombokValueParameter(Name.identifier("value"), valueType.toRef()),
|
||||||
|
)
|
||||||
|
|
||||||
|
addMultipleParameterType = DummyJavaClassType(JavaClasses.Map, typeArguments = listOf(keyType, valueType)).toRef()
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> return
|
||||||
|
}
|
||||||
|
|
||||||
|
val builderType = builderClassSymbol.defaultType().toFirResolvedTypeRef()
|
||||||
|
val visibility = builder.visibility.toVisibility()
|
||||||
|
|
||||||
|
destination += builderClassSymbol.createJavaMethod(
|
||||||
|
name = nameInSingularForm.toMethodName(builder),
|
||||||
|
valueParameters,
|
||||||
|
returnTypeRef = builderType,
|
||||||
|
modality = Modality.FINAL,
|
||||||
|
visibility = visibility
|
||||||
|
)
|
||||||
|
|
||||||
|
destination += builderClassSymbol.createJavaMethod(
|
||||||
|
name = field.name.toMethodName(builder),
|
||||||
|
valueParameters = listOf(ConeLombokValueParameter(field.name, addMultipleParameterType)),
|
||||||
|
returnTypeRef = builderType,
|
||||||
|
modality = Modality.FINAL,
|
||||||
|
visibility = visibility
|
||||||
|
)
|
||||||
|
|
||||||
|
destination += builderClassSymbol.createJavaMethod(
|
||||||
|
name = Name.identifier("clear${field.name.identifier.capitalize()}"),
|
||||||
|
valueParameters = listOf(),
|
||||||
|
returnTypeRef = builderType,
|
||||||
|
modality = Modality.FINAL,
|
||||||
|
visibility = visibility
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Name.toMethodName(builder: Builder): Name {
|
||||||
|
val prefix = builder.setterPrefix
|
||||||
|
return if (prefix.isNullOrBlank()) {
|
||||||
|
this
|
||||||
|
} else {
|
||||||
|
Name.identifier("${prefix}${identifier.capitalize()}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val String.singularForm: String?
|
||||||
|
get() = StringUtil.unpluralize(this)
|
||||||
|
|
||||||
|
private val LombokConfig.useGuava: Boolean
|
||||||
|
get() = getBoolean("lombok.singular.useGuava") ?: false
|
||||||
|
|
||||||
|
private fun JavaClassifierType.parameterType(index: Int, allowNull: Boolean): JavaType? {
|
||||||
|
val type = typeArguments.getOrNull(index) ?: return null
|
||||||
|
return if (allowNull) type.makeNullable() else type.makeNotNullable()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun JavaType.makeNullable(): JavaType = withAnnotations(annotations + NullabilityJavaAnnotation.Nullable)
|
||||||
|
fun JavaType.makeNotNullable(): JavaType = withAnnotations(annotations + NullabilityJavaAnnotation.NotNull)
|
||||||
|
|
||||||
|
fun FirClassSymbol<*>.createJavaMethod(
|
||||||
|
name: Name,
|
||||||
|
valueParameters: List<ConeLombokValueParameter>,
|
||||||
|
returnTypeRef: FirTypeRef,
|
||||||
|
visibility: Visibility,
|
||||||
|
modality: Modality,
|
||||||
|
dispatchReceiverType: ConeSimpleKotlinType? = this.defaultType(),
|
||||||
|
isStatic: Boolean = false
|
||||||
|
): FirJavaMethod {
|
||||||
|
return buildJavaMethod {
|
||||||
|
moduleData = this@createJavaMethod.moduleData
|
||||||
|
this.returnTypeRef = returnTypeRef
|
||||||
|
this.dispatchReceiverType = dispatchReceiverType
|
||||||
|
this.name = name
|
||||||
|
symbol = FirNamedFunctionSymbol(CallableId(classId, name))
|
||||||
|
status = FirResolvedDeclarationStatusImpl(visibility, modality, visibility.toEffectiveVisibility(this@createJavaMethod)).apply {
|
||||||
|
this.isStatic = isStatic
|
||||||
|
}
|
||||||
|
isFromSource = true
|
||||||
|
annotationBuilder = { emptyList() }
|
||||||
|
for (valueParameter in valueParameters) {
|
||||||
|
this.valueParameters += buildJavaValueParameter {
|
||||||
|
moduleData = this@createJavaMethod.moduleData
|
||||||
|
this.returnTypeRef = valueParameter.typeRef
|
||||||
|
this.name = valueParameter.name
|
||||||
|
annotationBuilder = { emptyList() }
|
||||||
|
isVararg = false
|
||||||
|
isFromSource = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.apply {
|
||||||
|
if (isStatic) {
|
||||||
|
containingClassForStaticMemberAttr = this@createJavaMethod.toLookupTag()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun FirClassSymbol<*>.createDefaultJavaConstructor(
|
||||||
|
visibility: Visibility,
|
||||||
|
): FirJavaConstructor {
|
||||||
|
val outerClassSymbol = this
|
||||||
|
return buildJavaConstructor {
|
||||||
|
moduleData = outerClassSymbol.moduleData
|
||||||
|
isFromSource = true
|
||||||
|
symbol = FirConstructorSymbol(classId)
|
||||||
|
isInner = outerClassSymbol.rawStatus.isInner
|
||||||
|
status = FirResolvedDeclarationStatusImpl(
|
||||||
|
visibility,
|
||||||
|
Modality.FINAL,
|
||||||
|
visibility.toEffectiveVisibility(outerClassSymbol)
|
||||||
|
).apply {
|
||||||
|
isExpect = false
|
||||||
|
isActual = false
|
||||||
|
isOverride = false
|
||||||
|
isInner = this@buildJavaConstructor.isInner
|
||||||
|
}
|
||||||
|
this.visibility = visibility
|
||||||
|
isPrimary = false
|
||||||
|
returnTypeRef = buildResolvedTypeRef {
|
||||||
|
type = outerClassSymbol.defaultType()
|
||||||
|
}
|
||||||
|
dispatchReceiverType = if (isInner) outerClassSymbol.defaultType() else null
|
||||||
|
typeParameters += outerClassSymbol.typeParameterSymbols.map { buildConstructedClassTypeParameterRef { symbol = it } }
|
||||||
|
annotationBuilder = { emptyList() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ConeLombokValueParameter(val name: Name, val typeRef: FirTypeRef)
|
||||||
|
|
||||||
|
@OptIn(SymbolInternals::class)
|
||||||
|
fun FirClassSymbol<*>.createJavaClass(
|
||||||
|
session: FirSession,
|
||||||
|
name: Name,
|
||||||
|
visibility: Visibility,
|
||||||
|
modality: Modality,
|
||||||
|
isStatic: Boolean,
|
||||||
|
superTypeRefs: List<FirTypeRef>,
|
||||||
|
): FirJavaClass? {
|
||||||
|
val containingClass = this.fir as? FirJavaClass ?: return null
|
||||||
|
val classId = containingClass.classId.createNestedClassId(name)
|
||||||
|
return buildJavaClass {
|
||||||
|
moduleData = containingClass.moduleData
|
||||||
|
symbol = FirRegularClassSymbol(classId)
|
||||||
|
this.name = name
|
||||||
|
isFromSource = true
|
||||||
|
this.visibility = visibility
|
||||||
|
this.modality = modality
|
||||||
|
this.isStatic = isStatic
|
||||||
|
classKind = ClassKind.CLASS
|
||||||
|
javaTypeParameterStack = containingClass.javaTypeParameterStack
|
||||||
|
scopeProvider = JavaScopeProvider
|
||||||
|
if (!isStatic) {
|
||||||
|
typeParameters += containingClass.typeParameters.map {
|
||||||
|
buildOuterClassTypeParameterRef { symbol = it.symbol }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.superTypeRefs += superTypeRefs
|
||||||
|
val effectiveVisibility = containingClass.effectiveVisibility.lowerBound(
|
||||||
|
visibility.toEffectiveVisibility(this@createJavaClass, forClass = true),
|
||||||
|
session.typeContext
|
||||||
|
)
|
||||||
|
isTopLevel = false
|
||||||
|
status = FirResolvedDeclarationStatusImpl(
|
||||||
|
visibility,
|
||||||
|
modality,
|
||||||
|
effectiveVisibility
|
||||||
|
).apply {
|
||||||
|
this.isInner = !isTopLevel && !this@buildJavaClass.isStatic
|
||||||
|
isCompanion = false
|
||||||
|
isData = false
|
||||||
|
isInline = false
|
||||||
|
isFun = classKind == ClassKind.INTERFACE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+104
@@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* 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.k2.java
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.Visibility
|
||||||
|
import org.jetbrains.kotlin.load.java.structure.*
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
|
object JavaClasses {
|
||||||
|
val Collection = DummyJavaClass("Collection", javaUtilName("Collection"), numberOfTypeParameters = 1)
|
||||||
|
val Map = DummyJavaClass("Map", javaUtilName("Map"), numberOfTypeParameters = 2)
|
||||||
|
|
||||||
|
|
||||||
|
private fun javaUtilName(name: String): FqName {
|
||||||
|
return FqName.fromSegments(listOf("java", "util", name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DummyJavaClass(name: String, override val fqName: FqName, numberOfTypeParameters: Int) : JavaClass {
|
||||||
|
override val name: Name = Name.identifier(name)
|
||||||
|
|
||||||
|
override val isFromSource: Boolean
|
||||||
|
get() = shouldNotBeCalled()
|
||||||
|
override val annotations: Collection<JavaAnnotation>
|
||||||
|
get() = shouldNotBeCalled()
|
||||||
|
override val isDeprecatedInJavaDoc: Boolean
|
||||||
|
get() = shouldNotBeCalled()
|
||||||
|
|
||||||
|
override fun findAnnotation(fqName: FqName): JavaAnnotation? {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override val isAbstract: Boolean
|
||||||
|
get() = shouldNotBeCalled()
|
||||||
|
override val isStatic: Boolean
|
||||||
|
get() = shouldNotBeCalled()
|
||||||
|
override val isFinal: Boolean
|
||||||
|
get() = shouldNotBeCalled()
|
||||||
|
override val visibility: Visibility
|
||||||
|
get() = shouldNotBeCalled()
|
||||||
|
override val typeParameters: List<JavaTypeParameter> = (1..numberOfTypeParameters).map {
|
||||||
|
DummyJavaTypeParameter(Name.identifier("T_$it"))
|
||||||
|
}
|
||||||
|
|
||||||
|
override val supertypes: Collection<JavaClassifierType>
|
||||||
|
get() = shouldNotBeCalled()
|
||||||
|
override val innerClassNames: Collection<Name>
|
||||||
|
get() = shouldNotBeCalled()
|
||||||
|
|
||||||
|
override fun findInnerClass(name: Name): JavaClass? {
|
||||||
|
shouldNotBeCalled()
|
||||||
|
}
|
||||||
|
|
||||||
|
override val outerClass: JavaClass?
|
||||||
|
get() = null
|
||||||
|
override val isInterface: Boolean
|
||||||
|
get() = shouldNotBeCalled()
|
||||||
|
override val isAnnotationType: Boolean
|
||||||
|
get() = shouldNotBeCalled()
|
||||||
|
override val isEnum: Boolean
|
||||||
|
get() = shouldNotBeCalled()
|
||||||
|
override val isRecord: Boolean
|
||||||
|
get() = shouldNotBeCalled()
|
||||||
|
override val isSealed: Boolean
|
||||||
|
get() = shouldNotBeCalled()
|
||||||
|
override val permittedTypes: Collection<JavaClassifierType>
|
||||||
|
get() = shouldNotBeCalled()
|
||||||
|
override val lightClassOriginKind: LightClassOriginKind?
|
||||||
|
get() = shouldNotBeCalled()
|
||||||
|
override val methods: Collection<JavaMethod>
|
||||||
|
get() = shouldNotBeCalled()
|
||||||
|
override val fields: Collection<JavaField>
|
||||||
|
get() = shouldNotBeCalled()
|
||||||
|
override val constructors: Collection<JavaConstructor>
|
||||||
|
get() = shouldNotBeCalled()
|
||||||
|
override val recordComponents: Collection<JavaRecordComponent>
|
||||||
|
get() = shouldNotBeCalled()
|
||||||
|
|
||||||
|
override fun hasDefaultConstructor(): Boolean {
|
||||||
|
shouldNotBeCalled()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DummyJavaTypeParameter(override val name: Name) : JavaTypeParameter {
|
||||||
|
override val isFromSource: Boolean
|
||||||
|
get() = shouldNotBeCalled()
|
||||||
|
override val annotations: Collection<JavaAnnotation>
|
||||||
|
get() = shouldNotBeCalled()
|
||||||
|
override val isDeprecatedInJavaDoc: Boolean
|
||||||
|
get() = shouldNotBeCalled()
|
||||||
|
|
||||||
|
override fun findAnnotation(fqName: FqName): JavaAnnotation? {
|
||||||
|
shouldNotBeCalled()
|
||||||
|
}
|
||||||
|
|
||||||
|
override val upperBounds: Collection<JavaClassifierType>
|
||||||
|
get() = emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun shouldNotBeCalled(): Nothing = error("should not be called")
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
* 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.k2.java
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.builtins.PrimitiveType
|
||||||
|
import org.jetbrains.kotlin.fir.types.jvm.FirJavaTypeRef
|
||||||
|
import org.jetbrains.kotlin.fir.types.jvm.buildJavaTypeRef
|
||||||
|
import org.jetbrains.kotlin.load.java.structure.*
|
||||||
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.name.SpecialNames
|
||||||
|
|
||||||
|
abstract class WrappedJavaType<T : JavaType>(val original: T, private val ownAnnotations: Collection<JavaAnnotation>?) : JavaType {
|
||||||
|
override val annotations: Collection<JavaAnnotation>
|
||||||
|
get() = ownAnnotations ?: original.annotations
|
||||||
|
|
||||||
|
override val isDeprecatedInJavaDoc: Boolean
|
||||||
|
get() = original.isDeprecatedInJavaDoc
|
||||||
|
}
|
||||||
|
|
||||||
|
class WrappedJavaArrayType(
|
||||||
|
original: JavaArrayType,
|
||||||
|
ownAnnotations: Collection<JavaAnnotation>?
|
||||||
|
) : WrappedJavaType<JavaArrayType>(original, ownAnnotations), JavaArrayType {
|
||||||
|
override val componentType: JavaType
|
||||||
|
get() = original.componentType
|
||||||
|
}
|
||||||
|
|
||||||
|
class WrappedJavaPrimitiveType(
|
||||||
|
original: JavaPrimitiveType,
|
||||||
|
ownAnnotations: Collection<JavaAnnotation>?
|
||||||
|
) : WrappedJavaType<JavaPrimitiveType>(original, ownAnnotations), JavaPrimitiveType {
|
||||||
|
override val type: PrimitiveType?
|
||||||
|
get() = original.type
|
||||||
|
}
|
||||||
|
|
||||||
|
class WrappedJavaWildcardType(
|
||||||
|
original: JavaWildcardType,
|
||||||
|
ownAnnotations: Collection<JavaAnnotation>?
|
||||||
|
) : WrappedJavaType<JavaWildcardType>(original, ownAnnotations), JavaWildcardType {
|
||||||
|
override val bound: JavaType?
|
||||||
|
get() = original.bound
|
||||||
|
override val isExtends: Boolean
|
||||||
|
get() = original.isExtends
|
||||||
|
}
|
||||||
|
|
||||||
|
class WrappedJavaClassifierType(
|
||||||
|
original: JavaClassifierType,
|
||||||
|
ownAnnotations: Collection<JavaAnnotation>?,
|
||||||
|
) : WrappedJavaType<JavaClassifierType>(original, ownAnnotations), JavaClassifierType {
|
||||||
|
override val classifier: JavaClassifier?
|
||||||
|
get() = original.classifier
|
||||||
|
override val typeArguments: List<JavaType?>
|
||||||
|
get() = original.typeArguments
|
||||||
|
override val isRaw: Boolean
|
||||||
|
get() = original.isRaw
|
||||||
|
override val classifierQualifiedName: String
|
||||||
|
get() = original.classifierQualifiedName
|
||||||
|
override val presentableText: String
|
||||||
|
get() = original.presentableText
|
||||||
|
}
|
||||||
|
|
||||||
|
fun JavaType.withAnnotations(annotations: Collection<JavaAnnotation>): JavaType = when (this) {
|
||||||
|
is JavaArrayType -> WrappedJavaArrayType(this, annotations)
|
||||||
|
is JavaClassifierType -> WrappedJavaClassifierType(this, annotations)
|
||||||
|
is JavaPrimitiveType -> WrappedJavaPrimitiveType(this, annotations)
|
||||||
|
is JavaWildcardType -> WrappedJavaWildcardType(this, annotations)
|
||||||
|
else -> this
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class NullabilityJavaAnnotation(override val classId: ClassId) : JavaAnnotation {
|
||||||
|
override val arguments: Collection<JavaAnnotationArgument>
|
||||||
|
get() = emptyList()
|
||||||
|
|
||||||
|
override fun resolve(): JavaClass? = null
|
||||||
|
|
||||||
|
object NotNull : NullabilityJavaAnnotation(ClassId(ORG_JETBRAINS_ANNOTATIONS, Name.identifier("NotNull")))
|
||||||
|
object Nullable : NullabilityJavaAnnotation(ClassId(ORG_JETBRAINS_ANNOTATIONS, Name.identifier("Nullable")))
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val ORG_JETBRAINS_ANNOTATIONS = FqName.fromSegments(listOf("org", "jetbrains", "annotations"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DummyJavaClassType(
|
||||||
|
override val classifier: JavaClass,
|
||||||
|
override val typeArguments: List<JavaType?>
|
||||||
|
) : JavaClassifierType {
|
||||||
|
override val annotations: Collection<JavaAnnotation>
|
||||||
|
get() = emptyList()
|
||||||
|
override val isDeprecatedInJavaDoc: Boolean
|
||||||
|
get() = false
|
||||||
|
override val isRaw: Boolean
|
||||||
|
get() = false
|
||||||
|
override val classifierQualifiedName: String
|
||||||
|
get() = classifier.fqName?.asString() ?: SpecialNames.NO_NAME_PROVIDED.asString()
|
||||||
|
override val presentableText: String
|
||||||
|
get() = classifierQualifiedName
|
||||||
|
}
|
||||||
|
|
||||||
|
fun JavaType.toRef(): FirJavaTypeRef = buildJavaTypeRef {
|
||||||
|
type = this@toRef
|
||||||
|
annotationBuilder = { emptyList() }
|
||||||
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// FILE: User.java
|
// FILE: User.java
|
||||||
|
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
|
|||||||
Reference in New Issue
Block a user