diff --git a/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/defaults.kt b/compiler/testData/foreignAnnotationsJava8/tests/jspecify/defaults.kt similarity index 100% rename from compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/defaults.kt rename to compiler/testData/foreignAnnotationsJava8/tests/jspecify/defaults.kt diff --git a/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/defaults.txt b/compiler/testData/foreignAnnotationsJava8/tests/jspecify/defaults.txt similarity index 100% rename from compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/defaults.txt rename to compiler/testData/foreignAnnotationsJava8/tests/jspecify/defaults.txt diff --git a/compiler/testData/foreignAnnotationsJava8/tests/jspecify/typeParameterBounds.kt b/compiler/testData/foreignAnnotationsJava8/tests/jspecify/typeParameterBounds.kt new file mode 100644 index 00000000000..995ca10e22e --- /dev/null +++ b/compiler/testData/foreignAnnotationsJava8/tests/jspecify/typeParameterBounds.kt @@ -0,0 +1,39 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER +// FILE: A.java + +import jspecify.annotations.*; + +public class A { + public void foo(T t) {} + public void bar(E e) {} +} + +// FILE: B.java + +import jspecify.annotations.*; + +@DefaultNotNull +public class B { + public void foo(T t) {} + public void bar(E e) {} +} + +// FILE: main.kt + +fun main(a1: A<Any?>, a2: A, b1: B<Any?>, b2: B) { + a1.foo(null) + a1.bar<String?>(null) + a1.bar("") + + a2.foo(null) + a2.bar<String?>(null) + a2.bar("") + + b1.foo(null) + b1.bar<String?>(null) + b1.bar("") + + b2.foo(null) + b2.bar<String?>(null) + b2.bar("") +} diff --git a/compiler/testData/foreignAnnotationsJava8/tests/jspecify/typeParameterBounds.txt b/compiler/testData/foreignAnnotationsJava8/tests/jspecify/typeParameterBounds.txt new file mode 100644 index 00000000000..dd3929be1cb --- /dev/null +++ b/compiler/testData/foreignAnnotationsJava8/tests/jspecify/typeParameterBounds.txt @@ -0,0 +1,21 @@ +package + +public fun main(/*0*/ a1: A, /*1*/ a2: A, /*2*/ b1: B, /*3*/ b2: B): kotlin.Unit + +public open class A { + public constructor A() + public open fun bar(/*0*/ e: E!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open fun foo(/*0*/ t: T!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +@jspecify.annotations.DefaultNotNull public open class B { + public constructor B() + public open fun bar(/*0*/ e: E): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open fun foo(/*0*/ t: T): kotlin.Unit + 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-java8/tests/org/jetbrains/kotlin/checkers/ForeignJava8AnnotationsNoAnnotationInClasspathTestGenerated.java b/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/ForeignJava8AnnotationsNoAnnotationInClasspathTestGenerated.java index 6ae8de9b296..71d41932970 100644 --- a/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/ForeignJava8AnnotationsNoAnnotationInClasspathTestGenerated.java +++ b/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/ForeignJava8AnnotationsNoAnnotationInClasspathTestGenerated.java @@ -43,24 +43,6 @@ public class ForeignJava8AnnotationsNoAnnotationInClasspathTestGenerated extends runTest("compiler/testData/foreignAnnotationsJava8/tests/typeUseOnObject.kt"); } - @TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis") - @TestDataPath("$PROJECT_ROOT") - @RunWith(JUnit3RunnerWithInners.class) - public static class Codeanalysis extends AbstractForeignJava8AnnotationsNoAnnotationInClasspathTest { - private void runTest(String testDataFilePath) throws Exception { - KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); - } - - public void testAllFilesPresentInCodeanalysis() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis"), Pattern.compile("^(.+)\\.kt$"), null, true); - } - - @TestMetadata("defaults.kt") - public void testDefaults() throws Exception { - runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/defaults.kt"); - } - } - @TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/jspecify") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) @@ -73,10 +55,20 @@ public class ForeignJava8AnnotationsNoAnnotationInClasspathTestGenerated extends KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/foreignAnnotationsJava8/tests/jspecify"), Pattern.compile("^(.+)\\.kt$"), null, true); } + @TestMetadata("defaults.kt") + public void testDefaults() throws Exception { + runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/defaults.kt"); + } + @TestMetadata("simple.kt") public void testSimple() throws Exception { runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/simple.kt"); } + + @TestMetadata("typeParameterBounds.kt") + public void testTypeParameterBounds() throws Exception { + runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/typeParameterBounds.kt"); + } } @TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305") diff --git a/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/ForeignJava8AnnotationsNoAnnotationInClasspathWithPsiClassReadingTestGenerated.java b/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/ForeignJava8AnnotationsNoAnnotationInClasspathWithPsiClassReadingTestGenerated.java index 30e8186de7d..73ff013bfdd 100644 --- a/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/ForeignJava8AnnotationsNoAnnotationInClasspathWithPsiClassReadingTestGenerated.java +++ b/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/ForeignJava8AnnotationsNoAnnotationInClasspathWithPsiClassReadingTestGenerated.java @@ -43,24 +43,6 @@ public class ForeignJava8AnnotationsNoAnnotationInClasspathWithPsiClassReadingTe runTest("compiler/testData/foreignAnnotationsJava8/tests/typeUseOnObject.kt"); } - @TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis") - @TestDataPath("$PROJECT_ROOT") - @RunWith(JUnit3RunnerWithInners.class) - public static class Codeanalysis extends AbstractForeignJava8AnnotationsNoAnnotationInClasspathWithPsiClassReadingTest { - private void runTest(String testDataFilePath) throws Exception { - KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); - } - - public void testAllFilesPresentInCodeanalysis() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis"), Pattern.compile("^(.+)\\.kt$"), null, true); - } - - @TestMetadata("defaults.kt") - public void testDefaults() throws Exception { - runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/defaults.kt"); - } - } - @TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/jspecify") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) @@ -73,10 +55,20 @@ public class ForeignJava8AnnotationsNoAnnotationInClasspathWithPsiClassReadingTe KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/foreignAnnotationsJava8/tests/jspecify"), Pattern.compile("^(.+)\\.kt$"), null, true); } + @TestMetadata("defaults.kt") + public void testDefaults() throws Exception { + runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/defaults.kt"); + } + @TestMetadata("simple.kt") public void testSimple() throws Exception { runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/simple.kt"); } + + @TestMetadata("typeParameterBounds.kt") + public void testTypeParameterBounds() throws Exception { + runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/typeParameterBounds.kt"); + } } @TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305") diff --git a/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/ForeignJava8AnnotationsTestGenerated.java b/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/ForeignJava8AnnotationsTestGenerated.java index 67cf2f3dbdd..5336fd61b7e 100644 --- a/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/ForeignJava8AnnotationsTestGenerated.java +++ b/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/ForeignJava8AnnotationsTestGenerated.java @@ -43,24 +43,6 @@ public class ForeignJava8AnnotationsTestGenerated extends AbstractForeignJava8An runTest("compiler/testData/foreignAnnotationsJava8/tests/typeUseOnObject.kt"); } - @TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis") - @TestDataPath("$PROJECT_ROOT") - @RunWith(JUnit3RunnerWithInners.class) - public static class Codeanalysis extends AbstractForeignJava8AnnotationsTest { - private void runTest(String testDataFilePath) throws Exception { - KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); - } - - public void testAllFilesPresentInCodeanalysis() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis"), Pattern.compile("^(.+)\\.kt$"), null, true); - } - - @TestMetadata("defaults.kt") - public void testDefaults() throws Exception { - runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/defaults.kt"); - } - } - @TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/jspecify") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) @@ -73,10 +55,20 @@ public class ForeignJava8AnnotationsTestGenerated extends AbstractForeignJava8An KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/foreignAnnotationsJava8/tests/jspecify"), Pattern.compile("^(.+)\\.kt$"), null, true); } + @TestMetadata("defaults.kt") + public void testDefaults() throws Exception { + runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/defaults.kt"); + } + @TestMetadata("simple.kt") public void testSimple() throws Exception { runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/simple.kt"); } + + @TestMetadata("typeParameterBounds.kt") + public void testTypeParameterBounds() throws Exception { + runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/typeParameterBounds.kt"); + } } @TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305") diff --git a/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/javac/JavacForeignJava8AnnotationsTestGenerated.java b/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/javac/JavacForeignJava8AnnotationsTestGenerated.java index d421c68e288..c4fb8dccc69 100644 --- a/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/javac/JavacForeignJava8AnnotationsTestGenerated.java +++ b/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/javac/JavacForeignJava8AnnotationsTestGenerated.java @@ -43,24 +43,6 @@ public class JavacForeignJava8AnnotationsTestGenerated extends AbstractJavacFore runTest("compiler/testData/foreignAnnotationsJava8/tests/typeUseOnObject.kt"); } - @TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis") - @TestDataPath("$PROJECT_ROOT") - @RunWith(JUnit3RunnerWithInners.class) - public static class Codeanalysis extends AbstractJavacForeignJava8AnnotationsTest { - private void runTest(String testDataFilePath) throws Exception { - KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); - } - - public void testAllFilesPresentInCodeanalysis() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis"), Pattern.compile("^(.+)\\.kt$"), null, true); - } - - @TestMetadata("defaults.kt") - public void testDefaults() throws Exception { - runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/defaults.kt"); - } - } - @TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/jspecify") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) @@ -73,10 +55,20 @@ public class JavacForeignJava8AnnotationsTestGenerated extends AbstractJavacFore KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/foreignAnnotationsJava8/tests/jspecify"), Pattern.compile("^(.+)\\.kt$"), null, true); } + @TestMetadata("defaults.kt") + public void testDefaults() throws Exception { + runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/defaults.kt"); + } + @TestMetadata("simple.kt") public void testSimple() throws Exception { runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/simple.kt"); } + + @TestMetadata("typeParameterBounds.kt") + public void testTypeParameterBounds() throws Exception { + runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/typeParameterBounds.kt"); + } } @TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305") diff --git a/core/compiler.common.jvm/src/org/jetbrains/kotlin/load/java/AnnotationQualifierApplicabilityType.kt b/core/compiler.common.jvm/src/org/jetbrains/kotlin/load/java/AnnotationQualifierApplicabilityType.kt index 305f0e8ee0d..a41346fd68f 100644 --- a/core/compiler.common.jvm/src/org/jetbrains/kotlin/load/java/AnnotationQualifierApplicabilityType.kt +++ b/core/compiler.common.jvm/src/org/jetbrains/kotlin/load/java/AnnotationQualifierApplicabilityType.kt @@ -6,5 +6,5 @@ package org.jetbrains.kotlin.load.java enum class AnnotationQualifierApplicabilityType { - METHOD_RETURN_TYPE, VALUE_PARAMETER, FIELD, TYPE_USE + METHOD_RETURN_TYPE, VALUE_PARAMETER, FIELD, TYPE_USE, TYPE_PARAMETER_BOUNDS } diff --git a/core/compiler.common.jvm/src/org/jetbrains/kotlin/load/java/AnnotationQualifiersFqNames.kt b/core/compiler.common.jvm/src/org/jetbrains/kotlin/load/java/AnnotationQualifiersFqNames.kt index a00526d2d36..b51c7066e73 100644 --- a/core/compiler.common.jvm/src/org/jetbrains/kotlin/load/java/AnnotationQualifiersFqNames.kt +++ b/core/compiler.common.jvm/src/org/jetbrains/kotlin/load/java/AnnotationQualifiersFqNames.kt @@ -18,7 +18,8 @@ val MIGRATION_ANNOTATION_FQNAME = FqName("kotlin.annotations.jvm.UnderMigration" val DEFAULT_JSPECIFY_APPLICABILITY = listOf( AnnotationQualifierApplicabilityType.FIELD, AnnotationQualifierApplicabilityType.METHOD_RETURN_TYPE, - AnnotationQualifierApplicabilityType.VALUE_PARAMETER + AnnotationQualifierApplicabilityType.VALUE_PARAMETER, + AnnotationQualifierApplicabilityType.TYPE_PARAMETER_BOUNDS ) val BUILT_IN_TYPE_QUALIFIER_DEFAULT_ANNOTATIONS = mapOf( diff --git a/core/compiler.common.jvm/src/org/jetbrains/kotlin/load/java/JvmAnnotationNames.kt b/core/compiler.common.jvm/src/org/jetbrains/kotlin/load/java/JvmAnnotationNames.kt index fd5e33ecad6..a8a00937884 100644 --- a/core/compiler.common.jvm/src/org/jetbrains/kotlin/load/java/JvmAnnotationNames.kt +++ b/core/compiler.common.jvm/src/org/jetbrains/kotlin/load/java/JvmAnnotationNames.kt @@ -39,8 +39,7 @@ val NULLABLE_ANNOTATIONS = listOf( FqName("edu.umd.cs.findbugs.annotations.CheckForNull"), FqName("edu.umd.cs.findbugs.annotations.Nullable"), FqName("edu.umd.cs.findbugs.annotations.PossiblyNull"), - FqName("io.reactivex.annotations.Nullable"), - JSPECIFY_NULLABLE + FqName("io.reactivex.annotations.Nullable") ) val JAVAX_NONNULL_ANNOTATION = FqName("javax.annotation.Nonnull") @@ -56,8 +55,7 @@ val NOT_NULL_ANNOTATIONS = listOf( FqName("org.eclipse.jdt.annotation.NonNull"), FqName("org.checkerframework.checker.nullness.qual.NonNull"), FqName("lombok.NonNull"), - FqName("io.reactivex.annotations.NonNull"), - JSPECIFY_NOT_NULL + FqName("io.reactivex.annotations.NonNull") ) val COMPATQUAL_NULLABLE_ANNOTATION = FqName("org.checkerframework.checker.nullness.compatqual.NullableDecl") diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/AnnotationTypeQualifierResolver.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/AnnotationTypeQualifierResolver.kt index 2d86d57c271..9ddc52c62a7 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/AnnotationTypeQualifierResolver.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/AnnotationTypeQualifierResolver.kt @@ -38,8 +38,15 @@ class AnnotationTypeQualifierResolver(storageManager: StorageManager, private va operator fun component1() = typeQualifier operator fun component2() = AnnotationQualifierApplicabilityType.values().filter(this::isApplicableTo) - private fun isApplicableTo(elementType: AnnotationQualifierApplicabilityType) = - isApplicableConsideringMask(AnnotationQualifierApplicabilityType.TYPE_USE) || isApplicableConsideringMask(elementType) + private fun isApplicableTo(elementType: AnnotationQualifierApplicabilityType): Boolean { + if (isApplicableConsideringMask(elementType)) return true + + // We explicitly state that while JSR-305 TYPE_USE annotations effectively should be applied to every type + // they are not applicable for type parameter bounds because it would be a breaking change otherwise. + // Only defaulting annotations from jspecify are applicable + return isApplicableConsideringMask(AnnotationQualifierApplicabilityType.TYPE_USE) && + elementType != AnnotationQualifierApplicabilityType.TYPE_PARAMETER_BOUNDS + } private fun isApplicableConsideringMask(elementType: AnnotationQualifierApplicabilityType) = (applicability and (1 shl elementType.ordinal)) != 0 diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/context.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/context.kt index 1bfa5735f1b..9bc6141283c 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/context.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/context.kt @@ -169,7 +169,7 @@ private fun LazyJavaResolverContext.extractDefaultNullabilityQualifier( val nullabilityQualifier = components .signatureEnhancement - .extractNullability(typeQualifier) + .extractNullability(typeQualifier, onlyForJspecify = false) ?.copy(isForWarningOnly = jsr305State.isWarning) ?: return null @@ -187,7 +187,8 @@ private fun LazyJavaResolverContext.child( delegateForTypeQualifiers: Lazy ) = LazyJavaResolverContext( components, - typeParameterOwner?.let { LazyJavaTypeParameterResolver(this, containingDeclaration, it, typeParametersIndexOffset) } + typeParameterOwner?.let { + LazyJavaTypeParameterResolver(this, containingDeclaration, it, typeParametersIndexOffset) } ?: typeParameterResolver, delegateForTypeQualifiers ) diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaTypeParameterDescriptor.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaTypeParameterDescriptor.kt index 9634791fe2c..058a2499a0c 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaTypeParameterDescriptor.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaTypeParameterDescriptor.kt @@ -45,6 +45,10 @@ class LazyJavaTypeParameterDescriptor( override val annotations = LazyJavaAnnotations(c, javaTypeParameter) override fun resolveUpperBounds(): List { + return computeNotEnhancedBounds().let { c.components.signatureEnhancement.enhanceTypeParameterBounds(this, it, c) } + } + + private fun computeNotEnhancedBounds(): List { val bounds = javaTypeParameter.upperBounds if (bounds.isEmpty()) { return listOf( diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/resolvers.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/resolvers.kt index b79ac07b3a5..e98c467a2d9 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/resolvers.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/resolvers.kt @@ -41,7 +41,10 @@ class LazyJavaTypeParameterResolver( private val resolve = c.storageManager.createMemoizedFunctionWithNullableValues { typeParameter: JavaTypeParameter -> typeParameters[typeParameter]?.let { index -> - LazyJavaTypeParameterDescriptor(c.child(this), typeParameter, typeParametersIndexOffset + index, containingDeclaration) + LazyJavaTypeParameterDescriptor( + c.child(this).copyWithNewDefaultTypeQualifiers(containingDeclaration.annotations), + typeParameter, typeParametersIndexOffset + index, containingDeclaration + ) } } diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/typeEnhancement/signatureEnhancement.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/typeEnhancement/signatureEnhancement.kt index e6349db6a59..2e5eb07a2a8 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/typeEnhancement/signatureEnhancement.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/typeEnhancement/signatureEnhancement.kt @@ -62,8 +62,11 @@ class SignatureEnhancement( } } - fun extractNullability(annotationDescriptor: AnnotationDescriptor): NullabilityQualifierWithMigrationStatus? { - extractNullabilityFromKnownAnnotations(annotationDescriptor)?.let { return it } + fun extractNullability( + annotationDescriptor: AnnotationDescriptor, + onlyForJspecify: Boolean + ): NullabilityQualifierWithMigrationStatus? { + extractNullabilityFromKnownAnnotations(annotationDescriptor, onlyForJspecify)?.let { return it } val typeQualifierAnnotation = annotationTypeQualifierResolver.resolveTypeQualifierAnnotation(annotationDescriptor) @@ -72,42 +75,63 @@ class SignatureEnhancement( val jsr305State = annotationTypeQualifierResolver.resolveJsr305AnnotationState(annotationDescriptor) if (jsr305State.isIgnore) return null - return extractNullabilityFromKnownAnnotations(typeQualifierAnnotation)?.copy(isForWarningOnly = jsr305State.isWarning) + return extractNullabilityFromKnownAnnotations( + typeQualifierAnnotation, onlyForJspecify + )?.copy(isForWarningOnly = jsr305State.isWarning) } private fun extractNullabilityFromKnownAnnotations( - annotationDescriptor: AnnotationDescriptor + annotationDescriptor: AnnotationDescriptor, + onlyForJspecify: Boolean ): NullabilityQualifierWithMigrationStatus? { val annotationFqName = annotationDescriptor.fqName ?: return null - return when { - annotationFqName in NULLABLE_ANNOTATIONS -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE) - annotationFqName in NOT_NULL_ANNOTATIONS -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL) - annotationFqName == JAVAX_NONNULL_ANNOTATION -> annotationDescriptor.extractNullabilityTypeFromArgument() + val migrationStatus = + jspecifyMigrationStatus(annotationFqName) + ?: (if (!onlyForJspecify) commonMigrationStatus(annotationFqName, annotationDescriptor) else null) + ?: return null - annotationFqName == COMPATQUAL_NULLABLE_ANNOTATION && jsr305State.enableCompatqualCheckerFrameworkAnnotations -> - NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE) + return if (!migrationStatus.isForWarningOnly + && annotationDescriptor is PossiblyExternalAnnotationDescriptor + && annotationDescriptor.isIdeExternalAnnotation + ) + migrationStatus.copy(isForWarningOnly = true) + else migrationStatus + } - annotationFqName == COMPATQUAL_NONNULL_ANNOTATION && jsr305State.enableCompatqualCheckerFrameworkAnnotations -> - NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL) + private fun jspecifyMigrationStatus( + annotationFqName: FqName + ): NullabilityQualifierWithMigrationStatus? = when (annotationFqName) { + JSPECIFY_NOT_NULL -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL) + JSPECIFY_NULLABLE -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE) + JSPECIFY_NULLNESS_UNKNOWN -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.FORCE_FLEXIBILITY) + else -> null + } - annotationFqName == ANDROIDX_RECENTLY_NON_NULL_ANNOTATION -> NullabilityQualifierWithMigrationStatus( - NullabilityQualifier.NOT_NULL, - isForWarningOnly = true - ) + private fun commonMigrationStatus( + annotationFqName: FqName, + annotationDescriptor: AnnotationDescriptor + ): NullabilityQualifierWithMigrationStatus? = when { + annotationFqName in NULLABLE_ANNOTATIONS -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE) + annotationFqName in NOT_NULL_ANNOTATIONS -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL) + annotationFqName == JAVAX_NONNULL_ANNOTATION -> annotationDescriptor.extractNullabilityTypeFromArgument() - annotationFqName == ANDROIDX_RECENTLY_NULLABLE_ANNOTATION -> NullabilityQualifierWithMigrationStatus( - NullabilityQualifier.NULLABLE, - isForWarningOnly = true - ) - else -> null - }?.let { migrationStatus -> - if (!migrationStatus.isForWarningOnly - && annotationDescriptor is PossiblyExternalAnnotationDescriptor - && annotationDescriptor.isIdeExternalAnnotation) - migrationStatus.copy(isForWarningOnly = true) - else migrationStatus - } + annotationFqName == COMPATQUAL_NULLABLE_ANNOTATION && jsr305State.enableCompatqualCheckerFrameworkAnnotations -> + NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE) + + annotationFqName == COMPATQUAL_NONNULL_ANNOTATION && jsr305State.enableCompatqualCheckerFrameworkAnnotations -> + NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL) + + annotationFqName == ANDROIDX_RECENTLY_NON_NULL_ANNOTATION -> NullabilityQualifierWithMigrationStatus( + NullabilityQualifier.NOT_NULL, + isForWarningOnly = true + ) + + annotationFqName == ANDROIDX_RECENTLY_NULLABLE_ANNOTATION -> NullabilityQualifierWithMigrationStatus( + NullabilityQualifier.NULLABLE, + isForWarningOnly = true + ) + else -> null } fun enhanceSignatures(c: LazyJavaResolverContext, platformSignatures: Collection): Collection { @@ -204,6 +228,20 @@ class SignatureEnhancement( return this } + fun enhanceTypeParameterBounds( + typeParameter: TypeParameterDescriptor, + bounds: List, + context: LazyJavaResolverContext + ): List { + return bounds.map { bound -> + SignatureParts( + typeParameter, bound, emptyList(), false, context, + AnnotationTypeQualifierResolver.QualifierApplicabilityType.TYPE_PARAMETER_BOUNDS, + typeParameterBounds = true + ).enhance().type + } + } + private fun ValueParameterDescriptor.hasDefaultValueInAnnotation(type: KotlinType): Boolean { val defaultValue = getDefaultValueFromAnnotation() @@ -220,7 +258,8 @@ class SignatureEnhancement( private val fromOverridden: Collection, private val isCovariant: Boolean, private val containerContext: LazyJavaResolverContext, - private val containerApplicabilityType: AnnotationQualifierApplicabilityType + private val containerApplicabilityType: AnnotationTypeQualifierResolver.QualifierApplicabilityType, + private val typeParameterBounds: Boolean = false ) { private val isForVarargParameter get() = typeContainer.safeAs()?.varargElementType != null @@ -316,7 +355,7 @@ class SignatureEnhancement( } private fun Annotations.extractNullability(): NullabilityQualifierWithMigrationStatus? = - this.firstNotNullResult(this@SignatureEnhancement::extractNullability) + this.firstNotNullResult { extractNullability(it, onlyForJspecify = typeParameterBounds) } private fun computeIndexedQualifiersForOverride(): (Int) -> JavaTypeQualifiers { @@ -356,7 +395,12 @@ class SignatureEnhancement( TypeAndDefaultQualifiers( type, c.defaultTypeQualifiers - ?.get(AnnotationQualifierApplicabilityType.TYPE_USE) + ?.get( + if (typeParameterBounds) + AnnotationTypeQualifierResolver.QualifierApplicabilityType.TYPE_PARAMETER_BOUNDS + else + AnnotationTypeQualifierResolver.QualifierApplicabilityType.TYPE_USE + ) ) )