Support codeanalysis annotations on type parameters bounds

This commit is contained in:
Denis Zharkov
2019-08-07 18:53:07 +03:00
committed by Victor Petukhov
parent 82d39dd86a
commit e27501497b
16 changed files with 200 additions and 114 deletions
@@ -0,0 +1,39 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// FILE: A.java
import jspecify.annotations.*;
public class A<T extends @NotNull Object> {
public void foo(T t) {}
public <E extends @NotNull Object> void bar(E e) {}
}
// FILE: B.java
import jspecify.annotations.*;
@DefaultNotNull
public class B<T> {
public void foo(T t) {}
public <E> void bar(E e) {}
}
// FILE: main.kt
fun main(a1: A<<!UPPER_BOUND_VIOLATED!>Any?<!>>, a2: A<String>, b1: B<<!UPPER_BOUND_VIOLATED!>Any?<!>>, b2: B<String>) {
a1.foo(null)
a1.bar<<!UPPER_BOUND_VIOLATED!>String?<!>>(null)
a1.bar<String>("")
a2.foo(null)
a2.bar<<!UPPER_BOUND_VIOLATED!>String?<!>>(null)
a2.bar<String>("")
b1.foo(<!NULL_FOR_NONNULL_TYPE!>null<!>)
b1.bar<<!UPPER_BOUND_VIOLATED!>String?<!>>(<!NULL_FOR_NONNULL_TYPE!>null<!>)
b1.bar<String>("")
b2.foo(<!NULL_FOR_NONNULL_TYPE!>null<!>)
b2.bar<<!UPPER_BOUND_VIOLATED!>String?<!>>(<!NULL_FOR_NONNULL_TYPE!>null<!>)
b2.bar<String>("")
}
@@ -0,0 +1,21 @@
package
public fun main(/*0*/ a1: A<kotlin.Any?>, /*1*/ a2: A<kotlin.String>, /*2*/ b1: B<kotlin.Any?>, /*3*/ b2: B<kotlin.String>): kotlin.Unit
public open class A</*0*/ T : @jspecify.annotations.NotNull kotlin.Any> {
public constructor A</*0*/ T : @jspecify.annotations.NotNull kotlin.Any>()
public open fun </*0*/ E : @jspecify.annotations.NotNull kotlin.Any> 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</*0*/ T : kotlin.Any> {
public constructor B</*0*/ T : kotlin.Any>()
public open fun </*0*/ E : kotlin.Any> 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
}
@@ -43,24 +43,6 @@ public class ForeignJava8AnnotationsNoAnnotationInClasspathTestGenerated extends
runTest("compiler/testData/foreignAnnotationsJava8/tests/typeUseOnObject.kt"); 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") @TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/jspecify")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @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); 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") @TestMetadata("simple.kt")
public void testSimple() throws Exception { public void testSimple() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/simple.kt"); 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") @TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305")
@@ -43,24 +43,6 @@ public class ForeignJava8AnnotationsNoAnnotationInClasspathWithPsiClassReadingTe
runTest("compiler/testData/foreignAnnotationsJava8/tests/typeUseOnObject.kt"); 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") @TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/jspecify")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @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); 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") @TestMetadata("simple.kt")
public void testSimple() throws Exception { public void testSimple() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/simple.kt"); 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") @TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305")
@@ -43,24 +43,6 @@ public class ForeignJava8AnnotationsTestGenerated extends AbstractForeignJava8An
runTest("compiler/testData/foreignAnnotationsJava8/tests/typeUseOnObject.kt"); 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") @TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/jspecify")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @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); 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") @TestMetadata("simple.kt")
public void testSimple() throws Exception { public void testSimple() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/simple.kt"); 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") @TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305")
@@ -43,24 +43,6 @@ public class JavacForeignJava8AnnotationsTestGenerated extends AbstractJavacFore
runTest("compiler/testData/foreignAnnotationsJava8/tests/typeUseOnObject.kt"); 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") @TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/jspecify")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @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); 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") @TestMetadata("simple.kt")
public void testSimple() throws Exception { public void testSimple() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/simple.kt"); 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") @TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305")
@@ -6,5 +6,5 @@
package org.jetbrains.kotlin.load.java package org.jetbrains.kotlin.load.java
enum class AnnotationQualifierApplicabilityType { enum class AnnotationQualifierApplicabilityType {
METHOD_RETURN_TYPE, VALUE_PARAMETER, FIELD, TYPE_USE METHOD_RETURN_TYPE, VALUE_PARAMETER, FIELD, TYPE_USE, TYPE_PARAMETER_BOUNDS
} }
@@ -18,7 +18,8 @@ val MIGRATION_ANNOTATION_FQNAME = FqName("kotlin.annotations.jvm.UnderMigration"
val DEFAULT_JSPECIFY_APPLICABILITY = listOf( val DEFAULT_JSPECIFY_APPLICABILITY = listOf(
AnnotationQualifierApplicabilityType.FIELD, AnnotationQualifierApplicabilityType.FIELD,
AnnotationQualifierApplicabilityType.METHOD_RETURN_TYPE, AnnotationQualifierApplicabilityType.METHOD_RETURN_TYPE,
AnnotationQualifierApplicabilityType.VALUE_PARAMETER AnnotationQualifierApplicabilityType.VALUE_PARAMETER,
AnnotationQualifierApplicabilityType.TYPE_PARAMETER_BOUNDS
) )
val BUILT_IN_TYPE_QUALIFIER_DEFAULT_ANNOTATIONS = mapOf( val BUILT_IN_TYPE_QUALIFIER_DEFAULT_ANNOTATIONS = mapOf(
@@ -39,8 +39,7 @@ val NULLABLE_ANNOTATIONS = listOf(
FqName("edu.umd.cs.findbugs.annotations.CheckForNull"), FqName("edu.umd.cs.findbugs.annotations.CheckForNull"),
FqName("edu.umd.cs.findbugs.annotations.Nullable"), FqName("edu.umd.cs.findbugs.annotations.Nullable"),
FqName("edu.umd.cs.findbugs.annotations.PossiblyNull"), FqName("edu.umd.cs.findbugs.annotations.PossiblyNull"),
FqName("io.reactivex.annotations.Nullable"), FqName("io.reactivex.annotations.Nullable")
JSPECIFY_NULLABLE
) )
val JAVAX_NONNULL_ANNOTATION = FqName("javax.annotation.Nonnull") 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.eclipse.jdt.annotation.NonNull"),
FqName("org.checkerframework.checker.nullness.qual.NonNull"), FqName("org.checkerframework.checker.nullness.qual.NonNull"),
FqName("lombok.NonNull"), FqName("lombok.NonNull"),
FqName("io.reactivex.annotations.NonNull"), FqName("io.reactivex.annotations.NonNull")
JSPECIFY_NOT_NULL
) )
val COMPATQUAL_NULLABLE_ANNOTATION = FqName("org.checkerframework.checker.nullness.compatqual.NullableDecl") val COMPATQUAL_NULLABLE_ANNOTATION = FqName("org.checkerframework.checker.nullness.compatqual.NullableDecl")
@@ -38,8 +38,15 @@ class AnnotationTypeQualifierResolver(storageManager: StorageManager, private va
operator fun component1() = typeQualifier operator fun component1() = typeQualifier
operator fun component2() = AnnotationQualifierApplicabilityType.values().filter(this::isApplicableTo) operator fun component2() = AnnotationQualifierApplicabilityType.values().filter(this::isApplicableTo)
private fun isApplicableTo(elementType: AnnotationQualifierApplicabilityType) = private fun isApplicableTo(elementType: AnnotationQualifierApplicabilityType): Boolean {
isApplicableConsideringMask(AnnotationQualifierApplicabilityType.TYPE_USE) || isApplicableConsideringMask(elementType) 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) = private fun isApplicableConsideringMask(elementType: AnnotationQualifierApplicabilityType) =
(applicability and (1 shl elementType.ordinal)) != 0 (applicability and (1 shl elementType.ordinal)) != 0
@@ -169,7 +169,7 @@ private fun LazyJavaResolverContext.extractDefaultNullabilityQualifier(
val nullabilityQualifier = val nullabilityQualifier =
components components
.signatureEnhancement .signatureEnhancement
.extractNullability(typeQualifier) .extractNullability(typeQualifier, onlyForJspecify = false)
?.copy(isForWarningOnly = jsr305State.isWarning) ?.copy(isForWarningOnly = jsr305State.isWarning)
?: return null ?: return null
@@ -187,7 +187,8 @@ private fun LazyJavaResolverContext.child(
delegateForTypeQualifiers: Lazy<JavaTypeQualifiersByElementType?> delegateForTypeQualifiers: Lazy<JavaTypeQualifiersByElementType?>
) = LazyJavaResolverContext( ) = LazyJavaResolverContext(
components, components,
typeParameterOwner?.let { LazyJavaTypeParameterResolver(this, containingDeclaration, it, typeParametersIndexOffset) } typeParameterOwner?.let {
LazyJavaTypeParameterResolver(this, containingDeclaration, it, typeParametersIndexOffset) }
?: typeParameterResolver, ?: typeParameterResolver,
delegateForTypeQualifiers delegateForTypeQualifiers
) )
@@ -45,6 +45,10 @@ class LazyJavaTypeParameterDescriptor(
override val annotations = LazyJavaAnnotations(c, javaTypeParameter) override val annotations = LazyJavaAnnotations(c, javaTypeParameter)
override fun resolveUpperBounds(): List<KotlinType> { override fun resolveUpperBounds(): List<KotlinType> {
return computeNotEnhancedBounds().let { c.components.signatureEnhancement.enhanceTypeParameterBounds(this, it, c) }
}
private fun computeNotEnhancedBounds(): List<KotlinType> {
val bounds = javaTypeParameter.upperBounds val bounds = javaTypeParameter.upperBounds
if (bounds.isEmpty()) { if (bounds.isEmpty()) {
return listOf( return listOf(
@@ -41,7 +41,10 @@ class LazyJavaTypeParameterResolver(
private val resolve = c.storageManager.createMemoizedFunctionWithNullableValues { typeParameter: JavaTypeParameter -> private val resolve = c.storageManager.createMemoizedFunctionWithNullableValues { typeParameter: JavaTypeParameter ->
typeParameters[typeParameter]?.let { index -> typeParameters[typeParameter]?.let { index ->
LazyJavaTypeParameterDescriptor(c.child(this), typeParameter, typeParametersIndexOffset + index, containingDeclaration) LazyJavaTypeParameterDescriptor(
c.child(this).copyWithNewDefaultTypeQualifiers(containingDeclaration.annotations),
typeParameter, typeParametersIndexOffset + index, containingDeclaration
)
} }
} }
@@ -62,8 +62,11 @@ class SignatureEnhancement(
} }
} }
fun extractNullability(annotationDescriptor: AnnotationDescriptor): NullabilityQualifierWithMigrationStatus? { fun extractNullability(
extractNullabilityFromKnownAnnotations(annotationDescriptor)?.let { return it } annotationDescriptor: AnnotationDescriptor,
onlyForJspecify: Boolean
): NullabilityQualifierWithMigrationStatus? {
extractNullabilityFromKnownAnnotations(annotationDescriptor, onlyForJspecify)?.let { return it }
val typeQualifierAnnotation = val typeQualifierAnnotation =
annotationTypeQualifierResolver.resolveTypeQualifierAnnotation(annotationDescriptor) annotationTypeQualifierResolver.resolveTypeQualifierAnnotation(annotationDescriptor)
@@ -72,42 +75,63 @@ class SignatureEnhancement(
val jsr305State = annotationTypeQualifierResolver.resolveJsr305AnnotationState(annotationDescriptor) val jsr305State = annotationTypeQualifierResolver.resolveJsr305AnnotationState(annotationDescriptor)
if (jsr305State.isIgnore) return null if (jsr305State.isIgnore) return null
return extractNullabilityFromKnownAnnotations(typeQualifierAnnotation)?.copy(isForWarningOnly = jsr305State.isWarning) return extractNullabilityFromKnownAnnotations(
typeQualifierAnnotation, onlyForJspecify
)?.copy(isForWarningOnly = jsr305State.isWarning)
} }
private fun extractNullabilityFromKnownAnnotations( private fun extractNullabilityFromKnownAnnotations(
annotationDescriptor: AnnotationDescriptor annotationDescriptor: AnnotationDescriptor,
onlyForJspecify: Boolean
): NullabilityQualifierWithMigrationStatus? { ): NullabilityQualifierWithMigrationStatus? {
val annotationFqName = annotationDescriptor.fqName ?: return null val annotationFqName = annotationDescriptor.fqName ?: return null
return when { val migrationStatus =
annotationFqName in NULLABLE_ANNOTATIONS -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE) jspecifyMigrationStatus(annotationFqName)
annotationFqName in NOT_NULL_ANNOTATIONS -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL) ?: (if (!onlyForJspecify) commonMigrationStatus(annotationFqName, annotationDescriptor) else null)
annotationFqName == JAVAX_NONNULL_ANNOTATION -> annotationDescriptor.extractNullabilityTypeFromArgument() ?: return null
annotationFqName == COMPATQUAL_NULLABLE_ANNOTATION && jsr305State.enableCompatqualCheckerFrameworkAnnotations -> return if (!migrationStatus.isForWarningOnly
NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE) && annotationDescriptor is PossiblyExternalAnnotationDescriptor
&& annotationDescriptor.isIdeExternalAnnotation
)
migrationStatus.copy(isForWarningOnly = true)
else migrationStatus
}
annotationFqName == COMPATQUAL_NONNULL_ANNOTATION && jsr305State.enableCompatqualCheckerFrameworkAnnotations -> private fun jspecifyMigrationStatus(
NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL) 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( private fun commonMigrationStatus(
NullabilityQualifier.NOT_NULL, annotationFqName: FqName,
isForWarningOnly = true 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( annotationFqName == COMPATQUAL_NULLABLE_ANNOTATION && jsr305State.enableCompatqualCheckerFrameworkAnnotations ->
NullabilityQualifier.NULLABLE, NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE)
isForWarningOnly = true
) annotationFqName == COMPATQUAL_NONNULL_ANNOTATION && jsr305State.enableCompatqualCheckerFrameworkAnnotations ->
else -> null NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL)
}?.let { migrationStatus ->
if (!migrationStatus.isForWarningOnly annotationFqName == ANDROIDX_RECENTLY_NON_NULL_ANNOTATION -> NullabilityQualifierWithMigrationStatus(
&& annotationDescriptor is PossiblyExternalAnnotationDescriptor NullabilityQualifier.NOT_NULL,
&& annotationDescriptor.isIdeExternalAnnotation) isForWarningOnly = true
migrationStatus.copy(isForWarningOnly = true) )
else migrationStatus
} annotationFqName == ANDROIDX_RECENTLY_NULLABLE_ANNOTATION -> NullabilityQualifierWithMigrationStatus(
NullabilityQualifier.NULLABLE,
isForWarningOnly = true
)
else -> null
} }
fun <D : CallableMemberDescriptor> enhanceSignatures(c: LazyJavaResolverContext, platformSignatures: Collection<D>): Collection<D> { fun <D : CallableMemberDescriptor> enhanceSignatures(c: LazyJavaResolverContext, platformSignatures: Collection<D>): Collection<D> {
@@ -204,6 +228,20 @@ class SignatureEnhancement(
return this return this
} }
fun enhanceTypeParameterBounds(
typeParameter: TypeParameterDescriptor,
bounds: List<KotlinType>,
context: LazyJavaResolverContext
): List<KotlinType> {
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 { private fun ValueParameterDescriptor.hasDefaultValueInAnnotation(type: KotlinType): Boolean {
val defaultValue = getDefaultValueFromAnnotation() val defaultValue = getDefaultValueFromAnnotation()
@@ -220,7 +258,8 @@ class SignatureEnhancement(
private val fromOverridden: Collection<KotlinType>, private val fromOverridden: Collection<KotlinType>,
private val isCovariant: Boolean, private val isCovariant: Boolean,
private val containerContext: LazyJavaResolverContext, private val containerContext: LazyJavaResolverContext,
private val containerApplicabilityType: AnnotationQualifierApplicabilityType private val containerApplicabilityType: AnnotationTypeQualifierResolver.QualifierApplicabilityType,
private val typeParameterBounds: Boolean = false
) { ) {
private val isForVarargParameter get() = typeContainer.safeAs<ValueParameterDescriptor>()?.varargElementType != null private val isForVarargParameter get() = typeContainer.safeAs<ValueParameterDescriptor>()?.varargElementType != null
@@ -316,7 +355,7 @@ class SignatureEnhancement(
} }
private fun Annotations.extractNullability(): NullabilityQualifierWithMigrationStatus? = private fun Annotations.extractNullability(): NullabilityQualifierWithMigrationStatus? =
this.firstNotNullResult(this@SignatureEnhancement::extractNullability) this.firstNotNullResult { extractNullability(it, onlyForJspecify = typeParameterBounds) }
private fun computeIndexedQualifiersForOverride(): (Int) -> JavaTypeQualifiers { private fun computeIndexedQualifiersForOverride(): (Int) -> JavaTypeQualifiers {
@@ -356,7 +395,12 @@ class SignatureEnhancement(
TypeAndDefaultQualifiers( TypeAndDefaultQualifiers(
type, type,
c.defaultTypeQualifiers c.defaultTypeQualifiers
?.get(AnnotationQualifierApplicabilityType.TYPE_USE) ?.get(
if (typeParameterBounds)
AnnotationTypeQualifierResolver.QualifierApplicabilityType.TYPE_PARAMETER_BOUNDS
else
AnnotationTypeQualifierResolver.QualifierApplicabilityType.TYPE_USE
)
) )
) )