Annotations supported

This commit is contained in:
Andrey Breslav
2013-10-15 20:41:49 +04:00
parent 93dc130e79
commit bed01b601b
6 changed files with 186 additions and 7 deletions
@@ -21,6 +21,9 @@ import org.jetbrains.jet.lang.resolve.java.lazy.types.LazyJavaTypeResolver
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor
import org.jetbrains.jet.lang.resolve.java.structure.JavaTypeParameter
import org.jetbrains.jet.lang.resolve.java.JavaClassFinder
import org.jetbrains.jet.lang.resolve.java.structure.JavaAnnotation
import org.jetbrains.jet.lang.resolve.java.lazy.descriptors.LazyJavaAnnotationDescriptor
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor
open class LazyJavaResolverContext(
val storageManager: StorageManager,
@@ -48,4 +51,7 @@ class LazyJavaResolverContextWithTypes(
fun LazyJavaResolverContextWithTypes.child(
containingDeclaration: DeclarationDescriptor,
typeParameters: Set<JavaTypeParameter>
): LazyJavaResolverContextWithTypes = this.withTypes(LazyJavaTypeParameterResolver(this, containingDeclaration, typeParameters))
): LazyJavaResolverContextWithTypes = this.withTypes(LazyJavaTypeParameterResolver(this, containingDeclaration, typeParameters))
fun LazyJavaResolverContextWithTypes.resolveAnnotations(javaAnnotations: Collection<JavaAnnotation>): List<AnnotationDescriptor>
= javaAnnotations.map {jAnnotation -> LazyJavaAnnotationDescriptor(this, jAnnotation)}
@@ -0,0 +1,150 @@
package org.jetbrains.jet.lang.resolve.java.lazy.descriptors
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.jet.lang.types.JetType
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant
import org.jetbrains.jet.lang.resolve.java.lazy.LazyJavaResolverContextWithTypes
import org.jetbrains.jet.lang.resolve.java.structure.*
import org.jetbrains.jet.lang.types.ErrorUtils
import org.jetbrains.jet.lang.resolve.constants.*
import org.jetbrains.jet.lang.resolve.name.Name
import org.jetbrains.jet.lang.resolve.name.FqName
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns
import org.jetbrains.jet.lang.descriptors.ClassDescriptor
import org.jetbrains.jet.lang.descriptors.VariableDescriptor
import org.jetbrains.jet.lang.resolve.java.resolver.JavaAnnotationArgumentResolver
import org.jetbrains.jet.lang.resolve.java.resolver.JavaAnnotationResolver.*
import org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames
import org.jetbrains.jet.lang.resolve.java.resolver.DescriptorResolverUtils
import org.jetbrains.jet.lang.resolve.DescriptorUtils
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor
import org.jetbrains.jet.lang.resolve.java.resolver.TypeUsage
import org.jetbrains.jet.lang.types.TypeProjectionImpl
import org.jetbrains.jet.lang.types.JetTypeImpl
import org.jetbrains.jet.lang.types.TypeConstructor
import org.jetbrains.jet.lang.types.TypeProjection
import org.jetbrains.jet.lang.resolve.scopes.JetScope
import org.jetbrains.jet.lang.resolve.java.lazy.types.LazyType
import org.jetbrains.jet.utils.valuesToMap
import org.jetbrains.jet.utils.keysToMap
import org.jetbrains.jet.utils.keysToMapExceptNulls
import org.jetbrains.jet.lang.resolve.java.resolver.JavaAnnotationResolver
import org.jetbrains.jet.renderer.DescriptorRenderer
class LazyJavaAnnotationDescriptor(
private val c: LazyJavaResolverContextWithTypes,
val javaAnnotation : JavaAnnotation
) : AnnotationDescriptor {
private val _type = c.storageManager.createLazyValue {() : JetType ->
val fqName = javaAnnotation.getFqName()
if (fqName == null) return@createLazyValue ErrorUtils.createErrorType("No fqName: $javaAnnotation")
val annotationClass = c.javaClassResolver.resolveClassByFqName(fqName)
annotationClass?.getDefaultType() ?: ErrorUtils.createErrorType(fqName.asString())
}
override fun getType(): JetType = _type()
private val _nameToArgument = c.storageManager.createLazyValue {
javaAnnotation.getArguments().valuesToMap { a -> a.getName() }
}
private val _valueArguments = c.storageManager.createMemoizedFunctionWithNullableValues<ValueParameterDescriptor, CompileTimeConstant<out Any?>> {
valueParameter ->
val nameToArg = _nameToArgument()
var javaAnnotationArgument = nameToArg[valueParameter.getName()]
if (javaAnnotationArgument == null && valueParameter.getName() == JavaAnnotationResolver.DEFAULT_ANNOTATION_MEMBER_NAME) {
javaAnnotationArgument = nameToArg[null]
}
resolveAnnotationArgument(javaAnnotationArgument)
}
override fun getValueArgument(valueParameterDescriptor: ValueParameterDescriptor) = _valueArguments(valueParameterDescriptor)
private val _allValueArguments = c.storageManager.createLazyValue {
val constructors = getAnnotationClass().getConstructors()
if (constructors.isEmpty()) mapOf<ValueParameterDescriptor, CompileTimeConstant<out Any?>>()
constructors.first().getValueParameters().keysToMapExceptNulls {
vp -> getValueArgument(vp)
}
}
override fun getAllValueArguments() = _allValueArguments()
private fun getAnnotationClass() = getType().getConstructor().getDeclarationDescriptor() as ClassDescriptor
private fun resolveAnnotationArgument(argument: JavaAnnotationArgument?): CompileTimeConstant<*>? {
return when (argument) {
is JavaLiteralAnnotationArgument -> JavaAnnotationArgumentResolver.resolveCompileTimeConstantValue(argument.getValue(), null)
is JavaReferenceAnnotationArgument -> resolveFromReference(argument.resolve())
is JavaArrayAnnotationArgument -> resolveFromArray(argument.getName() ?: DEFAULT_ANNOTATION_MEMBER_NAME, argument.getElements())
is JavaAnnotationAsAnnotationArgument -> resolveFromAnnotation(argument.getAnnotation())
is JavaClassObjectAnnotationArgument -> resolveFromJavaClassObjectType(argument.getReferencedType())
else -> null
}
}
private fun resolveFromAnnotation(javaAnnotation: JavaAnnotation): CompileTimeConstant<*>? {
val fqName = javaAnnotation.getFqName()
if (fqName == null) return null
if (JavaAnnotationResolver.isSpecialAnnotation(fqName)) {
return null
}
return AnnotationValue(LazyJavaAnnotationDescriptor(c, javaAnnotation))
}
private fun resolveFromArray(argumentName: Name, elements: List<JavaAnnotationArgument>): CompileTimeConstant<*>? {
if (getType().isError()) return null
val valueParameter = DescriptorResolverUtils.getAnnotationParameterByName(argumentName, getAnnotationClass())
if (valueParameter == null) return null
val values = elements.map {
argument -> resolveAnnotationArgument(argument) ?: NullValue.NULL
}
return ArrayValue(values, valueParameter.getType())
}
private fun resolveFromReference(element: JavaElement?): CompileTimeConstant<*>? {
if (element !is JavaField) return null
if (!element.isEnumEntry()) return null
val fqName = element.getContainingClass().getFqName()
if (fqName == null) return null
val enumClass = c.javaClassResolver.resolveClassByFqName(fqName)
if (enumClass == null) return null
val classifier = enumClass.getUnsubstitutedInnerClassesScope().getClassifier(element.getName())
if (classifier !is ClassDescriptor) return null
return EnumValue(classifier)
}
private fun resolveFromJavaClassObjectType(javaType: JavaType): CompileTimeConstant<*>? {
val `type` = c.typeResolver.transformJavaType(javaType, TypeUsage.MEMBER_SIGNATURE_INVARIANT)
val jlClass = c.javaClassResolver.resolveClassByFqName(JavaAnnotationArgumentResolver.JL_CLASS_FQ_NAME)
if (jlClass == null) return null
val arguments = listOf(TypeProjectionImpl(`type`))
val javaClassObjectType = object : LazyType(c.storageManager) {
override fun computeTypeConstructor() = jlClass.getTypeConstructor()
override fun computeArguments() = arguments
override fun computeMemberScope() = jlClass.getMemberScope(arguments)
}
return JavaClassValue(javaClassObjectType)
}
override fun toString(): String {
return DescriptorRenderer.TEXT.renderAnnotation(this)
}
}
@@ -18,6 +18,7 @@ import org.jetbrains.jet.lang.resolve.java.lazy.LazyJavaResolverContextWithTypes
import org.jetbrains.jet.lang.resolve.DescriptorFactory
import org.jetbrains.jet.lang.resolve.java.lazy.child
import org.jetbrains.jet.lang.resolve.java.resolver.TypeUsage
import org.jetbrains.jet.lang.resolve.java.lazy.resolveAnnotations
class LazyJavaClassDescriptor(
private val c: LazyJavaResolverContextWithTypes,
@@ -63,8 +64,8 @@ class LazyJavaClassDescriptor(
override fun getClassObjectDescriptor(): ClassDescriptor? = null
// TODO
override fun getAnnotations(): List<AnnotationDescriptor> = Collections.emptyList()
private val _annotations = c.resolveAnnotations(jClass.getAnnotations())
override fun getAnnotations(): List<AnnotationDescriptor> = _annotations
private inner class LazyJavaClassTypeConstructor : TypeConstructor {
@@ -20,13 +20,14 @@ import org.jetbrains.jet.lang.resolve.java.structure.JavaClass
import org.jetbrains.jet.lang.descriptors.ClassDescriptor
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor
import org.jetbrains.jet.lang.resolve.java.structure.JavaTypeParameter
import org.jetbrains.jet.utils.toMap
import org.jetbrains.jet.utils.valuesToMap
import org.jetbrains.jet.lang.resolve.java.lazy.descriptors.LazyJavaTypeParameterDescriptor
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor
import org.jetbrains.jet.lang.resolve.java.lazy.types.LazyJavaTypeResolver
import org.jetbrains.jet.lang.resolve.name.FqName
trait LazyJavaClassResolver {
fun resolveClass(javaClass: JavaClass): ClassDescriptor?
fun resolveClassByFqName(fqName: FqName): ClassDescriptor?
}
trait TypeParameterResolver {
@@ -44,7 +45,7 @@ class TypeParameterResolverImpl(
private val parent: TypeParameterResolver = TypeParameterResolver.EMPTY
) : TypeParameterResolver {
private val parameters = _typeParameters.toMap { p -> p.javaTypeParameter }
private val parameters = _typeParameters.valuesToMap { p -> p.javaTypeParameter }
override fun resolveTypeParameter(javaTypeParameter: JavaTypeParameter): TypeParameterDescriptor? {
return parameters[javaTypeParameter] ?: parent.resolveTypeParameter(javaTypeParameter)