diff --git a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/JCTreeConverter.kt b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/JCTreeConverter.kt index 333b757b80b..cd1c969204f 100644 --- a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/JCTreeConverter.kt +++ b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/JCTreeConverter.kt @@ -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() 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() val classes = JavacList.of(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() - 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(clazz.fields) { convertField(it) } val methods = mapValues(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 == "" - val name = name(method.name) + val name = treeMaker.name(method.name) val typeParameters = JavacList.nil() 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(treeMaker.Exec(call)) } else { JavacList.nil() @@ -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(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 mapValues(values: Iterable?, f: (T) -> R?): JavacList { - if (values == null) return JavacList.nil() - - var result = JavacList.nil() - for (item in values) { - f(item)?.let { result = result.prepend(it) } - } - return result.reverse() -} - -private inline fun mapPairedValues(valuePairs: List?, f: (String, Any) -> T?): JavacList { - if (valuePairs == null || valuePairs.isEmpty()) return JavacList.nil() - - val size = valuePairs.size - var result = JavacList.nil() - 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 JavacList.plus(other: JavacList): JavacList { - 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 List.isNullOrEmpty() = this == null || this.isEmpty() \ No newline at end of file +private fun List?.isNullOrEmpty() = this == null || this.isEmpty() \ No newline at end of file diff --git a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/KaptRunner.kt b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/KaptRunner.kt index 1f440fd824c..30c98de4138 100644 --- a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/KaptRunner.kt +++ b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/KaptRunner.kt @@ -55,6 +55,7 @@ class KaptRunner { init { JavacFileManager.preRegister(context) + KaptTreeMaker.preRegister(context) KaptJavaCompiler.preRegister(context) compiler = JavaCompiler.instance(context) as KaptJavaCompiler diff --git a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/KaptTreeMaker.kt b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/KaptTreeMaker.kt new file mode 100644 index 00000000000..c2a164c5b7e --- /dev/null +++ b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/KaptTreeMaker.kt @@ -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(::KaptTreeMaker)) + } + } +} \ No newline at end of file diff --git a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/SignatureParserVisitor.kt b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/SignatureParserVisitor.kt new file mode 100644 index 00000000000..c62565a6f36 --- /dev/null +++ b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/SignatureParserVisitor.kt @@ -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 = SmartList() +} + +class SignatureParser(val treeMaker: KaptTreeMaker) { + class ClassGenericSignature( + val typeParameters: JavacList, + val superClass: JCExpression, + val interfaces: JavacList) + + fun parseClassSignature( + signature: String?, + rawSuperClass: JCExpression, + rawInterfaces: JavacList + ): 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() + +private fun SignatureNode.split(l1: MutableList, e1: ElementKind, l2: MutableList, 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, + e1: ElementKind, + l2: MutableList, + e2: ElementKind, + l3: MutableList, + 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(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() + } +} \ No newline at end of file diff --git a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/utils.kt b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/utils.kt new file mode 100644 index 00000000000..d8663c5b865 --- /dev/null +++ b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/utils.kt @@ -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 mapValues(values: Iterable?, f: (T) -> R?): JavacList { + if (values == null) return JavacList.nil() + + var result = JavacList.nil() + for (item in values) { + f(item)?.let { result = result.prepend(it) } + } + return result.reverse() +} + +internal inline fun mapPairedValues(valuePairs: List?, f: (String, Any) -> T?): JavacList { + if (valuePairs == null || valuePairs.isEmpty()) return JavacList.nil() + + val size = valuePairs.size + var result = JavacList.nil() + 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 JavacList.plus(other: JavacList): JavacList { + return this.appendList(other) +} \ No newline at end of file diff --git a/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/JCTreeConverterTestGenerated.java b/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/JCTreeConverterTestGenerated.java index 02761abe2f4..5b112aa0164 100644 --- a/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/JCTreeConverterTestGenerated.java +++ b/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/JCTreeConverterTestGenerated.java @@ -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"); diff --git a/plugins/kapt3/testData/converter/genericSimple.kt b/plugins/kapt3/testData/converter/genericSimple.kt new file mode 100644 index 00000000000..22cd42fa66b --- /dev/null +++ b/plugins/kapt3/testData/converter/genericSimple.kt @@ -0,0 +1,8 @@ +import java.io.Serializable +import java.util.* + +interface Intf +interface Intf2, M : T> +interface OtherIntf +open class BaseClass +class MyClass : Intf, OtherIntf, BaseClass() \ No newline at end of file diff --git a/plugins/kapt3/testData/converter/genericSimple.txt b/plugins/kapt3/testData/converter/genericSimple.txt new file mode 100644 index 00000000000..0b7a3773d0c --- /dev/null +++ b/plugins/kapt3/testData/converter/genericSimple.txt @@ -0,0 +1,34 @@ +public abstract interface Intf { +} + +//////////////////// + + +public abstract interface Intf2, M extends T> { +} + +//////////////////// + + +public abstract interface OtherIntf { +} + +//////////////////// + + +public class BaseClass { + + public BaseClass() { + super(); + } +} + +//////////////////// + + +public final class MyClass extends BaseClass implements Intf, OtherIntf { + + public MyClass() { + super(); + } +}