• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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