Merge public static API of non-public base supertypes into public subtype
This commit is contained in:
+21
-6
@@ -19,7 +19,8 @@ fun main(args: Array<String>) {
|
|||||||
fun JarFile.classEntries() = entries().asSequence().filter { !it.isDirectory && it.name.endsWith(".class") }
|
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
|
val ClassBinarySignature.signature: String
|
||||||
get() = "$modifiers class $name" + if (supertypes.isEmpty()) "" else ": ${supertypes.joinToString()}"
|
get() = "$modifiers class $name" + if (supertypes.isEmpty()) "" else ": ${supertypes.joinToString()}"
|
||||||
@@ -48,12 +49,12 @@ fun getBinaryAPI(classStreams: Sequence<InputStream>, visibilityMap: Map<String,
|
|||||||
val memberSignatures =
|
val memberSignatures =
|
||||||
fields.filter { it.isPublic() }
|
fields.filter { it.isPublic() }
|
||||||
.sortedBy { it.name }
|
.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) }
|
methods.filter { it.isEffectivelyPublic(classVisibility) }
|
||||||
.sortedWith(compareBy({ it.name }, { it.desc }))
|
.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 =
|
fun ClassBinarySignature.isPublicAndAccessible(): Boolean =
|
||||||
isPublic && (outerName == null || classByName[outerName]?.isPublicAndAccessible() ?: true)
|
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 List<ClassBinarySignature>.dump() = dump(to = System.out)
|
||||||
|
|
||||||
fun <T: Appendable> List<ClassBinarySignature>.dump(to: T): T = to.apply { this@dump.forEach {
|
fun <T: Appendable> List<ClassBinarySignature>.dump(to: T): T = to.apply { this@dump.forEach {
|
||||||
appendln(it.signature)
|
appendln(it.signature)
|
||||||
it.memberSignatures.forEach { appendln(it) }
|
it.memberSignatures.forEach { appendln(it.signature) }
|
||||||
appendln("------------------\n")
|
appendln("------------------\n")
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -16,7 +16,8 @@ val ACCESS_NAMES = mapOf(
|
|||||||
Opcodes.ACC_ANNOTATION to "annotation")
|
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 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(" ")
|
fun getModifierString(access: Int): String = getModifiers(access).joinToString(" ")
|
||||||
|
|
||||||
|
|||||||
+5
-4
@@ -2,10 +2,11 @@ package cases.java;
|
|||||||
|
|
||||||
class Part1 {
|
class Part1 {
|
||||||
public static void publicMethod(String param) { }
|
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 { }
|
||||||
|
|||||||
+3
-1
@@ -1,4 +1,6 @@
|
|||||||
public class cases/java/Facade: cases/java/Part2
|
public class cases/java/Facade
|
||||||
public fun <init> ()V
|
public fun <init> ()V
|
||||||
|
public static fun publicMethod (I)V
|
||||||
|
public static fun publicMethod (Ljava/lang/String;)V
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user