Do not generate DefaultImpls if empty

This commit is contained in:
Yan Zhulanow
2015-10-26 16:03:58 +03:00
parent 2a28baa154
commit 3475b4796f
14 changed files with 271 additions and 64 deletions
@@ -334,7 +334,7 @@ public class ClassFileFactory implements OutputFileCollection {
public abstract String asText(ClassBuilderFactory factory);
}
public void removeInlinedClasses(Set<String> classNamesToRemove) {
public void removeClasses(Set<String> classNamesToRemove) {
for (String classInternalName : classNamesToRemove) {
generators.remove(classInternalName + ".class");
}
@@ -32,8 +32,12 @@ import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.jvm.diagnostics.DelegationToTraitImpl
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.kotlin.resolve.scopes.KtScope
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.ACC_FINAL
import org.jetbrains.org.objectweb.asm.Opcodes.ACC_PUBLIC
import org.jetbrains.org.objectweb.asm.Opcodes.V1_6
@@ -45,7 +49,9 @@ public class InterfaceImplBodyCodegen(
v: ClassBuilder,
state: GenerationState,
parentCodegen: MemberCodegen<*>?
) : ClassBodyCodegen(aClass, context, v, state, parentCodegen) {
) : ClassBodyCodegen(aClass, context, InterfaceImplBodyCodegen.InterfaceImplClassBuilder(v), state, parentCodegen) {
private var isAnythingGenerated: Boolean = false
get() = (v as InterfaceImplClassBuilder).isAnythingGenerated
override fun generateDeclaration() {
v.defineClass(
@@ -57,6 +63,7 @@ public class InterfaceImplBodyCodegen(
}
override fun classForInnerClassRecord(): ClassDescriptor? {
if (!isAnythingGenerated) return null
if (DescriptorUtils.isLocal(descriptor)) return null
val classDescriptorImpl = ClassDescriptorImpl(
descriptor, Name.identifier(JvmAbi.DEFAULT_IMPLS_CLASS_NAME),
@@ -144,9 +151,59 @@ public class InterfaceImplBodyCodegen(
}
override fun generateKotlinAnnotation() {
(v as InterfaceImplClassBuilder).stopCounting()
val av = v.newAnnotation(AsmUtil.asmDescByFqNameWithoutInnerClasses(KOTLIN_INTERFACE_DEFAULT_IMPLS), true)
av.visit(JvmAnnotationNames.VERSION_FIELD_NAME, JvmAbi.VERSION.toArray())
av.visitEnd()
AsmUtil.writeKotlinSyntheticClassAnnotation(v, state)
}
override fun done() {
super.done()
if (!isAnythingGenerated) {
state.factory.removeClasses(setOf(typeMapper.mapDefaultImpls(descriptor).internalName))
}
}
private class InterfaceImplClassBuilder(private val v: ClassBuilder) : DelegatingClassBuilder() {
private var shouldCount: Boolean = true
var isAnythingGenerated: Boolean = false
private set
fun stopCounting() {
shouldCount = false
}
override fun getDelegate() = v
override fun newField(
origin: JvmDeclarationOrigin,
access: Int,
name: String,
desc: String,
signature: String?,
value: Any?
): FieldVisitor {
if (shouldCount) isAnythingGenerated = true
return super.newField(origin, access, name, desc, signature, value)
}
override fun newMethod(
origin: JvmDeclarationOrigin,
access: Int,
name: String,
desc: String,
signature: String?,
exceptions: Array<out String>?
): MethodVisitor {
if (shouldCount) isAnythingGenerated = true
return super.newMethod(origin, access, name, desc, signature, exceptions)
}
override fun newAnnotation(desc: String, visible: Boolean): AnnotationVisitor {
if (shouldCount) isAnythingGenerated = true
return super.newAnnotation(desc, visible)
}
}
}
@@ -170,7 +170,7 @@ public class InlineCodegen extends CallGenerator {
codegen.propagateChildReifiedTypeParametersUsages(result.getReifiedTypeParametersUsages());
state.getFactory().removeInlinedClasses(result.getClassesToRemove());
state.getFactory().removeClasses(result.getClassesToRemove());
codegen.markLineNumberAfterInlineIfNeeded();
}
@@ -1,4 +1,5 @@
@kotlin.jvm.internal.KotlinClass Example {
@kotlin.jvm.internal.KotlinClass
public final class Example {
private field prop2: int
private synthetic final @org.jetbrains.annotations.NotNull field prop: java.lang.String
private field useSite2: int
@@ -11,4 +12,4 @@
public synthetic final method job(): void
public synthetic final method setProp2(p0: int): void
public final method setUseSite2(p0: int): void
}
}
@@ -1,30 +1,60 @@
@kotlin.jvm.internal.KotlinClass A {
@kotlin.jvm.internal.KotlinClass
public final class A {
private final @AnnField @AnnParameterField @AnnTypeField field a: int
private final @AnnField @AnnTypeField field x: int
public method <init>(@AnnParameterProperty @AnnParameterField p0: int): void
private synthetic deprecated final @AnnProperty @AnnFieldProperty @AnnParameterProperty method a$annotations(): void
private synthetic deprecated final static @AnnProperty @AnnFieldProperty @AnnParameterProperty method a$annotations(): void
public final method getA(): int
public final method getX(): int
private synthetic deprecated final @AnnProperty @AnnFieldProperty method x$annotations(): void
private synthetic deprecated final static @AnnProperty @AnnFieldProperty method x$annotations(): void
}
@kotlin.annotation.Target @java.lang.annotation.Retention @java.lang.annotation.Target @kotlin.jvm.internal.KotlinClass AnnField
@kotlin.annotation.Target
@java.lang.annotation.Retention
@java.lang.annotation.Target
@kotlin.jvm.internal.KotlinClass
public abstract class AnnField
@kotlin.annotation.Target @java.lang.annotation.Retention @java.lang.annotation.Target @kotlin.jvm.internal.KotlinClass AnnFieldProperty
@kotlin.annotation.Target
@java.lang.annotation.Retention
@java.lang.annotation.Target
@kotlin.jvm.internal.KotlinClass
public abstract class AnnFieldProperty
@kotlin.annotation.Target @java.lang.annotation.Retention @java.lang.annotation.Target @kotlin.jvm.internal.KotlinClass AnnParameterField
@kotlin.annotation.Target
@java.lang.annotation.Retention
@java.lang.annotation.Target
@kotlin.jvm.internal.KotlinClass
public abstract class AnnParameterField
@kotlin.annotation.Target @java.lang.annotation.Retention @java.lang.annotation.Target @kotlin.jvm.internal.KotlinClass AnnParameterProperty
@kotlin.annotation.Target
@java.lang.annotation.Retention
@java.lang.annotation.Target
@kotlin.jvm.internal.KotlinClass
public abstract class AnnParameterProperty
@kotlin.annotation.Target @java.lang.annotation.Retention @java.lang.annotation.Target @kotlin.jvm.internal.KotlinClass AnnProperty
@kotlin.annotation.Target
@java.lang.annotation.Retention
@java.lang.annotation.Target
@kotlin.jvm.internal.KotlinClass
public abstract class AnnProperty
@kotlin.annotation.Target @java.lang.annotation.Retention @java.lang.annotation.Target @kotlin.jvm.internal.KotlinClass AnnTypeField
@kotlin.annotation.Target
@java.lang.annotation.Retention
@java.lang.annotation.Target
@kotlin.jvm.internal.KotlinClass
public abstract class AnnTypeField
@kotlin.annotation.Target @java.lang.annotation.Retention @java.lang.annotation.Target @kotlin.jvm.internal.KotlinClass Anno
@kotlin.annotation.Target
@java.lang.annotation.Retention
@java.lang.annotation.Target
@kotlin.jvm.internal.KotlinClass
public abstract class Anno
@kotlin.jvm.internal.KotlinFileFacade DefaultTargetsKt {
private final @Anno field p2: int
method <clinit>(): void
public final method getP(): int
public final method getP2(): int
@kotlin.jvm.internal.KotlinFileFacade
public final class DefaultTargetsKt {
private final static @Anno field p2: int
static method <clinit>(): void
public final static method getP(): int
public final static method getP2(): int
}
@@ -1,10 +1,24 @@
@kotlin.annotation.Target @java.lang.annotation.Retention @java.lang.annotation.Target @kotlin.jvm.internal.KotlinClass ClsAnn
@kotlin.annotation.Target
@java.lang.annotation.Retention
@java.lang.annotation.Target
@kotlin.jvm.internal.KotlinClass
public abstract class ClsAnn
@kotlin.annotation.Target @java.lang.annotation.Retention @java.lang.annotation.Target @kotlin.jvm.internal.KotlinClass ExprAnn
@kotlin.annotation.Target
@java.lang.annotation.Retention
@java.lang.annotation.Target
@kotlin.jvm.internal.KotlinClass
public abstract class ExprAnn
@kotlin.annotation.Target @java.lang.annotation.Retention @java.lang.annotation.Target @kotlin.jvm.internal.KotlinClass FunAnn
@kotlin.annotation.Target
@java.lang.annotation.Retention
@java.lang.annotation.Target
@kotlin.jvm.internal.KotlinClass
public abstract class FunAnn
@kotlin.jvm.internal.KotlinSyntheticClass @kotlin.jvm.internal.KotlinFunction LiteralsKt$foo$1 {
@kotlin.jvm.internal.KotlinSyntheticClass
@kotlin.jvm.internal.KotlinFunction
final class LiteralsKt$foo$1 {
synthetic final field $arg: int
inner class LiteralsKt$foo$1
method <init>(p0: int): void
@@ -12,7 +26,9 @@
public method invoke(): java.lang.Object
}
@kotlin.jvm.internal.KotlinSyntheticClass @kotlin.jvm.internal.KotlinFunction LiteralsKt$foo$2 {
@kotlin.jvm.internal.KotlinSyntheticClass
@kotlin.jvm.internal.KotlinFunction
final class LiteralsKt$foo$2 {
synthetic final field $arg: int
inner class LiteralsKt$foo$2
method <init>(p0: int): void
@@ -20,12 +36,16 @@
public method invoke(): java.lang.Object
}
@kotlin.jvm.internal.KotlinLocalClass @kotlin.jvm.internal.KotlinClass LiteralsKt$foo$3 {
@kotlin.jvm.internal.KotlinLocalClass
@kotlin.jvm.internal.KotlinClass
public final class LiteralsKt$foo$3 {
inner class LiteralsKt$foo$3
method <init>(): void
}
@kotlin.jvm.internal.KotlinSyntheticClass @kotlin.jvm.internal.KotlinFunction LiteralsKt$foo$x$1 {
@kotlin.jvm.internal.KotlinSyntheticClass
@kotlin.jvm.internal.KotlinFunction
final class LiteralsKt$foo$x$1 {
synthetic final field $arg: int
inner class LiteralsKt$foo$x$1
method <init>(p0: int): void
@@ -33,15 +53,17 @@
public method invoke(): java.lang.Object
}
@kotlin.jvm.internal.KotlinFileFacade LiteralsKt {
@kotlin.jvm.internal.KotlinFileFacade
public final class LiteralsKt {
inner class LiteralsKt$foo$1
inner class LiteralsKt$foo$2
inner class LiteralsKt$foo$3
inner class LiteralsKt$foo$x$1
public final method bar(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function0): int
public final @org.jetbrains.annotations.NotNull method foo(p0: int): My
public final static method bar(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function0): int
public final static @org.jetbrains.annotations.NotNull method foo(p0: int): My
}
@kotlin.jvm.internal.KotlinClass My {
@kotlin.jvm.internal.KotlinClass
public class My {
public method <init>(): void
}
@@ -1,4 +1,5 @@
@kotlin.jvm.internal.KotlinClass A {
@kotlin.jvm.internal.KotlinClass
public final class A {
private @AnnField field p: int
private final @AnnField field x: int
private field y: int
@@ -6,20 +7,32 @@
public final @AnnGetter method getP(): int
public final method getX(): int
public final @AnnGetter method getY(): int
private synthetic deprecated final @AnnProp @AnnProp2 method p$annotations(): void
private synthetic deprecated final static @AnnProp @AnnProp2 method p$annotations(): void
public final @AnnSetter method setP(@AnnParam p0: int): void
public final @AnnSetter method setY(p0: int): void
private synthetic deprecated final @AnnProp2 method x$annotations(): void
private synthetic deprecated final static @AnnProp2 method x$annotations(): void
}
@java.lang.annotation.Retention @kotlin.jvm.internal.KotlinClass AnnField
@java.lang.annotation.Retention
@kotlin.jvm.internal.KotlinClass
public abstract class AnnField
@java.lang.annotation.Retention @kotlin.jvm.internal.KotlinClass AnnGetter
@java.lang.annotation.Retention
@kotlin.jvm.internal.KotlinClass
public abstract class AnnGetter
@java.lang.annotation.Retention @kotlin.jvm.internal.KotlinClass AnnParam
@java.lang.annotation.Retention
@kotlin.jvm.internal.KotlinClass
public abstract class AnnParam
@java.lang.annotation.Retention @kotlin.jvm.internal.KotlinClass AnnProp
@java.lang.annotation.Retention
@kotlin.jvm.internal.KotlinClass
public abstract class AnnProp
@java.lang.annotation.Retention @kotlin.jvm.internal.KotlinClass AnnProp2
@java.lang.annotation.Retention
@kotlin.jvm.internal.KotlinClass
public abstract class AnnProp2
@java.lang.annotation.Retention @kotlin.jvm.internal.KotlinClass AnnSetter
@java.lang.annotation.Retention
@kotlin.jvm.internal.KotlinClass
public abstract class AnnSetter
@@ -1,12 +1,16 @@
@kotlin.jvm.internal.KotlinClass A {
@kotlin.jvm.internal.KotlinClass
public final class A {
public method <init>(): void
public final @org.jetbrains.annotations.NotNull method f(@Ann p0: java.lang.String): java.lang.String
public final @org.jetbrains.annotations.NotNull method getP(@Ann p0: java.lang.String): java.lang.String
}
@java.lang.annotation.Retention @kotlin.jvm.internal.KotlinClass Ann
@java.lang.annotation.Retention
@kotlin.jvm.internal.KotlinClass
public abstract class Ann
@kotlin.jvm.internal.KotlinFileFacade OnReceiverKt {
public final @org.jetbrains.annotations.NotNull method getTopLevelP(@Ann p0: java.lang.String): java.lang.String
public final @org.jetbrains.annotations.NotNull method topLevelF(@Ann p0: java.lang.String): java.lang.String
@kotlin.jvm.internal.KotlinFileFacade
public final class OnReceiverKt {
public final static @org.jetbrains.annotations.NotNull method getTopLevelP(@Ann p0: java.lang.String): java.lang.String
public final static @org.jetbrains.annotations.NotNull method topLevelF(@Ann p0: java.lang.String): java.lang.String
}
@@ -0,0 +1,17 @@
interface A
interface B {
fun foo()
}
interface C {
val bar: Int
}
interface D {
fun baz() = 5
}
interface E {
class InsideE
}
@@ -0,0 +1,36 @@
@kotlin.jvm.internal.KotlinClass
public abstract class A
@kotlin.jvm.internal.KotlinClass
public abstract class B {
public abstract method foo(): void
}
@kotlin.jvm.internal.KotlinClass
public abstract class C {
public abstract method getBar(): int
}
@kotlin.jvm.internal.KotlinInterfaceDefaultImpls
@kotlin.jvm.internal.KotlinSyntheticClass
public final class D$DefaultImpls {
inner class D$DefaultImpls
public static method baz(p0: D): int
}
@kotlin.jvm.internal.KotlinClass
public abstract class D {
inner class D$DefaultImpls
public abstract method baz(): int
}
@kotlin.jvm.internal.KotlinClass
public final class E$InsideE {
inner class E$InsideE
public method <init>(): void
}
@kotlin.jvm.internal.KotlinClass
public abstract class E {
inner class E$InsideE
}
@@ -1,4 +1,5 @@
@kotlin.jvm.internal.KotlinClass A1 {
@kotlin.jvm.internal.KotlinClass
public abstract class A1 {
public method <init>(): void
public method contains(p0: java.lang.Object): boolean
public method containsAll(@org.jetbrains.annotations.NotNull p0: java.util.Collection): boolean
@@ -9,7 +10,8 @@
public method toArray(p0: java.lang.Object[]): java.lang.Object[]
}
@kotlin.jvm.internal.KotlinClass A2 {
@kotlin.jvm.internal.KotlinClass
public abstract class A2 {
public method <init>(): void
public method contains(@org.jetbrains.annotations.NotNull p0: java.lang.String): boolean
public final method contains(p0: java.lang.Object): boolean
@@ -22,7 +24,8 @@
public method toArray(p0: java.lang.Object[]): java.lang.Object[]
}
@kotlin.jvm.internal.KotlinClass A3 {
@kotlin.jvm.internal.KotlinClass
public abstract class A3 {
public method <init>(): void
public method contains(p0: java.lang.Object): boolean
public abstract method getSize(): int
@@ -34,7 +37,8 @@
public final method size(): int
}
@kotlin.jvm.internal.KotlinClass A4 {
@kotlin.jvm.internal.KotlinClass
public abstract class A4 {
public method <init>(): void
public method contains(p0: java.lang.Object): boolean
public method containsAll(@org.jetbrains.annotations.NotNull p0: java.util.Collection): boolean
@@ -47,7 +51,8 @@
public final method size(): int
}
@kotlin.jvm.internal.KotlinClass A5 {
@kotlin.jvm.internal.KotlinClass
public abstract class A5 {
public method <init>(): void
public final method contains(p0: java.lang.Object): boolean
public method contains(p0: java.lang.String): boolean
@@ -63,7 +68,8 @@
public final method size(): int
}
@kotlin.jvm.internal.KotlinClass A6 {
@kotlin.jvm.internal.KotlinClass
public abstract class A6 {
public method <init>(): void
public method contains(@org.jetbrains.annotations.NotNull p0: java.lang.String): boolean
public final method contains(p0: java.lang.Object): boolean
@@ -80,7 +86,8 @@
public final method size(): int
}
@kotlin.jvm.internal.KotlinClass A7 {
@kotlin.jvm.internal.KotlinClass
public abstract class A7 {
public method <init>(): void
public method contains(p0: int): boolean
public final method contains(p0: java.lang.Object): boolean
@@ -92,7 +99,8 @@
public method toArray(p0: java.lang.Object[]): java.lang.Object[]
}
@kotlin.jvm.internal.KotlinClass A8 {
@kotlin.jvm.internal.KotlinClass
public abstract class A8 {
public method <init>(): void
public method contains(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
public abstract method getSize(): int
@@ -102,13 +110,16 @@
public method toArray(p0: java.lang.Object[]): java.lang.Object[]
}
@kotlin.jvm.internal.KotlinInterfaceDefaultImpls @kotlin.jvm.internal.KotlinSyntheticClass I1$DefaultImpls {
@kotlin.jvm.internal.KotlinInterfaceDefaultImpls
@kotlin.jvm.internal.KotlinSyntheticClass
public final class I1$DefaultImpls {
inner class I1$DefaultImpls
public method contains(p0: I1, p1: java.lang.Object): boolean
public method containsAll(@org.jetbrains.annotations.NotNull p0: I1, p1: java.util.Collection): boolean
public static method contains(p0: I1, p1: java.lang.Object): boolean
public static method containsAll(@org.jetbrains.annotations.NotNull p0: I1, p1: java.util.Collection): boolean
}
@kotlin.jvm.internal.KotlinClass I1 {
@kotlin.jvm.internal.KotlinClass
public abstract class I1 {
inner class I1$DefaultImpls
public abstract method contains(p0: java.lang.Object): boolean
public abstract method containsAll(@org.jetbrains.annotations.NotNull p0: java.util.Collection): boolean
@@ -116,13 +127,16 @@
public abstract method toArray(p0: java.lang.Object[]): java.lang.Object[]
}
@kotlin.jvm.internal.KotlinInterfaceDefaultImpls @kotlin.jvm.internal.KotlinSyntheticClass I2$DefaultImpls {
@kotlin.jvm.internal.KotlinInterfaceDefaultImpls
@kotlin.jvm.internal.KotlinSyntheticClass
public final class I2$DefaultImpls {
inner class I2$DefaultImpls
public method contains(@org.jetbrains.annotations.NotNull p0: I2, p1: java.lang.String): boolean
public method containsAll(@org.jetbrains.annotations.NotNull p0: I2, p1: java.util.Collection): boolean
public static method contains(@org.jetbrains.annotations.NotNull p0: I2, p1: java.lang.String): boolean
public static method containsAll(@org.jetbrains.annotations.NotNull p0: I2, p1: java.util.Collection): boolean
}
@kotlin.jvm.internal.KotlinClass I2 {
@kotlin.jvm.internal.KotlinClass
public abstract class I2 {
inner class I2$DefaultImpls
public abstract method contains(@org.jetbrains.annotations.NotNull p0: java.lang.String): boolean
public abstract method containsAll(@org.jetbrains.annotations.NotNull p0: java.util.Collection): boolean
@@ -2,7 +2,9 @@ class A {
// Kind
annotation class Annotation
enum class Enum
interface Trait
interface Trait {
fun boo() {}
}
// Modality
open class OpenStaticClass
@@ -47,6 +47,7 @@ public abstract class AbstractBytecodeListingTest : CodegenTestCase() {
private val declarationsInsideClass = arrayListOf<Declaration>()
private val classAnnotations = arrayListOf<String>()
private var className = ""
private var classAccess = 0
private fun addAnnotation(desc: String, list: MutableList<String> = declarationsInsideClass.last().annotations) {
val name = Type.getType(desc).className
@@ -66,11 +67,14 @@ public abstract class AbstractBytecodeListingTest : CodegenTestCase() {
if ((access and Opcodes.ACC_DEPRECATED) != 0) addModifier("deprecated", list)
if ((access and Opcodes.ACC_FINAL) != 0) addModifier("final", list)
if ((access and Opcodes.ACC_ABSTRACT) != 0) addModifier("abstract", list)
if ((access and Opcodes.ACC_STATIC) != 0) addModifier("static", list)
}
public val text: String
get() = StringBuilder {
append(classAnnotations.joinToString(""))
get() = StringBuilder().apply {
append(classAnnotations.joinToString("\n", postfix = "\n"))
arrayListOf<String>().apply { handleModifiers(classAccess, this) }.forEach { append(it) }
append("class ")
append(className)
if (declarationsInsideClass.isNotEmpty()) {
append(" {\n")
@@ -147,6 +151,7 @@ public abstract class AbstractBytecodeListingTest : CodegenTestCase() {
interfaces: Array<out String>?
) {
className = name
classAccess = access
}
override fun visitInnerClass(name: String, outerName: String?, innerName: String?, access: Int) {
@@ -35,6 +35,12 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeListing"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("defaultImpls.kt")
public void testDefaultImpls() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeListing/defaultImpls.kt");
doTest(fileName);
}
@TestMetadata("compiler/testData/codegen/bytecodeListing/annotations")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)