[lombok] Experimental lombok plugin prototype

Add extension point for java descriptors
Add simple usage of this point to generate getter method
Add simple test infrastructure to test compilation with lombok plugin
This commit is contained in:
Andrey Zinovyev
2021-03-24 13:09:50 +03:00
committed by TeamCityServer
parent ac86ad252f
commit f71e08df4d
30 changed files with 606 additions and 3 deletions
@@ -33,13 +33,11 @@ import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.extensions.ExtensionsArea
import com.intellij.openapi.fileTypes.PlainTextFileType
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.LanguageLevelProjectExtension
import com.intellij.openapi.util.Disposer
import com.intellij.openapi.util.io.FileUtilRt
import com.intellij.openapi.util.text.StringUtil
import com.intellij.openapi.vfs.*
import com.intellij.openapi.vfs.impl.ZipHandler
import com.intellij.pom.java.LanguageLevel
import com.intellij.psi.PsiElementFinder
import com.intellij.psi.PsiManager
import com.intellij.psi.impl.JavaClassSupersImpl
@@ -94,6 +92,7 @@ import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.CodeAnalyzerInitializer
import org.jetbrains.kotlin.resolve.ModuleAnnotationsResolver
import org.jetbrains.kotlin.resolve.extensions.ExtraImportsProviderExtension
import org.jetbrains.kotlin.resolve.jvm.extensions.SyntheticJavaResolveExtension
import org.jetbrains.kotlin.resolve.extensions.SyntheticResolveExtension
import org.jetbrains.kotlin.resolve.jvm.KotlinJavaPsiFacade
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension
@@ -577,6 +576,7 @@ class KotlinCoreEnvironment private constructor(
fun registerPluginExtensionPoints(project: MockProject) {
ExpressionCodegenExtension.registerExtensionPoint(project)
SyntheticResolveExtension.registerExtensionPoint(project)
SyntheticJavaResolveExtension.registerExtensionPoint(project)
ClassBuilderInterceptorExtension.registerExtensionPoint(project)
AnalysisHandlerExtension.registerExtensionPoint(project)
PackageFragmentProviderExtension.registerExtensionPoint(project)
@@ -96,6 +96,7 @@ import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.CodeAnalyzerInitializer
import org.jetbrains.kotlin.resolve.ModuleAnnotationsResolver
import org.jetbrains.kotlin.resolve.extensions.ExtraImportsProviderExtension
import org.jetbrains.kotlin.resolve.jvm.extensions.SyntheticJavaResolveExtension
import org.jetbrains.kotlin.resolve.extensions.SyntheticResolveExtension
import org.jetbrains.kotlin.resolve.jvm.KotlinJavaPsiFacade
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension
@@ -569,6 +570,7 @@ class KotlinCoreEnvironment private constructor(
fun registerPluginExtensionPoints(project: MockProject) {
ExpressionCodegenExtension.registerExtensionPoint(project)
SyntheticResolveExtension.registerExtensionPoint(project)
SyntheticJavaResolveExtension.registerExtensionPoint(project)
ClassBuilderInterceptorExtension.registerExtensionPoint(project)
AnalysisHandlerExtension.registerExtensionPoint(project)
PackageFragmentProviderExtension.registerExtensionPoint(project)
@@ -45,6 +45,7 @@ import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.calls.tower.ImplicitsExtensionsResolutionFilter
import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver
import org.jetbrains.kotlin.resolve.jvm.JvmDiagnosticComponents
import org.jetbrains.kotlin.resolve.jvm.extensions.SyntheticJavaResolveExtension
import org.jetbrains.kotlin.resolve.jvm.multiplatform.OptionalAnnotationPackageFragmentProvider
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices
import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactory
@@ -116,6 +117,8 @@ fun StorageComponentContainer.configureJavaSpecificComponents(
useInstance(JavaDeprecationSettings)
useInstance(moduleClassResolver)
useInstance(SyntheticJavaResolveExtension.getProvider(moduleContext.project))
if (configureJavaClassFinder != null) {
configureJavaClassFinder()
} else {
@@ -0,0 +1,32 @@
/*
* 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.resolve.jvm.extensions
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.extensions.ProjectExtensionDescriptor
import org.jetbrains.kotlin.resolve.jvm.CompositeSyntheticJavaPartsProvider
import org.jetbrains.kotlin.resolve.jvm.SyntheticJavaPartsProvider
interface SyntheticJavaResolveExtension {
companion object : ProjectExtensionDescriptor<SyntheticJavaResolveExtension>(
"org.jetbrains.kotlin.syntheticJavaResolveExtension", SyntheticJavaResolveExtension::class.java
) {
fun getProvider(project: Project): SyntheticJavaPartsProvider {
val instances = getInstances(project)
val providers = instances.map { it.getProvider() }
return if (providers.isEmpty()) {
SyntheticJavaPartsProvider.EMPTY
} else {
CompositeSyntheticJavaPartsProvider(providers)
}
}
}
fun getProvider(): SyntheticJavaPartsProvider
}
@@ -35,6 +35,7 @@ import org.jetbrains.kotlin.load.java.typeEnhancement.SignatureEnhancement
import org.jetbrains.kotlin.load.kotlin.DeserializedDescriptorResolver
import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder
import org.jetbrains.kotlin.load.kotlin.PackagePartProvider
import org.jetbrains.kotlin.resolve.jvm.SyntheticJavaPartsProvider
import org.jetbrains.kotlin.resolve.sam.SamConversionResolver
import org.jetbrains.kotlin.serialization.deserialization.ErrorReporter
import org.jetbrains.kotlin.storage.StorageManager
@@ -63,7 +64,8 @@ class JavaResolverComponents(
val javaClassesTracker: JavaClassesTracker,
val settings: JavaResolverSettings,
val kotlinTypeChecker: NewKotlinTypeChecker,
val javaTypeEnhancementState: JavaTypeEnhancementState
val javaTypeEnhancementState: JavaTypeEnhancementState,
val syntheticPartsProvider: SyntheticJavaPartsProvider = SyntheticJavaPartsProvider.EMPTY
) {
fun replace(
javaResolverCache: JavaResolverCache = this.javaResolverCache
@@ -78,6 +78,7 @@ class LazyJavaClassMemberScope(
addAll(declaredMemberIndex().getMethodNames())
addAll(declaredMemberIndex().getRecordComponentNames())
addAll(computeClassNames(kindFilter, nameFilter))
addAll(c.components.syntheticPartsProvider.getSyntheticFunctionNames(ownerDescriptor))
}
internal val constructors = c.storageManager.createLazyValue {
@@ -496,6 +497,8 @@ class LazyJavaClassMemberScope(
if (jClass.isRecord && declaredMemberIndex().findRecordComponentByName(name) != null && result.none { it.valueParameters.isEmpty() }) {
result.add(resolveRecordComponentToFunctionDescriptor(declaredMemberIndex().findRecordComponentByName(name)!!))
}
c.components.syntheticPartsProvider.generateSyntheticMethods(ownerDescriptor, name, result)
}
private fun resolveRecordComponentToFunctionDescriptor(recordComponent: JavaRecordComponent): JavaMethodDescriptor {
@@ -0,0 +1,37 @@
/*
* 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.resolve.jvm
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
import org.jetbrains.kotlin.name.Name
interface SyntheticJavaPartsProvider {
companion object {
val EMPTY = CompositeSyntheticJavaPartsProvider(emptyList())
}
fun getSyntheticFunctionNames(thisDescriptor: ClassDescriptor): List<Name>
fun generateSyntheticMethods(
thisDescriptor: ClassDescriptor,
name: Name,
result: MutableCollection<SimpleFunctionDescriptor>
)
}
class CompositeSyntheticJavaPartsProvider(private val inner: List<SyntheticJavaPartsProvider>) : SyntheticJavaPartsProvider {
override fun getSyntheticFunctionNames(thisDescriptor: ClassDescriptor): List<Name> =
inner.flatMap { it.getSyntheticFunctionNames(thisDescriptor) }
override fun generateSyntheticMethods(
thisDescriptor: ClassDescriptor,
name: Name,
result: MutableCollection<SimpleFunctionDescriptor>
) = inner.forEach { it.generateSyntheticMethods(thisDescriptor, name, result) }
}
+1
View File
@@ -68,6 +68,7 @@ dependencies {
testCompile(projectTests(":kotlin-annotation-processing-cli"))
testCompile(projectTests(":kotlin-allopen-compiler-plugin"))
testCompile(projectTests(":kotlin-noarg-compiler-plugin"))
testCompile(projectTests(":plugins:lombok:lombok-compiler-plugin"))
testCompile(projectTests(":kotlin-sam-with-receiver-compiler-plugin"))
testCompile(projectTests(":kotlinx-serialization-compiler-plugin"))
testCompile(projectTests(":kotlinx-serialization-ide-plugin"))
@@ -166,6 +166,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.AbstractLombokCompileTest
import org.jetbrains.kotlin.nj2k.AbstractNewJavaToKotlinConverterMultiFileTest
import org.jetbrains.kotlin.nj2k.AbstractNewJavaToKotlinConverterSingleFileTest
import org.jetbrains.kotlin.nj2k.AbstractNewJavaToKotlinCopyPasteConversionTest
@@ -1858,6 +1859,12 @@ fun main(args: Array<String>) {
model("handlers/charFilter", testMethod = "doPerfTest", pattern = KT_WITHOUT_DOTS_IN_NAME)
}
}
testGroup("plugins/lombok/lombok-compiler-plugin/tests", "plugins/lombok/lombok-compiler-plugin/testData") {
testClass<AbstractLombokCompileTest> {
model("compile")
}
}
/*
testGroup("plugins/android-extensions/android-extensions-idea/tests", "plugins/android-extensions/android-extensions-idea/testData") {
testClass<AbstractAndroidCompletionTest> {
@@ -137,6 +137,7 @@ import org.jetbrains.kotlin.kapt.cli.test.AbstractArgumentParsingTest
import org.jetbrains.kotlin.kapt.cli.test.AbstractKaptToolIntegrationTest
import org.jetbrains.kotlin.kapt3.test.AbstractClassFileToSourceStubConverterTest
import org.jetbrains.kotlin.kapt3.test.AbstractKotlinKaptContextTest
import org.jetbrains.kotlin.lombok.AbstractLombokCompileTest
import org.jetbrains.kotlin.nj2k.AbstractNewJavaToKotlinConverterMultiFileTest
import org.jetbrains.kotlin.nj2k.AbstractNewJavaToKotlinConverterSingleFileTest
import org.jetbrains.kotlin.nj2k.AbstractNewJavaToKotlinCopyPasteConversionTest
@@ -1140,6 +1141,12 @@ fun main(args: Array<String>) {
model("quickfix", pattern = "^([\\w\\-_]+)\\.kt$", filenameStartsLowerCase = true)
}
}
testGroup("plugins/lombok/lombok-compiler-plugin/tests", "plugins/lombok/lombok-compiler-plugin/testData") {
testClass<AbstractLombokCompileTest> {
model("compile")
}
}
/*
testGroup("plugins/android-extensions/android-extensions-idea/tests", "plugins/android-extensions/android-extensions-idea/testData") {
testClass<AbstractAndroidCompletionTest> {
+6
View File
@@ -11054,6 +11054,12 @@
<sha256 value="e07bce4bb55d5a06f4c10d912fc9dee8a9b9c04ec549bbb8db4f20db34706f75" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.projectlombok" name="lombok" version="1.18.16">
<artifact name="lombok-1.18.16.jar">
<md5 value="fca4ae86d65bc29ad22cb971bd3e3700"/>
<sha256 value="7206cbbfd6efd5e85bceff29545633645650be58d58910a23b0d4835fbd15ed7"/>
</artifact>
</component>
<component group="org.robolectric" name="android-all" version="4.4_r1-robolectric-1">
<artifact name="android-all-4.4_r1-robolectric-1.jar">
<md5 value="1e478f10e107d1dddad09d32508f2ec9" origin="Generated by Gradle"/>
@@ -0,0 +1,42 @@
description = "Lombok compiler plugin"
plugins {
kotlin("jvm")
id("jps-compatible")
}
dependencies {
implementation(project(":compiler:util"))
implementation(project(":compiler:plugin-api"))
implementation(project(":compiler:frontend"))
implementation(project(":compiler:frontend.java"))
compileOnly(intellijCoreDep()) { includeJars("intellij-core") }
testImplementation(intellijCoreDep()) { includeJars("intellij-core") }
testImplementation(commonDep("junit:junit"))
testImplementation(projectTests(":compiler:tests-common"))
testImplementation("org.projectlombok:lombok:1.18.16")
testRuntimeOnly(toolsJar())
}
sourceSets {
"main" { projectDefault() }
"test" { projectDefault() }
}
projectTest(parallel = true) {
workingDir = rootDir
dependsOn(":dist")
}
publish()
runtimeJar()
testsJar()
sourcesJar()
javadocJar()
@@ -0,0 +1 @@
org.jetbrains.kotlin.lombok.LombokComponentRegistrar
@@ -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
import com.intellij.mock.MockProject
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.resolve.jvm.extensions.SyntheticJavaResolveExtension
class LombokComponentRegistrar : ComponentRegistrar {
companion object {
fun registerComponents(project: Project) {
SyntheticJavaResolveExtension.registerExtension(project, LombokResolveExtension())
}
}
override fun registerProjectComponents(project: MockProject, configuration: CompilerConfiguration) {
registerComponents(project)
}
}
@@ -0,0 +1,14 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.lombok
import org.jetbrains.kotlin.resolve.jvm.SyntheticJavaPartsProvider
import org.jetbrains.kotlin.resolve.jvm.extensions.SyntheticJavaResolveExtension
class LombokResolveExtension : SyntheticJavaResolveExtension {
override fun getProvider(): SyntheticJavaPartsProvider = LombokSyntheticJavaPartsProvider()
}
@@ -0,0 +1,57 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.lombok
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
import org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaClassDescriptor
import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl
import org.jetbrains.kotlin.lombok.processor.GetterProcessor
import org.jetbrains.kotlin.lombok.processor.Parts
import org.jetbrains.kotlin.lombok.processor.Processor
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.jvm.SyntheticJavaPartsProvider
import java.util.*
class LombokSyntheticJavaPartsProvider : SyntheticJavaPartsProvider {
private val processors = initProcessors()
private fun initProcessors(): List<Processor> =
listOf(
GetterProcessor()
)
private val partsCache: MutableMap<ClassDescriptor, Parts> = WeakHashMap()
override fun getSyntheticFunctionNames(thisDescriptor: ClassDescriptor): List<Name> =
getSyntheticParts(thisDescriptor).methods.map { it.name }
override fun generateSyntheticMethods(
thisDescriptor: ClassDescriptor,
name: Name,
result: MutableCollection<SimpleFunctionDescriptor>
) {
getSyntheticParts(thisDescriptor).methods.find { it.name == name }?.let {
result.add(it)
}
}
private fun extractClass(descriptor: ClassDescriptor): JavaClassImpl? =
(descriptor as? LazyJavaClassDescriptor)?.jClass as? JavaClassImpl
private fun getSyntheticParts(descriptor: ClassDescriptor): Parts =
extractClass(descriptor)?.let { jClass ->
partsCache.getOrPut(descriptor) {
computeSyntheticParts(descriptor, jClass)
}
} ?: Parts.Empty
private fun computeSyntheticParts(descriptor: ClassDescriptor, jClass: JavaClassImpl): Parts =
processors.map { it.contribute(descriptor, jClass) }.reduce { a, b -> a + b }
}
@@ -0,0 +1,9 @@
/*
* 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.config
class LombokConfig {
}
@@ -0,0 +1,63 @@
/*
* 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.processor
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl
import org.jetbrains.kotlin.lombok.utils.LombokAnnotationNames
import org.jetbrains.kotlin.lombok.utils.createFunction
import org.jetbrains.kotlin.lombok.utils.getVisibility
import org.jetbrains.kotlin.lombok.utils.toPreparedBase
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.model.SimpleTypeMarker
import org.jetbrains.kotlin.types.typeUtil.isBoolean
import org.jetbrains.kotlin.types.typeUtil.isPrimitiveNumberType
class GetterProcessor : Processor {
override fun contribute(classDescriptor: ClassDescriptor, jClass: JavaClassImpl): Parts {
val functions = classDescriptor.unsubstitutedMemberScope.getVariableNames()
.map {
classDescriptor.unsubstitutedMemberScope.getContributedVariables(it, NoLookupLocation.FROM_SYNTHETIC_SCOPE).single()
}.collectWithNotNull { it.annotations.findAnnotation(LombokAnnotationNames.GETTER) }
.mapNotNull { (field, annotation) -> createGetter(classDescriptor, field, annotation) }
// val functions = jClass.fields.collectWithNotNull { it.findAnnotation(LombokAnnotationNames.GETTER) }.mapNotNull { (field, annotation) ->
// createGetter(classDescriptor, field, annotation)
// }
return Parts(functions)
}
private fun createGetter(
classDescriptor: ClassDescriptor,
field: PropertyDescriptor,
annotation: AnnotationDescriptor
): SimpleFunctionDescriptor? {
val prefix = if (field.type.isPrimitiveBoolean()) "is" else "get"
val functionName = Name.identifier(prefix + toPreparedBase(field.name.identifier))
return createFunction(
classDescriptor,
functionName,
emptyList(),
field.returnType,
visibility = getVisibility(annotation)
)
}
@Suppress("UNCHECKED_CAST")
internal fun <E, R> Collection<E>.collectWithNotNull(f: (E) -> R?): List<Pair<E, R>> =
map { it to f(it) }.filter { it.second != null } as List<Pair<E, R>>
private fun KotlinType.isPrimitiveBoolean(): Boolean = this is SimpleTypeMarker && isBoolean() //todo
}
@@ -0,0 +1,17 @@
/*
* 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.processor
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
data class Parts(val methods: List<SimpleFunctionDescriptor> = emptyList()) {
operator fun plus(other: Parts): Parts = Parts(methods + other.methods)
companion object {
val Empty = Parts()
}
}
@@ -0,0 +1,14 @@
/*
* 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.processor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl
interface Processor {
fun contribute(classDescriptor: ClassDescriptor, jClass: JavaClassImpl): Parts
}
@@ -0,0 +1,15 @@
/*
* 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.name.FqName
object LombokAnnotationNames {
val GETTER = FqName("lombok.Getter")
val SETTER = FqName("lombok.Setter")
}
@@ -0,0 +1,63 @@
/*
* 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.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.DescriptorVisibility
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.descriptors.java.JavaVisibilities
import org.jetbrains.kotlin.load.java.structure.JavaAnnotation
import org.jetbrains.kotlin.load.java.structure.JavaEnumValueAnnotationArgument
import org.jetbrains.kotlin.load.java.structure.JavaLiteralAnnotationArgument
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.constants.EnumValue
import java.lang.IllegalArgumentException
internal fun getVisibility(annotation: JavaAnnotation, field: String = "value"): DescriptorVisibility {
val value = getStringAnnotationValue(annotation, field, "PUBLIC")
val visibility = when (value) {
"PUBLIC" -> Visibilities.Public
"PROTECTED" -> Visibilities.Protected
"PRIVATE" -> Visibilities.Private
"PACKAGE" -> JavaVisibilities.PackageVisibility
else -> Visibilities.Public
}
return DescriptorVisibilities.toDescriptorVisibility(visibility)
}
internal fun getVisibility(annotation: AnnotationDescriptor, field: String = "value"): DescriptorVisibility {
val value = getStringAnnotationValue(annotation, field, "PUBLIC")
val visibility = when (value) {
"PUBLIC" -> Visibilities.Public
"PROTECTED" -> Visibilities.Protected
"PRIVATE" -> Visibilities.Private
"PACKAGE" -> JavaVisibilities.PackageVisibility
else -> Visibilities.Public
}
return DescriptorVisibilities.toDescriptorVisibility(visibility)
}
private fun getStringAnnotationValue(annotation: JavaAnnotation, argumentName: String, default: String): String {
val argument = annotation.arguments.find { it.name?.identifier == argumentName }
?: throw IllegalArgumentException("No argument '$argumentName' found in $annotation")
return when (argument) {
is JavaEnumValueAnnotationArgument -> argument.entryName?.asString() ?: default
is JavaLiteralAnnotationArgument -> argument.value?.toString() ?: default
else -> throw RuntimeException("Argument $argument is not supported")
}
}
private fun getStringAnnotationValue(annotation: AnnotationDescriptor, argumentName: String, default: String): String {
val argument = annotation.allValueArguments[Name.identifier(argumentName)]
?: return default
return when (argument) {
is EnumValue -> argument.enumEntryName.identifier
else -> throw RuntimeException("Argument $argument is not supported")
}
}
@@ -0,0 +1,39 @@
/*
* 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.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.KotlinType
internal fun createFunction(
containingClass: ClassDescriptor,
name: Name,
valueParameters: List<ValueParameterDescriptor>,
returnType: KotlinType?,
modality: Modality? = Modality.OPEN,
visibility: DescriptorVisibility = DescriptorVisibilities.PUBLIC
): SimpleFunctionDescriptor {
val methodDescriptor = SimpleFunctionDescriptorImpl.create(
containingClass,
Annotations.EMPTY,
name,
CallableMemberDescriptor.Kind.SYNTHESIZED,
containingClass.source
)
methodDescriptor.initialize(
null,
containingClass.thisAsReceiverParameter,
mutableListOf(),
valueParameters,
returnType,
modality,
visibility
)
return methodDescriptor
}
@@ -0,0 +1,10 @@
/*
* 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.util.capitalizeDecapitalize.capitalizeAsciiOnly
internal fun toPreparedBase(name: String): String = name.capitalizeAsciiOnly()
@@ -0,0 +1,38 @@
//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;
void test() {
getAge();
isPrimitiveBoolean();
}
}
//FILE: test.kt
object Test {
fun usage() {
val obj = GetterTest()
val getter = obj.getAge()
val property = obj.age
//todo kotlin doesn't see isBoolean methods as properties
// obj.primitiveBoolean
obj.isPrimitiveBoolean()
obj.boxedBoolean
obj.getBoxedBoolean()
}
}
@@ -0,0 +1,22 @@
//FILE: GetterSetterExample.java
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
public class GetterSetterExample {
@Getter @Setter private int age = 10;
@Getter(AccessLevel.PROTECTED) private String name;
}
//FILE: test.kt
object Test {
fun usage() {
val obj = GetterSetterExample()
val getter = obj.getAge()
val property = obj.age
}
}
@@ -0,0 +1,31 @@
/*
* 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 lombok.Getter
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot
import org.jetbrains.kotlin.codegen.CodegenTestCase
import org.jetbrains.kotlin.utils.PathUtil
import java.io.File
abstract class AbstractLombokCompileTest : CodegenTestCase() {
override fun doMultiFileTest(wholeFile: File, files: List<TestFile>) {
compile(files)
}
override fun setupEnvironment(environment: KotlinCoreEnvironment) {
LombokComponentRegistrar.registerComponents(environment.project)
environment.updateClasspath(listOf(JvmClasspathRoot(getLombokJar())))
}
override fun updateJavaClasspath(javaClasspath: MutableList<String>) {
javaClasspath += getLombokJar().absolutePath
}
private fun getLombokJar(): File = PathUtil.getResourcePathForClass(Getter::class.java)
}
@@ -0,0 +1,41 @@
/*
* 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.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.runner.RunWith;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("plugins/lombok/lombok-compiler-plugin/testData/compile")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public class LombokCompileTestGenerated extends AbstractLombokCompileTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInCompile() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/lombok/lombok-compiler-plugin/testData/compile"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@TestMetadata("getters.kt")
public void testGetters() throws Exception {
runTest("plugins/lombok/lombok-compiler-plugin/testData/compile/getters.kt");
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("plugins/lombok/lombok-compiler-plugin/testData/compile/simple.kt");
}
}
+2
View File
@@ -346,6 +346,8 @@ include ":plugins:parcelize:parcelize-compiler",
":plugins:parcelize:parcelize-runtime",
":kotlin-parcelize-compiler"
include ":plugins:lombok:lombok-compiler-plugin"
include ":prepare:ide-plugin-dependencies:android-extensions-compiler-plugin-for-ide",
":prepare:ide-plugin-dependencies:allopen-compiler-plugin-for-ide",
":prepare:ide-plugin-dependencies:allopen-compiler-plugin-tests-for-ide",