jvm-abi-gen: Remove internal declarations from ABI

#KT-65690 Fixed
This commit is contained in:
Vladimir Tagakov
2024-02-08 11:54:13 -07:00
committed by Space Team
parent ebc2a18da5
commit d2792533b8
21 changed files with 263 additions and 37 deletions
@@ -10,18 +10,20 @@ import org.jetbrains.kotlin.backend.jvm.extensions.ClassGeneratorExtension
import org.jetbrains.kotlin.codegen.inline.coroutines.FOR_INLINE_SUFFIX
import org.jetbrains.kotlin.codegen.`when`.WhenByEnumsMapping
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.overrides.isEffectivelyPrivate
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.symbols.UnsafeDuringIrConstructionAPI
import org.jetbrains.kotlin.ir.util.isFileClass
import org.jetbrains.kotlin.ir.util.parentClassOrNull
import org.jetbrains.kotlin.ir.util.primaryConstructor
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
import org.jetbrains.org.objectweb.asm.AnnotationVisitor
import org.jetbrains.org.objectweb.asm.FieldVisitor
import org.jetbrains.org.objectweb.asm.MethodVisitor
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.commons.Method
import kotlin.metadata.jvm.JvmFieldSignature
import kotlin.metadata.jvm.JvmMemberSignature
import kotlin.metadata.jvm.JvmMethodSignature
enum class AbiMethodInfo {
KEEP,
@@ -30,7 +32,7 @@ enum class AbiMethodInfo {
sealed class AbiClassInfo {
object Public : AbiClassInfo()
class Stripped(val methodInfo: Map<Method, AbiMethodInfo>, val prune: Boolean = false) : AbiClassInfo()
class Stripped(val memberInfo: Map<JvmMemberSignature, AbiMethodInfo>, val prune: Boolean = false) : AbiClassInfo()
object Deleted : AbiClassInfo()
}
@@ -62,6 +64,7 @@ sealed class AbiClassInfo {
class JvmAbiClassBuilderInterceptor(
private val removeDataClassCopyIfConstructorIsPrivate: Boolean,
private val removePrivateClasses: Boolean,
private val treatInternalAsPrivate: Boolean,
) : ClassGeneratorExtension {
private var abiClassInfoBuilder = JvmAbiClassInfoBuilder(removePrivateClasses)
@@ -80,18 +83,22 @@ class JvmAbiClassBuilderInterceptor(
) : ClassGenerator by delegate {
private val isPrivateClass = irClass != null && DescriptorVisibilities.isPrivate(irClass.visibility)
private val isDataClass = irClass != null && irClass.isData
private val removeClassFromAbi = shouldRemoveFromAbi(irClass, removePrivateClasses)
private val removeClassFromAbi = shouldRemoveFromAbi(irClass, removePrivateClasses, treatInternalAsPrivate)
@OptIn(UnsafeDuringIrConstructionAPI::class)
private val primaryConstructorIsNotInAbi =
irClass?.primaryConstructor?.visibility?.let(DescriptorVisibilities::isPrivate) == true
private val primaryConstructorIsNotInAbi = irClass
?.primaryConstructor
?.visibility
?.let {
DescriptorVisibilities.isPrivate(it) || (treatInternalAsPrivate && it == DescriptorVisibilities.INTERNAL)
} == true
lateinit var internalName: String
lateinit var superInterfaces: List<String>
var localOrAnonymousClass = false
var keepClassAsIs = false
val methodInfos = mutableMapOf<Method, AbiMethodInfo>()
val maskedMethods = mutableSetOf<Method>() // Methods which should be stripped even if they are marked as KEEP
val memberInfos = mutableMapOf<JvmMemberSignature, AbiMethodInfo>()
val maskedMethods = mutableSetOf<JvmMethodSignature>() // Methods which should be stripped even if they are marked as KEEP
override fun defineClass(
version: Int, access: Int, name: String, signature: String?, superName: String, interfaces: Array<out String>
@@ -110,6 +117,32 @@ class JvmAbiClassBuilderInterceptor(
delegate.visitEnclosingMethod(owner, name, desc)
}
override fun newField(
declaration: IrField?, access: Int, name: String, desc: String, signature: String?, value: Any?
): FieldVisitor {
if (keepClassAsIs || removeClassFromAbi) {
// We don't care about fields when we remove or keep this class completely.
return delegate.newField(declaration, access, name, desc, signature, value)
}
val visibility = declaration?.visibility ?: DescriptorVisibilities.DEFAULT_VISIBILITY
if (DescriptorVisibilities.isPrivate(visibility)) {
// Remove all private fields.
return delegate.newField(declaration, access, name, desc, signature, value)
}
if (treatInternalAsPrivate && visibility == DescriptorVisibilities.INTERNAL) {
// Remove all internal fields.
return delegate.newField(declaration, access, name, desc, signature, value)
}
// Keep otherwise.
memberInfos[JvmFieldSignature(name, desc)] = AbiMethodInfo.KEEP
return delegate.newField(declaration, access, name, desc, signature, value)
}
override fun newMethod(
declaration: IrFunction?, access: Int, name: String, desc: String, signature: String?, exceptions: Array<out String>?
): MethodVisitor {
@@ -125,8 +158,8 @@ class JvmAbiClassBuilderInterceptor(
// and then checks for `f` if this method doesn't exist) so we have to remember to strip the
// original methods if there was a $$forInline version.
if (name.endsWith(FOR_INLINE_SUFFIX) && !isPrivateClass) {
methodInfos[Method(name, desc)] = AbiMethodInfo.KEEP
maskedMethods += Method(name.removeSuffix(FOR_INLINE_SUFFIX), desc)
memberInfos[JvmMethodSignature(name, desc)] = AbiMethodInfo.KEEP
maskedMethods += JvmMethodSignature(name.removeSuffix(FOR_INLINE_SUFFIX), desc)
return delegate.newMethod(declaration, access, name, desc, signature, exceptions)
}
@@ -138,6 +171,11 @@ class JvmAbiClassBuilderInterceptor(
return delegate.newMethod(declaration, access, name, desc, signature, exceptions)
}
// Remove internal functions from the ABI jars
if (treatInternalAsPrivate && declaration?.visibility == DescriptorVisibilities.INTERNAL) {
return delegate.newMethod(declaration, access, name, desc, signature, exceptions)
}
if (isDataClass && removeDataClassCopyIfConstructorIsPrivate &&
(name == "copy" || name == "copy${JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX}")
) {
@@ -148,9 +186,9 @@ class JvmAbiClassBuilderInterceptor(
// Copy inline functions verbatim
if (declaration?.isInline == true && !isPrivateClass) {
methodInfos[Method(name, desc)] = AbiMethodInfo.KEEP
memberInfos[JvmMethodSignature(name, desc)] = AbiMethodInfo.KEEP
} else {
methodInfos[Method(name, desc)] = AbiMethodInfo.STRIP
memberInfos[JvmMethodSignature(name, desc)] = AbiMethodInfo.STRIP
}
return delegate.newMethod(declaration, access, name, desc, signature, exceptions)
}
@@ -186,9 +224,9 @@ class JvmAbiClassBuilderInterceptor(
isWhenMappingClass -> AbiClassInfo.Deleted
else -> {
for (method in maskedMethods) {
methodInfos[method] = AbiMethodInfo.STRIP
memberInfos[method] = AbiMethodInfo.STRIP
}
AbiClassInfo.Stripped(methodInfos)
AbiClassInfo.Stripped(memberInfos)
}
}
abiClassInfoBuilder.recordInitialClassInfo(internalName, classInfo, superInterfaces)
@@ -200,9 +238,16 @@ class JvmAbiClassBuilderInterceptor(
}
}
private fun shouldRemoveFromAbi(irClass: IrClass?, removePrivateClasses: Boolean): Boolean = when {
private fun shouldRemoveFromAbi(irClass: IrClass?, removePrivateClasses: Boolean, treatInternalAsPrivate: Boolean): Boolean = when {
irClass == null -> false
irClass.isFileClass -> false
removePrivateClasses -> irClass.isEffectivelyPrivate()
removePrivateClasses -> irClass.isVisibilityStrippedFromAbi(stripInternal = treatInternalAsPrivate)
else -> false
}
private fun IrDeclarationWithVisibility.isVisibilityStrippedFromAbi(stripInternal: Boolean): Boolean {
val isInAbi = visibility == DescriptorVisibilities.PUBLIC
|| visibility == DescriptorVisibilities.PROTECTED
|| (!stripInternal && visibility == DescriptorVisibilities.INTERNAL)
return !isInAbi || parentClassOrNull?.isVisibilityStrippedFromAbi(stripInternal) == true
}
@@ -60,6 +60,17 @@ class JvmAbiCommandLineProcessor : CommandLineProcessor {
"private top-level classes will no longer be available from Java classes in the same package.",
false,
)
val TREAT_INTERNAL_AS_PRIVATE_OPTION: CliOption =
CliOption(
"treatInternalAsPrivate",
"true/false",
"""Treat internal declarations as private and remove from ABI. False by default due to backwards compatibility.
|If enabled, internal functions are removed and will no longer be available from Java if it's compiled against abi.jar.
|Works best in conjunction with flags:
| * removePrivateClasses - internal classes are being removed too;
| * removeDataClassCopyIfConstructorIsPrivate - copy method is removed along with internal constructor.""".trimMargin(),
false,
)
}
override val pluginId: String
@@ -72,6 +83,7 @@ class JvmAbiCommandLineProcessor : CommandLineProcessor {
REMOVE_DATA_CLASS_COPY_IF_CONSTRUCTOR_IS_PRIVATE_OPTION,
PRESERVE_DECLARATION_ORDER_OPTION,
REMOVE_PRIVATE_CLASSES_OPTION,
TREAT_INTERNAL_AS_PRIVATE_OPTION,
)
override fun processOption(option: AbstractCliOption, value: String, configuration: CompilerConfiguration) {
@@ -87,6 +99,10 @@ class JvmAbiCommandLineProcessor : CommandLineProcessor {
JvmAbiConfigurationKeys.REMOVE_PRIVATE_CLASSES,
value == "true"
)
TREAT_INTERNAL_AS_PRIVATE_OPTION -> configuration.put(
JvmAbiConfigurationKeys.TREAT_INTERNAL_AS_PRIVATE,
value == "true"
)
else -> throw CliOptionProcessingException("Unknown option: ${option.optionName}")
}
}
@@ -23,12 +23,14 @@ class JvmAbiComponentRegistrar : CompilerPluginRegistrar() {
val builderExtension = JvmAbiClassBuilderInterceptor(
removeDataClassCopy,
configuration.getBoolean(JvmAbiConfigurationKeys.REMOVE_PRIVATE_CLASSES),
configuration.getBoolean(JvmAbiConfigurationKeys.TREAT_INTERNAL_AS_PRIVATE),
)
val outputExtension = JvmAbiOutputExtension(
File(outputPath), builderExtension::buildAbiClassInfoAndReleaseResources,
messageCollector, configuration.getBoolean(JvmAbiConfigurationKeys.REMOVE_DEBUG_INFO),
removeDataClassCopy,
configuration.getBoolean(JvmAbiConfigurationKeys.PRESERVE_DECLARATION_ORDER),
configuration.getBoolean(JvmAbiConfigurationKeys.TREAT_INTERNAL_AS_PRIVATE),
)
ClassGeneratorExtension.registerExtension(builderExtension)
@@ -18,4 +18,6 @@ object JvmAbiConfigurationKeys {
CompilerConfigurationKey.create(JvmAbiCommandLineProcessor.PRESERVE_DECLARATION_ORDER_OPTION.description)
val REMOVE_PRIVATE_CLASSES: CompilerConfigurationKey<Boolean> =
CompilerConfigurationKey.create(JvmAbiCommandLineProcessor.REMOVE_PRIVATE_CLASSES_OPTION.description)
val TREAT_INTERNAL_AS_PRIVATE: CompilerConfigurationKey<Boolean> =
CompilerConfigurationKey.create(JvmAbiCommandLineProcessor.TREAT_INTERNAL_AS_PRIVATE_OPTION.description)
}
@@ -21,6 +21,7 @@ fun abiMetadataProcessor(
preserveDeclarationOrder: Boolean,
classesToBeDeleted: Set<String>,
pruneClass: Boolean,
treatInternalAsPrivate: Boolean,
): AnnotationVisitor =
kotlinClassHeaderVisitor { header ->
// kotlinx-metadata only supports writing Kotlin metadata of version >= 1.4, so we need to
@@ -39,14 +40,15 @@ fun abiMetadataProcessor(
removeDataClassCopyIfConstructorIsPrivate,
preserveDeclarationOrder,
classesToBeDeleted,
pruneClass
pruneClass,
treatInternalAsPrivate,
)
}
is KotlinClassMetadata.FileFacade -> {
metadata.kmPackage.removePrivateDeclarations(preserveDeclarationOrder, pruneClass)
metadata.kmPackage.removePrivateDeclarations(preserveDeclarationOrder, pruneClass, treatInternalAsPrivate)
}
is KotlinClassMetadata.MultiFileClassPart -> {
metadata.kmPackage.removePrivateDeclarations(preserveDeclarationOrder, pruneClass)
metadata.kmPackage.removePrivateDeclarations(preserveDeclarationOrder, pruneClass, treatInternalAsPrivate)
}
else -> Unit
}
@@ -162,12 +164,14 @@ private fun KmClass.removePrivateDeclarations(
preserveDeclarationOrder: Boolean,
classesToBeDeleted: Set<String>,
pruneClass: Boolean,
treatInternalAsPrivate: Boolean,
) {
constructors.removeIf { pruneClass || it.visibility.isPrivate }
constructors.removeIf { pruneClass || it.visibility.shouldRemove(treatInternalAsPrivate) }
(this as KmDeclarationContainer).removePrivateDeclarations(
copyFunShouldBeDeleted(removeCopyAlongWithConstructor),
preserveDeclarationOrder,
pruneClass,
treatInternalAsPrivate,
)
nestedClasses.removeIf { "$name\$$it" in classesToBeDeleted }
companionObject = companionObject.takeUnless { "$name\$$it" in classesToBeDeleted }
@@ -175,8 +179,12 @@ private fun KmClass.removePrivateDeclarations(
// TODO: do not serialize private type aliases once KT-17229 is fixed.
}
private fun KmPackage.removePrivateDeclarations(preserveDeclarationOrder: Boolean, pruneClass: Boolean) {
(this as KmDeclarationContainer).removePrivateDeclarations(false, preserveDeclarationOrder, pruneClass)
private fun KmPackage.removePrivateDeclarations(
preserveDeclarationOrder: Boolean,
pruneClass: Boolean,
treatInternalAsPrivate: Boolean,
) {
(this as KmDeclarationContainer).removePrivateDeclarations(false, preserveDeclarationOrder, pruneClass, treatInternalAsPrivate)
localDelegatedProperties.clear()
// TODO: do not serialize private type aliases once KT-17229 is fixed.
}
@@ -185,9 +193,10 @@ private fun KmDeclarationContainer.removePrivateDeclarations(
copyFunShouldBeDeleted: Boolean,
preserveDeclarationOrder: Boolean,
pruneClass: Boolean,
treatInternalAsPrivate: Boolean,
) {
functions.removeIf { pruneClass || it.visibility.isPrivate || (copyFunShouldBeDeleted && it.name == "copy") }
properties.removeIf { pruneClass || it.visibility.isPrivate }
functions.removeIf { pruneClass || it.visibility.shouldRemove(treatInternalAsPrivate) || (copyFunShouldBeDeleted && it.name == "copy") }
properties.removeIf { pruneClass || it.visibility.shouldRemove(treatInternalAsPrivate) }
if (!preserveDeclarationOrder) {
functions.sortWith(compareBy(KmFunction::name, { it.signature.toString() }))
@@ -205,5 +214,9 @@ private fun KmDeclarationContainer.removePrivateDeclarations(
private fun KmClass.copyFunShouldBeDeleted(removeDataClassCopy: Boolean): Boolean =
removeDataClassCopy && isData && constructors.none { !it.isSecondary }
private val Visibility.isPrivate: Boolean
get() = this == Visibility.PRIVATE || this == Visibility.PRIVATE_TO_THIS || this == Visibility.LOCAL
private fun Visibility.shouldRemove(treatInternalAsPrivate: Boolean): Boolean {
return this == Visibility.PRIVATE ||
this == Visibility.PRIVATE_TO_THIS ||
this == Visibility.LOCAL ||
(treatInternalAsPrivate && this == Visibility.INTERNAL)
}
@@ -16,11 +16,12 @@ import org.jetbrains.kotlin.codegen.extensions.ClassFileFactoryFinalizerExtensio
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
import org.jetbrains.org.objectweb.asm.*
import org.jetbrains.org.objectweb.asm.commons.ClassRemapper
import org.jetbrains.org.objectweb.asm.commons.Method
import org.jetbrains.org.objectweb.asm.commons.Remapper
import org.jetbrains.org.objectweb.asm.tree.FieldNode
import org.jetbrains.org.objectweb.asm.tree.MethodNode
import java.io.File
import kotlin.metadata.jvm.JvmFieldSignature
import kotlin.metadata.jvm.JvmMethodSignature
class JvmAbiOutputExtension(
private val outputPath: File,
@@ -29,12 +30,20 @@ class JvmAbiOutputExtension(
private val removeDebugInfo: Boolean,
private val removeDataClassCopyIfConstructorIsPrivate: Boolean,
private val preserveDeclarationOrder: Boolean,
private val treatInternalAsPrivate: Boolean,
) : ClassFileFactoryFinalizerExtension {
override fun finalizeClassFactory(factory: ClassFileFactory) {
// We need to wait until the end to produce any output in order to strip classes
// from the InnerClasses attributes.
val outputFiles =
AbiOutputFiles(abiClassInfoBuilder(), factory, removeDebugInfo, removeDataClassCopyIfConstructorIsPrivate, preserveDeclarationOrder)
AbiOutputFiles(
abiClassInfoBuilder(),
factory,
removeDebugInfo,
removeDataClassCopyIfConstructorIsPrivate,
preserveDeclarationOrder,
treatInternalAsPrivate,
)
if (outputPath.extension == "jar") {
// We don't include the runtime or main class in interface jars and always reset time stamps.
CompileEnvironmentUtil.writeToJar(
@@ -59,6 +68,7 @@ class JvmAbiOutputExtension(
val removeDebugInfo: Boolean,
val removeCopyAlongWithConstructor: Boolean,
val preserveDeclarationOrder: Boolean,
val treatInternalAsPrivate: Boolean,
) : OutputFileCollection {
private val classesToBeDeleted = abiClassInfos.mapNotNullTo(mutableSetOf()) { (className, action) ->
className.takeIf { action == AbiClassInfo.Deleted }
@@ -82,9 +92,9 @@ class JvmAbiOutputExtension(
is AbiClassInfo.Public -> outputFile // Copy verbatim
is AbiClassInfo.Stripped -> {
val prune = abiInfo.prune
val methodInfo = abiInfo.methodInfo
val memberInfo = abiInfo.memberInfo
val innerClassesToKeep = mutableSetOf<String>()
val noMethodsKept = methodInfo.values.none { it == AbiMethodInfo.KEEP }
val noMethodsKept = memberInfo.none { it.value == AbiMethodInfo.KEEP && it.key is JvmMethodSignature }
val writer = ClassWriter(0)
val remapper = ClassRemapper(writer, object : Remapper() {
override fun map(internalName: String): String =
@@ -98,12 +108,12 @@ class JvmAbiOutputExtension(
// Strip private fields.
override fun visitField(
access: Int,
name: String?,
descriptor: String?,
name: String,
descriptor: String,
signature: String?,
value: Any?,
): FieldVisitor? {
if (prune || access and Opcodes.ACC_PRIVATE != 0)
if (prune || memberInfo[JvmFieldSignature(name, descriptor)] != AbiMethodInfo.KEEP)
return null
return FieldNode(access, name, descriptor, signature, value).also {
keptFields += it
@@ -118,7 +128,7 @@ class JvmAbiOutputExtension(
exceptions: Array<out String>?
): MethodVisitor? {
if (prune) return null
val info = methodInfo[Method(name, descriptor)] ?: return null
val info = memberInfo[JvmMethodSignature(name, descriptor)] ?: return null
val node = MethodNode(access, name, descriptor, signature, exceptions).also {
keptMethods += it
@@ -164,7 +174,8 @@ class JvmAbiOutputExtension(
removeCopyAlongWithConstructor,
preserveDeclarationOrder,
classesToBeDeleted,
prune
prune,
treatInternalAsPrivate,
)
}
@@ -91,6 +91,9 @@ abstract class BaseJvmAbiTest : TestCase() {
abiOption(JvmAbiCommandLineProcessor.REMOVE_PRIVATE_CLASSES_OPTION.optionName, true.toString()).takeIf {
InTextDirectivesUtils.findStringWithPrefixes(directives, "// REMOVE_PRIVATE_CLASSES") != null
},
abiOption(JvmAbiCommandLineProcessor.TREAT_INTERNAL_AS_PRIVATE_OPTION.optionName, true.toString()).takeIf {
InTextDirectivesUtils.findStringWithPrefixes(directives, "// TREAT_INTERNAL_AS_PRIVATE") != null
},
).toTypedArray()
destination = compilation.destinationDir.canonicalPath
noSourceDebugExtension = InTextDirectivesUtils.findStringWithPrefixes(directives, "// NO_SOURCE_DEBUG_EXTENSION") != null
@@ -135,6 +135,16 @@ public class CompareJvmAbiTestGenerated extends AbstractCompareJvmAbiTest {
runTest("plugins/jvm-abi-gen/testData/compare/inlineFunctionBody/");
}
@TestMetadata("internalDeclarationsStrict")
public void testInternalDeclarationsStrict() {
runTest("plugins/jvm-abi-gen/testData/compare/internalDeclarationsStrict/");
}
@TestMetadata("internalFields")
public void testInternalFields() {
runTest("plugins/jvm-abi-gen/testData/compare/internalFields/");
}
@TestMetadata("lambdas")
public void testLambdas() {
runTest("plugins/jvm-abi-gen/testData/compare/lambdas/");
@@ -65,6 +65,16 @@ public class JvmAbiContentTestGenerated extends AbstractJvmAbiContentTest {
runTest("plugins/jvm-abi-gen/testData/content/innerClasses/");
}
@TestMetadata("internalClassAndCopyMethod")
public void testInternalClassAndCopyMethod() {
runTest("plugins/jvm-abi-gen/testData/content/internalClassAndCopyMethod/");
}
@TestMetadata("internalClassAndCopyMethodStrict")
public void testInternalClassAndCopyMethodStrict() {
runTest("plugins/jvm-abi-gen/testData/content/internalClassAndCopyMethodStrict/");
}
@TestMetadata("kt50005")
public void testKt50005() {
runTest("plugins/jvm-abi-gen/testData/content/kt50005/");
@@ -0,0 +1,33 @@
package test
internal fun funToBeRemoved() = Unit
internal fun internalTopLevelInlineFun() = Unit
internal class TopLevelClassToBeRemoved
fun emptyKtClassWorkaround() = Unit
class PublicOuterClass {
@JvmField
internal val fieldToBeRemoved = Unit
internal interface InternalInterfaceToBeRemoved
internal class InnerClass: InternalInterfaceToBeRemoved {
fun everyDeclarationShouldBeRemoved() = Unit
inline fun shouldBeRemoved() = Unit
class EffectivelyInternalClassRemoved
}
internal interface TransitivelyPublicInterface
data class Data internal constructor(
val couldNotBeRemoved: String,
internal val shouldBeRemoved: Any,
): TransitivelyPublicInterface
internal inline fun shouldBeRemoved() = Unit
}
@@ -0,0 +1,3 @@
// TREAT_INTERNAL_AS_PRIVATE
// REMOVE_PRIVATE_CLASSES
// REMOVE_DATA_CLASS_COPY_IF_CONSTRUCTOR_IS_PRIVATE
@@ -0,0 +1,11 @@
package test
fun emptyKtClassWorkaround() = Unit
class PublicOuterClass {
internal interface TransitivelyPublicInterface
data class Data internal constructor(
val couldNotBeRemoved: String
): TransitivelyPublicInterface
}
@@ -0,0 +1,14 @@
package test
@JvmField
internal val a: String = ""
internal val b: String = ""
fun emptyKtClassWorkaround() = Unit
class Class {
@JvmField
internal val a: String = ""
internal val b: String = ""
}
@@ -0,0 +1 @@
// TREAT_INTERNAL_AS_PRIVATE
@@ -0,0 +1,4 @@
package test
fun emptyKtClassWorkaround() = Unit
class Class
@@ -0,0 +1 @@
// TREAT_INTERNAL_AS_PRIVATE
@@ -0,0 +1,16 @@
@kotlin.Metadata
public final class test/Test$ConstructorToBeRemoved {
// source: 'test.kt'
public final inner class test/Test$ConstructorToBeRemoved
public final @org.jetbrains.annotations.NotNull method copy(@org.jetbrains.annotations.NotNull p0: java.lang.Object): test.Test$ConstructorToBeRemoved
public synthetic static method copy$default(p0: test.Test$ConstructorToBeRemoved, p1: java.lang.Object, p2: int, p3: java.lang.Object): test.Test$ConstructorToBeRemoved
public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
public method hashCode(): int
public @org.jetbrains.annotations.NotNull method toString(): java.lang.String
}
@kotlin.Metadata
public final class test/Test {
// source: 'test.kt'
public final inner class test/Test$ConstructorToBeRemoved
public method <init>(): void
}
@@ -0,0 +1,5 @@
package test
class Test {
internal data class ConstructorToBeRemoved internal constructor(internal val fieldToBeRemoved: Any)
}
@@ -0,0 +1,3 @@
// TREAT_INTERNAL_AS_PRIVATE
// REMOVE_PRIVATE_CLASSES
// REMOVE_DATA_CLASS_COPY_IF_CONSTRUCTOR_IS_PRIVATE
@@ -0,0 +1,16 @@
@kotlin.Metadata
public final class test/Test$EverythingExceptTheClassAndPropertyToBeRemoved {
// source: 'test.kt'
public final inner class test/Test$EverythingExceptTheClassAndPropertyToBeRemoved
public final @org.jetbrains.annotations.NotNull method component1(): java.lang.Object
public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
public final @org.jetbrains.annotations.NotNull method getA(): java.lang.Object
public method hashCode(): int
public @org.jetbrains.annotations.NotNull method toString(): java.lang.String
}
@kotlin.Metadata
public final class test/Test {
// source: 'test.kt'
public final inner class test/Test$EverythingExceptTheClassAndPropertyToBeRemoved
public method <init>(): void
}
@@ -0,0 +1,7 @@
package test
class Test {
internal data class ClassToBeRemoved internal constructor(val a: Any)
data class EverythingExceptTheClassAndPropertyToBeRemoved internal constructor(val a: Any)
}