diff --git a/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/defaultAndNicknameMigrationPolicy.kt b/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/defaultAndNicknameMigrationPolicy.kt new file mode 100644 index 00000000000..15e8c92e4a9 --- /dev/null +++ b/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/defaultAndNicknameMigrationPolicy.kt @@ -0,0 +1,69 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER +// JSR305_GLOBAL_REPORT warn + +// FILE: NonNullApi.java + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import javax.annotation.meta.TypeQualifierDefault; + +@Retention(RetentionPolicy.RUNTIME) +@Documented +@MyNonnull +@TypeQualifierDefault({ ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD }) +public @interface NonNullApi { +} + +// FILE: MigrationNonNullApi.java + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import javax.annotation.meta.TypeQualifierDefault; + +import kotlin.annotations.jvm.*; + +@Retention(RetentionPolicy.RUNTIME) +@Documented +@MyNonnull +@UnderMigration(status = MigrationStatus.STRICT) +@TypeQualifierDefault({ ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD }) +public @interface MigrationNonNullApi { +} + +// FILE: PolicyFromDefault.java + +@NonNullApi +public class PolicyFromDefault { + public String foo(String x) { + return x; + } + + public String bar = "bar"; +} + +// FILE: PolicyFromNickname.java + +@MigrationNonNullApi +public class PolicyFromNickname { + public String foo(String x) { + return x; + } + + public String bar = "bar"; +} + +// FILE: main.kt + +fun main(default: PolicyFromDefault, nickname: PolicyFromNickname) { + default.foo(null).length + default.foo("hello").length + + nickname.foo(null).length + nickname.foo("hello").length +} \ No newline at end of file diff --git a/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/defaultAndNicknameMigrationPolicy.txt b/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/defaultAndNicknameMigrationPolicy.txt new file mode 100644 index 00000000000..2effab74bfa --- /dev/null +++ b/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/defaultAndNicknameMigrationPolicy.txt @@ -0,0 +1,35 @@ +package + +public fun main(/*0*/ default: PolicyFromDefault, /*1*/ nickname: PolicyFromNickname): kotlin.Unit + +@kotlin.annotation.Retention(value = AnnotationRetention.RUNTIME) @kotlin.annotation.MustBeDocumented @MyNonnull @kotlin.annotations.jvm.UnderMigration(status = MigrationStatus.STRICT) @javax.annotation.meta.TypeQualifierDefault(value = {ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD}) public final annotation class MigrationNonNullApi : kotlin.Annotation { + public constructor MigrationNonNullApi() + 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.Retention(value = AnnotationRetention.RUNTIME) @kotlin.annotation.MustBeDocumented @MyNonnull @javax.annotation.meta.TypeQualifierDefault(value = {ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD}) public final annotation class NonNullApi : kotlin.Annotation { + public constructor NonNullApi() + 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 +} + +@NonNullApi public open class PolicyFromDefault { + public constructor PolicyFromDefault() + public final var bar: kotlin.String! + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open fun foo(/*0*/ x: kotlin.String!): kotlin.String! + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +@MigrationNonNullApi public open class PolicyFromNickname { + public constructor PolicyFromNickname() + public final var bar: kotlin.String + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open fun foo(/*0*/ x: kotlin.String): kotlin.String + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/ForeignAnnotationsNoAnnotationInClasspathTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/ForeignAnnotationsNoAnnotationInClasspathTestGenerated.java index c82e3f05bb5..e97b4b1e3dc 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/ForeignAnnotationsNoAnnotationInClasspathTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/ForeignAnnotationsNoAnnotationInClasspathTestGenerated.java @@ -473,4 +473,19 @@ public class ForeignAnnotationsNoAnnotationInClasspathTestGenerated extends Abst } } } + + @TestMetadata("compiler/testData/foreignAnnotations/tests/typeQualifierDefault") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class TypeQualifierDefault extends AbstractForeignAnnotationsNoAnnotationInClasspathTest { + public void testAllFilesPresentInTypeQualifierDefault() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/foreignAnnotations/tests/typeQualifierDefault"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("defaultAndNicknameMigrationPolicy.kt") + public void testDefaultAndNicknameMigrationPolicy() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/typeQualifierDefault/defaultAndNicknameMigrationPolicy.kt"); + doTest(fileName); + } + } } diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/ForeignAnnotationsNoAnnotationInClasspathWithFastClassReadingTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/ForeignAnnotationsNoAnnotationInClasspathWithFastClassReadingTestGenerated.java index 54a9edb29b3..61f8851a3de 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/ForeignAnnotationsNoAnnotationInClasspathWithFastClassReadingTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/ForeignAnnotationsNoAnnotationInClasspathWithFastClassReadingTestGenerated.java @@ -473,4 +473,19 @@ public class ForeignAnnotationsNoAnnotationInClasspathWithFastClassReadingTestGe } } } + + @TestMetadata("compiler/testData/foreignAnnotations/tests/typeQualifierDefault") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class TypeQualifierDefault extends AbstractForeignAnnotationsNoAnnotationInClasspathWithFastClassReadingTest { + public void testAllFilesPresentInTypeQualifierDefault() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/foreignAnnotations/tests/typeQualifierDefault"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("defaultAndNicknameMigrationPolicy.kt") + public void testDefaultAndNicknameMigrationPolicy() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/typeQualifierDefault/defaultAndNicknameMigrationPolicy.kt"); + doTest(fileName); + } + } } diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/ForeignAnnotationsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/ForeignAnnotationsTestGenerated.java index fec653548ec..0389aed9adb 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/ForeignAnnotationsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/ForeignAnnotationsTestGenerated.java @@ -473,4 +473,19 @@ public class ForeignAnnotationsTestGenerated extends AbstractForeignAnnotationsT } } } + + @TestMetadata("compiler/testData/foreignAnnotations/tests/typeQualifierDefault") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class TypeQualifierDefault extends AbstractForeignAnnotationsTest { + public void testAllFilesPresentInTypeQualifierDefault() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/foreignAnnotations/tests/typeQualifierDefault"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("defaultAndNicknameMigrationPolicy.kt") + public void testDefaultAndNicknameMigrationPolicy() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/typeQualifierDefault/defaultAndNicknameMigrationPolicy.kt"); + doTest(fileName); + } + } } diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/JavacForeignAnnotationsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/JavacForeignAnnotationsTestGenerated.java index 9709cc1d5ee..107975b9c13 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/JavacForeignAnnotationsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/JavacForeignAnnotationsTestGenerated.java @@ -473,4 +473,19 @@ public class JavacForeignAnnotationsTestGenerated extends AbstractJavacForeignAn } } } + + @TestMetadata("compiler/testData/foreignAnnotations/tests/typeQualifierDefault") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class TypeQualifierDefault extends AbstractJavacForeignAnnotationsTest { + public void testAllFilesPresentInTypeQualifierDefault() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/foreignAnnotations/tests/typeQualifierDefault"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("defaultAndNicknameMigrationPolicy.kt") + public void testDefaultAndNicknameMigrationPolicy() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/typeQualifierDefault/defaultAndNicknameMigrationPolicy.kt"); + doTest(fileName); + } + } } diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/AnnotationTypeQualifierResolver.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/AnnotationTypeQualifierResolver.kt index 696213f4afc..04d32d21dc3 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/AnnotationTypeQualifierResolver.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/AnnotationTypeQualifierResolver.kt @@ -138,13 +138,15 @@ class AnnotationTypeQualifierResolver(storageManager: StorageManager, private va } fun resolveJsr305AnnotationState(annotationDescriptor: AnnotationDescriptor): ReportLevel { - jsr305State.user[annotationDescriptor.fqName?.asString()]?.let { return it } - - annotationDescriptor.annotationClass?.migrationAnnotationStatus()?.let { return it } - + resolveJsr305CustomState(annotationDescriptor)?.let { return it } return jsr305State.global } + fun resolveJsr305CustomState(annotationDescriptor: AnnotationDescriptor): ReportLevel? { + jsr305State.user[annotationDescriptor.fqName?.asString()]?.let { return it } + return annotationDescriptor.annotationClass?.migrationAnnotationStatus() + } + private fun ClassDescriptor.migrationAnnotationStatus(): ReportLevel? { val stateDescriptor = annotations.findAnnotation(MIGRATION_ANNOTATION_FQNAME)?.firstArgumentValue()?.safeAs() ?: return null diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/context.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/context.kt index 4534495c9e7..14d3cf5127b 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/context.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/context.kt @@ -147,7 +147,12 @@ private fun LazyJavaResolverContext.extractDefaultNullabilityQualifier( typeQualifierResolver.resolveTypeQualifierDefaultAnnotation(annotationDescriptor) ?: return null - val jsr305State = typeQualifierResolver.resolveJsr305AnnotationState(typeQualifier).takeIf { it != ReportLevel.IGNORE } ?: return null + val jsr305State = typeQualifierResolver.resolveJsr305CustomState(annotationDescriptor) + ?: typeQualifierResolver.resolveJsr305AnnotationState(typeQualifier) + + if (jsr305State.isIgnore) { + return null + } val nullabilityQualifier = components