diff --git a/compiler/testData/foreignAnnotations/annotations/javax/annotation/ParametersAreNonnullByDefault.java b/compiler/testData/foreignAnnotations/annotations/javax/annotation/ParametersAreNonnullByDefault.java
new file mode 100644
index 00000000000..a2402b5d98f
--- /dev/null
+++ b/compiler/testData/foreignAnnotations/annotations/javax/annotation/ParametersAreNonnullByDefault.java
@@ -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:
+ *
+ * - An explicit nullness annotation
+ *
- The method overrides a method in a superclass (in which case the
+ * annotation of the corresponding parameter in the superclass applies)
+ *
- There is a default parameter annotation (like {@link ParametersAreNullableByDefault})
+ * applied to a more tightly nested element.
+ *
+ *
+ * @see Nonnull
+ */
+@Documented
+@Nonnull
+@TypeQualifierDefault(ElementType.PARAMETER)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ParametersAreNonnullByDefault {
+}
diff --git a/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/fieldsAreNullable.kt b/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/fieldsAreNullable.kt
new file mode 100644
index 00000000000..bf2f75921a9
--- /dev/null
+++ b/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/fieldsAreNullable.kt
@@ -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, "").length
+
+ a.bar().length
+ a.bar()!!.length
+
+ a.field?.length
+ a.field.length
+ a.field = null
+
+ a.nonNullField?.length
+ a.nonNullField.length
+ a.nonNullField = null
+}
diff --git a/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/fieldsAreNullable.txt b/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/fieldsAreNullable.txt
new file mode 100644
index 00000000000..48ecc072f23
--- /dev/null
+++ b/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/fieldsAreNullable.txt
@@ -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
+}
diff --git a/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/nullabilityFromOverridden.kt b/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/nullabilityFromOverridden.kt
new file mode 100644
index 00000000000..afbd2c72be6
--- /dev/null
+++ b/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/nullabilityFromOverridden.kt
@@ -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).length
+ a.foo2(null).length
+ a.foo3(null).length
+ a.bar1(null).length
+ a.bar2(null).length
+ a.baz(null).length
+
+ b.foo1(null).length
+ b.foo1(null)?.length
+ b.foo2(null).length
+ b.foo3(null).length
+ b.bar1(null).length
+ b.bar2(null).length
+ b.baz(null).length
+ b.baz(null)?.length
+
+ c.foo1(null).length
+ c.foo2(null).length
+ c.foo3(null).length
+ c.bar1(null).length
+ c.bar1(null)?.length
+ c.bar2(null).length
+ c.baz(null).length
+}
diff --git a/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/nullabilityFromOverridden.txt b/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/nullabilityFromOverridden.txt
new file mode 100644
index 00000000000..1582b886fe4
--- /dev/null
+++ b/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/nullabilityFromOverridden.txt
@@ -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
+}
diff --git a/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/overridingDefaultQualifier.kt b/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/overridingDefaultQualifier.kt
new file mode 100644
index 00000000000..c606ae1acfa
--- /dev/null
+++ b/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/overridingDefaultQualifier.kt
@@ -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 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 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 baz() {
+ return null;
+ }
+ }
+}
+
+// FILE: main.kt
+
+fun main(a: A, b: A.B, c: A.C) {
+ a.foo("", null)?.length
+ a.foo("", null).length
+ a.foo(null, "").length
+
+ a.foobar(null, "").length
+ a.foobar("", null)?.length
+
+ a.bar().length
+ a.bar()!!.length
+
+ a.field?.length
+ a.field.length
+
+ a.baz().get(0)
+ a.baz()!!.get(0).get(0)
+ a.baz()!!.get(0)?.get(0)
+
+ // b
+ b.foo("", null)?.length
+ b.foo("", null).length
+ b.foo(null, "").length
+
+ b.foobar(null, "").length
+ b.foobar("", null)?.length
+
+ b.bar().length
+ b.bar()!!.length
+
+ b.field?.length
+ b.field.length
+
+ b.baz().get(0)
+ b.baz()!!.get(0).get(0)
+ b.baz()!!.get(0)?.get(0)
+
+ // c
+ c.foo("", null)?.length
+ c.foo("", null).length
+ c.foo(null, "").length
+
+ c.foobar(null, "").length
+ c.foobar("", null)?.length
+
+ c.bar().length
+ c.bar()!!.length
+
+ c.field?.length
+ c.field.length
+
+ c.baz().get(0)
+ c.baz()!!.get(0).get(0)
+ c.baz()!!.get(0)?.get(0)
+}
diff --git a/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/overridingDefaultQualifier.txt b/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/overridingDefaultQualifier.txt
new file mode 100644
index 00000000000..d67706a2400
--- /dev/null
+++ b/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/overridingDefaultQualifier.txt
@@ -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?
+ 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?
+ 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?
+ 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
+}
diff --git a/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/parametersAreNonnullByDefault.kt b/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/parametersAreNonnullByDefault.kt
new file mode 100644
index 00000000000..b613006cb2f
--- /dev/null
+++ b/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/parametersAreNonnullByDefault.kt
@@ -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, null, "").length
+
+ a.bar().length
+ a.bar()!!.length
+
+ a.field?.length
+ a.field.length
+}
diff --git a/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/parametersAreNonnullByDefault.txt b/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/parametersAreNonnullByDefault.txt
new file mode 100644
index 00000000000..b1225b4032e
--- /dev/null
+++ b/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/parametersAreNonnullByDefault.txt
@@ -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
+}
diff --git a/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/parametersAreNonnullByDefaultPackage.kt b/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/parametersAreNonnullByDefaultPackage.kt
new file mode 100644
index 00000000000..84bb68a0baf
--- /dev/null
+++ b/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/parametersAreNonnullByDefaultPackage.kt
@@ -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, null, "").length
+
+ a.bar().length
+ a.bar()!!.length
+
+ a.field?.length
+ a.field.length
+
+ a2.foo("", "", null)?.length
+ a2.foo("", "", null).length
+ a2.foo(null, null, "").length
+
+ a2.bar().length
+ a2.bar()!!.length
+
+ a2.field?.length
+ a2.field.length
+}
diff --git a/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/parametersAreNonnullByDefaultPackage.txt b/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/parametersAreNonnullByDefaultPackage.txt
new file mode 100644
index 00000000000..6b6fb798d28
--- /dev/null
+++ b/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/parametersAreNonnullByDefaultPackage.txt
@@ -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
diff --git a/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/springNullable.kt b/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/springNullable.kt
new file mode 100644
index 00000000000..639f8e95e28
--- /dev/null
+++ b/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/springNullable.kt
@@ -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 baz() {
+ return null;
+ }
+}
+
+// FILE: main.kt
+
+fun main(a: A) {
+ a.foo("", null)?.length
+ a.foo("", null).length
+ a.foo(null, "").length
+
+ a.bar().length
+ a.bar()!!.length
+
+ a.field?.length
+ a.field.length
+
+ a.baz().get(0)
+ a.baz()!!.get(0).get(0)
+ a.baz()!!.get(0)?.get(0)
+}
diff --git a/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/springNullable.txt b/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/springNullable.txt
new file mode 100644
index 00000000000..45b243c67ee
--- /dev/null
+++ b/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/springNullable.txt
@@ -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?
+ 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
+}
diff --git a/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/springNullablePackage.kt b/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/springNullablePackage.kt
new file mode 100644
index 00000000000..a78be048348
--- /dev/null
+++ b/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/springNullablePackage.kt
@@ -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 baz() {
+ return null;
+ }
+}
+
+// FILE: main.kt
+
+fun main(a: test.A) {
+ a.foo("", null)?.length
+ a.foo("", null).length
+ a.foo(null, "").length
+
+ a.bar().length
+ a.bar()!!.length
+
+ a.field?.length
+ a.field.length
+
+ a.baz().get(0)
+ a.baz()!!.get(0).get(0)
+ a.baz()!!.get(0)?.get(0)
+}
diff --git a/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/springNullablePackage.txt b/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/springNullablePackage.txt
new file mode 100644
index 00000000000..615020e4e92
--- /dev/null
+++ b/compiler/testData/foreignAnnotations/tests/typeQualifierDefault/springNullablePackage.txt
@@ -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?
+ 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
diff --git a/compiler/testData/foreignAnnotationsJava8/annotations/javax/annotation/CheckForNull.java b/compiler/testData/foreignAnnotationsJava8/annotations/javax/annotation/CheckForNull.java
new file mode 100644
index 00000000000..6fe52005c26
--- /dev/null
+++ b/compiler/testData/foreignAnnotationsJava8/annotations/javax/annotation/CheckForNull.java
@@ -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 {
+
+}
diff --git a/compiler/testData/foreignAnnotationsJava8/annotations/javax/annotation/Nonnull.java b/compiler/testData/foreignAnnotationsJava8/annotations/javax/annotation/Nonnull.java
new file mode 100644
index 00000000000..4b7aad97c70
--- /dev/null
+++ b/compiler/testData/foreignAnnotationsJava8/annotations/javax/annotation/Nonnull.java
@@ -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 {
+
+ public When forConstantValue(Nonnull qualifierqualifierArgument,
+ Object value) {
+ if (value == null)
+ return When.NEVER;
+ return When.ALWAYS;
+ }
+ }
+}
diff --git a/compiler/testData/foreignAnnotationsJava8/annotations/javax/annotation/Nullable.java b/compiler/testData/foreignAnnotationsJava8/annotations/javax/annotation/Nullable.java
new file mode 100644
index 00000000000..d31993dbd77
--- /dev/null
+++ b/compiler/testData/foreignAnnotationsJava8/annotations/javax/annotation/Nullable.java
@@ -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 {
+
+}
diff --git a/compiler/testData/foreignAnnotationsJava8/annotations/javax/annotation/ParametersAreNonnullByDefault.java b/compiler/testData/foreignAnnotationsJava8/annotations/javax/annotation/ParametersAreNonnullByDefault.java
new file mode 100644
index 00000000000..a2402b5d98f
--- /dev/null
+++ b/compiler/testData/foreignAnnotationsJava8/annotations/javax/annotation/ParametersAreNonnullByDefault.java
@@ -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:
+ *
+ * - An explicit nullness annotation
+ *
- The method overrides a method in a superclass (in which case the
+ * annotation of the corresponding parameter in the superclass applies)
+ *
- There is a default parameter annotation (like {@link ParametersAreNullableByDefault})
+ * applied to a more tightly nested element.
+ *
+ *
+ * @see Nonnull
+ */
+@Documented
+@Nonnull
+@TypeQualifierDefault(ElementType.PARAMETER)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ParametersAreNonnullByDefault {
+}
diff --git a/compiler/testData/foreignAnnotationsJava8/annotations/javax/annotation/meta/TypeQualifier.java b/compiler/testData/foreignAnnotationsJava8/annotations/javax/annotation/meta/TypeQualifier.java
new file mode 100644
index 00000000000..99f63127277
--- /dev/null
+++ b/compiler/testData/foreignAnnotationsJava8/annotations/javax/annotation/meta/TypeQualifier.java
@@ -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;
+
+}
diff --git a/compiler/testData/foreignAnnotationsJava8/annotations/javax/annotation/meta/TypeQualifierDefault.java b/compiler/testData/foreignAnnotationsJava8/annotations/javax/annotation/meta/TypeQualifierDefault.java
new file mode 100644
index 00000000000..0c8bd528fc4
--- /dev/null
+++ b/compiler/testData/foreignAnnotationsJava8/annotations/javax/annotation/meta/TypeQualifierDefault.java
@@ -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 {};
+}
diff --git a/compiler/testData/foreignAnnotationsJava8/annotations/javax/annotation/meta/TypeQualifierNickname.java b/compiler/testData/foreignAnnotationsJava8/annotations/javax/annotation/meta/TypeQualifierNickname.java
new file mode 100644
index 00000000000..40c998382da
--- /dev/null
+++ b/compiler/testData/foreignAnnotationsJava8/annotations/javax/annotation/meta/TypeQualifierNickname.java
@@ -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.
+ *
+ *
+ * Thus, you might define a qualifier SocialSecurityNumber as follows:
+ *
+ *
+ *
+ *
+ @Documented
+ @TypeQualifierNickname @Pattern("[0-9]{3}-[0-9]{2}-[0-9]{4}")
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface SocialSecurityNumber {
+ }
+
+ *
+ *
+ */
+@Documented
+@Target(ElementType.ANNOTATION_TYPE)
+public @interface TypeQualifierNickname {
+
+}
diff --git a/compiler/testData/foreignAnnotationsJava8/annotations/javax/annotation/meta/TypeQualifierValidator.java b/compiler/testData/foreignAnnotationsJava8/annotations/javax/annotation/meta/TypeQualifierValidator.java
new file mode 100644
index 00000000000..8053011296b
--- /dev/null
+++ b/compiler/testData/foreignAnnotationsJava8/annotations/javax/annotation/meta/TypeQualifierValidator.java
@@ -0,0 +1,21 @@
+package javax.annotation.meta;
+
+import java.lang.annotation.Annotation;
+
+import javax.annotation.Nonnull;
+
+public interface TypeQualifierValidator {
+ /**
+ * 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);
+}
diff --git a/compiler/testData/foreignAnnotationsJava8/annotations/javax/annotation/meta/When.java b/compiler/testData/foreignAnnotationsJava8/annotations/javax/annotation/meta/When.java
new file mode 100644
index 00000000000..ec8a1bc7037
--- /dev/null
+++ b/compiler/testData/foreignAnnotationsJava8/annotations/javax/annotation/meta/When.java
@@ -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;
+
+}
diff --git a/compiler/testData/foreignAnnotationsJava8/tests/springNullableWithTypeUse.kt b/compiler/testData/foreignAnnotationsJava8/tests/springNullableWithTypeUse.kt
new file mode 100644
index 00000000000..c400c6ed766
--- /dev/null
+++ b/compiler/testData/foreignAnnotationsJava8/tests/springNullableWithTypeUse.kt
@@ -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 baz() {
+ return null;
+ }
+}
+
+// FILE: main.kt
+
+fun main(a: A) {
+ a.foo("", null)?.length
+ a.foo("", null).length
+ a.foo(null, "").length
+
+ a.bar().length
+ a.bar()!!.length
+
+ a.field?.length
+ a.field.length
+
+ a.baz().get(0)
+ a.baz()!!.get(0).get(0)
+ a.baz()!!.get(0)?.get(0)
+}
diff --git a/compiler/testData/foreignAnnotationsJava8/tests/springNullableWithTypeUse.txt b/compiler/testData/foreignAnnotationsJava8/tests/springNullableWithTypeUse.txt
new file mode 100644
index 00000000000..188ef5ec1f0
--- /dev/null
+++ b/compiler/testData/foreignAnnotationsJava8/tests/springNullableWithTypeUse.txt
@@ -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?
+ 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
+}
diff --git a/compiler/tests-common/org/jetbrains/kotlin/checkers/AbstractDiagnosticsTest.kt b/compiler/tests-common/org/jetbrains/kotlin/checkers/AbstractDiagnosticsTest.kt
index 1f435328de0..f716ad8d222 100644
--- a/compiler/tests-common/org/jetbrains/kotlin/checkers/AbstractDiagnosticsTest.kt
+++ b/compiler/tests-common/org/jetbrains/kotlin/checkers/AbstractDiagnosticsTest.kt
@@ -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(
diff --git a/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/ForeignJava8AnnotationsTestGenerated.java b/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/ForeignJava8AnnotationsTestGenerated.java
index b8430cefc39..a4ec796498a 100644
--- a/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/ForeignJava8AnnotationsTestGenerated.java
+++ b/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/ForeignJava8AnnotationsTestGenerated.java
@@ -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)
diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/ForeignAnnotationsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/ForeignAnnotationsTestGenerated.java
index 91ca10c2c55..a4f8c0a06c6 100644
--- a/compiler/tests/org/jetbrains/kotlin/checkers/ForeignAnnotationsTestGenerated.java
+++ b/compiler/tests/org/jetbrains/kotlin/checkers/ForeignAnnotationsTestGenerated.java
@@ -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);
+ }
+ }
}
diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/LoadJavaPackageAnnotationsTest.kt b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/LoadJavaPackageAnnotationsTest.kt
index 3f41f83d342..1c4251daff0 100644
--- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/LoadJavaPackageAnnotationsTest.kt
+++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/LoadJavaPackageAnnotationsTest.kt
@@ -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
diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/AnnotationTypeQualifierResolver.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/AnnotationTypeQualifierResolver.kt
index d449c8be01e..d1bfce4c17c 100644
--- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/AnnotationTypeQualifierResolver.kt
+++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/AnnotationTypeQualifierResolver.kt
@@ -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 =
+ 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
diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/LazyJavaPackageFragmentProvider.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/LazyJavaPackageFragmentProvider.kt
index dc44bdb7395..da4351d97a3 100644
--- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/LazyJavaPackageFragmentProvider.kt
+++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/LazyJavaPackageFragmentProvider.kt
@@ -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 =
c.storageManager.createMemoizedFunctionWithNullableValues {
diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/context.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/context.kt
index 1785155d63b..1dbb527d521 100644
--- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/context.kt
+++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/context.kt
@@ -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
+
+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
+) {
+ 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
+) = 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) }
+)
diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaClassDescriptor.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaClassDescriptor.kt
index ced8d9ed4f2..d61dd0d31b3 100644
--- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaClassDescriptor.kt
+++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaClassDescriptor.kt
@@ -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)
diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaClassMemberScope.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaClassMemberScope.kt
index 0a4bb9178bf..4cad381e9ee 100644
--- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaClassMemberScope.kt
+++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaClassMemberScope.kt
@@ -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 +
diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaPackageFragment.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaPackageFragment.kt
index f7fceb9bf81..9f7cc9af6b5 100644
--- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaPackageFragment.kt
+++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaPackageFragment.kt
@@ -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 = subPackages()
diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaScope.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaScope.kt
index 2e02a31f9e5..6895c9e6d45 100644
--- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaScope.kt
+++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaScope.kt
@@ -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 {
diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhancement/signatureEnhancement.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhancement/signatureEnhancement.kt
index 08d73ea4ef8..19b404ca825 100644
--- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhancement/signatureEnhancement.kt
+++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhancement/signatureEnhancement.kt
@@ -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 enhanceSignatures(platformSignatures: Collection): Collection {
+
+ 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 enhanceSignatures(c: LazyJavaResolverContext, platformSignatures: Collection): Collection {
return platformSignatures.map {
- it.enhanceSignature()
+ it.enhanceSignature(c)
}
}
- private fun D.enhanceSignature(): D {
+ private fun 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()
?.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()?.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,
- 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 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 {
@@ -292,6 +323,7 @@ class SignatureEnhancement(private val annotationTypeQualifierResolver: Annotati
private fun 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
)
}
diff --git a/idea/idea-test-framework/src/org/jetbrains/kotlin/idea/test/JdkAndMockLibraryProjectDescriptor.java b/idea/idea-test-framework/src/org/jetbrains/kotlin/idea/test/JdkAndMockLibraryProjectDescriptor.java
index 227b79ea4ed..94a7d4bed9f 100644
--- a/idea/idea-test-framework/src/org/jetbrains/kotlin/idea/test/JdkAndMockLibraryProjectDescriptor.java
+++ b/idea/idea-test-framework/src/org/jetbrains/kotlin/idea/test/JdkAndMockLibraryProjectDescriptor.java
@@ -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();