NoArg: Do not invoke initializers by default. Require "invokeInitializers" option to be set explicitly (KT-18667, KT-18668)
This commit is contained in:
committed by
Yan Zhulanow
parent
a983137978
commit
b99007961f
+7
@@ -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") {
|
||||||
|
|||||||
+28
@@ -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"
|
||||||
|
}
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
annotation class NoArg
|
||||||
|
|
||||||
|
@NoArg
|
||||||
|
class AuthenticationConfiguration(tokenExpiresIn: Long) {
|
||||||
|
var tokenExpiryDate: String
|
||||||
|
|
||||||
|
init {
|
||||||
|
tokenExpiryDate = tokenExpiresIn.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
+5
@@ -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)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -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,4 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
// INVOKE_INITIALIZERS
|
||||||
|
|
||||||
annotation class NoArg
|
annotation class NoArg
|
||||||
|
|
||||||
|
|||||||
+30
@@ -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
@@ -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
@@ -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"
|
||||||
|
}
|
||||||
+2
-1
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+18
@@ -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");
|
||||||
|
|||||||
Reference in New Issue
Block a user