Improve support for TYPE_USE default qualifiers
- Apply default qualifiers to type arguments if they contain TYPE_USE in applicability list - Read TYPE_USE placed default qualifier annotations #KT-19592 Fixed #KT-20016 In Progress
This commit is contained in:
+79
@@ -0,0 +1,79 @@
|
|||||||
|
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
|
||||||
|
// SKIP_JAVAC
|
||||||
|
|
||||||
|
// 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})
|
||||||
|
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}) 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
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -78,5 +78,5 @@ fun main(a: A) {
|
|||||||
|
|
||||||
a.baz()<!UNSAFE_CALL!>.<!>get(0)
|
a.baz()<!UNSAFE_CALL!>.<!>get(0)
|
||||||
a.baz()!!.get(0).get(0)
|
a.baz()!!.get(0).get(0)
|
||||||
a.baz()!!.get(0)?.get(0)
|
a.baz()!!.get(0)<!UNNECESSARY_SAFE_CALL!>?.<!>get(0)
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,7 @@ public fun main(/*0*/ a: A): kotlin.Unit
|
|||||||
public constructor A()
|
public constructor A()
|
||||||
public final var field: kotlin.String
|
public final var field: kotlin.String
|
||||||
public open fun bar(): kotlin.String
|
public open fun bar(): kotlin.String
|
||||||
@spr.Nullable public open fun baz(): kotlin.collections.(Mutable)List<kotlin.String!>?
|
@spr.Nullable public open fun baz(): kotlin.collections.(Mutable)List<kotlin.String>?
|
||||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
public open fun foo(/*0*/ x: kotlin.String, /*1*/ @spr.Nullable y: kotlin.CharSequence?): kotlin.String
|
public open fun foo(/*0*/ x: kotlin.String, /*1*/ @spr.Nullable y: kotlin.CharSequence?): kotlin.String
|
||||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
|||||||
@@ -0,0 +1,110 @@
|
|||||||
|
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
|
||||||
|
// RENDER_PACKAGE: test
|
||||||
|
|
||||||
|
// FILE: spr/Nullable.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.TypeQualifierNickname;
|
||||||
|
import javax.annotation.meta.When;
|
||||||
|
|
||||||
|
@Target({ElementType.TYPE_USE})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
@Nonnull(when = When.MAYBE)
|
||||||
|
@TypeQualifierNickname
|
||||||
|
public @interface Nullable {
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.PACKAGE)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
@Nonnull
|
||||||
|
@TypeQualifierDefault({ElementType.TYPE_USE})
|
||||||
|
public @interface NonNullApi {
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: test/package-info.java
|
||||||
|
|
||||||
|
@spr.NonNullApi()
|
||||||
|
package test;
|
||||||
|
|
||||||
|
// FILE: test/L.java
|
||||||
|
|
||||||
|
package test;
|
||||||
|
|
||||||
|
public class L<T extends java.util.Map<String, S>, S> {
|
||||||
|
public T t() { return null; }
|
||||||
|
public S s() { return null; }
|
||||||
|
|
||||||
|
public void setT(@spr.Nullable T t) {}
|
||||||
|
public void setS(S s) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: test/A.java
|
||||||
|
|
||||||
|
package test;
|
||||||
|
|
||||||
|
import spr.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class A {
|
||||||
|
public void foo(L<Map<String, Integer>, @Nullable Integer> l) {}
|
||||||
|
public void bar(L<?, Integer> l) {}
|
||||||
|
public L<Map<String, Integer>, @Nullable Integer> baz1() { return null; }
|
||||||
|
public L<?, Integer> baz2() { return null; }
|
||||||
|
public L<? extends Map<String, Integer>, Integer> baz3() { return null; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: main.kt
|
||||||
|
|
||||||
|
import test.L
|
||||||
|
|
||||||
|
fun main(a: test.A, l: L<Map<String, Int>, Int?>, l1: L<Map<String, Int>, Int>) {
|
||||||
|
a.foo(l)
|
||||||
|
a.foo(<!TYPE_MISMATCH!>l <!UNCHECKED_CAST!>as L<Map<String, Int>, Int><!><!>)
|
||||||
|
a.foo(<!TYPE_MISMATCH!>l <!UNCHECKED_CAST!>as L<Map<String, Int?>, Int?><!><!>)
|
||||||
|
|
||||||
|
a.bar(l1)
|
||||||
|
a.bar(<!TYPE_MISMATCH!>l1 <!UNCHECKED_CAST!>as L<Map<String, Int>, Int?><!><!>)
|
||||||
|
|
||||||
|
a.baz1().t().containsKey("")
|
||||||
|
a.baz1().t().<!TYPE_INFERENCE_ONLY_INPUT_TYPES!>containsKey<!>(null)
|
||||||
|
a.baz1().t().containsValue(1)
|
||||||
|
a.baz1().t().<!TYPE_INFERENCE_ONLY_INPUT_TYPES!>containsValue<!>(null)
|
||||||
|
a.baz1().s().hashCode()
|
||||||
|
|
||||||
|
a.baz1().setT(l.t())
|
||||||
|
a.baz1().setT(<!TYPE_MISMATCH!>l.t() <!UNCHECKED_CAST!>as L<Map<String, Int>, Int><!><!>)
|
||||||
|
a.baz1().setT(null)
|
||||||
|
|
||||||
|
a.baz2().t().containsKey("")
|
||||||
|
a.baz2().t().containsKey(null)
|
||||||
|
a.baz2().t().containsValue(1)
|
||||||
|
a.baz2().t().containsValue(null)
|
||||||
|
a.baz2().s().hashCode()
|
||||||
|
|
||||||
|
a.baz3().t().containsKey("")
|
||||||
|
a.baz3().t().<!TYPE_INFERENCE_ONLY_INPUT_TYPES!>containsKey<!>(null)
|
||||||
|
a.baz3().t().containsValue(1)
|
||||||
|
a.baz3().t().<!TYPE_INFERENCE_ONLY_INPUT_TYPES!>containsValue<!>(null)
|
||||||
|
a.baz3().s().hashCode()
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
public open class A {
|
||||||
|
public constructor A()
|
||||||
|
public open fun bar(/*0*/ l: test.L<*, kotlin.Int>): kotlin.Unit
|
||||||
|
public open fun baz1(): test.L<kotlin.collections.(Mutable)Map<kotlin.String, kotlin.Int>, @spr.Nullable kotlin.Int?>
|
||||||
|
public open fun baz2(): test.L<*, kotlin.Int>
|
||||||
|
public open fun baz3(): test.L<out kotlin.collections.(Mutable)Map<kotlin.String, kotlin.Int>, kotlin.Int>
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open fun foo(/*0*/ l: test.L<kotlin.collections.(Mutable)Map<kotlin.String, kotlin.Int>, @spr.Nullable kotlin.Int?>): kotlin.Unit
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
public open class L</*0*/ T : kotlin.collections.(Mutable)Map<kotlin.String!, S!>!, /*1*/ S : kotlin.Any!> {
|
||||||
|
public constructor L</*0*/ T : kotlin.collections.(Mutable)Map<kotlin.String!, S!>!, /*1*/ S : kotlin.Any!>()
|
||||||
|
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 fun s(): S
|
||||||
|
public open fun setS(/*0*/ s: S): kotlin.Unit
|
||||||
|
public open fun setT(/*0*/ @spr.Nullable t: @spr.Nullable T?): kotlin.Unit
|
||||||
|
public open fun t(): T
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
package
|
||||||
|
|
||||||
|
public fun main(/*0*/ a: test.A, /*1*/ l: test.L<kotlin.collections.Map<kotlin.String, kotlin.Int>, kotlin.Int?>, /*2*/ l1: test.L<kotlin.collections.Map<kotlin.String, kotlin.Int>, kotlin.Int>): kotlin.Unit
|
||||||
|
|
||||||
|
package spr {
|
||||||
|
|
||||||
|
@kotlin.annotation.Target(allowedTargets = {}) @kotlin.annotation.Retention(value = AnnotationRetention.RUNTIME) @kotlin.annotation.MustBeDocumented @javax.annotation.Nonnull @javax.annotation.meta.TypeQualifierDefault(value = {ElementType.TYPE_USE}) 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.TypeQualifierNickname public final annotation class Nullable : kotlin.Annotation {
|
||||||
|
public constructor Nullable()
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
package test {
|
||||||
|
|
||||||
|
public open class A {
|
||||||
|
public constructor A()
|
||||||
|
public open fun bar(/*0*/ l: test.L<*, kotlin.Int>): kotlin.Unit
|
||||||
|
public open fun baz1(): test.L<kotlin.collections.(Mutable)Map<kotlin.String, kotlin.Int>, @spr.Nullable kotlin.Int?>
|
||||||
|
public open fun baz2(): test.L<*, kotlin.Int>
|
||||||
|
public open fun baz3(): test.L<out kotlin.collections.(Mutable)Map<kotlin.String, kotlin.Int>, kotlin.Int>
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open fun foo(/*0*/ l: test.L<kotlin.collections.(Mutable)Map<kotlin.String, kotlin.Int>, @spr.Nullable kotlin.Int?>): kotlin.Unit
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
public open class L</*0*/ T : kotlin.collections.(Mutable)Map<kotlin.String!, S!>!, /*1*/ S : kotlin.Any!> {
|
||||||
|
public constructor L</*0*/ T : kotlin.collections.(Mutable)Map<kotlin.String!, S!>!, /*1*/ S : kotlin.Any!>()
|
||||||
|
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 fun s(): S
|
||||||
|
public open fun setS(/*0*/ s: S): kotlin.Unit
|
||||||
|
public open fun setT(/*0*/ @spr.Nullable t: @spr.Nullable T?): kotlin.Unit
|
||||||
|
public open fun t(): T
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
}
|
||||||
+12
@@ -56,11 +56,23 @@ public class ForeignJava8AnnotationsTestGenerated extends AbstractForeignJava8An
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/foreignAnnotationsJava8/tests/jsr305"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/foreignAnnotationsJava8/tests/jsr305"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("defaultAnnotationAppliedToType.kt")
|
||||||
|
public void testDefaultAnnotationAppliedToType() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305/defaultAnnotationAppliedToType.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("springNullableWithTypeUse.kt")
|
@TestMetadata("springNullableWithTypeUse.kt")
|
||||||
public void testSpringNullableWithTypeUse() throws Exception {
|
public void testSpringNullableWithTypeUse() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305/springNullableWithTypeUse.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305/springNullableWithTypeUse.kt");
|
||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("typeArguments.kt")
|
||||||
|
public void testTypeArguments() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305/typeArguments.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/typeEnhancement")
|
@TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/typeEnhancement")
|
||||||
|
|||||||
+12
@@ -56,11 +56,23 @@ public class JavacForeignJava8AnnotationsTestGenerated extends AbstractJavacFore
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/foreignAnnotationsJava8/tests/jsr305"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/foreignAnnotationsJava8/tests/jsr305"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("defaultAnnotationAppliedToType.kt")
|
||||||
|
public void testDefaultAnnotationAppliedToType() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305/defaultAnnotationAppliedToType.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("springNullableWithTypeUse.kt")
|
@TestMetadata("springNullableWithTypeUse.kt")
|
||||||
public void testSpringNullableWithTypeUse() throws Exception {
|
public void testSpringNullableWithTypeUse() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305/springNullableWithTypeUse.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305/springNullableWithTypeUse.kt");
|
||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("typeArguments.kt")
|
||||||
|
public void testTypeArguments() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305/typeArguments.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/typeEnhancement")
|
@TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/typeEnhancement")
|
||||||
|
|||||||
+3
@@ -18,11 +18,14 @@ package org.jetbrains.kotlin.checkers.javac
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.checkers.AbstractForeignJava8AnnotationsTest
|
import org.jetbrains.kotlin.checkers.AbstractForeignJava8AnnotationsTest
|
||||||
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
||||||
|
import org.jetbrains.kotlin.test.InTextDirectivesUtils
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
abstract class AbstractJavacForeignJava8AnnotationsTest : AbstractForeignJava8AnnotationsTest() {
|
abstract class AbstractJavacForeignJava8AnnotationsTest : AbstractForeignJava8AnnotationsTest() {
|
||||||
|
|
||||||
override fun analyzeAndCheck(testDataFile: File, files: List<TestFile>) {
|
override fun analyzeAndCheck(testDataFile: File, files: List<TestFile>) {
|
||||||
|
if (files.any { file -> InTextDirectivesUtils.isDirectiveDefined(file.expectedText, "// SKIP_JAVAC") }) return
|
||||||
|
|
||||||
val groupedByModule = files.groupBy(TestFile::module)
|
val groupedByModule = files.groupBy(TestFile::module)
|
||||||
val allKtFiles = groupedByModule.values.flatMap { getKtFiles(it, true) }
|
val allKtFiles = groupedByModule.values.flatMap { getKtFiles(it, true) }
|
||||||
environment.registerJavac(kotlinFiles = allKtFiles)
|
environment.registerJavac(kotlinFiles = allKtFiles)
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ class JavaTypeQualifiersByElementType(
|
|||||||
internal val nullabilityQualifiers: QualifierByApplicabilityType
|
internal val nullabilityQualifiers: QualifierByApplicabilityType
|
||||||
) {
|
) {
|
||||||
operator fun get(
|
operator fun get(
|
||||||
applicabilityType: AnnotationTypeQualifierResolver.QualifierApplicabilityType
|
applicabilityType: AnnotationTypeQualifierResolver.QualifierApplicabilityType?
|
||||||
): JavaTypeQualifiers? {
|
): JavaTypeQualifiers? {
|
||||||
val nullabilityQualifierWithMigrationStatus =
|
val nullabilityQualifierWithMigrationStatus =
|
||||||
nullabilityQualifiers[applicabilityType]
|
nullabilityQualifiers[applicabilityType]
|
||||||
@@ -204,3 +204,13 @@ fun LazyJavaResolverContext.childForClassOrPackage(
|
|||||||
containingDeclaration, typeParameterOwner, typeParametersIndexOffset,
|
containingDeclaration, typeParameterOwner, typeParametersIndexOffset,
|
||||||
lazy(LazyThreadSafetyMode.NONE) { computeNewDefaultTypeQualifiers(containingDeclaration.annotations) }
|
lazy(LazyThreadSafetyMode.NONE) { computeNewDefaultTypeQualifiers(containingDeclaration.annotations) }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fun LazyJavaResolverContext.copyWithNewDefaultTypeQualifiers(
|
||||||
|
additionalAnnotations: Annotations
|
||||||
|
) = if (additionalAnnotations.isEmpty())
|
||||||
|
this
|
||||||
|
else
|
||||||
|
LazyJavaResolverContext(
|
||||||
|
components, typeParameterResolver,
|
||||||
|
lazy(LazyThreadSafetyMode.NONE) { computeNewDefaultTypeQualifiers(additionalAnnotations) }
|
||||||
|
)
|
||||||
|
|||||||
+69
-44
@@ -29,7 +29,7 @@ import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor
|
|||||||
import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor
|
import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor
|
||||||
import org.jetbrains.kotlin.load.java.descriptors.JavaPropertyDescriptor
|
import org.jetbrains.kotlin.load.java.descriptors.JavaPropertyDescriptor
|
||||||
import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext
|
import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext
|
||||||
import org.jetbrains.kotlin.load.java.lazy.computeNewDefaultTypeQualifiers
|
import org.jetbrains.kotlin.load.java.lazy.copyWithNewDefaultTypeQualifiers
|
||||||
import org.jetbrains.kotlin.load.java.lazy.descriptors.isJavaField
|
import org.jetbrains.kotlin.load.java.lazy.descriptors.isJavaField
|
||||||
import org.jetbrains.kotlin.load.kotlin.SignatureBuildingComponents
|
import org.jetbrains.kotlin.load.kotlin.SignatureBuildingComponents
|
||||||
import org.jetbrains.kotlin.load.kotlin.computeJvmDescriptor
|
import org.jetbrains.kotlin.load.kotlin.computeJvmDescriptor
|
||||||
@@ -109,7 +109,7 @@ class SignatureEnhancement(private val annotationTypeQualifierResolver: Annotati
|
|||||||
// Fake overrides with one overridden has been enhanced before
|
// Fake overrides with one overridden has been enhanced before
|
||||||
if (kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE && original.overriddenDescriptors.size == 1) return this
|
if (kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE && original.overriddenDescriptors.size == 1) return this
|
||||||
|
|
||||||
val outerScopeQualifiers = c.computeNewDefaultTypeQualifiers(annotations)
|
val memberContext = c.copyWithNewDefaultTypeQualifiers(annotations)
|
||||||
|
|
||||||
// When loading method as an override for a property, all annotations are stick to its getter
|
// When loading method as an override for a property, all annotations are stick to its getter
|
||||||
val annotationOwnerForMember =
|
val annotationOwnerForMember =
|
||||||
@@ -125,9 +125,8 @@ class SignatureEnhancement(private val annotationTypeQualifierResolver: Annotati
|
|||||||
annotationOwnerForMember.safeAs<FunctionDescriptor>()
|
annotationOwnerForMember.safeAs<FunctionDescriptor>()
|
||||||
?.getUserData(JavaMethodDescriptor.ORIGINAL_VALUE_PARAMETER_FOR_EXTENSION_RECEIVER),
|
?.getUserData(JavaMethodDescriptor.ORIGINAL_VALUE_PARAMETER_FOR_EXTENSION_RECEIVER),
|
||||||
isCovariant = false,
|
isCovariant = false,
|
||||||
defaultTopLevelQualifiers =
|
containerContext = memberContext,
|
||||||
outerScopeQualifiers
|
containerApplicabilityType = AnnotationTypeQualifierResolver.QualifierApplicabilityType.VALUE_PARAMETER
|
||||||
?.get(AnnotationTypeQualifierResolver.QualifierApplicabilityType.VALUE_PARAMETER)
|
|
||||||
) { it.extensionReceiverParameter!!.type }.enhance()
|
) { it.extensionReceiverParameter!!.type }.enhance()
|
||||||
else null
|
else null
|
||||||
|
|
||||||
@@ -148,9 +147,8 @@ class SignatureEnhancement(private val annotationTypeQualifierResolver: Annotati
|
|||||||
p ->
|
p ->
|
||||||
parts(
|
parts(
|
||||||
typeContainer = p, isCovariant = false,
|
typeContainer = p, isCovariant = false,
|
||||||
defaultTopLevelQualifiers =
|
containerContext = memberContext,
|
||||||
outerScopeQualifiers
|
containerApplicabilityType = AnnotationTypeQualifierResolver.QualifierApplicabilityType.VALUE_PARAMETER
|
||||||
?.get(AnnotationTypeQualifierResolver.QualifierApplicabilityType.VALUE_PARAMETER)
|
|
||||||
) { it.valueParameters[p.index].type }
|
) { it.valueParameters[p.index].type }
|
||||||
.enhance(predefinedEnhancementInfo?.parametersInfo?.getOrNull(p.index))
|
.enhance(predefinedEnhancementInfo?.parametersInfo?.getOrNull(p.index))
|
||||||
}
|
}
|
||||||
@@ -158,15 +156,12 @@ class SignatureEnhancement(private val annotationTypeQualifierResolver: Annotati
|
|||||||
val returnTypeEnhancement =
|
val returnTypeEnhancement =
|
||||||
parts(
|
parts(
|
||||||
typeContainer = annotationOwnerForMember, isCovariant = true,
|
typeContainer = annotationOwnerForMember, isCovariant = true,
|
||||||
defaultTopLevelQualifiers =
|
containerContext = memberContext,
|
||||||
outerScopeQualifiers?.get(
|
containerApplicabilityType =
|
||||||
if (this.safeAs<PropertyDescriptor>()?.isJavaField == true)
|
if (this.safeAs<PropertyDescriptor>()?.isJavaField == true)
|
||||||
AnnotationTypeQualifierResolver.QualifierApplicabilityType.FIELD
|
AnnotationTypeQualifierResolver.QualifierApplicabilityType.FIELD
|
||||||
else
|
else
|
||||||
AnnotationTypeQualifierResolver.QualifierApplicabilityType.METHOD_RETURN_TYPE
|
AnnotationTypeQualifierResolver.QualifierApplicabilityType.METHOD_RETURN_TYPE
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
) { it.returnType!! }.enhance(predefinedEnhancementInfo?.returnTypeInfo)
|
) { it.returnType!! }.enhance(predefinedEnhancementInfo?.returnTypeInfo)
|
||||||
|
|
||||||
if ((receiverTypeEnhancement?.wereChanges ?: false)
|
if ((receiverTypeEnhancement?.wereChanges ?: false)
|
||||||
@@ -183,7 +178,8 @@ class SignatureEnhancement(private val annotationTypeQualifierResolver: Annotati
|
|||||||
private val fromOverride: KotlinType,
|
private val fromOverride: KotlinType,
|
||||||
private val fromOverridden: Collection<KotlinType>,
|
private val fromOverridden: Collection<KotlinType>,
|
||||||
private val isCovariant: Boolean,
|
private val isCovariant: Boolean,
|
||||||
private val defaultTopLevelQualifiers: JavaTypeQualifiers?
|
private val containerContext: LazyJavaResolverContext,
|
||||||
|
private val containerApplicabilityType: AnnotationTypeQualifierResolver.QualifierApplicabilityType
|
||||||
) {
|
) {
|
||||||
fun enhance(predefined: TypeEnhancementInfo? = null): PartEnhancementResult {
|
fun enhance(predefined: TypeEnhancementInfo? = null): PartEnhancementResult {
|
||||||
val qualifiers = computeIndexedQualifiersForOverride()
|
val qualifiers = computeIndexedQualifiersForOverride()
|
||||||
@@ -222,7 +218,10 @@ class SignatureEnhancement(private val annotationTypeQualifierResolver: Annotati
|
|||||||
isNotNullTypeParameter = unwrap() is NotNullTypeParameter)
|
isNotNullTypeParameter = unwrap() is NotNullTypeParameter)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun KotlinType.extractQualifiersFromAnnotations(isHeadTypeConstructor: Boolean): JavaTypeQualifiers {
|
private fun KotlinType.extractQualifiersFromAnnotations(
|
||||||
|
isHeadTypeConstructor: Boolean,
|
||||||
|
defaultQualifiersForType: JavaTypeQualifiers?
|
||||||
|
): JavaTypeQualifiers {
|
||||||
val composedAnnotation =
|
val composedAnnotation =
|
||||||
if (isHeadTypeConstructor && typeContainer != null)
|
if (isHeadTypeConstructor && typeContainer != null)
|
||||||
composeAnnotations(typeContainer.annotations, annotations)
|
composeAnnotations(typeContainer.annotations, annotations)
|
||||||
@@ -234,7 +233,12 @@ class SignatureEnhancement(private val annotationTypeQualifierResolver: Annotati
|
|||||||
|
|
||||||
fun <T: Any> uniqueNotNull(x: T?, y: T?) = if (x == null || y == null || x == y) x ?: y else null
|
fun <T: Any> uniqueNotNull(x: T?, y: T?) = if (x == null || y == null || x == y) x ?: y else null
|
||||||
|
|
||||||
val defaultTypeQualifier = defaultTopLevelQualifiers?.takeIf { isHeadTypeConstructor }
|
val defaultTypeQualifier =
|
||||||
|
if (isHeadTypeConstructor)
|
||||||
|
containerContext.defaultTypeQualifiers?.get(containerApplicabilityType)
|
||||||
|
else
|
||||||
|
defaultQualifiersForType
|
||||||
|
|
||||||
val nullabilityInfo =
|
val nullabilityInfo =
|
||||||
composedAnnotation.extractNullability()
|
composedAnnotation.extractNullability()
|
||||||
?: defaultTypeQualifier?.nullability?.let {
|
?: defaultTypeQualifier?.nullability?.let {
|
||||||
@@ -263,24 +267,6 @@ class SignatureEnhancement(private val annotationTypeQualifierResolver: Annotati
|
|||||||
this.firstNotNullResult(this@SignatureEnhancement::extractNullability)
|
this.firstNotNullResult(this@SignatureEnhancement::extractNullability)
|
||||||
|
|
||||||
private fun computeIndexedQualifiersForOverride(): (Int) -> JavaTypeQualifiers {
|
private fun computeIndexedQualifiersForOverride(): (Int) -> JavaTypeQualifiers {
|
||||||
fun KotlinType.toIndexed(): List<KotlinType> {
|
|
||||||
val list = ArrayList<KotlinType>(1)
|
|
||||||
|
|
||||||
fun add(type: KotlinType) {
|
|
||||||
list.add(type)
|
|
||||||
for (arg in type.arguments) {
|
|
||||||
if (arg.isStarProjection) {
|
|
||||||
list.add(arg.type)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
add(arg.type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
add(this)
|
|
||||||
return list
|
|
||||||
}
|
|
||||||
|
|
||||||
val indexedFromSupertypes = fromOverridden.map { it.toIndexed() }
|
val indexedFromSupertypes = fromOverridden.map { it.toIndexed() }
|
||||||
val indexedThisType = fromOverride.toIndexed()
|
val indexedThisType = fromOverride.toIndexed()
|
||||||
@@ -298,18 +284,49 @@ class SignatureEnhancement(private val annotationTypeQualifierResolver: Annotati
|
|||||||
val isHeadTypeConstructor = index == 0
|
val isHeadTypeConstructor = index == 0
|
||||||
assert(isHeadTypeConstructor || !onlyHeadTypeConstructor) { "Only head type constructors should be computed" }
|
assert(isHeadTypeConstructor || !onlyHeadTypeConstructor) { "Only head type constructors should be computed" }
|
||||||
|
|
||||||
val qualifiers = indexedThisType[index]
|
val (qualifiers, defaultQualifiers) = indexedThisType[index]
|
||||||
val verticalSlice = indexedFromSupertypes.mapNotNull { it.getOrNull(index) }
|
val verticalSlice = indexedFromSupertypes.mapNotNull { it.getOrNull(index)?.type }
|
||||||
|
|
||||||
// Only the head type constructor is safely co-variant
|
// Only the head type constructor is safely co-variant
|
||||||
qualifiers.computeQualifiersForOverride(verticalSlice, isHeadTypeConstructor)
|
qualifiers.computeQualifiersForOverride(verticalSlice, defaultQualifiers, isHeadTypeConstructor)
|
||||||
}
|
}
|
||||||
|
|
||||||
return { index -> computedResult.getOrElse(index) { JavaTypeQualifiers.NONE } }
|
return { index -> computedResult.getOrElse(index) { JavaTypeQualifiers.NONE } }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun KotlinType.toIndexed(): List<TypeAndDefaultQualifiers> {
|
||||||
|
val list = ArrayList<TypeAndDefaultQualifiers>(1)
|
||||||
|
|
||||||
|
fun add(type: KotlinType, ownerContext: LazyJavaResolverContext) {
|
||||||
|
val c = ownerContext.copyWithNewDefaultTypeQualifiers(type.annotations)
|
||||||
|
|
||||||
|
list.add(
|
||||||
|
TypeAndDefaultQualifiers(
|
||||||
|
type,
|
||||||
|
c.defaultTypeQualifiers
|
||||||
|
?.get(AnnotationTypeQualifierResolver.QualifierApplicabilityType.TYPE_USE)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
for (arg in type.arguments) {
|
||||||
|
if (arg.isStarProjection) {
|
||||||
|
// TODO: sort out how to handle wildcards
|
||||||
|
list.add(TypeAndDefaultQualifiers(arg.type, null))
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
add(arg.type, c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
add(this, containerContext)
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
private fun KotlinType.computeQualifiersForOverride(
|
private fun KotlinType.computeQualifiersForOverride(
|
||||||
fromSupertypes: Collection<KotlinType>,
|
fromSupertypes: Collection<KotlinType>,
|
||||||
|
defaultQualifiersForType: JavaTypeQualifiers?,
|
||||||
isHeadTypeConstructor: Boolean
|
isHeadTypeConstructor: Boolean
|
||||||
): JavaTypeQualifiers {
|
): JavaTypeQualifiers {
|
||||||
val superQualifiers = fromSupertypes.map { it.extractQualifiers() }
|
val superQualifiers = fromSupertypes.map { it.extractQualifiers() }
|
||||||
@@ -319,7 +336,7 @@ class SignatureEnhancement(private val annotationTypeQualifierResolver: Annotati
|
|||||||
.mapNotNull { it.unwrapEnhancement().extractQualifiers().nullability }
|
.mapNotNull { it.unwrapEnhancement().extractQualifiers().nullability }
|
||||||
.toSet()
|
.toSet()
|
||||||
|
|
||||||
val own = extractQualifiersFromAnnotations(isHeadTypeConstructor)
|
val own = extractQualifiersFromAnnotations(isHeadTypeConstructor, defaultQualifiersForType)
|
||||||
val ownNullability = own.takeIf { !it.isNullabilityQualifierForWarning }?.nullability
|
val ownNullability = own.takeIf { !it.isNullabilityQualifierForWarning }?.nullability
|
||||||
val ownNullabilityForWarning = own.nullability
|
val ownNullabilityForWarning = own.nullability
|
||||||
|
|
||||||
@@ -355,7 +372,8 @@ class SignatureEnhancement(private val annotationTypeQualifierResolver: Annotati
|
|||||||
private fun <D : CallableMemberDescriptor> D.parts(
|
private fun <D : CallableMemberDescriptor> D.parts(
|
||||||
typeContainer: Annotated?,
|
typeContainer: Annotated?,
|
||||||
isCovariant: Boolean,
|
isCovariant: Boolean,
|
||||||
defaultTopLevelQualifiers: JavaTypeQualifiers?,
|
containerContext: LazyJavaResolverContext,
|
||||||
|
containerApplicabilityType: AnnotationTypeQualifierResolver.QualifierApplicabilityType,
|
||||||
collector: (CallableMemberDescriptor) -> KotlinType
|
collector: (CallableMemberDescriptor) -> KotlinType
|
||||||
): SignatureParts {
|
): SignatureParts {
|
||||||
return SignatureParts(
|
return SignatureParts(
|
||||||
@@ -365,7 +383,9 @@ class SignatureEnhancement(private val annotationTypeQualifierResolver: Annotati
|
|||||||
collector(it)
|
collector(it)
|
||||||
},
|
},
|
||||||
isCovariant,
|
isCovariant,
|
||||||
defaultTopLevelQualifiers
|
// recompute default type qualifiers using type annotations
|
||||||
|
containerContext.copyWithNewDefaultTypeQualifiers(collector(this).annotations),
|
||||||
|
containerApplicabilityType
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -402,3 +422,8 @@ private fun Set<NullabilityQualifier>.select(own: NullabilityQualifier?, isCovar
|
|||||||
NullabilityQualifier.FORCE_FLEXIBILITY
|
NullabilityQualifier.FORCE_FLEXIBILITY
|
||||||
else
|
else
|
||||||
select(NullabilityQualifier.NOT_NULL, NullabilityQualifier.NULLABLE, own, isCovariant)
|
select(NullabilityQualifier.NOT_NULL, NullabilityQualifier.NULLABLE, own, isCovariant)
|
||||||
|
|
||||||
|
private data class TypeAndDefaultQualifiers(
|
||||||
|
val type: KotlinType,
|
||||||
|
val defaultQualifiers: JavaTypeQualifiers?
|
||||||
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user