mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-04-11 08:31:32 +00:00
Kapt: Drop custom annotation stub factory, implement it with AnnotationParser in sun.reflect as done in Javac
This commit is contained in:
committed by
Yan Zhulanow
parent
0a684aa1d1
commit
82dcbf36e5
@@ -8,7 +8,6 @@
|
||||
<orderEntry type="jdk" jdkName="1.8" jdkType="JavaSDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="intellij-core" level="project" />
|
||||
<orderEntry type="library" name="asm" level="project" />
|
||||
<orderEntry type="module" module-name="light-classes" />
|
||||
<orderEntry type="module" module-name="frontend" />
|
||||
<orderEntry type="module" module-name="annotation-processing" />
|
||||
|
||||
@@ -19,7 +19,7 @@ package org.jetbrains.kotlin.java.model
|
||||
import com.intellij.psi.PsiAnnotationOwner
|
||||
import com.intellij.psi.PsiClass
|
||||
import org.jetbrains.kotlin.java.model.elements.JeAnnotationMirror
|
||||
import org.jetbrains.kotlin.java.model.internal.createAnnotation
|
||||
import org.jetbrains.kotlin.java.model.internal.KotlinAnnotationProxyMaker
|
||||
import javax.lang.model.element.AnnotationMirror
|
||||
import javax.lang.model.element.Element
|
||||
import java.lang.reflect.Array as RArray
|
||||
@@ -30,14 +30,18 @@ interface JeAnnotationOwner : Element {
|
||||
override fun getAnnotationMirrors() = annotationOwner?.annotations?.map { JeAnnotationMirror(it) } ?: emptyList()
|
||||
|
||||
override fun <A : Annotation> getAnnotation(annotationClass: Class<A>): A? {
|
||||
if (!annotationClass.isAnnotation) {
|
||||
throw IllegalArgumentException("Not an annotation class: " + annotationClass)
|
||||
}
|
||||
|
||||
val annotationFqName = annotationClass.canonicalName
|
||||
|
||||
val annotation = annotationOwner?.annotations
|
||||
?.firstOrNull { it.qualifiedName == annotationFqName } ?: return null
|
||||
val annotationDeclaration = annotation.nameReferenceElement?.resolve() as? PsiClass ?: return null
|
||||
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return createAnnotation(annotation, annotationDeclaration, annotationClass) as? A
|
||||
return KotlinAnnotationProxyMaker(annotation, annotationDeclaration, annotationClass).generate() as? A
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.java.model.internal;
|
||||
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiType;
|
||||
import sun.reflect.annotation.EnumConstantNotPresentExceptionProxy;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public final class AnnotationUtil {
|
||||
public static final Map<PsiType, Class<?>> ARRAY_TYPES_MAP;
|
||||
|
||||
static {
|
||||
Map<PsiType, Class<?>> classes = new HashMap<PsiType, Class<?>>();
|
||||
|
||||
classes.put(PsiType.BYTE, byte.class);
|
||||
classes.put(PsiType.SHORT, short.class);
|
||||
classes.put(PsiType.INT, int.class);
|
||||
classes.put(PsiType.CHAR, char.class);
|
||||
classes.put(PsiType.BOOLEAN, boolean.class);
|
||||
classes.put(PsiType.LONG, long.class);
|
||||
classes.put(PsiType.FLOAT, float.class);
|
||||
classes.put(PsiType.DOUBLE, double.class);
|
||||
|
||||
ARRAY_TYPES_MAP = Collections.unmodifiableMap(classes);
|
||||
}
|
||||
|
||||
public static Object createEnumValue(Class<?> enumClass, String name) {
|
||||
try {
|
||||
return Enum.valueOf((Class)enumClass, name);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
//noinspection unchecked
|
||||
return new EnumConstantNotPresentExceptionProxy((Class<Enum<?>>) enumClass, name);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* 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.java.model.internal
|
||||
|
||||
import com.intellij.psi.*
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightAnnotation
|
||||
import org.jetbrains.kotlin.java.model.types.toJeType
|
||||
import sun.reflect.annotation.AnnotationParser
|
||||
import sun.reflect.annotation.ExceptionProxy
|
||||
import java.io.ObjectInputStream
|
||||
import java.lang.reflect.Array
|
||||
import java.lang.reflect.Method
|
||||
import java.util.*
|
||||
import javax.lang.model.type.MirroredTypeException
|
||||
import javax.lang.model.type.MirroredTypesException
|
||||
import javax.lang.model.type.TypeMirror
|
||||
|
||||
class KotlinAnnotationProxyMaker(val annotation: PsiAnnotation, val annotationClass: PsiClass, val annotationType: Class<out Annotation>) {
|
||||
fun generate(): Any {
|
||||
return AnnotationParser.annotationForMap(annotationType, getAllValuesForParser(getAllPsiValues()))
|
||||
}
|
||||
|
||||
private fun getAllPsiValues(): List<Triple<PsiAnnotationMethod, PsiAnnotationMemberValue, Method>> {
|
||||
val values = mutableListOf<Triple<PsiAnnotationMethod, PsiAnnotationMemberValue, Method>>()
|
||||
for (method in annotationClass.methods) {
|
||||
val jMethod = try { annotationType.getMethod(method.name) } catch (e : NoSuchMethodException) { continue }
|
||||
if (method !is PsiAnnotationMethod) continue
|
||||
if (method.returnType == null) continue
|
||||
|
||||
val value = annotation.findAttributeValue(method.name) ?: method.defaultValue ?: continue
|
||||
values += Triple(method, value, jMethod)
|
||||
}
|
||||
return values
|
||||
}
|
||||
|
||||
private fun getAllValuesForParser(values: List<Triple<PsiAnnotationMethod, PsiAnnotationMemberValue, Method>>): Map<String, Any?> {
|
||||
val parserValues = mutableMapOf<String, Any?>()
|
||||
val evaluator = JavaPsiFacade.getInstance(annotation.project).constantEvaluationHelper
|
||||
for ((method, value, jMethod) in values) {
|
||||
val jReturnType = jMethod.returnType ?: unexpectedType("no return type for ${jMethod.name}")
|
||||
parserValues.put(method.name, getConstantValue(value, method.returnType!!, jReturnType, evaluator))
|
||||
}
|
||||
return parserValues
|
||||
}
|
||||
}
|
||||
|
||||
private fun getConstantValue(
|
||||
psiValue: PsiAnnotationMemberValue,
|
||||
returnType: PsiType,
|
||||
jReturnType: Class<*>,
|
||||
evaluator: PsiConstantEvaluationHelper
|
||||
): Any? {
|
||||
val manager = psiValue.manager
|
||||
|
||||
when {
|
||||
returnType == PsiType.NULL || returnType == PsiType.VOID -> unexpectedType("void")
|
||||
jReturnType == String::class.java -> return calculateConstantValue(psiValue, evaluator)
|
||||
jReturnType == Class::class.java -> {
|
||||
val type = (psiValue as PsiClassObjectAccessExpression).operand.type.toJeType(manager)
|
||||
return MirroredTypeExceptionProxy(type)
|
||||
}
|
||||
jReturnType.isArray -> {
|
||||
val jComponentType = jReturnType.componentType ?: unexpectedType("no component type for $jReturnType")
|
||||
if (returnType !is PsiArrayType) unexpectedType(returnType)
|
||||
|
||||
val arrayValues = when (psiValue) {
|
||||
is PsiArrayInitializerMemberValue -> psiValue.initializers.toList()
|
||||
else -> listOf(psiValue)
|
||||
}
|
||||
|
||||
if (jComponentType == Class::class.java) {
|
||||
val typeMirrors = arrayValues.map { (it as PsiClassObjectAccessExpression).operand.type.toJeType(manager) }
|
||||
return MirroredTypesExceptionProxy(Collections.unmodifiableList(typeMirrors))
|
||||
} else {
|
||||
val arr = Array.newInstance(jComponentType, arrayValues.size)
|
||||
arrayValues.forEachIndexed { i, componentPsiValue ->
|
||||
val componentValue = getConstantValue(componentPsiValue, returnType.componentType, jComponentType, evaluator)
|
||||
try { Array.set(arr, i, componentValue) } catch (e: IllegalArgumentException) { return null }
|
||||
}
|
||||
return arr
|
||||
}
|
||||
}
|
||||
jReturnType.isEnum -> {
|
||||
val enumConstant = (psiValue.originalElement as? PsiReference)?.resolve() as? PsiEnumConstant
|
||||
?: error("$psiValue can not be resolved to enum constant")
|
||||
return AnnotationUtil.createEnumValue(jReturnType, enumConstant.name)
|
||||
}
|
||||
else -> return castPrimitiveValue(returnType, calculateConstantValue(psiValue, evaluator))
|
||||
}
|
||||
}
|
||||
|
||||
private fun castPrimitiveValue(type: PsiType, value: Any?): Any? = when (type) {
|
||||
PsiType.BYTE -> byteValue(value)
|
||||
PsiType.SHORT -> shortValue(value)
|
||||
PsiType.INT -> intValue(value)
|
||||
PsiType.CHAR -> charValue(value)
|
||||
PsiType.BOOLEAN -> booleanValue(value)
|
||||
PsiType.LONG -> longValue(value)
|
||||
PsiType.FLOAT -> floatValue(value)
|
||||
PsiType.DOUBLE -> doubleValue(value)
|
||||
else -> unexpectedType(type)
|
||||
}
|
||||
|
||||
private fun byteValue(value: Any?): Byte = (value as? Number)?.toByte() ?: 0
|
||||
private fun intValue(value: Any?): Int = (value as? Number)?.toInt() ?: 0
|
||||
private fun shortValue(value: Any?): Short = (value as? Number)?.toShort() ?: 0
|
||||
private fun booleanValue(value: Any?): Boolean = if (value == true) true else false
|
||||
private fun charValue(value: Any?): Char = value as? Char ?: 0.toChar()
|
||||
|
||||
private fun longValue(value: Any?): Long = (value as? Number)?.toLong() ?: 0
|
||||
private fun floatValue(value: Any?): Float = (value as? Number)?.toFloat() ?: 0f
|
||||
private fun doubleValue(value: Any?): Double = (value as? Number)?.toDouble() ?: 0.0
|
||||
|
||||
private fun calculateConstantValue(value: PsiAnnotationMemberValue?, evaluator: PsiConstantEvaluationHelper) = when (value) {
|
||||
is PsiLiteral -> value.value
|
||||
is KtLightAnnotation.LightExpressionValue<*> -> value.getConstantValue()
|
||||
is PsiExpression -> evaluator.computeConstantExpression(value)
|
||||
else -> null
|
||||
}
|
||||
|
||||
private fun unexpectedType(type: String): Nothing = error("Unexpected type: $type")
|
||||
private fun unexpectedType(type: PsiType): Nothing = unexpectedType(type.presentableText)
|
||||
|
||||
private class MirroredTypeExceptionProxy(@Transient private var type: TypeMirror?) : ExceptionProxy() {
|
||||
private val typeString = type.toString()
|
||||
|
||||
@Suppress("IMPLICIT_CAST_TO_ANY")
|
||||
override fun hashCode() = (if (type != null) type else typeString)?.hashCode() ?: 0
|
||||
override fun equals(other: Any?) = type != null && other is MirroredTypeExceptionProxy && type == other.type
|
||||
override fun toString() = typeString
|
||||
|
||||
override fun generateException() = MirroredTypeException(type)
|
||||
|
||||
// Explicitly set all transient fields.
|
||||
private fun readObject(s: ObjectInputStream) {
|
||||
s.defaultReadObject()
|
||||
type = null
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val serialVersionUID: Long = 269
|
||||
}
|
||||
}
|
||||
|
||||
private class MirroredTypesExceptionProxy(@Transient private var types: List<TypeMirror>?) : ExceptionProxy() {
|
||||
private val typeStrings: String = types.toString()
|
||||
|
||||
@Suppress("IMPLICIT_CAST_TO_ANY")
|
||||
override fun hashCode() = (if (types != null) types else typeStrings)?.hashCode() ?: 0
|
||||
override fun equals(other: Any?) = types != null && other is MirroredTypesExceptionProxy && types == other.types
|
||||
override fun toString() = typeStrings
|
||||
|
||||
override fun generateException() = MirroredTypesException(types)
|
||||
|
||||
// Explicitly set all transient fields.
|
||||
private fun readObject(s: ObjectInputStream) {
|
||||
s.defaultReadObject()
|
||||
types = null
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val serialVersionUID: Long = 269
|
||||
}
|
||||
}
|
||||
@@ -1,272 +0,0 @@
|
||||
/*
|
||||
* 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.java.model.internal
|
||||
|
||||
import com.intellij.psi.*
|
||||
import org.jetbrains.kotlin.asJava.KtLightAnnotation
|
||||
import org.jetbrains.org.objectweb.asm.ClassWriter
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.*
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
import java.net.URL
|
||||
import java.net.URLClassLoader
|
||||
|
||||
internal fun createAnnotation(
|
||||
annotation: PsiAnnotation,
|
||||
annotationDeclaration: PsiClass,
|
||||
annotationClass: Class<*>
|
||||
): Annotation? {
|
||||
val qualifiedName = annotationDeclaration.qualifiedName ?: return null
|
||||
val implQualifiedName = "stub." + qualifiedName + ".Impl" + Integer.toHexString(annotation.text.hashCode())
|
||||
|
||||
val annotationInternalName = annotationDeclaration.getInternalName()
|
||||
val implInternalName = implQualifiedName.replace('.', '/')
|
||||
|
||||
val bytes = createAnnotationImplementationClass(annotation, annotationDeclaration, annotationInternalName, implInternalName)
|
||||
return loadClass(implQualifiedName, bytes, annotationClass)?.newInstance() as? Annotation
|
||||
}
|
||||
|
||||
private fun createAnnotationImplementationClass(
|
||||
annotation: PsiAnnotation,
|
||||
annotationDeclaration: PsiClass,
|
||||
annotationInternalName: String,
|
||||
implInternalName: String
|
||||
): ByteArray {
|
||||
return ClassWriter(ClassWriter.COMPUTE_FRAMES or ClassWriter.COMPUTE_MAXS).apply {
|
||||
visit(V1_6, ACC_SUPER or ACC_PUBLIC, implInternalName, null, "java/lang/Object", arrayOf(annotationInternalName))
|
||||
|
||||
with(visitMethod(ACC_PUBLIC, "<init>", "()V", null, null)) {
|
||||
visitCode()
|
||||
visitVarInsn(ALOAD, 0)
|
||||
visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false)
|
||||
visitInsn(RETURN)
|
||||
visitMaxs(-1, -1)
|
||||
visitEnd()
|
||||
}
|
||||
|
||||
with(visitMethod(ACC_PUBLIC, "annotationType", "()Ljava/lang/Class;",
|
||||
"()Ljava/lang/Class<+Ljava/lang/annotation/Annotation;>;", null)) {
|
||||
visitCode()
|
||||
visitLdcInsn(Type.getType("L$annotationInternalName;"))
|
||||
visitInsn(ARETURN)
|
||||
visitMaxs(-1, -1)
|
||||
visitEnd()
|
||||
}
|
||||
|
||||
if (annotationDeclaration.allMethods.isNotEmpty()) {
|
||||
val evaluator = JavaPsiFacade.getInstance(annotation.project).constantEvaluationHelper
|
||||
|
||||
for (method in annotationDeclaration.methods) {
|
||||
if (method !is PsiAnnotationMethod) continue
|
||||
|
||||
if (method.returnType == null) continue
|
||||
val returnType = method.returnType!!
|
||||
|
||||
val value = annotation.findAttributeValue(method.name) ?: method.defaultValue
|
||||
|
||||
when (returnType) {
|
||||
PsiType.VOID -> unexpectedType("void")
|
||||
PsiType.NULL -> unexpectedType("null")
|
||||
is PsiClassType -> {
|
||||
val resolvedClass = returnType.resolve()
|
||||
val resolvedQualifiedName = resolvedClass?.qualifiedName
|
||||
if (resolvedQualifiedName == "java.lang.String") {
|
||||
writeStringMethod(method, calculateConstantValue(value, evaluator))
|
||||
}
|
||||
else if (resolvedClass != null && resolvedClass.isEnum) {
|
||||
writeEnumMethod(method, resolvedClass, value)
|
||||
}
|
||||
else {
|
||||
unexpectedType("$resolvedQualifiedName")
|
||||
}
|
||||
}
|
||||
is PsiPrimitiveType -> writeLiteralMethod(method, calculateConstantValue(value, evaluator))
|
||||
is PsiArrayType -> writeArrayMethod(method, value, evaluator)
|
||||
else -> unexpectedType(returnType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
visitEnd()
|
||||
}.toByteArray()
|
||||
}
|
||||
|
||||
private fun ClassWriter.writeEnumMethod(method: PsiAnnotationMethod, enumClass: PsiClass, value: PsiAnnotationMemberValue?) {
|
||||
val enumInternalName = enumClass.getInternalName()
|
||||
val enumConstant = (value?.originalElement as? PsiReference)?.resolve() as? PsiEnumConstant ?: return
|
||||
|
||||
val mv = visitMethod(ACC_PUBLIC, method.name, "()L$enumInternalName;", null, null)
|
||||
|
||||
with (InstructionAdapter(mv)) {
|
||||
visitCode()
|
||||
|
||||
getstatic(enumInternalName, enumConstant.name!!, "L$enumInternalName;")
|
||||
visitInsn(ARETURN)
|
||||
|
||||
visitMaxs(-1 ,-1)
|
||||
visitEnd()
|
||||
}
|
||||
}
|
||||
|
||||
private fun ClassWriter.writeStringMethod(method: PsiAnnotationMethod, value: Any?) {
|
||||
val stringValue = (value as? String) ?: null
|
||||
|
||||
val mv = visitMethod(ACC_PUBLIC, method.name, "()Ljava/lang/String;", null, null)
|
||||
|
||||
with (InstructionAdapter(mv)) {
|
||||
visitCode()
|
||||
|
||||
if (stringValue != null) {
|
||||
visitLdcInsn(stringValue)
|
||||
} else {
|
||||
visitInsn(ACONST_NULL)
|
||||
}
|
||||
visitInsn(ARETURN)
|
||||
|
||||
visitMaxs(-1 ,-1)
|
||||
visitEnd()
|
||||
}
|
||||
}
|
||||
|
||||
private fun ClassWriter.writeArrayMethod(
|
||||
method: PsiAnnotationMethod,
|
||||
value: PsiAnnotationMemberValue?,
|
||||
evaluator: PsiConstantEvaluationHelper
|
||||
) {
|
||||
val componentType = (method.returnType as? PsiArrayType)?.componentType ?: return
|
||||
val componentAsmType = componentType.toAsmType() ?: return
|
||||
|
||||
val initializers = (value as? PsiArrayInitializerMemberValue)?.initializers ?: emptyArray()
|
||||
|
||||
val mv = visitMethod(ACC_PUBLIC, method.name, "()[" + componentAsmType.descriptor, null, null)
|
||||
|
||||
with (InstructionAdapter(mv)) {
|
||||
visitCode()
|
||||
|
||||
iconst(initializers.size)
|
||||
newarray(componentAsmType)
|
||||
|
||||
initializers.forEachIndexed { index, value ->
|
||||
val valueObject = calculateConstantValue(value, evaluator)
|
||||
|
||||
dup()
|
||||
iconst(index)
|
||||
putValue(componentAsmType, valueObject)
|
||||
astore(componentAsmType)
|
||||
}
|
||||
|
||||
visitInsn(ARETURN)
|
||||
visitMaxs(-1, -1)
|
||||
visitEnd()
|
||||
}
|
||||
}
|
||||
|
||||
private fun calculateConstantValue(value: PsiAnnotationMemberValue?, evaluator: PsiConstantEvaluationHelper) = when (value) {
|
||||
is PsiLiteral -> value.value
|
||||
is KtLightAnnotation.LightExpressionValue<*> -> value.getConstantValue()
|
||||
is PsiExpression -> evaluator.computeConstantExpression(value)
|
||||
else -> null
|
||||
}
|
||||
|
||||
private fun InstructionAdapter.putValue(type: Type, value: Any?) = when (type) {
|
||||
Type.DOUBLE_TYPE -> dconst(doubleValue(value))
|
||||
Type.FLOAT_TYPE -> fconst(floatValue(value))
|
||||
Type.LONG_TYPE -> lconst(longValue(value))
|
||||
Type.BYTE_TYPE, Type.SHORT_TYPE, Type.INT_TYPE, Type.CHAR_TYPE, Type.BOOLEAN_TYPE -> iconst(type.castValue(value))
|
||||
else -> aconst(value)
|
||||
}
|
||||
|
||||
private fun ClassWriter.writeLiteralMethod(method: PsiAnnotationMethod, value: Any?) {
|
||||
val returnType = method.returnType ?: return
|
||||
val asmType = returnType.toAsmType() ?: return
|
||||
|
||||
val mv = visitMethod(ACC_PUBLIC, method.name, "()" + asmType.descriptor, null, null)
|
||||
with (InstructionAdapter(mv)) {
|
||||
visitCode()
|
||||
|
||||
putValue(asmType, value)
|
||||
areturn(asmType)
|
||||
|
||||
visitMaxs(-1, -1)
|
||||
visitEnd()
|
||||
}
|
||||
}
|
||||
|
||||
private fun PsiType.toAsmType(): Type? = when (this) {
|
||||
PsiType.BYTE -> Type.BYTE_TYPE
|
||||
PsiType.SHORT -> Type.SHORT_TYPE
|
||||
PsiType.INT -> Type.INT_TYPE
|
||||
PsiType.CHAR -> Type.CHAR_TYPE
|
||||
PsiType.BOOLEAN -> Type.BOOLEAN_TYPE
|
||||
PsiType.LONG -> Type.LONG_TYPE
|
||||
PsiType.FLOAT -> Type.FLOAT_TYPE
|
||||
PsiType.DOUBLE -> Type.DOUBLE_TYPE
|
||||
is PsiClassType -> resolve()?.let { Type.getObjectType(it.getInternalName()) }
|
||||
else -> null
|
||||
}
|
||||
|
||||
private fun Type.castValue(value: Any?): Int = when (this) {
|
||||
Type.BYTE_TYPE -> byteValue(value)
|
||||
Type.SHORT_TYPE -> shortValue(value)
|
||||
Type.INT_TYPE -> intValue(value)
|
||||
Type.CHAR_TYPE -> charValue(value)
|
||||
Type.BOOLEAN_TYPE -> booleanValue(value)
|
||||
else -> unexpectedType(this)
|
||||
}
|
||||
|
||||
private fun PsiClass.getInternalName(): String {
|
||||
val containingClass = this.containingClass
|
||||
return if (containingClass != null) {
|
||||
containingClass.getInternalName() + "$" + this.name
|
||||
} else {
|
||||
qualifiedName?.replace('.', '/') ?: error("Invalid class name ($this)")
|
||||
}
|
||||
}
|
||||
|
||||
private fun byteValue(value: Any?): Int = (value as? Number)?.toByte()?.toInt() ?: 0
|
||||
private fun intValue(value: Any?): Int = (value as? Number)?.toInt() ?: 0
|
||||
private fun shortValue(value: Any?): Int = (value as? Number)?.toShort()?.toInt() ?: 0
|
||||
private fun booleanValue(value: Any?): Int = if (value == true) 1 else 0
|
||||
private fun charValue(value: Any?): Int = (value as? Char)?.toInt() ?: 0.toChar().toInt()
|
||||
|
||||
private fun longValue(value: Any?): Long = (value as? Number)?.toLong() ?: 0
|
||||
private fun floatValue(value: Any?): Float = (value as? Number)?.toFloat() ?: 0f
|
||||
private fun doubleValue(value: Any?): Double = (value as? Number)?.toDouble() ?: 0.0
|
||||
|
||||
private fun loadClass(fqName: String, bytes: ByteArray, annotationClass: Class<*>): Class<*>? {
|
||||
class ByteClassLoader(
|
||||
urls: Array<out URL>?,
|
||||
parent: ClassLoader?,
|
||||
val extraClasses: MutableMap<String, ByteArray>,
|
||||
predefinedClasses: List<Class<*>>
|
||||
) : URLClassLoader(urls, parent) {
|
||||
private val predefinedClasses = predefinedClasses.associateBy { it.canonicalName }
|
||||
|
||||
override fun findClass(name: String): Class<*>? {
|
||||
return extraClasses.remove(name)?.let {
|
||||
defineClass(name, it, 0, it.size)
|
||||
} ?: predefinedClasses[name] ?: super.findClass(name)
|
||||
}
|
||||
}
|
||||
|
||||
val classLoader = ByteClassLoader(emptyArray(), annotationClass.classLoader, hashMapOf(fqName to bytes), listOf())
|
||||
return Class.forName(fqName, false, classLoader)
|
||||
}
|
||||
|
||||
private fun unexpectedType(type: String): Nothing = error("Unexpected type: $type")
|
||||
private fun unexpectedType(type: PsiType): Nothing = unexpectedType(type.presentableText)
|
||||
private fun unexpectedType(type: Type): Nothing = unexpectedType(type.descriptor)
|
||||
Reference in New Issue
Block a user