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.lazy.descriptors.LazyJavaAnnotationDescriptor
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.jet.lang.resolve.java.resolver.ExternalAnnotationResolver
open class LazyJavaResolverContext(
val storageManager: StorageManager,
val finder: JavaClassFinder,
val javaClassResolver: LazyJavaClassResolver
val javaClassResolver: LazyJavaClassResolver,
val externalAnnotationResolver: ExternalAnnotationResolver
)
fun LazyJavaResolverContext.withTypes(
@@ -37,6 +39,7 @@ fun LazyJavaResolverContext.withTypes(
storageManager,
finder,
javaClassResolver,
externalAnnotationResolver,
LazyJavaTypeResolver(this, typeParameterResolver),
typeParameterResolver)
@@ -44,14 +47,12 @@ class LazyJavaResolverContextWithTypes(
storageManager: StorageManager,
finder: JavaClassFinder,
javaClassResolver: LazyJavaClassResolver,
externalAnnotationResolver: ExternalAnnotationResolver,
val typeResolver: LazyJavaTypeResolver,
val typeParameterResolver: TypeParameterResolver
) : LazyJavaResolverContext(storageManager, finder, javaClassResolver)
) : LazyJavaResolverContext(storageManager, finder, javaClassResolver, externalAnnotationResolver)
fun LazyJavaResolverContextWithTypes.child(
containingDeclaration: DeclarationDescriptor,
typeParameters: Set<JavaTypeParameter>
): LazyJavaResolverContextWithTypes = this.withTypes(LazyJavaTypeParameterResolver(this, containingDeclaration, typeParameters))
fun LazyJavaResolverContextWithTypes.resolveAnnotations(javaAnnotations: Collection<JavaAnnotation>): List<AnnotationDescriptor>
= javaAnnotations.map {jAnnotation -> LazyJavaAnnotationDescriptor(this, jAnnotation)}
): LazyJavaResolverContextWithTypes = this.withTypes(LazyJavaTypeParameterResolver(this, containingDeclaration, typeParameters))
@@ -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.keysToMap
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.renderer.DescriptorRenderer
@@ -128,7 +129,7 @@ class LazyJavaAnnotationDescriptor(
}
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)
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.resolver.TypeUsage
import org.jetbrains.jet.lang.resolve.java.lazy.resolveAnnotations
import org.jetbrains.jet.lang.resolve.java.lazy.types.toAttributes
class LazyJavaClassDescriptor(
private val c: LazyJavaResolverContextWithTypes,
@@ -82,7 +83,7 @@ class LazyJavaClassDescriptor(
private val _supertypes = c.storageManager.createLazyValue {
jClass.getSupertypes().map {
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.resolve.java.structure.JavaTypeParameter
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.lazy.LazyJavaResolverContextWithTypes
import org.jetbrains.jet.lang.resolve.java.lazy.types.toAttributes
class LazyJavaTypeParameterDescriptor(
private val c: LazyJavaResolverContextWithTypes,
@@ -46,7 +46,7 @@ class LazyJavaTypeParameterDescriptor(
}
else {
return bounds.map {
javaType -> c.typeResolver.transformJavaType(javaType, TypeUsage.UPPER_BOUND)
javaType -> c.typeResolver.transformJavaType(javaType, TypeUsage.UPPER_BOUND.toAttributes())
}.toSet()
}
}
@@ -16,7 +16,6 @@
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.descriptors.TypeParameterDescriptor
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.*
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.jet.lang.resolve.java.structure.JavaPrimitiveType
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.JavaClass
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.TypeParameterResolverImpl
import org.jetbrains.jet.lang.resolve.java.lazy.LazyJavaResolverContext
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(
private val c: LazyJavaResolverContext,
@@ -49,7 +46,7 @@ class LazyJavaTypeResolver(
) {
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) {
is JavaPrimitiveType -> {
val canonicalText = javaType.getCanonicalText()
@@ -57,33 +54,36 @@ class LazyJavaTypeResolver(
assert(jetType != null, "Primitive type is not found: " + canonicalText)
return jetType!!
}
is JavaClassifierType -> LazyJavaClassifierType(javaType, howThisTypeIsUsed).applyNullablility(howThisTypeIsUsed)
is JavaArrayType -> transformArrayType(javaType, howThisTypeIsUsed).applyNullablility(howThisTypeIsUsed)
is JavaClassifierType -> LazyJavaClassifierType(javaType, attr).applyNullablility(attr)
is JavaArrayType -> transformArrayType(javaType, attr).applyNullablility(attr)
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()
if (javaComponentType is JavaPrimitiveType) {
val jetType = JavaToKotlinClassMap.getInstance().mapPrimitiveKotlinClass("[" + javaComponentType.getCanonicalText())
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 componentType = transformJavaType(javaComponentType, howArgumentTypeIsUsed)
val componentType = transformJavaType(javaComponentType, howArgumentTypeIsUsed.toAttributes())
return TypeUtils.makeNullable(KotlinBuiltIns.getInstance().getArrayType(projectionKind, componentType))
}
private fun JetType.applyNullablility(howThisTypeIsUsed: TypeUsage): JetType {
return TypeUtils.makeNullableAsSpecified(this, howThisTypeIsUsed !in NOT_NULL_POSITIONS)
private fun JetType.applyNullablility(attr: JavaTypeAttributes): JetType {
if (attr.howThisTypeIsUsed in NOT_NULL_POSITIONS) {
return TypeUtils.makeNotNullable(this)
}
return this
}
private fun transformToTypeProjection(
javaType: JavaType,
howThisTypeIsUsed: TypeUsage,
attr: JavaTypeAttributes,
typeConstructorBeingApplied: () -> TypeConstructor,
typeParameterIndex: Int
): TypeProjection {
@@ -93,10 +93,10 @@ class LazyJavaTypeResolver(
if (bound == null)
LazyStarProjection(c, typeConstructorBeingApplied, typeParameterIndex)
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 val javaType: JavaClassifierType,
private val howThisTypeIsUsed: TypeUsage
private val attr: JavaTypeAttributes
) : LazyType(c.storageManager) {
@@ -126,7 +126,18 @@ class LazyJavaTypeResolver(
is JavaClass -> {
val fqName = classifier.getFqName()
.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)
classData?.getTypeConstructor()
@@ -141,11 +152,11 @@ class LazyJavaTypeResolver(
}
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 {
p ->
val (i, t) = p
transformToTypeProjection(t, howTheProjectionIsUsed, {getConstructor()}, i)
transformToTypeProjection(t, howTheProjectionIsUsed.toAttributes(), {getConstructor()}, i)
}.toList()
}
@@ -156,5 +167,35 @@ class LazyJavaTypeResolver(
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
}