Java declaration annotations are treated as type annotations

This is needed, for example, to approximate flexible types correctly when rendering them in the code
This commit is contained in:
Andrey Breslav
2014-09-17 14:25:00 +04:00
parent bd21e487fc
commit 91b0b83ec3
33 changed files with 119 additions and 64 deletions
@@ -98,17 +98,23 @@ public final class JvmAnnotationNames {
public static final FqName OLD_KOTLIN_TRAIT_IMPL = new FqName("jet.KotlinTraitImpl");
private static final Set<JvmClassName> SPECIAL_ANNOTATIONS = new HashSet<JvmClassName>();
private static final Set<JvmClassName> NULLABILITY_ANNOTATIONS = new HashSet<JvmClassName>();
static {
for (FqName fqName : Arrays.asList(KOTLIN_CLASS, KOTLIN_PACKAGE, KOTLIN_SIGNATURE, JETBRAINS_NOT_NULL_ANNOTATION,
JETBRAINS_NULLABLE_ANNOTATION)) {
for (FqName fqName : Arrays.asList(KOTLIN_CLASS, KOTLIN_PACKAGE, KOTLIN_SIGNATURE)) {
SPECIAL_ANNOTATIONS.add(JvmClassName.byFqNameWithoutInnerClasses(fqName));
}
SPECIAL_ANNOTATIONS.add(KotlinSyntheticClass.CLASS_NAME);
for (FqName fqName : Arrays.asList(JETBRAINS_NOT_NULL_ANNOTATION, JETBRAINS_NULLABLE_ANNOTATION)) {
NULLABILITY_ANNOTATIONS.add(JvmClassName.byFqNameWithoutInnerClasses(fqName));
}
}
public static boolean isSpecialAnnotation(@NotNull ClassId classId) {
public static boolean isSpecialAnnotation(@NotNull ClassId classId, boolean javaSpecificAnnotationsAreSpecial) {
JvmClassName className = JvmClassName.byClassId(classId);
return SPECIAL_ANNOTATIONS.contains(className) || className.getInternalName().startsWith("jet/runtime/typeinfo/");
return (javaSpecificAnnotationsAreSpecial && NULLABILITY_ANNOTATIONS.contains(className))
|| SPECIAL_ANNOTATIONS.contains(className)
|| className.getInternalName().startsWith("jet/runtime/typeinfo/");
}
private JvmAnnotationNames() {
@@ -24,14 +24,18 @@ import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames
import org.jetbrains.jet.lang.resolve.java.lazy.descriptors.resolveAnnotation
class LazyJavaAnnotations(c: LazyJavaResolverContextWithTypes, val annotationOwner: JavaAnnotationOwner) : Annotations {
class LazyJavaAnnotations(
c: LazyJavaResolverContextWithTypes,
val annotationOwner: JavaAnnotationOwner,
private val extraLookup: (FqName) -> JavaAnnotation? = { null }
) : Annotations {
private val annotationDescriptors = c.storageManager.createMemoizedFunctionWithNullableValues {
(annotation: JavaAnnotation) ->
c.resolveAnnotation(annotation)
}
override fun findAnnotation(fqName: FqName): AnnotationDescriptor? {
val jAnnotation = annotationOwner.findAnnotation(fqName)
val jAnnotation = annotationOwner.findAnnotation(fqName) ?: extraLookup(fqName)
if (jAnnotation == null) return null
return annotationDescriptors(jAnnotation)
@@ -45,7 +49,7 @@ class LazyJavaAnnotations(c: LazyJavaResolverContextWithTypes, val annotationOwn
}
fun LazyJavaResolverContextWithTypes.resolveAnnotations(annotationsOwner: JavaAnnotationOwner): Annotations
= LazyJavaAnnotations(this, annotationsOwner)
= LazyJavaAnnotations(this, annotationsOwner) { fqName -> externalAnnotationResolver.findExternalAnnotation(annotationsOwner, fqName) }
private fun GlobalJavaResolverContext.hasAnnotation(owner: JavaAnnotationOwner, annotationFqName: FqName): Boolean
= owner.findAnnotation(annotationFqName) != null || externalAnnotationResolver.findExternalAnnotation(owner, annotationFqName) != null
@@ -37,6 +37,7 @@ import org.jetbrains.jet.renderer.DescriptorRenderer
import org.jetbrains.jet.lang.resolve.java.mapping.JavaToKotlinClassMap
import org.jetbrains.jet.lang.resolve.resolveTopLevelClass
import org.jetbrains.jet.lang.resolve.kotlin.DeserializedResolverUtils.kotlinFqNameToJavaFqName
import org.jetbrains.jet.lang.resolve.java.PLATFORM_TYPES
private object DEPRECATED_IN_JAVA : JavaLiteralAnnotationArgument {
override val name: Name? = null
@@ -45,7 +46,7 @@ private object DEPRECATED_IN_JAVA : JavaLiteralAnnotationArgument {
fun LazyJavaResolverContextWithTypes.resolveAnnotation(annotation: JavaAnnotation): LazyJavaAnnotationDescriptor? {
val classId = annotation.getClassId()
if (classId == null || JvmAnnotationNames.isSpecialAnnotation(classId)) return null
if (classId == null || JvmAnnotationNames.isSpecialAnnotation(classId, !PLATFORM_TYPES)) return null
return LazyJavaAnnotationDescriptor(this, annotation)
}
@@ -34,8 +34,6 @@ import org.jetbrains.jet.lang.types.TypeUtils
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns
import org.jetbrains.jet.lang.resolve.java.lazy.hasNotNullAnnotation
import org.jetbrains.jet.lang.resolve.java.lazy.types.LazyJavaTypeAttributes
import org.jetbrains.jet.lang.resolve.java.lazy.hasMutableAnnotation
import org.jetbrains.jet.lang.resolve.java.lazy.hasReadOnlyAnnotation
import org.jetbrains.jet.lang.resolve.java.structure.JavaValueParameter
import java.util.ArrayList
import java.util.LinkedHashSet
@@ -46,7 +44,7 @@ import org.jetbrains.jet.lang.resolve.java.resolver.ExternalSignatureResolver
import org.jetbrains.jet.lang.resolve.java.sam.SingleAbstractMethodUtils
import org.jetbrains.jet.utils.*
import org.jetbrains.jet.lang.resolve.java.PLATFORM_TYPES
import org.jetbrains.jet.lang.types.lowerIfFlexible
import org.jetbrains.jet.lang.descriptors.annotations.Annotations
public abstract class LazyJavaMemberScope(
protected val c: LazyJavaResolverContextWithTypes,
@@ -116,8 +114,9 @@ public abstract class LazyJavaMemberScope(
fun resolveMethodToFunctionDescriptor(method: JavaMethod, record: Boolean = true): JavaMethodDescriptor {
val annotations = c.resolveAnnotations(method)
val functionDescriptorImpl = JavaMethodDescriptor.createJavaMethod(
_containingDeclaration, c.resolveAnnotations(method), method.getName(), c.sourceElementFactory.source(method)
_containingDeclaration, annotations, method.getName(), c.sourceElementFactory.source(method)
)
val c = c.child(functionDescriptorImpl, method.getTypeParameters().toSet())
@@ -126,13 +125,7 @@ public abstract class LazyJavaMemberScope(
val valueParameters = resolveValueParameters(c, functionDescriptorImpl, method.getValueParameters())
val annotationMethod = method.getContainingClass().isAnnotationType()
val returnTypeAttrs = LazyJavaTypeAttributes(c, method, TypeUsage.MEMBER_SIGNATURE_COVARIANT, allowFlexible = !annotationMethod) {
if (c.hasReadOnlyAnnotation(method) && !c.hasMutableAnnotation(method))
TypeUsage.MEMBER_SIGNATURE_CONTRAVARIANT
else
TypeUsage.MEMBER_SIGNATURE_COVARIANT
}
val returnTypeAttrs = LazyJavaTypeAttributes(c, method, TypeUsage.MEMBER_SIGNATURE_COVARIANT, annotations, allowFlexible = !annotationMethod)
val returnJavaType = method.getReturnType() ?: throw IllegalStateException("Constructor passed as method: $method")
// Annotation arguments are never null in Java
val returnType = c.typeResolver.transformJavaType(returnJavaType, returnTypeAttrs).let {
@@ -174,10 +167,8 @@ public abstract class LazyJavaMemberScope(
pair ->
val (index, javaParameter) = pair
val typeUsage = LazyJavaTypeAttributes(c, javaParameter, TypeUsage.MEMBER_SIGNATURE_CONTRAVARIANT) {
if (c.hasMutableAnnotation(javaParameter)) TypeUsage.MEMBER_SIGNATURE_COVARIANT else TypeUsage.MEMBER_SIGNATURE_CONTRAVARIANT
}
val annotations = c.resolveAnnotations(javaParameter)
val typeUsage = LazyJavaTypeAttributes(c, javaParameter, TypeUsage.MEMBER_SIGNATURE_CONTRAVARIANT, annotations)
val (outType, varargElementType) =
if (javaParameter.isVararg()) {
val paramType = javaParameter.getType()
@@ -213,7 +204,7 @@ public abstract class LazyJavaMemberScope(
function,
null,
index,
c.resolveAnnotations(javaParameter),
annotations,
name,
outType,
false,
@@ -254,7 +245,7 @@ public abstract class LazyJavaMemberScope(
val propertyDescriptor = createPropertyDescriptor(field)
propertyDescriptor.initialize(null, null)
val propertyType = getPropertyType(field)
val propertyType = getPropertyType(field, propertyDescriptor.getAnnotations())
val effectiveSignature = c.externalSignatureResolver.resolveAlternativeFieldSignature(field, propertyType, isVar)
val signatureErrors = effectiveSignature.getErrors()
if (!signatureErrors.isEmpty()) {
@@ -285,7 +276,7 @@ public abstract class LazyJavaMemberScope(
c.sourceElementFactory.source(field))
}
private fun getPropertyType(field: JavaField): JetType {
private fun getPropertyType(field: JavaField, annotations: Annotations): JetType {
// Fields do not have their own generic parameters
val finalStatic = field.isFinal() && field.isStatic()
@@ -293,7 +284,7 @@ public abstract class LazyJavaMemberScope(
val allowFlexible = PLATFORM_TYPES && !(finalStatic && c.javaPropertyInitializerEvaluator.isNotNullCompileTimeConstant(field))
val propertyType = c.typeResolver.transformJavaType(
field.getType(),
LazyJavaTypeAttributes(c, field, TypeUsage.MEMBER_SIGNATURE_INVARIANT, allowFlexible)
LazyJavaTypeAttributes(c, field, TypeUsage.MEMBER_SIGNATURE_INVARIANT, annotations, allowFlexible)
)
if ((!allowFlexible || !PLATFORM_TYPES) && finalStatic) {
return TypeUtils.makeNotNullable(propertyType)
@@ -33,6 +33,10 @@ import java.util.HashSet
import org.jetbrains.jet.lang.types.checker.JetTypeChecker
import org.jetbrains.jet.lang.resolve.java.PLATFORM_TYPES
import org.jetbrains.jet.lang.resolve.java.lazy.types.Flexibility.*
import org.jetbrains.jet.lang.descriptors.annotations.Annotations
import org.jetbrains.jet.lang.resolve.name.FqName
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames
class LazyJavaTypeResolver(
private val c: LazyJavaResolverContext,
@@ -262,6 +266,8 @@ class LazyJavaTypeResolver(
}
}
override fun isNullable(): Boolean = _nullable()
override fun getAnnotations() = attr.annotations
}
public open class FlexibleJavaClassifierType protected (
@@ -312,6 +318,7 @@ trait JavaTypeAttributes {
get() = INFLEXIBLE
val allowFlexible: Boolean
get() = true
val annotations: Annotations
}
fun JavaTypeAttributes.isFlexible() = flexibility != INFLEXIBLE
@@ -326,23 +333,32 @@ class LazyJavaTypeAttributes(
c: LazyJavaResolverContext,
val annotationOwner: JavaAnnotationOwner,
override val howThisTypeIsUsed: TypeUsage,
override val allowFlexible: Boolean = true,
computeHowThisTypeIsUsedAccordingToAnnotations: () -> TypeUsage = {howThisTypeIsUsed}
override val annotations: Annotations,
override val allowFlexible: Boolean = true
): JavaTypeAttributes {
override val howThisTypeIsUsedAccordingToAnnotations: TypeUsage by c.storageManager.createLazyValue(
computeHowThisTypeIsUsedAccordingToAnnotations
)
override val howThisTypeIsUsedAccordingToAnnotations: TypeUsage by c.storageManager.createLazyValue {
if (annotations.isMarkedReadOnly() && !annotations.isMarkedMutable())
TypeUsage.MEMBER_SIGNATURE_CONTRAVARIANT
else
TypeUsage.MEMBER_SIGNATURE_COVARIANT
}
override val isMarkedNotNull: Boolean by c.storageManager.createLazyValue { c.hasNotNullAnnotation(annotationOwner) }
}
private fun Annotations.isMarkedReadOnly() = findAnnotation(JvmAnnotationNames.JETBRAINS_READONLY_ANNOTATION) != null
private fun Annotations.isMarkedMutable() = findAnnotation(JvmAnnotationNames.JETBRAINS_MUTABLE_ANNOTATION) != null
private fun Annotations.isMarkedNotNull() = findAnnotation(JvmAnnotationNames.JETBRAINS_NOT_NULL_ANNOTATION) != null
fun TypeUsage.toAttributes(allowFlexible: Boolean = true) = object : JavaTypeAttributes {
override val howThisTypeIsUsed: TypeUsage = this@toAttributes
override val howThisTypeIsUsedAccordingToAnnotations: TypeUsage
get() = howThisTypeIsUsed
override val isMarkedNotNull: Boolean = false
override val allowFlexible: Boolean = allowFlexible
override val annotations: Annotations = Annotations.EMPTY
}
fun JavaTypeAttributes.toFlexible(flexibility: Flexibility) =
@@ -119,7 +119,7 @@ public class AnnotationDescriptorLoader extends BaseDescriptorLoader implements
@NotNull final List<AnnotationDescriptor> result,
@NotNull final ModuleDescriptor moduleDescriptor
) {
if (JvmAnnotationNames.isSpecialAnnotation(classId)) return null;
if (JvmAnnotationNames.isSpecialAnnotation(classId, true)) return null;
final ClassDescriptor annotationClass = resolveClass(classId, moduleDescriptor);