Make TYPE_USE default qualifiers overriding all other applicabilities
If there is default qualifier with TYPE_USE closer than one with METHOD then its nullability should be considered even when enhancing return type #KT-20016 Fixed
This commit is contained in:
+80
@@ -0,0 +1,80 @@
|
|||||||
|
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
|
||||||
|
// SKIP_JAVAC
|
||||||
|
// SKIP_COMPILED_JAVA
|
||||||
|
|
||||||
|
// FILE: spr/NonNullApi.java
|
||||||
|
|
||||||
|
package spr;
|
||||||
|
|
||||||
|
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.Nonnull;
|
||||||
|
import javax.annotation.meta.TypeQualifierDefault;
|
||||||
|
|
||||||
|
@Target({ElementType.TYPE, ElementType.TYPE_USE})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
@Nonnull
|
||||||
|
@TypeQualifierDefault({ElementType.TYPE_USE, ElementType.METHOD})
|
||||||
|
public @interface NonNullApi {
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: spr/NullableApi.java
|
||||||
|
|
||||||
|
package spr;
|
||||||
|
|
||||||
|
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.Nonnull;
|
||||||
|
import javax.annotation.meta.TypeQualifierDefault;
|
||||||
|
import javax.annotation.meta.When;
|
||||||
|
|
||||||
|
@Target({ElementType.TYPE_USE})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
@Nonnull(when = When.MAYBE)
|
||||||
|
@TypeQualifierDefault({ElementType.TYPE_USE})
|
||||||
|
public @interface NullableApi {
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: A.java
|
||||||
|
|
||||||
|
import spr.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
@NonNullApi
|
||||||
|
public class A {
|
||||||
|
public String foo(String x) { return ""; }
|
||||||
|
public @NullableApi String bar(@NullableApi String y) { return ""; }
|
||||||
|
public @NullableApi List<String> baz1() { return null; }
|
||||||
|
public List<@NullableApi String> baz2() { return null; }
|
||||||
|
public @NullableApi List<@NonNullApi String> baz3() { return null; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: main.kt
|
||||||
|
|
||||||
|
fun main(a: A) {
|
||||||
|
a.foo("").length
|
||||||
|
a.foo(<!NULL_FOR_NONNULL_TYPE!>null<!>)<!UNNECESSARY_SAFE_CALL!>?.<!>length
|
||||||
|
|
||||||
|
a.bar("")<!UNSAFE_CALL!>.<!>length
|
||||||
|
a.bar(null)?.length
|
||||||
|
|
||||||
|
a.baz1()<!UNSAFE_CALL!>.<!>get(0)<!UNSAFE_CALL!>.<!>length
|
||||||
|
a.baz1()!!.get(0)<!UNSAFE_CALL!>.<!>length
|
||||||
|
a.baz1()!!.get(0)?.length
|
||||||
|
|
||||||
|
a.baz2().get(0)<!UNSAFE_CALL!>.<!>length
|
||||||
|
a.baz2()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.get(0)<!UNSAFE_CALL!>.<!>length
|
||||||
|
a.baz2()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.get(0)?.length
|
||||||
|
|
||||||
|
a.baz3()<!UNSAFE_CALL!>.<!>get(0).length
|
||||||
|
a.baz3()!!.get(0).length
|
||||||
|
a.baz3()!!.get(0)<!UNNECESSARY_SAFE_CALL!>?.<!>length
|
||||||
|
}
|
||||||
+32
@@ -0,0 +1,32 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public fun main(/*0*/ a: A): kotlin.Unit
|
||||||
|
|
||||||
|
@spr.NonNullApi public open class A {
|
||||||
|
public constructor A()
|
||||||
|
@spr.NullableApi public open fun bar(/*0*/ @spr.NullableApi y: @spr.NullableApi kotlin.String?): @spr.NullableApi kotlin.String?
|
||||||
|
@spr.NullableApi public open fun baz1(): (@spr.NullableApi kotlin.collections.MutableList<kotlin.String?>?..@spr.NullableApi kotlin.collections.List<kotlin.String?>?)
|
||||||
|
public open fun baz2(): kotlin.collections.(Mutable)List<@spr.NullableApi kotlin.String?>
|
||||||
|
@spr.NullableApi public open fun baz3(): (@spr.NullableApi kotlin.collections.MutableList<@spr.NonNullApi kotlin.String>?..@spr.NullableApi kotlin.collections.List<@spr.NonNullApi 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
|
||||||
|
}
|
||||||
|
|
||||||
|
package spr {
|
||||||
|
|
||||||
|
@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.CLASS, AnnotationTarget.FILE, AnnotationTarget.TYPE}) @kotlin.annotation.Retention(value = AnnotationRetention.RUNTIME) @kotlin.annotation.MustBeDocumented @javax.annotation.Nonnull @javax.annotation.meta.TypeQualifierDefault(value = {ElementType.TYPE_USE, ElementType.METHOD}) 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
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.TYPE}) @kotlin.annotation.Retention(value = AnnotationRetention.RUNTIME) @kotlin.annotation.MustBeDocumented @javax.annotation.Nonnull(when = When.MAYBE) @javax.annotation.meta.TypeQualifierDefault(value = {ElementType.TYPE_USE}) public final annotation class NullableApi : kotlin.Annotation {
|
||||||
|
public constructor NullableApi()
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
+6
@@ -79,6 +79,12 @@ public class ForeignJava8AnnotationsNoAnnotationInClasspathTestGenerated extends
|
|||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305/typeArguments.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305/typeArguments.kt");
|
||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("typeUseVsMethodConflict.kt")
|
||||||
|
public void testTypeUseVsMethodConflict() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305/typeUseVsMethodConflict.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/typeEnhancement")
|
@TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/typeEnhancement")
|
||||||
|
|||||||
+6
@@ -79,6 +79,12 @@ public class ForeignJava8AnnotationsNoAnnotationInClasspathWithFastClassReadingT
|
|||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305/typeArguments.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305/typeArguments.kt");
|
||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("typeUseVsMethodConflict.kt")
|
||||||
|
public void testTypeUseVsMethodConflict() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305/typeUseVsMethodConflict.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/typeEnhancement")
|
@TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/typeEnhancement")
|
||||||
|
|||||||
+6
@@ -79,6 +79,12 @@ public class ForeignJava8AnnotationsTestGenerated extends AbstractForeignJava8An
|
|||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305/typeArguments.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305/typeArguments.kt");
|
||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("typeUseVsMethodConflict.kt")
|
||||||
|
public void testTypeUseVsMethodConflict() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305/typeUseVsMethodConflict.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/typeEnhancement")
|
@TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/typeEnhancement")
|
||||||
|
|||||||
+6
@@ -79,6 +79,12 @@ public class JavacForeignJava8AnnotationsTestGenerated extends AbstractJavacFore
|
|||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305/typeArguments.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305/typeArguments.kt");
|
||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("typeUseVsMethodConflict.kt")
|
||||||
|
public void testTypeUseVsMethodConflict() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305/typeUseVsMethodConflict.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/typeEnhancement")
|
@TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/typeEnhancement")
|
||||||
|
|||||||
+6
-2
@@ -42,10 +42,14 @@ class AnnotationTypeQualifierResolver(storageManager: StorageManager, val jsr305
|
|||||||
private val typeQualifier: AnnotationDescriptor,
|
private val typeQualifier: AnnotationDescriptor,
|
||||||
private val applicability: Int
|
private val applicability: Int
|
||||||
) {
|
) {
|
||||||
private fun isApplicableTo(elementType: QualifierApplicabilityType) = (applicability and (1 shl elementType.ordinal)) != 0
|
|
||||||
|
|
||||||
operator fun component1() = typeQualifier
|
operator fun component1() = typeQualifier
|
||||||
operator fun component2() = QualifierApplicabilityType.values().filter(this::isApplicableTo)
|
operator fun component2() = QualifierApplicabilityType.values().filter(this::isApplicableTo)
|
||||||
|
|
||||||
|
private fun isApplicableTo(elementType: QualifierApplicabilityType) =
|
||||||
|
isApplicableConsideringMask(QualifierApplicabilityType.TYPE_USE) || isApplicableConsideringMask(elementType)
|
||||||
|
|
||||||
|
private fun isApplicableConsideringMask(elementType: QualifierApplicabilityType) =
|
||||||
|
(applicability and (1 shl elementType.ordinal)) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
private val resolvedNicknames =
|
private val resolvedNicknames =
|
||||||
|
|||||||
@@ -78,10 +78,7 @@ class JavaTypeQualifiersByElementType(
|
|||||||
operator fun get(
|
operator fun get(
|
||||||
applicabilityType: AnnotationTypeQualifierResolver.QualifierApplicabilityType?
|
applicabilityType: AnnotationTypeQualifierResolver.QualifierApplicabilityType?
|
||||||
): JavaTypeQualifiers? {
|
): JavaTypeQualifiers? {
|
||||||
val nullabilityQualifierWithMigrationStatus =
|
val nullabilityQualifierWithMigrationStatus = nullabilityQualifiers[applicabilityType] ?: return null
|
||||||
nullabilityQualifiers[applicabilityType]
|
|
||||||
?: nullabilityQualifiers[AnnotationTypeQualifierResolver.QualifierApplicabilityType.TYPE_USE]
|
|
||||||
?: return null
|
|
||||||
|
|
||||||
return JavaTypeQualifiers(
|
return JavaTypeQualifiers(
|
||||||
nullabilityQualifierWithMigrationStatus.qualifier, null,
|
nullabilityQualifierWithMigrationStatus.qualifier, null,
|
||||||
|
|||||||
Reference in New Issue
Block a user