Support TypeQualifierNickname for nullability annotations
#KT-10942 In Progress
This commit is contained in:
+13
@@ -18,7 +18,10 @@ package org.jetbrains.kotlin.load.java
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.resolveClassByFqName
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
@@ -49,6 +52,16 @@ class AnnotationTypeQualifierResolver(storageManager: StorageManager) {
|
||||
|
||||
return resolveTypeQualifierNickname(annotationClass)
|
||||
}
|
||||
|
||||
fun isTypeQualifier(moduleDescriptor: ModuleDescriptor, classFqName: FqName): Boolean {
|
||||
val classDescriptor = moduleDescriptor.resolveClassByFqName(
|
||||
classFqName, NoLookupLocation.FROM_JAVA_LOADER
|
||||
) ?: return false
|
||||
|
||||
if (classDescriptor.isTypeQualifierAnnotation) return true
|
||||
|
||||
return resolveTypeQualifierNickname(classDescriptor) != null
|
||||
}
|
||||
}
|
||||
|
||||
private val ClassDescriptor.isAnnotatedWithTypeQualifier: Boolean
|
||||
|
||||
+14
-3
@@ -146,7 +146,9 @@ abstract class LazyJavaScope(protected val c: LazyJavaResolverContext) : MemberS
|
||||
val annotationMethod = method.containingClass.isAnnotationType
|
||||
val returnTypeAttrs = LazyJavaTypeAttributes(
|
||||
TypeUsage.COMMON, annotations,
|
||||
isForAnnotationParameter = annotationMethod
|
||||
isForAnnotationParameter = annotationMethod,
|
||||
moduleDescriptor = c.module,
|
||||
annotationTypeQualifierResolver = c.components.annotationTypeQualifierResolver
|
||||
)
|
||||
return c.typeResolver.transformJavaType(method.returnType, returnTypeAttrs)
|
||||
}
|
||||
@@ -163,7 +165,12 @@ abstract class LazyJavaScope(protected val c: LazyJavaResolverContext) : MemberS
|
||||
val (index, javaParameter) = pair
|
||||
|
||||
val annotations = c.resolveAnnotations(javaParameter)
|
||||
val typeUsage = LazyJavaTypeAttributes(TypeUsage.COMMON, annotations)
|
||||
val typeUsage =
|
||||
LazyJavaTypeAttributes(
|
||||
TypeUsage.COMMON, annotations,
|
||||
annotationTypeQualifierResolver = c.components.annotationTypeQualifierResolver,
|
||||
moduleDescriptor = c.module
|
||||
)
|
||||
val (outType, varargElementType) =
|
||||
if (javaParameter.isVararg) {
|
||||
val paramType = javaParameter.type as? JavaArrayType
|
||||
@@ -281,7 +288,11 @@ abstract class LazyJavaScope(protected val c: LazyJavaResolverContext) : MemberS
|
||||
val isNotNullable = !(field.isFinalStatic && field.hasConstantNotNullInitializer)
|
||||
val propertyType = c.typeResolver.transformJavaType(
|
||||
field.type,
|
||||
LazyJavaTypeAttributes(TypeUsage.COMMON, annotations)
|
||||
LazyJavaTypeAttributes(
|
||||
TypeUsage.COMMON, annotations,
|
||||
annotationTypeQualifierResolver = c.components.annotationTypeQualifierResolver,
|
||||
moduleDescriptor = c.module
|
||||
)
|
||||
)
|
||||
if (!isNotNullable) {
|
||||
return TypeUtils.makeNotNullable(propertyType)
|
||||
|
||||
+8
-2
@@ -17,11 +17,13 @@
|
||||
package org.jetbrains.kotlin.load.java.lazy.types
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.annotations.CompositeAnnotations
|
||||
import org.jetbrains.kotlin.descriptors.annotations.FilteredAnnotations
|
||||
import org.jetbrains.kotlin.load.java.ANNOTATIONS_COPIED_TO_TYPES
|
||||
import org.jetbrains.kotlin.load.java.AnnotationTypeQualifierResolver
|
||||
import org.jetbrains.kotlin.load.java.components.TypeUsage
|
||||
import org.jetbrains.kotlin.load.java.components.TypeUsage.COMMON
|
||||
import org.jetbrains.kotlin.load.java.components.TypeUsage.SUPERTYPE
|
||||
@@ -309,9 +311,13 @@ enum class JavaTypeFlexibility {
|
||||
class LazyJavaTypeAttributes(
|
||||
override val howThisTypeIsUsed: TypeUsage,
|
||||
annotations: Annotations,
|
||||
override val isForAnnotationParameter: Boolean = false
|
||||
override val isForAnnotationParameter: Boolean = false,
|
||||
private val annotationTypeQualifierResolver: AnnotationTypeQualifierResolver,
|
||||
private val moduleDescriptor: ModuleDescriptor
|
||||
): JavaTypeAttributes {
|
||||
override val typeAnnotations = FilteredAnnotations(annotations) { it in ANNOTATIONS_COPIED_TO_TYPES }
|
||||
override val typeAnnotations = FilteredAnnotations(annotations) {
|
||||
it in ANNOTATIONS_COPIED_TO_TYPES || annotationTypeQualifierResolver.isTypeQualifier(moduleDescriptor, it)
|
||||
}
|
||||
}
|
||||
|
||||
fun TypeUsage.toAttributes(
|
||||
|
||||
+28
-21
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.load.java.typeEnhancement
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.load.java.*
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor
|
||||
@@ -25,6 +26,8 @@ import org.jetbrains.kotlin.load.kotlin.SignatureBuildingComponents
|
||||
import org.jetbrains.kotlin.load.kotlin.computeJvmDescriptor
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.asFlexibleType
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||
@@ -32,7 +35,7 @@ import org.jetbrains.kotlin.types.isFlexible
|
||||
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
|
||||
import java.util.*
|
||||
|
||||
class SignatureEnhancement {
|
||||
class SignatureEnhancement(private val annotationTypeQualifierResolver: AnnotationTypeQualifierResolver) {
|
||||
fun <D : CallableMemberDescriptor> enhanceSignatures(platformSignatures: Collection<D>): Collection<D> {
|
||||
return platformSignatures.map {
|
||||
it.enhanceSignature()
|
||||
@@ -143,29 +146,10 @@ class SignatureEnhancement {
|
||||
private fun KotlinType.extractQualifiersFromAnnotations(): JavaTypeQualifiers {
|
||||
fun <T: Any> List<FqName>.ifPresent(qualifier: T) = if (any { annotations.findAnnotation(it) != null}) qualifier else null
|
||||
|
||||
// These two overloads are just for sake of optimization as in most cases last parameter in second overload is null
|
||||
fun <T: Any> uniqueNotNull(x: T?, y: T?) = if (x == null || y == null || x == y) x ?: y else null
|
||||
fun <T: Any> uniqueNotNull(a: T?, b: T?, c: T?) =
|
||||
if (c == null)
|
||||
uniqueNotNull(a, b)
|
||||
else
|
||||
listOf(a, b, c).filterNotNull().toSet().singleOrNull()
|
||||
|
||||
// Javax/FundBugs NonNull annotation has parameter `when` that determines actual nullability
|
||||
fun FqName.extractQualifierFromAnnotationWithWhen(): NullabilityQualifier? {
|
||||
val annotationDescriptor = annotations.findAnnotation(this) ?: return null
|
||||
return annotationDescriptor.allValueArguments.values.singleOrNull()?.value?.let {
|
||||
enumEntryDescriptor ->
|
||||
if (enumEntryDescriptor !is ClassDescriptor) return@let null
|
||||
if (enumEntryDescriptor.name.asString() == "ALWAYS") NullabilityQualifier.NOT_NULL else NullabilityQualifier.NULLABLE
|
||||
} ?: NullabilityQualifier.NOT_NULL
|
||||
}
|
||||
val nullability = annotations.extractNullability()
|
||||
|
||||
val nullability = uniqueNotNull(
|
||||
NULLABLE_ANNOTATIONS.ifPresent(NullabilityQualifier.NULLABLE),
|
||||
NOT_NULL_ANNOTATIONS.ifPresent(NullabilityQualifier.NOT_NULL),
|
||||
JAVAX_NONNULL_ANNOTATION.extractQualifierFromAnnotationWithWhen()
|
||||
)
|
||||
return JavaTypeQualifiers(
|
||||
nullability,
|
||||
uniqueNotNull(
|
||||
@@ -180,6 +164,29 @@ class SignatureEnhancement {
|
||||
)
|
||||
}
|
||||
|
||||
private fun Annotations.extractNullability(): NullabilityQualifier? {
|
||||
for (annotationDescriptor in this) {
|
||||
when (annotationDescriptor.annotationClass?.fqNameSafe) {
|
||||
in NULLABLE_ANNOTATIONS -> return NullabilityQualifier.NULLABLE
|
||||
in NOT_NULL_ANNOTATIONS -> return NullabilityQualifier.NOT_NULL
|
||||
}
|
||||
|
||||
val typeQualifier =
|
||||
annotationTypeQualifierResolver
|
||||
.resolveTypeQualifierAnnotation(annotationDescriptor)
|
||||
?.takeIf { it.annotationClass?.fqNameSafe == JAVAX_NONNULL_ANNOTATION }
|
||||
?: continue
|
||||
|
||||
return typeQualifier.allValueArguments.values.singleOrNull()?.value?.let {
|
||||
enumEntryDescriptor ->
|
||||
if (enumEntryDescriptor !is ClassDescriptor) return@let null
|
||||
if (enumEntryDescriptor.name.asString() == "ALWAYS") NullabilityQualifier.NOT_NULL else NullabilityQualifier.NULLABLE
|
||||
} ?: NullabilityQualifier.NOT_NULL
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
fun KotlinType.computeIndexedQualifiersForOverride(
|
||||
fromSupertypes: Collection<KotlinType>, isCovariant: Boolean
|
||||
): (Int) -> JavaTypeQualifiers {
|
||||
|
||||
Reference in New Issue
Block a user