Support TypeQualifierDefault from JSR 305 for nullability qualifiers

#KT-10942 Fixed
This commit is contained in:
Denis Zharkov
2017-06-24 17:07:13 +03:00
parent 5141a88a53
commit e26c210d69
39 changed files with 1538 additions and 76 deletions
@@ -0,0 +1,28 @@
package javax.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.annotation.meta.TypeQualifierDefault;
/**
* This annotation can be applied to a package, class or method to indicate that
* the method parameters in that element are nonnull by default unless there is:
* <ul>
* <li>An explicit nullness annotation
* <li>The method overrides a method in a superclass (in which case the
* annotation of the corresponding parameter in the superclass applies)
* <li>There is a default parameter annotation (like {@link ParametersAreNullableByDefault})
* applied to a more tightly nested element.
* </ul>
*
* @see Nonnull
*/
@Documented
@Nonnull
@TypeQualifierDefault(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface ParametersAreNonnullByDefault {
}
@@ -0,0 +1,58 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// FILE: FieldsAreNullable.java
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.annotation.Nonnull;
import javax.annotation.CheckForNull;
import javax.annotation.meta.TypeQualifierDefault;
@Retention(RetentionPolicy.RUNTIME)
@Documented
@CheckForNull
@TypeQualifierDefault({ElementType.FIELD})
public @interface FieldsAreNullable {
}
// FILE: A.java
import javax.annotation.*;
@FieldsAreNullable
public class A {
public String field = null;
@Nonnull
public String nonNullField = "";
public String foo(String q, @Nonnull String x, @CheckForNull CharSequence y) {
return "";
}
@Nonnull
public String bar() {
return "";
}
}
// FILE: main.kt
fun main(a: A) {
// foo is platform
a.foo("", "", null)?.length
a.foo("", "", null).length
a.foo(null, <!NULL_FOR_NONNULL_TYPE!>null<!>, "").length
a.bar().length
a.bar()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.length
a.field?.length
a.field<!UNSAFE_CALL!>.<!>length
a.field = null
a.nonNullField<!UNNECESSARY_SAFE_CALL!>?.<!>length
a.nonNullField.length
a.nonNullField = <!NULL_FOR_NONNULL_TYPE!>null<!>
}
@@ -0,0 +1,21 @@
package
public fun main(/*0*/ a: A): kotlin.Unit
@FieldsAreNullable public open class A {
public constructor A()
public final var field: kotlin.String?
@javax.annotation.Nonnull public final var nonNullField: kotlin.String
@javax.annotation.Nonnull public open fun bar(): kotlin.String
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open fun foo(/*0*/ q: kotlin.String!, /*1*/ @javax.annotation.Nonnull x: kotlin.String, /*2*/ @javax.annotation.CheckForNull y: kotlin.CharSequence?): kotlin.String!
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@kotlin.annotation.Retention(value = AnnotationRetention.RUNTIME) @kotlin.annotation.MustBeDocumented @javax.annotation.CheckForNull @javax.annotation.meta.TypeQualifierDefault(value = {ElementType.FIELD}) public final annotation class FieldsAreNullable : kotlin.Annotation {
public constructor FieldsAreNullable()
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
}
@@ -0,0 +1,158 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// FILE: NonNullApi.java
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.annotation.Nonnull;
import javax.annotation.meta.TypeQualifierDefault;
@Target(ElementType.CLASS)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Nonnull
@TypeQualifierDefault({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
public @interface NonNullApi {
}
// FILE: NullableApi.java
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.annotation.CheckForNull;
import javax.annotation.meta.TypeQualifierDefault;
@Target(ElementType.CLASS)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@CheckForNull
@TypeQualifierDefault({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
public @interface NullableApi {
}
// FILE: A.java
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import javax.annotation.Nonnull;
@NonNullApi
public class A {
public String foo1(String x) { return ""; }
public String foo2(String x) { return ""; }
public String foo3(String x) { return ""; }
@Nullable
public String bar1(@Nullable String x) { return ""; }
@Nullable
public String bar2(@Nullable String x) { return ""; }
public String baz(@Nonnull String x) { return ""; }
}
// FILE: AInt.java
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import javax.annotation.Nonnull;
@NonNullApi
public interface AInt {
public CharSequence foo1(String x);
public CharSequence foo2(String x);
public CharSequence foo3(String x);
@Nullable
public CharSequence bar1(@Nullable String x);
@Nullable
public CharSequence bar2(@Nullable String x);
public CharSequence baz(@Nonnull String x);
}
// FILE: B.java
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import javax.annotation.Nonnull;
@NullableApi
public class B extends A implements AInt {
// conflicts
public String foo1(String x) { return ""; }
// no conflicts
@Nonnull
public String foo2(@Nonnull String x) { return ""; }
// fake override for foo3 shouldn't have any conflicts
// no conflicts
public String bar1(String x) { return ""; }
// conflicts
public String baz(String x) { return ""; }
}
// FILE: C.java
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import javax.annotation.Nonnull;
@NonNullApi
public class C extends A implements AInt {
// no conflicts
public String foo1(String x) { return ""; }
// no conflicts
public String foo2(@Nonnull String x) { return ""; }
// fake override for foo3 shouldn't have any conflicts
// no conflicts, covariant override
public String bar1(String x) { return ""; }
// no conflicts
@Nullable
public String bar2(@Nullable String x) { return ""; }
// no conflicts
public String baz(String x) { return ""; }
}
// FILE: main.kt
fun main(a: A, b: B, c: C) {
a.foo1(<!NULL_FOR_NONNULL_TYPE!>null<!>).length
a.foo2(<!NULL_FOR_NONNULL_TYPE!>null<!>).length
a.foo3(<!NULL_FOR_NONNULL_TYPE!>null<!>).length
a.bar1(null)<!UNSAFE_CALL!>.<!>length
a.bar2(null)<!UNSAFE_CALL!>.<!>length
a.baz(<!NULL_FOR_NONNULL_TYPE!>null<!>).length
b.foo1(null).length
b.foo1(null)?.length
b.foo2(<!NULL_FOR_NONNULL_TYPE!>null<!>).length
b.foo3(<!NULL_FOR_NONNULL_TYPE!>null<!>).length
b.bar1(null)<!UNSAFE_CALL!>.<!>length
b.bar2(null)<!UNSAFE_CALL!>.<!>length
b.baz(null).length
b.baz(null)?.length
c.foo1(<!NULL_FOR_NONNULL_TYPE!>null<!>).length
c.foo2(<!NULL_FOR_NONNULL_TYPE!>null<!>).length
c.foo3(<!NULL_FOR_NONNULL_TYPE!>null<!>).length
c.bar1(null).length
c.bar1(null)<!UNNECESSARY_SAFE_CALL!>?.<!>length
c.bar2(null)<!UNSAFE_CALL!>.<!>length
c.baz(<!NULL_FOR_NONNULL_TYPE!>null<!>).length
}
@@ -0,0 +1,68 @@
package
public fun main(/*0*/ a: A, /*1*/ b: B, /*2*/ c: C): kotlin.Unit
@NonNullApi public open class A {
public constructor A()
@javax.annotation.Nullable public open fun bar1(/*0*/ @javax.annotation.Nullable x: kotlin.String?): kotlin.String?
@javax.annotation.Nullable public open fun bar2(/*0*/ @javax.annotation.Nullable x: kotlin.String?): kotlin.String?
public open fun baz(/*0*/ @javax.annotation.Nonnull x: kotlin.String): kotlin.String
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open fun foo1(/*0*/ x: kotlin.String): kotlin.String
public open fun foo2(/*0*/ x: kotlin.String): kotlin.String
public open fun foo3(/*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
}
@NonNullApi public interface AInt {
@javax.annotation.Nullable public abstract fun bar1(/*0*/ @javax.annotation.Nullable x: kotlin.String?): kotlin.CharSequence?
@javax.annotation.Nullable public abstract fun bar2(/*0*/ @javax.annotation.Nullable x: kotlin.String?): kotlin.CharSequence?
public abstract fun baz(/*0*/ @javax.annotation.Nonnull x: kotlin.String): kotlin.CharSequence
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public abstract fun foo1(/*0*/ x: kotlin.String): kotlin.CharSequence
public abstract fun foo2(/*0*/ x: kotlin.String): kotlin.CharSequence
public abstract fun foo3(/*0*/ x: kotlin.String): kotlin.CharSequence
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@NullableApi public open class B : A, AInt {
public constructor B()
public open override /*2*/ fun bar1(/*0*/ x: kotlin.String?): kotlin.String?
@javax.annotation.Nullable public open override /*2*/ /*fake_override*/ fun bar2(/*0*/ @javax.annotation.Nullable x: kotlin.String?): kotlin.String?
public open override /*2*/ fun baz(/*0*/ x: kotlin.String!): kotlin.String!
public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*2*/ fun foo1(/*0*/ x: kotlin.String!): kotlin.String!
@javax.annotation.Nonnull public open override /*2*/ fun foo2(/*0*/ @javax.annotation.Nonnull x: kotlin.String): kotlin.String
public open override /*2*/ /*fake_override*/ fun foo3(/*0*/ x: kotlin.String): kotlin.String
public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String
}
@NonNullApi public open class C : A, AInt {
public constructor C()
public open override /*2*/ fun bar1(/*0*/ x: kotlin.String!): kotlin.String
@javax.annotation.Nullable public open override /*2*/ fun bar2(/*0*/ @javax.annotation.Nullable x: kotlin.String?): kotlin.String?
public open override /*2*/ fun baz(/*0*/ x: kotlin.String): kotlin.String
public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*2*/ fun foo1(/*0*/ x: kotlin.String): kotlin.String
public open override /*2*/ fun foo2(/*0*/ @javax.annotation.Nonnull x: kotlin.String): kotlin.String
public open override /*2*/ /*fake_override*/ fun foo3(/*0*/ x: kotlin.String): kotlin.String
public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String
}
@kotlin.annotation.Target(allowedTargets = {}) @kotlin.annotation.Retention(value = AnnotationRetention.RUNTIME) @kotlin.annotation.MustBeDocumented @javax.annotation.Nonnull @javax.annotation.meta.TypeQualifierDefault(value = {ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD}) public final annotation class NonNullApi : kotlin.Annotation {
public constructor NonNullApi()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@kotlin.annotation.Target(allowedTargets = {}) @kotlin.annotation.Retention(value = AnnotationRetention.RUNTIME) @kotlin.annotation.MustBeDocumented @javax.annotation.CheckForNull @javax.annotation.meta.TypeQualifierDefault(value = {ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD}) 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
}
@@ -0,0 +1,186 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// FILE: NonNullApi.java
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.annotation.Nonnull;
import javax.annotation.meta.TypeQualifierDefault;
@Target(ElementType.PACKAGE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Nonnull
@TypeQualifierDefault({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
public @interface NonNullApi {
}
// FILE: NullableApi.java
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.annotation.CheckForNull;
import javax.annotation.meta.TypeQualifierDefault;
@Target(ElementType.PACKAGE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@CheckForNull
@TypeQualifierDefault({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
public @interface NullableApi {
}
// FILE: FieldsAreNullable.java
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.annotation.Nonnull;
import javax.annotation.CheckForNull;
import javax.annotation.meta.TypeQualifierDefault;
@Retention(RetentionPolicy.RUNTIME)
@Documented
@CheckForNull
@TypeQualifierDefault({ElementType.FIELD})
public @interface FieldsAreNullable {
}
// FILE: A.java
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import javax.annotation.Nonnull;
@NonNullApi
public class A {
public String field = null;
public String foo(String x, @CheckForNull CharSequence y) {
return "";
}
@NullableApi
public String foobar(String x, @Nonnull CharSequence y) {
return "";
}
public String bar() {
return "";
}
@Nullable
public java.util.List<String> baz() {
return null;
}
@NullableApi
public class B {
public String field = null;
public String foo(String x, @Nonnull CharSequence y) {
return "";
}
@NonNullApi
public String foobar(String x, @Nullable CharSequence y) {
return "";
}
public String bar() {
return "";
}
@Nullable
public java.util.List<String> baz() {
return null;
}
}
@FieldsAreNullable
public class C {
public String field = null;
public String foo(String x, @Nullable CharSequence y) {
return "";
}
@NullableApi
public String foobar(String x, @Nullable CharSequence y) {
return "";
}
public String bar() {
return "";
}
@Nullable
public java.util.List<String> baz() {
return null;
}
}
}
// FILE: main.kt
fun main(a: A, b: A.B, c: A.C) {
a.foo("", null)<!UNNECESSARY_SAFE_CALL!>?.<!>length
a.foo("", null).length
a.foo(<!NULL_FOR_NONNULL_TYPE!>null<!>, "").length
a.foobar(null, "")<!UNSAFE_CALL!>.<!>length
a.foobar("", <!NULL_FOR_NONNULL_TYPE!>null<!>)?.length
a.bar().length
a.bar()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.length
a.field<!UNNECESSARY_SAFE_CALL!>?.<!>length
a.field.length
a.baz()<!UNSAFE_CALL!>.<!>get(0)
a.baz()!!.get(0).get(0)
a.baz()!!.get(0)?.get(0)
// b
b.foo("", <!NULL_FOR_NONNULL_TYPE!>null<!>)?.length
b.foo("", <!NULL_FOR_NONNULL_TYPE!>null<!>)<!UNSAFE_CALL!>.<!>length
b.foo(null, "")<!UNSAFE_CALL!>.<!>length
b.foobar(<!NULL_FOR_NONNULL_TYPE!>null<!>, "").length
b.foobar("", null)<!UNNECESSARY_SAFE_CALL!>?.<!>length
b.bar()<!UNSAFE_CALL!>.<!>length
b.bar()!!.length
b.field?.length
b.field<!UNSAFE_CALL!>.<!>length
b.baz()<!UNSAFE_CALL!>.<!>get(0)
b.baz()!!.get(0).get(0)
b.baz()!!.get(0)?.get(0)
// c
c.foo("", null)<!UNNECESSARY_SAFE_CALL!>?.<!>length
c.foo("", null).length
c.foo(<!NULL_FOR_NONNULL_TYPE!>null<!>, "").length
c.foobar(null, "")<!UNSAFE_CALL!>.<!>length
c.foobar("", null)?.length
c.bar().length
c.bar()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.length
c.field?.length
c.field<!UNSAFE_CALL!>.<!>length
c.baz()<!UNSAFE_CALL!>.<!>get(0)
c.baz()!!.get(0).get(0)
c.baz()!!.get(0)?.get(0)
}
@@ -0,0 +1,60 @@
package
public fun main(/*0*/ a: A, /*1*/ b: A.B, /*2*/ c: A.C): kotlin.Unit
@NonNullApi public open class A {
public constructor A()
public final var field: kotlin.String
public open fun bar(): kotlin.String
@javax.annotation.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 fun foo(/*0*/ x: kotlin.String, /*1*/ @javax.annotation.CheckForNull y: kotlin.CharSequence?): kotlin.String
@NullableApi public open fun foobar(/*0*/ x: kotlin.String?, /*1*/ @javax.annotation.Nonnull y: kotlin.CharSequence): kotlin.String?
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
@NullableApi public open inner class B {
public constructor B()
public final var field: kotlin.String?
public open fun bar(): kotlin.String?
@javax.annotation.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 fun foo(/*0*/ x: kotlin.String?, /*1*/ @javax.annotation.Nonnull y: kotlin.CharSequence): kotlin.String?
@NonNullApi public open fun foobar(/*0*/ x: kotlin.String, /*1*/ @javax.annotation.Nullable y: kotlin.CharSequence?): kotlin.String
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@FieldsAreNullable public open inner class C {
public constructor C()
public final var field: kotlin.String?
public open fun bar(): kotlin.String
@javax.annotation.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 fun foo(/*0*/ x: kotlin.String, /*1*/ @javax.annotation.Nullable y: kotlin.CharSequence?): kotlin.String
@NullableApi public open fun foobar(/*0*/ x: kotlin.String?, /*1*/ @javax.annotation.Nullable y: kotlin.CharSequence?): kotlin.String?
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
}
@kotlin.annotation.Retention(value = AnnotationRetention.RUNTIME) @kotlin.annotation.MustBeDocumented @javax.annotation.CheckForNull @javax.annotation.meta.TypeQualifierDefault(value = {ElementType.FIELD}) public final annotation class FieldsAreNullable : kotlin.Annotation {
public constructor FieldsAreNullable()
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 = {}) @kotlin.annotation.Retention(value = AnnotationRetention.RUNTIME) @kotlin.annotation.MustBeDocumented @javax.annotation.Nonnull @javax.annotation.meta.TypeQualifierDefault(value = {ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD}) public final annotation class NonNullApi : kotlin.Annotation {
public constructor NonNullApi()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@kotlin.annotation.Target(allowedTargets = {}) @kotlin.annotation.Retention(value = AnnotationRetention.RUNTIME) @kotlin.annotation.MustBeDocumented @javax.annotation.CheckForNull @javax.annotation.meta.TypeQualifierDefault(value = {ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD}) 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
}
@@ -0,0 +1,33 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// FILE: A.java
import javax.annotation.*;
@ParametersAreNonnullByDefault
public class A {
@Nullable public String field = null;
public String foo(String q, @Nonnull String x, @CheckForNull CharSequence y) {
return "";
}
@Nonnull
public String bar() {
return "";
}
}
// FILE: main.kt
fun main(a: A) {
// foo is platform
a.foo("", "", null)?.length
a.foo("", "", null).length
a.foo(<!NULL_FOR_NONNULL_TYPE!>null<!>, <!NULL_FOR_NONNULL_TYPE!>null<!>, "").length
a.bar().length
a.bar()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.length
a.field?.length
a.field<!UNSAFE_CALL!>.<!>length
}
@@ -0,0 +1,13 @@
package
public fun main(/*0*/ a: A): kotlin.Unit
@javax.annotation.ParametersAreNonnullByDefault public open class A {
public constructor A()
@javax.annotation.Nullable public final var field: kotlin.String?
@javax.annotation.Nonnull public open fun bar(): kotlin.String
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open fun foo(/*0*/ q: kotlin.String, /*1*/ @javax.annotation.Nonnull x: kotlin.String, /*2*/ @javax.annotation.CheckForNull y: kotlin.CharSequence?): kotlin.String!
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,73 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// RENDER_PACKAGE: test
// RENDER_PACKAGE: test2
// FILE: test/package-info.java
@javax.annotation.ParametersAreNonnullByDefault()
package test;
// FILE: test/A.java
package test;
import javax.annotation.*;
public class A {
@Nullable public String field = null;
public String foo(String q, @Nonnull String x, @CheckForNull CharSequence y) {
return "";
}
@Nonnull
public String bar() {
return "";
}
}
// FILE: test2/A2.java
package test2;
import javax.annotation.*;
public class A2 {
@Nullable public String field = null;
public String foo(String q, @Nonnull String x, @CheckForNull CharSequence y) {
return "";
}
@Nonnull
public String bar() {
return "";
}
}
// FILE: main.kt
import test.A
import test2.A2
fun main(a: A, a2: A2) {
a.foo("", "", null)?.length
a.foo("", "", null).length
a.foo(<!NULL_FOR_NONNULL_TYPE!>null<!>, <!NULL_FOR_NONNULL_TYPE!>null<!>, "").length
a.bar().length
a.bar()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.length
a.field?.length
a.field<!UNSAFE_CALL!>.<!>length
a2.foo("", "", null)?.length
a2.foo("", "", null).length
a2.foo(null, <!NULL_FOR_NONNULL_TYPE!>null<!>, "").length
a2.bar().length
a2.bar()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.length
a2.field?.length
a2.field<!UNSAFE_CALL!>.<!>length
}
@@ -0,0 +1,27 @@
package test
public open class A {
public constructor A()
@javax.annotation.Nullable public final var field: kotlin.String?
@javax.annotation.Nonnull public open fun bar(): kotlin.String
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open fun foo(/*0*/ q: kotlin.String, /*1*/ @javax.annotation.Nonnull x: kotlin.String, /*2*/ @javax.annotation.CheckForNull y: kotlin.CharSequence?): kotlin.String!
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
package test2
public open class A2 {
public constructor A2()
@javax.annotation.Nullable public final var field: kotlin.String?
@javax.annotation.Nonnull public open fun bar(): kotlin.String
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open fun foo(/*0*/ q: kotlin.String!, /*1*/ @javax.annotation.Nonnull x: kotlin.String, /*2*/ @javax.annotation.CheckForNull y: kotlin.CharSequence?): kotlin.String!
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
package
public fun main(/*0*/ a: test.A, /*1*/ a2: test2.A2): kotlin.Unit
@@ -0,0 +1,82 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// 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.METHOD, ElementType.PARAMETER})
@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.CLASS)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Nonnull
@TypeQualifierDefault({ElementType.METHOD, ElementType.PARAMETER})
public @interface NonNullApi {
}
// FILE: A.java
import spr.*;
@NonNullApi
public class A {
public String field = null;
public String foo(String x, @Nullable CharSequence y) {
return "";
}
public String bar() {
return "";
}
@Nullable
public java.util.List<String> baz() {
return null;
}
}
// FILE: main.kt
fun main(a: A) {
a.foo("", null)<!UNNECESSARY_SAFE_CALL!>?.<!>length
a.foo("", null).length
a.foo(<!NULL_FOR_NONNULL_TYPE!>null<!>, "").length
a.bar().length
a.bar()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.length
a.field?.length
a.field.length
a.baz()<!UNSAFE_CALL!>.<!>get(0)
a.baz()!!.get(0).get(0)
a.baz()!!.get(0)?.get(0)
}
@@ -0,0 +1,14 @@
package
public fun main(/*0*/ a: A): kotlin.Unit
@spr.NonNullApi public open class A {
public constructor A()
public final var field: kotlin.String!
public open fun bar(): 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 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 toString(): kotlin.String
}
@@ -0,0 +1,89 @@
// !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.METHOD, ElementType.PARAMETER})
@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.METHOD, ElementType.PARAMETER})
public @interface NonNullApi {
}
// FILE: test/package-info.java
@spr.NonNullApi()
package test;
// FILE: test/A.java
package test;
import spr.*;
public class A {
public String field = null;
public String foo(String x, @Nullable CharSequence y) {
return "";
}
public String bar() {
return "";
}
@Nullable
public java.util.List<String> baz() {
return null;
}
}
// FILE: main.kt
fun main(a: test.A) {
a.foo("", null)<!UNNECESSARY_SAFE_CALL!>?.<!>length
a.foo("", null).length
a.foo(<!NULL_FOR_NONNULL_TYPE!>null<!>, "").length
a.bar().length
a.bar()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.length
a.field?.length
a.field.length
a.baz()<!UNSAFE_CALL!>.<!>get(0)
a.baz()!!.get(0).get(0)
a.baz()!!.get(0)?.get(0)
}
@@ -0,0 +1,16 @@
package test
public open class A {
public constructor A()
public final var field: kotlin.String!
public open fun bar(): 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 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 toString(): kotlin.String
}
package
public fun main(/*0*/ a: test.A): kotlin.Unit
@@ -0,0 +1,16 @@
package javax.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.annotation.meta.TypeQualifierNickname;
import javax.annotation.meta.When;
@Documented
@TypeQualifierNickname
@Nonnull(when = When.MAYBE)
@Retention(RetentionPolicy.RUNTIME)
public @interface CheckForNull {
}
@@ -0,0 +1,26 @@
package javax.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.annotation.meta.TypeQualifier;
import javax.annotation.meta.TypeQualifierValidator;
import javax.annotation.meta.When;
@Documented
@TypeQualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface Nonnull {
When when() default When.ALWAYS;
static class Checker implements TypeQualifierValidator<Nonnull> {
public When forConstantValue(Nonnull qualifierqualifierArgument,
Object value) {
if (value == null)
return When.NEVER;
return When.ALWAYS;
}
}
}
@@ -0,0 +1,16 @@
package javax.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.annotation.meta.TypeQualifierNickname;
import javax.annotation.meta.When;
@Documented
@TypeQualifierNickname
@Nonnull(when = When.UNKNOWN)
@Retention(RetentionPolicy.RUNTIME)
public @interface Nullable {
}
@@ -0,0 +1,28 @@
package javax.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.annotation.meta.TypeQualifierDefault;
/**
* This annotation can be applied to a package, class or method to indicate that
* the method parameters in that element are nonnull by default unless there is:
* <ul>
* <li>An explicit nullness annotation
* <li>The method overrides a method in a superclass (in which case the
* annotation of the corresponding parameter in the superclass applies)
* <li>There is a default parameter annotation (like {@link ParametersAreNullableByDefault})
* applied to a more tightly nested element.
* </ul>
*
* @see Nonnull
*/
@Documented
@Nonnull
@TypeQualifierDefault(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface ParametersAreNonnullByDefault {
}
@@ -0,0 +1,27 @@
package javax.annotation.meta;
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;
/**
* This qualifier is applied to an annotation to denote that the annotation
* should be treated as a type qualifier.
*/
@Documented
@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TypeQualifier {
/**
* Describes the kinds of values the qualifier can be applied to. If a
* numeric class is provided (e.g., Number.class or Integer.class) then the
* annotation can also be applied to the corresponding primitive numeric
* types.
*/
Class<?> applicableTo() default Object.class;
}
@@ -0,0 +1,20 @@
package javax.annotation.meta;
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;
/**
* This qualifier is applied to an annotation to denote that the annotation
* defines a default type qualifier that is visible within the scope of the
* element it is applied to.
*/
@Documented
@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TypeQualifierDefault {
ElementType[] value() default {};
}
@@ -0,0 +1,33 @@
package javax.annotation.meta;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
/**
*
* This annotation is applied to a annotation, and marks the annotation as being
* a qualifier nickname. Applying a nickname annotation X to a element Y should
* be interpreted as having the same meaning as applying all of annotations of X
* (other than QualifierNickname) to Y.
*
* <p>
* Thus, you might define a qualifier SocialSecurityNumber as follows:
* </p>
*
*
* <code>
@Documented
@TypeQualifierNickname @Pattern("[0-9]{3}-[0-9]{2}-[0-9]{4}")
@Retention(RetentionPolicy.RUNTIME)
public @interface SocialSecurityNumber {
}
</code>
*
*
*/
@Documented
@Target(ElementType.ANNOTATION_TYPE)
public @interface TypeQualifierNickname {
}
@@ -0,0 +1,21 @@
package javax.annotation.meta;
import java.lang.annotation.Annotation;
import javax.annotation.Nonnull;
public interface TypeQualifierValidator<A extends Annotation> {
/**
* Given a type qualifier, check to see if a known specific constant value
* is an instance of the set of values denoted by the qualifier.
*
* @param annotation
* the type qualifier
* @param value
* the value to check
* @return a value indicating whether or not the value is an member of the
* values denoted by the type qualifier
*/
public @Nonnull
When forConstantValue(@Nonnull A annotation, Object value);
}
@@ -0,0 +1,23 @@
package javax.annotation.meta;
/**
* Used to describe the relationship between a qualifier T and the set of values
* S possible on an annotated element.
*
* In particular, an issues should be reported if an ALWAYS or MAYBE value is
* used where a NEVER value is required, or if a NEVER or MAYBE value is used
* where an ALWAYS value is required.
*
*
*/
public enum When {
/** S is a subset of T */
ALWAYS,
/** nothing definitive is known about the relation between S and T */
UNKNOWN,
/** S intersection T is non empty and S - T is nonempty */
MAYBE,
/** S intersection T is empty */
NEVER;
}
@@ -0,0 +1,82 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// 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.METHOD, ElementType.PARAMETER})
@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.CLASS)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Nonnull
@TypeQualifierDefault({ElementType.TYPE_USE})
public @interface NonNullApi {
}
// FILE: A.java
import spr.*;
@NonNullApi
public class A {
public String field = null;
public String foo(String x, @Nullable CharSequence y) {
return "";
}
public String bar() {
return "";
}
@Nullable
public java.util.List<String> baz() {
return null;
}
}
// FILE: main.kt
fun main(a: A) {
a.foo("", null)<!UNNECESSARY_SAFE_CALL!>?.<!>length
a.foo("", null).length
a.foo(<!NULL_FOR_NONNULL_TYPE!>null<!>, "").length
a.bar().length
a.bar()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.length
a.field<!UNNECESSARY_SAFE_CALL!>?.<!>length
a.field.length
a.baz()<!UNSAFE_CALL!>.<!>get(0)
a.baz()!!.get(0).get(0)
a.baz()!!.get(0)?.get(0)
}
@@ -0,0 +1,14 @@
package
public fun main(/*0*/ a: A): kotlin.Unit
@spr.NonNullApi public open class A {
public constructor A()
public final var field: kotlin.String
public open fun bar(): 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 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 toString(): kotlin.String
}
@@ -66,6 +66,7 @@ import org.jetbrains.kotlin.test.util.DescriptorValidator
import org.jetbrains.kotlin.test.util.RecursiveDescriptorComparator import org.jetbrains.kotlin.test.util.RecursiveDescriptorComparator
import org.jetbrains.kotlin.test.util.RecursiveDescriptorComparator.RECURSIVE import org.jetbrains.kotlin.test.util.RecursiveDescriptorComparator.RECURSIVE
import org.jetbrains.kotlin.test.util.RecursiveDescriptorComparator.RECURSIVE_ALL import org.jetbrains.kotlin.test.util.RecursiveDescriptorComparator.RECURSIVE_ALL
import org.jetbrains.kotlin.utils.keysToMap
import org.junit.Assert import org.junit.Assert
import java.io.File import java.io.File
import java.util.* import java.util.*
@@ -363,7 +364,15 @@ abstract class AbstractDiagnosticsTest : BaseDiagnosticsTest() {
val comparator = RecursiveDescriptorComparator(createdAffectedPackagesConfiguration(testFiles, modules.values)) val comparator = RecursiveDescriptorComparator(createdAffectedPackagesConfiguration(testFiles, modules.values))
val isMultiModuleTest = modules.size != 1 val isMultiModuleTest = modules.size != 1
val rootPackageText = StringBuilder()
val packages =
(testFiles.flatMap {
InTextDirectivesUtils.findListWithPrefixes(it.expectedText, "// RENDER_PACKAGE:").map {
FqName(it.trim())
}
} + FqName.ROOT).toSet()
val textByPackage = packages.keysToMap { StringBuilder() }
val sortedModules = modules.keys.sortedWith(Comparator { x, y -> val sortedModules = modules.keys.sortedWith(Comparator { x, y ->
when { when {
@@ -375,32 +384,37 @@ abstract class AbstractDiagnosticsTest : BaseDiagnosticsTest() {
} }
}) })
val module = sortedModules.iterator() for ((packageName, packageText) in textByPackage.entries) {
while (module.hasNext()) { val module = sortedModules.iterator()
val moduleDescriptor = modules[module.next()]!! while (module.hasNext()) {
val aPackage = moduleDescriptor.getPackage(FqName.ROOT) val moduleDescriptor = modules[module.next()]!!
assertFalse(aPackage.isEmpty())
if (isMultiModuleTest) { val aPackage = moduleDescriptor.getPackage(packageName)
rootPackageText.append(String.format("// -- Module: %s --\n", moduleDescriptor.name)) assertFalse(aPackage.isEmpty())
}
val actualSerialized = comparator.serializeRecursively(aPackage) if (isMultiModuleTest) {
rootPackageText.append(actualSerialized) packageText.append(String.format("// -- Module: %s --\n", moduleDescriptor.name))
}
if (isMultiModuleTest && module.hasNext()) { val actualSerialized = comparator.serializeRecursively(aPackage)
rootPackageText.append("\n\n") packageText.append(actualSerialized)
if (isMultiModuleTest && module.hasNext()) {
packageText.append("\n\n")
}
} }
} }
val lineCount = StringUtil.getLineBreakCount(rootPackageText) val allPackagesText = textByPackage.values.joinToString("\n")
val lineCount = StringUtil.getLineBreakCount(allPackagesText)
assert(lineCount < 1000) { assert(lineCount < 1000) {
"Rendered descriptors of this test take up $lineCount lines. " + "Rendered descriptors of this test take up $lineCount lines. " +
"Please ensure you don't render JRE contents to the .txt file. " + "Please ensure you don't render JRE contents to the .txt file. " +
"Such tests are hard to maintain, take long time to execute and are subject to sudden unreviewed changes anyway." "Such tests are hard to maintain, take long time to execute and are subject to sudden unreviewed changes anyway."
} }
KotlinTestUtils.assertEqualsToFile(expectedFile, rootPackageText.toString()) KotlinTestUtils.assertEqualsToFile(expectedFile, allPackagesText)
} }
private fun createdAffectedPackagesConfiguration( private fun createdAffectedPackagesConfiguration(
@@ -48,6 +48,12 @@ public class ForeignJava8AnnotationsTestGenerated extends AbstractForeignJava8An
doTest(fileName); doTest(fileName);
} }
@TestMetadata("springNullableWithTypeUse.kt")
public void testSpringNullableWithTypeUse() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotationsJava8/tests/springNullableWithTypeUse.kt");
doTest(fileName);
}
@TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/typeEnhancement") @TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/typeEnhancement")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
@@ -89,4 +89,55 @@ public class ForeignAnnotationsTestGenerated extends AbstractForeignAnnotationsT
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/rxjava.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/rxjava.kt");
doTest(fileName); doTest(fileName);
} }
@TestMetadata("compiler/testData/foreignAnnotations/tests/typeQualifierDefault")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class TypeQualifierDefault extends AbstractForeignAnnotationsTest {
public void testAllFilesPresentInTypeQualifierDefault() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/foreignAnnotations/tests/typeQualifierDefault"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("fieldsAreNullable.kt")
public void testFieldsAreNullable() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/typeQualifierDefault/fieldsAreNullable.kt");
doTest(fileName);
}
@TestMetadata("nullabilityFromOverridden.kt")
public void testNullabilityFromOverridden() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/typeQualifierDefault/nullabilityFromOverridden.kt");
doTest(fileName);
}
@TestMetadata("overridingDefaultQualifier.kt")
public void testOverridingDefaultQualifier() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/typeQualifierDefault/overridingDefaultQualifier.kt");
doTest(fileName);
}
@TestMetadata("parametersAreNonnullByDefault.kt")
public void testParametersAreNonnullByDefault() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/typeQualifierDefault/parametersAreNonnullByDefault.kt");
doTest(fileName);
}
@TestMetadata("parametersAreNonnullByDefaultPackage.kt")
public void testParametersAreNonnullByDefaultPackage() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/typeQualifierDefault/parametersAreNonnullByDefaultPackage.kt");
doTest(fileName);
}
@TestMetadata("springNullable.kt")
public void testSpringNullable() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/typeQualifierDefault/springNullable.kt");
doTest(fileName);
}
@TestMetadata("springNullablePackage.kt")
public void testSpringNullablePackage() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/typeQualifierDefault/springNullablePackage.kt");
doTest(fileName);
}
}
} }
@@ -68,10 +68,10 @@ class LoadJavaPackageAnnotationsTest : KtUsefulTestCase() {
it.getMemberScope().getContributedClassifier(Name.identifier("A"), NoLookupLocation.FROM_TEST) != null it.getMemberScope().getContributedClassifier(Name.identifier("A"), NoLookupLocation.FROM_TEST) != null
}.let { assertInstanceOf(it, LazyJavaPackageFragment::class.java) } }.let { assertInstanceOf(it, LazyJavaPackageFragment::class.java) }
val annotation = packageFragmentDescriptor.getPackageAnnotations().findAnnotation(FqName("test.Ann")) val annotation = packageFragmentDescriptor.annotations.findAnnotation(FqName("test.Ann"))
assertNotNull(annotation) assertNotNull(annotation)
val singleAnnotation = packageFragmentDescriptor.getPackageAnnotations().singleOrNull() val singleAnnotation = packageFragmentDescriptor.annotations.singleOrNull()
assertNotNull(singleAnnotation) assertNotNull(singleAnnotation)
val annotationFqName = singleAnnotation!!.type.constructor.declarationDescriptor?.fqNameSafe val annotationFqName = singleAnnotation!!.type.constructor.declarationDescriptor?.fqNameSafe
@@ -20,12 +20,16 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.constants.ArrayValue
import org.jetbrains.kotlin.resolve.constants.ConstantValue
import org.jetbrains.kotlin.resolve.constants.EnumValue
import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass
import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
private val TYPE_QUALIFIER_NICKNAME_FQNAME = FqName("javax.annotation.meta.TypeQualifierNickname") private val TYPE_QUALIFIER_NICKNAME_FQNAME = FqName("javax.annotation.meta.TypeQualifierNickname")
private val TYPE_QUALIFIER_FQNAME = FqName("javax.annotation.meta.TypeQualifier") private val TYPE_QUALIFIER_FQNAME = FqName("javax.annotation.meta.TypeQualifier")
private val TYPE_QUALIFIER_DEFAULT_FQNAME = FqName("javax.annotation.meta.TypeQualifierDefault")
class AnnotationTypeQualifierResolver(storageManager: StorageManager) { class AnnotationTypeQualifierResolver(storageManager: StorageManager) {
private val resolvedNicknames = private val resolvedNicknames =
@@ -49,6 +53,58 @@ class AnnotationTypeQualifierResolver(storageManager: StorageManager) {
return resolveTypeQualifierNickname(annotationClass) return resolveTypeQualifierNickname(annotationClass)
} }
enum class QualifierApplicabilityType {
METHOD_RETURN_TYPE, VALUE_PARAMETER, FIELD, TYPE_USE
}
class TypeQualifierWithApplicability(
private val typeQualifier: AnnotationDescriptor,
private val applicability: Int
) {
private fun isApplicableTo(elementType: QualifierApplicabilityType) = (applicability and (1 shl elementType.ordinal)) != 0
operator fun component1() = typeQualifier
operator fun component2() = QualifierApplicabilityType.values().filter(this::isApplicableTo)
}
fun resolveTypeQualifierDefaultAnnotation(annotationDescriptor: AnnotationDescriptor): TypeQualifierWithApplicability? {
val typeQualifierDefaultAnnotatedClass =
annotationDescriptor.annotationClass?.takeIf { it.annotations.hasAnnotation(TYPE_QUALIFIER_DEFAULT_FQNAME) }
?: return null
val elementTypesMask =
annotationDescriptor.annotationClass!!
.annotations.findAnnotation(TYPE_QUALIFIER_DEFAULT_FQNAME)!!
.allValueArguments
.flatMap { (parameter, argument) ->
if (parameter.name == JvmAnnotationNames.DEFAULT_ANNOTATION_MEMBER_NAME)
argument.mapConstantToQualifierApplicabilityTypes()
else
emptyList()
}
.fold(0) { acc: Int, applicabilityType -> acc or (1 shl applicabilityType.ordinal) }
val typeQualifier =
typeQualifierDefaultAnnotatedClass.annotations.firstNotNullResult(this::resolveTypeQualifierAnnotation)
?: return null
return TypeQualifierWithApplicability(typeQualifier, elementTypesMask)
}
private fun ConstantValue<*>.mapConstantToQualifierApplicabilityTypes(): List<QualifierApplicabilityType> =
when (this) {
is ArrayValue -> value.flatMap { it.mapConstantToQualifierApplicabilityTypes() }
is EnumValue -> listOfNotNull(
when (value.name.identifier) {
"METHOD" -> QualifierApplicabilityType.METHOD_RETURN_TYPE
"FIELD" -> QualifierApplicabilityType.FIELD
"PARAMETER" -> QualifierApplicabilityType.VALUE_PARAMETER
"TYPE_USE" -> QualifierApplicabilityType.TYPE_USE
else -> null
}
)
else -> emptyList()
}
} }
private val ClassDescriptor.isAnnotatedWithTypeQualifier: Boolean private val ClassDescriptor.isAnnotatedWithTypeQualifier: Boolean
@@ -26,7 +26,7 @@ class LazyJavaPackageFragmentProvider(
components: JavaResolverComponents components: JavaResolverComponents
) : PackageFragmentProvider { ) : PackageFragmentProvider {
private val c = LazyJavaResolverContext(components, TypeParameterResolver.EMPTY) private val c = LazyJavaResolverContext(components, TypeParameterResolver.EMPTY) { null }
private val packageFragments: MemoizedFunctionToNullable<FqName, LazyJavaPackageFragment> = private val packageFragments: MemoizedFunctionToNullable<FqName, LazyJavaPackageFragment> =
c.storageManager.createMemoizedFunctionWithNullableValues { c.storageManager.createMemoizedFunctionWithNullableValues {
@@ -17,10 +17,8 @@
package org.jetbrains.kotlin.load.java.lazy package org.jetbrains.kotlin.load.java.lazy
import org.jetbrains.kotlin.builtins.ReflectionTypes import org.jetbrains.kotlin.builtins.ReflectionTypes
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.PackagePartProvider
import org.jetbrains.kotlin.descriptors.SupertypeLoopChecker
import org.jetbrains.kotlin.incremental.components.LookupTracker import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.load.java.AnnotationTypeQualifierResolver import org.jetbrains.kotlin.load.java.AnnotationTypeQualifierResolver
import org.jetbrains.kotlin.load.java.JavaClassFinder import org.jetbrains.kotlin.load.java.JavaClassFinder
@@ -28,11 +26,14 @@ import org.jetbrains.kotlin.load.java.components.*
import org.jetbrains.kotlin.load.java.lazy.types.JavaTypeResolver import org.jetbrains.kotlin.load.java.lazy.types.JavaTypeResolver
import org.jetbrains.kotlin.load.java.sources.JavaSourceElementFactory import org.jetbrains.kotlin.load.java.sources.JavaSourceElementFactory
import org.jetbrains.kotlin.load.java.structure.JavaTypeParameterListOwner import org.jetbrains.kotlin.load.java.structure.JavaTypeParameterListOwner
import org.jetbrains.kotlin.load.java.typeEnhancement.JavaTypeQualifiers
import org.jetbrains.kotlin.load.java.typeEnhancement.NullabilityQualifier
import org.jetbrains.kotlin.load.java.typeEnhancement.SignatureEnhancement import org.jetbrains.kotlin.load.java.typeEnhancement.SignatureEnhancement
import org.jetbrains.kotlin.load.kotlin.DeserializedDescriptorResolver import org.jetbrains.kotlin.load.kotlin.DeserializedDescriptorResolver
import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder
import org.jetbrains.kotlin.serialization.deserialization.ErrorReporter import org.jetbrains.kotlin.serialization.deserialization.ErrorReporter
import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.storage.StorageManager
import java.util.*
class JavaResolverComponents( class JavaResolverComponents(
val storageManager: StorageManager, val storageManager: StorageManager,
@@ -66,10 +67,33 @@ class JavaResolverComponents(
) )
} }
class LazyJavaResolverContext( private typealias QualifierByApplicabilityType = EnumMap<AnnotationTypeQualifierResolver.QualifierApplicabilityType, NullabilityQualifier?>
val components: JavaResolverComponents,
val typeParameterResolver: TypeParameterResolver class JavaTypeQualifiersByElementType(
internal val nullabilityQualifiers: QualifierByApplicabilityType
) { ) {
operator fun get(
applicabilityType: AnnotationTypeQualifierResolver.QualifierApplicabilityType
): JavaTypeQualifiers? =
(
nullabilityQualifiers[applicabilityType]
?: nullabilityQualifiers[AnnotationTypeQualifierResolver.QualifierApplicabilityType.TYPE_USE]
)?.let { JavaTypeQualifiers(it, null, isNotNullTypeParameter = false) }
}
class LazyJavaResolverContext internal constructor(
val components: JavaResolverComponents,
val typeParameterResolver: TypeParameterResolver,
internal val delegateForDefaultTypeQualifiers: Lazy<JavaTypeQualifiersByElementType?>
) {
constructor(
components: JavaResolverComponents,
typeParameterResolver: TypeParameterResolver,
typeQualifiersComputation: () -> JavaTypeQualifiersByElementType?
) : this(components, typeParameterResolver, lazy(LazyThreadSafetyMode.NONE, typeQualifiersComputation))
val defaultTypeQualifiers: JavaTypeQualifiersByElementType? by delegateForDefaultTypeQualifiers
val typeResolver = JavaTypeResolver(this, typeParameterResolver) val typeResolver = JavaTypeResolver(this, typeParameterResolver)
val storageManager: StorageManager val storageManager: StorageManager
@@ -80,14 +104,59 @@ class LazyJavaResolverContext(
fun LazyJavaResolverContext.child( fun LazyJavaResolverContext.child(
typeParameterResolver: TypeParameterResolver typeParameterResolver: TypeParameterResolver
) = LazyJavaResolverContext(components, typeParameterResolver) ) = LazyJavaResolverContext(components, typeParameterResolver, delegateForDefaultTypeQualifiers)
fun LazyJavaResolverContext.computeNewDefaultTypeQualifiers(
additionalAnnotations: Annotations
): JavaTypeQualifiersByElementType? {
val typeQualifierDefaults =
additionalAnnotations.mapNotNull(components.annotationTypeQualifierResolver::resolveTypeQualifierDefaultAnnotation)
if (typeQualifierDefaults.isEmpty()) return defaultTypeQualifiers
val nullabilityQualifiers =
defaultTypeQualifiers?.nullabilityQualifiers?.let(::QualifierByApplicabilityType)
?: QualifierByApplicabilityType(AnnotationTypeQualifierResolver.QualifierApplicabilityType::class.java)
var wasUpdate = false
for ((typeQualifier, applicableTo) in typeQualifierDefaults) {
val nullability = components.signatureEnhancement.extractNullability(typeQualifier) ?: continue
for (applicabilityType in applicableTo) {
nullabilityQualifiers[applicabilityType] = nullability
wasUpdate = true
}
}
return if (!wasUpdate) defaultTypeQualifiers else JavaTypeQualifiersByElementType(nullabilityQualifiers)
}
fun LazyJavaResolverContext.replaceComponents( fun LazyJavaResolverContext.replaceComponents(
components: JavaResolverComponents components: JavaResolverComponents
) = LazyJavaResolverContext(components, typeParameterResolver) ) = LazyJavaResolverContext(components, typeParameterResolver, delegateForDefaultTypeQualifiers)
fun LazyJavaResolverContext.child( private fun LazyJavaResolverContext.child(
containingDeclaration: DeclarationDescriptor,
typeParameterOwner: JavaTypeParameterListOwner?,
typeParametersIndexOffset: Int = 0,
delegateForTypeQualifiers: Lazy<JavaTypeQualifiersByElementType?>
) = LazyJavaResolverContext(
components,
typeParameterOwner?.let { LazyJavaTypeParameterResolver(this, containingDeclaration, it, typeParametersIndexOffset) }
?: typeParameterResolver,
delegateForTypeQualifiers
)
fun LazyJavaResolverContext.childForMethod(
containingDeclaration: DeclarationDescriptor, containingDeclaration: DeclarationDescriptor,
typeParameterOwner: JavaTypeParameterListOwner, typeParameterOwner: JavaTypeParameterListOwner,
typeParametersIndexOffset: Int = 0 typeParametersIndexOffset: Int = 0
) = this.child(LazyJavaTypeParameterResolver(this, containingDeclaration, typeParameterOwner, typeParametersIndexOffset)) ) = child(containingDeclaration, typeParameterOwner, typeParametersIndexOffset, delegateForDefaultTypeQualifiers)
fun LazyJavaResolverContext.childForClassOrPackage(
containingDeclaration: ClassOrPackageFragmentDescriptor,
typeParameterOwner: JavaTypeParameterListOwner? = null,
typeParametersIndexOffset: Int = 0
) = child(
containingDeclaration, typeParameterOwner, typeParametersIndexOffset,
lazy(LazyThreadSafetyMode.NONE) { computeNewDefaultTypeQualifiers(containingDeclaration.annotations) }
)
@@ -28,7 +28,7 @@ import org.jetbrains.kotlin.load.java.components.JavaResolverCache
import org.jetbrains.kotlin.load.java.components.TypeUsage import org.jetbrains.kotlin.load.java.components.TypeUsage
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext
import org.jetbrains.kotlin.load.java.lazy.child import org.jetbrains.kotlin.load.java.lazy.childForClassOrPackage
import org.jetbrains.kotlin.load.java.lazy.replaceComponents import org.jetbrains.kotlin.load.java.lazy.replaceComponents
import org.jetbrains.kotlin.load.java.lazy.resolveAnnotations import org.jetbrains.kotlin.load.java.lazy.resolveAnnotations
import org.jetbrains.kotlin.load.java.lazy.types.toAttributes import org.jetbrains.kotlin.load.java.lazy.types.toAttributes
@@ -64,7 +64,7 @@ class LazyJavaClassDescriptor(
private val PUBLIC_METHOD_NAMES_IN_OBJECT = setOf("equals", "hashCode", "getClass", "wait", "notify", "notifyAll", "toString") private val PUBLIC_METHOD_NAMES_IN_OBJECT = setOf("equals", "hashCode", "getClass", "wait", "notify", "notifyAll", "toString")
} }
private val c: LazyJavaResolverContext = outerContext.child(this, jClass) private val c: LazyJavaResolverContext = outerContext.childForClassOrPackage(this, jClass)
init { init {
c.components.javaResolverCache.recordClass(jClass, this) c.components.javaResolverCache.recordClass(jClass, this)
@@ -37,7 +37,7 @@ 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.descriptors.copyValueParameters import org.jetbrains.kotlin.load.java.descriptors.copyValueParameters
import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext
import org.jetbrains.kotlin.load.java.lazy.child import org.jetbrains.kotlin.load.java.lazy.childForMethod
import org.jetbrains.kotlin.load.java.lazy.resolveAnnotations import org.jetbrains.kotlin.load.java.lazy.resolveAnnotations
import org.jetbrains.kotlin.load.java.lazy.types.toAttributes import org.jetbrains.kotlin.load.java.lazy.types.toAttributes
import org.jetbrains.kotlin.load.java.structure.JavaArrayType import org.jetbrains.kotlin.load.java.structure.JavaArrayType
@@ -86,6 +86,7 @@ class LazyJavaClassMemberScope(
} }
c.components.signatureEnhancement.enhanceSignatures( c.components.signatureEnhancement.enhanceSignatures(
c,
result.ifEmpty { listOfNotNull(createDefaultConstructor()) } result.ifEmpty { listOfNotNull(createDefaultConstructor()) }
).toList() ).toList()
} }
@@ -424,7 +425,7 @@ class LazyJavaClassMemberScope(
val getter = DescriptorFactory.createDefaultGetter(propertyDescriptor, Annotations.EMPTY) val getter = DescriptorFactory.createDefaultGetter(propertyDescriptor, Annotations.EMPTY)
propertyDescriptor.initialize(getter, null) propertyDescriptor.initialize(getter, null)
val returnType = givenType ?: computeMethodReturnType(method, annotations, c.child(propertyDescriptor, method)) val returnType = givenType ?: computeMethodReturnType(method, annotations, c.childForMethod(propertyDescriptor, method))
propertyDescriptor.setType(returnType, listOf(), getDispatchReceiverParameter(), null as KotlinType?) propertyDescriptor.setType(returnType, listOf(), getDispatchReceiverParameter(), null as KotlinType?)
getter.initialize(returnType) getter.initialize(returnType)
@@ -511,7 +512,7 @@ class LazyJavaClassMemberScope(
) )
val c = c.child(constructorDescriptor, constructor, typeParametersIndexOffset = classDescriptor.declaredTypeParameters.size) val c = c.childForMethod(constructorDescriptor, constructor, typeParametersIndexOffset = classDescriptor.declaredTypeParameters.size)
val valueParameters = resolveValueParameters(c, constructorDescriptor, constructor.valueParameters) val valueParameters = resolveValueParameters(c, constructorDescriptor, constructor.valueParameters)
val constructorTypeParameters = val constructorTypeParameters =
classDescriptor.declaredTypeParameters + classDescriptor.declaredTypeParameters +
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.SourceElement import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.descriptors.impl.PackageFragmentDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.PackageFragmentDescriptorImpl
import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext
import org.jetbrains.kotlin.load.java.lazy.childForClassOrPackage
import org.jetbrains.kotlin.load.java.lazy.resolveAnnotations import org.jetbrains.kotlin.load.java.lazy.resolveAnnotations
import org.jetbrains.kotlin.load.java.structure.JavaClass import org.jetbrains.kotlin.load.java.structure.JavaClass
import org.jetbrains.kotlin.load.java.structure.JavaPackage import org.jetbrains.kotlin.load.java.structure.JavaPackage
@@ -31,9 +32,11 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.storage.getValue import org.jetbrains.kotlin.storage.getValue
class LazyJavaPackageFragment( class LazyJavaPackageFragment(
private val c: LazyJavaResolverContext, outerContext: LazyJavaResolverContext,
private val jPackage: JavaPackage private val jPackage: JavaPackage
) : PackageFragmentDescriptorImpl(c.module, jPackage.fqName) { ) : PackageFragmentDescriptorImpl(outerContext.module, jPackage.fqName) {
private val c = outerContext.childForClassOrPackage(this)
internal val binaryClasses by c.storageManager.createLazyValue { internal val binaryClasses by c.storageManager.createLazyValue {
c.components.packageMapper.findPackageParts(fqName.asString()).mapNotNull { partName -> c.components.packageMapper.findPackageParts(fqName.asString()).mapNotNull { partName ->
val classId = ClassId(fqName, Name.identifier(partName)) val classId = ClassId(fqName, Name.identifier(partName))
@@ -49,10 +52,7 @@ class LazyJavaPackageFragment(
onRecursiveCall = listOf() onRecursiveCall = listOf()
) )
private val packageAnnotations = c.resolveAnnotations(jPackage) override val annotations = c.resolveAnnotations(jPackage)
// Test only method
fun getPackageAnnotations() = packageAnnotations
internal fun getSubPackageFqNames(): List<FqName> = subPackages() internal fun getSubPackageFqNames(): List<FqName> = subPackages()
@@ -26,7 +26,7 @@ import org.jetbrains.kotlin.load.java.components.TypeUsage
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.child import org.jetbrains.kotlin.load.java.lazy.childForMethod
import org.jetbrains.kotlin.load.java.lazy.resolveAnnotations import org.jetbrains.kotlin.load.java.lazy.resolveAnnotations
import org.jetbrains.kotlin.load.java.lazy.types.LazyJavaTypeAttributes import org.jetbrains.kotlin.load.java.lazy.types.LazyJavaTypeAttributes
import org.jetbrains.kotlin.load.java.structure.JavaArrayType import org.jetbrains.kotlin.load.java.structure.JavaArrayType
@@ -87,7 +87,7 @@ abstract class LazyJavaScope(protected val c: LazyJavaResolverContext) : MemberS
computeNonDeclaredFunctions(result, name) computeNonDeclaredFunctions(result, name)
c.components.signatureEnhancement.enhanceSignatures(result).toList() c.components.signatureEnhancement.enhanceSignatures(c, result).toList()
} }
open protected fun JavaMethodDescriptor.isVisibleAsFunction() = true open protected fun JavaMethodDescriptor.isVisibleAsFunction() = true
@@ -114,7 +114,7 @@ abstract class LazyJavaScope(protected val c: LazyJavaResolverContext) : MemberS
ownerDescriptor, annotations, method.name, c.components.sourceElementFactory.source(method) ownerDescriptor, annotations, method.name, c.components.sourceElementFactory.source(method)
) )
val c = c.child(functionDescriptorImpl, method) val c = c.childForMethod(functionDescriptorImpl, method)
val methodTypeParameters = method.typeParameters.map { p -> c.typeParameterResolver.resolveTypeParameter(p)!! } val methodTypeParameters = method.typeParameters.map { p -> c.typeParameterResolver.resolveTypeParameter(p)!! }
val valueParameters = resolveValueParameters(c, functionDescriptorImpl, method.valueParameters) val valueParameters = resolveValueParameters(c, functionDescriptorImpl, method.valueParameters)
@@ -246,7 +246,7 @@ abstract class LazyJavaScope(protected val c: LazyJavaResolverContext) : MemberS
if (DescriptorUtils.isAnnotationClass(ownerDescriptor)) if (DescriptorUtils.isAnnotationClass(ownerDescriptor))
properties.toList() properties.toList()
else else
c.components.signatureEnhancement.enhanceSignatures(properties).toList() c.components.signatureEnhancement.enhanceSignatures(c, properties).toList()
} }
private fun resolveProperty(field: JavaField): PropertyDescriptor { private fun resolveProperty(field: JavaField): PropertyDescriptor {
@@ -19,12 +19,17 @@ package org.jetbrains.kotlin.load.java.typeEnhancement
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotated import org.jetbrains.kotlin.descriptors.annotations.Annotated
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.annotations.composeAnnotations import org.jetbrains.kotlin.descriptors.annotations.composeAnnotations
import org.jetbrains.kotlin.load.java.* import org.jetbrains.kotlin.load.java.*
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor 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.lazy.LazyJavaResolverContext
import org.jetbrains.kotlin.load.java.lazy.computeNewDefaultTypeQualifiers
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
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
@@ -36,17 +41,40 @@ import org.jetbrains.kotlin.types.asFlexibleType
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.types.isFlexible import org.jetbrains.kotlin.types.isFlexible
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import java.util.* import java.util.*
class SignatureEnhancement(private val annotationTypeQualifierResolver: AnnotationTypeQualifierResolver) { class SignatureEnhancement(private val annotationTypeQualifierResolver: AnnotationTypeQualifierResolver) {
fun <D : CallableMemberDescriptor> enhanceSignatures(platformSignatures: Collection<D>): Collection<D> {
fun extractNullability(annotationDescriptor: AnnotationDescriptor): NullabilityQualifier? {
when (annotationDescriptor.annotationClass?.fqNameSafe) {
in NULLABLE_ANNOTATIONS -> return NullabilityQualifier.NULLABLE
in NOT_NULL_ANNOTATIONS -> return NullabilityQualifier.NOT_NULL
}
val typeQualifier =
annotationTypeQualifierResolver
.resolveTypeQualifierAnnotation(annotationDescriptor)
?.takeIf { it.annotationClass?.fqNameSafe == JAVAX_NONNULL_ANNOTATION }
?: return null
return typeQualifier.allValueArguments.values.singleOrNull()?.value?.let {
enumEntryDescriptor ->
if (enumEntryDescriptor !is ClassDescriptor) return@let null
if (enumEntryDescriptor.name.asString() == "ALWAYS") NullabilityQualifier.NOT_NULL else NullabilityQualifier.NULLABLE
} ?: NullabilityQualifier.NOT_NULL
}
fun <D : CallableMemberDescriptor> enhanceSignatures(c: LazyJavaResolverContext, platformSignatures: Collection<D>): Collection<D> {
return platformSignatures.map { return platformSignatures.map {
it.enhanceSignature() it.enhanceSignature(c)
} }
} }
private fun <D : CallableMemberDescriptor> D.enhanceSignature(): D { private fun <D : CallableMemberDescriptor> D.enhanceSignature(c: LazyJavaResolverContext): D {
val outerScopeQualifiers = c.computeNewDefaultTypeQualifiers(annotations)
// TODO type parameters // TODO type parameters
// TODO use new type parameters while enhancing other types // TODO use new type parameters while enhancing other types
// TODO Propagation into generic type arguments // TODO Propagation into generic type arguments
@@ -62,7 +90,10 @@ class SignatureEnhancement(private val annotationTypeQualifierResolver: Annotati
typeContainer = typeContainer =
this.safeAs<FunctionDescriptor>() this.safeAs<FunctionDescriptor>()
?.getUserData(JavaMethodDescriptor.ORIGINAL_VALUE_PARAMETER_FOR_EXTENSION_RECEIVER), ?.getUserData(JavaMethodDescriptor.ORIGINAL_VALUE_PARAMETER_FOR_EXTENSION_RECEIVER),
isCovariant = false isCovariant = false,
defaultTopLevelQualifiers =
outerScopeQualifiers
?.get(AnnotationTypeQualifierResolver.QualifierApplicabilityType.VALUE_PARAMETER)
) { it.extensionReceiverParameter!!.type }.enhance() ) { it.extensionReceiverParameter!!.type }.enhance()
else null else null
@@ -81,12 +112,28 @@ class SignatureEnhancement(private val annotationTypeQualifierResolver: Annotati
val valueParameterEnhancements = valueParameters.map { val valueParameterEnhancements = valueParameters.map {
p -> p ->
parts(typeContainer = p, isCovariant = false) { it.valueParameters[p.index].type } parts(
typeContainer = p, isCovariant = false,
defaultTopLevelQualifiers =
outerScopeQualifiers
?.get(AnnotationTypeQualifierResolver.QualifierApplicabilityType.VALUE_PARAMETER)
) { it.valueParameters[p.index].type }
.enhance(predefinedEnhancementInfo?.parametersInfo?.getOrNull(p.index)) .enhance(predefinedEnhancementInfo?.parametersInfo?.getOrNull(p.index))
} }
val returnTypeEnhancement = val returnTypeEnhancement =
parts(typeContainer = this, isCovariant = true) { it.returnType!! }.enhance(predefinedEnhancementInfo?.returnTypeInfo) parts(
typeContainer = this, isCovariant = true,
defaultTopLevelQualifiers =
outerScopeQualifiers?.get(
if (this.safeAs<PropertyDescriptor>()?.isJavaField == true)
AnnotationTypeQualifierResolver.QualifierApplicabilityType.FIELD
else
AnnotationTypeQualifierResolver.QualifierApplicabilityType.METHOD_RETURN_TYPE
)
) { it.returnType!! }.enhance(predefinedEnhancementInfo?.returnTypeInfo)
if ((receiverTypeEnhancement?.wereChanges ?: false) if ((receiverTypeEnhancement?.wereChanges ?: false)
|| returnTypeEnhancement.wereChanges || valueParameterEnhancements.any { it.wereChanges }) { || returnTypeEnhancement.wereChanges || valueParameterEnhancements.any { it.wereChanges }) {
@@ -101,7 +148,8 @@ class SignatureEnhancement(private val annotationTypeQualifierResolver: Annotati
private val typeContainer: Annotated?, private val typeContainer: Annotated?,
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?
) { ) {
fun enhance(predefined: TypeEnhancementInfo? = null): PartEnhancementResult { fun enhance(predefined: TypeEnhancementInfo? = null): PartEnhancementResult {
val qualifiers = computeIndexedQualifiersForOverride() val qualifiers = computeIndexedQualifiersForOverride()
@@ -152,7 +200,10 @@ 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 nullability = composedAnnotation.extractNullability() val defaultTypeQualifier = defaultTopLevelQualifiers?.takeIf { isHeadTypeConstructor }
val nullability =
composedAnnotation.extractNullability()
?: defaultTypeQualifier?.nullability
return JavaTypeQualifiers( return JavaTypeQualifiers(
nullability, nullability,
@@ -168,28 +219,8 @@ class SignatureEnhancement(private val annotationTypeQualifierResolver: Annotati
) )
} }
private fun Annotations.extractNullability(): NullabilityQualifier? { private fun Annotations.extractNullability(): NullabilityQualifier? =
for (annotationDescriptor in this) { this.firstNotNullResult(this@SignatureEnhancement::extractNullability)
when (annotationDescriptor.annotationClass?.fqNameSafe) {
in NULLABLE_ANNOTATIONS -> return NullabilityQualifier.NULLABLE
in NOT_NULL_ANNOTATIONS -> return NullabilityQualifier.NOT_NULL
}
val typeQualifier =
annotationTypeQualifierResolver
.resolveTypeQualifierAnnotation(annotationDescriptor)
?.takeIf { it.annotationClass?.fqNameSafe == JAVAX_NONNULL_ANNOTATION }
?: continue
return typeQualifier.allValueArguments.values.singleOrNull()?.value?.let {
enumEntryDescriptor ->
if (enumEntryDescriptor !is ClassDescriptor) return@let null
if (enumEntryDescriptor.name.asString() == "ALWAYS") NullabilityQualifier.NOT_NULL else NullabilityQualifier.NULLABLE
} ?: NullabilityQualifier.NOT_NULL
}
return null
}
private fun computeIndexedQualifiersForOverride(): (Int) -> JavaTypeQualifiers { private fun computeIndexedQualifiersForOverride(): (Int) -> JavaTypeQualifiers {
fun KotlinType.toIndexed(): List<KotlinType> { fun KotlinType.toIndexed(): List<KotlinType> {
@@ -292,6 +323,7 @@ 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?,
collector: (D) -> KotlinType collector: (D) -> KotlinType
): SignatureParts { ): SignatureParts {
return SignatureParts( return SignatureParts(
@@ -301,7 +333,8 @@ class SignatureEnhancement(private val annotationTypeQualifierResolver: Annotati
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
collector(it as D) collector(it as D)
}, },
isCovariant isCovariant,
defaultTopLevelQualifiers
) )
} }
@@ -66,7 +66,7 @@ public class JdkAndMockLibraryProjectDescriptor extends KotlinLightProjectDescri
File libraryJar = File libraryJar =
isJsLibrary isJsLibrary
? MockLibraryUtil.compileJsLibraryToJar(sourcesPath, LIBRARY_NAME, withSources) ? MockLibraryUtil.compileJsLibraryToJar(sourcesPath, LIBRARY_NAME, withSources)
: MockLibraryUtil.compileJvmLibraryToJar(sourcesPath, LIBRARY_NAME, withSources, extraOptions, classpath); : MockLibraryUtil.compileJvmLibraryToJar(sourcesPath, LIBRARY_NAME, withSources, true, extraOptions, classpath);
String jarUrl = getJarUrl(libraryJar); String jarUrl = getJarUrl(libraryJar);
Library.ModifiableModel libraryModel = model.getModuleLibraryTable().getModifiableModel().createLibrary(LIBRARY_NAME).getModifiableModel(); Library.ModifiableModel libraryModel = model.getModuleLibraryTable().getModifiableModel().createLibrary(LIBRARY_NAME).getModifiableModel();