1 /*
2 * Copyright (C) 2021 Square, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package com.squareup.kotlinpoet.metadata.classinspectors
17
18 import javax.lang.model.element.Element
19 import javax.lang.model.element.ExecutableElement
20 import javax.lang.model.element.NestingKind
21 import javax.lang.model.element.QualifiedNameable
22 import javax.lang.model.element.TypeElement
23 import javax.lang.model.element.VariableElement
24 import javax.lang.model.type.ArrayType
25 import javax.lang.model.type.DeclaredType
26 import javax.lang.model.type.ErrorType
27 import javax.lang.model.type.ExecutableType
28 import javax.lang.model.type.IntersectionType
29 import javax.lang.model.type.NoType
30 import javax.lang.model.type.NullType
31 import javax.lang.model.type.PrimitiveType
32 import javax.lang.model.type.TypeKind.BOOLEAN
33 import javax.lang.model.type.TypeKind.BYTE
34 import javax.lang.model.type.TypeKind.CHAR
35 import javax.lang.model.type.TypeKind.DOUBLE
36 import javax.lang.model.type.TypeKind.FLOAT
37 import javax.lang.model.type.TypeKind.INT
38 import javax.lang.model.type.TypeKind.LONG
39 import javax.lang.model.type.TypeKind.SHORT
40 import javax.lang.model.type.TypeMirror
41 import javax.lang.model.type.TypeVariable
42 import javax.lang.model.type.UnionType
43 import javax.lang.model.type.WildcardType
44 import javax.lang.model.util.AbstractTypeVisitor8
45 import javax.lang.model.util.Types
46 import kotlin.metadata.jvm.JvmFieldSignature
47 import kotlin.metadata.jvm.JvmMethodSignature
48
49 /*
50 * Adapted from
51 * - https://github.com/Takhion/kotlin-metadata/blob/e6de126575ad6ca10b093129b7c30d000c9b0c37/lib/src/main/kotlin/me/eugeniomarletti/kotlin/metadata/jvm/JvmDescriptorUtils.kt
52 * - https://github.com/Takhion/kotlin-metadata/pull/13
53 */
54
55 /**
56 * For reference, see the [JVM specification, section 4.2](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.2).
57 *
58 * @return the name of this [Element] in its "internal form".
59 */
60 @Suppress("RecursivePropertyAccessor")
61 internal val Element.internalName: String
62 get() = when (this) {
63 is TypeElement -> {
64 when (nestingKind) {
65 NestingKind.TOP_LEVEL ->
66 qualifiedName.toString().replace('.', '/')
67 NestingKind.MEMBER ->
68 enclosingElement.internalName + "$" + simpleName
69 NestingKind.LOCAL, NestingKind.ANONYMOUS ->
70 error("Unsupported nesting $nestingKind")
71 null ->
72 error("Unsupported, nestingKind == null")
73 }
74 }
75 is QualifiedNameable -> qualifiedName.toString().replace('.', '/')
76 else -> simpleName.toString()
77 }
78
79 /**
80 * @return the "field descriptor" of this type.
81 * @see [JvmDescriptorTypeVisitor]
82 */
83 @Suppress("unused")
84 internal val NoType.descriptor: String
85 get() = "V"
86
87 /**
88 * @return the "field descriptor" of this type.
89 * @see [JvmDescriptorTypeVisitor]
90 */
91 internal val DeclaredType.descriptor: String
92 get() = "L" + asElement().internalName + ";"
93
94 /**
95 * @return the "field descriptor" of this type.
96 * @see [JvmDescriptorTypeVisitor]
97 */
98 internal val PrimitiveType.descriptor: String
99 get() = when (this.kind) {
100 BYTE -> "B"
101 CHAR -> "C"
102 DOUBLE -> "D"
103 FLOAT -> "F"
104 INT -> "I"
105 LONG -> "J"
106 SHORT -> "S"
107 BOOLEAN -> "Z"
108 else -> error("Unknown primitive type $this")
109 }
110
111 /**
112 * @see [JvmDescriptorTypeVisitor]
113 */
descriptornull114 internal fun TypeMirror.descriptor(types: Types): String =
115 accept(JvmDescriptorTypeVisitor, types)
116
117 /**
118 * @return the "field descriptor" of this type.
119 * @see [JvmDescriptorTypeVisitor]
120 */
121 internal fun WildcardType.descriptor(types: Types): String =
122 types.erasure(this).descriptor(types)
123
124 /**
125 * @return the "field descriptor" of this type.
126 * @see [JvmDescriptorTypeVisitor]
127 */
128 internal fun TypeVariable.descriptor(types: Types): String =
129 types.erasure(this).descriptor(types)
130
131 /**
132 * @return the "field descriptor" of this type.
133 * @see [JvmDescriptorTypeVisitor]
134 */
135 internal fun ArrayType.descriptor(types: Types): String =
136 "[" + componentType.descriptor(types)
137
138 /**
139 * @return the "method descriptor" of this type.
140 * @see [JvmDescriptorTypeVisitor]
141 */
142 internal fun ExecutableType.descriptor(types: Types): String {
143 val parameterDescriptors = parameterTypes.joinToString(separator = "") { it.descriptor(types) }
144 val returnDescriptor = returnType.descriptor(types)
145 return "($parameterDescriptors)$returnDescriptor"
146 }
147
148 /**
149 * Returns the JVM signature in the form "$Name$MethodDescriptor", for example: `equals(Ljava/lang/Object;)Z`.
150 *
151 * Useful for comparing with [JvmMethodSignature].
152 *
153 * For reference, see the [JVM specification, section 4.3](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3).
154 */
jvmMethodSignaturenull155 internal fun ExecutableElement.jvmMethodSignature(types: Types): String {
156 return "$simpleName${asType().descriptor(types)}"
157 }
158
159 /**
160 * Returns the JVM signature in the form "$Name:$FieldDescriptor", for example: `"value:Ljava/lang/String;"`.
161 *
162 * Useful for comparing with [JvmFieldSignature].
163 *
164 * For reference, see the [JVM specification, section 4.3](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3).
165 */
jvmFieldSignaturenull166 internal fun VariableElement.jvmFieldSignature(types: Types): String {
167 return "$simpleName:${asType().descriptor(types)}"
168 }
169
170 /**
171 * When applied over a type, it returns either:
172 * - a "field descriptor", for example: `Ljava/lang/Object;`
173 * - a "method descriptor", for example: `(Ljava/lang/Object;)Z`
174 *
175 * For reference, see the [JVM specification, section 4.3](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3).
176 */
177 internal object JvmDescriptorTypeVisitor : AbstractTypeVisitor8<String, Types>() {
visitNoTypenull178 override fun visitNoType(t: NoType, types: Types): String = t.descriptor
179 override fun visitDeclared(t: DeclaredType, types: Types): String = t.descriptor
180 override fun visitPrimitive(t: PrimitiveType, types: Types): String = t.descriptor
181
182 override fun visitArray(t: ArrayType, types: Types): String = t.descriptor(types)
183 override fun visitWildcard(t: WildcardType, types: Types): String = t.descriptor(types)
184 override fun visitExecutable(t: ExecutableType, types: Types): String = t.descriptor(types)
185 override fun visitTypeVariable(t: TypeVariable, types: Types): String = t.descriptor(types)
186
187 override fun visitNull(t: NullType, types: Types): String = visitUnknown(t, types)
188
189 override fun visitError(t: ErrorType, types: Types): String = visitUnknown(t, types)
190
191 override fun visitUnion(t: UnionType, types: Types): String = visitUnknown(t, types)
192
193 override fun visitIntersection(t: IntersectionType, types: Types): String = visitUnknown(t, types)
194
195 override fun visitUnknown(t: TypeMirror, types: Types): String = error("Unsupported type $t")
196 }
197