Allow to trigger search for external annotations lazily

This commit is contained in:
Andrey Breslav
2013-10-17 18:41:40 +04:00
parent bed01b601b
commit 8b6047e48f
6 changed files with 105 additions and 31 deletions
@@ -0,0 +1,30 @@
/*
* Copyright 2010-2013 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.jet.lang.resolve.java.lazy
import org.jetbrains.jet.lang.resolve.java.structure.JavaAnnotation
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.jet.lang.resolve.java.lazy.descriptors.LazyJavaAnnotationDescriptor
import org.jetbrains.jet.lang.resolve.java.structure.JavaAnnotationOwner
fun LazyJavaResolverContextWithTypes.resolveAnnotations(javaAnnotations: Collection<JavaAnnotation>): List<AnnotationDescriptor>
= javaAnnotations.map {jAnnotation -> LazyJavaAnnotationDescriptor(this, jAnnotation)}
// TODO: These methods are a workaround for inability to refactor List<AnnotationDescriptor> -> Annotations at the moment
fun JavaAnnotationOwner.hasMutableAnnotation(): Boolean = false
fun JavaAnnotationOwner.hasReadOnlyAnnotation(): Boolean = false
fun JavaAnnotationOwner.hasNotNullAnnotation(): Boolean = false
@@ -24,11 +24,13 @@ import org.jetbrains.jet.lang.resolve.java.JavaClassFinder
import org.jetbrains.jet.lang.resolve.java.structure.JavaAnnotation import org.jetbrains.jet.lang.resolve.java.structure.JavaAnnotation
import org.jetbrains.jet.lang.resolve.java.lazy.descriptors.LazyJavaAnnotationDescriptor import org.jetbrains.jet.lang.resolve.java.lazy.descriptors.LazyJavaAnnotationDescriptor
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.jet.lang.resolve.java.resolver.ExternalAnnotationResolver
open class LazyJavaResolverContext( open class LazyJavaResolverContext(
val storageManager: StorageManager, val storageManager: StorageManager,
val finder: JavaClassFinder, val finder: JavaClassFinder,
val javaClassResolver: LazyJavaClassResolver val javaClassResolver: LazyJavaClassResolver,
val externalAnnotationResolver: ExternalAnnotationResolver
) )
fun LazyJavaResolverContext.withTypes( fun LazyJavaResolverContext.withTypes(
@@ -37,6 +39,7 @@ fun LazyJavaResolverContext.withTypes(
storageManager, storageManager,
finder, finder,
javaClassResolver, javaClassResolver,
externalAnnotationResolver,
LazyJavaTypeResolver(this, typeParameterResolver), LazyJavaTypeResolver(this, typeParameterResolver),
typeParameterResolver) typeParameterResolver)
@@ -44,14 +47,12 @@ class LazyJavaResolverContextWithTypes(
storageManager: StorageManager, storageManager: StorageManager,
finder: JavaClassFinder, finder: JavaClassFinder,
javaClassResolver: LazyJavaClassResolver, javaClassResolver: LazyJavaClassResolver,
externalAnnotationResolver: ExternalAnnotationResolver,
val typeResolver: LazyJavaTypeResolver, val typeResolver: LazyJavaTypeResolver,
val typeParameterResolver: TypeParameterResolver val typeParameterResolver: TypeParameterResolver
) : LazyJavaResolverContext(storageManager, finder, javaClassResolver) ) : LazyJavaResolverContext(storageManager, finder, javaClassResolver, externalAnnotationResolver)
fun LazyJavaResolverContextWithTypes.child( fun LazyJavaResolverContextWithTypes.child(
containingDeclaration: DeclarationDescriptor, containingDeclaration: DeclarationDescriptor,
typeParameters: Set<JavaTypeParameter> 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)}
@@ -29,6 +29,7 @@ import org.jetbrains.jet.lang.resolve.java.lazy.types.LazyType
import org.jetbrains.jet.utils.valuesToMap import org.jetbrains.jet.utils.valuesToMap
import org.jetbrains.jet.utils.keysToMap import org.jetbrains.jet.utils.keysToMap
import org.jetbrains.jet.utils.keysToMapExceptNulls import org.jetbrains.jet.utils.keysToMapExceptNulls
import org.jetbrains.jet.lang.resolve.java.lazy.types.toAttributes
import org.jetbrains.jet.lang.resolve.java.resolver.JavaAnnotationResolver import org.jetbrains.jet.lang.resolve.java.resolver.JavaAnnotationResolver
import org.jetbrains.jet.renderer.DescriptorRenderer import org.jetbrains.jet.renderer.DescriptorRenderer
@@ -128,7 +129,7 @@ class LazyJavaAnnotationDescriptor(
} }
private fun resolveFromJavaClassObjectType(javaType: JavaType): CompileTimeConstant<*>? { private fun resolveFromJavaClassObjectType(javaType: JavaType): CompileTimeConstant<*>? {
val `type` = c.typeResolver.transformJavaType(javaType, TypeUsage.MEMBER_SIGNATURE_INVARIANT) val `type` = c.typeResolver.transformJavaType(javaType, TypeUsage.MEMBER_SIGNATURE_INVARIANT.toAttributes())
val jlClass = c.javaClassResolver.resolveClassByFqName(JavaAnnotationArgumentResolver.JL_CLASS_FQ_NAME) val jlClass = c.javaClassResolver.resolveClassByFqName(JavaAnnotationArgumentResolver.JL_CLASS_FQ_NAME)
if (jlClass == null) return null if (jlClass == null) return null
@@ -19,6 +19,7 @@ import org.jetbrains.jet.lang.resolve.DescriptorFactory
import org.jetbrains.jet.lang.resolve.java.lazy.child 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.resolver.TypeUsage
import org.jetbrains.jet.lang.resolve.java.lazy.resolveAnnotations import org.jetbrains.jet.lang.resolve.java.lazy.resolveAnnotations
import org.jetbrains.jet.lang.resolve.java.lazy.types.toAttributes
class LazyJavaClassDescriptor( class LazyJavaClassDescriptor(
private val c: LazyJavaResolverContextWithTypes, private val c: LazyJavaResolverContextWithTypes,
@@ -82,7 +83,7 @@ class LazyJavaClassDescriptor(
private val _supertypes = c.storageManager.createLazyValue { private val _supertypes = c.storageManager.createLazyValue {
jClass.getSupertypes().map { jClass.getSupertypes().map {
supertype -> supertype ->
innerC.typeResolver.transformJavaType(supertype, TypeUsage.SUPERTYPE) innerC.typeResolver.transformJavaType(supertype, TypeUsage.SUPERTYPE.toAttributes())
} }
} }
@@ -22,9 +22,9 @@ import org.jetbrains.jet.lang.types.Variance
import org.jetbrains.jet.lang.types.JetType import org.jetbrains.jet.lang.types.JetType
import org.jetbrains.jet.lang.resolve.java.structure.JavaTypeParameter import org.jetbrains.jet.lang.resolve.java.structure.JavaTypeParameter
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns
import org.jetbrains.jet.lang.resolve.java.lazy.types.LazyJavaTypeResolver
import org.jetbrains.jet.lang.resolve.java.resolver.TypeUsage import org.jetbrains.jet.lang.resolve.java.resolver.TypeUsage
import org.jetbrains.jet.lang.resolve.java.lazy.LazyJavaResolverContextWithTypes import org.jetbrains.jet.lang.resolve.java.lazy.LazyJavaResolverContextWithTypes
import org.jetbrains.jet.lang.resolve.java.lazy.types.toAttributes
class LazyJavaTypeParameterDescriptor( class LazyJavaTypeParameterDescriptor(
private val c: LazyJavaResolverContextWithTypes, private val c: LazyJavaResolverContextWithTypes,
@@ -46,7 +46,7 @@ class LazyJavaTypeParameterDescriptor(
} }
else { else {
return bounds.map { return bounds.map {
javaType -> c.typeResolver.transformJavaType(javaType, TypeUsage.UPPER_BOUND) javaType -> c.typeResolver.transformJavaType(javaType, TypeUsage.UPPER_BOUND.toAttributes())
}.toSet() }.toSet()
} }
} }
@@ -16,7 +16,6 @@
package org.jetbrains.jet.lang.resolve.java.lazy.types package org.jetbrains.jet.lang.resolve.java.lazy.types
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.jet.lang.resolve.java.structure.JavaType import org.jetbrains.jet.lang.resolve.java.structure.JavaType
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor
import org.jetbrains.jet.lang.descriptors.ClassDescriptor import org.jetbrains.jet.lang.descriptors.ClassDescriptor
@@ -26,8 +25,6 @@ import org.jetbrains.jet.lang.resolve.java.resolver.*
import org.jetbrains.jet.lang.types.Variance.* import org.jetbrains.jet.lang.types.Variance.*
import org.jetbrains.jet.lang.types.* import org.jetbrains.jet.lang.types.*
import org.jetbrains.kotlin.util.iif import org.jetbrains.kotlin.util.iif
import org.jetbrains.jet.utils.*
import org.jetbrains.jet.storage.*
import org.jetbrains.kotlin.util.eq import org.jetbrains.kotlin.util.eq
import org.jetbrains.jet.lang.resolve.java.structure.JavaPrimitiveType import org.jetbrains.jet.lang.resolve.java.structure.JavaPrimitiveType
import org.jetbrains.jet.lang.resolve.java.structure.JavaArrayType import org.jetbrains.jet.lang.resolve.java.structure.JavaArrayType
@@ -37,11 +34,11 @@ import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns
import org.jetbrains.jet.lang.resolve.java.structure.JavaTypeParameter import org.jetbrains.jet.lang.resolve.java.structure.JavaTypeParameter
import org.jetbrains.jet.lang.resolve.java.structure.JavaClass import org.jetbrains.jet.lang.resolve.java.structure.JavaClass
import org.jetbrains.kotlin.util.sure import org.jetbrains.kotlin.util.sure
import org.jetbrains.jet.lang.resolve.java.lazy.TypeParameterResolver
import org.jetbrains.jet.lang.resolve.java.lazy.descriptors.LazyJavaTypeParameterDescriptor import org.jetbrains.jet.lang.resolve.java.lazy.descriptors.LazyJavaTypeParameterDescriptor
import org.jetbrains.jet.lang.resolve.java.lazy.TypeParameterResolverImpl
import org.jetbrains.jet.lang.resolve.java.lazy.LazyJavaResolverContext
import org.jetbrains.jet.lang.resolve.scopes.JetScope import org.jetbrains.jet.lang.resolve.scopes.JetScope
import org.jetbrains.jet.lang.resolve.java.structure.JavaAnnotationOwner
import org.jetbrains.jet.lang.resolve.java.lazy.*
import org.jetbrains.jet.storage.*
class LazyJavaTypeResolver( class LazyJavaTypeResolver(
private val c: LazyJavaResolverContext, private val c: LazyJavaResolverContext,
@@ -49,7 +46,7 @@ class LazyJavaTypeResolver(
) { ) {
private val NOT_NULL_POSITIONS = setOf(TYPE_ARGUMENT, UPPER_BOUND, SUPERTYPE_ARGUMENT, SUPERTYPE) private val NOT_NULL_POSITIONS = setOf(TYPE_ARGUMENT, UPPER_BOUND, SUPERTYPE_ARGUMENT, SUPERTYPE)
public fun transformJavaType(javaType: JavaType, howThisTypeIsUsed: TypeUsage): JetType { public fun transformJavaType(javaType: JavaType, attr: JavaTypeAttributes): JetType {
return when (javaType) { return when (javaType) {
is JavaPrimitiveType -> { is JavaPrimitiveType -> {
val canonicalText = javaType.getCanonicalText() val canonicalText = javaType.getCanonicalText()
@@ -57,33 +54,36 @@ class LazyJavaTypeResolver(
assert(jetType != null, "Primitive type is not found: " + canonicalText) assert(jetType != null, "Primitive type is not found: " + canonicalText)
return jetType!! return jetType!!
} }
is JavaClassifierType -> LazyJavaClassifierType(javaType, howThisTypeIsUsed).applyNullablility(howThisTypeIsUsed) is JavaClassifierType -> LazyJavaClassifierType(javaType, attr).applyNullablility(attr)
is JavaArrayType -> transformArrayType(javaType, howThisTypeIsUsed).applyNullablility(howThisTypeIsUsed) is JavaArrayType -> transformArrayType(javaType, attr).applyNullablility(attr)
else -> throw UnsupportedOperationException("Unsupported type: " + javaType) else -> throw UnsupportedOperationException("Unsupported type: " + javaType)
} }
} }
public fun transformArrayType(arrayType: JavaArrayType, howThisTypeIsUsed: TypeUsage, isVararg: Boolean = false): JetType { public fun transformArrayType(arrayType: JavaArrayType, attr: JavaTypeAttributes, isVararg: Boolean = false): JetType {
val javaComponentType = arrayType.getComponentType() val javaComponentType = arrayType.getComponentType()
if (javaComponentType is JavaPrimitiveType) { if (javaComponentType is JavaPrimitiveType) {
val jetType = JavaToKotlinClassMap.getInstance().mapPrimitiveKotlinClass("[" + javaComponentType.getCanonicalText()) val jetType = JavaToKotlinClassMap.getInstance().mapPrimitiveKotlinClass("[" + javaComponentType.getCanonicalText())
if (jetType != null) return jetType if (jetType != null) return jetType
} }
val projectionKind = if (howThisTypeIsUsed == MEMBER_SIGNATURE_CONTRAVARIANT && !isVararg) OUT_VARIANCE else INVARIANT val projectionKind = if (attr.howThisTypeIsUsed == MEMBER_SIGNATURE_CONTRAVARIANT && !isVararg) OUT_VARIANCE else INVARIANT
val howArgumentTypeIsUsed = isVararg.iif(MEMBER_SIGNATURE_CONTRAVARIANT, TYPE_ARGUMENT) val howArgumentTypeIsUsed = isVararg.iif(MEMBER_SIGNATURE_CONTRAVARIANT, TYPE_ARGUMENT)
val componentType = transformJavaType(javaComponentType, howArgumentTypeIsUsed) val componentType = transformJavaType(javaComponentType, howArgumentTypeIsUsed.toAttributes())
return TypeUtils.makeNullable(KotlinBuiltIns.getInstance().getArrayType(projectionKind, componentType)) return TypeUtils.makeNullable(KotlinBuiltIns.getInstance().getArrayType(projectionKind, componentType))
} }
private fun JetType.applyNullablility(howThisTypeIsUsed: TypeUsage): JetType { private fun JetType.applyNullablility(attr: JavaTypeAttributes): JetType {
return TypeUtils.makeNullableAsSpecified(this, howThisTypeIsUsed !in NOT_NULL_POSITIONS) if (attr.howThisTypeIsUsed in NOT_NULL_POSITIONS) {
return TypeUtils.makeNotNullable(this)
}
return this
} }
private fun transformToTypeProjection( private fun transformToTypeProjection(
javaType: JavaType, javaType: JavaType,
howThisTypeIsUsed: TypeUsage, attr: JavaTypeAttributes,
typeConstructorBeingApplied: () -> TypeConstructor, typeConstructorBeingApplied: () -> TypeConstructor,
typeParameterIndex: Int typeParameterIndex: Int
): TypeProjection { ): TypeProjection {
@@ -93,10 +93,10 @@ class LazyJavaTypeResolver(
if (bound == null) if (bound == null)
LazyStarProjection(c, typeConstructorBeingApplied, typeParameterIndex) LazyStarProjection(c, typeConstructorBeingApplied, typeParameterIndex)
else { else {
TypeProjectionImpl(javaType.isExtends().iif(OUT_VARIANCE, IN_VARIANCE), transformJavaType(bound, UPPER_BOUND)) TypeProjectionImpl(javaType.isExtends().iif(OUT_VARIANCE, IN_VARIANCE), transformJavaType(bound, UPPER_BOUND.toAttributes()))
} }
} }
else -> TypeProjectionImpl(INVARIANT, transformJavaType(javaType, howThisTypeIsUsed)) else -> TypeProjectionImpl(INVARIANT, transformJavaType(javaType, attr))
} }
} }
@@ -113,7 +113,7 @@ class LazyJavaTypeResolver(
private inner class LazyJavaClassifierType( private inner class LazyJavaClassifierType(
private val javaType: JavaClassifierType, private val javaType: JavaClassifierType,
private val howThisTypeIsUsed: TypeUsage private val attr: JavaTypeAttributes
) : LazyType(c.storageManager) { ) : LazyType(c.storageManager) {
@@ -126,7 +126,18 @@ class LazyJavaTypeResolver(
is JavaClass -> { is JavaClass -> {
val fqName = classifier.getFqName() val fqName = classifier.getFqName()
.sure("Class type should have a FQ name: " + classifier) .sure("Class type should have a FQ name: " + classifier)
val classData = JavaToKotlinClassMap.getInstance().mapKotlinClass(fqName, howThisTypeIsUsed)
val javaToKotlinClassMap = JavaToKotlinClassMap.getInstance()
val howThisTypeIsUsedEffectively = when {
// This case has to be checked before isMarkedReadOnly/isMarkedMutable, because those two are slow
// not mapped, we don't care about being marked mutable/read-only
javaToKotlinClassMap.mapPlatformClass(fqName).isEmpty() -> attr.howThisTypeIsUsed
// Read (possibly external) annotations
else -> attr.howThisTypeIsUsedAccordingToAnnotations
}
val classData = javaToKotlinClassMap.mapKotlinClass(fqName, howThisTypeIsUsedEffectively)
?: c.javaClassResolver.resolveClass(classifier) ?: c.javaClassResolver.resolveClass(classifier)
classData?.getTypeConstructor() classData?.getTypeConstructor()
@@ -141,11 +152,11 @@ class LazyJavaTypeResolver(
} }
override fun computeArguments(): List<TypeProjection> { override fun computeArguments(): List<TypeProjection> {
var howTheProjectionIsUsed = howThisTypeIsUsed.eq(SUPERTYPE).iif(SUPERTYPE_ARGUMENT, TYPE_ARGUMENT) var howTheProjectionIsUsed = attr.howThisTypeIsUsed.eq(SUPERTYPE).iif(SUPERTYPE_ARGUMENT, TYPE_ARGUMENT)
return javaType.getTypeArguments().withIndices().map { return javaType.getTypeArguments().withIndices().map {
p -> p ->
val (i, t) = p val (i, t) = p
transformToTypeProjection(t, howTheProjectionIsUsed, {getConstructor()}, i) transformToTypeProjection(t, howTheProjectionIsUsed.toAttributes(), {getConstructor()}, i)
}.toList() }.toList()
} }
@@ -156,5 +167,35 @@ class LazyJavaTypeResolver(
return (descriptor as ClassDescriptor).getMemberScope(getArguments()) return (descriptor as ClassDescriptor).getMemberScope(getArguments())
} }
private val _nullable = c.storageManager.createLazyValue { !attr.isMarkedNotNull }
override fun isNullable(): Boolean = _nullable()
} }
}
trait JavaTypeAttributes {
val howThisTypeIsUsed: TypeUsage
val howThisTypeIsUsedAccordingToAnnotations: TypeUsage
val isMarkedNotNull: Boolean
}
class LazyJavaTypeAttributes(
c: LazyJavaResolverContext,
val annotationOwner: JavaAnnotationOwner,
override val howThisTypeIsUsed: TypeUsage,
computeHowThisTypeIsUsedAccrodingToAnnotations: () -> TypeUsage
): JavaTypeAttributes {
override val howThisTypeIsUsedAccordingToAnnotations: TypeUsage by c.storageManager.createLazyValue(
computeHowThisTypeIsUsedAccrodingToAnnotations
)
override val isMarkedNotNull: Boolean by c.storageManager.createLazyValue { annotationOwner.hasNotNullAnnotation() }
}
fun TypeUsage.toAttributes() = object : JavaTypeAttributes {
override val howThisTypeIsUsed: TypeUsage = this@toAttributes
override val howThisTypeIsUsedAccordingToAnnotations: TypeUsage
get() = howThisTypeIsUsed
override val isMarkedNotNull: Boolean = false
} }