@@ -43,54 +43,25 @@ public fun Sequence<InputStream>.loadApiFromJvmClasses(visibilityFilter: (String
43
43
val supertypes = listOf (superName) - " java/lang/Object" + interfaces.sorted()
44
44
45
45
val fieldSignatures = fields
46
- .map {
47
- val annotationHolders =
48
- mVisibility?.members?.get(JvmFieldSignature (it.name, it.desc))?.propertyAnnotation
49
- val foundAnnotations = methods.annotationsFor(annotationHolders?.method)
50
- it.toFieldBinarySignature(foundAnnotations)
51
- }.filter {
52
- it.isEffectivelyPublic(classAccess, mVisibility)
53
- }.filter {
46
+ .map { it.buildFieldSignature(mVisibility, this , classNodeMap) }
47
+ .filter { it.field.isEffectivelyPublic(classAccess, mVisibility) }
48
+ .filter {
54
49
/*
55
50
* Filter out 'public static final Companion' field that doesn't constitute public API.
56
51
* For that we first check if field corresponds to the 'Companion' class and then
57
52
* if companion is effectively public by itself, so the 'Companion' field has the same visibility.
58
53
*/
59
- if (! it.isCompanionField(classNode.kotlinMetadata)) return @filter true
60
- val outerKClass = (classNode.kotlinMetadata as KotlinClassMetadata .Class ).toKmClass()
61
- val companionName = name + " $" + outerKClass.companionObject
62
- // False positive is better than the crash here
63
- val companionClass = classNodeMap[companionName] ? : return @filter true
64
- val visibility = visibilityMap[companionName] ? : return @filter true
54
+ val companionClass = when (it) {
55
+ is BasicFieldBinarySignature -> return @filter true
56
+ is CompanionFieldBinarySignature -> it.companion
57
+ }
58
+ val visibility = visibilityMap[companionClass.name] ? : return @filter true
65
59
companionClass.isEffectivelyPublic(visibility)
66
- }
60
+ }.map { it.field }
67
61
68
62
// NB: this 'map' is O(methods + properties * methods) which may accidentally be quadratic
69
- val methodSignatures = methods.map {
70
- /* *
71
- * For getters/setters, pull the annotations from the property
72
- * This is either on the field if any or in a '$annotations' synthetic function.
73
- */
74
- val annotationHolders =
75
- mVisibility?.members?.get(JvmMethodSignature (it.name, it.desc))?.propertyAnnotation
76
- val foundAnnotations = ArrayList <AnnotationNode >()
77
- if (annotationHolders != null ) {
78
- foundAnnotations + = fields.annotationsFor(annotationHolders.field)
79
- foundAnnotations + = methods.annotationsFor(annotationHolders.method)
80
- }
81
-
82
- /* *
83
- * For synthetic $default methods, pull the annotations from the corresponding method
84
- */
85
- val alternateDefaultSignature = mVisibility?.name?.let { className ->
86
- it.alternateDefaultSignature(className)
87
- }
88
- foundAnnotations + = methods.annotationsFor(alternateDefaultSignature)
89
-
90
- it.toMethodBinarySignature(foundAnnotations, alternateDefaultSignature)
91
- }.filter {
92
- it.isEffectivelyPublic(classAccess, mVisibility)
93
- }
63
+ val methodSignatures = methods.map { it.buildMethodSignature(mVisibility, this ) }
64
+ .filter { it.isEffectivelyPublic(classAccess, mVisibility) }
94
65
95
66
ClassBinarySignature (
96
67
name, superName, outerClassName, supertypes, fieldSignatures + methodSignatures, classAccess,
@@ -102,6 +73,82 @@ public fun Sequence<InputStream>.loadApiFromJvmClasses(visibilityFilter: (String
102
73
}
103
74
}
104
75
76
+ /* *
77
+ * Wraps a [FieldBinarySignature] along with additional information.
78
+ */
79
+ private sealed class FieldBinarySignatureWrapper (val field : FieldBinarySignature )
80
+
81
+ /* *
82
+ * Wraps a regular field's binary signature.
83
+ */
84
+ private class BasicFieldBinarySignature (field : FieldBinarySignature ) : FieldBinarySignatureWrapper(field)
85
+
86
+ /* *
87
+ * Wraps a binary signature for a field referencing a companion object.
88
+ */
89
+ private class CompanionFieldBinarySignature (field : FieldBinarySignature , val companion : ClassNode ) :
90
+ FieldBinarySignatureWrapper (field)
91
+
92
+ private fun FieldNode.buildFieldSignature (
93
+ ownerVisibility : ClassVisibility ? ,
94
+ ownerClass : ClassNode ,
95
+ classes : TreeMap <String , ClassNode >
96
+ ): FieldBinarySignatureWrapper {
97
+ val annotationHolders =
98
+ ownerVisibility?.members?.get(JvmFieldSignature (name, desc))?.propertyAnnotation
99
+ val foundAnnotations = mutableListOf<AnnotationNode >()
100
+ foundAnnotations.addAll(ownerClass.methods.annotationsFor(annotationHolders?.method))
101
+
102
+ var companionClass: ClassNode ? = null
103
+ if (isCompanionField(ownerClass.kotlinMetadata)) {
104
+ /*
105
+ * If the field was generated to hold the reference to a companion class's instance,
106
+ * then we have to also take all annotations from the companion class an associate it with
107
+ * the field. Otherwise, all these annotations will be lost and if the class was marked
108
+ * as non-public API using some annotation, then we won't be able to filter out
109
+ * the companion field.
110
+ */
111
+ val companionName = ownerClass.companionName(ownerClass.kotlinMetadata)
112
+ companionClass = classes[companionName]
113
+ foundAnnotations.addAll(companionClass?.visibleAnnotations.orEmpty())
114
+ foundAnnotations.addAll(companionClass?.invisibleAnnotations.orEmpty())
115
+ }
116
+
117
+ val fieldSignature = toFieldBinarySignature(foundAnnotations)
118
+ return if (companionClass != null ) {
119
+ CompanionFieldBinarySignature (fieldSignature, companionClass)
120
+ } else {
121
+ BasicFieldBinarySignature (fieldSignature)
122
+ }
123
+ }
124
+
125
+ private fun MethodNode.buildMethodSignature (
126
+ ownerVisibility : ClassVisibility ? ,
127
+ ownerClass : ClassNode
128
+ ): MethodBinarySignature {
129
+ /* *
130
+ * For getters/setters, pull the annotations from the property
131
+ * This is either on the field if any or in a '$annotations' synthetic function.
132
+ */
133
+ val annotationHolders =
134
+ ownerVisibility?.members?.get(JvmMethodSignature (name, desc))?.propertyAnnotation
135
+ val foundAnnotations = ArrayList <AnnotationNode >()
136
+ if (annotationHolders != null ) {
137
+ foundAnnotations + = ownerClass.fields.annotationsFor(annotationHolders.field)
138
+ foundAnnotations + = ownerClass.methods.annotationsFor(annotationHolders.method)
139
+ }
140
+
141
+ /* *
142
+ * For synthetic $default methods, pull the annotations from the corresponding method
143
+ */
144
+ val alternateDefaultSignature = ownerVisibility?.name?.let { className ->
145
+ alternateDefaultSignature(className)
146
+ }
147
+ foundAnnotations + = ownerClass.methods.annotationsFor(alternateDefaultSignature)
148
+
149
+ return toMethodBinarySignature(foundAnnotations, alternateDefaultSignature)
150
+ }
151
+
105
152
private fun List<MethodNode>.annotationsFor (methodSignature : JvmMethodSignature ? ): List <AnnotationNode > {
106
153
if (methodSignature == null ) return emptyList()
107
154
0 commit comments