Annotation mapper is introduced to map java annotation targets to kotlin targets + a set of new / fixed tests
This commit is contained in:
@@ -38,6 +38,7 @@ public final class JvmAnnotationNames {
|
||||
public static final String KIND_FIELD_NAME = "kind";
|
||||
public static final String DATA_FIELD_NAME = "data";
|
||||
public static final Name DEFAULT_ANNOTATION_MEMBER_NAME = Name.identifier("value");
|
||||
public static final Name TARGET_ANNOTATION_MEMBER_NAME = Name.identifier("allowedTargets");
|
||||
|
||||
public static final FqName JETBRAINS_NOT_NULL_ANNOTATION = new FqName("org.jetbrains.annotations.NotNull");
|
||||
public static final FqName JETBRAINS_NULLABLE_ANNOTATION = new FqName("org.jetbrains.annotations.Nullable");
|
||||
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.components
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||
import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext
|
||||
import org.jetbrains.kotlin.load.java.lazy.descriptors.resolveAnnotation
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaAnnotation
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaAnnotationArgument
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaArrayAnnotationArgument
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaEnumValueAnnotationArgument
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
|
||||
import org.jetbrains.kotlin.resolve.constants.ArrayValue
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue
|
||||
import org.jetbrains.kotlin.resolve.constants.EnumValue
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationTarget
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import java.lang.annotation.Target
|
||||
import java.util.*
|
||||
import kotlin.annotation
|
||||
|
||||
public object JavaAnnotationMapper {
|
||||
|
||||
private val targetClassId = ClassId.topLevel(FqName(javaClass<Target>().getCanonicalName()))
|
||||
|
||||
public fun mapJavaAnnotation(annotation: JavaAnnotation, c: LazyJavaResolverContext): AnnotationDescriptor? =
|
||||
when (annotation.classId) {
|
||||
targetClassId -> JavaTargetAnnotationDescriptor(annotation, c, c.module.builtIns)
|
||||
else -> null
|
||||
}
|
||||
|
||||
public val kotlinToJavaNameMap: Map<FqName, FqName> =
|
||||
mapOf(KotlinBuiltIns.FQ_NAMES.target to FqName(javaClass<Target>().getCanonicalName()))
|
||||
}
|
||||
|
||||
class JavaTargetAnnotationDescriptor(
|
||||
annotation: JavaAnnotation,
|
||||
c: LazyJavaResolverContext,
|
||||
val builtIns: KotlinBuiltIns
|
||||
): AnnotationDescriptor {
|
||||
|
||||
private val valueArguments = c.storageManager.createLazyValue {
|
||||
val firstArgument = annotation.arguments.firstOrNull()
|
||||
val targetArgument = when (firstArgument) {
|
||||
is JavaArrayAnnotationArgument -> JavaAnnotationTargetMapper.mapJavaTargetArguments(firstArgument.getElements(), builtIns)
|
||||
is JavaEnumValueAnnotationArgument -> JavaAnnotationTargetMapper.mapJavaTargetArguments(listOf(firstArgument), builtIns)
|
||||
else -> return@createLazyValue emptyMap<ValueParameterDescriptor, ConstantValue<*>>()
|
||||
}
|
||||
val parameterDescriptor = builtIns.targetAnnotation.constructors.firstOrNull()?.valueParameters?.firstOrNull()
|
||||
parameterDescriptor?.let { mapOf(it to targetArgument) } ?: emptyMap()
|
||||
}
|
||||
|
||||
override fun getAllValueArguments() = valueArguments()
|
||||
|
||||
override fun getType() = builtIns.targetAnnotation.defaultType
|
||||
}
|
||||
|
||||
public object JavaAnnotationTargetMapper {
|
||||
private val targetNameLists = mapOf("PACKAGE" to EnumSet.of(AnnotationTarget.PACKAGE),
|
||||
"TYPE" to EnumSet.of(AnnotationTarget.CLASSIFIER),
|
||||
"ANNOTATION_TYPE" to EnumSet.of(AnnotationTarget.ANNOTATION_CLASS),
|
||||
"TYPE_PARAMETER" to EnumSet.of(AnnotationTarget.TYPE_PARAMETER),
|
||||
"FIELD" to EnumSet.of(AnnotationTarget.FIELD),
|
||||
"LOCAL_VARIABLE" to EnumSet.of(AnnotationTarget.LOCAL_VARIABLE),
|
||||
"PARAMETER" to EnumSet.of(AnnotationTarget.VALUE_PARAMETER),
|
||||
"CONSTRUCTOR" to EnumSet.of(AnnotationTarget.CONSTRUCTOR),
|
||||
"METHOD" to EnumSet.of(AnnotationTarget.FUNCTION,
|
||||
AnnotationTarget.PROPERTY_GETTER,
|
||||
AnnotationTarget.PROPERTY_SETTER),
|
||||
"TYPE_USE" to EnumSet.of(AnnotationTarget.TYPE)
|
||||
)
|
||||
|
||||
public fun mapJavaTargetArgumentByName(argumentName: String?): Set<AnnotationTarget> = targetNameLists[argumentName] ?: emptySet()
|
||||
|
||||
public fun mapJavaTargetArguments(arguments: List<JavaAnnotationArgument>, builtIns: KotlinBuiltIns): ConstantValue<*>? {
|
||||
// Map arguments: java.lang.annotation.Target -> kotlin.annotation.target
|
||||
val kotlinTargets = arguments.filterIsInstance<JavaEnumValueAnnotationArgument>()
|
||||
.flatMap { mapJavaTargetArgumentByName(it.resolve()?.name?.asString()) }
|
||||
.map { builtIns.getAnnotationTargetEnumEntry(Name.identifier(it.name())) }
|
||||
.filterNotNull()
|
||||
.map { EnumValue(it) }
|
||||
val parameterDescriptor = DescriptorResolverUtils.getAnnotationParameterByName(JvmAnnotationNames.TARGET_ANNOTATION_MEMBER_NAME,
|
||||
builtIns.targetAnnotation)
|
||||
return ArrayValue(kotlinTargets, parameterDescriptor?.type ?: ErrorUtils.createErrorType("Error: AnnotationTarget[]"), builtIns)
|
||||
}
|
||||
}
|
||||
+4
-2
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.kotlin.load.java.lazy
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.load.java.components.JavaAnnotationMapper
|
||||
import org.jetbrains.kotlin.load.java.lazy.descriptors.resolveAnnotation
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaAnnotation
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaAnnotationOwner
|
||||
@@ -29,17 +30,18 @@ class LazyJavaAnnotations(
|
||||
) : Annotations {
|
||||
private val annotationDescriptors = c.storageManager.createMemoizedFunctionWithNullableValues {
|
||||
annotation: JavaAnnotation ->
|
||||
c.resolveAnnotation(annotation)
|
||||
JavaAnnotationMapper.mapJavaAnnotation(annotation, c) ?: c.resolveAnnotation(annotation)
|
||||
}
|
||||
|
||||
override fun findAnnotation(fqName: FqName) =
|
||||
annotationOwner.findAnnotation(fqName)?.let(annotationDescriptors)
|
||||
?: JavaAnnotationMapper.kotlinToJavaNameMap[fqName]?.let { annotationOwner.findAnnotation(it)?.let(annotationDescriptors) }
|
||||
|
||||
override fun findExternalAnnotation(fqName: FqName) =
|
||||
c.externalAnnotationResolver.findExternalAnnotation(annotationOwner, fqName)?.let(annotationDescriptors)
|
||||
|
||||
override fun iterator() =
|
||||
annotationOwner.getAnnotations().asSequence().map(annotationDescriptors).filterNotNull().iterator()
|
||||
annotationOwner.annotations.asSequence().map(annotationDescriptors).filterNotNull().iterator()
|
||||
|
||||
override fun isEmpty() = !iterator().hasNext()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user