Kapt3: Parse generic signatures of methods and fields
This commit is contained in:
committed by
Yan Zhulanow
parent
efd25de13f
commit
5b780ec56c
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.kapt3
|
||||
|
||||
import com.sun.tools.javac.code.Flags
|
||||
import com.sun.tools.javac.code.TypeTag
|
||||
import com.sun.tools.javac.file.JavacFileManager
|
||||
import com.sun.tools.javac.tree.JCTree
|
||||
@@ -44,17 +45,19 @@ class JCTreeConverter(
|
||||
val origins: Map<Any, JvmDeclarationOrigin>
|
||||
) {
|
||||
private companion object {
|
||||
private val VISIBILITY_MODIFIERS = Opcodes.ACC_PUBLIC or Opcodes.ACC_PRIVATE or Opcodes.ACC_PROTECTED
|
||||
private val MODALITY_MODIFIERS = Opcodes.ACC_FINAL or Opcodes.ACC_ABSTRACT
|
||||
private val VISIBILITY_MODIFIERS = (Opcodes.ACC_PUBLIC or Opcodes.ACC_PRIVATE or Opcodes.ACC_PROTECTED).toLong()
|
||||
private val MODALITY_MODIFIERS = (Opcodes.ACC_FINAL or Opcodes.ACC_ABSTRACT).toLong()
|
||||
|
||||
private val CLASS_MODIFIERS = VISIBILITY_MODIFIERS or MODALITY_MODIFIERS or
|
||||
Opcodes.ACC_DEPRECATED or Opcodes.ACC_INTERFACE or Opcodes.ACC_ANNOTATION or Opcodes.ACC_ENUM or Opcodes.ACC_STATIC
|
||||
(Opcodes.ACC_DEPRECATED or Opcodes.ACC_INTERFACE or Opcodes.ACC_ANNOTATION or Opcodes.ACC_ENUM or Opcodes.ACC_STATIC).toLong()
|
||||
|
||||
private val METHOD_MODIFIERS = VISIBILITY_MODIFIERS or MODALITY_MODIFIERS or
|
||||
Opcodes.ACC_SYNCHRONIZED or Opcodes.ACC_STATIC or Opcodes.ACC_NATIVE or Opcodes.ACC_DEPRECATED
|
||||
(Opcodes.ACC_SYNCHRONIZED or Opcodes.ACC_STATIC or Opcodes.ACC_NATIVE or Opcodes.ACC_DEPRECATED).toLong()
|
||||
|
||||
private val FIELD_MODIFIERS = VISIBILITY_MODIFIERS or MODALITY_MODIFIERS or
|
||||
Opcodes.ACC_STATIC or Opcodes.ACC_VOLATILE or Opcodes.ACC_TRANSIENT or Opcodes.ACC_ENUM
|
||||
(Opcodes.ACC_STATIC or Opcodes.ACC_VOLATILE or Opcodes.ACC_TRANSIENT or Opcodes.ACC_ENUM).toLong()
|
||||
|
||||
private val PARAMETER_MODIFIERS = FIELD_MODIFIERS or Flags.PARAMETER or Flags.VARARGS or Opcodes.ACC_FINAL.toLong()
|
||||
|
||||
private val BLACKLISTED_ANNOTATATIONS = listOf(
|
||||
"java.lang.Deprecated", "kotlin.Deprecated", // Deprecated annotations
|
||||
@@ -170,7 +173,7 @@ class JCTreeConverter(
|
||||
val typeExpression = if (isEnum(field.access)) {
|
||||
treeMaker.convertSimpleName(type.className.substringAfterLast('.'))
|
||||
} else {
|
||||
treeMaker.convertType(type)
|
||||
signatureParser.parseFieldSignature(field.signature, treeMaker.convertType(type))
|
||||
}
|
||||
|
||||
val value = field.value
|
||||
@@ -196,27 +199,33 @@ class JCTreeConverter(
|
||||
}
|
||||
|
||||
val modifiers = convertModifiers(
|
||||
if (containingClass.isEnum()) (method.access and VISIBILITY_MODIFIERS.inv()) else method.access,
|
||||
if (containingClass.isEnum()) (method.access.toLong() and VISIBILITY_MODIFIERS.inv()) else method.access.toLong(),
|
||||
ElementKind.METHOD, visibleAnnotations, method.invisibleAnnotations)
|
||||
|
||||
val isConstructor = method.name == "<init>"
|
||||
val name = treeMaker.name(method.name)
|
||||
val typeParameters = JavacList.nil<JCTypeParameter>()
|
||||
val receiverParameter = null
|
||||
|
||||
val returnType = Type.getReturnType(method.desc)
|
||||
val returnTypeExpr = if (isConstructor) null else treeMaker.convertType(returnType)
|
||||
val jcReturnType = if (isConstructor) null else treeMaker.convertType(returnType)
|
||||
|
||||
val parametersInfo = method.getParametersInfo(containingClass)
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val parameters = mapValues(parametersInfo) { info ->
|
||||
val modifiers = convertModifiers(info.access, ElementKind.PARAMETER, info.visibleAnnotations, info.invisibleAnnotations)
|
||||
val parameters = mapValuesIndexed(parametersInfo) { index, info ->
|
||||
val lastParameter = index == parametersInfo.lastIndex
|
||||
val isArrayType = info.type.sort == Type.ARRAY
|
||||
|
||||
val varargs = if (lastParameter && isArrayType && method.isVarargs()) Flags.VARARGS else 0L
|
||||
val modifiers = convertModifiers(
|
||||
info.flags or varargs or Flags.PARAMETER,
|
||||
ElementKind.PARAMETER, info.visibleAnnotations, info.invisibleAnnotations)
|
||||
val name = treeMaker.name(info.name)
|
||||
val type = treeMaker.convertType(info.type)
|
||||
treeMaker.VarDef(modifiers, name, type, null)
|
||||
}
|
||||
|
||||
val thrown = mapValues(method.exceptions) { treeMaker.convertFqName(it) }
|
||||
val exceptionTypes = mapValues(method.exceptions) { treeMaker.convertFqName(it) }
|
||||
|
||||
val genericType = signatureParser.parseMethodSignature(method.signature, parameters, exceptionTypes, jcReturnType)
|
||||
|
||||
val defaultValue = method.annotationDefault?.let { convertLiteralExpression(it) }
|
||||
|
||||
@@ -250,15 +259,25 @@ class JCTreeConverter(
|
||||
treeMaker.Block(0, JavacList.of(returnStatement))
|
||||
}
|
||||
|
||||
return treeMaker.MethodDef(modifiers, name, returnTypeExpr,
|
||||
typeParameters, receiverParameter, parameters, thrown, body, defaultValue)
|
||||
return treeMaker.MethodDef(
|
||||
modifiers, name, genericType.returnType, genericType.typeParameters,
|
||||
genericType.parameterTypes, genericType.exceptionTypes,
|
||||
body, defaultValue)
|
||||
}
|
||||
|
||||
private fun convertModifiers(
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
private inline fun convertModifiers(
|
||||
access: Int,
|
||||
kind: ElementKind,
|
||||
visibleAnnotations: List<AnnotationNode>?,
|
||||
invisibleAnnotations: List<AnnotationNode>?
|
||||
): JCModifiers = convertModifiers(access.toLong(), kind, visibleAnnotations, invisibleAnnotations)
|
||||
|
||||
private fun convertModifiers(
|
||||
access: Long,
|
||||
kind: ElementKind,
|
||||
visibleAnnotations: List<AnnotationNode>?,
|
||||
invisibleAnnotations: List<AnnotationNode>?
|
||||
): JCModifiers {
|
||||
var annotations = visibleAnnotations?.fold(JavacList.nil<JCAnnotation>()) { list, anno ->
|
||||
convertAnnotation(anno)?.let { list.prepend(it) } ?: list
|
||||
@@ -271,10 +290,10 @@ class JCTreeConverter(
|
||||
ElementKind.CLASS -> access and CLASS_MODIFIERS
|
||||
ElementKind.METHOD -> access and METHOD_MODIFIERS
|
||||
ElementKind.FIELD -> access and FIELD_MODIFIERS
|
||||
ElementKind.PARAMETER -> access and Opcodes.ACC_FINAL
|
||||
ElementKind.PARAMETER -> access and PARAMETER_MODIFIERS
|
||||
else -> throw IllegalArgumentException("Invalid element kind: $kind")
|
||||
}
|
||||
return treeMaker.Modifiers(flags.toLong(), annotations)
|
||||
return treeMaker.Modifiers(flags, annotations)
|
||||
}
|
||||
|
||||
private fun convertAnnotation(annotation: AnnotationNode): JCAnnotation? {
|
||||
@@ -331,7 +350,7 @@ class JCTreeConverter(
|
||||
}
|
||||
|
||||
private class ParameterInfo(
|
||||
val access: Int,
|
||||
val flags: Long,
|
||||
val name: String,
|
||||
val type: Type,
|
||||
val visibleAnnotations: List<AnnotationNode>?,
|
||||
@@ -378,5 +397,6 @@ private fun isStatic(access: Int) = (access and Opcodes.ACC_STATIC) > 0
|
||||
private fun isAbstract(access: Int) = (access and Opcodes.ACC_ABSTRACT) > 0
|
||||
private fun ClassNode.isEnum() = (access and Opcodes.ACC_ENUM) > 0
|
||||
private fun ClassNode.isAnnotation() = (access and Opcodes.ACC_ANNOTATION) > 0
|
||||
private fun MethodNode.isVarargs() = (access and Opcodes.ACC_VARARGS) > 0
|
||||
|
||||
private fun <T> List<T>?.isNullOrEmpty() = this == null || this.isEmpty()
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.kotlin.kapt3
|
||||
|
||||
import com.sun.tools.javac.code.BoundKind
|
||||
import com.sun.tools.javac.code.TypeTag
|
||||
import com.sun.tools.javac.tree.JCTree.*
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.signature.SignatureVisitor
|
||||
@@ -27,19 +28,36 @@ import org.jetbrains.org.objectweb.asm.signature.SignatureReader
|
||||
import com.sun.tools.javac.util.List as JavacList
|
||||
|
||||
/*
|
||||
TopLevel
|
||||
Root (Class)
|
||||
* FormalTypeParameter
|
||||
+ SuperClass
|
||||
* Interface
|
||||
|
||||
FormalTypeParameter < TopLevel
|
||||
Root (Method)
|
||||
* TypeParameter
|
||||
* ParameterType
|
||||
+ ReturnType
|
||||
* ExceptionType
|
||||
|
||||
Root (Field)
|
||||
+ SuperClass
|
||||
|
||||
TypeParameter < Root
|
||||
+ ClassBound
|
||||
* InterfaceBound
|
||||
|
||||
ClassBound < FormalTypeParameter
|
||||
ParameterType < Root
|
||||
+ Type
|
||||
|
||||
ReturnType < Root
|
||||
+ Type
|
||||
|
||||
Type :: ClassType | TypeVariable | PrimitiveType | ArrayType
|
||||
|
||||
ClassBound < TypeParameter
|
||||
+ ClassType
|
||||
|
||||
InterfaceBound < FormalTypeParameter
|
||||
InterfaceBound < TypeParameter
|
||||
? ClassType
|
||||
? TypeVariable
|
||||
|
||||
@@ -59,7 +77,8 @@ import com.sun.tools.javac.util.List as JavacList
|
||||
*/
|
||||
|
||||
enum class ElementKind {
|
||||
Root, TypeParameter, ClassBound, InterfaceBound, SuperClass, Interface, ClassType, TypeArgument, TypeVariable
|
||||
Root, TypeParameter, ClassBound, InterfaceBound, SuperClass, Interface, TypeArgument, ParameterType, ReturnType, ExceptionType,
|
||||
ClassType, TypeVariable, PrimitiveType, ArrayType
|
||||
}
|
||||
|
||||
class SignatureNode(val kind: ElementKind, val name: String? = null) {
|
||||
@@ -71,6 +90,13 @@ class SignatureParser(val treeMaker: KaptTreeMaker) {
|
||||
val typeParameters: JavacList<JCTypeParameter>,
|
||||
val superClass: JCExpression,
|
||||
val interfaces: JavacList<JCExpression>)
|
||||
|
||||
class MethodGenericSignature(
|
||||
val typeParameters: JavacList<JCTypeParameter>,
|
||||
val parameterTypes: JavacList<JCVariableDecl>,
|
||||
val exceptionTypes: JavacList<JCExpression>,
|
||||
val returnType: JCExpression?
|
||||
)
|
||||
|
||||
fun parseClassSignature(
|
||||
signature: String?,
|
||||
@@ -88,9 +114,51 @@ class SignatureParser(val treeMaker: KaptTreeMaker) {
|
||||
root.split(typeParameters, TypeParameter, superClasses, SuperClass, interfaces, Interface)
|
||||
|
||||
val jcTypeParameters = mapValues(typeParameters) { parseTypeParameter(it) }
|
||||
val superClassType = parseType(superClasses.single().children.single())
|
||||
val interfaceTypes = mapValues(interfaces) { parseType(it.children.single()) }
|
||||
return ClassGenericSignature(jcTypeParameters, superClassType, interfaceTypes)
|
||||
val jcSuperClass = parseType(superClasses.single().children.single())
|
||||
val jcInterfaces = mapValues(interfaces) { parseType(it.children.single()) }
|
||||
return ClassGenericSignature(jcTypeParameters, jcSuperClass, jcInterfaces)
|
||||
}
|
||||
|
||||
fun parseMethodSignature(
|
||||
signature: String?,
|
||||
rawParameters: JavacList<JCVariableDecl>,
|
||||
rawExceptionTypes: JavacList<JCExpression>,
|
||||
rawReturnType: JCExpression?
|
||||
): MethodGenericSignature {
|
||||
if (signature == null) {
|
||||
return MethodGenericSignature(JavacList.nil(), rawParameters, rawExceptionTypes, rawReturnType)
|
||||
}
|
||||
|
||||
val root = parse(signature)
|
||||
val typeParameters = smartList()
|
||||
val parameterTypes = smartList()
|
||||
val exceptionTypes = smartList()
|
||||
val returnTypes = smartList()
|
||||
root.split(typeParameters, TypeParameter, parameterTypes, ParameterType, exceptionTypes, ExceptionType, returnTypes, ReturnType)
|
||||
|
||||
val jcTypeParameters = mapValues(typeParameters) { parseTypeParameter(it) }
|
||||
assert(rawParameters.size >= parameterTypes.size)
|
||||
val offset = rawParameters.size - parameterTypes.size
|
||||
val jcParameters = mapValuesIndexed(parameterTypes) { index, it ->
|
||||
val rawParameter = rawParameters[index + offset]
|
||||
treeMaker.VarDef(rawParameter.modifiers, rawParameter.getName(), parseType(it.children.single()), rawParameter.initializer)
|
||||
}
|
||||
val jcExceptionTypes = mapValues(exceptionTypes) { parseType(it) }
|
||||
val jcReturnType = if (rawReturnType == null) null else parseType(returnTypes.single().children.single())
|
||||
return MethodGenericSignature(jcTypeParameters, jcParameters, jcExceptionTypes, jcReturnType)
|
||||
}
|
||||
|
||||
fun parseFieldSignature(
|
||||
signature: String?,
|
||||
rawType: JCExpression
|
||||
): JCExpression {
|
||||
if (signature == null) return rawType
|
||||
|
||||
val root = parse(signature)
|
||||
val superClass = root.children.single()
|
||||
assert(superClass.kind == SuperClass)
|
||||
|
||||
return parseType(superClass.children.single())
|
||||
}
|
||||
|
||||
private fun parseTypeParameter(node: SignatureNode): JCTypeParameter {
|
||||
@@ -135,6 +203,22 @@ class SignatureParser(val treeMaker: KaptTreeMaker) {
|
||||
})
|
||||
}
|
||||
TypeVariable -> treeMaker.convertSimpleName(node.name!!)
|
||||
ArrayType -> treeMaker.TypeArray(parseType(node.children.single()))
|
||||
PrimitiveType -> {
|
||||
val typeTag = when (node.name!!.single()) {
|
||||
'V' -> TypeTag.VOID
|
||||
'Z' -> TypeTag.BOOLEAN
|
||||
'C' -> TypeTag.CHAR
|
||||
'B' -> TypeTag.BYTE
|
||||
'S' -> TypeTag.SHORT
|
||||
'I' -> TypeTag.INT
|
||||
'F' -> TypeTag.FLOAT
|
||||
'J' -> TypeTag.LONG
|
||||
'D' -> TypeTag.DOUBLE
|
||||
else -> error("Illegal primitive type ${node.name}")
|
||||
}
|
||||
treeMaker.TypeIdent(typeTag)
|
||||
}
|
||||
else -> error("Unsupported type: $node")
|
||||
}
|
||||
}
|
||||
@@ -165,7 +249,8 @@ private fun SignatureNode.split(
|
||||
l2: MutableList<SignatureNode>,
|
||||
e2: ElementKind,
|
||||
l3: MutableList<SignatureNode>,
|
||||
e3: ElementKind) {
|
||||
e3: ElementKind
|
||||
) {
|
||||
for (child in children) {
|
||||
val kind = child.kind
|
||||
when (kind) {
|
||||
@@ -177,6 +262,28 @@ private fun SignatureNode.split(
|
||||
}
|
||||
}
|
||||
|
||||
private fun SignatureNode.split(
|
||||
l1: MutableList<SignatureNode>,
|
||||
e1: ElementKind,
|
||||
l2: MutableList<SignatureNode>,
|
||||
e2: ElementKind,
|
||||
l3: MutableList<SignatureNode>,
|
||||
e3: ElementKind,
|
||||
l4: MutableList<SignatureNode>,
|
||||
e4: ElementKind
|
||||
) {
|
||||
for (child in children) {
|
||||
val kind = child.kind
|
||||
when (kind) {
|
||||
e1 -> l1 += child
|
||||
e2 -> l2 += child
|
||||
e3 -> l3 += child
|
||||
e4 -> l4 += child
|
||||
else -> error("Unknown kind: $kind")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class SignatureParserVisitor : SignatureVisitor(Opcodes.ASM5) {
|
||||
val root = SignatureNode(Root)
|
||||
private val stack = ArrayDeque<SignatureNode>(5).apply { add(root) }
|
||||
@@ -231,7 +338,31 @@ private class SignatureParserVisitor : SignatureVisitor(Opcodes.ASM5) {
|
||||
}
|
||||
|
||||
override fun visitTypeVariable(name: String) {
|
||||
push(TypeVariable, parent = InterfaceBound, name = name)
|
||||
push(TypeVariable, name = name)
|
||||
}
|
||||
|
||||
override fun visitParameterType(): SignatureVisitor {
|
||||
push(ParameterType, parent = Root)
|
||||
return super.visitParameterType()
|
||||
}
|
||||
|
||||
override fun visitReturnType(): SignatureVisitor {
|
||||
push(ReturnType, parent = Root)
|
||||
return super.visitReturnType()
|
||||
}
|
||||
|
||||
override fun visitExceptionType(): SignatureVisitor {
|
||||
push(ExceptionType, parent = Root)
|
||||
return super.visitExceptionType()
|
||||
}
|
||||
|
||||
override fun visitBaseType(descriptor: Char) {
|
||||
push(PrimitiveType, name = descriptor.toString())
|
||||
}
|
||||
|
||||
override fun visitArrayType(): SignatureVisitor {
|
||||
push(ArrayType)
|
||||
return super.visitArrayType()
|
||||
}
|
||||
|
||||
override fun visitEnd() {
|
||||
|
||||
@@ -27,6 +27,16 @@ internal inline fun <T, R> mapValues(values: Iterable<T>?, f: (T) -> R?): JavacL
|
||||
return result.reverse()
|
||||
}
|
||||
|
||||
internal inline fun <T, R> mapValuesIndexed(values: Iterable<T>?, f: (Int, T) -> R?): JavacList<R> {
|
||||
if (values == null) return JavacList.nil()
|
||||
|
||||
var result = JavacList.nil<R>()
|
||||
values.forEachIndexed { index, item ->
|
||||
f(index, item)?.let { result = result.prepend(it) }
|
||||
}
|
||||
return result.reverse()
|
||||
}
|
||||
|
||||
internal inline fun <T> mapPairedValues(valuePairs: List<Any>?, f: (String, Any) -> T?): JavacList<T> {
|
||||
if (valuePairs == null || valuePairs.isEmpty()) return JavacList.nil()
|
||||
|
||||
|
||||
+2
-2
@@ -31,9 +31,9 @@ public abstract @interface Anno2 {
|
||||
|
||||
public abstract Colors[] colors() default {Colors.BLACK, Colors.WHITE};
|
||||
|
||||
public abstract java.lang.Class clazz();
|
||||
public abstract java.lang.Class<?> clazz();
|
||||
|
||||
public abstract java.lang.Class[] classes();
|
||||
public abstract java.lang.Class<?>[] classes();
|
||||
}
|
||||
|
||||
////////////////////
|
||||
|
||||
+4
-5
@@ -1,11 +1,10 @@
|
||||
|
||||
public final class FunctionsTest {
|
||||
|
||||
public final kotlin.reflect.KProperty1 f() {
|
||||
|
||||
public final kotlin.reflect.KProperty1<java.lang.String, java.lang.Integer> f() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public final kotlin.jvm.functions.Function2 f2() {
|
||||
public final kotlin.jvm.functions.Function2<java.lang.Integer, java.lang.Integer, java.lang.Boolean> f2() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -19,4 +18,4 @@ public final class FunctionsTest {
|
||||
public FunctionsTest() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
-1
@@ -5,4 +5,11 @@ interface Intf<I1, I2 : Serializable>
|
||||
interface Intf2<out T : List<String>, M : T>
|
||||
interface OtherIntf<O : CharSequence>
|
||||
open class BaseClass<B : Any>
|
||||
class MyClass<M1, M2> : Intf<Any, java.util.Date>, OtherIntf<String>, BaseClass<RuntimeException>()
|
||||
class MyClass<M1, M2> : Intf<Any, java.util.Date>, OtherIntf<String>, BaseClass<RuntimeException>() {
|
||||
val fld: List<Map<String, M1>>? = null
|
||||
}
|
||||
|
||||
interface ABC {
|
||||
fun <T : CharSequence> abc(item: T, items: List<T>, vararg otherItems: T): List<T>
|
||||
fun <X> bcd(vararg a: Char): Int
|
||||
}
|
||||
@@ -27,8 +27,23 @@ public class BaseClass<B extends java.lang.Object> {
|
||||
|
||||
|
||||
public final class MyClass<M1 extends java.lang.Object, M2 extends java.lang.Object> extends BaseClass<java.lang.RuntimeException> implements Intf<java.lang.Object, java.util.Date>, OtherIntf<java.lang.String> {
|
||||
private final java.util.List<java.util.Map<java.lang.String, M1>> fld = null;
|
||||
|
||||
public final java.util.List<java.util.Map<java.lang.String, M1>> getFld() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public MyClass() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////
|
||||
|
||||
|
||||
public abstract interface ABC {
|
||||
|
||||
public abstract <T extends java.lang.CharSequence>java.util.List<T> abc(T item, java.util.List<? extends T> items, T... otherItems);
|
||||
|
||||
public abstract <X extends java.lang.Object>int bcd(char... a);
|
||||
}
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ public final class Test {
|
||||
|
||||
public final class Inner {
|
||||
|
||||
public Inner(Test $outer) {
|
||||
public Inner() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user