1 /*
<lambda>null2 * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3 */
4
5 package kotlinx.coroutines.tools
6
7 import org.objectweb.asm.*
8 import org.objectweb.asm.tree.*
9 import java.io.*
10 import java.util.jar.*
11
12 fun JarFile.classEntries() = entries().asSequence().filter {
13 !it.isDirectory && it.name.endsWith(".class") && !it.name.startsWith("META-INF/")
14 }
15
getBinaryAPInull16 fun getBinaryAPI(jar: JarFile, visibilityMap: Map<String, ClassVisibility>): List<ClassBinarySignature> =
17 getBinaryAPI(jar.classEntries().map { entry -> jar.getInputStream(entry) }, visibilityMap)
18
getBinaryAPInull19 fun getBinaryAPI(
20 classStreams: Sequence<InputStream>,
21 visibilityMap: Map<String, ClassVisibility>
22 ): List<ClassBinarySignature> =
23 classStreams.map {
24 it.use { stream ->
25 val classNode = ClassNode()
26 ClassReader(stream).accept(classNode, ClassReader.SKIP_CODE)
27 classNode
28 }
29 }.map {
<lambda>null30 with(it) {
31 val classVisibility = visibilityMap[name]
32 val classAccess = AccessFlags(effectiveAccess and Opcodes.ACC_STATIC.inv())
33 val supertypes = listOf(superName) - "java/lang/Object" + interfaces.sorted()
34
35 val memberSignatures = (
36 fields.map {
37 with(it) {
38 FieldBinarySignature(
39 name,
40 desc,
41 isPublishedApi(),
42 AccessFlags(access)
43 )
44 }
45 } +
46 methods.map {
47 with(it) {
48 MethodBinarySignature(
49 name,
50 desc,
51 isPublishedApi(),
52 AccessFlags(access)
53 )
54 }
55 }
56 ).filter {
57 it.isEffectivelyPublic(classAccess, classVisibility)
58 }
59
60 ClassBinarySignature(
61 name,
62 superName,
63 outerClassName,
64 supertypes,
65 memberSignatures,
66 classAccess,
67 isEffectivelyPublic(classVisibility),
68 isFileOrMultipartFacade() || isDefaultImpls()
69 )
70 }
<lambda>null71 }.asIterable().sortedBy { it.name }
72
73
filterOutNonPublicnull74 fun List<ClassBinarySignature>.filterOutNonPublic(nonPublicPackages: List<String> = emptyList()): List<ClassBinarySignature> {
75 val nonPublicPaths = nonPublicPackages.map { it.replace('.', '/') + '/' }
76 val classByName = associateBy { it.name }
77
78 fun ClassBinarySignature.isInNonPublicPackage() =
79 nonPublicPaths.any { name.startsWith(it) }
80
81 fun ClassBinarySignature.isPublicAndAccessible(): Boolean =
82 isEffectivelyPublic &&
83 (outerName == null || classByName[outerName]?.let { outerClass ->
84 !(this.access.isProtected && outerClass.access.isFinal)
85 && outerClass.isPublicAndAccessible()
86 } ?: true)
87
88 fun supertypes(superName: String) = generateSequence({ classByName[superName] }, { classByName[it.superName] })
89
90 fun ClassBinarySignature.flattenNonPublicBases(): ClassBinarySignature {
91
92 val nonPublicSupertypes = supertypes(superName).takeWhile { !it.isPublicAndAccessible() }.toList()
93 if (nonPublicSupertypes.isEmpty())
94 return this
95
96 val inheritedStaticSignatures =
97 nonPublicSupertypes.flatMap { it.memberSignatures.filter { it.access.isStatic } }
98
99 // not covered the case when there is public superclass after chain of private superclasses
100 return this.copy(
101 memberSignatures = memberSignatures + inheritedStaticSignatures,
102 supertypes = supertypes - superName
103 )
104 }
105
106 return filter { !it.isInNonPublicPackage() && it.isPublicAndAccessible() }
107 .map { it.flattenNonPublicBases() }
108 .filterNot { it.isNotUsedWhenEmpty && it.memberSignatures.isEmpty() }
109 }
110
Listnull111 fun List<ClassBinarySignature>.dump() = dump(to = System.out)
112
113 fun <T : Appendable> List<ClassBinarySignature>.dump(to: T): T = to.apply {
114 this@dump.forEach {
115 append(it.signature).appendln(" {")
116 it.memberSignatures.sortedWith(MEMBER_SORT_ORDER).forEach { append("\t").appendln(it.signature) }
117 appendln("}\n")
118 }
119 }
120
121