@@ -2,57 +2,74 @@ package kotlinx.benchmark.gradle
2
2
3
3
import org.jetbrains.org.objectweb.asm.*
4
4
import org.jetbrains.org.objectweb.asm.tree.*
5
- import java.io.File
6
5
7
6
data class AnnotationData (
7
+ val name : String ,
8
8
val parameters : Map <String , Any ?>
9
9
)
10
10
11
- data class ClassAnnotations (
12
- val classAnnotations : Map <String , AnnotationData >,
13
- val methodAnnotations : Map <String , Map <String , AnnotationData >>,
14
- val fieldAnnotations : Map <String , Map <String , AnnotationData >>
11
+ data class ClassAnnotationsDescriptor (
12
+ val packageName : String ,
13
+ val name : String ,
14
+ val visibility : String ,
15
+ val annotations : List <AnnotationData >,
16
+ val methods : List <MethodAnnotationsDescriptor >,
17
+ val fields : List <FieldAnnotationsDescriptor >
18
+ )
19
+
20
+ data class MethodAnnotationsDescriptor (
21
+ val name : String ,
22
+ val visibility : String ,
23
+ val annotations : List <AnnotationData >
24
+ )
25
+
26
+ data class FieldAnnotationsDescriptor (
27
+ val name : String ,
28
+ val visibility : String ,
29
+ val annotations : List <AnnotationData >
15
30
)
16
31
17
32
class AnnotationProcessor {
18
33
19
- private val classAnnotationsMap = mutableMapOf< String , ClassAnnotations >()
34
+ private val classAnnotationsDescriptors = mutableListOf< ClassAnnotationsDescriptor >()
20
35
21
- fun processClassFile ( classFile : File ) {
22
- val classReader = ClassReader (classFile.readBytes() )
36
+ fun processClassBytes ( classBytes : ByteArray ) {
37
+ val classReader = ClassReader (classBytes )
23
38
val classNode = ClassNode ()
24
39
classReader.accept(classNode, 0 )
25
40
26
- val classAnnotations = mutableMapOf<String , AnnotationData >()
27
- val methodAnnotations = mutableMapOf<String , MutableMap <String , AnnotationData >>()
28
- val fieldAnnotations = mutableMapOf<String , MutableMap <String , AnnotationData >>()
41
+ val classAnnotations = classNode.visibleAnnotations
42
+ ?.filter { it.desc != " Lkotlin/Metadata;" }
43
+ ?.map { parseAnnotation(it) }
44
+ ? : emptyList()
29
45
30
- classNode.visibleAnnotations?.forEach { annotationNode ->
31
- if (annotationNode.desc != " Lkotlin/Metadata;" ) {
32
- val annotationData = parseAnnotation(annotationNode)
33
- classAnnotations[annotationNode.desc] = annotationData
34
- }
46
+ val methodDescriptors = classNode.methods.map { methodNode ->
47
+ val methodAnnotations = methodNode.visibleAnnotations
48
+ ?.filter { it.desc != " Lkotlin/Metadata;" }
49
+ ?.map { parseAnnotation(it) }
50
+ ? : emptyList()
51
+ MethodAnnotationsDescriptor (methodNode.name, getVisibility(methodNode.access), methodAnnotations)
35
52
}
36
53
37
- classNode.methods?.forEach { methodNode ->
38
- methodNode.visibleAnnotations?.forEach { annotationNode ->
39
- if (annotationNode.desc != " Lkotlin/Metadata;" ) {
40
- val annotationData = parseAnnotation(annotationNode)
41
- methodAnnotations.getOrPut(methodNode.name) { mutableMapOf () }[annotationNode.desc] = annotationData
42
- }
43
- }
54
+ val fieldDescriptors = classNode.fields.map { fieldNode ->
55
+ val fieldAnnotations = fieldNode.visibleAnnotations
56
+ ?.filter { it.desc != " Lkotlin/Metadata;" }
57
+ ?.map { parseAnnotation(it) }
58
+ ? : emptyList()
59
+ FieldAnnotationsDescriptor (fieldNode.name, getFieldVisibility(classNode, fieldNode), fieldAnnotations)
44
60
}
45
61
46
- classNode.fields?.forEach { fieldNode ->
47
- fieldNode.visibleAnnotations?.forEach { annotationNode ->
48
- if (annotationNode.desc != " Lkotlin/Metadata;" ) {
49
- val annotationData = parseAnnotation(annotationNode)
50
- fieldAnnotations.getOrPut(fieldNode.name) { mutableMapOf () }[annotationNode.desc] = annotationData
51
- }
52
- }
53
- }
62
+ val packageName = classNode.name.substringBeforeLast(' /' , " " ).replace(' /' , ' .' )
63
+ val classDescriptor = ClassAnnotationsDescriptor (
64
+ packageName,
65
+ classNode.name.replace(' /' , ' .' ).substringAfterLast(' /' ),
66
+ getVisibility(classNode.access),
67
+ classAnnotations,
68
+ methodDescriptors,
69
+ fieldDescriptors
70
+ )
54
71
55
- classAnnotationsMap[classNode.name] = ClassAnnotations (classAnnotations, methodAnnotations, fieldAnnotations )
72
+ classAnnotationsDescriptors.add(classDescriptor )
56
73
}
57
74
58
75
private fun parseAnnotation (annotationNode : AnnotationNode ): AnnotationData {
@@ -64,7 +81,7 @@ class AnnotationProcessor {
64
81
parameters[name] = formatAnnotationValue(value)
65
82
}
66
83
}
67
- return AnnotationData (parameters)
84
+ return AnnotationData (annotationNode.desc.removePrefix( " L " ).removeSuffix( " ; " ).replace( ' / ' , ' . ' ), parameters)
68
85
}
69
86
70
87
private fun formatAnnotationValue (value : Any? ): Any? {
@@ -103,7 +120,38 @@ class AnnotationProcessor {
103
120
return sb.toString()
104
121
}
105
122
106
- fun getClassAnnotations (): Map <String , ClassAnnotations > {
107
- return classAnnotationsMap
123
+ private fun getVisibility (access : Int ): String {
124
+ return when {
125
+ (access and Opcodes .ACC_PUBLIC ) != 0 -> " public"
126
+ (access and Opcodes .ACC_PROTECTED ) != 0 -> " protected"
127
+ (access and Opcodes .ACC_PRIVATE ) != 0 -> " private"
128
+ else -> " package-private"
129
+ }
130
+ }
131
+
132
+ private fun getFieldVisibility (classNode : ClassNode , fieldNode : FieldNode ): String {
133
+ val getterName = " get${fieldNode.name.capitalize()} "
134
+ val setterName = " set${fieldNode.name.capitalize()} "
135
+
136
+ val getterMethod = classNode.methods.find { it.name == getterName }
137
+ val setterMethod = classNode.methods.find { it.name == setterName }
138
+
139
+ return if (getterMethod != null && setterMethod != null ) {
140
+ val getterVisibility = getVisibility(getterMethod.access)
141
+ val setterVisibility = getVisibility(setterMethod.access)
142
+ if (getterVisibility == setterVisibility) getterVisibility else " package-private"
143
+ } else {
144
+ getVisibility(fieldNode.access)
145
+ }
146
+ }
147
+
148
+ fun getClassDescriptors (): List <ClassAnnotationsDescriptor > {
149
+ return classAnnotationsDescriptors
150
+ }
151
+
152
+ fun getClassAnnotations (packageName : String , className : String ): List <AnnotationData > {
153
+ return classAnnotationsDescriptors
154
+ .filter { it.packageName == packageName && it.name == className }
155
+ .flatMap { it.annotations }
108
156
}
109
157
}
0 commit comments