NoArg: Do not invoke initializers by default. Require "invokeInitializers" option to be set explicitly (KT-18667, KT-18668)

This commit is contained in:
Yan Zhulanow
2017-07-04 17:18:41 +03:00
committed by Yan Zhulanow
parent a983137978
commit b99007961f
14 changed files with 160 additions and 9 deletions
@@ -165,6 +165,13 @@ class SimpleKotlinGradleIT : BaseGradleIT() {
} }
} }
@Test
fun testNoArgKt18668() {
Project("noArgKt18668", GRADLE_VERSION).build("build") {
assertSuccessful()
}
}
@Test @Test
fun testSamWithReceiverSimple() { fun testSamWithReceiverSimple() {
Project("samWithReceiverSimple", GRADLE_VERSION).build("build") { Project("samWithReceiverSimple", GRADLE_VERSION).build("build") {
@@ -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"
}
@@ -0,0 +1,12 @@
package test
annotation class NoArg
@NoArg
class AuthenticationConfiguration(tokenExpiresIn: Long) {
var tokenExpiryDate: String
init {
tokenExpiryDate = tokenExpiresIn.toString()
}
}
@@ -20,6 +20,8 @@ open class NoArgExtension {
internal val myAnnotations = mutableListOf<String>() internal val myAnnotations = mutableListOf<String>()
internal val myPresets = mutableListOf<String>() internal val myPresets = mutableListOf<String>()
open var invokeInitializers: Boolean = false
open fun annotation(fqName: String) { open fun annotation(fqName: String) {
myAnnotations.add(fqName) myAnnotations.add(fqName)
} }
@@ -71,6 +71,7 @@ class NoArgKotlinGradleSubplugin : KotlinGradleSubplugin<AbstractCompile> {
private val ANNOTATION_ARG_NAME = "annotation" private val ANNOTATION_ARG_NAME = "annotation"
private val PRESET_ARG_NAME = "preset" private val PRESET_ARG_NAME = "preset"
private val INVOKE_INITIALIZERS_ARG_NAME = "invokeInitializers"
} }
override fun isApplicable(project: Project, task: AbstractCompile) = NoArgGradleSubplugin.isEnabled(project) override fun isApplicable(project: Project, task: AbstractCompile) = NoArgGradleSubplugin.isEnabled(project)
@@ -96,6 +97,10 @@ class NoArgKotlinGradleSubplugin : KotlinGradleSubplugin<AbstractCompile> {
options += SubpluginOption(PRESET_ARG_NAME, preset) options += SubpluginOption(PRESET_ARG_NAME, preset)
} }
if (noArgExtension.invokeInitializers) {
options += SubpluginOption(INVOKE_INITIALIZERS_ARG_NAME, "true")
}
return options return options
} }
@@ -17,7 +17,6 @@
package org.jetbrains.kotlin.noarg package org.jetbrains.kotlin.noarg
import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.context.ConstructorContext
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations 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.codegen.FunctionGenerationStrategy.CodegenBased
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.org.objectweb.asm.Opcodes 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) { override fun generateClassSyntheticParts(codegen: ImplementationBodyCodegen) = with(codegen) {
if (shouldGenerateNoArgConstructor()) { if (shouldGenerateNoArgConstructor()) {
generateNoArgConstructor() generateNoArgConstructor()
@@ -50,7 +48,11 @@ class NoArgExpressionCodegenExtension : ExpressionCodegenExtension {
override fun doGenerateBody(codegen: ExpressionCodegen, signature: JvmMethodSignature) { override fun doGenerateBody(codegen: ExpressionCodegen, signature: JvmMethodSignature) {
codegen.v.load(0, AsmTypes.OBJECT_TYPE) codegen.v.load(0, AsmTypes.OBJECT_TYPE)
codegen.v.visitMethodInsn(Opcodes.INVOKESPECIAL, superClassInternalName, "<init>", "()V", false) codegen.v.visitMethodInsn(Opcodes.INVOKESPECIAL, superClassInternalName, "<init>", "()V", false)
generateInitializers(codegen)
if (invokeInitializers) {
generateInitializers(codegen)
}
codegen.v.visitInsn(Opcodes.RETURN) codegen.v.visitInsn(Opcodes.RETURN)
} }
}) })
+12 -3
View File
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.noarg
import com.intellij.mock.MockProject import com.intellij.mock.MockProject
import com.intellij.openapi.extensions.Extensions import com.intellij.openapi.extensions.Extensions
import org.jetbrains.kotlin.noarg.diagnostic.DefaultErrorMessagesNoArg 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.codegen.extensions.ExpressionCodegenExtension
import org.jetbrains.kotlin.compiler.plugin.CliOption import org.jetbrains.kotlin.compiler.plugin.CliOption
import org.jetbrains.kotlin.compiler.plugin.CliOptionProcessingException 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.extensions.StorageComponentContainerContributor
import org.jetbrains.kotlin.noarg.NoArgCommandLineProcessor.Companion.SUPPORTED_PRESETS import org.jetbrains.kotlin.noarg.NoArgCommandLineProcessor.Companion.SUPPORTED_PRESETS
import org.jetbrains.kotlin.noarg.NoArgConfigurationKeys.ANNOTATION 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.NoArgConfigurationKeys.PRESET
import org.jetbrains.kotlin.noarg.diagnostic.CliNoArgDeclarationChecker import org.jetbrains.kotlin.noarg.diagnostic.CliNoArgDeclarationChecker
import org.jetbrains.kotlin.resolve.TargetPlatform import org.jetbrains.kotlin.resolve.TargetPlatform
@@ -43,6 +43,9 @@ object NoArgConfigurationKeys {
CompilerConfigurationKey.create("annotation qualified name") CompilerConfigurationKey.create("annotation qualified name")
val PRESET: CompilerConfigurationKey<List<String>> = CompilerConfigurationKey.create("annotation preset") val PRESET: CompilerConfigurationKey<List<String>> = CompilerConfigurationKey.create("annotation preset")
val INVOKE_INITIALIZERS: CompilerConfigurationKey<Boolean> = CompilerConfigurationKey.create(
"invoke instance initializers in a no-arg constructor")
} }
class NoArgCommandLineProcessor : CommandLineProcessor { class NoArgCommandLineProcessor : CommandLineProcessor {
@@ -55,15 +58,20 @@ class NoArgCommandLineProcessor : CommandLineProcessor {
val PRESET_OPTION = CliOption("preset", "<name>", "Preset name (${SUPPORTED_PRESETS.keys.joinToString()})", val PRESET_OPTION = CliOption("preset", "<name>", "Preset name (${SUPPORTED_PRESETS.keys.joinToString()})",
required = false, allowMultipleOccurrences = true) 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" val PLUGIN_ID = "org.jetbrains.kotlin.noarg"
} }
override val pluginId = PLUGIN_ID 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) { override fun processOption(option: CliOption, value: String, configuration: CompilerConfiguration) = when (option) {
ANNOTATION_OPTION -> configuration.appendList(ANNOTATION, value) ANNOTATION_OPTION -> configuration.appendList(ANNOTATION, value)
PRESET_OPTION -> configuration.appendList(PRESET, value) PRESET_OPTION -> configuration.appendList(PRESET, value)
INVOKE_INITIALIZERS_OPTION -> configuration.put(INVOKE_INITIALIZERS, value == "true")
else -> throw CliOptionProcessingException("Unknown option: ${option.name}") else -> throw CliOptionProcessingException("Unknown option: ${option.name}")
} }
} }
@@ -79,7 +87,8 @@ class NoArgComponentRegistrar : ComponentRegistrar {
Extensions.getRootArea().getExtensionPoint(DefaultErrorMessages.Extension.EP_NAME).registerExtension(DefaultErrorMessagesNoArg()) Extensions.getRootArea().getExtensionPoint(DefaultErrorMessages.Extension.EP_NAME).registerExtension(DefaultErrorMessagesNoArg())
StorageComponentContainerContributor.registerExtension(project, CliNoArgComponentContainerContributor(annotations)) StorageComponentContainerContributor.registerExtension(project, CliNoArgComponentContainerContributor(annotations))
ExpressionCodegenExtension.registerExtension(project, NoArgExpressionCodegenExtension()) val invokeInitializers = configuration[INVOKE_INITIALIZERS] ?: false
ExpressionCodegenExtension.registerExtension(project, NoArgExpressionCodegenExtension(invokeInitializers))
} }
} }
+1
View File
@@ -1,4 +1,5 @@
// WITH_RUNTIME // WITH_RUNTIME
// INVOKE_INITIALIZERS
annotation class NoArg annotation class NoArg
@@ -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"
}
}
+14
View File
@@ -0,0 +1,14 @@
// WITH_RUNTIME
annotation class NoArg
@NoArg
class Foo(val s1: String) {
val s2: String = ""
val l: List<String> = listOf()
}
fun box(): String {
val instance = Foo::class.java.newInstance()
return "OK"
}
+22
View File
@@ -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"
}
@@ -30,7 +30,8 @@ abstract class AbstractBlackBoxCodegenTestForNoArg : AbstractBlackBoxCodegenTest
val project = myEnvironment.project val project = myEnvironment.project
registerExtension(project, CliNoArgComponentContainerContributor(NOARG_ANNOTATIONS)) 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) super.loadMultiFiles(files)
} }
@@ -34,6 +34,6 @@ abstract class AbstractBytecodeListingTestForNoArg : AbstractBytecodeListingTest
val project = environment.project val project = environment.project
StorageComponentContainerContributor.registerExtension(project, CliNoArgComponentContainerContributor(NOARG_ANNOTATIONS)) StorageComponentContainerContributor.registerExtension(project, CliNoArgComponentContainerContributor(NOARG_ANNOTATIONS))
ExpressionCodegenExtension.registerExtension(project, NoArgExpressionCodegenExtension()) ExpressionCodegenExtension.registerExtension(project, NoArgExpressionCodegenExtension(false))
} }
} }
@@ -42,6 +42,24 @@ public class BlackBoxCodegenTestForNoArgGenerated extends AbstractBlackBoxCodege
doTest(fileName); 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") @TestMetadata("simple.kt")
public void testSimple() throws Exception { public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/noarg/noarg-cli/testData/box/simple.kt"); String fileName = KotlinTestUtils.navigationMetadata("plugins/noarg/noarg-cli/testData/box/simple.kt");