Add @UnderMigration annotation and options for report level

This commit is contained in:
Leonid Stashevsky
2017-09-28 17:15:08 +03:00
parent a524bde9b7
commit 95d32d8d1e
75 changed files with 1436 additions and 139 deletions
+2 -1
View File
@@ -32,7 +32,8 @@ val testDistProjects = listOf(
":kotlin-daemon-client",
":kotlin-preloader",
":plugins:android-extensions-compiler",
":kotlin-ant")
":kotlin-ant",
":kotlin-annotations-jvm")
dependencies {
depDistProjects.forEach {
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.config.AnalysisFlag
import org.jetbrains.kotlin.config.JvmTarget
import org.jetbrains.kotlin.utils.Jsr305State
import org.jetbrains.kotlin.utils.ReportLevel
class K2JVMCompilerArguments : CommonCompilerArguments() {
companion object {
@@ -165,10 +166,15 @@ class K2JVMCompilerArguments : CommonCompilerArguments() {
@Argument(
value = "-Xjsr305",
deprecatedName = "-Xjsr305-annotations",
valueDescription = "{ignore|strict|warn}",
description = "Specify global behavior for JSR-305 nullability annotations: ignore, treat as other supported nullability annotations, or report a warning"
valueDescription = "{ignore|strict|warn}" +
"|under-migration:{ignore-strict-warn}" +
"|@<fully qualified class name>:{ignore|strict|warn}",
description = "Specify behaviors for JSR-305 nullability annotations for: " +
"global, annotated with @UnderMigration or custom annotation " +
"with specific value: ignore, treat as other supported nullability annotations, or report a warning. " +
"Note that strict value is experimental yet"
)
var jsr305: String? by FreezableVar(Jsr305State.DEFAULT.description)
var jsr305: Array<String>? by FreezableVar(null)
@Argument(
value = "-Xno-exception-on-explicit-equals-for-boxed-null",
@@ -181,20 +187,54 @@ class K2JVMCompilerArguments : CommonCompilerArguments() {
override fun configureAnalysisFlags(collector: MessageCollector): MutableMap<AnalysisFlag<*>, Any> {
val result = super.configureAnalysisFlags(collector)
result[AnalysisFlag.jsr305] = parseJsr305(collector)
return result
}
if (jsr305 == "enable") {
collector.report(
CompilerMessageSeverity.STRONG_WARNING,
"Option 'enable' for -Xjsr305 flag is deprecated. Please use 'strict' instead"
)
result.put(AnalysisFlag.jsr305, Jsr305State.STRICT)
fun parseJsr305(collector: MessageCollector): Jsr305State {
var global: ReportLevel? = null
var migration: ReportLevel? = null
val userDefined = mutableMapOf<String, ReportLevel>()
fun parseJsr305UnderMigration(collector: MessageCollector, item: String): ReportLevel? {
val rawState = item.split(":").takeIf { it.size == 2 }?.get(1)
return ReportLevel.findByDescription(rawState)
}
else {
Jsr305State.findByDescription(jsr305)?.let {
result.put(AnalysisFlag.jsr305, it)
jsr305?.forEach { item ->
when {
item.startsWith("@") -> {
val (name, state) = parseJsr305UserDefined(collector, item) ?: return@forEach
val current = userDefined[name]
current?.let { return@forEach }
userDefined[name] = state
}
item.startsWith("under-migration") -> {
migration?.let { return@forEach }
migration = parseJsr305UnderMigration(collector, item)
}
item == "enable" -> {
collector.report(
CompilerMessageSeverity.STRONG_WARNING,
"Option 'enable' for -Xjsr305 flag is deprecated. Please use 'strict' instead"
)
global?.let { return@forEach }
global = ReportLevel.STRICT
}
else -> {
global?.let { return@forEach }
global = ReportLevel.findByDescription(item)
}
}
}
return result
val state = Jsr305State(global ?: ReportLevel.WARN, migration, userDefined)
return if (state == Jsr305State.DISABLED) Jsr305State.DISABLED else state
}
private fun parseJsr305UserDefined(collector: MessageCollector, item: String): Pair<String, ReportLevel>? {
val (name, rawState) = item.substring(1).split(":").takeIf { it.size == 2 } ?: return null
val state = ReportLevel.findByDescription(rawState) ?: return null
return name to state
}
}
+2 -1
View File
@@ -9,7 +9,8 @@ where advanced options include:
-Xmultifile-parts-inherit Compile multifile classes as a hierarchy of parts and facade
-Xmodule-path=<path> Paths where to find Java 9+ modules
-Xjavac-arguments=<option[,]> Java compiler arguments
-Xjsr305={ignore|strict|warn} Specify global behavior for JSR-305 nullability annotations: ignore, treat as other supported nullability annotations, or report a warning
-Xjsr305={ignore|strict|warn}|under-migration:{ignore-strict-warn}|@<fully qualified class name>:{ignore|strict|warn}
Specify behaviors for JSR-305 nullability annotations for: global, annotated with @UnderMigration or custom annotation with specific value: ignore, treat as other supported nullability annotations, or report a warning. Note that strict value is experimental yet
-Xload-builtins-from-dependencies
Load definitions of built-in declarations from module dependencies, instead of from the compiler
-Xno-call-assertions Don't generate not-null assertions for arguments of platform types
@@ -0,0 +1,18 @@
import 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;
import kotlin.annotations.jvm.*;
@Documented
@TypeQualifierNickname
@Nonnull(when = When.ALWAYS)
@Retention(RetentionPolicy.RUNTIME)
@UnderMigration(status = MigrationStatus.WARN)
public @interface MyMigrationNonnull {
}
@@ -0,0 +1,18 @@
import 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;
import kotlin.annotations.jvm.*;
@Documented
@TypeQualifierNickname
@Nonnull(when = When.MAYBE)
@Retention(RetentionPolicy.RUNTIME)
@UnderMigration(status = MigrationStatus.WARN)
public @interface MyMigrationNullable {
}
@@ -1,5 +1,5 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// JSR305_ANNOTATIONS_IGNORE
// JSR305_GLOBAL_REPORT ignore
// FILE: A.java
@@ -1,4 +1,4 @@
// WARNING_FOR_JSR305_ANNOTATIONS
// JSR305_GLOBAL_REPORT warn
// FILE: J.java
@@ -1,4 +1,4 @@
// WARNING_FOR_JSR305_ANNOTATIONS
// JSR305_GLOBAL_REPORT warn
// FILE: J.java
@@ -1,4 +1,4 @@
// WARNING_FOR_JSR305_ANNOTATIONS
// JSR305_GLOBAL_REPORT warn
// FILE: J.java
@@ -1,5 +1,5 @@
// !DIAGNOSTICS: -UNUSED_EXPRESSION
// WARNING_FOR_JSR305_ANNOTATIONS
// JSR305_GLOBAL_REPORT warn
// FILE: J.java
@@ -1,5 +1,5 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
// WARNING_FOR_JSR305_ANNOTATIONS
// JSR305_GLOBAL_REPORT warn
// FILE: J.java
@@ -1,5 +1,5 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
// WARNING_FOR_JSR305_ANNOTATIONS
// JSR305_GLOBAL_REPORT warn
// FILE: J.java
@@ -1,4 +1,4 @@
// WARNING_FOR_JSR305_ANNOTATIONS
// JSR305_GLOBAL_REPORT warn
// FILE: J.java
@@ -1,4 +1,4 @@
// WARNING_FOR_JSR305_ANNOTATIONS
// JSR305_GLOBAL_REPORT warn
// FILE: J.java
@@ -1,5 +1,5 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
// WARNING_FOR_JSR305_ANNOTATIONS
// JSR305_GLOBAL_REPORT warn
// FILE: J.java
@@ -1,5 +1,5 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
// WARNING_FOR_JSR305_ANNOTATIONS
// JSR305_GLOBAL_REPORT warn
// FILE: J.java
@@ -1,5 +1,5 @@
// !CHECK_TYPE
// WARNING_FOR_JSR305_ANNOTATIONS
// JSR305_GLOBAL_REPORT warn
// FILE: J.java
@@ -1,4 +1,4 @@
// WARNING_FOR_JSR305_ANNOTATIONS
// JSR305_GLOBAL_REPORT warn
// FILE: J.java
@@ -1,5 +1,5 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
// WARNING_FOR_JSR305_ANNOTATIONS
// JSR305_GLOBAL_REPORT warn
// FILE: J.java
@@ -1,4 +1,4 @@
// WARNING_FOR_JSR305_ANNOTATIONS
// JSR305_GLOBAL_REPORT warn
// FILE: J.java
@@ -1,5 +1,5 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
// WARNING_FOR_JSR305_ANNOTATIONS
// JSR305_GLOBAL_REPORT warn
// KT-6829 False warning on map to @Nullable
@@ -1,5 +1,5 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE
// WARNING_FOR_JSR305_ANNOTATIONS
// JSR305_GLOBAL_REPORT warn
// FILE: J.java
@@ -1,4 +1,4 @@
// WARNING_FOR_JSR305_ANNOTATIONS
// JSR305_GLOBAL_REPORT warn
// FILE: J.java
@@ -1,4 +1,4 @@
// WARNING_FOR_JSR305_ANNOTATIONS
// JSR305_GLOBAL_REPORT warn
// FILE: J.java
@@ -1,4 +1,4 @@
// WARNING_FOR_JSR305_ANNOTATIONS
// JSR305_GLOBAL_REPORT warn
// FILE: J.java
@@ -1,5 +1,5 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
// WARNING_FOR_JSR305_ANNOTATIONS
// JSR305_GLOBAL_REPORT warn
// FILE: J.java
@@ -1,5 +1,5 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// WARNING_FOR_JSR305_ANNOTATIONS
// JSR305_GLOBAL_REPORT warn
// FILE: A.java
public class A<T> {
@@ -1,5 +1,5 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// WARNING_FOR_JSR305_ANNOTATIONS
// JSR305_GLOBAL_REPORT warn
// FILE: MyNullable.java
import javax.annotation.*;
@@ -1,5 +1,5 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// WARNING_FOR_JSR305_ANNOTATIONS
// JSR305_GLOBAL_REPORT warn
// FILE: A.java
@@ -1,5 +1,5 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// WARNING_FOR_JSR305_ANNOTATIONS
// JSR305_GLOBAL_REPORT warn
// FILE: A.java
@@ -1,5 +1,5 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// WARNING_FOR_JSR305_ANNOTATIONS
// JSR305_GLOBAL_REPORT warn
// FILE: FieldsAreNullable.java
import java.lang.annotation.Documented;
@@ -1,5 +1,5 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// WARNING_FOR_JSR305_ANNOTATIONS
// JSR305_GLOBAL_REPORT warn
// FILE: NonNullApi.java
@@ -1,5 +1,5 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// WARNING_FOR_JSR305_ANNOTATIONS
// JSR305_GLOBAL_REPORT warn
// FILE: NonNullApi.java
@@ -1,5 +1,5 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// WARNING_FOR_JSR305_ANNOTATIONS
// JSR305_GLOBAL_REPORT warn
// FILE: A.java
@@ -1,5 +1,5 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// WARNING_FOR_JSR305_ANNOTATIONS
// JSR305_GLOBAL_REPORT warn
// FILE: test/package-info.java
@@ -1,5 +1,5 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// WARNING_FOR_JSR305_ANNOTATIONS
// JSR305_GLOBAL_REPORT warn
// FILE: spr/Nullable.java
@@ -1,5 +1,5 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// WARNING_FOR_JSR305_ANNOTATIONS
// JSR305_GLOBAL_REPORT warn
// FILE: spr/Nullable.java
@@ -0,0 +1,84 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// JSR305_GLOBAL_REPORT ignore
// FILE: MyErrorNonnull.java
import 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;
import kotlin.annotations.jvm.*;
@Documented
@TypeQualifierNickname
@Nonnull(when = When.ALWAYS)
@Retention(RetentionPolicy.RUNTIME)
@UnderMigration(status = MigrationStatus.STRICT)
public @interface MyErrorNonnull {
}
// FILE: MyWarnNonnull.java
import 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;
import kotlin.annotations.jvm.*;
@Documented
@TypeQualifierNickname
@Nonnull(when = When.ALWAYS)
@Retention(RetentionPolicy.RUNTIME)
@UnderMigration(status = MigrationStatus.WARN)
public @interface MyWarnNonnull {
}
// FILE: MyIgnoreNonnull.java
import 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;
import kotlin.annotations.jvm.*;
@Documented
@TypeQualifierNickname
@Nonnull(when = When.ALWAYS)
@Retention(RetentionPolicy.RUNTIME)
@UnderMigration(status = MigrationStatus.IGNORE)
public @interface MyIgnoreNonnull {
}
// FILE: A.java
public class A {
public void foo(@MyErrorNonnull String bar) {}
public void foo2(@MyWarnNonnull String bar) {}
public void foo3(@MyIgnoreNonnull String bar) {}
public void foo4(@MyMigrationNonnull String bar) {}
}
// FILE: main.kt
fun main(a: A) {
a.foo("")
a.foo(<!NULL_FOR_NONNULL_TYPE!>null<!>)
a.foo2("")
a.foo2(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)
a.foo3("")
a.foo3(null)
a.foo4("")
a.foo4(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)
}
@@ -0,0 +1,35 @@
package
public fun main(/*0*/ a: A): kotlin.Unit
public open class A {
public constructor A()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open fun foo(/*0*/ @MyErrorNonnull bar: kotlin.String): kotlin.Unit
public open fun foo2(/*0*/ @MyWarnNonnull bar: kotlin.String!): kotlin.Unit
public open fun foo3(/*0*/ @MyIgnoreNonnull bar: kotlin.String!): kotlin.Unit
public open fun foo4(/*0*/ @MyMigrationNonnull bar: kotlin.String!): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@kotlin.annotation.MustBeDocumented @javax.annotation.meta.TypeQualifierNickname @javax.annotation.Nonnull(when = When.ALWAYS) @kotlin.annotation.Retention(value = AnnotationRetention.RUNTIME) @kotlin.annotations.jvm.UnderMigration(status = MigrationStatus.STRICT) public final annotation class MyErrorNonnull : kotlin.Annotation {
public constructor MyErrorNonnull()
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.MustBeDocumented @javax.annotation.meta.TypeQualifierNickname @javax.annotation.Nonnull(when = When.ALWAYS) @kotlin.annotation.Retention(value = AnnotationRetention.RUNTIME) @kotlin.annotations.jvm.UnderMigration(status = MigrationStatus.IGNORE) public final annotation class MyIgnoreNonnull : kotlin.Annotation {
public constructor MyIgnoreNonnull()
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.MustBeDocumented @javax.annotation.meta.TypeQualifierNickname @javax.annotation.Nonnull(when = When.ALWAYS) @kotlin.annotation.Retention(value = AnnotationRetention.RUNTIME) @kotlin.annotations.jvm.UnderMigration(status = MigrationStatus.WARN) public final annotation class MyWarnNonnull : kotlin.Annotation {
public constructor MyWarnNonnull()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,57 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// JSR305_GLOBAL_REPORT ignore
// JSR305_MIGRATION_REPORT strict
// JSR305_SPECIAL_REPORT MyNonnull:warn
// FILE: A.java
import javax.annotation.*;
public class A {
@MyMigrationNullable public String field = null;
@MyMigrationNullable
public String foo(@MyMigrationNonnull String x, CharSequence y) {
return "";
}
@MyMigrationNonnull
public String bar() {
return "";
}
@MyNullable public String field2 = null;
@MyNullable
public String foo2(@MyNonnull String x, CharSequence y) {
return "";
}
@MyNonnull
public String bar2() {
return "";
}
}
// FILE: main.kt
fun main(a: A) {
a.foo("", null)?.length
a.foo("", null)<!UNSAFE_CALL!>.<!>length
a.foo(<!NULL_FOR_NONNULL_TYPE!>null<!>, "")<!UNSAFE_CALL!>.<!>length
a.bar().length
a.bar()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.length
a.field?.length
a.field<!UNSAFE_CALL!>.<!>length
a.foo2("", null)?.length
a.foo2("", null).length
a.foo2(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>, "").length
a.bar2().length
a.bar2()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.length
a.field2?.length
a.field2.length
}
@@ -0,0 +1,16 @@
package
public fun main(/*0*/ a: A): kotlin.Unit
public open class A {
public constructor A()
@MyMigrationNullable public final var field: kotlin.String?
@MyNullable public final var field2: kotlin.String!
@MyMigrationNonnull public open fun bar(): kotlin.String
@MyNonnull public open fun bar2(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
@MyMigrationNullable public open fun foo(/*0*/ @MyMigrationNonnull x: kotlin.String, /*1*/ y: kotlin.CharSequence!): kotlin.String?
@MyNullable public open fun foo2(/*0*/ @MyNonnull x: kotlin.String!, /*1*/ y: kotlin.CharSequence!): kotlin.String!
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,57 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// JSR305_GLOBAL_REPORT warn
// JSR305_MIGRATION_REPORT ignore
// JSR305_SPECIAL_REPORT MyNullable:strict, MyMigrationNonnull:strict
// FILE: A.java
import javax.annotation.*;
public class A {
@MyMigrationNullable public String field = null;
@MyMigrationNullable
public String foo(@MyMigrationNonnull String x, CharSequence y) {
return "";
}
@MyMigrationNonnull
public String bar() {
return "";
}
@MyNullable public String field2 = null;
@MyNullable
public String foo2(@MyNonnull String x, CharSequence y) {
return "";
}
@MyNonnull
public String bar2() {
return "";
}
}
// FILE: main.kt
fun main(a: A) {
a.foo("", null)?.length
a.foo("", null).length
a.foo(<!NULL_FOR_NONNULL_TYPE!>null<!>, "").length
a.bar().length
a.bar()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.length
a.field?.length
a.field.length
a.foo2("", null)?.length
a.foo2("", null)<!UNSAFE_CALL!>.<!>length
a.foo2(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>, "")<!UNSAFE_CALL!>.<!>length
a.bar2().length
a.bar2()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.length
a.field2?.length
a.field2<!UNSAFE_CALL!>.<!>length
}
@@ -0,0 +1,16 @@
package
public fun main(/*0*/ a: A): kotlin.Unit
public open class A {
public constructor A()
@MyMigrationNullable public final var field: kotlin.String!
@MyNullable public final var field2: kotlin.String?
@MyMigrationNonnull public open fun bar(): kotlin.String
@MyNonnull public open fun bar2(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
@MyMigrationNullable public open fun foo(/*0*/ @MyMigrationNonnull x: kotlin.String, /*1*/ y: kotlin.CharSequence!): kotlin.String!
@MyNullable public open fun foo2(/*0*/ @MyNonnull x: kotlin.String!, /*1*/ y: kotlin.CharSequence!): kotlin.String?
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,78 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// JSR305_GLOBAL_REPORT warn
// JSR305_MIGRATION_REPORT strict
// JSR305_SPECIAL_REPORT MyNonnull:ignore, MySuperNull:strict
// FILE: MySuperNull.java
import 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 MySuperNull {
}
// FILE: A.java
import javax.annotation.*;
public class A {
@MyMigrationNullable public String field = null;
@MyMigrationNullable
public String foo(@MyMigrationNonnull String x, CharSequence y) {
return "";
}
@MyMigrationNonnull
public String bar() {
return "";
}
@MyNullable public String field2 = null;
@MyNullable
public String foo2(@MyNonnull String x, CharSequence y) {
return "";
}
@MyNonnull
public String bar2() {
return "";
}
@MySuperNull public String field3 = null;
}
// FILE: main.kt
fun main(a: A) {
a.foo("", null)?.length
a.foo("", null)<!UNSAFE_CALL!>.<!>length
a.foo(<!NULL_FOR_NONNULL_TYPE!>null<!>, "")<!UNSAFE_CALL!>.<!>length
a.bar().length
a.bar()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.length
a.field?.length
a.field<!UNSAFE_CALL!>.<!>length
a.foo2("", null)?.length
<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>a.foo2("", null)<!>.length
<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>a.foo2(null, "")<!>.length
a.bar2().length
a.bar2()!!.length
a.field2?.length
<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>a.field2<!>.length
a.field3?.length
a.field3<!UNSAFE_CALL!>.<!>length
}
@@ -0,0 +1,24 @@
package
public fun main(/*0*/ a: A): kotlin.Unit
public open class A {
public constructor A()
@MyMigrationNullable public final var field: kotlin.String?
@MyNullable public final var field2: kotlin.String!
@MySuperNull public final var field3: kotlin.String?
@MyMigrationNonnull public open fun bar(): kotlin.String
@MyNonnull public open fun bar2(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
@MyMigrationNullable public open fun foo(/*0*/ @MyMigrationNonnull x: kotlin.String, /*1*/ y: kotlin.CharSequence!): kotlin.String?
@MyNullable public open fun foo2(/*0*/ @MyNonnull x: kotlin.String!, /*1*/ 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.MustBeDocumented @javax.annotation.meta.TypeQualifierNickname @javax.annotation.Nonnull(when = When.MAYBE) @kotlin.annotation.Retention(value = AnnotationRetention.RUNTIME) public final annotation class MySuperNull : kotlin.Annotation {
public constructor MySuperNull()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,57 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// JSR305_GLOBAL_REPORT strict
// JSR305_MIGRATION_REPORT ignore
// JSR305_SPECIAL_REPORT MyNullable:warn, MyMigrationNonnull:strict
// FILE: A.java
import javax.annotation.*;
public class A {
@MyMigrationNullable public String field = null;
@MyMigrationNullable
public String foo(@MyMigrationNonnull String x, CharSequence y) {
return "";
}
@MyMigrationNonnull
public String bar() {
return "";
}
@MyNullable public String field2 = null;
@MyNullable
public String foo2(@MyNonnull String x, CharSequence y) {
return "";
}
@MyNonnull
public String bar2() {
return "";
}
}
// FILE: main.kt
fun main(a: A) {
a.foo("", null)?.length
a.foo("", null).length
a.foo(<!NULL_FOR_NONNULL_TYPE!>null<!>, "").length
a.bar().length
a.bar()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.length
a.field?.length
a.field.length
a.foo2("", null)?.length
<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>a.foo2("", null)<!>.length
<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>a.foo2(<!NULL_FOR_NONNULL_TYPE!>null<!>, "")<!>.length
a.bar2().length
a.bar2()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.length
a.field2?.length
<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>a.field2<!>.length
}
@@ -0,0 +1,16 @@
package
public fun main(/*0*/ a: A): kotlin.Unit
public open class A {
public constructor A()
@MyMigrationNullable public final var field: kotlin.String!
@MyNullable public final var field2: kotlin.String!
@MyMigrationNonnull public open fun bar(): kotlin.String
@MyNonnull public open fun bar2(): kotlin.String
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
@MyMigrationNullable public open fun foo(/*0*/ @MyMigrationNonnull x: kotlin.String, /*1*/ y: kotlin.CharSequence!): kotlin.String!
@MyNullable public open fun foo2(/*0*/ @MyNonnull x: kotlin.String, /*1*/ y: kotlin.CharSequence!): kotlin.String!
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,57 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// JSR305_GLOBAL_REPORT strict
// JSR305_MIGRATION_REPORT warn
// JSR305_SPECIAL_REPORT MyNullable:ignore, MyMigrationNullable:strict
// FILE: A.java
import javax.annotation.*;
public class A {
@MyMigrationNullable public String field = null;
@MyMigrationNullable
public String foo(@MyMigrationNonnull String x, CharSequence y) {
return "";
}
@MyMigrationNonnull
public String bar() {
return "";
}
@MyNullable public String field2 = null;
@MyNullable
public String foo2(@MyNonnull String x, CharSequence y) {
return "";
}
@MyNonnull
public String bar2() {
return "";
}
}
// FILE: main.kt
fun main(a: A) {
a.foo("", null)?.length
a.foo("", null)<!UNSAFE_CALL!>.<!>length
a.foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>, "")<!UNSAFE_CALL!>.<!>length
a.bar().length
a.bar()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.length
a.field?.length
a.field<!UNSAFE_CALL!>.<!>length
a.foo2("", null)?.length
a.foo2("", null).length
a.foo2(<!NULL_FOR_NONNULL_TYPE!>null<!>, "").length
a.bar2().length
a.bar2()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.length
a.field2?.length
a.field2.length
}
@@ -0,0 +1,16 @@
package
public fun main(/*0*/ a: A): kotlin.Unit
public open class A {
public constructor A()
@MyMigrationNullable public final var field: kotlin.String?
@MyNullable public final var field2: kotlin.String!
@MyMigrationNonnull public open fun bar(): kotlin.String!
@MyNonnull public open fun bar2(): kotlin.String
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
@MyMigrationNullable public open fun foo(/*0*/ @MyMigrationNonnull x: kotlin.String!, /*1*/ y: kotlin.CharSequence!): kotlin.String?
@MyNullable public open fun foo2(/*0*/ @MyNonnull x: kotlin.String, /*1*/ y: kotlin.CharSequence!): kotlin.String!
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,85 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// JSR305_GLOBAL_REPORT warn
// JSR305_MIGRATION_REPORT strict
// FILE: A.java
import javax.annotation.Nullable;
import javax.annotation.Nonnull;
public class A {
@MyNullable
public String foo() { return ""; }
@MyMigrationNullable
public String foo2() { return ""; }
@Nullable
public String foo3() { return ""; }
public String foo4() { return ""; }
public void bar(@MyNonnull String baz) { }
public void bar2(@MyMigrationNonnull String baz) { }
public void bar3(@Nonnull String baz) {}
public void bar4(String baz) {}
}
// FILE: B.java
public class B extends A {
@MyMigrationNullable
public String foo() { return ""; }
@MyNullable
public String foo2() { return ""; }
@MyNullable
public String foo3() { return ""; }
@MyNullable
public String foo4() { return ""; }
public void bar(@MyMigrationNonnull String baz) { }
public void bar2(@MyNonnull String baz) { }
public void bar3(@MyNonnull String baz) {}
public void bar4(@MyNonnull String baz) {}
}
// FILE: C.java
public class C extends A {
@MyMigrationNullable
public String foo4() { return ""; }
public void bar4(@MyMigrationNonnull String baz) {}
}
// FILE: main.kt
fun main(b: B, c: C) {
b.foo()<!UNSAFE_CALL!>.<!>length
b.foo()?.length
b.foo2()<!UNSAFE_CALL!>.<!>length
b.foo2()?.length
b.foo3()<!UNSAFE_CALL!>.<!>length
b.foo3()?.length
<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>b.foo4()<!>.length
b.foo4()?.length
b.bar(<!NULL_FOR_NONNULL_TYPE!>null<!>)
b.bar("")
b.bar2(<!NULL_FOR_NONNULL_TYPE!>null<!>)
b.bar2("")
b.bar3(<!NULL_FOR_NONNULL_TYPE!>null<!>)
b.bar3("")
b.bar4(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)
b.bar4("")
c.foo4()<!UNSAFE_CALL!>.<!>length
c.foo4()?.length
c.bar4(<!NULL_FOR_NONNULL_TYPE!>null<!>)
c.bar4("")
}
@@ -0,0 +1,48 @@
package
public fun main(/*0*/ b: B, /*1*/ c: C): kotlin.Unit
public open class A {
public constructor A()
public open fun bar(/*0*/ @MyNonnull baz: kotlin.String!): kotlin.Unit
public open fun bar2(/*0*/ @MyMigrationNonnull baz: kotlin.String): kotlin.Unit
public open fun bar3(/*0*/ @javax.annotation.Nonnull baz: kotlin.String): kotlin.Unit
public open fun bar4(/*0*/ baz: kotlin.String!): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
@MyNullable public open fun foo(): kotlin.String!
@MyMigrationNullable public open fun foo2(): kotlin.String?
@javax.annotation.Nullable public open fun foo3(): kotlin.String?
public open fun foo4(): 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 B : A {
public constructor B()
public open override /*1*/ fun bar(/*0*/ @MyMigrationNonnull baz: kotlin.String): kotlin.Unit
public open override /*1*/ fun bar2(/*0*/ @MyNonnull baz: kotlin.String): kotlin.Unit
public open override /*1*/ fun bar3(/*0*/ @MyNonnull baz: kotlin.String): kotlin.Unit
public open override /*1*/ fun bar4(/*0*/ @MyNonnull baz: kotlin.String!): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
@MyMigrationNullable public open override /*1*/ fun foo(): kotlin.String?
@MyNullable public open override /*1*/ fun foo2(): kotlin.String?
@MyNullable public open override /*1*/ fun foo3(): kotlin.String?
@MyNullable public open override /*1*/ fun foo4(): 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 C : A {
public constructor C()
public open override /*1*/ /*fake_override*/ fun bar(/*0*/ @MyNonnull baz: kotlin.String!): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun bar2(/*0*/ @MyMigrationNonnull baz: kotlin.String): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun bar3(/*0*/ @javax.annotation.Nonnull baz: kotlin.String): kotlin.Unit
public open override /*1*/ fun bar4(/*0*/ @MyMigrationNonnull baz: kotlin.String): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
@MyNullable public open override /*1*/ /*fake_override*/ fun foo(): kotlin.String!
@MyMigrationNullable public open override /*1*/ /*fake_override*/ fun foo2(): kotlin.String?
@javax.annotation.Nullable public open override /*1*/ /*fake_override*/ fun foo3(): kotlin.String?
@MyMigrationNullable public open override /*1*/ fun foo4(): kotlin.String?
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,37 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// JSR305_GLOBAL_REPORT ignore
// JSR305_MIGRATION_REPORT ignore
// JSR305_SPECIAL_REPORT MyNonnull:warn, MyMigrationNonnull:strict
// FILE: A.java
import javax.annotation.*;
public class A {
@MyMigrationNullable public String field = null;
@MyMigrationNullable
public String foo(@MyMigrationNonnull String x, CharSequence y) {
return "";
}
@MyNonnull
@MyMigrationNonnull
public String bar() {
return "";
}
}
// FILE: main.kt
fun main(a: A) {
a.foo("", null)?.length
a.foo("", null).length
a.foo(<!NULL_FOR_NONNULL_TYPE!>null<!>, "").length
a.bar().length
a.bar()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.length
a.field?.length
a.field.length
}
@@ -0,0 +1,13 @@
package
public fun main(/*0*/ a: A): kotlin.Unit
public open class A {
public constructor A()
@MyMigrationNullable public final var field: kotlin.String!
@MyNonnull @MyMigrationNonnull public open fun bar(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
@MyMigrationNullable public open fun foo(/*0*/ @MyMigrationNonnull x: kotlin.String, /*1*/ y: kotlin.CharSequence!): kotlin.String!
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,57 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// JSR305_GLOBAL_REPORT ignore
// JSR305_MIGRATION_REPORT warn
// JSR305_SPECIAL_REPORT MyNonnull:strict
// FILE: A.java
import javax.annotation.*;
public class A {
@MyMigrationNullable public String field = null;
@MyMigrationNullable
public String foo(@MyMigrationNonnull String x, CharSequence y) {
return "";
}
@MyMigrationNonnull
public String bar() {
return "";
}
@MyNullable public String field2 = null;
@MyNullable
public String foo2(@MyNonnull String x, CharSequence y) {
return "";
}
@MyNonnull
public String bar2() {
return "";
}
}
// FILE: main.kt
fun main(a: A) {
a.foo("", null)?.length
<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>a.foo("", null)<!>.length
<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>a.foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>, "")<!>.length
a.bar().length
a.bar()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.length
a.field?.length
<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>a.field<!>.length
a.foo2("", null)?.length
a.foo2("", null).length
a.foo2(<!NULL_FOR_NONNULL_TYPE!>null<!>, "").length
a.bar2().length
a.bar2()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.length
a.field2?.length
a.field2.length
}
@@ -0,0 +1,16 @@
package
public fun main(/*0*/ a: A): kotlin.Unit
public open class A {
public constructor A()
@MyMigrationNullable public final var field: kotlin.String!
@MyNullable public final var field2: kotlin.String!
@MyMigrationNonnull public open fun bar(): kotlin.String!
@MyNonnull public open fun bar2(): kotlin.String
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
@MyMigrationNullable public open fun foo(/*0*/ @MyMigrationNonnull x: kotlin.String!, /*1*/ y: kotlin.CharSequence!): kotlin.String!
@MyNullable public open fun foo2(/*0*/ @MyNonnull x: kotlin.String, /*1*/ 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
}
@@ -71,6 +71,11 @@ public class ForTestCompileRuntime {
return assertExists(new File("dist/kotlinc/lib/kotlin-stdlib-js.jar"));
}
@NotNull
public static File jvmAnnotationsForTests() {
return assertExists(new File("dist/kotlinc/lib/kotlin-annotations-jvm.jar"));
}
// TODO: Do not use these classes, remove them after stdlib tests are merged in the same build as the compiler
@NotNull
@Deprecated
@@ -19,11 +19,11 @@ package org.jetbrains.kotlin.checkers
import org.jetbrains.kotlin.codegen.CodegenTestUtil
import org.jetbrains.kotlin.test.InTextDirectivesUtils
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.MockLibraryUtil
import java.io.File
abstract class AbstractForeignAnnotationsNoAnnotationInClasspathTest : AbstractForeignAnnotationsTest() {
private val compiledJavaPath = KotlinTestUtils.tmpDir("java-compiled-files")
override fun getExtraClasspath(): List<File> {
val foreignAnnotations = createJarWithForeignAnnotations()
val testAnnotations = compileTestAnnotations(foreignAnnotations)
@@ -45,7 +45,4 @@ abstract class AbstractForeignAnnotationsNoAnnotationInClasspathTest : AbstractF
override fun isJavaSourceRootNeeded() = false
override fun skipDescriptorsValidation() = true
private fun createJarWithForeignAnnotations(): List<File> =
listOf(MockLibraryUtil.compileJvmLibraryToJar(annotationsPath, "foreign-annotations"))
}
@@ -16,23 +16,26 @@
package org.jetbrains.kotlin.checkers
import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime
import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.test.ConfigurationKind
import org.jetbrains.kotlin.test.InTextDirectivesUtils
import org.jetbrains.kotlin.test.MockLibraryUtil
import org.jetbrains.kotlin.test.TestJdkKind
import org.jetbrains.kotlin.utils.Jsr305State
import org.jetbrains.kotlin.utils.ReportLevel
import java.io.File
val FOREIGN_ANNOTATIONS_SOURCES_PATH = "third-party/annotations"
val TEST_ANNOTATIONS_SOURCE_PATH = "compiler/testData/foreignAnnotations/testAnnotations"
abstract class AbstractForeignAnnotationsTest : AbstractDiagnosticsTest() {
private val WARNING_FOR_JSR305_ANNOTATIONS_DIRECTIVE = "WARNING_FOR_JSR305_ANNOTATIONS"
private val JSR305_ANNOTATIONS_IGNORE_DIRECTIVE = "JSR305_ANNOTATIONS_IGNORE"
private val JSR305_GLOBAL_DIRECTIVE = "JSR305_GLOBAL_REPORT"
private val JSR305_MIGRATION_DIRECTIVE = "JSR305_MIGRATION_REPORT"
private val JSR305_SPECIAL_DIRECTIVE = "JSR305_SPECIAL_REPORT"
override fun getExtraClasspath(): List<File> {
val foreignAnnotations = listOf(MockLibraryUtil.compileJvmLibraryToJar(annotationsPath, "foreign-annotations"))
val foreignAnnotations = createJarWithForeignAnnotations()
return foreignAnnotations + compileTestAnnotations(foreignAnnotations)
}
@@ -40,9 +43,15 @@ abstract class AbstractForeignAnnotationsTest : AbstractDiagnosticsTest() {
listOf(MockLibraryUtil.compileJvmLibraryToJar(
TEST_ANNOTATIONS_SOURCE_PATH,
"test-foreign-annotations",
extraOptions = listOf("-Xallow-kotlin-package"),
extraClasspath = extraClassPath.map { it.path }
))
protected fun createJarWithForeignAnnotations(): List<File> = listOf(
MockLibraryUtil.compileJvmLibraryToJar(annotationsPath, "foreign-annotations"),
ForTestCompileRuntime.jvmAnnotationsForTests()
)
override fun getConfigurationKind(): ConfigurationKind = ConfigurationKind.ALL
override fun getTestJdkKind(file: File): TestJdkKind = TestJdkKind.FULL_JDK
@@ -51,22 +60,27 @@ abstract class AbstractForeignAnnotationsTest : AbstractDiagnosticsTest() {
get() = FOREIGN_ANNOTATIONS_SOURCES_PATH
override fun loadLanguageVersionSettings(module: List<TestFile>): LanguageVersionSettings {
val hasWarningDirective = module.any {
InTextDirectivesUtils.isDirectiveDefined(it.expectedText, WARNING_FOR_JSR305_ANNOTATIONS_DIRECTIVE)
}
val hasIgnoreDirective = module.any {
InTextDirectivesUtils.isDirectiveDefined(it.expectedText, JSR305_ANNOTATIONS_IGNORE_DIRECTIVE)
}
val jsr305State = when {
hasIgnoreDirective -> Jsr305State.IGNORE
hasWarningDirective -> Jsr305State.WARN
else -> Jsr305State.STRICT
}
return LanguageVersionSettingsImpl(LanguageVersion.LATEST_STABLE, ApiVersion.LATEST_STABLE,
mapOf(AnalysisFlag.jsr305 to jsr305State)
)
val analysisFlags = loadAnalysisFlags(module)
return LanguageVersionSettingsImpl(LanguageVersion.LATEST_STABLE, ApiVersion.LATEST_STABLE, analysisFlags)
}
private fun loadAnalysisFlags(module: List<TestFile>): Map<AnalysisFlag<*>, Any?> {
val globalState = module.getDirectiveValue(JSR305_GLOBAL_DIRECTIVE) ?: ReportLevel.STRICT
val migrationState = module.getDirectiveValue(JSR305_MIGRATION_DIRECTIVE)
val userAnnotationsState = module.flatMap {
InTextDirectivesUtils.findListWithPrefixes(it.expectedText, JSR305_SPECIAL_DIRECTIVE)
}.mapNotNull {
val (name, stateDescription) = it.split(":").takeIf { it.size == 2 } ?: return@mapNotNull null
val state = ReportLevel.findByDescription(stateDescription) ?: return@mapNotNull null
name to state
}.toMap()
return mapOf(AnalysisFlag.jsr305 to Jsr305State(globalState, migrationState, userAnnotationsState))
}
private fun List<TestFile>.getDirectiveValue(directive: String): ReportLevel? = mapNotNull {
InTextDirectivesUtils.findLinesWithPrefixesRemoved(it.expectedText, directive).firstOrNull()
}.firstOrNull().let { ReportLevel.findByDescription(it) }
}
@@ -401,4 +401,76 @@ public class ForeignAnnotationsNoAnnotationInClasspathTestGenerated extends Abst
}
}
}
@TestMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Jsr305NullabilityWarnings extends AbstractForeignAnnotationsNoAnnotationInClasspathTest {
public void testAllFilesPresentInJsr305NullabilityWarnings() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Migration extends AbstractForeignAnnotationsNoAnnotationInClasspathTest {
public void testAllFilesPresentInMigration() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("customMigration.kt")
public void testCustomMigration() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration/customMigration.kt");
doTest(fileName);
}
@TestMetadata("globalIgnore.kt")
public void testGlobalIgnore() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration/globalIgnore.kt");
doTest(fileName);
}
@TestMetadata("globalWarningMigrationIgnore.kt")
public void testGlobalWarningMigrationIgnore() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration/globalWarningMigrationIgnore.kt");
doTest(fileName);
}
@TestMetadata("migrationError.kt")
public void testMigrationError() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration/migrationError.kt");
doTest(fileName);
}
@TestMetadata("migrationIgnore.kt")
public void testMigrationIgnore() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration/migrationIgnore.kt");
doTest(fileName);
}
@TestMetadata("migrationWarning.kt")
public void testMigrationWarning() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration/migrationWarning.kt");
doTest(fileName);
}
@TestMetadata("overrideConflicts.kt")
public void testOverrideConflicts() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration/overrideConflicts.kt");
doTest(fileName);
}
@TestMetadata("specialCollision.kt")
public void testSpecialCollision() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration/specialCollision.kt");
doTest(fileName);
}
@TestMetadata("stateRefinement.kt")
public void testStateRefinement() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration/stateRefinement.kt");
doTest(fileName);
}
}
}
}
@@ -401,4 +401,76 @@ public class ForeignAnnotationsNoAnnotationInClasspathWithFastClassReadingTestGe
}
}
}
@TestMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Jsr305NullabilityWarnings extends AbstractForeignAnnotationsNoAnnotationInClasspathWithFastClassReadingTest {
public void testAllFilesPresentInJsr305NullabilityWarnings() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Migration extends AbstractForeignAnnotationsNoAnnotationInClasspathWithFastClassReadingTest {
public void testAllFilesPresentInMigration() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("customMigration.kt")
public void testCustomMigration() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration/customMigration.kt");
doTest(fileName);
}
@TestMetadata("globalIgnore.kt")
public void testGlobalIgnore() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration/globalIgnore.kt");
doTest(fileName);
}
@TestMetadata("globalWarningMigrationIgnore.kt")
public void testGlobalWarningMigrationIgnore() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration/globalWarningMigrationIgnore.kt");
doTest(fileName);
}
@TestMetadata("migrationError.kt")
public void testMigrationError() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration/migrationError.kt");
doTest(fileName);
}
@TestMetadata("migrationIgnore.kt")
public void testMigrationIgnore() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration/migrationIgnore.kt");
doTest(fileName);
}
@TestMetadata("migrationWarning.kt")
public void testMigrationWarning() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration/migrationWarning.kt");
doTest(fileName);
}
@TestMetadata("overrideConflicts.kt")
public void testOverrideConflicts() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration/overrideConflicts.kt");
doTest(fileName);
}
@TestMetadata("specialCollision.kt")
public void testSpecialCollision() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration/specialCollision.kt");
doTest(fileName);
}
@TestMetadata("stateRefinement.kt")
public void testStateRefinement() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration/stateRefinement.kt");
doTest(fileName);
}
}
}
}
@@ -401,4 +401,76 @@ public class ForeignAnnotationsTestGenerated extends AbstractForeignAnnotationsT
}
}
}
@TestMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Jsr305NullabilityWarnings extends AbstractForeignAnnotationsTest {
public void testAllFilesPresentInJsr305NullabilityWarnings() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Migration extends AbstractForeignAnnotationsTest {
public void testAllFilesPresentInMigration() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("customMigration.kt")
public void testCustomMigration() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration/customMigration.kt");
doTest(fileName);
}
@TestMetadata("globalIgnore.kt")
public void testGlobalIgnore() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration/globalIgnore.kt");
doTest(fileName);
}
@TestMetadata("globalWarningMigrationIgnore.kt")
public void testGlobalWarningMigrationIgnore() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration/globalWarningMigrationIgnore.kt");
doTest(fileName);
}
@TestMetadata("migrationError.kt")
public void testMigrationError() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration/migrationError.kt");
doTest(fileName);
}
@TestMetadata("migrationIgnore.kt")
public void testMigrationIgnore() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration/migrationIgnore.kt");
doTest(fileName);
}
@TestMetadata("migrationWarning.kt")
public void testMigrationWarning() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration/migrationWarning.kt");
doTest(fileName);
}
@TestMetadata("overrideConflicts.kt")
public void testOverrideConflicts() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration/overrideConflicts.kt");
doTest(fileName);
}
@TestMetadata("specialCollision.kt")
public void testSpecialCollision() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration/specialCollision.kt");
doTest(fileName);
}
@TestMetadata("stateRefinement.kt")
public void testStateRefinement() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration/stateRefinement.kt");
doTest(fileName);
}
}
}
}
@@ -401,4 +401,76 @@ public class JavacForeignAnnotationsTestGenerated extends AbstractJavacForeignAn
}
}
}
@TestMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Jsr305NullabilityWarnings extends AbstractJavacForeignAnnotationsTest {
public void testAllFilesPresentInJsr305NullabilityWarnings() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Migration extends AbstractJavacForeignAnnotationsTest {
public void testAllFilesPresentInMigration() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("customMigration.kt")
public void testCustomMigration() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration/customMigration.kt");
doTest(fileName);
}
@TestMetadata("globalIgnore.kt")
public void testGlobalIgnore() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration/globalIgnore.kt");
doTest(fileName);
}
@TestMetadata("globalWarningMigrationIgnore.kt")
public void testGlobalWarningMigrationIgnore() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration/globalWarningMigrationIgnore.kt");
doTest(fileName);
}
@TestMetadata("migrationError.kt")
public void testMigrationError() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration/migrationError.kt");
doTest(fileName);
}
@TestMetadata("migrationIgnore.kt")
public void testMigrationIgnore() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration/migrationIgnore.kt");
doTest(fileName);
}
@TestMetadata("migrationWarning.kt")
public void testMigrationWarning() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration/migrationWarning.kt");
doTest(fileName);
}
@TestMetadata("overrideConflicts.kt")
public void testOverrideConflicts() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration/overrideConflicts.kt");
doTest(fileName);
}
@TestMetadata("specialCollision.kt")
public void testSpecialCollision() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration/specialCollision.kt");
doTest(fileName);
}
@TestMetadata("stateRefinement.kt")
public void testStateRefinement() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityWarnings/migration/stateRefinement.kt");
doTest(fileName);
}
}
}
}
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.container.get
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.descriptors.resolveClassByFqName
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.load.java.AnnotationTypeQualifierResolver
@@ -128,7 +129,7 @@ class TypeQualifierAnnotationResolverTest : KtUsefulTestCase() {
private fun ClassDescriptor.findSingleTypeQualifierAnnotationOnMethod(
name: String,
typeQualifierResolver: AnnotationTypeQualifierResolver
) = unsubstitutedMemberScope
): AnnotationDescriptor = unsubstitutedMemberScope
.getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_TEST)
.single()
.annotations.single()
@@ -98,4 +98,4 @@ public annotation class Repeatable
* documentation for the element to which the annotation is applied.
*/
@Target(AnnotationTarget.ANNOTATION_CLASS)
public annotation class MustBeDocumented
public annotation class MustBeDocumented
@@ -19,21 +19,42 @@ package org.jetbrains.kotlin.load.java
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.load.java.lazy.NullabilityQualifierWithApplicability
import org.jetbrains.kotlin.load.java.typeEnhancement.NullabilityQualifier
import org.jetbrains.kotlin.load.java.typeEnhancement.NullabilityQualifierWithMigrationStatus
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.constants.ArrayValue
import org.jetbrains.kotlin.resolve.constants.ConstantValue
import org.jetbrains.kotlin.resolve.constants.EnumValue
import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass
import org.jetbrains.kotlin.resolve.descriptorUtil.firstArgumentValue
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.utils.Jsr305State
import org.jetbrains.kotlin.utils.ReportLevel
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
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, val jsr305State: Jsr305State) {
private val MIGRATION_ANNOTATION_FQNAME = FqName("kotlin.annotations.jvm.UnderMigration")
private val BUILT_IN_TYPE_QUALIFIER_DEFAULT_ANNOTATIONS = mapOf(
FqName("javax.annotation.ParametersAreNullableByDefault") to
NullabilityQualifierWithApplicability(
NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE),
listOf(AnnotationTypeQualifierResolver.QualifierApplicabilityType.VALUE_PARAMETER)
),
FqName("javax.annotation.ParametersAreNonnullByDefault") to
NullabilityQualifierWithApplicability(
NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL),
listOf(AnnotationTypeQualifierResolver.QualifierApplicabilityType.VALUE_PARAMETER)
)
)
class AnnotationTypeQualifierResolver(storageManager: StorageManager, private val jsr305State: Jsr305State) {
enum class QualifierApplicabilityType {
METHOD_RETURN_TYPE, VALUE_PARAMETER, FIELD, TYPE_USE
}
@@ -68,7 +89,7 @@ class AnnotationTypeQualifierResolver(storageManager: StorageManager, val jsr305
}
fun resolveTypeQualifierAnnotation(annotationDescriptor: AnnotationDescriptor): AnnotationDescriptor? {
if (jsr305State.isIgnored()) {
if (jsr305State.disabled) {
return null
}
@@ -78,8 +99,19 @@ class AnnotationTypeQualifierResolver(storageManager: StorageManager, val jsr305
return resolveTypeQualifierNickname(annotationClass)
}
fun resolveQualifierBuiltInDefaultAnnotation(annotationDescriptor: AnnotationDescriptor): NullabilityQualifierWithApplicability? {
if (jsr305State.disabled) {
return null
}
return BUILT_IN_TYPE_QUALIFIER_DEFAULT_ANNOTATIONS[annotationDescriptor.fqName]?.let { (qualifier, applicability) ->
val state = resolveJsr305AnnotationState(annotationDescriptor).takeIf { it != ReportLevel.IGNORE } ?: return null
return NullabilityQualifierWithApplicability(qualifier.copy(isForWarningOnly = state.isWarning), applicability)
}
}
fun resolveTypeQualifierDefaultAnnotation(annotationDescriptor: AnnotationDescriptor): TypeQualifierWithApplicability? {
if (jsr305State.isIgnored()) {
if (jsr305State.disabled) {
return null
}
@@ -99,12 +131,34 @@ class AnnotationTypeQualifierResolver(storageManager: StorageManager, val jsr305
}
.fold(0) { acc: Int, applicabilityType -> acc or (1 shl applicabilityType.ordinal) }
val typeQualifier =
typeQualifierDefaultAnnotatedClass.annotations.firstNotNullResult(this::resolveTypeQualifierAnnotation)
?: return null
val typeQualifier = typeQualifierDefaultAnnotatedClass.annotations.firstOrNull { resolveTypeQualifierAnnotation(it) != null }
?: return null
return TypeQualifierWithApplicability(typeQualifier, elementTypesMask)
}
fun resolveJsr305AnnotationState(annotationDescriptor: AnnotationDescriptor): ReportLevel {
jsr305State.user[annotationDescriptor.fqName?.asString()]?.let { return it }
annotationDescriptor.annotationClass?.migrationAnnotationStatus()?.let { return it }
return jsr305State.global
}
private fun ClassDescriptor.migrationAnnotationStatus(): ReportLevel? {
val stateDescriptor = annotations.findAnnotation(MIGRATION_ANNOTATION_FQNAME)?.firstArgumentValue()?.safeAs<ClassDescriptor>()
?: return null
jsr305State.migration?.let { return jsr305State.migration }
return when (stateDescriptor.name.asString()) {
"STRICT" -> ReportLevel.STRICT
"WARN" -> ReportLevel.WARN
"IGNORE" -> ReportLevel.IGNORE
else -> null
}
}
private fun ConstantValue<*>.mapConstantToQualifierApplicabilityTypes(): List<QualifierApplicabilityType> =
when (this) {
is ArrayValue -> value.flatMap { it.mapConstantToQualifierApplicabilityTypes() }
@@ -119,6 +173,8 @@ class AnnotationTypeQualifierResolver(storageManager: StorageManager, val jsr305
)
else -> emptyList()
}
val disabled: Boolean = jsr305State.disabled
}
val BUILT_IN_TYPE_QUALIFIER_FQ_NAMES = setOf(JAVAX_NONNULL_ANNOTATION, JAVAX_CHECKFORNULL_ANNOTATION)
@@ -28,14 +28,13 @@ 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.NullabilityQualifierWithMigrationStatus
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.name.FqName
import org.jetbrains.kotlin.serialization.deserialization.ErrorReporter
import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.utils.ReportLevel
import java.util.*
class JavaResolverComponents(
@@ -116,7 +115,7 @@ fun LazyJavaResolverContext.child(
fun LazyJavaResolverContext.computeNewDefaultTypeQualifiers(
additionalAnnotations: Annotations
): JavaTypeQualifiersByElementType? {
if (components.annotationTypeQualifierResolver.jsr305State.isIgnored()) return defaultTypeQualifiers
if (components.annotationTypeQualifierResolver.disabled) return defaultTypeQualifiers
val nullabilityQualifiersWithApplicability =
additionalAnnotations.mapNotNull(this::extractDefaultNullabilityQualifier)
@@ -128,10 +127,9 @@ fun LazyJavaResolverContext.computeNewDefaultTypeQualifiers(
?: QualifierByApplicabilityType(AnnotationTypeQualifierResolver.QualifierApplicabilityType::class.java)
var wasUpdate = false
val isForWarning = components.annotationTypeQualifierResolver.jsr305State.isWarning()
for ((nullability, applicableTo) in nullabilityQualifiersWithApplicability) {
for (applicabilityType in applicableTo) {
nullabilityQualifiersByType[applicabilityType] = NullabilityQualifierWithMigrationStatus(nullability, isForWarning)
nullabilityQualifiersByType[applicabilityType] = nullability
wasUpdate = true
}
}
@@ -142,35 +140,30 @@ fun LazyJavaResolverContext.computeNewDefaultTypeQualifiers(
private fun LazyJavaResolverContext.extractDefaultNullabilityQualifier(
annotationDescriptor: AnnotationDescriptor
): NullabilityQualifierWithApplicability? {
BUILT_IN_TYPE_QUALIFIER_DEFAULT_ANNOTATIONS[annotationDescriptor.fqName]?.let { return it }
val typeQualifierResolver = components.annotationTypeQualifierResolver
typeQualifierResolver.resolveQualifierBuiltInDefaultAnnotation(annotationDescriptor)?.let { return it }
val (typeQualifier, applicability) =
components.annotationTypeQualifierResolver.resolveTypeQualifierDefaultAnnotation(annotationDescriptor)
typeQualifierResolver.resolveTypeQualifierDefaultAnnotation(annotationDescriptor)
?: return null
val nullabilityQualifier = components.signatureEnhancement.extractNullability(typeQualifier)?.qualifier ?: return null
val jsr305State = typeQualifierResolver.resolveJsr305AnnotationState(typeQualifier).takeIf { it != ReportLevel.IGNORE } ?: return null
val nullabilityQualifier =
components
.signatureEnhancement
.extractNullability(typeQualifier)
?.copy(isForWarningOnly = jsr305State.isWarning)
?: return null
return NullabilityQualifierWithApplicability(nullabilityQualifier, applicability)
}
data class NullabilityQualifierWithApplicability(
val nullabilityQualifier: NullabilityQualifier,
val nullabilityQualifier: NullabilityQualifierWithMigrationStatus,
val qualifierApplicabilityTypes: Collection<AnnotationTypeQualifierResolver.QualifierApplicabilityType>
)
private val BUILT_IN_TYPE_QUALIFIER_DEFAULT_ANNOTATIONS = mapOf(
FqName("javax.annotation.ParametersAreNullableByDefault") to
NullabilityQualifierWithApplicability(
NullabilityQualifier.NULLABLE,
listOf(AnnotationTypeQualifierResolver.QualifierApplicabilityType.VALUE_PARAMETER)
),
FqName("javax.annotation.ParametersAreNonnullByDefault") to
NullabilityQualifierWithApplicability(
NullabilityQualifier.NOT_NULL,
listOf(AnnotationTypeQualifierResolver.QualifierApplicabilityType.VALUE_PARAMETER)
)
)
fun LazyJavaResolverContext.replaceComponents(
components: JavaResolverComponents
) = LazyJavaResolverContext(components, typeParameterResolver, delegateForDefaultTypeQualifiers)
@@ -55,7 +55,7 @@ class LazyJavaPackageFragment(
override val annotations =
// Do not resolve package annotations if JSR-305 is disabled
if (c.components.annotationTypeQualifierResolver.jsr305State.isIgnored()) Annotations.EMPTY
if (c.components.annotationTypeQualifierResolver.disabled) Annotations.EMPTY
else c.resolveAnnotations(jPackage)
internal fun getSubPackageFqNames(): List<FqName> = subPackages()
@@ -52,8 +52,8 @@ class SignatureEnhancement(private val annotationTypeQualifierResolver: Annotati
private fun AnnotationDescriptor.extractNullabilityTypeFromArgument(): NullabilityQualifierWithMigrationStatus? {
val enumEntryDescriptor = firstArgumentValue()
// if no argument is specified, use default value: NOT_NULL
?: return NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL)
// if no argument is specified, use default value: NOT_NULL
?: return NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL)
if (enumEntryDescriptor !is ClassDescriptor) return null
@@ -72,9 +72,10 @@ class SignatureEnhancement(private val annotationTypeQualifierResolver: Annotati
annotationTypeQualifierResolver.resolveTypeQualifierAnnotation(annotationDescriptor)
?: return null
val forWarning = annotationTypeQualifierResolver.jsr305State.isWarning()
val jsr305State = annotationTypeQualifierResolver.resolveJsr305AnnotationState(annotationDescriptor)
if (jsr305State.isIgnore) return null
return extractNullabilityFromKnownAnnotations(typeQualifierAnnotation)?.copy(isForWarningOnly = forWarning)
return extractNullabilityFromKnownAnnotations(typeQualifierAnnotation)?.copy(isForWarningOnly = jsr305State.isWarning)
}
private fun extractNullabilityFromKnownAnnotations(
@@ -119,7 +120,7 @@ class SignatureEnhancement(private val annotationTypeQualifierResolver: Annotati
if (extensionReceiverParameter != null)
partsForValueParameter(
parameterDescriptor =
annotationOwnerForMember.safeAs<FunctionDescriptor>()
annotationOwnerForMember.safeAs<FunctionDescriptor>()
?.getUserData(JavaMethodDescriptor.ORIGINAL_VALUE_PARAMETER_FOR_EXTENSION_RECEIVER),
methodContext = memberContext
) { it.extensionReceiverParameter!!.type }.enhance()
@@ -138,10 +139,9 @@ class SignatureEnhancement(private val annotationTypeQualifierResolver: Annotati
}
}
val valueParameterEnhancements = annotationOwnerForMember.valueParameters.map {
p ->
partsForValueParameter(p, memberContext) { it.valueParameters[p.index].type }
.enhance(predefinedEnhancementInfo?.parametersInfo?.getOrNull(p.index))
val valueParameterEnhancements = annotationOwnerForMember.valueParameters.map { p ->
partsForValueParameter(p, memberContext) { it.valueParameters[p.index].type }
.enhance(predefinedEnhancementInfo?.parametersInfo?.getOrNull(p.index))
}
val returnTypeEnhancement =
@@ -149,10 +149,10 @@ class SignatureEnhancement(private val annotationTypeQualifierResolver: Annotati
typeContainer = annotationOwnerForMember, isCovariant = true,
containerContext = memberContext,
containerApplicabilityType =
if (this.safeAs<PropertyDescriptor>()?.isJavaField == true)
AnnotationTypeQualifierResolver.QualifierApplicabilityType.FIELD
else
AnnotationTypeQualifierResolver.QualifierApplicabilityType.METHOD_RETURN_TYPE
if (this.safeAs<PropertyDescriptor>()?.isJavaField == true)
AnnotationTypeQualifierResolver.QualifierApplicabilityType.FIELD
else
AnnotationTypeQualifierResolver.QualifierApplicabilityType.METHOD_RETURN_TYPE
) { it.returnType!! }.enhance(predefinedEnhancementInfo?.returnTypeInfo)
if ((receiverTypeEnhancement?.wereChanges ?: false)
@@ -176,14 +176,12 @@ class SignatureEnhancement(private val annotationTypeQualifierResolver: Annotati
val qualifiers = computeIndexedQualifiersForOverride()
val qualifiersWithPredefined: ((Int) -> JavaTypeQualifiers)? = predefined?.let {
{
index ->
{ index ->
predefined.map[index] ?: qualifiers(index)
}
}
return fromOverride.enhance(qualifiersWithPredefined ?: qualifiers)?.let {
enhanced ->
return fromOverride.enhance(qualifiersWithPredefined ?: qualifiers)?.let { enhanced ->
PartEnhancementResult(enhanced, wereChanges = true)
} ?: PartEnhancementResult(fromOverride, wereChanges = false)
}
@@ -219,10 +217,10 @@ class SignatureEnhancement(private val annotationTypeQualifierResolver: Annotati
else
annotations
fun <T: Any> List<FqName>.ifPresent(qualifier: T) =
fun <T : Any> List<FqName>.ifPresent(qualifier: T) =
if (any { composedAnnotation.findAnnotation(it) != null }) qualifier else null
fun <T: Any> uniqueNotNull(x: T?, y: T?) = if (x == null || y == null || x == y) x ?: y else null
fun <T : Any> uniqueNotNull(x: T?, y: T?) = if (x == null || y == null || x == y) x ?: y else null
val defaultTypeQualifier =
if (isHeadTypeConstructor)
@@ -270,8 +268,7 @@ class SignatureEnhancement(private val annotationTypeQualifierResolver: Annotati
val onlyHeadTypeConstructor = isCovariant && fromOverridden.any { !KotlinTypeChecker.DEFAULT.equalTypes(it, fromOverride) }
val treeSize = if (onlyHeadTypeConstructor) 1 else indexedThisType.size
val computedResult = Array(treeSize) {
index ->
val computedResult = Array(treeSize) { index ->
val isHeadTypeConstructor = index == 0
assert(isHeadTypeConstructor || !onlyHeadTypeConstructor) { "Only head type constructors should be computed" }
@@ -59,7 +59,7 @@ class RuntimeModuleData private constructor(
val runtimePackagePartProvider = RuntimePackagePartProvider(classLoader)
val javaResolverCache = JavaResolverCache.EMPTY
val notFoundClasses = NotFoundClasses(storageManager, module)
val annotationTypeQualifierResolver = AnnotationTypeQualifierResolver(storageManager, Jsr305State.IGNORE)
val annotationTypeQualifierResolver = AnnotationTypeQualifierResolver(storageManager, Jsr305State.DISABLED)
val globalJavaResolverContext = JavaResolverComponents(
storageManager, ReflectJavaClassFinder(classLoader), reflectKotlinClassFinder, deserializedDescriptorResolver,
ExternalAnnotationResolver.EMPTY, SignaturePropagator.DO_NOTHING, RuntimeErrorReporter, javaResolverCache,
@@ -16,21 +16,48 @@
package org.jetbrains.kotlin.utils
enum class Jsr305State(
val description: String
) {
enum class ReportLevel(val description: String) {
IGNORE("ignore"),
WARN("warn"),
STRICT("strict"),
;
companion object {
@JvmField
val DEFAULT: Jsr305State = WARN
fun findByDescription(description: String?) = values().firstOrNull { it.description == description }
fun findByDescription(description: String?): ReportLevel? = values().firstOrNull { it.description == description }
}
fun isIgnored(): Boolean = this == IGNORE
fun isWarning(): Boolean = this == WARN
val isWarning: Boolean get() = this == ReportLevel.WARN
val isIgnore: Boolean get() = this == ReportLevel.IGNORE
}
data class Jsr305State(
val global: ReportLevel,
val migration: ReportLevel?,
val user: Map<String, ReportLevel>
) {
val description: Array<String> by lazy {
val result = mutableListOf<String>()
result.add(global.description)
migration?.let { result.add("under-migration:${it.description}") }
user.forEach {
result.add("@${it.key}:${it.value.description}")
}
result.toTypedArray()
}
val disabled: Boolean get() = this === DISABLED
companion object {
@JvmField
val DEFAULT: Jsr305State = Jsr305State(ReportLevel.WARN, null, emptyMap())
@JvmField
val DISABLED: Jsr305State = Jsr305State(ReportLevel.IGNORE, ReportLevel.IGNORE, emptyMap())
@JvmField
val STRICT: Jsr305State = Jsr305State(ReportLevel.STRICT, ReportLevel.STRICT, emptyMap())
}
}
@@ -21,6 +21,7 @@ import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.analyzer.LanguageSettingsProvider
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.idea.caches.resolve.LibraryInfo
import org.jetbrains.kotlin.idea.caches.resolve.ModuleSourceInfo
@@ -43,11 +44,8 @@ object IDELanguageSettingsProvider : LanguageSettingsProvider {
val settings = KotlinFacetSettingsProvider.getInstance(project).getSettings(module) ?: continue
val compilerArguments = settings.mergedCompilerArguments as? K2JVMCompilerArguments ?: continue
val jsr305state = Jsr305State.findByDescription(compilerArguments.jsr305)
if (jsr305state != null && jsr305state != Jsr305State.DEFAULT) {
map.put(AnalysisFlag.jsr305, jsr305state)
break
}
val jsr305State = compilerArguments.parseJsr305(MessageCollector.NONE)
map.put(AnalysisFlag.jsr305, jsr305State)
}
return map
}
@@ -28,6 +28,8 @@ import org.jetbrains.kotlin.idea.test.KotlinJdkAndLibraryProjectDescriptor
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
import org.jetbrains.kotlin.test.MockLibraryUtil
import org.jetbrains.kotlin.utils.Jsr305State
import org.jetbrains.kotlin.utils.ReportLevel
import org.jetbrains.kotlin.utils.ReportLevel.Companion.findByDescription
class Jsr305HighlightingTest : KotlinLightCodeInsightFixtureTestCase() {
override fun getProjectDescriptor(): LightProjectDescriptor {
@@ -48,7 +50,7 @@ class Jsr305HighlightingTest : KotlinLightCodeInsightFixtureTestCase() {
facetSettings.apply {
val jsrStateByTestName =
Jsr305State.findByDescription(getTestName(true)) ?: return@apply
ReportLevel.findByDescription(getTestName(true)) ?: return@apply
compilerSettings!!.additionalArguments += " -Xjsr305=${jsrStateByTestName.description}"
updateMergedArguments()
@@ -0,0 +1,36 @@
description = 'Kotlin annotations for JVM'
apply plugin: 'kotlin'
configureJvm6Project(project)
configurePublishing(project)
sourceSets {
main {
kotlin {
srcDir 'src'
}
}
}
artifacts {
archives sourcesJar
archives javadocJar
}
dist {
from (jar, sourcesJar)
}
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile) {
kotlinOptions.jdkHome = JDK_16
kotlinOptions.jvmTarget = 1.6
}
compileKotlin {
kotlinOptions.freeCompilerArgs = [
"-Xallow-kotlin-package",
"-module-name", project.name
]
}
@@ -0,0 +1,34 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kotlin.annotations.jvm
/**
* Contains the list of possible migration statuses.
*/
public enum class MigrationStatus {
IGNORE,
WARN,
@Deprecated("experimental feature")
STRICT
}
/**
* This meta-annotation is intended for user nullability annotations with JSR-305 type qualifiers. Behaviour of meta-annotated
* nullability annotations can be controlled via compilation flag.
*/
@Target(AnnotationTarget.ANNOTATION_CLASS)
public annotation class UnderMigration(val status: MigrationStatus)
+2
View File
@@ -131,6 +131,7 @@ include ":kotlin-build-common",
":examples:kotlin-jsr223-daemon-local-eval-example",
":ultimate",
":ultimate:ultimate-runner",
":kotlin-annotations-jvm",
// plugin markers:
':kotlin-gradle-plugin:plugin-marker',
@@ -199,6 +200,7 @@ project(':kotlin-annotation-processing-gradle').projectDir = "$rootDir/libraries
project(':kotlin-annotation-processing').projectDir = "$rootDir/plugins/kapt3" as File
project(':examples:kotlin-jsr223-local-example').projectDir = "$rootDir/libraries/examples/kotlin-jsr223-local-example" as File
project(':examples:kotlin-jsr223-daemon-local-eval-example').projectDir = "$rootDir/libraries/examples/kotlin-jsr223-daemon-local-eval-example" as File
project(':kotlin-annotations-jvm').projectDir = "$rootDir/libraries/tools/kotlin-annotations-jvm" as File
// plugin markers:
project(':kotlin-gradle-plugin:plugin-marker').projectDir = file("$rootDir/libraries/tools/kotlin-gradle-plugin/plugin-marker")