diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/JavaTypeEnhancementStateParser.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/JavaTypeEnhancementStateParser.kt index 59fd75bb57c..fb355d14acd 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/JavaTypeEnhancementStateParser.kt +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/JavaTypeEnhancementStateParser.kt @@ -180,4 +180,11 @@ class JavaTypeEnhancementStateParser(private val collector: MessageCollector) { return FqName(name) to state } + + companion object { + private val DEFAULT = JavaTypeEnhancementStateParser(MessageCollector.NONE) + + fun parsePlainNullabilityAnnotationReportLevels(nullabilityAnnotations: String) = + DEFAULT.parseNullabilityAnnotationReportLevels(arrayOf(nullabilityAnnotations)).entries.singleOrNull()?.toPair() + } } diff --git a/compiler/testData/diagnostics/foreignAnnotationsTests/tests/multiple.kt b/compiler/testData/diagnostics/foreignAnnotationsTests/tests/multiple.kt new file mode 100644 index 00000000000..8fdc9db210a --- /dev/null +++ b/compiler/testData/diagnostics/foreignAnnotationsTests/tests/multiple.kt @@ -0,0 +1,158 @@ +// NULLABILITY_ANNOTATIONS: @io.reactivex.annotations:strict, @org.eclipse.jdt.annotation:warn, @androidx.annotation:strict, @com.android.annotations:ignore + +// FILE: A1.java +import io.reactivex.annotations.*; + +public class A1 { + @Nullable public String field = null; + + @Nullable + public String foo(@NonNull String x, @Nullable CharSequence y) { + return ""; + } + + @NonNull + public String bar() { + return ""; + } + + @Nullable + public T baz(@NonNull T x) { return x; } +} + +// FILE: A2.java +import org.eclipse.jdt.annotation.*; + +public class A2 { + @Nullable public String field = null; + + @Nullable + public String foo(@NonNull String x, @Nullable CharSequence y) { + return ""; + } + + @NonNull + public String bar() { + return ""; + } + + @Nullable + public T baz(@NonNull T x) { return x; } +} + +// FILE: A3.java +import androidx.annotation.*; + +public class A3 { + @Nullable public String field = null; + + @Nullable + public String foo(@NonNull String x, @Nullable CharSequence y) { + return ""; + } + + @NonNull + public String bar() { + return ""; + } + + @Nullable + public T baz(@NonNull T x) { return x; } +} + +// FILE: A4.java +import com.android.annotations.*; + +public class A4 { + @Nullable public String field = null; + + @Nullable + public String foo(@NonNull String x, @Nullable CharSequence y) { + return ""; + } + + @NonNull + public String bar() { + return ""; + } + + @Nullable + public T baz(@NonNull T x) { return x; } +} + +// FILE: main.kt +fun main1(a: A1, a1: A1) { + 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("").length + a.baz("")?.length + a.baz(null).length + + a1.baz("")!!.length + a1.baz(null)!!.length +} + +fun main2(a: A2, a1: A2) { + 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("").length + a.baz("")?.length + a.baz(null).length + + a1.baz("")!!.length + a1.baz(null)!!.length +} + +fun main3(a: A3, a1: A3) { + 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("").length + a.baz("")?.length + a.baz(null).length + + a1.baz("")!!.length + a1.baz(null)!!.length +} + +fun main4(a: A4, a1: A4) { + 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("").length + a.baz("")?.length + a.baz(null).length + + a1.baz("")!!.length + a1.baz(null)!!.length +} diff --git a/compiler/testData/diagnostics/foreignAnnotationsTests/tests/multiple.txt b/compiler/testData/diagnostics/foreignAnnotationsTests/tests/multiple.txt new file mode 100644 index 00000000000..38c7293686d --- /dev/null +++ b/compiler/testData/diagnostics/foreignAnnotationsTests/tests/multiple.txt @@ -0,0 +1,39 @@ +package + +public fun main1(/*0*/ a: A1, /*1*/ a1: A1): kotlin.Unit +public fun main2(/*0*/ a: A2, /*1*/ a1: A2): kotlin.Unit +public fun main3(/*0*/ a: A3, /*1*/ a1: A3): kotlin.Unit +public fun main4(/*0*/ a: [ERROR : A4], /*1*/ a1: [ERROR : A4]): kotlin.Unit + +public open class A1 { + public constructor A1() + @io.reactivex.annotations.Nullable public final var field: kotlin.String? + @io.reactivex.annotations.NonNull public open fun bar(): kotlin.String + @io.reactivex.annotations.Nullable public open fun baz(/*0*/ @io.reactivex.annotations.NonNull x: T): T? + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @io.reactivex.annotations.Nullable public open fun foo(/*0*/ @io.reactivex.annotations.NonNull x: kotlin.String, /*1*/ @io.reactivex.annotations.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 +} + +public open class A2 { + public constructor A2() + @org.eclipse.jdt.annotation.Nullable public final var field: kotlin.String! + @org.eclipse.jdt.annotation.NonNull public open fun bar(): kotlin.String! + @org.eclipse.jdt.annotation.Nullable public open fun baz(/*0*/ @org.eclipse.jdt.annotation.NonNull x: T!): T! + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @org.eclipse.jdt.annotation.Nullable public open fun foo(/*0*/ @org.eclipse.jdt.annotation.NonNull x: kotlin.String!, /*1*/ @org.eclipse.jdt.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 +} + +public open class A3 { + public constructor A3() + @androidx.annotation.Nullable public final var field: kotlin.String? + @androidx.annotation.NonNull public open fun bar(): kotlin.String + @androidx.annotation.Nullable public open fun baz(/*0*/ @androidx.annotation.NonNull x: T): T? + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @androidx.annotation.Nullable public open fun foo(/*0*/ @androidx.annotation.NonNull x: kotlin.String, /*1*/ @androidx.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 +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ForeignAnnotationsCompiledJavaTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ForeignAnnotationsCompiledJavaTestGenerated.java index 0b233b28706..d41bceadb27 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ForeignAnnotationsCompiledJavaTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ForeignAnnotationsCompiledJavaTestGenerated.java @@ -86,6 +86,12 @@ public class ForeignAnnotationsCompiledJavaTestGenerated extends AbstractForeign runTest("compiler/testData/diagnostics/foreignAnnotationsTests/tests/lombokSimple.kt"); } + @Test + @TestMetadata("multiple.kt") + public void testMultiple() throws Exception { + runTest("compiler/testData/diagnostics/foreignAnnotationsTests/tests/multiple.kt"); + } + @Test @TestMetadata("rxjava.kt") public void testRxjava() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ForeignAnnotationsCompiledJavaWithPsiClassReadingTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ForeignAnnotationsCompiledJavaWithPsiClassReadingTestGenerated.java index f02e06c5866..b1a49b0b39d 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ForeignAnnotationsCompiledJavaWithPsiClassReadingTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ForeignAnnotationsCompiledJavaWithPsiClassReadingTestGenerated.java @@ -86,6 +86,12 @@ public class ForeignAnnotationsCompiledJavaWithPsiClassReadingTestGenerated exte runTest("compiler/testData/diagnostics/foreignAnnotationsTests/tests/lombokSimple.kt"); } + @Test + @TestMetadata("multiple.kt") + public void testMultiple() throws Exception { + runTest("compiler/testData/diagnostics/foreignAnnotationsTests/tests/multiple.kt"); + } + @Test @TestMetadata("rxjava.kt") public void testRxjava() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ForeignAnnotationsSourceJavaTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ForeignAnnotationsSourceJavaTestGenerated.java index b791423a262..ebb07343737 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ForeignAnnotationsSourceJavaTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ForeignAnnotationsSourceJavaTestGenerated.java @@ -86,6 +86,12 @@ public class ForeignAnnotationsSourceJavaTestGenerated extends AbstractForeignAn runTest("compiler/testData/diagnostics/foreignAnnotationsTests/tests/lombokSimple.kt"); } + @Test + @TestMetadata("multiple.kt") + public void testMultiple() throws Exception { + runTest("compiler/testData/diagnostics/foreignAnnotationsTests/tests/multiple.kt"); + } + @Test @TestMetadata("rxjava.kt") public void testRxjava() throws Exception { diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/directives/ForeignAnnotationsDirectives.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/directives/ForeignAnnotationsDirectives.kt index 0b71adf5962..abe416e79ff 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/directives/ForeignAnnotationsDirectives.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/directives/ForeignAnnotationsDirectives.kt @@ -5,9 +5,11 @@ package org.jetbrains.kotlin.test.directives +import org.jetbrains.kotlin.cli.common.arguments.JavaTypeEnhancementStateParser import org.jetbrains.kotlin.test.directives.model.SimpleDirectivesContainer import org.jetbrains.kotlin.test.services.configuration.JavaForeignAnnotationType import org.jetbrains.kotlin.load.java.ReportLevel +import org.jetbrains.kotlin.name.FqName @Suppress("RemoveExplicitTypeArguments") object ForeignAnnotationsDirectives : SimpleDirectivesContainer() { @@ -30,6 +32,11 @@ object ForeignAnnotationsDirectives : SimpleDirectivesContainer() { additionalParser = ReportLevel.Companion::findByDescription ) + val NULLABILITY_ANNOTATIONS by valueDirective>( + description = "List of annotations with their report levels", + parser = JavaTypeEnhancementStateParser.Companion::parsePlainNullabilityAnnotationReportLevels + ) + val ANNOTATIONS_PATH by enumDirective( description = "Path to foreign annotations" ) diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/configuration/JvmForeignAnnotationsConfigurator.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/configuration/JvmForeignAnnotationsConfigurator.kt index 80f91903e24..02eb3d4cbbc 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/configuration/JvmForeignAnnotationsConfigurator.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/configuration/JvmForeignAnnotationsConfigurator.kt @@ -45,6 +45,7 @@ open class JvmForeignAnnotationsConfigurator(testServices: TestServices) : Envir override val directivesContainers: List get() = listOf(ForeignAnnotationsDirectives) + @OptIn(ExperimentalStdlibApi::class) override fun provideAdditionalAnalysisFlags(directives: RegisteredDirectives): Map, Any?> { val defaultJsr305Settings = Jsr305Settings.DEFAULT val globalState = directives.singleOrZeroValue(JSR305_GLOBAL_REPORT) ?: defaultJsr305Settings.globalLevel @@ -54,8 +55,13 @@ open class JvmForeignAnnotationsConfigurator(testServices: TestServices) : Envir val state = ReportLevel.findByDescription(stateDescription) ?: return@mapNotNull null FqName(name) to state }.toMap() - val configuredReportLevels = - directives.singleOrZeroValue(JSPECIFY_STATE)?.let { mapOf(JSPECIFY_ANNOTATIONS_PACKAGE to it) } ?: emptyMap() + val configuredReportLevels = buildMap { + directives.singleOrZeroValue(JSPECIFY_STATE)?.let { put(JSPECIFY_ANNOTATIONS_PACKAGE, it) } + for ((fqname, reportLevel) in directives[ForeignAnnotationsDirectives.NULLABILITY_ANNOTATIONS]) { + put(fqname, reportLevel) + } + } + return mapOf( JvmAnalysisFlags.javaTypeEnhancementState to JavaTypeEnhancementState( Jsr305Settings(globalState, migrationState, userAnnotationsState),