From b99007961faca32d4f1ab7bfa6c365ee2f18dd10 Mon Sep 17 00:00:00 2001 From: Yan Zhulanow Date: Tue, 4 Jul 2017 17:18:41 +0300 Subject: [PATCH] NoArg: Do not invoke initializers by default. Require "invokeInitializers" option to be set explicitly (KT-18667, KT-18668) --- .../kotlin/gradle/SimpleKotlinGradleIT.kt | 7 +++++ .../testProject/noArgKt18668/build.gradle | 28 +++++++++++++++++ .../testProject/noArgKt18668/src/test.kt | 12 ++++++++ .../kotlin/noarg/gradle/NoArgExtension.kt | 2 ++ .../kotlin/noarg/gradle/NoArgSubplugin.kt | 5 ++++ .../src/NoArgExpressionCodegenExtension.kt | 10 ++++--- plugins/noarg/noarg-cli/src/NoArgPlugin.kt | 15 ++++++++-- .../noarg-cli/testData/box/initializers.kt | 1 + .../initializersWithoutInvokeInitializers.kt | 30 +++++++++++++++++++ .../noarg/noarg-cli/testData/box/kt18667.kt | 14 +++++++++ .../noarg/noarg-cli/testData/box/kt18668.kt | 22 ++++++++++++++ .../AbstractBlackBoxCodegenTestForNoArg.kt | 3 +- .../AbstractBytecodeListingTestForNoArg.kt | 2 +- .../BlackBoxCodegenTestForNoArgGenerated.java | 18 +++++++++++ 14 files changed, 160 insertions(+), 9 deletions(-) create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/noArgKt18668/build.gradle create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/noArgKt18668/src/test.kt create mode 100644 plugins/noarg/noarg-cli/testData/box/initializersWithoutInvokeInitializers.kt create mode 100644 plugins/noarg/noarg-cli/testData/box/kt18667.kt create mode 100644 plugins/noarg/noarg-cli/testData/box/kt18668.kt diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/SimpleKotlinGradleIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/SimpleKotlinGradleIT.kt index 134a604d437..07c724ecfbb 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/SimpleKotlinGradleIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/SimpleKotlinGradleIT.kt @@ -165,6 +165,13 @@ class SimpleKotlinGradleIT : BaseGradleIT() { } } + @Test + fun testNoArgKt18668() { + Project("noArgKt18668", GRADLE_VERSION).build("build") { + assertSuccessful() + } + } + @Test fun testSamWithReceiverSimple() { Project("samWithReceiverSimple", GRADLE_VERSION).build("build") { diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/noArgKt18668/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/noArgKt18668/build.gradle new file mode 100644 index 00000000000..04fcc006097 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/noArgKt18668/build.gradle @@ -0,0 +1,28 @@ +buildscript { + repositories { + mavenLocal() + } + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath "org.jetbrains.kotlin:kotlin-noarg:$kotlin_version" + } +} + +apply plugin: "kotlin" +apply plugin: "kotlin-noarg" + +repositories { + mavenLocal() +} + +noArg { + annotation("test.NoArg") +} + +sourceSets { + main.kotlin.srcDir 'src' +} + +dependencies { + compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/noArgKt18668/src/test.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/noArgKt18668/src/test.kt new file mode 100644 index 00000000000..d1cd8bd1a67 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/noArgKt18668/src/test.kt @@ -0,0 +1,12 @@ +package test + +annotation class NoArg + +@NoArg +class AuthenticationConfiguration(tokenExpiresIn: Long) { + var tokenExpiryDate: String + + init { + tokenExpiryDate = tokenExpiresIn.toString() + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-noarg/src/main/kotlin/org/jetbrains/kotlin/noarg/gradle/NoArgExtension.kt b/libraries/tools/kotlin-noarg/src/main/kotlin/org/jetbrains/kotlin/noarg/gradle/NoArgExtension.kt index d1fa5c127b2..f9217f39344 100644 --- a/libraries/tools/kotlin-noarg/src/main/kotlin/org/jetbrains/kotlin/noarg/gradle/NoArgExtension.kt +++ b/libraries/tools/kotlin-noarg/src/main/kotlin/org/jetbrains/kotlin/noarg/gradle/NoArgExtension.kt @@ -20,6 +20,8 @@ open class NoArgExtension { internal val myAnnotations = mutableListOf() internal val myPresets = mutableListOf() + open var invokeInitializers: Boolean = false + open fun annotation(fqName: String) { myAnnotations.add(fqName) } diff --git a/libraries/tools/kotlin-noarg/src/main/kotlin/org/jetbrains/kotlin/noarg/gradle/NoArgSubplugin.kt b/libraries/tools/kotlin-noarg/src/main/kotlin/org/jetbrains/kotlin/noarg/gradle/NoArgSubplugin.kt index af2956c6019..483f8774848 100644 --- a/libraries/tools/kotlin-noarg/src/main/kotlin/org/jetbrains/kotlin/noarg/gradle/NoArgSubplugin.kt +++ b/libraries/tools/kotlin-noarg/src/main/kotlin/org/jetbrains/kotlin/noarg/gradle/NoArgSubplugin.kt @@ -71,6 +71,7 @@ class NoArgKotlinGradleSubplugin : KotlinGradleSubplugin { private val ANNOTATION_ARG_NAME = "annotation" private val PRESET_ARG_NAME = "preset" + private val INVOKE_INITIALIZERS_ARG_NAME = "invokeInitializers" } override fun isApplicable(project: Project, task: AbstractCompile) = NoArgGradleSubplugin.isEnabled(project) @@ -96,6 +97,10 @@ class NoArgKotlinGradleSubplugin : KotlinGradleSubplugin { options += SubpluginOption(PRESET_ARG_NAME, preset) } + if (noArgExtension.invokeInitializers) { + options += SubpluginOption(INVOKE_INITIALIZERS_ARG_NAME, "true") + } + return options } diff --git a/plugins/noarg/noarg-cli/src/NoArgExpressionCodegenExtension.kt b/plugins/noarg/noarg-cli/src/NoArgExpressionCodegenExtension.kt index cb1692efaeb..2d61e61f661 100644 --- a/plugins/noarg/noarg-cli/src/NoArgExpressionCodegenExtension.kt +++ b/plugins/noarg/noarg-cli/src/NoArgExpressionCodegenExtension.kt @@ -17,7 +17,6 @@ package org.jetbrains.kotlin.noarg import org.jetbrains.kotlin.codegen.* -import org.jetbrains.kotlin.codegen.context.ConstructorContext import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations @@ -32,9 +31,8 @@ import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature import org.jetbrains.kotlin.codegen.FunctionGenerationStrategy.CodegenBased import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.org.objectweb.asm.Opcodes -import org.jetbrains.org.objectweb.asm.Type -class NoArgExpressionCodegenExtension : ExpressionCodegenExtension { +class NoArgExpressionCodegenExtension(val invokeInitializers: Boolean = false) : ExpressionCodegenExtension { override fun generateClassSyntheticParts(codegen: ImplementationBodyCodegen) = with(codegen) { if (shouldGenerateNoArgConstructor()) { generateNoArgConstructor() @@ -50,7 +48,11 @@ class NoArgExpressionCodegenExtension : ExpressionCodegenExtension { override fun doGenerateBody(codegen: ExpressionCodegen, signature: JvmMethodSignature) { codegen.v.load(0, AsmTypes.OBJECT_TYPE) codegen.v.visitMethodInsn(Opcodes.INVOKESPECIAL, superClassInternalName, "", "()V", false) - generateInitializers(codegen) + + if (invokeInitializers) { + generateInitializers(codegen) + } + codegen.v.visitInsn(Opcodes.RETURN) } }) diff --git a/plugins/noarg/noarg-cli/src/NoArgPlugin.kt b/plugins/noarg/noarg-cli/src/NoArgPlugin.kt index dac7b14f21a..65ed107995d 100644 --- a/plugins/noarg/noarg-cli/src/NoArgPlugin.kt +++ b/plugins/noarg/noarg-cli/src/NoArgPlugin.kt @@ -19,7 +19,6 @@ package org.jetbrains.kotlin.noarg import com.intellij.mock.MockProject import com.intellij.openapi.extensions.Extensions import org.jetbrains.kotlin.noarg.diagnostic.DefaultErrorMessagesNoArg -import org.jetbrains.kotlin.codegen.extensions.ClassBuilderInterceptorExtension import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension import org.jetbrains.kotlin.compiler.plugin.CliOption import org.jetbrains.kotlin.compiler.plugin.CliOptionProcessingException @@ -33,6 +32,7 @@ import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor import org.jetbrains.kotlin.noarg.NoArgCommandLineProcessor.Companion.SUPPORTED_PRESETS import org.jetbrains.kotlin.noarg.NoArgConfigurationKeys.ANNOTATION +import org.jetbrains.kotlin.noarg.NoArgConfigurationKeys.INVOKE_INITIALIZERS import org.jetbrains.kotlin.noarg.NoArgConfigurationKeys.PRESET import org.jetbrains.kotlin.noarg.diagnostic.CliNoArgDeclarationChecker import org.jetbrains.kotlin.resolve.TargetPlatform @@ -43,6 +43,9 @@ object NoArgConfigurationKeys { CompilerConfigurationKey.create("annotation qualified name") val PRESET: CompilerConfigurationKey> = CompilerConfigurationKey.create("annotation preset") + + val INVOKE_INITIALIZERS: CompilerConfigurationKey = CompilerConfigurationKey.create( + "invoke instance initializers in a no-arg constructor") } class NoArgCommandLineProcessor : CommandLineProcessor { @@ -55,15 +58,20 @@ class NoArgCommandLineProcessor : CommandLineProcessor { val PRESET_OPTION = CliOption("preset", "", "Preset name (${SUPPORTED_PRESETS.keys.joinToString()})", required = false, allowMultipleOccurrences = true) + val INVOKE_INITIALIZERS_OPTION = CliOption("invokeInitializers", "true/false", + "Invoke instance initializers in a no-arg constructor", + required = false, allowMultipleOccurrences = false) + val PLUGIN_ID = "org.jetbrains.kotlin.noarg" } override val pluginId = PLUGIN_ID - override val pluginOptions = listOf(ANNOTATION_OPTION, PRESET_OPTION) + override val pluginOptions = listOf(ANNOTATION_OPTION, PRESET_OPTION, INVOKE_INITIALIZERS_OPTION) override fun processOption(option: CliOption, value: String, configuration: CompilerConfiguration) = when (option) { ANNOTATION_OPTION -> configuration.appendList(ANNOTATION, value) PRESET_OPTION -> configuration.appendList(PRESET, value) + INVOKE_INITIALIZERS_OPTION -> configuration.put(INVOKE_INITIALIZERS, value == "true") else -> throw CliOptionProcessingException("Unknown option: ${option.name}") } } @@ -79,7 +87,8 @@ class NoArgComponentRegistrar : ComponentRegistrar { Extensions.getRootArea().getExtensionPoint(DefaultErrorMessages.Extension.EP_NAME).registerExtension(DefaultErrorMessagesNoArg()) StorageComponentContainerContributor.registerExtension(project, CliNoArgComponentContainerContributor(annotations)) - ExpressionCodegenExtension.registerExtension(project, NoArgExpressionCodegenExtension()) + val invokeInitializers = configuration[INVOKE_INITIALIZERS] ?: false + ExpressionCodegenExtension.registerExtension(project, NoArgExpressionCodegenExtension(invokeInitializers)) } } diff --git a/plugins/noarg/noarg-cli/testData/box/initializers.kt b/plugins/noarg/noarg-cli/testData/box/initializers.kt index 7eb055c704c..1702d879368 100644 --- a/plugins/noarg/noarg-cli/testData/box/initializers.kt +++ b/plugins/noarg/noarg-cli/testData/box/initializers.kt @@ -1,4 +1,5 @@ // WITH_RUNTIME +// INVOKE_INITIALIZERS annotation class NoArg diff --git a/plugins/noarg/noarg-cli/testData/box/initializersWithoutInvokeInitializers.kt b/plugins/noarg/noarg-cli/testData/box/initializersWithoutInvokeInitializers.kt new file mode 100644 index 00000000000..6048cbbfa9a --- /dev/null +++ b/plugins/noarg/noarg-cli/testData/box/initializersWithoutInvokeInitializers.kt @@ -0,0 +1,30 @@ +// WITH_RUNTIME + +annotation class NoArg + +class Simple(val a: String) + +@NoArg +class Test(val a: String) { + val x = 5 + val y: Simple? = Simple("Hello, world!") +} + +fun box(): String { + try { + val test = Test::class.java.newInstance() + + if (test.x != 0) { + return "Bad 5" + } + + if (test.y != null) { + return "Bad Hello, world!" + } + + return "OK" + } catch (e: Throwable) { + e.printStackTrace() + return "Fail" + } +} \ No newline at end of file diff --git a/plugins/noarg/noarg-cli/testData/box/kt18667.kt b/plugins/noarg/noarg-cli/testData/box/kt18667.kt new file mode 100644 index 00000000000..bf192ce0683 --- /dev/null +++ b/plugins/noarg/noarg-cli/testData/box/kt18667.kt @@ -0,0 +1,14 @@ +// WITH_RUNTIME + +annotation class NoArg + +@NoArg +class Foo(val s1: String) { + val s2: String = "" + val l: List = listOf() +} + +fun box(): String { + val instance = Foo::class.java.newInstance() + return "OK" +} \ No newline at end of file diff --git a/plugins/noarg/noarg-cli/testData/box/kt18668.kt b/plugins/noarg/noarg-cli/testData/box/kt18668.kt new file mode 100644 index 00000000000..30be29a8e5f --- /dev/null +++ b/plugins/noarg/noarg-cli/testData/box/kt18668.kt @@ -0,0 +1,22 @@ +// WITH_RUNTIME + +annotation class NoArg + +@NoArg +class AuthenticationConfiguration(tokenExpiresIn: Long) { + var tokenExpiryDate: String? + + init { + tokenExpiryDate = tokenExpiresIn.toString() + } +} + +fun box(): String { + val instance = AuthenticationConfiguration::class.java.newInstance() + + if (instance.tokenExpiryDate != null) { + return "Initializer invoked" + } + + return "OK" +} \ No newline at end of file diff --git a/plugins/plugins-tests/tests/org/jetbrains/kotlin/noarg/AbstractBlackBoxCodegenTestForNoArg.kt b/plugins/plugins-tests/tests/org/jetbrains/kotlin/noarg/AbstractBlackBoxCodegenTestForNoArg.kt index 348f7a261c0..2af1cbe09d5 100644 --- a/plugins/plugins-tests/tests/org/jetbrains/kotlin/noarg/AbstractBlackBoxCodegenTestForNoArg.kt +++ b/plugins/plugins-tests/tests/org/jetbrains/kotlin/noarg/AbstractBlackBoxCodegenTestForNoArg.kt @@ -30,7 +30,8 @@ abstract class AbstractBlackBoxCodegenTestForNoArg : AbstractBlackBoxCodegenTest val project = myEnvironment.project registerExtension(project, CliNoArgComponentContainerContributor(NOARG_ANNOTATIONS)) - ExpressionCodegenExtension.registerExtension(project, NoArgExpressionCodegenExtension()) + val invokeInitializers = files.any { "// INVOKE_INITIALIZERS" in it.content } + ExpressionCodegenExtension.registerExtension(project, NoArgExpressionCodegenExtension(invokeInitializers)) super.loadMultiFiles(files) } diff --git a/plugins/plugins-tests/tests/org/jetbrains/kotlin/noarg/AbstractBytecodeListingTestForNoArg.kt b/plugins/plugins-tests/tests/org/jetbrains/kotlin/noarg/AbstractBytecodeListingTestForNoArg.kt index 835a8f7d97f..b5f3be9ed22 100644 --- a/plugins/plugins-tests/tests/org/jetbrains/kotlin/noarg/AbstractBytecodeListingTestForNoArg.kt +++ b/plugins/plugins-tests/tests/org/jetbrains/kotlin/noarg/AbstractBytecodeListingTestForNoArg.kt @@ -34,6 +34,6 @@ abstract class AbstractBytecodeListingTestForNoArg : AbstractBytecodeListingTest val project = environment.project StorageComponentContainerContributor.registerExtension(project, CliNoArgComponentContainerContributor(NOARG_ANNOTATIONS)) - ExpressionCodegenExtension.registerExtension(project, NoArgExpressionCodegenExtension()) + ExpressionCodegenExtension.registerExtension(project, NoArgExpressionCodegenExtension(false)) } } \ No newline at end of file diff --git a/plugins/plugins-tests/tests/org/jetbrains/kotlin/noarg/BlackBoxCodegenTestForNoArgGenerated.java b/plugins/plugins-tests/tests/org/jetbrains/kotlin/noarg/BlackBoxCodegenTestForNoArgGenerated.java index 5a92f45d5cf..250ec9f258c 100644 --- a/plugins/plugins-tests/tests/org/jetbrains/kotlin/noarg/BlackBoxCodegenTestForNoArgGenerated.java +++ b/plugins/plugins-tests/tests/org/jetbrains/kotlin/noarg/BlackBoxCodegenTestForNoArgGenerated.java @@ -42,6 +42,24 @@ public class BlackBoxCodegenTestForNoArgGenerated extends AbstractBlackBoxCodege doTest(fileName); } + @TestMetadata("initializersWithoutInvokeInitializers.kt") + public void testInitializersWithoutInvokeInitializers() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("plugins/noarg/noarg-cli/testData/box/initializersWithoutInvokeInitializers.kt"); + doTest(fileName); + } + + @TestMetadata("kt18667.kt") + public void testKt18667() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("plugins/noarg/noarg-cli/testData/box/kt18667.kt"); + doTest(fileName); + } + + @TestMetadata("kt18668.kt") + public void testKt18668() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("plugins/noarg/noarg-cli/testData/box/kt18668.kt"); + doTest(fileName); + } + @TestMetadata("simple.kt") public void testSimple() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("plugins/noarg/noarg-cli/testData/box/simple.kt");