Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.jetbrains.kotlin.load.java.structure.impl.classFiles.Annotations.kt Maven / Gradle / Ivy
/*
* Copyright 2010-2017 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.load.java.structure.impl.classFiles
import org.jetbrains.kotlin.load.java.structure.*
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.jetbrains.org.objectweb.asm.*
import java.lang.reflect.Array
internal class AnnotationsAndParameterCollectorMethodVisitor(
private val member: BinaryJavaMethodBase,
private val context: ClassifierResolutionContext,
private val signatureParser: BinaryClassSignatureParser,
private val parametersToSkipNumber: Int,
private val parametersCountInMethodDesc: Int
) : MethodVisitor(ASM_API_VERSION_FOR_CLASS_READING) {
private var parameterIndex = 0
private var visibleAnnotableParameterCount = parametersCountInMethodDesc
private var invisibleAnnotableParameterCount = parametersCountInMethodDesc
override fun visitAnnotationDefault(): AnnotationVisitor? =
BinaryJavaAnnotationVisitor(context, signatureParser) {
member.safeAs()?.annotationParameterDefaultValue = it
}
override fun visitParameter(name: String?, access: Int) {
if (name != null) {
val index = parameterIndex - parametersToSkipNumber
if (index >= 0) {
val parameter = member.valueParameters.getOrNull(index) ?: error(
"No parameter with index $parameterIndex-$parametersToSkipNumber (name=$name access=$access) " +
"in method ${member.containingClass.fqName}.${member.name}"
)
parameter.updateName(Name.identifier(name))
}
}
parameterIndex++
}
override fun visitAnnotation(desc: String, visible: Boolean) =
BinaryJavaAnnotation.addAnnotation(
member.annotations as MutableCollection,
desc, context, signatureParser
)
@Suppress("NOTHING_TO_OVERRIDE")
override fun visitAnnotableParameterCount(parameterCount: Int, visible: Boolean) {
if (visible) {
visibleAnnotableParameterCount = parameterCount
} else {
invisibleAnnotableParameterCount = parameterCount
}
}
override fun visitParameterAnnotation(parameter: Int, desc: String, visible: Boolean): AnnotationVisitor? {
val absoluteParameterIndex =
parameter + parametersCountInMethodDesc - if (visible) visibleAnnotableParameterCount else invisibleAnnotableParameterCount
val index = absoluteParameterIndex - parametersToSkipNumber
if (index < 0) return null
val annotations =
member.valueParameters[index].annotations as MutableCollection?
?: return null
return BinaryJavaAnnotation.addAnnotation(annotations, desc, context, signatureParser)
}
override fun visitTypeAnnotation(typeRef: Int, typePath: TypePath?, desc: String, visible: Boolean): AnnotationVisitor? {
// TODO: support annotations on type arguments
if (typePath != null) return null
val typeReference = TypeReference(typeRef)
return when (typeReference.sort) {
TypeReference.METHOD_RETURN -> member.safeAs()?.returnType?.let {
BinaryJavaAnnotation.addTypeAnnotation(it, desc, context, signatureParser)
}
TypeReference.METHOD_FORMAL_PARAMETER ->
BinaryJavaAnnotation.addTypeAnnotation(
member.valueParameters[typeReference.formalParameterIndex].type,
desc, context, signatureParser
)
else -> null
}
}
}
class BinaryJavaAnnotation private constructor(
desc: String,
private val context: ClassifierResolutionContext,
override val arguments: Collection
) : JavaAnnotation {
companion object {
fun createAnnotationAndVisitor(
desc: String,
context: ClassifierResolutionContext,
signatureParser: BinaryClassSignatureParser
): Pair {
val arguments = mutableListOf()
val annotation = BinaryJavaAnnotation(desc, context, arguments)
return annotation to BinaryJavaAnnotationVisitor(context, signatureParser, arguments)
}
fun addAnnotation(
annotations: MutableCollection,
desc: String,
context: ClassifierResolutionContext,
signatureParser: BinaryClassSignatureParser
): AnnotationVisitor {
val (javaAnnotation, annotationVisitor) = createAnnotationAndVisitor(desc, context, signatureParser)
annotations.add(javaAnnotation)
return annotationVisitor
}
fun addTypeAnnotation(
type: JavaType,
desc: String,
context: ClassifierResolutionContext,
signatureParser: BinaryClassSignatureParser
): AnnotationVisitor? {
type as? PlainJavaClassifierType ?: return null
val (javaAnnotation, annotationVisitor) = createAnnotationAndVisitor(desc, context, signatureParser)
type.addAnnotation(javaAnnotation)
return annotationVisitor
}
}
private val classifierResolutionResult by lazy(LazyThreadSafetyMode.NONE) {
context.resolveByInternalName(Type.getType(desc).internalName)
}
override val classId: ClassId?
get() = classifierResolutionResult.classifier.safeAs()?.classId
?: ClassId.topLevel(FqName(classifierResolutionResult.qualifiedName))
override fun resolve() = classifierResolutionResult.classifier as? JavaClass
}
class BinaryJavaAnnotationVisitor(
private val context: ClassifierResolutionContext,
private val signatureParser: BinaryClassSignatureParser,
private val sink: (JavaAnnotationArgument) -> Unit
) : AnnotationVisitor(ASM_API_VERSION_FOR_CLASS_READING) {
constructor(
context: ClassifierResolutionContext,
signatureParser: BinaryClassSignatureParser,
arguments: MutableCollection
) : this(context, signatureParser, { arguments.add(it) })
private fun addArgument(argument: JavaAnnotationArgument?) {
if (argument != null) {
sink(argument)
}
}
override fun visitAnnotation(name: String?, desc: String): AnnotationVisitor {
val (annotation, visitor) = BinaryJavaAnnotation.createAnnotationAndVisitor(desc, context, signatureParser)
sink(PlainJavaAnnotationAsAnnotationArgument(name, annotation))
return visitor
}
override fun visitEnum(name: String?, desc: String, value: String) {
val enumClassId = context.mapInternalNameToClassId(Type.getType(desc).internalName)
addArgument(PlainJavaEnumValueAnnotationArgument(name, enumClassId, value))
}
override fun visit(name: String?, value: Any?) {
addArgument(convertConstValue(name, value))
}
private fun convertConstValue(name: String?, value: Any?): JavaAnnotationArgument? {
return when (value) {
is Byte, is Boolean, is Char, is Short, is Int, is Long, is Float, is Double, is String ->
PlainJavaLiteralAnnotationArgument(name, value)
is Type -> PlainJavaClassObjectAnnotationArgument(name, value, signatureParser, context)
else -> value?.takeIf { it.javaClass.isArray }?.let { array ->
val arguments = (0 until Array.getLength(array)).mapNotNull { index ->
convertConstValue(name = null, value = Array.get(array, index))
}
PlainJavaArrayAnnotationArgument(name, arguments)
}
}
}
override fun visitArray(name: String?): AnnotationVisitor {
val result = mutableListOf()
addArgument(PlainJavaArrayAnnotationArgument(name, result))
return BinaryJavaAnnotationVisitor(context, signatureParser, result)
}
}
abstract class PlainJavaAnnotationArgument(name: String?) : JavaAnnotationArgument {
override val name: Name? = name?.takeIf(Name::isValidIdentifier)?.let(Name::identifier)
}
class PlainJavaLiteralAnnotationArgument(
name: String?,
override val value: Any?
) : PlainJavaAnnotationArgument(name), JavaLiteralAnnotationArgument
class PlainJavaClassObjectAnnotationArgument(
name: String?,
private val type: Type,
private val signatureParser: BinaryClassSignatureParser,
private val context: ClassifierResolutionContext
) : PlainJavaAnnotationArgument(name), JavaClassObjectAnnotationArgument {
override fun getReferencedType() = signatureParser.mapAsmType(type, context)
}
class PlainJavaArrayAnnotationArgument(
name: String?,
private val elements: List
) : PlainJavaAnnotationArgument(name), JavaArrayAnnotationArgument {
override fun getElements(): List = elements
}
class PlainJavaAnnotationAsAnnotationArgument(
name: String?,
private val annotation: JavaAnnotation
) : PlainJavaAnnotationArgument(name), JavaAnnotationAsAnnotationArgument {
override fun getAnnotation() = annotation
}
class PlainJavaEnumValueAnnotationArgument(
name: String?,
override val enumClassId: ClassId,
entryName: String
) : PlainJavaAnnotationArgument(name), JavaEnumValueAnnotationArgument {
override val entryName = Name.identifier(entryName)
}