Kapt3: Parse generic signatures of classes.
Refactoring (move TreeMaker helper functions to KaptTreeMaker, mapValues() and others to utils.kt).
This commit is contained in:
committed by
Yan Zhulanow
parent
e4158a5571
commit
efd25de13f
@@ -22,7 +22,6 @@ import com.sun.tools.javac.tree.JCTree
|
||||
import com.sun.tools.javac.tree.JCTree.*
|
||||
import com.sun.tools.javac.tree.TreeMaker
|
||||
import com.sun.tools.javac.util.Context
|
||||
import com.sun.tools.javac.util.Names
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
@@ -67,8 +66,8 @@ class JCTreeConverter(
|
||||
}
|
||||
|
||||
private val fileManager = context.get(JavaFileManager::class.java) as JavacFileManager
|
||||
private val treeMaker = TreeMaker.instance(context)
|
||||
private val nameTable = Names.instance(context).table
|
||||
private val treeMaker = TreeMaker.instance(context) as KaptTreeMaker
|
||||
private val signatureParser = SignatureParser(treeMaker)
|
||||
|
||||
private var done = false
|
||||
|
||||
@@ -90,7 +89,7 @@ class JCTreeConverter(
|
||||
|
||||
val packageAnnotations = JavacList.nil<JCAnnotation>()
|
||||
val packageName = ktFile.packageFqName.asString()
|
||||
val packageClause = if (packageName.isEmpty()) null else convertFqName(packageName)
|
||||
val packageClause = if (packageName.isEmpty()) null else treeMaker.convertFqName(packageName)
|
||||
|
||||
val imports = JavacList.nil<JCTree>()
|
||||
val classes = JavacList.of<JCTree>(classDeclaration)
|
||||
@@ -102,7 +101,7 @@ class JCTreeConverter(
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns false for the inner classe or if the origin for the class was not found.
|
||||
* Returns false for the inner classes or if the origin for the class was not found.
|
||||
*/
|
||||
private fun convertClass(clazz: ClassNode, isTopLevel: Boolean): JCClassDecl? {
|
||||
if (isSynthetic(clazz.access)) return null
|
||||
@@ -124,16 +123,18 @@ class JCTreeConverter(
|
||||
return null
|
||||
}
|
||||
|
||||
val simpleName = name(if (isDefaultImpls) "DefaultImpls" else descriptor.name.asString())
|
||||
val simpleName = treeMaker.name(if (isDefaultImpls) "DefaultImpls" else descriptor.name.asString())
|
||||
|
||||
val typeParams = JavacList.nil<JCTypeParameter>()
|
||||
val extending = if (clazz.superName == "java/lang/Object" || isEnum) null else convertFqName(clazz.superName)
|
||||
|
||||
val implementing = mapValues(clazz.interfaces) {
|
||||
val interfaces = mapValues(clazz.interfaces) {
|
||||
if (isAnnotation && it == "java/lang/annotation/Annotation") return@mapValues null
|
||||
convertFqName(it)
|
||||
treeMaker.convertFqName(it)
|
||||
}
|
||||
|
||||
val superClass = treeMaker.convertFqName(clazz.superName)
|
||||
|
||||
val hasSuperClass = clazz.superName != "java/lang/Object" && !isEnum
|
||||
val genericType = signatureParser.parseClassSignature(clazz.signature, superClass, interfaces)
|
||||
|
||||
val fields = mapValues<FieldNode, JCTree>(clazz.fields) { convertField(it) }
|
||||
val methods = mapValues<MethodNode, JCTree>(clazz.methods) {
|
||||
if (isEnum) {
|
||||
@@ -149,21 +150,27 @@ class JCTreeConverter(
|
||||
convertClass(innerClassNode, false)
|
||||
}
|
||||
|
||||
return treeMaker.ClassDef(modifiers, simpleName, typeParams, extending, implementing, fields + methods + nestedClasses)
|
||||
return treeMaker.ClassDef(
|
||||
modifiers,
|
||||
simpleName,
|
||||
genericType.typeParameters,
|
||||
if (hasSuperClass) genericType.superClass else null,
|
||||
genericType.interfaces,
|
||||
fields + methods + nestedClasses)
|
||||
}
|
||||
|
||||
private fun convertField(field: FieldNode): JCVariableDecl? {
|
||||
if (isSynthetic(field.access)) return null
|
||||
|
||||
val modifiers = convertModifiers(field.access, ElementKind.FIELD, field.visibleAnnotations, field.invisibleAnnotations)
|
||||
val name = name(field.name)
|
||||
val name = treeMaker.name(field.name)
|
||||
val type = Type.getType(field.desc)
|
||||
|
||||
// Enum type must be an identifier (Javac requirement)
|
||||
val typeExpression = if (isEnum(field.access)) {
|
||||
convertSimpleName(type.className.substringAfterLast('.'))
|
||||
treeMaker.convertSimpleName(type.className.substringAfterLast('.'))
|
||||
} else {
|
||||
convertType(type)
|
||||
treeMaker.convertType(type)
|
||||
}
|
||||
|
||||
val value = field.value
|
||||
@@ -193,23 +200,23 @@ class JCTreeConverter(
|
||||
ElementKind.METHOD, visibleAnnotations, method.invisibleAnnotations)
|
||||
|
||||
val isConstructor = method.name == "<init>"
|
||||
val name = name(method.name)
|
||||
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 convertType(returnType)
|
||||
val returnTypeExpr = 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 name = name(info.name)
|
||||
val type = convertType(info.type)
|
||||
val name = treeMaker.name(info.name)
|
||||
val type = treeMaker.convertType(info.type)
|
||||
treeMaker.VarDef(modifiers, name, type, null)
|
||||
}
|
||||
|
||||
val thrown = mapValues(method.exceptions) { convertFqName(it) }
|
||||
val thrown = mapValues(method.exceptions) { treeMaker.convertFqName(it) }
|
||||
|
||||
val defaultValue = method.annotationDefault?.let { convertLiteralExpression(it) }
|
||||
|
||||
@@ -229,7 +236,7 @@ class JCTreeConverter(
|
||||
val args = mapValues(superClassConstructor.valueParameters) { param ->
|
||||
convertLiteralExpression(getDefaultValue(typeMapper.mapType(param.type)))
|
||||
}
|
||||
val call = treeMaker.Apply(JavacList.nil(), convertSimpleName("super"), args)
|
||||
val call = treeMaker.Apply(JavacList.nil(), treeMaker.convertSimpleName("super"), args)
|
||||
JavacList.of<JCStatement>(treeMaker.Exec(call))
|
||||
} else {
|
||||
JavacList.nil<JCStatement>()
|
||||
@@ -275,9 +282,9 @@ class JCTreeConverter(
|
||||
val fqName = annotationType.className
|
||||
if (BLACKLISTED_ANNOTATATIONS.any { fqName.startsWith(it) }) return null
|
||||
|
||||
val name = convertType(annotationType)
|
||||
val name = treeMaker.convertType(annotationType)
|
||||
val values = mapPairedValues<JCExpression>(annotation.values) { key, value ->
|
||||
treeMaker.Assign(convertSimpleName(key), convertLiteralExpression(value))
|
||||
treeMaker.Assign(treeMaker.convertSimpleName(key), convertLiteralExpression(value))
|
||||
}
|
||||
return treeMaker.Annotation(name, values)
|
||||
}
|
||||
@@ -300,11 +307,11 @@ class JCTreeConverter(
|
||||
assert(value.size == 2)
|
||||
val enumType = Type.getType(value[0] as String)
|
||||
val valueName = value[1] as String
|
||||
treeMaker.Select(convertType(enumType), name(valueName))
|
||||
treeMaker.Select(treeMaker.convertType(enumType), treeMaker.name(valueName))
|
||||
}
|
||||
is List<*> -> treeMaker.NewArray(null, JavacList.nil(), mapValues(value) { convertLiteralExpression(it) })
|
||||
|
||||
is Type -> treeMaker.Select(convertType(value), name("class"))
|
||||
is Type -> treeMaker.Select(treeMaker.convertType(value), treeMaker.name("class"))
|
||||
is AnnotationNode -> convertAnnotation(value) ?: error("Annotation is filtered out")
|
||||
else -> throw IllegalArgumentException("Illegal literal expression value: $value (${value.javaClass.canonicalName})")
|
||||
}
|
||||
@@ -321,46 +328,6 @@ class JCTreeConverter(
|
||||
Type.DOUBLE_TYPE -> 0.0
|
||||
else -> null
|
||||
}
|
||||
|
||||
private fun convertType(type: Type): JCExpression {
|
||||
convertBuiltinType(type)?.let { return it }
|
||||
if (type.sort == Type.ARRAY) {
|
||||
return treeMaker.TypeArray(convertType(type.elementType))
|
||||
}
|
||||
return convertFqName(type.className)
|
||||
}
|
||||
|
||||
private fun convertFqName(internalOrFqName: String): JCExpression {
|
||||
val path = internalOrFqName.replace('/', '.').split('.')
|
||||
assert(path.isNotEmpty())
|
||||
if (path.size == 1) return convertSimpleName(path.single())
|
||||
|
||||
var expr = treeMaker.Select(convertSimpleName(path[0]), name(path[1]))
|
||||
for (index in 2..path.lastIndex) {
|
||||
expr = treeMaker.Select(expr, name(path[index]))
|
||||
}
|
||||
return expr
|
||||
}
|
||||
|
||||
private fun convertBuiltinType(type: Type): JCExpression? {
|
||||
val typeTag = when (type) {
|
||||
Type.BYTE_TYPE -> TypeTag.BYTE
|
||||
Type.BOOLEAN_TYPE -> TypeTag.BOOLEAN
|
||||
Type.CHAR_TYPE -> TypeTag.CHAR
|
||||
Type.SHORT_TYPE -> TypeTag.SHORT
|
||||
Type.INT_TYPE -> TypeTag.INT
|
||||
Type.LONG_TYPE -> TypeTag.LONG
|
||||
Type.FLOAT_TYPE -> TypeTag.FLOAT
|
||||
Type.DOUBLE_TYPE -> TypeTag.DOUBLE
|
||||
Type.VOID_TYPE -> TypeTag.VOID
|
||||
else -> null
|
||||
} ?: return null
|
||||
return treeMaker.TypeIdent(typeTag)
|
||||
}
|
||||
|
||||
private fun convertSimpleName(name: String): JCExpression = treeMaker.Ident(name(name))
|
||||
|
||||
private fun name(name: String) = nameTable.fromString(name)
|
||||
}
|
||||
|
||||
private class ParameterInfo(
|
||||
@@ -400,36 +367,6 @@ private fun MethodNode.getParametersInfo(containingClass: ClassNode): List<Param
|
||||
return parameterInfos
|
||||
}
|
||||
|
||||
private inline fun <T, R> mapValues(values: Iterable<T>?, f: (T) -> R?): JavacList<R> {
|
||||
if (values == null) return JavacList.nil()
|
||||
|
||||
var result = JavacList.nil<R>()
|
||||
for (item in values) {
|
||||
f(item)?.let { result = result.prepend(it) }
|
||||
}
|
||||
return result.reverse()
|
||||
}
|
||||
|
||||
private inline fun <T> mapPairedValues(valuePairs: List<Any>?, f: (String, Any) -> T?): JavacList<T> {
|
||||
if (valuePairs == null || valuePairs.isEmpty()) return JavacList.nil()
|
||||
|
||||
val size = valuePairs.size
|
||||
var result = JavacList.nil<T>()
|
||||
assert(size % 2 == 0)
|
||||
var index = 0
|
||||
while (index < size) {
|
||||
val key = valuePairs[index] as String
|
||||
val value = valuePairs[index + 1]
|
||||
f(key, value)?.let { result = result.prepend(it) }
|
||||
index += 2
|
||||
}
|
||||
return result.reverse()
|
||||
}
|
||||
|
||||
private operator fun <T : Any> JavacList<T>.plus(other: JavacList<T>): JavacList<T> {
|
||||
return this.appendList(other)
|
||||
}
|
||||
|
||||
private val ClassDescriptor.isNested: Boolean
|
||||
get() = containingDeclaration is ClassDescriptor
|
||||
|
||||
@@ -442,4 +379,4 @@ 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 <T> List<T>.isNullOrEmpty() = this == null || this.isEmpty()
|
||||
private fun <T> List<T>?.isNullOrEmpty() = this == null || this.isEmpty()
|
||||
@@ -55,6 +55,7 @@ class KaptRunner {
|
||||
|
||||
init {
|
||||
JavacFileManager.preRegister(context)
|
||||
KaptTreeMaker.preRegister(context)
|
||||
KaptJavaCompiler.preRegister(context)
|
||||
|
||||
compiler = JavaCompiler.instance(context) as KaptJavaCompiler
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.kapt3
|
||||
|
||||
import com.sun.tools.javac.code.TypeTag
|
||||
import com.sun.tools.javac.tree.JCTree
|
||||
import com.sun.tools.javac.tree.TreeMaker
|
||||
import com.sun.tools.javac.util.Context
|
||||
import com.sun.tools.javac.util.Names
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.Type.*
|
||||
|
||||
class KaptTreeMaker(context: Context?) : TreeMaker(context) {
|
||||
private val nameTable = Names.instance(context).table
|
||||
|
||||
fun convertType(type: Type): JCTree.JCExpression {
|
||||
convertBuiltinType(type)?.let { return it }
|
||||
if (type.sort == ARRAY) {
|
||||
return TypeArray(convertType(type.elementType))
|
||||
}
|
||||
return convertFqName(type.className)
|
||||
}
|
||||
|
||||
fun convertFqName(internalOrFqName: String): JCTree.JCExpression {
|
||||
val path = internalOrFqName.replace('/', '.').split('.')
|
||||
assert(path.isNotEmpty())
|
||||
if (path.size == 1) return convertSimpleName(path.single())
|
||||
|
||||
var expr = Select(convertSimpleName(path[0]), name(path[1]))
|
||||
for (index in 2..path.lastIndex) {
|
||||
expr = Select(expr, name(path[index]))
|
||||
}
|
||||
return expr
|
||||
}
|
||||
|
||||
fun convertBuiltinType(type: Type): JCTree.JCExpression? {
|
||||
val typeTag = when (type) {
|
||||
BYTE_TYPE -> TypeTag.BYTE
|
||||
BOOLEAN_TYPE -> TypeTag.BOOLEAN
|
||||
CHAR_TYPE -> TypeTag.CHAR
|
||||
SHORT_TYPE -> TypeTag.SHORT
|
||||
INT_TYPE -> TypeTag.INT
|
||||
LONG_TYPE -> TypeTag.LONG
|
||||
FLOAT_TYPE -> TypeTag.FLOAT
|
||||
DOUBLE_TYPE -> TypeTag.DOUBLE
|
||||
VOID_TYPE -> TypeTag.VOID
|
||||
else -> null
|
||||
} ?: return null
|
||||
return TypeIdent(typeTag)
|
||||
}
|
||||
|
||||
fun convertSimpleName(name: String): JCTree.JCExpression = Ident(name(name))
|
||||
|
||||
fun name(name: String) = nameTable.fromString(name)
|
||||
|
||||
companion object {
|
||||
fun preRegister(context: Context) {
|
||||
context.put(treeMakerKey, Context.Factory<TreeMaker>(::KaptTreeMaker))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.kapt3
|
||||
|
||||
import com.sun.tools.javac.code.BoundKind
|
||||
import com.sun.tools.javac.tree.JCTree.*
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.signature.SignatureVisitor
|
||||
import java.util.*
|
||||
import org.jetbrains.kotlin.kapt3.ElementKind.*
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
import org.jetbrains.org.objectweb.asm.signature.SignatureReader
|
||||
import com.sun.tools.javac.util.List as JavacList
|
||||
|
||||
/*
|
||||
TopLevel
|
||||
* FormalTypeParameter
|
||||
+ SuperClass
|
||||
* Interface
|
||||
|
||||
FormalTypeParameter < TopLevel
|
||||
+ ClassBound
|
||||
* InterfaceBound
|
||||
|
||||
ClassBound < FormalTypeParameter
|
||||
+ ClassType
|
||||
|
||||
InterfaceBound < FormalTypeParameter
|
||||
? ClassType
|
||||
? TypeVariable
|
||||
|
||||
TypeVariable < InterfaceBound
|
||||
|
||||
SuperClass < TopLevel
|
||||
+ ClassType
|
||||
|
||||
Interface < TopLevel
|
||||
+ ClassType
|
||||
|
||||
ClassType < *
|
||||
* TypeArgument
|
||||
|
||||
TypeArgument < ClassType
|
||||
+ ClassType
|
||||
*/
|
||||
|
||||
enum class ElementKind {
|
||||
Root, TypeParameter, ClassBound, InterfaceBound, SuperClass, Interface, ClassType, TypeArgument, TypeVariable
|
||||
}
|
||||
|
||||
class SignatureNode(val kind: ElementKind, val name: String? = null) {
|
||||
val children: MutableList<SignatureNode> = SmartList<SignatureNode>()
|
||||
}
|
||||
|
||||
class SignatureParser(val treeMaker: KaptTreeMaker) {
|
||||
class ClassGenericSignature(
|
||||
val typeParameters: JavacList<JCTypeParameter>,
|
||||
val superClass: JCExpression,
|
||||
val interfaces: JavacList<JCExpression>)
|
||||
|
||||
fun parseClassSignature(
|
||||
signature: String?,
|
||||
rawSuperClass: JCExpression,
|
||||
rawInterfaces: JavacList<JCExpression>
|
||||
): ClassGenericSignature {
|
||||
if (signature == null) {
|
||||
return ClassGenericSignature(JavacList.nil(), rawSuperClass, rawInterfaces)
|
||||
}
|
||||
|
||||
val root = parse(signature)
|
||||
val typeParameters = smartList()
|
||||
val superClasses = smartList()
|
||||
val interfaces = smartList()
|
||||
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)
|
||||
}
|
||||
|
||||
private fun parseTypeParameter(node: SignatureNode): JCTypeParameter {
|
||||
assert(node.kind == TypeParameter)
|
||||
|
||||
val classBounds = smartList()
|
||||
val interfaceBounds = smartList()
|
||||
node.split(classBounds, ClassBound, interfaceBounds, InterfaceBound)
|
||||
assert(classBounds.size <= 1)
|
||||
|
||||
val jcClassBound = classBounds.firstOrNull()?.let { parseBound(it) }
|
||||
val jcInterfaceBounds = mapValues(interfaceBounds) { parseBound(it) }
|
||||
val allBounds = if (jcClassBound != null) jcInterfaceBounds.prepend(jcClassBound) else jcInterfaceBounds
|
||||
return treeMaker.TypeParameter(treeMaker.name(node.name!!), allBounds)
|
||||
}
|
||||
|
||||
private fun parseBound(node: SignatureNode): JCExpression {
|
||||
assert(node.kind == ClassBound || node.kind == InterfaceBound)
|
||||
return parseType(node.children.single())
|
||||
}
|
||||
|
||||
private fun parseType(node: SignatureNode): JCExpression {
|
||||
val kind = node.kind
|
||||
return when (kind) {
|
||||
ClassType -> {
|
||||
val classFqName = node.name!!.replace('/', '.')
|
||||
val args = node.children
|
||||
val fqNameExpression = treeMaker.convertFqName(classFqName)
|
||||
if (args.isEmpty()) return fqNameExpression
|
||||
|
||||
treeMaker.TypeApply(fqNameExpression, mapValues(args) { arg ->
|
||||
assert(arg.kind == TypeArgument) { "Unexpected kind ${arg.kind}, $TypeArgument expected" }
|
||||
val variance = arg.name ?: return@mapValues treeMaker.Wildcard(treeMaker.TypeBoundKind(BoundKind.UNBOUND), null)
|
||||
|
||||
val argType = parseType(arg.children.single())
|
||||
when (variance.single()) {
|
||||
'=' -> argType
|
||||
'+' -> treeMaker.Wildcard(treeMaker.TypeBoundKind(BoundKind.EXTENDS), argType)
|
||||
'-' -> treeMaker.Wildcard(treeMaker.TypeBoundKind(BoundKind.SUPER), argType)
|
||||
else -> error("Unknown variance, '=', '+' or '-' expected")
|
||||
}
|
||||
})
|
||||
}
|
||||
TypeVariable -> treeMaker.convertSimpleName(node.name!!)
|
||||
else -> error("Unsupported type: $node")
|
||||
}
|
||||
}
|
||||
|
||||
private fun parse(signature: String): SignatureNode {
|
||||
val parser = SignatureParserVisitor()
|
||||
SignatureReader(signature).accept(parser)
|
||||
return parser.root
|
||||
}
|
||||
}
|
||||
|
||||
private fun smartList() = SmartList<SignatureNode>()
|
||||
|
||||
private fun SignatureNode.split(l1: MutableList<SignatureNode>, e1: ElementKind, l2: MutableList<SignatureNode>, e2: ElementKind) {
|
||||
for (child in children) {
|
||||
val kind = child.kind
|
||||
when (kind) {
|
||||
e1 -> l1 += child
|
||||
e2 -> l2 += child
|
||||
else -> error("Unknown kind: $kind")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun SignatureNode.split(
|
||||
l1: MutableList<SignatureNode>,
|
||||
e1: ElementKind,
|
||||
l2: MutableList<SignatureNode>,
|
||||
e2: ElementKind,
|
||||
l3: MutableList<SignatureNode>,
|
||||
e3: ElementKind) {
|
||||
for (child in children) {
|
||||
val kind = child.kind
|
||||
when (kind) {
|
||||
e1 -> l1 += child
|
||||
e2 -> l2 += child
|
||||
e3 -> l3 += 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) }
|
||||
|
||||
private fun push(kind: ElementKind, parent: ElementKind? = null, name: String? = null) {
|
||||
if (parent != null) {
|
||||
while (stack.peek().kind != parent) {
|
||||
stack.pop()
|
||||
}
|
||||
}
|
||||
|
||||
val newNode = SignatureNode(kind, name)
|
||||
stack.peek().children += newNode
|
||||
stack.push(newNode)
|
||||
}
|
||||
|
||||
override fun visitSuperclass(): SignatureVisitor {
|
||||
push(SuperClass, parent = Root)
|
||||
return super.visitSuperclass()
|
||||
}
|
||||
|
||||
override fun visitInterface(): SignatureVisitor {
|
||||
push(Interface, parent = Root)
|
||||
return super.visitInterface()
|
||||
}
|
||||
|
||||
override fun visitFormalTypeParameter(name: String) {
|
||||
push(TypeParameter, parent = Root, name = name)
|
||||
}
|
||||
|
||||
override fun visitClassBound(): SignatureVisitor {
|
||||
push(ClassBound, parent = TypeParameter)
|
||||
return super.visitClassBound()
|
||||
}
|
||||
|
||||
override fun visitInterfaceBound(): SignatureVisitor {
|
||||
push(InterfaceBound, parent = TypeParameter)
|
||||
return super.visitInterfaceBound()
|
||||
}
|
||||
|
||||
override fun visitTypeArgument() {
|
||||
push(TypeArgument, parent = ClassType)
|
||||
}
|
||||
|
||||
override fun visitTypeArgument(wildcard: Char): SignatureVisitor {
|
||||
push(TypeArgument, parent = ClassType, name = wildcard.toString())
|
||||
return super.visitTypeArgument(wildcard)
|
||||
}
|
||||
|
||||
override fun visitClassType(name: String) {
|
||||
push(ClassType, name = name)
|
||||
}
|
||||
|
||||
override fun visitTypeVariable(name: String) {
|
||||
push(TypeVariable, parent = InterfaceBound, name = name)
|
||||
}
|
||||
|
||||
override fun visitEnd() {
|
||||
while (stack.peek().kind != ClassType) {
|
||||
stack.pop()
|
||||
}
|
||||
stack.pop()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.kapt3
|
||||
import com.sun.tools.javac.util.List as JavacList
|
||||
|
||||
internal inline fun <T, R> mapValues(values: Iterable<T>?, f: (T) -> R?): JavacList<R> {
|
||||
if (values == null) return JavacList.nil()
|
||||
|
||||
var result = JavacList.nil<R>()
|
||||
for (item in values) {
|
||||
f(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()
|
||||
|
||||
val size = valuePairs.size
|
||||
var result = JavacList.nil<T>()
|
||||
assert(size % 2 == 0)
|
||||
var index = 0
|
||||
while (index < size) {
|
||||
val key = valuePairs[index] as String
|
||||
val value = valuePairs[index + 1]
|
||||
f(key, value)?.let { result = result.prepend(it) }
|
||||
index += 2
|
||||
}
|
||||
return result.reverse()
|
||||
}
|
||||
|
||||
internal operator fun <T : Any> JavacList<T>.plus(other: JavacList<T>): JavacList<T> {
|
||||
return this.appendList(other)
|
||||
}
|
||||
@@ -65,6 +65,12 @@ public class JCTreeConverterTestGenerated extends AbstractJCTreeConverterTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("genericSimple.kt")
|
||||
public void testGenericSimple() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/testData/converter/genericSimple.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("inheritanceSimple.kt")
|
||||
public void testInheritanceSimple() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/testData/converter/inheritanceSimple.kt");
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import java.io.Serializable
|
||||
import java.util.*
|
||||
|
||||
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>()
|
||||
@@ -0,0 +1,34 @@
|
||||
public abstract interface Intf<I1 extends java.lang.Object, I2 extends java.io.Serializable> {
|
||||
}
|
||||
|
||||
////////////////////
|
||||
|
||||
|
||||
public abstract interface Intf2<T extends java.util.List<? extends java.lang.String>, M extends T> {
|
||||
}
|
||||
|
||||
////////////////////
|
||||
|
||||
|
||||
public abstract interface OtherIntf<O extends java.lang.CharSequence> {
|
||||
}
|
||||
|
||||
////////////////////
|
||||
|
||||
|
||||
public class BaseClass<B extends java.lang.Object> {
|
||||
|
||||
public BaseClass() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////
|
||||
|
||||
|
||||
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> {
|
||||
|
||||
public MyClass() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user