From 10cfde4ab90c9b889ba142467b1c3083054ffa1b Mon Sep 17 00:00:00 2001 From: Yan Zhulanow Date: Wed, 26 Oct 2016 01:50:53 +0300 Subject: [PATCH] Kapt3: Call super class constructor with some default parameters. Allow interface, annotation, enum modifiers on class. --- .../kotlin/codegen/ClassFileFactory.java | 4 ++ .../jetbrains/kotlin/kapt3/JCTreeConverter.kt | 33 ++++++++-- .../kapt3/test/AbstractJCTreeConverterTest.kt | 5 +- .../test/JCTreeConverterTestGenerated.java | 6 ++ .../testData/converter/inheritanceSimple.kt | 13 ++++ .../testData/converter/inheritanceSimple.txt | 61 +++++++++++++++++++ 6 files changed, 114 insertions(+), 8 deletions(-) create mode 100644 plugins/kapt3/testData/converter/inheritanceSimple.kt create mode 100644 plugins/kapt3/testData/converter/inheritanceSimple.txt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassFileFactory.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassFileFactory.java index ee7d6702a60..4f54c9316fa 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassFileFactory.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassFileFactory.java @@ -58,6 +58,10 @@ public class ClassFileFactory implements OutputFileCollection { this.builderFactory = builderFactory; } + public GenerationState getGenerationState() { + return state; + } + @NotNull public ClassBuilder newVisitor( @NotNull JvmDeclarationOrigin origin, diff --git a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/JCTreeConverter.kt b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/JCTreeConverter.kt index ecfe717b330..0228addfa35 100644 --- a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/JCTreeConverter.kt +++ b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/JCTreeConverter.kt @@ -23,8 +23,10 @@ import com.sun.tools.javac.util.Context import com.sun.tools.javac.util.Name import com.sun.tools.javac.util.Names import com.sun.tools.javac.util.SharedNameTable +import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Type @@ -32,12 +34,18 @@ import org.jetbrains.org.objectweb.asm.tree.* import javax.lang.model.element.ElementKind import com.sun.tools.javac.util.List as JavacList -class JCTreeConverter(context: Context, val classes: List, val origins: Map) { +class JCTreeConverter( + context: Context, + val typeMapper: KotlinTypeMapper, + val classes: List, + val origins: Map +) { 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 CLASS_MODIFIERS = VISIBILITY_MODIFIERS or MODALITY_MODIFIERS or Opcodes.ACC_DEPRECATED + 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 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 @@ -72,7 +80,7 @@ class JCTreeConverter(context: Context, val classes: List, val origin // Nested classes will be processed during the outer classes conversion if (descriptor.containingDeclaration is ClassDescriptor) return null - val classDeclaration = convert(clazz) + val classDeclaration = convertClass(clazz) val packageAnnotations = JavacList.nil() val packageName = ktFile.packageFqName.asString() @@ -87,7 +95,7 @@ class JCTreeConverter(context: Context, val classes: List, val origin /** * Returns false for the inner classe or if the origin for the class was not found. */ - private fun convert(clazz: ClassNode): JCClassDecl? { + private fun convertClass(clazz: ClassNode): JCClassDecl? { if (isSynthetic(clazz.access)) return null val descriptor = origins[clazz]?.descriptor as? ClassDescriptor ?: return null @@ -102,7 +110,7 @@ class JCTreeConverter(context: Context, val classes: List, val origin val nestedClasses = mapValues(clazz.innerClasses) { innerClass -> if (innerClass.outerName != clazz.name) return@mapValues null val innerClassNode = classes.firstOrNull { it.name == innerClass.name } ?: return@mapValues null - convert(innerClassNode) + convertClass(innerClassNode) } return treeMaker.ClassDef(modifiers, simpleName, typeParams, extending, implementing, fields + methods + nestedClasses) @@ -150,7 +158,20 @@ class JCTreeConverter(context: Context, val classes: List, val origin val body = if (defaultValue != null) { null } else if (isConstructor) { - var statements = JavacList.nil() + // We already checked it in convertClass() + val declaration = origins[containingClass]?.descriptor as ClassDescriptor + val superClass = declaration.getSuperClassOrAny() + val superClassConstructor = superClass.constructors.firstOrNull { it.visibility.isVisible(null, it, declaration) } + + var statements = if (superClassConstructor != null) { + val args = mapValues(superClassConstructor.valueParameters) { param -> + convertLiteralExpression(getDefaultValue(typeMapper.mapType(param.type))) + } + val call = treeMaker.Apply(JavacList.nil(), convertSimpleName("super"), args) + JavacList.of(treeMaker.Exec(call)) + } else { + JavacList.nil() + } for (field in containingClass.fields) { if ((field.access and Opcodes.ACC_FINAL) == 0) continue diff --git a/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/AbstractJCTreeConverterTest.kt b/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/AbstractJCTreeConverterTest.kt index a1906e56dd8..a4c6d5307f6 100644 --- a/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/AbstractJCTreeConverterTest.kt +++ b/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/AbstractJCTreeConverterTest.kt @@ -34,10 +34,11 @@ abstract class AbstractJCTreeConverterTest : CodegenTestCase() { val txtFile = File(wholeFile.parentFile, wholeFile.nameWithoutExtension + ".txt") val classBuilderFactory = Kapt3BuilderFactory() - CodegenTestUtil.generateFiles(myEnvironment, myFiles, classBuilderFactory) + val factory = CodegenTestUtil.generateFiles(myEnvironment, myFiles, classBuilderFactory) + val typeMapper = factory.generationState.typeMapper val kaptRunner = KaptRunner() - val converter = JCTreeConverter(kaptRunner.context, classBuilderFactory.compiledClasses, classBuilderFactory.origins) + val converter = JCTreeConverter(kaptRunner.context, typeMapper, classBuilderFactory.compiledClasses, classBuilderFactory.origins) val javaFiles = converter.convert() KotlinTestUtils.assertEqualsToFile(txtFile, javaFiles.joinToString("\n\n////////////////////\n\n")) 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 81baee8323c..c4cb576d3ea 100644 --- a/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/JCTreeConverterTestGenerated.java +++ b/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/JCTreeConverterTestGenerated.java @@ -40,4 +40,10 @@ public class JCTreeConverterTestGenerated extends AbstractJCTreeConverterTest { String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/testData/converter/dataClass.kt"); doTest(fileName); } + + @TestMetadata("inheritanceSimple.kt") + public void testInheritanceSimple() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/testData/converter/inheritanceSimple.kt"); + doTest(fileName); + } } diff --git a/plugins/kapt3/testData/converter/inheritanceSimple.kt b/plugins/kapt3/testData/converter/inheritanceSimple.kt new file mode 100644 index 00000000000..a5f43fd0478 --- /dev/null +++ b/plugins/kapt3/testData/converter/inheritanceSimple.kt @@ -0,0 +1,13 @@ +interface Context + +enum class Result { + SUCCESS, ERROR +} + +abstract class BaseClass(context: Context, num: Int, bool: Boolean) { + abstract fun doJob(): Result +} + +class Inheritor(context: Context) : BaseClass(context, 5, true) { + override fun doJob() = Result.SUCCESS +} \ No newline at end of file diff --git a/plugins/kapt3/testData/converter/inheritanceSimple.txt b/plugins/kapt3/testData/converter/inheritanceSimple.txt new file mode 100644 index 00000000000..2376c756985 --- /dev/null +++ b/plugins/kapt3/testData/converter/inheritanceSimple.txt @@ -0,0 +1,61 @@ +public abstract interface Context { +} + +//////////////////// + + +public final class Context { +} + +//////////////////// + + +public enum Result extends java.lang.Enum { +; + public static final Result SUCCESS; + public static final Result ERROR; + + protected /*missing*/ Result(@java.lang.Synthetic() + java.lang.String $enum_name_or_ordinal$0, @java.lang.Synthetic() + int $enum_name_or_ordinal$1) { + super(null, 0); + this.SUCCESS = null; + this.ERROR = null; + } + + public static Result[] values() { + return null; + } + + public static Result valueOf(java.lang.String p0) { + return null; + } +} + +//////////////////// + + +public abstract class BaseClass { + + public abstract Result doJob() { + return null; + } + + public /*missing*/ BaseClass(Context context, int num, boolean bool) { + super(); + } +} + +//////////////////// + + +public final class Inheritor extends BaseClass { + + public Result doJob() { + return null; + } + + public /*missing*/ Inheritor(Context context) { + super(null, 0, false); + } +} \ No newline at end of file