Merge public static API of non-public base supertypes into public subtype

This commit is contained in:
Ilya Gorbunov
2016-03-22 20:11:40 +03:00
parent 472b386101
commit bd8c83bee2
4 changed files with 31 additions and 12 deletions
@@ -19,7 +19,8 @@ fun main(args: Array<String>) {
fun JarFile.classEntries() = entries().asSequence().filter { !it.isDirectory && it.name.endsWith(".class") }
data class ClassBinarySignature(val name: String, val outerName: String?, val modifiers: String, val supertypes: List<String>, val memberSignatures: List<String>, val isPublic: Boolean)
data class ClassBinarySignature(val name: String, val superName: String, val outerName: String?, val modifiers: String, val supertypes: List<String>, val memberSignatures: List<MemberBinarySignature>, val isPublic: Boolean)
data class MemberBinarySignature(val name: String, val signature: String, val isStatic: Boolean)
val ClassBinarySignature.signature: String
get() = "$modifiers class $name" + if (supertypes.isEmpty()) "" else ": ${supertypes.joinToString()}"
@@ -48,12 +49,12 @@ fun getBinaryAPI(classStreams: Sequence<InputStream>, visibilityMap: Map<String,
val memberSignatures =
fields.filter { it.isPublic() }
.sortedBy { it.name }
.map { with(it) { "${getModifierString(access)} field $name $desc" } } +
.map { with(it) { MemberBinarySignature(name, "${getModifierString(access)} field $name $desc", isStatic(access) ) } } +
methods.filter { it.isEffectivelyPublic(classVisibility) }
.sortedWith(compareBy({ it.name }, { it.desc }))
.map { with(it) { "${getModifierString(access)} fun $name $desc" } }
.map { with(it) { MemberBinarySignature(name, "${getModifierString(access)} fun $name $desc", isStatic(access) ) } }
ClassBinarySignature(name, outerClassName, modifiers, supertypes, memberSignatures, isPublic)
ClassBinarySignature(name, superName, outerClassName, modifiers, supertypes, memberSignatures, isPublic)
}}
@@ -64,14 +65,28 @@ fun List<ClassBinarySignature>.filterOutNonPublic(): List<ClassBinarySignature>
fun ClassBinarySignature.isPublicAndAccessible(): Boolean =
isPublic && (outerName == null || classByName[outerName]?.isPublicAndAccessible() ?: true)
return filter { it -> it.isPublicAndAccessible() }
fun supertypes(superName: String) = generateSequence({ classByName[superName] }, { classByName[it.superName] })
fun ClassBinarySignature.flattenNonPublicBases(): ClassBinarySignature {
val nonPublicSupertypes = supertypes(superName).takeWhile { !it.isPublicAndAccessible() }.toList()
if (nonPublicSupertypes.isEmpty())
return this
val inheritedStaticSignatures = nonPublicSupertypes.flatMap { it.memberSignatures.filter { it.isStatic }}
// not covered the case when there is public superclass after chain of private superclasses
return this.copy(memberSignatures = memberSignatures + inheritedStaticSignatures, supertypes = supertypes - superName)
}
return filter { it -> it.isPublicAndAccessible() }.map { it.flattenNonPublicBases() }
}
fun List<ClassBinarySignature>.dump() = dump(to = System.out)
fun <T: Appendable> List<ClassBinarySignature>.dump(to: T): T = to.apply { this@dump.forEach {
appendln(it.signature)
it.memberSignatures.forEach { appendln(it) }
it.memberSignatures.forEach { appendln(it.signature) }
appendln("------------------\n")
}}
@@ -16,7 +16,8 @@ val ACCESS_NAMES = mapOf(
Opcodes.ACC_ANNOTATION to "annotation")
private fun isPublic(access: Int) = access and Opcodes.ACC_PUBLIC != 0 || access and Opcodes.ACC_PROTECTED != 0
public fun isPublic(access: Int) = access and Opcodes.ACC_PUBLIC != 0 || access and Opcodes.ACC_PROTECTED != 0
public fun isStatic(access: Int) = access and Opcodes.ACC_STATIC != 0
fun getModifiers(access: Int): List<String> = ACCESS_NAMES.entries.mapNotNull { if (access and it.key != 0) it.value else null }
fun getModifierString(access: Int): String = getModifiers(access).joinToString(" ")
@@ -2,10 +2,11 @@ package cases.java;
class Part1 {
public static void publicMethod(String param) { }
public static class Part2 extends Part1 {
public static void publicMethod(int param) { }
}
}
class Part2 extends Part1 {
public static void publicMethod(int param) { }
}
public class Facade extends Part2 { }
public class Facade extends Part1.Part2 { }
@@ -1,4 +1,6 @@
public class cases/java/Facade: cases/java/Part2
public class cases/java/Facade
public fun <init> ()V
public static fun publicMethod (I)V
public static fun publicMethod (Ljava/lang/String;)V
------------------