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.RECURSIVE
import org.jetbrains.kotlin.test.util.RecursiveDescriptorComparator.RECURSIVE_ALL
import org.jetbrains.kotlin.utils.keysToMap
import org.junit.Assert
import java.io.File
import java.util.*
@@ -363,7 +364,15 @@ abstract class AbstractDiagnosticsTest : BaseDiagnosticsTest() {
val comparator = RecursiveDescriptorComparator(createdAffectedPackagesConfiguration(testFiles, modules.values))
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 ->
when {
@@ -375,32 +384,37 @@ abstract class AbstractDiagnosticsTest : BaseDiagnosticsTest() {
}
})
val module = sortedModules.iterator()
while (module.hasNext()) {
val moduleDescriptor = modules[module.next()]!!
val aPackage = moduleDescriptor.getPackage(FqName.ROOT)
assertFalse(aPackage.isEmpty())
for ((packageName, packageText) in textByPackage.entries) {
val module = sortedModules.iterator()
while (module.hasNext()) {
val moduleDescriptor = modules[module.next()]!!
if (isMultiModuleTest) {
rootPackageText.append(String.format("// -- Module: %s --\n", moduleDescriptor.name))
}
val aPackage = moduleDescriptor.getPackage(packageName)
assertFalse(aPackage.isEmpty())
val actualSerialized = comparator.serializeRecursively(aPackage)
rootPackageText.append(actualSerialized)
if (isMultiModuleTest) {
packageText.append(String.format("// -- Module: %s --\n", moduleDescriptor.name))
}
if (isMultiModuleTest && module.hasNext()) {
rootPackageText.append("\n\n")
val actualSerialized = comparator.serializeRecursively(aPackage)
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) {
"Rendered descriptors of this test take up $lineCount lines. " +
"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."
}
KotlinTestUtils.assertEqualsToFile(expectedFile, rootPackageText.toString())
KotlinTestUtils.assertEqualsToFile(expectedFile, allPackagesText)
}
private fun createdAffectedPackagesConfiguration(
@@ -48,6 +48,12 @@ public class ForeignJava8AnnotationsTestGenerated extends AbstractForeignJava8An
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")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -89,4 +89,55 @@ public class ForeignAnnotationsTestGenerated extends AbstractForeignAnnotationsT
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/rxjava.kt");
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
}.let { assertInstanceOf(it, LazyJavaPackageFragment::class.java) }
val annotation = packageFragmentDescriptor.getPackageAnnotations().findAnnotation(FqName("test.Ann"))
val annotation = packageFragmentDescriptor.annotations.findAnnotation(FqName("test.Ann"))
assertNotNull(annotation)
val singleAnnotation = packageFragmentDescriptor.getPackageAnnotations().singleOrNull()
val singleAnnotation = packageFragmentDescriptor.annotations.singleOrNull()
assertNotNull(singleAnnotation)
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.annotations.AnnotationDescriptor
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.storage.StorageManager
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
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_DEFAULT_FQNAME = FqName("javax.annotation.meta.TypeQualifierDefault")
class AnnotationTypeQualifierResolver(storageManager: StorageManager) {
private val resolvedNicknames =
@@ -49,6 +53,58 @@ class AnnotationTypeQualifierResolver(storageManager: StorageManager) {
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
@@ -26,7 +26,7 @@ class LazyJavaPackageFragmentProvider(
components: JavaResolverComponents
) : PackageFragmentProvider {
private val c = LazyJavaResolverContext(components, TypeParameterResolver.EMPTY)
private val c = LazyJavaResolverContext(components, TypeParameterResolver.EMPTY) { null }
private val packageFragments: MemoizedFunctionToNullable<FqName, LazyJavaPackageFragment> =
c.storageManager.createMemoizedFunctionWithNullableValues {
@@ -17,10 +17,8 @@
package org.jetbrains.kotlin.load.java.lazy
import org.jetbrains.kotlin.builtins.ReflectionTypes
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.PackagePartProvider
import org.jetbrains.kotlin.descriptors.SupertypeLoopChecker
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.load.java.AnnotationTypeQualifierResolver
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.sources.JavaSourceElementFactory
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.kotlin.DeserializedDescriptorResolver
import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder
import org.jetbrains.kotlin.serialization.deserialization.ErrorReporter
import org.jetbrains.kotlin.storage.StorageManager
import java.util.*
class JavaResolverComponents(
val storageManager: StorageManager,
@@ -66,10 +67,33 @@ class JavaResolverComponents(
)
}
class LazyJavaResolverContext(
val components: JavaResolverComponents,
val typeParameterResolver: TypeParameterResolver
private typealias QualifierByApplicabilityType = EnumMap<AnnotationTypeQualifierResolver.QualifierApplicabilityType, NullabilityQualifier?>
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 storageManager: StorageManager
@@ -80,14 +104,59 @@ class LazyJavaResolverContext(
fun LazyJavaResolverContext.child(
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(
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,
typeParameterOwner: JavaTypeParameterListOwner,
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.descriptors.JavaClassDescriptor
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.resolveAnnotations
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 c: LazyJavaResolverContext = outerContext.child(this, jClass)
private val c: LazyJavaResolverContext = outerContext.childForClassOrPackage(this, jClass)
init {
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.copyValueParameters
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.types.toAttributes
import org.jetbrains.kotlin.load.java.structure.JavaArrayType
@@ -86,6 +86,7 @@ class LazyJavaClassMemberScope(
}
c.components.signatureEnhancement.enhanceSignatures(
c,
result.ifEmpty { listOfNotNull(createDefaultConstructor()) }
).toList()
}
@@ -424,7 +425,7 @@ class LazyJavaClassMemberScope(
val getter = DescriptorFactory.createDefaultGetter(propertyDescriptor, Annotations.EMPTY)
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?)
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 constructorTypeParameters =
classDescriptor.declaredTypeParameters +
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.descriptors.impl.PackageFragmentDescriptorImpl
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.structure.JavaClass
import org.jetbrains.kotlin.load.java.structure.JavaPackage
@@ -31,9 +32,11 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.storage.getValue
class LazyJavaPackageFragment(
private val c: LazyJavaResolverContext,
outerContext: LazyJavaResolverContext,
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 {
c.components.packageMapper.findPackageParts(fqName.asString()).mapNotNull { partName ->
val classId = ClassId(fqName, Name.identifier(partName))
@@ -49,10 +52,7 @@ class LazyJavaPackageFragment(
onRecursiveCall = listOf()
)
private val packageAnnotations = c.resolveAnnotations(jPackage)
// Test only method
fun getPackageAnnotations() = packageAnnotations
override val annotations = c.resolveAnnotations(jPackage)
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.JavaPropertyDescriptor
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.types.LazyJavaTypeAttributes
import org.jetbrains.kotlin.load.java.structure.JavaArrayType
@@ -87,7 +87,7 @@ abstract class LazyJavaScope(protected val c: LazyJavaResolverContext) : MemberS
computeNonDeclaredFunctions(result, name)
c.components.signatureEnhancement.enhanceSignatures(result).toList()
c.components.signatureEnhancement.enhanceSignatures(c, result).toList()
}
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)
)
val c = c.child(functionDescriptorImpl, method)
val c = c.childForMethod(functionDescriptorImpl, method)
val methodTypeParameters = method.typeParameters.map { p -> c.typeParameterResolver.resolveTypeParameter(p)!! }
val valueParameters = resolveValueParameters(c, functionDescriptorImpl, method.valueParameters)
@@ -246,7 +246,7 @@ abstract class LazyJavaScope(protected val c: LazyJavaResolverContext) : MemberS
if (DescriptorUtils.isAnnotationClass(ownerDescriptor))
properties.toList()
else
c.components.signatureEnhancement.enhanceSignatures(properties).toList()
c.components.signatureEnhancement.enhanceSignatures(c, properties).toList()
}
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.ClassDescriptor
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.AnnotationDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.annotations.composeAnnotations
import org.jetbrains.kotlin.load.java.*
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor
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.computeJvmDescriptor
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.isFlexible
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import java.util.*
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 {
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 use new type parameters while enhancing other types
// TODO Propagation into generic type arguments
@@ -62,7 +90,10 @@ class SignatureEnhancement(private val annotationTypeQualifierResolver: Annotati
typeContainer =
this.safeAs<FunctionDescriptor>()
?.getUserData(JavaMethodDescriptor.ORIGINAL_VALUE_PARAMETER_FOR_EXTENSION_RECEIVER),
isCovariant = false
isCovariant = false,
defaultTopLevelQualifiers =
outerScopeQualifiers
?.get(AnnotationTypeQualifierResolver.QualifierApplicabilityType.VALUE_PARAMETER)
) { it.extensionReceiverParameter!!.type }.enhance()
else null
@@ -81,12 +112,28 @@ class SignatureEnhancement(private val annotationTypeQualifierResolver: Annotati
val valueParameterEnhancements = valueParameters.map {
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))
}
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)
|| returnTypeEnhancement.wereChanges || valueParameterEnhancements.any { it.wereChanges }) {
@@ -101,7 +148,8 @@ class SignatureEnhancement(private val annotationTypeQualifierResolver: Annotati
private val typeContainer: Annotated?,
private val fromOverride: KotlinType,
private val fromOverridden: Collection<KotlinType>,
private val isCovariant: Boolean
private val isCovariant: Boolean,
private val defaultTopLevelQualifiers: JavaTypeQualifiers?
) {
fun enhance(predefined: TypeEnhancementInfo? = null): PartEnhancementResult {
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
val nullability = composedAnnotation.extractNullability()
val defaultTypeQualifier = defaultTopLevelQualifiers?.takeIf { isHeadTypeConstructor }
val nullability =
composedAnnotation.extractNullability()
?: defaultTypeQualifier?.nullability
return JavaTypeQualifiers(
nullability,
@@ -168,28 +219,8 @@ class SignatureEnhancement(private val annotationTypeQualifierResolver: Annotati
)
}
private fun Annotations.extractNullability(): NullabilityQualifier? {
for (annotationDescriptor in this) {
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 Annotations.extractNullability(): NullabilityQualifier? =
this.firstNotNullResult(this@SignatureEnhancement::extractNullability)
private fun computeIndexedQualifiersForOverride(): (Int) -> JavaTypeQualifiers {
fun KotlinType.toIndexed(): List<KotlinType> {
@@ -292,6 +323,7 @@ class SignatureEnhancement(private val annotationTypeQualifierResolver: Annotati
private fun <D : CallableMemberDescriptor> D.parts(
typeContainer: Annotated?,
isCovariant: Boolean,
defaultTopLevelQualifiers: JavaTypeQualifiers?,
collector: (D) -> KotlinType
): SignatureParts {
return SignatureParts(
@@ -301,7 +333,8 @@ class SignatureEnhancement(private val annotationTypeQualifierResolver: Annotati
@Suppress("UNCHECKED_CAST")
collector(it as D)
},
isCovariant
isCovariant,
defaultTopLevelQualifiers
)
}
@@ -66,7 +66,7 @@ public class JdkAndMockLibraryProjectDescriptor extends KotlinLightProjectDescri
File libraryJar =
isJsLibrary
? 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);
Library.ModifiableModel libraryModel = model.getModuleLibraryTable().getModifiableModel().createLibrary(LIBRARY_NAME).getModifiableModel();