diff --git a/compiler/testData/foreignAnnotations/tests/jsr305NullabilityNicknames.kt b/compiler/testData/foreignAnnotations/tests/jsr305NullabilityNicknames.kt index 4c38ebf6bc7..a91e5bb322f 100644 --- a/compiler/testData/foreignAnnotations/tests/jsr305NullabilityNicknames.kt +++ b/compiler/testData/foreignAnnotations/tests/jsr305NullabilityNicknames.kt @@ -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).length a.foo(null, "").length + a.baz("", null)?.length + a.baz("", null).length + a.baz(null, "").length + a.bar().length a.bar()!!.length diff --git a/compiler/testData/foreignAnnotations/tests/jsr305NullabilityNicknames.txt b/compiler/testData/foreignAnnotations/tests/jsr305NullabilityNicknames.txt index 7076e2dfb33..3397e6b6ca2 100644 --- a/compiler/testData/foreignAnnotations/tests/jsr305NullabilityNicknames.txt +++ b/compiler/testData/foreignAnnotations/tests/jsr305NullabilityNicknames.txt @@ -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 diff --git a/compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/jsr305NullabilityNicknames.kt b/compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/jsr305NullabilityNicknames.kt index 5d40b90f9be..5d6b9b4f5b8 100644 --- a/compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/jsr305NullabilityNicknames.kt +++ b/compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/jsr305NullabilityNicknames.kt @@ -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) { a.foo("", null).length a.foo(null, "").length + a.baz("", null).length + a.baz(null, "").length + a.bar().length a.bar()!!.length diff --git a/compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/jsr305NullabilityNicknames.txt b/compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/jsr305NullabilityNicknames.txt index ebc84337f3d..17f5733a6c5 100644 --- a/compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/jsr305NullabilityNicknames.txt +++ b/compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/jsr305NullabilityNicknames.txt @@ -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 diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhancement/signatureEnhancement.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhancement/signatureEnhancement.kt index a8b9b4b33ca..ca0f5328cc0 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhancement/signatureEnhancement.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhancement/signatureEnhancement.kt @@ -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) } } }