diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt index 45e7c4b5134..b45c1cde8df 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt @@ -79,6 +79,7 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To private val INFO_AS_WARNINGS = "kapt.info.as.warnings" private val INCLUDE_COMPILE_CLASSPATH = "kapt.include.compile.classpath" private val INCREMENTAL_APT = "kapt.incremental.apt" + private val KAPT_KEEP_KDOC_COMMENTS_IN_STUBS = "kapt.keep.kdoc.comments.in.stubs" const val KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME = "kotlinKaptWorkerDependencies" @@ -119,6 +120,10 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To fun includeCompileClasspath(project: Project): Boolean? = project.findProperty(INCLUDE_COMPILE_CLASSPATH)?.run { toString().toBoolean() } + fun Project.isKaptKeepKdocCommentsInStubs(): Boolean { + return !(hasProperty(KAPT_KEEP_KDOC_COMMENTS_IN_STUBS) && property(KAPT_KEEP_KDOC_COMMENTS_IN_STUBS) == "false") + } + fun findMainKaptConfiguration(project: Project) = project.findKaptConfiguration(SourceSet.MAIN_SOURCE_SET_NAME) fun createAptConfigurationIfNeeded(project: Project, sourceSetName: String): Configuration { @@ -392,6 +397,7 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To pluginOptions += SubpluginOption("mapDiagnosticLocations", "${kaptExtension.mapDiagnosticLocations}") pluginOptions += SubpluginOption("strictMode", "${kaptExtension.strictMode}") pluginOptions += SubpluginOption("stripMetadata", "${kaptExtension.stripMetadata}") + pluginOptions += SubpluginOption("keepKdocCommentsInStubs", "${project.isKaptKeepKdocCommentsInStubs()}") pluginOptions += SubpluginOption("showProcessorTimings", "${kaptExtension.showProcessorTimings}") pluginOptions += SubpluginOption("detectMemoryLeaks", kaptExtension.detectMemoryLeaks) pluginOptions += SubpluginOption("infoAsWarnings", "${project.isInfoAsWarnings()}") diff --git a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/KaptOptions.kt b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/KaptOptions.kt index c8cf29e70c5..ca207927c6c 100644 --- a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/KaptOptions.kt +++ b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/KaptOptions.kt @@ -62,7 +62,8 @@ class KaptOptions( val flags: MutableSet = mutableSetOf( KaptFlag.USE_LIGHT_ANALYSIS, - KaptFlag.INCLUDE_COMPILE_CLASSPATH + KaptFlag.INCLUDE_COMPILE_CLASSPATH, + KaptFlag.KEEP_KDOC_COMMENTS_IN_STUBS ) var mode: AptMode = AptMode.WITH_COMPILATION @@ -114,7 +115,8 @@ enum class KaptFlag(val description: String) { STRICT("Strict mode"), INCLUDE_COMPILE_CLASSPATH("Detect annotation processors in compile classpath"), INCREMENTAL_APT("Incremental annotation processing (apt mode)"), - STRIP_METADATA("Strip @Metadata annotations from stubs") + STRIP_METADATA("Strip @Metadata annotations from stubs"), + KEEP_KDOC_COMMENTS_IN_STUBS("Keep KDoc comments in stubs") ; } diff --git a/plugins/kapt3/kapt3-cli/src/KaptCliOption.kt b/plugins/kapt3/kapt3-cli/src/KaptCliOption.kt index 7a77e139860..078989a315e 100644 --- a/plugins/kapt3/kapt3-cli/src/KaptCliOption.kt +++ b/plugins/kapt3/kapt3-cli/src/KaptCliOption.kt @@ -195,6 +195,12 @@ enum class KaptCliOption( cliToolOption = CliToolOption("-Kapt-strip-metadata", FLAG) ), + KEEP_KDOC_COMMENTS_IN_STUBS( + "keepKdocCommentsInStubs", + "true | false", + "Keep KDoc comments in stubs" + ), + DETECT_MEMORY_LEAKS_OPTION("detectMemoryLeaks", "true | false", "Detect memory leaks in annotation processors"), INCLUDE_COMPILE_CLASSPATH( "includeCompileClasspath", diff --git a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/Kapt3Plugin.kt b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/Kapt3Plugin.kt index 62f22dca4c2..d053ac69664 100644 --- a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/Kapt3Plugin.kt +++ b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/Kapt3Plugin.kt @@ -117,6 +117,7 @@ class Kapt3CommandLineProcessor : CommandLineProcessor { INFO_AS_WARNINGS_OPTION -> setFlag(KaptFlag.INFO_AS_WARNINGS, value) STRICT_MODE_OPTION -> setFlag(KaptFlag.STRICT, value) STRIP_METADATA_OPTION -> setFlag(KaptFlag.STRIP_METADATA, value) + KEEP_KDOC_COMMENTS_IN_STUBS -> setFlag(KaptFlag.KEEP_KDOC_COMMENTS_IN_STUBS, value) SHOW_PROCESSOR_TIMINGS -> setFlag(KaptFlag.SHOW_PROCESSOR_TIMINGS, value) INCLUDE_COMPILE_CLASSPATH -> setFlag(KaptFlag.INCLUDE_COMPILE_CLASSPATH, value) diff --git a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt index bd6b5b6ef8e..c6b0cf5bff8 100644 --- a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt +++ b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt @@ -113,6 +113,7 @@ class ClassFileToSourceStubConverter(val kaptContext: KaptContextForStubGenerati private val correctErrorTypes = kaptContext.options[KaptFlag.CORRECT_ERROR_TYPES] private val strictMode = kaptContext.options[KaptFlag.STRICT] private val stripMetadata = kaptContext.options[KaptFlag.STRIP_METADATA] + private val keepKdocComments = kaptContext.options[KaptFlag.KEEP_KDOC_COMMENTS_IN_STUBS] private val mutableBindings = mutableMapOf() @@ -433,7 +434,11 @@ class ClassFileToSourceStubConverter(val kaptContext: KaptContextForStubGenerati superTypes.superClass, superTypes.interfaces, enumValues + sortedFields + sortedMethods + nestedClasses - ).keepKdocComments(clazz) + ).also { + if (keepKdocComments) { + it.keepKdocComments(clazz) + } + } } private class MemberData(val name: String, val descriptor: String, val position: KotlinPosition?) @@ -708,7 +713,11 @@ class ClassFileToSourceStubConverter(val kaptContext: KaptContextForStubGenerati lineMappings.registerField(containingClass, field) val initializer = explicitInitializer ?: convertPropertyInitializer(field) - return treeMaker.VarDef(modifiers, treeMaker.name(name), typeExpression, initializer).keepKdocComments(field) + return treeMaker.VarDef(modifiers, treeMaker.name(name), typeExpression, initializer).also { + if (keepKdocComments) { + it.keepKdocComments(field) + } + } } private fun convertPropertyInitializer(field: FieldNode): JCExpression? { @@ -954,7 +963,11 @@ class ClassFileToSourceStubConverter(val kaptContext: KaptContextForStubGenerati modifiers, treeMaker.name(name), returnType, genericSignature.typeParameters, genericSignature.parameterTypes, genericSignature.exceptionTypes, body, defaultValue - ).keepKdocComments(method).keepSignature(lineMappings, method) + ).keepSignature(lineMappings, method).also { + if (keepKdocComments) { + it.keepKdocComments(method) + } + } } private fun isIgnored(annotations: List?): Boolean { diff --git a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3IntegrationTest.kt b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3IntegrationTest.kt index 9a9f77d35f8..043d26c253f 100644 --- a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3IntegrationTest.kt +++ b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3IntegrationTest.kt @@ -141,7 +141,8 @@ abstract class AbstractKotlinKapt3IntegrationTest : KotlinKapt3TestBase() { incrementalDataOutputDir = Files.createTempDirectory("kaptIncrementalData").toFile() mutableOptions?.let { processingOptions.putAll(it) } - flags.addAll(kaptFlags) + flags.addAll(kaptFlagsToAdd) + flags.removeAll(kaptFlagsToRemove) detectMemoryLeaks = DetectMemoryLeaksMode.NONE }.build() diff --git a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3Test.kt b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3Test.kt index ee2a0d826bf..746203c3bb1 100644 --- a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3Test.kt +++ b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3Test.kt @@ -129,7 +129,8 @@ abstract class AbstractKotlinKapt3Test : KotlinKapt3TestBase() { incrementalDataOutputDir = sourcesOutputDir this.javacOptions.putAll(javacOptions) - flags.addAll(kaptFlags) + flags.addAll(kaptFlagsToAdd) + flags.removeAll(kaptFlagsToRemove) detectMemoryLeaks = DetectMemoryLeaksMode.NONE }.build() @@ -251,21 +252,16 @@ open class AbstractClassFileToSourceStubConverterTest : AbstractKotlinKapt3Test( fun testSuppressWarning() {} override fun doTest(filePath: String) { - val wholeFile = File(filePath) + val testFile = File(filePath) - kaptFlags.add(KaptFlag.MAP_DIAGNOSTIC_LOCATIONS) + kaptFlagsToAdd.add(KaptFlag.MAP_DIAGNOSTIC_LOCATIONS) - if (wholeFile.isOptionSet("CORRECT_ERROR_TYPES")) { - kaptFlags.add(KaptFlag.CORRECT_ERROR_TYPES) - } - - if (wholeFile.isOptionSet("STRICT_MODE")) { - kaptFlags.add(KaptFlag.STRICT) - } - - if (wholeFile.isOptionSet("STRIP_METADATA")) { - kaptFlags.add(KaptFlag.STRIP_METADATA) + addOrRemoveFlag(KaptFlag.CORRECT_ERROR_TYPES, testFile) + if (isFlagEnabled("STRICT_MODE", testFile)) { + kaptFlagsToAdd.add(KaptFlag.STRICT) } + addOrRemoveFlag(KaptFlag.STRIP_METADATA, testFile) + addOrRemoveFlag(KaptFlag.KEEP_KDOC_COMMENTS_IN_STUBS, testFile) super.doTest(filePath) doTestWithJdk9(AbstractClassFileToSourceStubConverterTest::class.java, filePath) @@ -273,8 +269,8 @@ open class AbstractClassFileToSourceStubConverterTest : AbstractKotlinKapt3Test( } override fun check(kaptContext: KaptContextForStubGeneration, javaFiles: List, txtFile: File, wholeFile: File) { - val generateNonExistentClass = wholeFile.isOptionSet("NON_EXISTENT_CLASS") - val validate = !wholeFile.isOptionSet("NO_VALIDATION") + val generateNonExistentClass = isFlagEnabled("NON_EXISTENT_CLASS", wholeFile) + val validate = !isFlagEnabled("NO_VALIDATION", wholeFile) val expectedErrors = wholeFile.getRawOptionValues(EXPECTED_ERROR).sorted() val convertedFiles = convert(kaptContext, javaFiles, generateNonExistentClass) @@ -331,9 +327,9 @@ open class AbstractClassFileToSourceStubConverterTest : AbstractKotlinKapt3Test( abstract class AbstractKotlinKaptContextTest : AbstractKotlinKapt3Test() { override fun doTest(filePath: String) { - kaptFlags.add(KaptFlag.CORRECT_ERROR_TYPES) - kaptFlags.add(KaptFlag.STRICT) - kaptFlags.add(KaptFlag.MAP_DIAGNOSTIC_LOCATIONS) + kaptFlagsToAdd.add(KaptFlag.CORRECT_ERROR_TYPES) + kaptFlagsToAdd.add(KaptFlag.STRICT) + kaptFlagsToAdd.add(KaptFlag.MAP_DIAGNOSTIC_LOCATIONS) super.doTest(filePath) } diff --git a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/ClassFileToSourceStubConverterTestGenerated.java b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/ClassFileToSourceStubConverterTestGenerated.java index 1a862e3d1d4..3a738140417 100644 --- a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/ClassFileToSourceStubConverterTestGenerated.java +++ b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/ClassFileToSourceStubConverterTestGenerated.java @@ -74,6 +74,12 @@ public class ClassFileToSourceStubConverterTestGenerated extends AbstractClassFi runTest("plugins/kapt3/kapt3-compiler/testData/converter/comments.kt"); } + /** Regression test for KT-43593. */ + @TestMetadata("commentsRemoved.kt") + public void testCommentsRemoved() throws Exception { + runTest("plugins/kapt3/kapt3-compiler/testData/converter/commentsRemoved.kt"); + } + @TestMetadata("cyrillicClassName.kt") public void testCyrillicClassName() throws Exception { runTest("plugins/kapt3/kapt3-compiler/testData/converter/cyrillicClassName.kt"); diff --git a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/IrClassFileToSourceStubConverterTestGenerated.java b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/IrClassFileToSourceStubConverterTestGenerated.java index c9b4da61a23..f1e2da8eca4 100644 --- a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/IrClassFileToSourceStubConverterTestGenerated.java +++ b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/IrClassFileToSourceStubConverterTestGenerated.java @@ -75,6 +75,12 @@ public class IrClassFileToSourceStubConverterTestGenerated extends AbstractIrCla runTest("plugins/kapt3/kapt3-compiler/testData/converter/comments.kt"); } + /** Regression test for KT-43593. */ + @TestMetadata("commentsRemoved.kt") + public void testCommentsRemoved() throws Exception { + runTest("plugins/kapt3/kapt3-compiler/testData/converter/commentsRemoved.kt"); + } + @TestMetadata("cyrillicClassName.kt") public void testCyrillicClassName() throws Exception { runTest("plugins/kapt3/kapt3-compiler/testData/converter/cyrillicClassName.kt"); diff --git a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/KotlinKapt3TestBase.kt b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/KotlinKapt3TestBase.kt index c2efa4e912f..5f95a8fb4bb 100644 --- a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/KotlinKapt3TestBase.kt +++ b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/KotlinKapt3TestBase.kt @@ -10,29 +10,41 @@ import org.jetbrains.kotlin.codegen.CodegenTestCase import java.io.File abstract class KotlinKapt3TestBase : CodegenTestCase() { - val kaptFlags = mutableListOf() + val kaptFlagsToAdd = mutableListOf() + val kaptFlagsToRemove = mutableListOf() override fun setUp() { super.setUp() - kaptFlags.clear() + kaptFlagsToAdd.clear() + kaptFlagsToRemove.clear() } - protected fun File.isOptionSet(name: String) = this.useLines { lines -> lines.any { it.trim() == "// $name" } } + protected fun isFlagEnabled(flagName: String, testFile: File): Boolean { + val stringToCheck = "// $flagName" + return testFile.useLines { lines -> lines.any { it.trim() == stringToCheck } } + } + + private fun isFlagDisabled(flagName: String, testFile: File): Boolean { + val stringToCheck = "// !$flagName" + return testFile.useLines { lines -> lines.any { it.trim() == stringToCheck } } + } + + protected fun addOrRemoveFlag(flag: KaptFlag, testFile: File) { + if (isFlagEnabled(flag.name, testFile)) { + kaptFlagsToAdd.add(flag) + } else if (isFlagDisabled(flag.name, testFile)) { + kaptFlagsToRemove.add(flag) + } + } override fun doTest(filePath: String) { - val wholeFile = File(filePath) + val testFile = File(filePath) - kaptFlags.add(KaptFlag.MAP_DIAGNOSTIC_LOCATIONS) + kaptFlagsToAdd.add(KaptFlag.MAP_DIAGNOSTIC_LOCATIONS) - fun handleFlag(flag: KaptFlag) { - if (wholeFile.isOptionSet(flag.name)) { - kaptFlags.add(flag) - } - } - - handleFlag(KaptFlag.CORRECT_ERROR_TYPES) - handleFlag(KaptFlag.STRICT) - handleFlag(KaptFlag.DUMP_DEFAULT_PARAMETER_VALUES) + addOrRemoveFlag(KaptFlag.CORRECT_ERROR_TYPES, testFile) + addOrRemoveFlag(KaptFlag.STRICT, testFile) + addOrRemoveFlag(KaptFlag.DUMP_DEFAULT_PARAMETER_VALUES, testFile) super.doTest(filePath) } diff --git a/plugins/kapt3/kapt3-compiler/testData/converter/commentsRemoved.kt b/plugins/kapt3/kapt3-compiler/testData/converter/commentsRemoved.kt new file mode 100644 index 00000000000..c9eef52e2a9 --- /dev/null +++ b/plugins/kapt3/kapt3-compiler/testData/converter/commentsRemoved.kt @@ -0,0 +1,67 @@ +// !KEEP_KDOC_COMMENTS_IN_STUBS +/** Test. */ +class Test { + /** method(). */ + fun method() {} + + /** method(int). */ + fun method(a: Int) {} + + /** method(String). */ + fun method(a: String) {} + + /** prop. */ + const val prop: String = "" + + /** prop2. */ + @Anno + val prop2: String = "" + + /** prop3. */ + var prop3: String + /** get. */ get() = "" + /** set. */ set(v) {} +} + +/** + * Test2 + * Multiline + * documentation. + */ +class Test2(val a: String) + +class Test3 /** constructor. */ protected constructor(val a: String) + +/** Obj. */ +object Obj + +@Target(AnnotationTarget.PROPERTY) +annotation class Anno + +/* simple comment. */ +class Test4 { + // method simple comment + fun method() {} +} + +enum class EnumError { + One { + override fun doIt() = "" + + class OneOne { + /** Documentation for 'test'. */ + fun test() {} + } + }, + Two { + /** Documentation for 'doIt'. */ + override fun doIt() = "" + }; + + abstract fun doIt(): String +} + +/** + * `/* Failure */` + */ +interface TestComponent \ No newline at end of file diff --git a/plugins/kapt3/kapt3-compiler/testData/converter/commentsRemoved.txt b/plugins/kapt3/kapt3-compiler/testData/converter/commentsRemoved.txt new file mode 100644 index 00000000000..9f2a6e685a5 --- /dev/null +++ b/plugins/kapt3/kapt3-compiler/testData/converter/commentsRemoved.txt @@ -0,0 +1,153 @@ +import java.lang.System; + +@kotlin.Metadata() +@java.lang.annotation.Target(value = {}) +@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) +@kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.PROPERTY}) +public abstract @interface Anno { +} + +//////////////////// + + +import java.lang.System; + +@kotlin.Metadata() +public enum EnumError { + /*public static final*/ One /* = new EnumError() */, + /*public static final*/ Two /* = new EnumError() */; + + EnumError() { + } + + @org.jetbrains.annotations.NotNull() + public abstract java.lang.String doIt(); +} + +//////////////////// + + +import java.lang.System; + +@kotlin.Metadata() +public final class Obj { + @org.jetbrains.annotations.NotNull() + public static final Obj INSTANCE = null; + + private Obj() { + super(); + } +} + +//////////////////// + + +import java.lang.System; + +@kotlin.Metadata() +public final class Test { + @org.jetbrains.annotations.NotNull() + public final java.lang.String prop = ""; + @org.jetbrains.annotations.NotNull() + private final java.lang.String prop2 = ""; + + public Test() { + super(); + } + + public final void method() { + } + + public final void method(int a) { + } + + public final void method(@org.jetbrains.annotations.NotNull() + java.lang.String a) { + } + + @org.jetbrains.annotations.NotNull() + public final java.lang.String getProp2() { + return null; + } + + @Anno() + @java.lang.Deprecated() + public static void getProp2$annotations() { + } + + @org.jetbrains.annotations.NotNull() + public final java.lang.String getProp3() { + return null; + } + + public final void setProp3(@org.jetbrains.annotations.NotNull() + java.lang.String v) { + } +} + +//////////////////// + + +import java.lang.System; + +@kotlin.Metadata() +public final class Test2 { + @org.jetbrains.annotations.NotNull() + private final java.lang.String a = null; + + public Test2(@org.jetbrains.annotations.NotNull() + java.lang.String a) { + super(); + } + + @org.jetbrains.annotations.NotNull() + public final java.lang.String getA() { + return null; + } +} + +//////////////////// + + +import java.lang.System; + +@kotlin.Metadata() +public final class Test3 { + @org.jetbrains.annotations.NotNull() + private final java.lang.String a = null; + + protected Test3(@org.jetbrains.annotations.NotNull() + java.lang.String a) { + super(); + } + + @org.jetbrains.annotations.NotNull() + public final java.lang.String getA() { + return null; + } +} + +//////////////////// + + +import java.lang.System; + +@kotlin.Metadata() +public final class Test4 { + + public Test4() { + super(); + } + + public final void method() { + } +} + +//////////////////// + + +import java.lang.System; + +@kotlin.Metadata() +public abstract interface TestComponent { +}