NoArg: Add compiler plugin
This commit is contained in:
committed by
Yan Zhulanow
parent
6abde4223b
commit
e626b121ad
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="kotlin-runtime" level="project" />
|
||||
<orderEntry type="module" module-name="frontend" />
|
||||
<orderEntry type="module" module-name="backend" />
|
||||
<orderEntry type="module" module-name="frontend.java" />
|
||||
</component>
|
||||
</module>
|
||||
+1
@@ -0,0 +1 @@
|
||||
org.jetbrains.kotlin.noarg.NoArgCommandLineProcessor
|
||||
+1
@@ -0,0 +1 @@
|
||||
org.jetbrains.kotlin.noarg.NoArgComponentRegistrar
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.noarg
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.codegen.ClassBuilder
|
||||
import org.jetbrains.kotlin.codegen.ClassBuilderFactory
|
||||
import org.jetbrains.kotlin.codegen.DelegatingClassBuilder
|
||||
import org.jetbrains.kotlin.codegen.extensions.ClassBuilderInterceptorExtension
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
||||
import org.jetbrains.kotlin.extensions.AnnotationBasedExtension
|
||||
import org.jetbrains.kotlin.psi.KtClass
|
||||
import org.jetbrains.kotlin.psi.KtModifierListOwner
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
|
||||
class CliNoArgClassBuilderInterceptorExtension(
|
||||
private val noArgAnnotationFqNames: List<String>
|
||||
) : AbstractNoArgClassBuilderInterceptorExtension() {
|
||||
override fun getAnnotationFqNames(modifierListOwner: KtModifierListOwner) = noArgAnnotationFqNames
|
||||
}
|
||||
|
||||
abstract class AbstractNoArgClassBuilderInterceptorExtension : ClassBuilderInterceptorExtension, AnnotationBasedExtension {
|
||||
override fun interceptClassBuilderFactory(
|
||||
interceptedFactory: ClassBuilderFactory,
|
||||
bindingContext: BindingContext,
|
||||
diagnostics: DiagnosticSink
|
||||
): ClassBuilderFactory = NoArgClassBuilderFactory(interceptedFactory, bindingContext)
|
||||
|
||||
private inner class NoArgClassBuilderFactory(
|
||||
private val delegateFactory: ClassBuilderFactory,
|
||||
val bindingContext: BindingContext
|
||||
) : ClassBuilderFactory {
|
||||
|
||||
override fun newClassBuilder(origin: JvmDeclarationOrigin): ClassBuilder {
|
||||
return AllOpenClassBuilder(delegateFactory.newClassBuilder(origin), bindingContext)
|
||||
}
|
||||
|
||||
override fun getClassBuilderMode() = delegateFactory.classBuilderMode
|
||||
|
||||
override fun asText(builder: ClassBuilder?): String? {
|
||||
return delegateFactory.asText((builder as AllOpenClassBuilder).delegateClassBuilder)
|
||||
}
|
||||
|
||||
override fun asBytes(builder: ClassBuilder?): ByteArray? {
|
||||
return delegateFactory.asBytes((builder as AllOpenClassBuilder).delegateClassBuilder)
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
delegateFactory.close()
|
||||
}
|
||||
}
|
||||
|
||||
private inner class AllOpenClassBuilder(
|
||||
internal val delegateClassBuilder: ClassBuilder,
|
||||
val bindingContext: BindingContext
|
||||
) : DelegatingClassBuilder() {
|
||||
override fun getDelegate() = delegateClassBuilder
|
||||
|
||||
private var superClassInternalName = ""
|
||||
private var hasSpecialAnnotation = false
|
||||
private var noArgConstructorGenerated = false
|
||||
|
||||
override fun defineClass(
|
||||
origin: PsiElement?,
|
||||
version: Int,
|
||||
access: Int,
|
||||
name: String,
|
||||
signature: String?,
|
||||
superName: String,
|
||||
interfaces: Array<out String>
|
||||
) {
|
||||
super.defineClass(origin, version, access, name, signature, superName, interfaces)
|
||||
|
||||
hasSpecialAnnotation = false
|
||||
noArgConstructorGenerated = false
|
||||
superClassInternalName = superName
|
||||
|
||||
if (origin is KtClass) {
|
||||
val descriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, origin] as? ClassDescriptor
|
||||
if (descriptor != null && descriptor.kind == ClassKind.CLASS && descriptor.hasSpecialAnnotation (origin)) {
|
||||
hasSpecialAnnotation = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun newMethod(
|
||||
origin: JvmDeclarationOrigin,
|
||||
access: Int,
|
||||
name: String,
|
||||
desc: String,
|
||||
signature: String?,
|
||||
exceptions: Array<out String>?
|
||||
): MethodVisitor {
|
||||
if (name == "<init>" && desc == "()V") {
|
||||
noArgConstructorGenerated = true
|
||||
}
|
||||
|
||||
return super.newMethod(origin, access, name, desc, signature, exceptions)
|
||||
}
|
||||
|
||||
override fun done() {
|
||||
val superClassInternalName = this.superClassInternalName
|
||||
if (hasSpecialAnnotation && !noArgConstructorGenerated && superClassInternalName.isNotEmpty()) {
|
||||
super.newMethod(JvmDeclarationOrigin.NO_ORIGIN, Opcodes.ACC_PUBLIC, "<init>", "()V", null, null).apply {
|
||||
visitCode()
|
||||
visitVarInsn(Opcodes.ALOAD, 0)
|
||||
visitMethodInsn(Opcodes.INVOKESPECIAL, superClassInternalName, "<init>", "()V", false)
|
||||
visitInsn(Opcodes.RETURN)
|
||||
visitMaxs(1, 1)
|
||||
visitEnd()
|
||||
}
|
||||
}
|
||||
|
||||
super.done()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.noarg
|
||||
|
||||
import com.intellij.mock.MockProject
|
||||
import org.jetbrains.kotlin.codegen.extensions.ClassBuilderInterceptorExtension
|
||||
import org.jetbrains.kotlin.compiler.plugin.CliOption
|
||||
import org.jetbrains.kotlin.compiler.plugin.CliOptionProcessingException
|
||||
import org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor
|
||||
import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.CompilerConfigurationKey
|
||||
|
||||
object NoArgConfigurationKeys {
|
||||
val ANNOTATION: CompilerConfigurationKey<List<String>> =
|
||||
CompilerConfigurationKey.create("annotation qualified name")
|
||||
}
|
||||
|
||||
class NoArgCommandLineProcessor : CommandLineProcessor {
|
||||
companion object {
|
||||
val PLUGIN_ID = "org.jetbrains.kotlin.noarg"
|
||||
|
||||
val ANNOTATION_OPTION = CliOption("annotation", "<fqname>", "Annotation qualified names",
|
||||
required = false, allowMultipleOccurrences = true)
|
||||
}
|
||||
|
||||
override val pluginId = "org.jetbrains.kotlin.noarg"
|
||||
override val pluginOptions = listOf(ANNOTATION_OPTION)
|
||||
|
||||
override fun processOption(option: CliOption, value: String, configuration: CompilerConfiguration) = when (option) {
|
||||
ANNOTATION_OPTION -> {
|
||||
val paths = configuration.getList(NoArgConfigurationKeys.ANNOTATION).toMutableList()
|
||||
paths.add(value)
|
||||
configuration.put(NoArgConfigurationKeys.ANNOTATION, paths)
|
||||
}
|
||||
else -> throw CliOptionProcessingException("Unknown option: ${option.name}")
|
||||
}
|
||||
}
|
||||
|
||||
class NoArgComponentRegistrar : ComponentRegistrar {
|
||||
override fun registerProjectComponents(project: MockProject, configuration: CompilerConfiguration) {
|
||||
val annotations = configuration.get(NoArgConfigurationKeys.ANNOTATION) ?: return
|
||||
if (annotations.isEmpty()) return
|
||||
|
||||
ClassBuilderInterceptorExtension.registerExtension(project, CliNoArgClassBuilderInterceptorExtension(annotations))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
@NoArg
|
||||
annotation class NoArg
|
||||
|
||||
@NoArg
|
||||
interface Intf
|
||||
|
||||
@NoArg
|
||||
enum class Colors { RED, WHITE }
|
||||
|
||||
@NoArg
|
||||
object Obj
|
||||
|
||||
class MyClass(a: Int) {
|
||||
@NoArg
|
||||
fun someFun() {}
|
||||
|
||||
@field:NoArg @get:NoArg @set:NoArg
|
||||
var abc: String = ""
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
@NoArg
|
||||
@kotlin.Metadata
|
||||
public final enum class Colors {
|
||||
private synthetic final static field $VALUES: Colors[]
|
||||
public final static field RED: Colors
|
||||
public final static field WHITE: Colors
|
||||
static method <clinit>(): void
|
||||
protected method <init>(p0: java.lang.String, p1: int): void
|
||||
public static method valueOf(p0: java.lang.String): Colors
|
||||
public static method values(): Colors[]
|
||||
}
|
||||
|
||||
@NoArg
|
||||
@kotlin.Metadata
|
||||
public interface Intf
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class MyClass {
|
||||
private @NoArg @org.jetbrains.annotations.NotNull field abc: java.lang.String
|
||||
public method <init>(p0: int): void
|
||||
public final @NoArg @org.jetbrains.annotations.NotNull method getAbc(): java.lang.String
|
||||
public final @NoArg method setAbc(@org.jetbrains.annotations.NotNull p0: java.lang.String): void
|
||||
public final @NoArg method someFun(): void
|
||||
}
|
||||
|
||||
@NoArg
|
||||
@java.lang.annotation.Retention
|
||||
@kotlin.Metadata
|
||||
public annotation class NoArg
|
||||
|
||||
@NoArg
|
||||
@kotlin.Metadata
|
||||
public final class Obj {
|
||||
public final static field INSTANCE: Obj
|
||||
static method <clinit>(): void
|
||||
private method <init>(): void
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
annotation class NoArg
|
||||
|
||||
@NoArg
|
||||
annotation class MetaAnno
|
||||
|
||||
@NoArg
|
||||
interface BaseIntf
|
||||
|
||||
@NoArg
|
||||
class Test(a: String = "", i: Int = 2)
|
||||
|
||||
class Test2 : BaseIntf {
|
||||
constructor(a: String = "", b: Long = 0L) {}
|
||||
}
|
||||
|
||||
@MetaAnno
|
||||
class Test3(a: String) {
|
||||
constructor() : this("") {}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
@NoArg
|
||||
@kotlin.Metadata
|
||||
public interface BaseIntf
|
||||
|
||||
@NoArg
|
||||
@java.lang.annotation.Retention
|
||||
@kotlin.Metadata
|
||||
public annotation class MetaAnno
|
||||
|
||||
@java.lang.annotation.Retention
|
||||
@kotlin.Metadata
|
||||
public annotation class NoArg
|
||||
|
||||
@NoArg
|
||||
@kotlin.Metadata
|
||||
public final class Test {
|
||||
public method <init>(): void
|
||||
public method <init>(@org.jetbrains.annotations.NotNull p0: java.lang.String, p1: int): void
|
||||
public synthetic method <init>(p0: java.lang.String, p1: int, p2: int, p3: kotlin.jvm.internal.DefaultConstructorMarker): void
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class Test2 {
|
||||
public method <init>(): void
|
||||
public method <init>(@org.jetbrains.annotations.NotNull p0: java.lang.String, p1: long): void
|
||||
public synthetic method <init>(p0: java.lang.String, p1: long, p2: int, p3: kotlin.jvm.internal.DefaultConstructorMarker): void
|
||||
}
|
||||
|
||||
@MetaAnno
|
||||
@kotlin.Metadata
|
||||
public final class Test3 {
|
||||
public method <init>(): void
|
||||
public method <init>(@org.jetbrains.annotations.NotNull p0: java.lang.String): void
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
annotation class NoArg
|
||||
|
||||
@NoArg
|
||||
annotation class MyAnno
|
||||
|
||||
@MyAnno
|
||||
interface Base
|
||||
|
||||
@MyAnno
|
||||
class Test(a: String) : Base
|
||||
@@ -0,0 +1,19 @@
|
||||
@MyAnno
|
||||
@kotlin.Metadata
|
||||
public interface Base
|
||||
|
||||
@NoArg
|
||||
@java.lang.annotation.Retention
|
||||
@kotlin.Metadata
|
||||
public annotation class MyAnno
|
||||
|
||||
@java.lang.annotation.Retention
|
||||
@kotlin.Metadata
|
||||
public annotation class NoArg
|
||||
|
||||
@MyAnno
|
||||
@kotlin.Metadata
|
||||
public final class Test {
|
||||
public method <init>(): void
|
||||
public method <init>(@org.jetbrains.annotations.NotNull p0: java.lang.String): void
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
annotation class NoArg
|
||||
|
||||
class Test(a: String)
|
||||
@@ -0,0 +1,8 @@
|
||||
@java.lang.annotation.Retention
|
||||
@kotlin.Metadata
|
||||
public annotation class NoArg
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class Test {
|
||||
public method <init>(@org.jetbrains.annotations.NotNull p0: java.lang.String): void
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
annotation class NoArg
|
||||
annotation class NoArg2
|
||||
|
||||
@NoArg @NoArg2
|
||||
class Test(a: String)
|
||||
@@ -0,0 +1,15 @@
|
||||
@java.lang.annotation.Retention
|
||||
@kotlin.Metadata
|
||||
public annotation class NoArg
|
||||
|
||||
@java.lang.annotation.Retention
|
||||
@kotlin.Metadata
|
||||
public annotation class NoArg2
|
||||
|
||||
@NoArg
|
||||
@NoArg2
|
||||
@kotlin.Metadata
|
||||
public final class Test {
|
||||
public method <init>(): void
|
||||
public method <init>(@org.jetbrains.annotations.NotNull p0: java.lang.String): void
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
annotation class NoArg
|
||||
|
||||
@NoArg
|
||||
class Test(a: String)
|
||||
@@ -0,0 +1,10 @@
|
||||
@java.lang.annotation.Retention
|
||||
@kotlin.Metadata
|
||||
public annotation class NoArg
|
||||
|
||||
@NoArg
|
||||
@kotlin.Metadata
|
||||
public final class Test {
|
||||
public method <init>(): void
|
||||
public method <init>(@org.jetbrains.annotations.NotNull p0: java.lang.String): void
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
annotation class NoArg
|
||||
|
||||
@NoArg
|
||||
interface BaseIntf
|
||||
|
||||
open class Test1(a: String) : BaseIntf
|
||||
|
||||
class Test12(b: Int) : Test1("")
|
||||
|
||||
@NoArg
|
||||
abstract class BaseClass
|
||||
|
||||
class MyClass(a: String) : BaseClass()
|
||||
@@ -0,0 +1,31 @@
|
||||
@NoArg
|
||||
@kotlin.Metadata
|
||||
public abstract class BaseClass {
|
||||
public method <init>(): void
|
||||
}
|
||||
|
||||
@NoArg
|
||||
@kotlin.Metadata
|
||||
public interface BaseIntf
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class MyClass {
|
||||
public method <init>(): void
|
||||
public method <init>(@org.jetbrains.annotations.NotNull p0: java.lang.String): void
|
||||
}
|
||||
|
||||
@java.lang.annotation.Retention
|
||||
@kotlin.Metadata
|
||||
public annotation class NoArg
|
||||
|
||||
@kotlin.Metadata
|
||||
public class Test1 {
|
||||
public method <init>(): void
|
||||
public method <init>(@org.jetbrains.annotations.NotNull p0: java.lang.String): void
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class Test12 {
|
||||
public method <init>(): void
|
||||
public method <init>(p0: int): void
|
||||
}
|
||||
Reference in New Issue
Block a user