[Lombok] Make visibility of fields of @Value classes private by default (K1)

^KT-51092
This commit is contained in:
Dmitriy Novozhilov
2023-02-07 15:22:52 +02:00
committed by Space Team
parent a9248569a6
commit 0550f0d394
9 changed files with 89 additions and 8 deletions
@@ -292,7 +292,7 @@ abstract class LazyJavaScope(
}
private fun resolveProperty(field: JavaField): PropertyDescriptor {
val propertyDescriptor = createPropertyDescriptor(field)
var propertyDescriptor = createPropertyDescriptor(field)
// Annotations on Java fields are loaded as property annotations, therefore backingField = null below
propertyDescriptor.initialize(null, null, null, null)
@@ -305,6 +305,9 @@ abstract class LazyJavaScope(
null,
emptyList()
)
(ownerDescriptor as? ClassDescriptor)?.let { classDescriptor ->
propertyDescriptor = with(c) { c.components.syntheticPartsProvider.modifyField(classDescriptor, propertyDescriptor) }
}
if (DescriptorUtils.shouldRecordInitializerForProperty(propertyDescriptor, propertyDescriptor.type)) {
propertyDescriptor.setCompileTimeInitializerFactory {
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.resolve.jvm
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext
import org.jetbrains.kotlin.name.Name
@@ -45,6 +46,9 @@ interface SyntheticJavaPartsProvider {
context(LazyJavaResolverContext)
fun generateNestedClass(thisDescriptor: ClassDescriptor, name: Name, result: MutableList<ClassDescriptor>)
context(LazyJavaResolverContext)
fun modifyField(thisDescriptor: ClassDescriptor, propertyDescriptor: PropertyDescriptorImpl): PropertyDescriptorImpl
}
@Suppress("IncorrectFormatting") // KTIJ-22227
@@ -86,4 +90,12 @@ class CompositeSyntheticJavaPartsProvider(private val inner: List<SyntheticJavaP
override fun generateNestedClass(thisDescriptor: ClassDescriptor, name: Name, result: MutableList<ClassDescriptor>) {
inner.forEach { it.generateNestedClass(thisDescriptor, name, result) }
}
context(LazyJavaResolverContext)
override fun modifyField(
thisDescriptor: ClassDescriptor,
propertyDescriptor: PropertyDescriptorImpl
): PropertyDescriptorImpl {
return inner.fold(propertyDescriptor) { property, provider -> provider.modifyField(thisDescriptor, property) }
}
}
@@ -16,6 +16,7 @@ object LombokNames {
val WITH = FqName("lombok.With")
val DATA = FqName("lombok.Data")
val VALUE = FqName("lombok.Value")
val PACKAGE_PRIVATE = FqName("lombok.PackagePrivate")
val NO_ARGS_CONSTRUCTOR = FqName("lombok.NoArgsConstructor")
val ALL_ARGS_CONSTRUCTOR = FqName("lombok.AllArgsConstructor")
val REQUIRED_ARGS_CONSTRUCTOR = FqName("lombok.RequiredArgsConstructor")
@@ -5,16 +5,13 @@
package org.jetbrains.kotlin.lombok
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext
import org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaClassDescriptor
import org.jetbrains.kotlin.load.java.lazy.descriptors.SyntheticJavaClassDescriptor
import org.jetbrains.kotlin.lombok.config.LombokConfig
import org.jetbrains.kotlin.lombok.processor.*
import org.jetbrains.kotlin.lombok.utils.getJavaClass
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.jvm.SyntheticJavaPartsProvider
import java.util.*
@@ -36,6 +33,8 @@ class LombokSyntheticJavaPartsProvider(config: LombokConfig) : SyntheticJavaPart
BuilderProcessor(config)
)
private val valueFieldModifier = ValueFieldModifier(config)
/**
* kotlin resolve references in two calls - first it gets names, then actual member descriptor
* but for us it is much easier to run full generation for class once
@@ -102,6 +101,14 @@ class LombokSyntheticJavaPartsProvider(config: LombokConfig) : SyntheticJavaPart
return builder.build()
}
context(LazyJavaResolverContext)
override fun modifyField(
thisDescriptor: ClassDescriptor,
propertyDescriptor: PropertyDescriptorImpl
): PropertyDescriptorImpl {
return valueFieldModifier.modifyField(thisDescriptor, propertyDescriptor) ?: propertyDescriptor
}
/**
* Deduplicates generated functions using name and argument counts, as lombok does
*/
@@ -113,9 +120,7 @@ class LombokSyntheticJavaPartsProvider(config: LombokConfig) : SyntheticJavaPart
}
}
companion object {
/**
* Lombok treat functions as having the same signature by arguments count only
* Corresponding code in lombok - https://github.com/projectlombok/lombok/blob/v1.18.20/src/core/lombok/javac/handlers/JavacHandlerUtil.java#L752
@@ -0,0 +1,24 @@
/*
* Copyright 2010-2023 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.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
import org.jetbrains.kotlin.load.java.JavaDescriptorVisibilities
import org.jetbrains.kotlin.lombok.config.LombokAnnotations
import org.jetbrains.kotlin.lombok.config.LombokConfig
class ValueFieldModifier(val config: LombokConfig) {
fun modifyField(thisDescriptor: ClassDescriptor, propertyDescriptor: PropertyDescriptorImpl): PropertyDescriptorImpl? {
// Explicit visibility
if (propertyDescriptor.visibility != JavaDescriptorVisibilities.PACKAGE_VISIBILITY) return null
if (LombokAnnotations.Value.getOrNull(thisDescriptor) == null) return null
return propertyDescriptor.newCopyBuilder().apply {
setVisibility(DescriptorVisibilities.PRIVATE)
}.build() as? PropertyDescriptorImpl
}
}
+18
View File
@@ -0,0 +1,18 @@
// IGNORE_BACKEND_K2: JVM_IR
// ISSUE: KT-51092
// FILE: MyValue.java
import lombok.Value;
@Value
public class MyValue {
String defaultValue;
private String privateValue;
public String publicValue;
}
// FILE: main.kt
fun box(): String {
val x = MyValue("A", "B", "C")
val result = x.defaultValue + x.privateValue + x.publicValue;
return if (result == "ABC") "OK" else "Error: $x"
}
@@ -187,6 +187,12 @@ public class BlackBoxCodegenTestForLombokGenerated extends AbstractBlackBoxCodeg
runTest("plugins/lombok/testData/box/value.kt");
}
@Test
@TestMetadata("valueFieldAccess.kt")
public void testValueFieldAccess() throws Exception {
runTest("plugins/lombok/testData/box/valueFieldAccess.kt");
}
@Test
@TestMetadata("with.kt")
public void testWith() throws Exception {
@@ -187,6 +187,12 @@ public class FirBlackBoxCodegenTestForLombokGenerated extends AbstractFirBlackBo
runTest("plugins/lombok/testData/box/value.kt");
}
@Test
@TestMetadata("valueFieldAccess.kt")
public void testValueFieldAccess() throws Exception {
runTest("plugins/lombok/testData/box/valueFieldAccess.kt");
}
@Test
@TestMetadata("with.kt")
public void testWith() throws Exception {
@@ -187,6 +187,12 @@ public class IrBlackBoxCodegenTestForLombokGenerated extends AbstractIrBlackBoxC
runTest("plugins/lombok/testData/box/value.kt");
}
@Test
@TestMetadata("valueFieldAccess.kt")
public void testValueFieldAccess() throws Exception {
runTest("plugins/lombok/testData/box/valueFieldAccess.kt");
}
@Test
@TestMetadata("with.kt")
public void testWith() throws Exception {