Support foreign nullability annotations

#KT-10418 Fixed
 #KT-10594 Fixed
This commit is contained in:
Denis Zharkov
2016-01-11 22:04:31 +03:00
parent fd8a718797
commit f4613b8db1
41 changed files with 1236 additions and 8 deletions
@@ -19,11 +19,26 @@ package org.jetbrains.kotlin.load.java
import org.jetbrains.kotlin.name.FqName
val NULLABLE_ANNOTATIONS = listOf(
JvmAnnotationNames.JETBRAINS_NULLABLE_ANNOTATION
JvmAnnotationNames.JETBRAINS_NULLABLE_ANNOTATION,
FqName("android.support.annotation.Nullable"),
FqName("org.eclipse.jdt.annotation.Nullable"),
FqName("org.checkerframework.checker.nullness.qual.Nullable"),
FqName("javax.annotation.Nullable"),
FqName("javax.annotation.CheckForNull"),
FqName("edu.umd.cs.findbugs.annotations.CheckForNull"),
FqName("edu.umd.cs.findbugs.annotations.Nullable"),
FqName("edu.umd.cs.findbugs.annotations.PossiblyNull")
)
val JAVAX_NONNULL_ANNOTATION = FqName("javax.annotation.Nonnull")
val NOT_NULL_ANNOTATIONS = listOf(
JvmAnnotationNames.JETBRAINS_NOT_NULL_ANNOTATION
JvmAnnotationNames.JETBRAINS_NOT_NULL_ANNOTATION,
FqName("edu.umd.cs.findbugs.annotations.NonNull"),
FqName("android.support.annotation.NonNull"),
FqName("org.eclipse.jdt.annotation.NonNull"),
FqName("org.checkerframework.checker.nullness.qual.NonNull"),
FqName("lombok.NonNull")
)
val READ_ONLY_ANNOTATIONS = listOf(
@@ -37,5 +52,6 @@ val MUTABLE_ANNOTATIONS = listOf(
// When these annotations appear on a declaration, they are copied to the _type_ of the declaration, becoming type annotations
// See also DescriptorRendererOptions#excludedTypeAnnotationClasses
val ANNOTATIONS_COPIED_TO_TYPES: Set<FqName> = listOf(
NULLABLE_ANNOTATIONS, NOT_NULL_ANNOTATIONS, READ_ONLY_ANNOTATIONS, MUTABLE_ANNOTATIONS
NULLABLE_ANNOTATIONS, NOT_NULL_ANNOTATIONS, READ_ONLY_ANNOTATIONS, MUTABLE_ANNOTATIONS,
listOf(JAVAX_NONNULL_ANNOTATION)
).flatMap { it }.toSet()
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.load.java.typeEnhancement
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.typeEnhancement.MutabilityQualifier.MUTABLE
@@ -64,11 +65,32 @@ private fun KotlinType.extractQualifiers(): JavaTypeQualifiers {
private fun Annotations.extractQualifiers(): JavaTypeQualifiers {
fun <T: Any> List<FqName>.ifPresent(qualifier: T) = if (any { findAnnotation(it) != null}) qualifier else null
fun <T: Any> singleNotNull(x: T?, y: T?) = if (x == null || y == null) x ?: y 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 = findAnnotation(this) ?: return null
return annotationDescriptor.allValueArguments.values.singleOrNull()?.value?.let {
enumEntryDescriptor ->
if (enumEntryDescriptor !is ClassDescriptor) return@let null
if (enumEntryDescriptor.name.asString() == "ALWAYS") NOT_NULL else NULLABLE
} ?: NOT_NULL
}
return JavaTypeQualifiers(
singleNotNull(NULLABLE_ANNOTATIONS.ifPresent(NULLABLE), NOT_NULL_ANNOTATIONS.ifPresent(NOT_NULL)),
singleNotNull(READ_ONLY_ANNOTATIONS.ifPresent(READ_ONLY), MUTABLE_ANNOTATIONS.ifPresent(MUTABLE))
uniqueNotNull(
NULLABLE_ANNOTATIONS.ifPresent(NULLABLE),
NOT_NULL_ANNOTATIONS.ifPresent(NOT_NULL),
JAVAX_NONNULL_ANNOTATION.extractQualifierFromAnnotationWithWhen()
),
uniqueNotNull(READ_ONLY_ANNOTATIONS.ifPresent(READ_ONLY), MUTABLE_ANNOTATIONS.ifPresent(MUTABLE))
)
}