[Lombok] Add implementation of plugin for FIR
This commit is contained in:
committed by
teamcity
parent
e58e86932c
commit
a84ece7233
@@ -13,6 +13,8 @@ import org.jetbrains.kotlin.fir.declarations.utils.*
|
||||
import org.jetbrains.kotlin.fir.dispatchReceiverClassOrNull
|
||||
import org.jetbrains.kotlin.fir.isNewPlaceForBodyGeneration
|
||||
import org.jetbrains.kotlin.fir.isSubstitutionOrIntersectionOverride
|
||||
import org.jetbrains.kotlin.fir.scopes.getDeclaredConstructors
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.declaredMemberScope
|
||||
import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||
|
||||
@@ -8,8 +8,7 @@ package org.jetbrains.kotlin.fir.java
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaTypeParameter
|
||||
|
||||
internal class JavaTypeParameterStack {
|
||||
|
||||
class JavaTypeParameterStack : Iterable<Map.Entry<JavaTypeParameter, FirTypeParameterSymbol>> {
|
||||
private val typeParameterMap = mutableMapOf<JavaTypeParameter, FirTypeParameterSymbol>()
|
||||
|
||||
fun addParameter(javaTypeParameter: JavaTypeParameter, symbol: FirTypeParameterSymbol) {
|
||||
@@ -25,6 +24,10 @@ internal class JavaTypeParameterStack {
|
||||
?: throw IllegalArgumentException("Cannot find Java type parameter $javaTypeParameter in stack")
|
||||
}
|
||||
|
||||
override operator fun iterator(): Iterator<Map.Entry<JavaTypeParameter, FirTypeParameterSymbol>> {
|
||||
return typeParameterMap.iterator()
|
||||
}
|
||||
|
||||
companion object {
|
||||
val EMPTY: JavaTypeParameterStack = JavaTypeParameterStack()
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ class FirJavaClass @FirImplementationDetail internal constructor(
|
||||
override val superTypeRefs: MutableList<FirTypeRef>,
|
||||
override val typeParameters: MutableList<FirTypeParameterRef>,
|
||||
internal val javaPackage: JavaPackage?,
|
||||
internal val javaTypeParameterStack: JavaTypeParameterStack,
|
||||
val javaTypeParameterStack: JavaTypeParameterStack,
|
||||
internal val existingNestedClassifierNames: List<Name>
|
||||
) : FirRegularClass() {
|
||||
override val hasLazyNestedClassifiers: Boolean get() = true
|
||||
|
||||
@@ -21,7 +21,6 @@ import org.jetbrains.kotlin.fir.references.FirControlFlowGraphReference
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeSimpleKotlinType
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.jvm.FirJavaTypeRef
|
||||
import org.jetbrains.kotlin.fir.visitors.FirTransformer
|
||||
import org.jetbrains.kotlin.fir.visitors.FirVisitor
|
||||
import org.jetbrains.kotlin.fir.visitors.transformInplace
|
||||
@@ -240,7 +239,7 @@ class FirJavaMethodBuilder : FirFunctionBuilder, FirTypeParametersOwnerBuilder,
|
||||
origin = javaOrigin(isFromSource),
|
||||
resolvePhase,
|
||||
attributes,
|
||||
returnTypeRef as FirJavaTypeRef,
|
||||
returnTypeRef,
|
||||
typeParameters,
|
||||
valueParameters,
|
||||
name,
|
||||
|
||||
+12
-4
@@ -23,7 +23,6 @@ import org.jetbrains.kotlin.fir.types.coneTypeSafe
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
private fun FirAnnotation.toAnnotationLookupTag(): ConeClassLikeLookupTag? =
|
||||
// this cast fails when we have generic-typed annotations @T
|
||||
@@ -159,10 +158,19 @@ fun FirAnnotation.findArgumentByName(name: Name): FirExpression? {
|
||||
return arguments.singleOrNull()
|
||||
}
|
||||
|
||||
fun FirAnnotation.getStringArgument(name: Name): String? =
|
||||
findArgumentByName(name)?.let { expression ->
|
||||
expression.safeAs<FirConstExpression<*>>()?.value as? String
|
||||
fun FirAnnotation.getBooleanArgument(name: Name): Boolean? = getPrimitiveArgumentValue(name)
|
||||
fun FirAnnotation.getStringArgument(name: Name): String? = getPrimitiveArgumentValue(name)
|
||||
fun FirAnnotation.getIntArgument(name: Name): Int? = getPrimitiveArgumentValue(name)
|
||||
fun FirAnnotation.getStringArrayArgument(name: Name): List<String>? {
|
||||
val argument = findArgumentByName(name) as? FirArrayOfCall ?: return null
|
||||
return argument.arguments.mapNotNull { (it as? FirConstExpression<*>)?.value as? String }
|
||||
}
|
||||
|
||||
private inline fun <reified T> FirAnnotation.getPrimitiveArgumentValue(name: Name): T? {
|
||||
return findArgumentByName(name)?.let { expression ->
|
||||
(expression as? FirConstExpression<*>)?.value as? T
|
||||
}
|
||||
}
|
||||
|
||||
fun FirAnnotationContainer.getJvmNameFromAnnotation(target: AnnotationUseSiteTarget? = null): String? {
|
||||
val annotationCalls = getAnnotationsByClassId(StandardClassIds.Annotations.JvmName)
|
||||
|
||||
-1
@@ -53,7 +53,6 @@ object FirGeneratedElementsValidator : FirDefaultVisitor<Unit, Any?>() {
|
||||
}
|
||||
|
||||
override fun visitTypeRef(typeRef: FirTypeRef, data: Any?) {
|
||||
require(typeRef is FirResolvedTypeRef)
|
||||
typeRef.acceptChildren(this, null)
|
||||
}
|
||||
|
||||
|
||||
@@ -29,9 +29,7 @@ import org.jetbrains.kotlin.kapt3.test.AbstractClassFileToSourceStubConverterTes
|
||||
import org.jetbrains.kotlin.kapt3.test.AbstractIrClassFileToSourceStubConverterTest
|
||||
import org.jetbrains.kotlin.kapt3.test.AbstractIrKotlinKaptContextTest
|
||||
import org.jetbrains.kotlin.kapt3.test.AbstractKotlinKaptContextTest
|
||||
import org.jetbrains.kotlin.lombok.AbstractBlackBoxCodegenTestForLombok
|
||||
import org.jetbrains.kotlin.lombok.AbstractDiagnosticTestForLombok
|
||||
import org.jetbrains.kotlin.lombok.AbstractIrBlackBoxCodegenTestForLombok
|
||||
import org.jetbrains.kotlin.lombok.*
|
||||
import org.jetbrains.kotlin.noarg.*
|
||||
import org.jetbrains.kotlin.parcelize.test.runners.*
|
||||
import org.jetbrains.kotlin.samWithReceiver.AbstractSamWithReceiverScriptTest
|
||||
@@ -430,8 +428,14 @@ fun main(args: Array<String>) {
|
||||
testClass<AbstractIrBlackBoxCodegenTestForLombok> {
|
||||
model("box")
|
||||
}
|
||||
testClass<AbstractFirBlackBoxCodegenTestForLombok> {
|
||||
model("box")
|
||||
}
|
||||
testClass<AbstractDiagnosticTestForLombok> {
|
||||
model("diagnostics")
|
||||
model("diagnostics", excludedPattern = excludedFirTestdataPattern)
|
||||
}
|
||||
testClass<AbstractFirDiagnosticTestForLombok> {
|
||||
model("diagnostics", excludedPattern = excludedFirTestdataPattern)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,11 +8,13 @@ plugins {
|
||||
dependencies {
|
||||
embedded(project(":kotlin-lombok-compiler-plugin.common"))
|
||||
embedded(project(":kotlin-lombok-compiler-plugin.k1"))
|
||||
embedded(project(":kotlin-lombok-compiler-plugin.k2"))
|
||||
embedded(project(":kotlin-lombok-compiler-plugin.cli"))
|
||||
|
||||
testImplementation(intellijCore())
|
||||
testImplementation(project(":kotlin-lombok-compiler-plugin.common"))
|
||||
testImplementation(project(":kotlin-lombok-compiler-plugin.k1"))
|
||||
testImplementation(project(":kotlin-lombok-compiler-plugin.k2"))
|
||||
testImplementation(project(":kotlin-lombok-compiler-plugin.cli"))
|
||||
|
||||
testImplementation("org.projectlombok:lombok:1.18.16")
|
||||
|
||||
@@ -11,9 +11,11 @@ dependencies {
|
||||
compileOnly(project(":compiler:plugin-api"))
|
||||
compileOnly(project(":compiler:frontend"))
|
||||
compileOnly(project(":compiler:frontend.java"))
|
||||
compileOnly(project(":compiler:fir:entrypoint"))
|
||||
|
||||
implementation(project(":kotlin-lombok-compiler-plugin.common"))
|
||||
implementation(project(":kotlin-lombok-compiler-plugin.k1"))
|
||||
implementation(project(":kotlin-lombok-compiler-plugin.k2"))
|
||||
|
||||
compileOnly(intellijCore())
|
||||
}
|
||||
|
||||
@@ -15,17 +15,20 @@ import org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor
|
||||
import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.CompilerConfigurationKey
|
||||
import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar
|
||||
import org.jetbrains.kotlin.lombok.LombokConfigurationKeys.CONFIG_FILE
|
||||
import org.jetbrains.kotlin.lombok.k2.FirLombokRegistrar
|
||||
import org.jetbrains.kotlin.resolve.jvm.extensions.SyntheticJavaResolveExtension
|
||||
import java.io.File
|
||||
import java.lang.IllegalArgumentException
|
||||
|
||||
class LombokComponentRegistrar : ComponentRegistrar {
|
||||
|
||||
companion object {
|
||||
fun registerComponents(project: Project, compilerConfiguration: CompilerConfiguration) {
|
||||
val config = LombokPluginConfig(compilerConfiguration[CONFIG_FILE])
|
||||
val configFile = compilerConfiguration[CONFIG_FILE]
|
||||
val config = LombokPluginConfig(configFile)
|
||||
SyntheticJavaResolveExtension.registerExtension(project, LombokResolveExtension(config))
|
||||
FirExtensionRegistrar.registerExtension(project, FirLombokRegistrar(configFile))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.lombok.utils
|
||||
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
object LombokNames {
|
||||
@@ -20,6 +21,16 @@ object LombokNames {
|
||||
val REQUIRED_ARGS_CONSTRUCTOR = FqName("lombok.RequiredArgsConstructor")
|
||||
|
||||
|
||||
val ACCESSORS_ID = ClassId.topLevel(ACCESSORS)
|
||||
val GETTER_ID = ClassId.topLevel(GETTER)
|
||||
val SETTER_ID = ClassId.topLevel(SETTER)
|
||||
val WITH_ID = ClassId.topLevel(WITH)
|
||||
val DATA_ID = ClassId.topLevel(DATA)
|
||||
val VALUE_ID = ClassId.topLevel(VALUE)
|
||||
val NO_ARGS_CONSTRUCTOR_ID = ClassId.topLevel(NO_ARGS_CONSTRUCTOR)
|
||||
val ALL_ARGS_CONSTRUCTOR_ID = ClassId.topLevel(ALL_ARGS_CONSTRUCTOR)
|
||||
val REQUIRED_ARGS_CONSTRUCTOR_ID = ClassId.topLevel(REQUIRED_ARGS_CONSTRUCTOR)
|
||||
|
||||
//taken from idea lombok plugin
|
||||
val NON_NULL_ANNOTATIONS = listOf(
|
||||
"androidx.annotation.NonNull",
|
||||
|
||||
-19
@@ -5,31 +5,12 @@
|
||||
|
||||
package org.jetbrains.kotlin.lombok.utils
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.lombok.config.LombokAnnotations.Accessors
|
||||
|
||||
object AccessorNames {
|
||||
const val IS = "is"
|
||||
const val GET = "get"
|
||||
const val SET = "set"
|
||||
}
|
||||
|
||||
/**
|
||||
* 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()
|
||||
toPropertyName(name.identifier, prefixes)
|
||||
} else {
|
||||
val id = name.identifier
|
||||
val name = toPropertyName(id, config.prefix)
|
||||
name.takeIf { it.length != id.length}
|
||||
}
|
||||
}
|
||||
|
||||
fun toPropertyName(name: String, prefixesToStrip: List<String> = emptyList()): String =
|
||||
name.stripPrefixes(prefixesToStrip).decapitalize()
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.lombok.config.LombokAnnotations.Accessors
|
||||
|
||||
/**
|
||||
* 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()
|
||||
toPropertyName(name.identifier, prefixes)
|
||||
} else {
|
||||
val id = name.identifier
|
||||
val name = toPropertyName(id, config.prefix)
|
||||
name.takeIf { it.length != id.length}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
description = "Lombok compiler plugin (K2)"
|
||||
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
id("jps-compatible")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":kotlin-lombok-compiler-plugin.common"))
|
||||
compileOnly(project(":compiler:fir:cones"))
|
||||
compileOnly(project(":compiler:fir:tree"))
|
||||
compileOnly(project(":compiler:fir:resolve"))
|
||||
compileOnly(project(":compiler:fir:checkers"))
|
||||
compileOnly(project(":compiler:fir:java"))
|
||||
compileOnly(project(":compiler:fir:entrypoint"))
|
||||
|
||||
compileOnly(intellijCore())
|
||||
runtimeOnly(kotlinStdlib())
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
"main" { projectDefault() }
|
||||
"test" { none() }
|
||||
}
|
||||
|
||||
runtimeJar()
|
||||
sourcesJar()
|
||||
javadocJar()
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar
|
||||
import org.jetbrains.kotlin.lombok.k2.config.LombokService
|
||||
import org.jetbrains.kotlin.lombok.k2.generators.*
|
||||
import java.io.File
|
||||
|
||||
class FirLombokRegistrar(private val lombokConfigFile: File?) : FirExtensionRegistrar() {
|
||||
override fun ExtensionRegistrarContext.configurePlugin() {
|
||||
+LombokService.getFactory(lombokConfigFile)
|
||||
+::GetterGenerator
|
||||
+::SetterGenerator
|
||||
+::WithGenerator
|
||||
+::LombokConstructorsGenerator
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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.config
|
||||
|
||||
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.extensions.FirExtensionSessionComponent
|
||||
import org.jetbrains.kotlin.fir.extensions.FirExtensionSessionComponent.Factory
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
||||
import org.jetbrains.kotlin.lombok.config.LombokConfig
|
||||
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.Data
|
||||
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.RequiredArgsConstructor
|
||||
import org.jetbrains.kotlin.lombok.k2.config.ConeLombokAnnotations.Setter
|
||||
import org.jetbrains.kotlin.lombok.k2.config.ConeLombokAnnotations.Value
|
||||
import org.jetbrains.kotlin.lombok.k2.config.ConeLombokAnnotations.With
|
||||
import java.io.File
|
||||
|
||||
@OptIn(SymbolInternals::class)
|
||||
class LombokService(session: FirSession, configFile: File?) : FirExtensionSessionComponent(session) {
|
||||
companion object {
|
||||
fun getFactory(configFile: File?): Factory {
|
||||
return Factory { LombokService(it, configFile) }
|
||||
}
|
||||
}
|
||||
|
||||
private val config = configFile?.let(LombokConfig::parse) ?: LombokConfig.Empty
|
||||
private val cachesFactory = session.firCachesFactory
|
||||
|
||||
private val accessorsCache: Cache<Accessors> = cachesFactory.createCache { symbol ->
|
||||
Accessors.get(symbol.fir, config)
|
||||
}
|
||||
|
||||
private val accessorsIfAnnotatedCache: Cache<Accessors?> = cachesFactory.createCache { symbol ->
|
||||
Accessors.getIfAnnotated(symbol.fir, config)
|
||||
}
|
||||
|
||||
private val getterCache: Cache<Getter?> = cachesFactory.createCache { symbol ->
|
||||
Getter.getOrNull(symbol.fir)
|
||||
}
|
||||
|
||||
private val setterCache: Cache<Setter?> = cachesFactory.createCache { symbol ->
|
||||
Setter.getOrNull(symbol.fir)
|
||||
}
|
||||
|
||||
private val withCache: Cache<With?> = cachesFactory.createCache { symbol ->
|
||||
With.getOrNull(symbol.fir)
|
||||
}
|
||||
|
||||
private val noArgsConstructorCache: Cache<NoArgsConstructor?> = cachesFactory.createCache { symbol ->
|
||||
NoArgsConstructor.getOrNull(symbol.fir)
|
||||
}
|
||||
|
||||
private val allArgsConstructorCache: Cache<AllArgsConstructor?> = cachesFactory.createCache { symbol ->
|
||||
AllArgsConstructor.getOrNull(symbol.fir)
|
||||
}
|
||||
|
||||
private val requiredArgsConstructorCache: Cache<RequiredArgsConstructor?> = cachesFactory.createCache { symbol ->
|
||||
RequiredArgsConstructor.getOrNull(symbol.fir)
|
||||
}
|
||||
|
||||
private val dataCache: Cache<Data?> = cachesFactory.createCache { symbol ->
|
||||
Data.getOrNull(symbol.fir)
|
||||
}
|
||||
|
||||
private val valueCache: Cache<Value?> = cachesFactory.createCache { symbol ->
|
||||
Value.getOrNull(symbol.fir)
|
||||
}
|
||||
|
||||
fun getAccessors(symbol: FirBasedSymbol<*>): Accessors = accessorsCache.getValue(symbol)
|
||||
fun getAccessorsIfAnnotated(symbol: FirBasedSymbol<*>): Accessors? = accessorsIfAnnotatedCache.getValue(symbol)
|
||||
fun getGetter(symbol: FirBasedSymbol<*>): Getter? = getterCache.getValue(symbol)
|
||||
fun getSetter(symbol: FirBasedSymbol<*>): Setter? = setterCache.getValue(symbol)
|
||||
fun getWith(symbol: FirBasedSymbol<*>): With? = withCache.getValue(symbol)
|
||||
fun getNoArgsConstructor(symbol: FirBasedSymbol<*>): NoArgsConstructor? = noArgsConstructorCache.getValue(symbol)
|
||||
fun getAllArgsConstructor(symbol: FirBasedSymbol<*>): AllArgsConstructor? = allArgsConstructorCache.getValue(symbol)
|
||||
fun getRequiredArgsConstructor(symbol: FirBasedSymbol<*>): RequiredArgsConstructor? = requiredArgsConstructorCache.getValue(symbol)
|
||||
fun getData(symbol: FirBasedSymbol<*>): Data? = dataCache.getValue(symbol)
|
||||
fun getValue(symbol: FirBasedSymbol<*>): Value? = valueCache.getValue(symbol)
|
||||
}
|
||||
|
||||
private typealias Cache<T> = FirCache<FirBasedSymbol<*>, T, Nothing?>
|
||||
|
||||
val FirSession.lombokService: LombokService by FirSession.sessionComponentAccessor()
|
||||
+193
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* 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.config
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.jetbrains.kotlin.fir.FirAnnotationContainer
|
||||
import org.jetbrains.kotlin.fir.declarations.getBooleanArgument
|
||||
import org.jetbrains.kotlin.fir.declarations.getStringArrayArgument
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||
import org.jetbrains.kotlin.fir.types.coneTypeSafe
|
||||
import org.jetbrains.kotlin.lombok.config.AccessLevel
|
||||
import org.jetbrains.kotlin.lombok.config.LombokConfig
|
||||
import org.jetbrains.kotlin.lombok.k2.config.LombokConfigNames.ACCESS
|
||||
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.FLUENT
|
||||
import org.jetbrains.kotlin.lombok.k2.config.LombokConfigNames.FLUENT_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_CONFIG
|
||||
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.utils.LombokNames
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
|
||||
/*
|
||||
* Lombok has two ways of configuration - lombok.config file and directly in annotations. Annotations has priority.
|
||||
* Not all things can be configured in annotations
|
||||
* So to make things easier I put all configuration in 'annotations' classes, but populate them from config too. So far it allows
|
||||
* keeping processors' code unaware about configuration origin.
|
||||
*
|
||||
*/
|
||||
|
||||
fun List<FirAnnotation>.findAnnotation(classId: ClassId): FirAnnotation? {
|
||||
return firstOrNull { it.annotationTypeRef.coneTypeSafe<ConeClassLikeType>()?.lookupTag?.classId == classId }
|
||||
}
|
||||
|
||||
abstract class ConeAnnotationCompanion<T>(val name: ClassId) {
|
||||
|
||||
abstract fun extract(annotation: FirAnnotation): T
|
||||
|
||||
fun getOrNull(annotated: FirAnnotationContainer): T? {
|
||||
return annotated.annotations.findAnnotation(name)?.let(this::extract)
|
||||
}
|
||||
}
|
||||
|
||||
abstract class ConeAnnotationAndConfigCompanion<T>(val annotationName: ClassId) {
|
||||
|
||||
abstract fun extract(annotation: FirAnnotation?, config: LombokConfig): T
|
||||
|
||||
/**
|
||||
* Get from annotation or config or default
|
||||
*/
|
||||
fun get(annotated: FirAnnotationContainer, config: LombokConfig): T =
|
||||
extract(annotated.annotations.findAnnotation(annotationName), config)
|
||||
|
||||
/**
|
||||
* If element is annotated, get from it or config or default
|
||||
*/
|
||||
fun getIfAnnotated(annotated: FirAnnotationContainer, config: LombokConfig): T? =
|
||||
annotated.annotations.findAnnotation(annotationName)?.let { annotation ->
|
||||
extract(annotation, config)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
object ConeLombokAnnotations {
|
||||
class Accessors(
|
||||
val fluent: Boolean = false,
|
||||
val chain: Boolean = false,
|
||||
val noIsPrefix: Boolean = false,
|
||||
val prefix: List<String> = emptyList()
|
||||
) {
|
||||
companion object : ConeAnnotationAndConfigCompanion<Accessors>(LombokNames.ACCESSORS_ID) {
|
||||
override fun extract(annotation: FirAnnotation?, config: LombokConfig): Accessors {
|
||||
val fluent = annotation?.getBooleanArgument(FLUENT)
|
||||
?: config.getBoolean(FLUENT_CONFIG)
|
||||
?: false
|
||||
val chain = annotation?.getBooleanArgument(CHAIN)
|
||||
?: config.getBoolean(CHAIN_CONFIG)
|
||||
?: fluent
|
||||
val noIsPrefix = config.getBoolean(NO_IS_PREFIX_CONFIG) ?: false
|
||||
val prefix = annotation?.getStringArrayArgument(PREFIX)
|
||||
?: config.getMultiString(PREFIX_CONFIG)
|
||||
?: emptyList()
|
||||
|
||||
return Accessors(fluent, chain, noIsPrefix, prefix)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Getter(val visibility: AccessLevel = AccessLevel.PUBLIC) {
|
||||
companion object : ConeAnnotationCompanion<Getter>(LombokNames.GETTER_ID) {
|
||||
override fun extract(annotation: FirAnnotation): Getter = Getter(
|
||||
visibility = getAccessLevel(annotation)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class Setter(val visibility: AccessLevel = AccessLevel.PUBLIC) {
|
||||
companion object : ConeAnnotationCompanion<Setter>(LombokNames.SETTER_ID) {
|
||||
override fun extract(annotation: FirAnnotation): Setter = Setter(
|
||||
visibility = getAccessLevel(annotation)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class With(val visibility: AccessLevel = AccessLevel.PUBLIC) {
|
||||
companion object : ConeAnnotationCompanion<With>(LombokNames.WITH_ID) {
|
||||
override fun extract(annotation: FirAnnotation): With = With(
|
||||
visibility = getAccessLevel(annotation)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
interface ConstructorAnnotation {
|
||||
val visibility: Visibility
|
||||
val staticName: String?
|
||||
}
|
||||
|
||||
class NoArgsConstructor(
|
||||
override val visibility: Visibility,
|
||||
override val staticName: String?
|
||||
) : ConstructorAnnotation {
|
||||
companion object : ConeAnnotationCompanion<NoArgsConstructor>(LombokNames.NO_ARGS_CONSTRUCTOR_ID) {
|
||||
override fun extract(annotation: FirAnnotation): NoArgsConstructor = NoArgsConstructor(
|
||||
visibility = getVisibility(annotation, ACCESS),
|
||||
staticName = annotation.getNonBlankStringArgument(STATIC_NAME)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class AllArgsConstructor(
|
||||
override val visibility: Visibility = Visibilities.Public,
|
||||
override val staticName: String? = null
|
||||
) : ConstructorAnnotation {
|
||||
companion object : ConeAnnotationCompanion<AllArgsConstructor>(LombokNames.ALL_ARGS_CONSTRUCTOR_ID) {
|
||||
override fun extract(annotation: FirAnnotation): AllArgsConstructor = AllArgsConstructor(
|
||||
visibility = getVisibility(annotation, ACCESS),
|
||||
staticName = annotation.getNonBlankStringArgument(STATIC_NAME)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class RequiredArgsConstructor(
|
||||
override val visibility: Visibility = Visibilities.Public,
|
||||
override val staticName: String? = null
|
||||
) : ConstructorAnnotation {
|
||||
companion object : ConeAnnotationCompanion<RequiredArgsConstructor>(LombokNames.REQUIRED_ARGS_CONSTRUCTOR_ID) {
|
||||
override fun extract(annotation: FirAnnotation): RequiredArgsConstructor = RequiredArgsConstructor(
|
||||
visibility = getVisibility(annotation, ACCESS),
|
||||
staticName = annotation.getNonBlankStringArgument(STATIC_NAME)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class Data(val staticConstructor: String?) {
|
||||
fun asSetter(): Setter = Setter()
|
||||
fun asGetter(): Getter = Getter()
|
||||
|
||||
fun asRequiredArgsConstructor(): RequiredArgsConstructor = RequiredArgsConstructor(
|
||||
staticName = staticConstructor
|
||||
)
|
||||
|
||||
companion object : ConeAnnotationCompanion<Data>(LombokNames.DATA_ID) {
|
||||
override fun extract(annotation: FirAnnotation): Data =
|
||||
Data(
|
||||
staticConstructor = annotation.getNonBlankStringArgument(STATIC_CONSTRUCTOR)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class Value(val staticConstructor: String?) {
|
||||
fun asGetter(): Getter = Getter()
|
||||
|
||||
fun asAllArgsConstructor(): AllArgsConstructor = AllArgsConstructor(
|
||||
staticName = staticConstructor
|
||||
)
|
||||
|
||||
companion object : ConeAnnotationCompanion<Value>(LombokNames.VALUE_ID) {
|
||||
override fun extract(annotation: FirAnnotation): Value = Value(
|
||||
staticConstructor = annotation.getNonBlankStringArgument(STATIC_CONSTRUCTOR)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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.config
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.jetbrains.kotlin.fir.declarations.findArgumentByName
|
||||
import org.jetbrains.kotlin.fir.declarations.getStringArgument
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
||||
import org.jetbrains.kotlin.fir.expressions.FirConstExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.toResolvedCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirEnumEntrySymbol
|
||||
import org.jetbrains.kotlin.lombok.config.AccessLevel
|
||||
import org.jetbrains.kotlin.lombok.utils.trimToNull
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
fun getAccessLevel(annotation: FirAnnotation, field: Name = LombokConfigNames.VALUE): AccessLevel {
|
||||
val value = annotation.getArgumentAsString(field) ?: return AccessLevel.PUBLIC
|
||||
return AccessLevel.valueOf(value)
|
||||
}
|
||||
|
||||
private fun FirAnnotation.getArgumentAsString(field: Name): String? {
|
||||
val argument = findArgumentByName(field) ?: return null
|
||||
return when (argument) {
|
||||
is FirConstExpression<*> -> argument.value as? String
|
||||
is FirQualifiedAccessExpression -> {
|
||||
val symbol = argument.toResolvedCallableSymbol()
|
||||
if (symbol is FirEnumEntrySymbol) {
|
||||
symbol.callableId.callableName.identifier
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
fun getVisibility(annotation: FirAnnotation, field: Name = LombokConfigNames.VALUE): Visibility {
|
||||
return getAccessLevel(annotation, field).toVisibility()
|
||||
}
|
||||
|
||||
fun FirAnnotation.getNonBlankStringArgument(name: Name): String? = getStringArgument(name)?.trimToNull()
|
||||
|
||||
object LombokConfigNames {
|
||||
val VALUE = Name.identifier("value")
|
||||
val FLUENT = Name.identifier("fluent")
|
||||
val CHAIN = Name.identifier("chain")
|
||||
val PREFIX = Name.identifier("prefix")
|
||||
val ACCESS = Name.identifier("access")
|
||||
val STATIC_NAME = Name.identifier("staticName")
|
||||
val STATIC_CONSTRUCTOR = Name.identifier("staticConstructor")
|
||||
|
||||
|
||||
const val FLUENT_CONFIG = "lombok.accessors.fluent"
|
||||
const val CHAIN_CONFIG = "lombok.accessors.chain"
|
||||
const val PREFIX_CONFIG = "lombok.accessors.prefix"
|
||||
const val NO_IS_PREFIX_CONFIG = "lombok.getter.noIsPrefix"
|
||||
}
|
||||
+231
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* 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 org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.containingClassForStaticMemberAttr
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.builder.buildConstructedClassTypeParameterRef
|
||||
import org.jetbrains.kotlin.fir.declarations.builder.buildTypeParameterCopy
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isInner
|
||||
import org.jetbrains.kotlin.fir.java.declarations.*
|
||||
import org.jetbrains.kotlin.fir.resolve.defaultType
|
||||
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.fir.toEffectiveVisibility
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||
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.lombok.k2.config.ConeLombokAnnotations
|
||||
import org.jetbrains.kotlin.lombok.k2.config.LombokService
|
||||
import org.jetbrains.kotlin.lombok.k2.config.lombokService
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.callableIdForConstructor
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||
|
||||
abstract class AbstractConstructorGeneratorPart<T : ConeLombokAnnotations.ConstructorAnnotation>(private val session: FirSession) {
|
||||
protected val lombokService: LombokService
|
||||
get() = session.lombokService
|
||||
|
||||
protected abstract fun getConstructorInfo(classSymbol: FirClassSymbol<*>): T?
|
||||
protected abstract fun getFieldsForParameters(classSymbol: FirClassSymbol<*>): List<FirJavaField>
|
||||
|
||||
@OptIn(SymbolInternals::class)
|
||||
fun createConstructor(classSymbol: FirClassSymbol<*>): FirFunction? {
|
||||
val constructorInfo = getConstructorInfo(classSymbol) ?: return null
|
||||
val staticName = constructorInfo.staticName?.let { Name.identifier(it) }
|
||||
|
||||
val substitutor: JavaTypeSubstitutor
|
||||
val builder = if (staticName == null) {
|
||||
FirJavaConstructorBuilder().apply {
|
||||
symbol = FirConstructorSymbol(classSymbol.classId.callableIdForConstructor())
|
||||
classSymbol.fir.typeParameters.mapTo(typeParameters) {
|
||||
buildConstructedClassTypeParameterRef { symbol = it.symbol }
|
||||
}
|
||||
substitutor = JavaTypeSubstitutor.Empty
|
||||
returnTypeRef = buildResolvedTypeRef {
|
||||
type = classSymbol.defaultType()
|
||||
}
|
||||
isInner = classSymbol.isInner
|
||||
isPrimary = false
|
||||
isFromSource = true
|
||||
annotationBuilder = { emptyList() }
|
||||
}
|
||||
} else {
|
||||
FirJavaMethodBuilder().apply {
|
||||
name = staticName
|
||||
val methodSymbol = FirNamedFunctionSymbol(CallableId(classSymbol.classId, staticName))
|
||||
symbol = methodSymbol
|
||||
|
||||
val classTypeParameterSymbols = classSymbol.fir.typeParameters.map { it.symbol }
|
||||
classTypeParameterSymbols.mapTo(typeParameters) {
|
||||
buildTypeParameterCopy(it.fir) {
|
||||
symbol = FirTypeParameterSymbol()
|
||||
containingDeclarationSymbol = methodSymbol
|
||||
}
|
||||
}
|
||||
|
||||
val javaClass = classSymbol.fir as FirJavaClass
|
||||
val javaTypeParametersFromClass = javaClass.javaTypeParameterStack
|
||||
.filter { it.value in classTypeParameterSymbols }
|
||||
.map { it.key }
|
||||
|
||||
val functionTypeParameterToJavaTypeParameter = typeParameters.zip(javaTypeParametersFromClass)
|
||||
.associate { (parameter, javaParameter) -> parameter.symbol to JavaTypeParameterStub(javaParameter) }
|
||||
|
||||
for ((parameter, javaParameter) in functionTypeParameterToJavaTypeParameter) {
|
||||
javaClass.javaTypeParameterStack.addParameter(javaParameter, parameter)
|
||||
}
|
||||
|
||||
val javaTypeSubstitution: Map<JavaClassifier, JavaType> = javaTypeParametersFromClass
|
||||
.zip(functionTypeParameterToJavaTypeParameter.values)
|
||||
.associate { (originalParameter, newParameter) ->
|
||||
originalParameter to JavaTypeParameterTypeStub(newParameter)
|
||||
}
|
||||
|
||||
substitutor = JavaTypeSubstitutorByMap(javaTypeSubstitution)
|
||||
returnTypeRef = buildResolvedTypeRef {
|
||||
type = classSymbol.classId.defaultType(functionTypeParameterToJavaTypeParameter.keys.toList())
|
||||
}
|
||||
|
||||
isStatic = true
|
||||
isFromSource = true
|
||||
annotationBuilder = { emptyList() }
|
||||
}
|
||||
}
|
||||
|
||||
builder.apply {
|
||||
moduleData = classSymbol.moduleData
|
||||
status = FirResolvedDeclarationStatusImpl(
|
||||
constructorInfo.visibility,
|
||||
Modality.FINAL,
|
||||
constructorInfo.visibility.toEffectiveVisibility(classSymbol)
|
||||
).apply {
|
||||
if (staticName != null) {
|
||||
isStatic = true
|
||||
}
|
||||
}
|
||||
|
||||
val fields = getFieldsForParameters(classSymbol)
|
||||
fields.mapTo(valueParameters) { field ->
|
||||
buildJavaValueParameter {
|
||||
moduleData = field.moduleData
|
||||
returnTypeRef = when (val typeRef = field.returnTypeRef) {
|
||||
is FirJavaTypeRef -> buildJavaTypeRef {
|
||||
type = substitutor.substituteOrSelf(typeRef.type)
|
||||
annotationBuilder = { emptyList() }
|
||||
}
|
||||
else -> typeRef
|
||||
}
|
||||
name = field.name
|
||||
annotationBuilder = { emptyList() }
|
||||
isVararg = false
|
||||
isFromSource = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return builder.build().apply {
|
||||
containingClassForStaticMemberAttr = classSymbol.toLookupTag()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class JavaTypeParameterStub(val original: JavaTypeParameter) : JavaTypeParameter {
|
||||
override val name: Name
|
||||
get() = original.name
|
||||
override val isFromSource: Boolean
|
||||
get() = true
|
||||
override val annotations: Collection<JavaAnnotation>
|
||||
get() = original.annotations
|
||||
override val isDeprecatedInJavaDoc: Boolean
|
||||
get() = original.isDeprecatedInJavaDoc
|
||||
|
||||
override fun findAnnotation(fqName: FqName): JavaAnnotation? {
|
||||
return original.findAnnotation(fqName)
|
||||
}
|
||||
|
||||
override val upperBounds: Collection<JavaClassifierType>
|
||||
get() = original.upperBounds
|
||||
}
|
||||
|
||||
private class JavaClassifierTypeStub(
|
||||
val original: JavaClassifierType,
|
||||
override val typeArguments: List<JavaType?>,
|
||||
) : JavaClassifierType {
|
||||
override val annotations: Collection<JavaAnnotation>
|
||||
get() = original.annotations
|
||||
override val isDeprecatedInJavaDoc: Boolean
|
||||
get() = original.isDeprecatedInJavaDoc
|
||||
override val classifier: JavaClassifier?
|
||||
get() = original.classifier
|
||||
override val isRaw: Boolean
|
||||
get() = original.isRaw
|
||||
override val classifierQualifiedName: String
|
||||
get() = original.classifierQualifiedName
|
||||
override val presentableText: String
|
||||
get() = original.presentableText
|
||||
}
|
||||
|
||||
private class JavaTypeParameterTypeStub(
|
||||
override val classifier: JavaTypeParameter
|
||||
) : JavaClassifierType {
|
||||
override val annotations: Collection<JavaAnnotation>
|
||||
get() = emptyList()
|
||||
override val isDeprecatedInJavaDoc: Boolean
|
||||
get() = false
|
||||
override val typeArguments: List<JavaType?>
|
||||
get() = emptyList()
|
||||
override val isRaw: Boolean
|
||||
get() = false
|
||||
override val classifierQualifiedName: String
|
||||
get() = classifier.name.identifier
|
||||
override val presentableText: String
|
||||
get() = classifierQualifiedName
|
||||
}
|
||||
|
||||
private sealed class JavaTypeSubstitutor {
|
||||
object Empty : JavaTypeSubstitutor() {
|
||||
override fun substituteOrNull(type: JavaType): JavaType? {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
fun substituteOrSelf(type: JavaType): JavaType {
|
||||
return substituteOrNull(type) ?: type
|
||||
}
|
||||
|
||||
abstract fun substituteOrNull(type: JavaType): JavaType?
|
||||
}
|
||||
|
||||
private class JavaTypeSubstitutorByMap(val map: Map<JavaClassifier, JavaType>) : JavaTypeSubstitutor() {
|
||||
override fun substituteOrNull(type: JavaType): JavaType? {
|
||||
if (type !is JavaClassifierType) return null
|
||||
map[type.classifier]?.let { return it }
|
||||
var hasNewArguments = false
|
||||
val newArguments = type.typeArguments.map { argument ->
|
||||
if (argument == null) return@map null
|
||||
val newArgument = substituteOrNull(argument)
|
||||
if (newArgument !== argument) {
|
||||
hasNewArguments = true
|
||||
newArgument
|
||||
} else {
|
||||
argument
|
||||
}
|
||||
}
|
||||
return runIf(hasNewArguments) {
|
||||
JavaClassifierTypeStub(type, newArguments)
|
||||
}
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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 org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.java.declarations.FirJavaField
|
||||
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.lombok.k2.config.ConeLombokAnnotations.AllArgsConstructor
|
||||
|
||||
class AllArgsConstructorGeneratorPart(session: FirSession) : AbstractConstructorGeneratorPart<AllArgsConstructor>(session) {
|
||||
override fun getConstructorInfo(classSymbol: FirClassSymbol<*>): AllArgsConstructor? {
|
||||
return lombokService.getAllArgsConstructor(classSymbol)
|
||||
?: lombokService.getValue(classSymbol)?.asAllArgsConstructor()
|
||||
}
|
||||
|
||||
@OptIn(SymbolInternals::class)
|
||||
override fun getFieldsForParameters(classSymbol: FirClassSymbol<*>): List<FirJavaField> {
|
||||
return classSymbol.fir.declarations.filterIsInstance<FirJavaField>()
|
||||
}
|
||||
}
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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 org.jetbrains.kotlin.descriptors.Modality
|
||||
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.declarations.impl.FirResolvedDeclarationStatusImpl
|
||||
import org.jetbrains.kotlin.fir.extensions.FirDeclarationGenerationExtension
|
||||
import org.jetbrains.kotlin.fir.extensions.MemberGenerationContext
|
||||
import org.jetbrains.kotlin.fir.java.declarations.FirJavaField
|
||||
import org.jetbrains.kotlin.fir.java.declarations.FirJavaMethod
|
||||
import org.jetbrains.kotlin.fir.java.declarations.buildJavaMethod
|
||||
import org.jetbrains.kotlin.fir.resolve.defaultType
|
||||
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.toEffectiveVisibility
|
||||
import org.jetbrains.kotlin.lombok.config.AccessLevel
|
||||
import org.jetbrains.kotlin.lombok.k2.config.ConeLombokAnnotations.Accessors
|
||||
import org.jetbrains.kotlin.lombok.k2.config.ConeLombokAnnotations.Getter
|
||||
import org.jetbrains.kotlin.lombok.k2.config.LombokService
|
||||
import org.jetbrains.kotlin.lombok.k2.config.lombokService
|
||||
import org.jetbrains.kotlin.lombok.utils.AccessorNames
|
||||
import org.jetbrains.kotlin.lombok.utils.capitalize
|
||||
import org.jetbrains.kotlin.lombok.utils.collectWithNotNull
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
class GetterGenerator(session: FirSession) : FirDeclarationGenerationExtension(session) {
|
||||
private val lombokService: LombokService
|
||||
get() = session.lombokService
|
||||
|
||||
private val cache: FirCache<FirClassSymbol<*>, Map<Name, FirJavaMethod>?, Nothing?> =
|
||||
session.firCachesFactory.createCache(::createGetters)
|
||||
|
||||
override fun getCallableNamesForClass(classSymbol: FirClassSymbol<*>): Set<Name> {
|
||||
if (!classSymbol.isSuitableJavaClass()) return emptySet()
|
||||
return cache.getValue(classSymbol)?.keys ?: emptySet()
|
||||
}
|
||||
|
||||
override fun generateFunctions(callableId: CallableId, context: MemberGenerationContext?): List<FirNamedFunctionSymbol> {
|
||||
val owner = context?.owner
|
||||
if (owner == null || !owner.isSuitableJavaClass()) return emptyList()
|
||||
val getter = cache.getValue(owner)?.get(callableId.callableName) ?: return emptyList()
|
||||
return listOf(getter.symbol)
|
||||
}
|
||||
|
||||
private fun createGetters(classSymbol: FirClassSymbol<*>): Map<Name, FirJavaMethod>? {
|
||||
val fieldsWithGetter = computeFieldsWithGetter(classSymbol) ?: return null
|
||||
val globalAccessors = lombokService.getAccessors(classSymbol)
|
||||
return fieldsWithGetter.mapNotNull { (field, getterInfo) ->
|
||||
val getterName = computeGetterName(field, getterInfo, globalAccessors) ?: return@mapNotNull null
|
||||
val function = buildJavaMethod {
|
||||
moduleData = field.moduleData
|
||||
returnTypeRef = field.returnTypeRef
|
||||
dispatchReceiverType = classSymbol.defaultType()
|
||||
name = getterName
|
||||
symbol = FirNamedFunctionSymbol(CallableId(classSymbol.classId, getterName))
|
||||
val visibility = getterInfo.visibility.toVisibility()
|
||||
status = FirResolvedDeclarationStatusImpl(visibility, Modality.OPEN, visibility.toEffectiveVisibility(classSymbol))
|
||||
isStatic = false
|
||||
isFromSource = true
|
||||
annotationBuilder = { emptyList() }
|
||||
}
|
||||
getterName to function
|
||||
}.toMap()
|
||||
}
|
||||
|
||||
@OptIn(SymbolInternals::class)
|
||||
private fun computeFieldsWithGetter(classSymbol: FirClassSymbol<*>): List<Pair<FirJavaField, Getter>>? {
|
||||
val classGetter = lombokService.getGetter(classSymbol)
|
||||
?: lombokService.getData(classSymbol)?.asGetter()
|
||||
?: lombokService.getValue(classSymbol)?.asGetter()
|
||||
|
||||
return classSymbol.fir.declarations
|
||||
.filterIsInstance<FirJavaField>()
|
||||
.collectWithNotNull { lombokService.getGetter(it.symbol) ?: classGetter }
|
||||
.takeIf { it.isNotEmpty() }
|
||||
}
|
||||
|
||||
private fun computeGetterName(field: FirJavaField, getterInfo: Getter, globalAccessors: Accessors): Name? {
|
||||
if (getterInfo.visibility == AccessLevel.NONE) return null
|
||||
val accessors = lombokService.getAccessorsIfAnnotated(field.symbol) ?: globalAccessors
|
||||
val propertyName = field.toAccessorBaseName(accessors) ?: return null
|
||||
val functionName = if (accessors.fluent) {
|
||||
propertyName
|
||||
} else {
|
||||
val prefix = if (field.returnTypeRef.isPrimitiveBoolean() && !accessors.noIsPrefix) AccessorNames.IS else AccessorNames.GET
|
||||
prefix + propertyName.capitalize()
|
||||
}
|
||||
return Name.identifier(functionName)
|
||||
}
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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 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.extensions.FirDeclarationGenerationExtension
|
||||
import org.jetbrains.kotlin.fir.extensions.MemberGenerationContext
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.SpecialNames
|
||||
|
||||
class LombokConstructorsGenerator(session: FirSession) : FirDeclarationGenerationExtension(session) {
|
||||
private val parts: List<AbstractConstructorGeneratorPart<*>> = listOf(
|
||||
AllArgsConstructorGeneratorPart(session),
|
||||
NoArgsConstructorGeneratorPart(session),
|
||||
RequiredArgsConstructorGeneratorPart(session)
|
||||
)
|
||||
|
||||
private val cache: FirCache<FirClassSymbol<*>, Collection<FirFunctionSymbol<*>>?, Nothing?> =
|
||||
session.firCachesFactory.createCache(::createConstructors)
|
||||
|
||||
override fun getCallableNamesForClass(classSymbol: FirClassSymbol<*>): Set<Name> {
|
||||
if (!classSymbol.isSuitableJavaClass()) return emptySet()
|
||||
return cache.getValue(classSymbol)?.mapTo(mutableSetOf()) {
|
||||
when (it) {
|
||||
is FirConstructorSymbol -> SpecialNames.INIT
|
||||
else -> it.callableId.callableName
|
||||
}
|
||||
} ?: emptySet()
|
||||
}
|
||||
|
||||
override fun generateFunctions(callableId: CallableId, context: MemberGenerationContext?): List<FirNamedFunctionSymbol> {
|
||||
val owner = context?.owner ?: return emptyList()
|
||||
if (!owner.isSuitableJavaClass()) return emptyList()
|
||||
return cache.getValue(owner)?.filterIsInstance<FirNamedFunctionSymbol>().orEmpty()
|
||||
}
|
||||
|
||||
override fun generateConstructors(context: MemberGenerationContext): List<FirConstructorSymbol> {
|
||||
val owner = context.owner
|
||||
if (!owner.isSuitableJavaClass()) return emptyList()
|
||||
return cache.getValue(owner)?.filterIsInstance<FirConstructorSymbol>().orEmpty()
|
||||
}
|
||||
|
||||
private fun createConstructors(classSymbol: FirClassSymbol<*>): Collection<FirFunctionSymbol<*>>? {
|
||||
return parts
|
||||
.mapNotNull { it.createConstructor(classSymbol) }
|
||||
.takeIf { it.isNotEmpty() }
|
||||
?.filterClashingDeclarations(classSymbol)
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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 org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.java.declarations.FirJavaField
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.lombok.k2.config.ConeLombokAnnotations.NoArgsConstructor
|
||||
|
||||
class NoArgsConstructorGeneratorPart(session: FirSession) : AbstractConstructorGeneratorPart<NoArgsConstructor>(session) {
|
||||
override fun getConstructorInfo(classSymbol: FirClassSymbol<*>): NoArgsConstructor? {
|
||||
return lombokService.getNoArgsConstructor(classSymbol)
|
||||
}
|
||||
|
||||
override fun getFieldsForParameters(classSymbol: FirClassSymbol<*>): List<FirJavaField> {
|
||||
return emptyList()
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.psi.PsiField
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.expressions.classId
|
||||
import org.jetbrains.kotlin.fir.java.declarations.FirJavaField
|
||||
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.lombok.k2.config.ConeLombokAnnotations.RequiredArgsConstructor
|
||||
import org.jetbrains.kotlin.lombok.utils.LombokNames
|
||||
import org.jetbrains.kotlin.psi
|
||||
|
||||
class RequiredArgsConstructorGeneratorPart(session: FirSession) : AbstractConstructorGeneratorPart<RequiredArgsConstructor>(session) {
|
||||
override fun getConstructorInfo(classSymbol: FirClassSymbol<*>): RequiredArgsConstructor? {
|
||||
return lombokService.getRequiredArgsConstructor(classSymbol)
|
||||
?: lombokService.getData(classSymbol)?.asRequiredArgsConstructor()
|
||||
}
|
||||
|
||||
@OptIn(SymbolInternals::class)
|
||||
override fun getFieldsForParameters(classSymbol: FirClassSymbol<*>): List<FirJavaField> {
|
||||
return classSymbol.fir.declarations
|
||||
.filterIsInstance<FirJavaField>()
|
||||
.filter { it.isFieldRequired() }
|
||||
}
|
||||
|
||||
private fun FirJavaField.isFieldRequired(): Boolean {
|
||||
// TODO: consider adding `hasInitializer` property directly to java model
|
||||
val hasInitializer = (source?.psi as? PsiField)?.hasInitializer() ?: false
|
||||
if (hasInitializer) return false
|
||||
if (isVal) return true
|
||||
return annotations.any { it.classId?.asSingleFqName() in LombokNames.NON_NULL_ANNOTATIONS }
|
||||
}
|
||||
}
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* 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 org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
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.declarations.impl.FirResolvedDeclarationStatusImpl
|
||||
import org.jetbrains.kotlin.fir.extensions.FirDeclarationGenerationExtension
|
||||
import org.jetbrains.kotlin.fir.extensions.MemberGenerationContext
|
||||
import org.jetbrains.kotlin.fir.java.declarations.FirJavaField
|
||||
import org.jetbrains.kotlin.fir.java.declarations.FirJavaMethod
|
||||
import org.jetbrains.kotlin.fir.java.declarations.buildJavaMethod
|
||||
import org.jetbrains.kotlin.fir.java.declarations.buildJavaValueParameter
|
||||
import org.jetbrains.kotlin.fir.resolve.defaultType
|
||||
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.toEffectiveVisibility
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||
import org.jetbrains.kotlin.lombok.config.AccessLevel
|
||||
import org.jetbrains.kotlin.lombok.k2.config.ConeLombokAnnotations.Accessors
|
||||
import org.jetbrains.kotlin.lombok.k2.config.ConeLombokAnnotations.Setter
|
||||
import org.jetbrains.kotlin.lombok.k2.config.LombokService
|
||||
import org.jetbrains.kotlin.lombok.k2.config.lombokService
|
||||
import org.jetbrains.kotlin.lombok.utils.AccessorNames
|
||||
import org.jetbrains.kotlin.lombok.utils.capitalize
|
||||
import org.jetbrains.kotlin.lombok.utils.collectWithNotNull
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
class SetterGenerator(session: FirSession) : FirDeclarationGenerationExtension(session) {
|
||||
private val lombokService: LombokService
|
||||
get() = session.lombokService
|
||||
|
||||
private val cache: FirCache<FirClassSymbol<*>, Map<Name, FirJavaMethod>?, Nothing?> =
|
||||
session.firCachesFactory.createCache(::createSetters)
|
||||
|
||||
override fun getCallableNamesForClass(classSymbol: FirClassSymbol<*>): Set<Name> {
|
||||
if (!classSymbol.isSuitableForSetters()) return emptySet()
|
||||
return cache.getValue(classSymbol)?.keys ?: emptySet()
|
||||
}
|
||||
|
||||
override fun generateFunctions(callableId: CallableId, context: MemberGenerationContext?): List<FirNamedFunctionSymbol> {
|
||||
val owner = context?.owner
|
||||
if (owner == null || !owner.isSuitableForSetters()) return emptyList()
|
||||
val getter = cache.getValue(owner)?.get(callableId.callableName) ?: return emptyList()
|
||||
return listOf(getter.symbol)
|
||||
}
|
||||
|
||||
private fun FirClassSymbol<*>.isSuitableForSetters(): Boolean {
|
||||
return isSuitableJavaClass() && classKind != ClassKind.ENUM_CLASS
|
||||
}
|
||||
|
||||
private fun createSetters(classSymbol: FirClassSymbol<*>): Map<Name, FirJavaMethod>? {
|
||||
val fieldsWithSetter = computeFieldsWithSetters(classSymbol) ?: return null
|
||||
val globalAccessors = lombokService.getAccessors(classSymbol)
|
||||
return fieldsWithSetter.mapNotNull { (field, setterInfo) ->
|
||||
val accessors = lombokService.getAccessorsIfAnnotated(field.symbol) ?: globalAccessors
|
||||
val setterName = computeSetterName(field, setterInfo, accessors) ?: return@mapNotNull null
|
||||
val function = buildJavaMethod {
|
||||
moduleData = field.moduleData
|
||||
returnTypeRef = if (accessors.chain) {
|
||||
buildResolvedTypeRef {
|
||||
type = classSymbol.defaultType()
|
||||
}
|
||||
} else {
|
||||
session.builtinTypes.unitType
|
||||
}
|
||||
|
||||
dispatchReceiverType = classSymbol.defaultType()
|
||||
name = setterName
|
||||
symbol = FirNamedFunctionSymbol(CallableId(classSymbol.classId, setterName))
|
||||
val visibility = setterInfo.visibility.toVisibility()
|
||||
status = FirResolvedDeclarationStatusImpl(visibility, Modality.OPEN, visibility.toEffectiveVisibility(classSymbol))
|
||||
|
||||
valueParameters += buildJavaValueParameter {
|
||||
moduleData = field.moduleData
|
||||
returnTypeRef = field.returnTypeRef
|
||||
name = field.name
|
||||
annotationBuilder = { emptyList() }
|
||||
isVararg = false
|
||||
isFromSource = true
|
||||
}
|
||||
|
||||
isStatic = false
|
||||
isFromSource = true
|
||||
annotationBuilder = { emptyList() }
|
||||
}
|
||||
setterName to function
|
||||
}.toMap()
|
||||
}
|
||||
|
||||
@OptIn(SymbolInternals::class)
|
||||
private fun computeFieldsWithSetters(classSymbol: FirClassSymbol<*>): List<Pair<FirJavaField, Setter>>? {
|
||||
val classSetter = lombokService.getSetter(classSymbol)
|
||||
?: lombokService.getData(classSymbol)?.asSetter()
|
||||
|
||||
return classSymbol.fir.declarations
|
||||
.filterIsInstance<FirJavaField>()
|
||||
.filter { it.isVar }
|
||||
.collectWithNotNull { lombokService.getSetter(it.symbol) ?: classSetter }
|
||||
.takeIf { it.isNotEmpty() }
|
||||
}
|
||||
|
||||
private fun computeSetterName(field: FirJavaField, setterInfo: Setter, accessors: Accessors): Name? {
|
||||
if (setterInfo.visibility == AccessLevel.NONE) return null
|
||||
val propertyName = field.toAccessorBaseName(accessors) ?: return null
|
||||
val functionName = if (accessors.fluent) {
|
||||
propertyName
|
||||
} else {
|
||||
AccessorNames.SET + propertyName.capitalize()
|
||||
}
|
||||
return Name.identifier(functionName)
|
||||
}
|
||||
}
|
||||
+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.generators
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
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.declarations.impl.FirResolvedDeclarationStatusImpl
|
||||
import org.jetbrains.kotlin.fir.extensions.FirDeclarationGenerationExtension
|
||||
import org.jetbrains.kotlin.fir.extensions.MemberGenerationContext
|
||||
import org.jetbrains.kotlin.fir.java.declarations.FirJavaField
|
||||
import org.jetbrains.kotlin.fir.java.declarations.FirJavaMethod
|
||||
import org.jetbrains.kotlin.fir.java.declarations.buildJavaMethod
|
||||
import org.jetbrains.kotlin.fir.java.declarations.buildJavaValueParameter
|
||||
import org.jetbrains.kotlin.fir.resolve.defaultType
|
||||
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.toEffectiveVisibility
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||
import org.jetbrains.kotlin.lombok.config.AccessLevel
|
||||
import org.jetbrains.kotlin.lombok.k2.config.ConeLombokAnnotations.With
|
||||
import org.jetbrains.kotlin.lombok.k2.config.LombokService
|
||||
import org.jetbrains.kotlin.lombok.k2.config.lombokService
|
||||
import org.jetbrains.kotlin.lombok.utils.collectWithNotNull
|
||||
import org.jetbrains.kotlin.lombok.utils.toPropertyNameCapitalized
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
class WithGenerator(session: FirSession) : FirDeclarationGenerationExtension(session) {
|
||||
private val lombokService: LombokService
|
||||
get() = session.lombokService
|
||||
|
||||
private val cache: FirCache<FirClassSymbol<*>, Map<Name, FirJavaMethod>?, Nothing?> =
|
||||
session.firCachesFactory.createCache(::createWith)
|
||||
|
||||
override fun getCallableNamesForClass(classSymbol: FirClassSymbol<*>): Set<Name> {
|
||||
if (!classSymbol.isSuitableJavaClass()) return emptySet()
|
||||
return cache.getValue(classSymbol)?.keys ?: emptySet()
|
||||
}
|
||||
|
||||
override fun generateFunctions(callableId: CallableId, context: MemberGenerationContext?): List<FirNamedFunctionSymbol> {
|
||||
val owner = context?.owner
|
||||
if (owner == null || !owner.isSuitableJavaClass()) return emptyList()
|
||||
val getter = cache.getValue(owner)?.get(callableId.callableName) ?: return emptyList()
|
||||
return listOf(getter.symbol)
|
||||
}
|
||||
|
||||
private fun createWith(classSymbol: FirClassSymbol<*>): Map<Name, FirJavaMethod>? {
|
||||
val fieldsWithWith = computeFieldsWithWithAnnotation(classSymbol) ?: return null
|
||||
return fieldsWithWith.mapNotNull { (field, withInfo) ->
|
||||
val withName = computeWithName(field, withInfo) ?: return@mapNotNull null
|
||||
val function = buildJavaMethod {
|
||||
moduleData = field.moduleData
|
||||
returnTypeRef = buildResolvedTypeRef {
|
||||
type = classSymbol.defaultType()
|
||||
}
|
||||
|
||||
dispatchReceiverType = classSymbol.defaultType()
|
||||
name = withName
|
||||
symbol = FirNamedFunctionSymbol(CallableId(classSymbol.classId, withName))
|
||||
val visibility = withInfo.visibility.toVisibility()
|
||||
status = FirResolvedDeclarationStatusImpl(visibility, Modality.OPEN, visibility.toEffectiveVisibility(classSymbol))
|
||||
|
||||
valueParameters += buildJavaValueParameter {
|
||||
moduleData = field.moduleData
|
||||
returnTypeRef = field.returnTypeRef
|
||||
name = field.name
|
||||
annotationBuilder = { emptyList() }
|
||||
isVararg = false
|
||||
isFromSource = true
|
||||
}
|
||||
|
||||
isStatic = false
|
||||
isFromSource = true
|
||||
annotationBuilder = { emptyList() }
|
||||
}
|
||||
withName to function
|
||||
}.toMap()
|
||||
}
|
||||
|
||||
@OptIn(SymbolInternals::class)
|
||||
private fun computeFieldsWithWithAnnotation(classSymbol: FirClassSymbol<*>): List<Pair<FirJavaField, With>>? {
|
||||
val classWith = lombokService.getWith(classSymbol)
|
||||
|
||||
return classSymbol.fir.declarations
|
||||
.filterIsInstance<FirJavaField>()
|
||||
.filter { it.isVar }
|
||||
.collectWithNotNull { lombokService.getWith(it.symbol) ?: classWith }
|
||||
.takeIf { it.isNotEmpty() }
|
||||
}
|
||||
|
||||
private fun computeWithName(field: FirJavaField, withInfo: With): Name? {
|
||||
if (withInfo.visibility == AccessLevel.NONE) return null
|
||||
val functionName = "with" + toPropertyNameCapitalized(field.name.identifier)
|
||||
return Name.identifier(functionName)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package org.jetbrains.kotlin.lombok.k2.generators
|
||||
|
||||
import org.jetbrains.kotlin.builtins.PrimitiveType
|
||||
import org.jetbrains.kotlin.fir.declarations.FirConstructor
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||
import org.jetbrains.kotlin.fir.java.declarations.FirJavaField
|
||||
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.jvm.FirJavaTypeRef
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaPrimitiveType
|
||||
import org.jetbrains.kotlin.lombok.k2.config.ConeLombokAnnotations
|
||||
import org.jetbrains.kotlin.lombok.utils.AccessorNames
|
||||
import org.jetbrains.kotlin.lombok.utils.toPropertyName
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.contracts.contract
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
fun FirJavaField.toAccessorBaseName(config: ConeLombokAnnotations.Accessors): String? {
|
||||
val isPrimitiveBoolean = returnTypeRef.isPrimitiveBoolean()
|
||||
return if (config.prefix.isEmpty()) {
|
||||
val prefixes = if (isPrimitiveBoolean) listOf(AccessorNames.IS) else emptyList()
|
||||
toPropertyName(name.identifier, prefixes)
|
||||
} else {
|
||||
val id = name.identifier
|
||||
val name = toPropertyName(id, config.prefix)
|
||||
name.takeIf { it.length != id.length}
|
||||
}
|
||||
}
|
||||
|
||||
fun FirTypeRef.isPrimitiveBoolean(): Boolean {
|
||||
return when (this) {
|
||||
is FirJavaTypeRef -> (type as? JavaPrimitiveType)?.type == PrimitiveType.BOOLEAN
|
||||
else -> this.coneTypeSafe<ConeKotlinType>()?.lowerBoundIfFlexible()?.isBoolean ?: false
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
fun FirClassSymbol<*>.isSuitableJavaClass(): Boolean {
|
||||
contract {
|
||||
returns(true) implies (this@isSuitableJavaClass is FirRegularClassSymbol)
|
||||
}
|
||||
return (this is FirRegularClassSymbol) && origin == FirDeclarationOrigin.Java.Source
|
||||
}
|
||||
|
||||
@OptIn(SymbolInternals::class)
|
||||
fun List<FirFunction>.filterClashingDeclarations(classSymbol: FirClassSymbol<*>): List<FirFunctionSymbol<*>> {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val allStaticFunctionsAndConstructors = classSymbol.fir.declarations.filterIsInstance<FirFunction>().toMutableList()
|
||||
val result = mutableListOf<FirFunction>()
|
||||
for (function in this) {
|
||||
if (allStaticFunctionsAndConstructors.none { sameSignature(it, function) }) {
|
||||
allStaticFunctionsAndConstructors += function
|
||||
result += function
|
||||
}
|
||||
}
|
||||
return result.map { it.symbol }
|
||||
}
|
||||
|
||||
/**
|
||||
* 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: FirFunction, b: FirFunction): Boolean {
|
||||
if (a is FirConstructor && b !is FirConstructor || a !is FirConstructor && b is FirConstructor) return false
|
||||
if (a.symbol.callableId.callableName != b.symbol.callableId.callableName) return false
|
||||
val aVararg = a.valueParameters.any { it.isVararg }
|
||||
val bVararg = b.valueParameters.any { it.isVararg }
|
||||
val aSize = a.valueParameters.size
|
||||
val bSize = b.valueParameters.size
|
||||
return aVararg && bVararg ||
|
||||
aVararg && bSize >= (aSize - 1) ||
|
||||
bVararg && aSize >= (bSize - 1) ||
|
||||
aSize == bSize
|
||||
}
|
||||
Vendored
+7
-2
@@ -1,6 +1,10 @@
|
||||
// FULL_JDK
|
||||
// WITH_STDLIB
|
||||
// FILE: DataExample.java
|
||||
|
||||
import lombok.*;
|
||||
import java.util.List;
|
||||
import java.util.Arrays;
|
||||
|
||||
@Data public class DataExample {
|
||||
private final String name;
|
||||
@@ -13,6 +17,7 @@ import lombok.*;
|
||||
public static class Exercise<T> {
|
||||
private final String name;
|
||||
private final T value;
|
||||
private final List<T> list;
|
||||
}
|
||||
|
||||
public static void usage() {
|
||||
@@ -21,7 +26,7 @@ import lombok.*;
|
||||
obj.getTags();
|
||||
obj.setScore(1.5);
|
||||
|
||||
Exercise<Integer> ex = Exercise.of("name", 12);
|
||||
Exercise<Integer> ex = Exercise.of("name", 12, Arrays.asList(1, 2, 3));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +43,6 @@ fun box(): String {
|
||||
obj.score = 2.5
|
||||
assertEquals(obj.score, 2.5)
|
||||
|
||||
val ex: DataExample.Exercise<Int> = DataExample.Exercise.of("name", 12)
|
||||
val ex: DataExample.Exercise<Int> = DataExample.Exercise.of("name", 12, listOf(1, 2, 3))
|
||||
return "OK"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
// KT-46529
|
||||
|
||||
// FILE: PrefixJava.java
|
||||
|
||||
import lombok.*;
|
||||
import lombok.experimental.*;
|
||||
|
||||
@Getter @Setter @Accessors(chain = false, fluent = true, prefix = {"pxo"})
|
||||
public class PrefixJava {
|
||||
private String pxaPropA = "A";
|
||||
@Accessors(chain = true) private String pxoPropC = "C";
|
||||
@Accessors private String pxaPropD = "D";
|
||||
}
|
||||
|
||||
|
||||
// FILE: test.kt
|
||||
|
||||
fun test() {
|
||||
//not generated because doesn't have prefix from class level @Accessors
|
||||
assertEquals(<!ARGUMENT_TYPE_MISMATCH!>PrefixJava().<!UNRESOLVED_REFERENCE!>propA<!><!>, "A")
|
||||
//not generated because doesn't have prefix from config
|
||||
assertEquals(<!ARGUMENT_TYPE_MISMATCH!>PrefixJava().<!UNRESOLVED_REFERENCE!>propC<!><!>, "C")
|
||||
assertEquals(PrefixJava().propD, "D")
|
||||
}
|
||||
|
||||
// FILE: lombok.config
|
||||
lombok.accessors.prefix += pxa
|
||||
@@ -1,4 +1,3 @@
|
||||
// FIR_IDENTICAL
|
||||
// KT-46529
|
||||
|
||||
// FILE: PrefixJava.java
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
// FILE: GetterTest.java
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
|
||||
public class GetterTest {
|
||||
@Getter private int age = 10;
|
||||
|
||||
@Getter(AccessLevel.PROTECTED) private String name;
|
||||
|
||||
@Getter private boolean primitiveBoolean;
|
||||
|
||||
@Getter private Boolean boxedBoolean;
|
||||
|
||||
@Getter(AccessLevel.NONE) private Boolean invisible;
|
||||
|
||||
void test() {
|
||||
getAge();
|
||||
isPrimitiveBoolean();
|
||||
// getInvisible();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// FILE: test.kt
|
||||
|
||||
fun test() {
|
||||
val obj = GetterTest()
|
||||
val getter = obj.getAge()
|
||||
val property = obj.age
|
||||
|
||||
//todo kotlin doesn't seee isBoolean methods as property
|
||||
obj.<!INVISIBLE_REFERENCE!>primitiveBoolean<!>
|
||||
obj.isPrimitiveBoolean()
|
||||
|
||||
obj.boxedBoolean
|
||||
obj.getBoxedBoolean()
|
||||
|
||||
//shouldn't be accesible from here
|
||||
obj.<!INVISIBLE_REFERENCE!>getName<!>()
|
||||
|
||||
obj.<!UNRESOLVED_REFERENCE!>getInvisible<!>()
|
||||
|
||||
OverridenGetterTest().usage()
|
||||
}
|
||||
|
||||
class OverridenGetterTest : GetterTest() {
|
||||
fun usage() {
|
||||
getName()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// FIR_IDENTICAL
|
||||
// FILE: GetterTest.java
|
||||
|
||||
import lombok.AccessLevel;
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
// FILE: ClassLevelGetterTest.java
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class ClassLevelGetterTest {
|
||||
private int age = 10;
|
||||
|
||||
@Getter(AccessLevel.PROTECTED) private String name;
|
||||
|
||||
private boolean primitiveBoolean;
|
||||
|
||||
private Boolean boxedBoolean;
|
||||
|
||||
void test() {
|
||||
getAge();
|
||||
isPrimitiveBoolean();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// FILE: test.kt
|
||||
|
||||
fun test() {
|
||||
val obj = ClassLevelGetterTest()
|
||||
val getter = obj.getAge()
|
||||
val property = obj.age
|
||||
|
||||
obj.isPrimitiveBoolean()
|
||||
|
||||
obj.boxedBoolean
|
||||
obj.getBoxedBoolean()
|
||||
|
||||
//shouldn't be accesible from here
|
||||
obj.<!INVISIBLE_REFERENCE!>getName<!>()
|
||||
|
||||
OverridenGetterTest().usage()
|
||||
}
|
||||
|
||||
class OverridenGetterTest : ClassLevelGetterTest() {
|
||||
fun usage() {
|
||||
getName()
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
// FIR_IDENTICAL
|
||||
// FILE: ClassLevelGetterTest.java
|
||||
|
||||
import lombok.AccessLevel;
|
||||
|
||||
@@ -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
|
||||
|
||||
fun test() {
|
||||
val obj = SetterTest()
|
||||
obj.setAge(42)
|
||||
obj.age = 42
|
||||
|
||||
//synthetic property generated only when there is a getter
|
||||
obj.<!INVISIBLE_REFERENCE!>primitiveBoolean<!> = false
|
||||
obj.setPrimitiveBoolean(true)
|
||||
|
||||
//shouldn't be accesible from here
|
||||
obj.<!INVISIBLE_REFERENCE!>setName<!>("abc")
|
||||
|
||||
OverridenGetterTest().usage()
|
||||
}
|
||||
|
||||
class OverridenGetterTest : SetterTest() {
|
||||
fun usage() {
|
||||
setName("abc")
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
// FIR_IDENTICAL
|
||||
// FILE: SetterTest.java
|
||||
|
||||
import lombok.AccessLevel;
|
||||
|
||||
Generated
+1
-1
@@ -27,7 +27,7 @@ public class DiagnosticTestForLombokGenerated extends AbstractDiagnosticTestForL
|
||||
|
||||
@Test
|
||||
public void testAllFilesPresentInDiagnostics() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/lombok/testData/diagnostics"), Pattern.compile("^(.+)\\.kt$"), null, true);
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/lombok/testData/diagnostics"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Generated
+165
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* 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 com.intellij.testFramework.TestDataPath;
|
||||
import org.jetbrains.kotlin.test.util.KtTestUtil;
|
||||
import org.jetbrains.kotlin.test.TargetBackend;
|
||||
import org.jetbrains.kotlin.test.TestMetadata;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/** This class is generated by {@link GenerateNewCompilerTests.kt}. DO NOT MODIFY MANUALLY */
|
||||
@SuppressWarnings("all")
|
||||
@TestMetadata("plugins/lombok/testData/box")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class FirBlackBoxCodegenTestForLombokGenerated extends AbstractFirBlackBoxCodegenTestForLombok {
|
||||
@Test
|
||||
@TestMetadata("accessorsStripPrefix.kt")
|
||||
public void testAccessorsStripPrefix() throws Exception {
|
||||
runTest("plugins/lombok/testData/box/accessorsStripPrefix.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("accessorsStripPrefixConfig.kt")
|
||||
public void testAccessorsStripPrefixConfig() throws Exception {
|
||||
runTest("plugins/lombok/testData/box/accessorsStripPrefixConfig.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("allArgsConstructor.kt")
|
||||
public void testAllArgsConstructor() throws Exception {
|
||||
runTest("plugins/lombok/testData/box/allArgsConstructor.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("allArgsConstructorStatic.kt")
|
||||
public void testAllArgsConstructorStatic() throws Exception {
|
||||
runTest("plugins/lombok/testData/box/allArgsConstructorStatic.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllFilesPresentInBox() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/lombok/testData/box"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("configAccessors.kt")
|
||||
public void testConfigAccessors() throws Exception {
|
||||
runTest("plugins/lombok/testData/box/configAccessors.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("configAccessorsOverride.kt")
|
||||
public void testConfigAccessorsOverride() throws Exception {
|
||||
runTest("plugins/lombok/testData/box/configAccessorsOverride.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("configCaseInsensitive.kt")
|
||||
public void testConfigCaseInsensitive() throws Exception {
|
||||
runTest("plugins/lombok/testData/box/configCaseInsensitive.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("configSimple.kt")
|
||||
public void testConfigSimple() throws Exception {
|
||||
runTest("plugins/lombok/testData/box/configSimple.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("data.kt")
|
||||
public void testData() throws Exception {
|
||||
runTest("plugins/lombok/testData/box/data.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("genericsAccessors.kt")
|
||||
public void testGenericsAccessors() throws Exception {
|
||||
runTest("plugins/lombok/testData/box/genericsAccessors.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("genericsConstructors.kt")
|
||||
public void testGenericsConstructors() throws Exception {
|
||||
runTest("plugins/lombok/testData/box/genericsConstructors.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("genericsConstructorsStatic.kt")
|
||||
public void testGenericsConstructorsStatic() throws Exception {
|
||||
runTest("plugins/lombok/testData/box/genericsConstructorsStatic.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("gettersFluent.kt")
|
||||
public void testGettersFluent() throws Exception {
|
||||
runTest("plugins/lombok/testData/box/gettersFluent.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("noArgsConstructor.kt")
|
||||
public void testNoArgsConstructor() throws Exception {
|
||||
runTest("plugins/lombok/testData/box/noArgsConstructor.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("noArgsConstructorStatic.kt")
|
||||
public void testNoArgsConstructorStatic() throws Exception {
|
||||
runTest("plugins/lombok/testData/box/noArgsConstructorStatic.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nullability.kt")
|
||||
public void testNullability() throws Exception {
|
||||
runTest("plugins/lombok/testData/box/nullability.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("propertyFromSuper.kt")
|
||||
public void testPropertyFromSuper() throws Exception {
|
||||
runTest("plugins/lombok/testData/box/propertyFromSuper.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("requiredArgsConstructor.kt")
|
||||
public void testRequiredArgsConstructor() throws Exception {
|
||||
runTest("plugins/lombok/testData/box/requiredArgsConstructor.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("requiredArgsConstructorStatic.kt")
|
||||
public void testRequiredArgsConstructorStatic() throws Exception {
|
||||
runTest("plugins/lombok/testData/box/requiredArgsConstructorStatic.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("settersVariations.kt")
|
||||
public void testSettersVariations() throws Exception {
|
||||
runTest("plugins/lombok/testData/box/settersVariations.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
runTest("plugins/lombok/testData/box/simple.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("value.kt")
|
||||
public void testValue() throws Exception {
|
||||
runTest("plugins/lombok/testData/box/value.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("with.kt")
|
||||
public void testWith() throws Exception {
|
||||
runTest("plugins/lombok/testData/box/with.kt");
|
||||
}
|
||||
}
|
||||
Generated
+68
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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 com.intellij.testFramework.TestDataPath;
|
||||
import org.jetbrains.kotlin.test.util.KtTestUtil;
|
||||
import org.jetbrains.kotlin.test.TestMetadata;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/** This class is generated by {@link GenerateNewCompilerTests.kt}. DO NOT MODIFY MANUALLY */
|
||||
@SuppressWarnings("all")
|
||||
@TestMetadata("plugins/lombok/testData/diagnostics")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class FirDiagnosticTestForLombokGenerated extends AbstractFirDiagnosticTestForLombok {
|
||||
@Test
|
||||
@TestMetadata("accessorsStripPrefixCombined.kt")
|
||||
public void testAccessorsStripPrefixCombined() throws Exception {
|
||||
runTest("plugins/lombok/testData/diagnostics/accessorsStripPrefixCombined.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllFilesPresentInDiagnostics() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/lombok/testData/diagnostics"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationTypes.kt")
|
||||
public void testAnnotationTypes() throws Exception {
|
||||
runTest("plugins/lombok/testData/diagnostics/annotationTypes.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("clashAccessors.kt")
|
||||
public void testClashAccessors() throws Exception {
|
||||
runTest("plugins/lombok/testData/diagnostics/clashAccessors.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("getters.kt")
|
||||
public void testGetters() throws Exception {
|
||||
runTest("plugins/lombok/testData/diagnostics/getters.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("gettersClassLevel.kt")
|
||||
public void testGettersClassLevel() throws Exception {
|
||||
runTest("plugins/lombok/testData/diagnostics/gettersClassLevel.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("setters.kt")
|
||||
public void testSetters() throws Exception {
|
||||
runTest("plugins/lombok/testData/diagnostics/setters.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("settersClassLevel.kt")
|
||||
public void testSettersClassLevel() throws Exception {
|
||||
runTest("plugins/lombok/testData/diagnostics/settersClassLevel.kt");
|
||||
}
|
||||
}
|
||||
@@ -14,8 +14,11 @@ import org.jetbrains.kotlin.test.directives.model.RegisteredDirectives
|
||||
import org.jetbrains.kotlin.test.model.TestFile
|
||||
import org.jetbrains.kotlin.test.model.TestModule
|
||||
import org.jetbrains.kotlin.test.runners.AbstractDiagnosticTest
|
||||
import org.jetbrains.kotlin.test.runners.AbstractFirDiagnosticTest
|
||||
import org.jetbrains.kotlin.test.runners.codegen.AbstractBlackBoxCodegenTest
|
||||
import org.jetbrains.kotlin.test.runners.codegen.AbstractFirBlackBoxCodegenTest
|
||||
import org.jetbrains.kotlin.test.runners.codegen.AbstractIrBlackBoxCodegenTest
|
||||
import org.jetbrains.kotlin.test.runners.configurationForClassicAndFirTestsAlongside
|
||||
import org.jetbrains.kotlin.test.services.*
|
||||
import org.jetbrains.kotlin.utils.PathUtil
|
||||
import java.io.File
|
||||
@@ -36,6 +39,13 @@ open class AbstractIrBlackBoxCodegenTestForLombok : AbstractIrBlackBoxCodegenTes
|
||||
}
|
||||
}
|
||||
|
||||
open class AbstractFirBlackBoxCodegenTestForLombok : AbstractFirBlackBoxCodegenTest() {
|
||||
override fun configure(builder: TestConfigurationBuilder) {
|
||||
super.configure(builder)
|
||||
builder.enableLombok()
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------- diagnostics ----------------------------
|
||||
|
||||
open class AbstractDiagnosticTestForLombok : AbstractDiagnosticTest() {
|
||||
@@ -45,6 +55,14 @@ open class AbstractDiagnosticTestForLombok : AbstractDiagnosticTest() {
|
||||
}
|
||||
}
|
||||
|
||||
open class AbstractFirDiagnosticTestForLombok : AbstractFirDiagnosticTest() {
|
||||
override fun configure(builder: TestConfigurationBuilder) {
|
||||
super.configure(builder)
|
||||
builder.configurationForClassicAndFirTestsAlongside()
|
||||
builder.enableLombok()
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------- configuration ----------------------------
|
||||
|
||||
fun TestConfigurationBuilder.enableLombok() {
|
||||
|
||||
@@ -355,6 +355,7 @@ include ":plugins:parcelize:parcelize-compiler",
|
||||
include ":kotlin-lombok-compiler-plugin",
|
||||
":kotlin-lombok-compiler-plugin.common",
|
||||
":kotlin-lombok-compiler-plugin.k1",
|
||||
":kotlin-lombok-compiler-plugin.k2",
|
||||
":kotlin-lombok-compiler-plugin.cli",
|
||||
":kotlin-lombok"
|
||||
|
||||
@@ -699,6 +700,7 @@ project(':kotlin-allopen-compiler-plugin.k2').projectDir = "$rootDir/plugins/all
|
||||
project(':kotlin-lombok-compiler-plugin').projectDir = "$rootDir/plugins/lombok" as File
|
||||
project(':kotlin-lombok-compiler-plugin.cli').projectDir = "$rootDir/plugins/lombok/lombok.cli" as File
|
||||
project(':kotlin-lombok-compiler-plugin.k1').projectDir = "$rootDir/plugins/lombok/lombok.k1" as File
|
||||
project(':kotlin-lombok-compiler-plugin.k2').projectDir = "$rootDir/plugins/lombok/lombok.k2" as File
|
||||
project(':kotlin-lombok-compiler-plugin.common').projectDir = "$rootDir/plugins/lombok/lombok.common" as File
|
||||
|
||||
project(':kotlin-noarg-compiler-plugin').projectDir = "$rootDir/plugins/noarg" as File
|
||||
|
||||
Reference in New Issue
Block a user