Fix loading JSR-305 nicknames for @CheckForNull annotation

For sake of working without jsr305.jar in the classpath `resolveTypeQualifierAnnotation`
may return javax.annotation.CheckForNull (although the latter is nickname itself)

 #KT-19985 Fixed
This commit is contained in:
Denis Zharkov
2017-08-30 17:34:28 +03:00
parent ed79891ee6
commit 4e4bf31016
5 changed files with 74 additions and 6 deletions
@@ -16,6 +16,23 @@ public @interface MyNullable {
}
// FILE: MyCheckForNull.java
import javax.annotation.*;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.annotation.meta.TypeQualifierNickname;
import javax.annotation.meta.When;
@Documented
@TypeQualifierNickname
@CheckForNull
@Retention(RetentionPolicy.RUNTIME)
public @interface MyCheckForNull {
}
// FILE: MyNonnull.java
import javax.annotation.*;
import java.lang.annotation.Documented;
@@ -50,6 +67,10 @@ public class A {
return "";
}
@MyCheckForNull
public String baz(@MyNonnull String x, @MyCheckForNull CharSequence y) {
return "";
}
}
// FILE: main.kt
@@ -59,6 +80,10 @@ fun main(a: A) {
a.foo("", null)<!UNSAFE_CALL!>.<!>length
a.foo(<!NULL_FOR_NONNULL_TYPE!>null<!>, "")<!UNSAFE_CALL!>.<!>length
a.baz("", null)?.length
a.baz("", null)<!UNSAFE_CALL!>.<!>length
a.baz(<!NULL_FOR_NONNULL_TYPE!>null<!>, "")<!UNSAFE_CALL!>.<!>length
a.bar().length
a.bar()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.length
@@ -6,12 +6,20 @@ public open class A {
public constructor A()
@MyNullable public final var field: kotlin.String?
@MyNonnull public open fun bar(): kotlin.String
@MyCheckForNull public open fun baz(/*0*/ @MyNonnull x: kotlin.String, /*1*/ @MyCheckForNull y: kotlin.CharSequence?): kotlin.String?
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
@MyNullable public open fun foo(/*0*/ @MyNonnull x: kotlin.String, /*1*/ @MyNullable y: kotlin.CharSequence?): kotlin.String?
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@kotlin.annotation.MustBeDocumented @javax.annotation.meta.TypeQualifierNickname @javax.annotation.CheckForNull @kotlin.annotation.Retention(value = AnnotationRetention.RUNTIME) public final annotation class MyCheckForNull : kotlin.Annotation {
public constructor MyCheckForNull()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@kotlin.annotation.MustBeDocumented @javax.annotation.meta.TypeQualifierNickname @javax.annotation.Nonnull(when = When.ALWAYS) @kotlin.annotation.Retention(value = AnnotationRetention.RUNTIME) public final annotation class MyNonnull : kotlin.Annotation {
public constructor MyNonnull()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
@@ -18,6 +18,23 @@ public @interface MyNullable {
}
// FILE: MyCheckForNull.java
import javax.annotation.*;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.annotation.meta.TypeQualifierNickname;
import javax.annotation.meta.When;
@Documented
@TypeQualifierNickname
@CheckForNull
@Retention(RetentionPolicy.RUNTIME)
public @interface MyCheckForNull {
}
// FILE: MyNonnull.java
import javax.annotation.*;
import java.lang.annotation.Documented;
@@ -52,6 +69,10 @@ public class A {
return "";
}
@MyCheckForNull
public String baz(@MyNonnull String x, @MyCheckForNull CharSequence y) {
return "";
}
}
// FILE: main.kt
@@ -61,6 +82,9 @@ fun main(a: A) {
<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>a.foo("", null)<!>.length
<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>a.foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>, "")<!>.length
<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>a.baz("", null)<!>.length
<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>a.baz(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>, "")<!>.length
a.bar().length
a.bar()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.length
@@ -6,12 +6,20 @@ public open class A {
public constructor A()
@MyNullable public final var field: kotlin.String!
@MyNonnull public open fun bar(): kotlin.String!
@MyCheckForNull public open fun baz(/*0*/ @MyNonnull x: kotlin.String!, /*1*/ @MyCheckForNull y: kotlin.CharSequence!): kotlin.String!
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
@MyNullable public open fun foo(/*0*/ @MyNonnull x: kotlin.String!, /*1*/ @MyNullable y: kotlin.CharSequence!): kotlin.String!
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@kotlin.annotation.MustBeDocumented @javax.annotation.meta.TypeQualifierNickname @javax.annotation.CheckForNull @kotlin.annotation.Retention(value = AnnotationRetention.RUNTIME) public final annotation class MyCheckForNull : kotlin.Annotation {
public constructor MyCheckForNull()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@kotlin.annotation.MustBeDocumented @javax.annotation.meta.TypeQualifierNickname @javax.annotation.Nonnull(when = When.ALWAYS) @kotlin.annotation.Retention(value = AnnotationRetention.RUNTIME) public final annotation class MyNonnull : kotlin.Annotation {
public constructor MyNonnull()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
@@ -36,11 +36,12 @@ 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.firstArgumentValue
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.asFlexibleType
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.types.isFlexible
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
import org.jetbrains.kotlin.types.unwrapEnhancement
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import java.util.*
@@ -76,11 +77,13 @@ class SignatureEnhancement(private val annotationTypeQualifierResolver: Annotati
else -> {
val forWarning = annotationTypeQualifierResolver.jsr305State.isWarning()
annotationTypeQualifierResolver
.resolveTypeQualifierAnnotation(annotationDescriptor)
?.takeIf { it.fqName == JAVAX_NONNULL_ANNOTATION }
?.extractNullabilityTypeFromArgument()
?.copy(isForWarningOnly = forWarning)
val typeQualifierAnnotation =
annotationTypeQualifierResolver.resolveTypeQualifierAnnotation(annotationDescriptor)
?: return null
// resolveTypeQualifierAnnotation guarantees that `typeQualifierAnnotation` is javax.annotation.NonNull with argument
// or javax.annotation.CheckForNull without arguments
extractNullability(typeQualifierAnnotation)?.copy(isForWarningOnly = forWarning)
}
}
}