Support compiler flag -Xcodeanalysis-annotations

This commit is contained in:
Denis Zharkov
2019-08-15 12:17:29 +03:00
committed by Victor Petukhov
parent c734bac676
commit f3a490ee16
45 changed files with 1031 additions and 35 deletions
@@ -23,7 +23,9 @@ import org.jetbrains.kotlin.utils.ReportLevel
class JavaTypeEnhancementStateParser(private val collector: MessageCollector) {
fun parse(
jsr305Args: Array<String>?, supportCompatqualCheckerFrameworkAnnotations: String?
jsr305Args: Array<String>?,
supportCompatqualCheckerFrameworkAnnotations: String?,
codeAnalysisState: String?
): JavaTypeEnhancementState {
val jsr305State = parseJsr305State(jsr305Args)
@@ -40,15 +42,34 @@ class JavaTypeEnhancementStateParser(private val collector: MessageCollector) {
}
}
val codeAnalysisReportLevel = parseCodeAnalysisReportLevel(codeAnalysisState)
val state = JavaTypeEnhancementState(
jsr305State.global ?: ReportLevel.WARN, jsr305State.migration, jsr305State.usedDefined,
enableCompatqualCheckerFrameworkAnnotations =
enableCompatqualCheckerFrameworkAnnotations
?: JavaTypeEnhancementState.COMPATQUAL_CHECKER_FRAMEWORK_ANNOTATIONS_SUPPORT_DEFAULT_VALUE
?: JavaTypeEnhancementState.COMPATQUAL_CHECKER_FRAMEWORK_ANNOTATIONS_SUPPORT_DEFAULT_VALUE,
jspecifyReportLevel = codeAnalysisReportLevel
)
return if (state == JavaTypeEnhancementState.DISABLED_JSR_305) JavaTypeEnhancementState.DISABLED_JSR_305 else state
}
private fun parseCodeAnalysisReportLevel(codeAnalysisState: String?): ReportLevel {
if (codeAnalysisState == null) return JavaTypeEnhancementState.DEFAULT_REPORT_LEVEL_FOR_CODE_ANALYSIS
val reportLevel = ReportLevel.findByDescription(codeAnalysisState)
if (reportLevel == null) {
collector.report(
CompilerMessageSeverity.ERROR,
"Unrecognized -Xcodeanalysis-annotations option: $codeAnalysisState. Possible values are 'disable'/'warn'/'strict'"
)
return JavaTypeEnhancementState.DEFAULT_REPORT_LEVEL_FOR_CODE_ANALYSIS
}
return reportLevel
}
private data class Jsr305State(
val global: ReportLevel?,
val migration: ReportLevel?,
@@ -263,6 +263,14 @@ class K2JVMCompilerArguments : CommonCompilerArguments() {
)
var supportCompatqualCheckerFrameworkAnnotations: String? by NullableStringFreezableVar(null)
@Argument(
value = "-Xjspecify-annotations",
valueDescription = "ignore|strict|warn",
description = "Specify behavior for jspecify annotations.\n" +
"Default value is 'warn'"
)
var jspecifyAnnotations: String? by FreezableVar(null)
@Argument(
value = "-Xno-exception-on-explicit-equals-for-boxed-null",
description = "Do not throw NPE on explicit 'equals' call for null receiver of platform boxed primitive type"
@@ -397,7 +405,8 @@ class K2JVMCompilerArguments : CommonCompilerArguments() {
result[JvmAnalysisFlags.strictMetadataVersionSemantics] = strictMetadataVersionSemantics
result[JvmAnalysisFlags.javaTypeEnhancementState] = JavaTypeEnhancementStateParser(collector).parse(
jsr305,
supportCompatqualCheckerFrameworkAnnotations
supportCompatqualCheckerFrameworkAnnotations,
jspecifyAnnotations
)
result[AnalysisFlags.ignoreDataFlowInAssert] = JVMAssertionsMode.fromString(assertionsMode) != JVMAssertionsMode.LEGACY
JvmDefaultMode.fromStringOrNull(jvmDefault)?.let {
+7
View File
@@ -0,0 +1,7 @@
@codeanalysis.experimental.annotations.DefaultNotNull
public class A {
public void foo(String x) {}
@codeanalysis.experimental.annotations.Nullable
public String bar() { return null; }
}
+5
View File
@@ -0,0 +1,5 @@
$TESTDATA_DIR$/jspecifyUsage.kt
$TESTDATA_DIR$/jspecify
$FOREIGN_ANNOTATIONS_DIR$
-d
$TEMP_DIR$
+7
View File
@@ -0,0 +1,7 @@
compiler/testData/cli/jvm/codeanalysisUsage.kt:2:11: warning: type mismatch: inferred type is Nothing? but String was expected
a.foo(null)
^
compiler/testData/cli/jvm/codeanalysisUsage.kt:3:5: warning: unsafe use of a nullable receiver of type String?
a.bar().hashCode()
^
OK
+6
View File
@@ -0,0 +1,6 @@
-Xcodeanalysis-annotations=ignore
$TESTDATA_DIR$/codeanalysisUsage.kt
$TESTDATA_DIR$/codeanalysis
$FOREIGN_ANNOTATIONS_DIR$
-d
$TEMP_DIR$
+1
View File
@@ -0,0 +1 @@
OK
+6
View File
@@ -0,0 +1,6 @@
-Xcodeanalysis-annotations=strict
$TESTDATA_DIR$/codeanalysisUsage.kt
$TESTDATA_DIR$/codeanalysis
$FOREIGN_ANNOTATIONS_DIR$
-d
$TEMP_DIR$
+4
View File
@@ -0,0 +1,4 @@
compiler/testData/cli/jvm/jspecifyUsage.kt:2:11: error: null can not be a value of a non-null type String
a.foo(null)
^
COMPILATION_ERROR
+4
View File
@@ -0,0 +1,4 @@
fun bar(a: A) {
a.foo(null)
a.bar().hashCode()
}
+6
View File
@@ -0,0 +1,6 @@
-Xjspecify-annotations=warn
$TESTDATA_DIR$/codeanalysisUsage.kt
$TESTDATA_DIR$/codeanalysis
$FOREIGN_ANNOTATIONS_DIR$
-d
$TEMP_DIR$
+7
View File
@@ -0,0 +1,7 @@
compiler/testData/cli/jvm/jspecifyUsage.kt:2:11: warning: type mismatch: inferred type is Nothing? but String was expected
a.foo(null)
^
compiler/testData/cli/jvm/jspecifyUsage.kt:3:5: warning: unsafe use of a nullable receiver of type String?
a.bar().hashCode()
^
OK
+3
View File
@@ -12,6 +12,9 @@ where advanced options include:
-Xassertions=legacy: calculate condition on each call, check depends on jvm assertion settings in the kotlin package;
default: legacy
-Xbuild-file=<path> Path to the .xml build file to compile
-Xcodeanalysis-annotations=ignore|strict|warn
Specify behavior for Codeanalysis annotations.
Default value is 'warn'
-Xcompile-java Reuse javac analysis and compile Java source files
-Xnormalize-constructor-calls={disable|enable}
Normalize constructor calls (disable: don't normalize; enable: normalize),
@@ -0,0 +1,52 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// CODE_ANALYSIS_STATE ignore
// FILE: A.java
import jspecify.annotations.*;
public class A {
@Nullable public String field = null;
@Nullable
public String foo(@NotNull String x, @UnknownNullness CharSequence y) {
return "";
}
@NotNull
public String bar() {
return "";
}
@DefaultNotNull
public String everythingNotNullable(String x) { return ""; }
@DefaultNullable
public String everythingNullable(String x) { return ""; }
@DefaultNullnessUnknown
public String everythingUnknown(String x) { return ""; }
}
// 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.everythingNotNullable(null)?.length
a.everythingNotNullable(null).length
a.everythingNotNullable("").length
a.everythingNullable(null).length
a.everythingNullable(null)?.length
a.everythingUnknown(null).length
a.everythingUnknown(null)?.length
}
@@ -0,0 +1,16 @@
package
public fun main(/*0*/ a: A): kotlin.Unit
public open class A {
public constructor A()
@jspecify.annotations.Nullable public final var field: kotlin.String!
@jspecify.annotations.NotNull public open fun bar(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
@jspecify.annotations.DefaultNotNull public open fun everythingNotNullable(/*0*/ x: kotlin.String!): kotlin.String!
@jspecify.annotations.DefaultNullable public open fun everythingNullable(/*0*/ x: kotlin.String!): kotlin.String!
@jspecify.annotations.DefaultNullnessUnknown public open fun everythingUnknown(/*0*/ x: kotlin.String!): kotlin.String!
@jspecify.annotations.Nullable public open fun foo(/*0*/ @jspecify.annotations.NotNull x: kotlin.String!, /*1*/ @jspecify.annotations.UnknownNullness 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,81 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// CODE_ANALYSIS_STATE warn
// FILE: A.java
import jspecify.annotations.*;
public class A<T extends @NotNull Object, E extends @Nullable Object, F extends @UnknownNullness Object> {
}
// FILE: B.java
import jspecify.annotations.*;
public class B {
public void superAsIs(A<? super CharSequence, ? super CharSequence, ? super CharSequence> a) {}
public void superNotNull(A<? super @NotNull CharSequence, ? super @NotNull CharSequence, ? super @NotNull CharSequence> a) {}
public void superNullable(A<? super @Nullable CharSequence, ? super @Nullable CharSequence, ? super @Nullable CharSequence> a) {}
public void extendsAsIs(A<? extends CharSequence, ? extends CharSequence, ? extends CharSequence> a) {}
public void extendsNotNull(A<? extends @NotNull CharSequence, ? extends @NotNull CharSequence, ? extends @NotNull CharSequence> a) {}
public void extendsNullable(A<? extends @Nullable CharSequence, ? extends @Nullable CharSequence, ? extends @Nullable CharSequence> a) {}
public void noBounds(A<?, ?, ?> a) {}
}
// FILE: main.kt
fun main(
aNotNullNotNullNotNull: A<String, String, String>,
aNotNullNotNullNull: A<String, String, String?>,
aNotNullNullNotNull: A<String, String?, String>,
aNotNullNullNull: A<String, String?, String?>,
aAnyNotNullNotNullNotNull: A<Any, Any, Any>,
aAnyNotNullNotNullNull: A<Any, Any, Any?>,
aAnyNotNullNullNotNull: A<Any, Any?, Any>,
aAnyNotNullNullNull: A<Any, Any?, Any?>,
b: B
) {
// TODO: NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS should be reported
b.superAsIs(aAnyNotNullNotNullNotNull)
// TODO: NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS should be reported
b.superAsIs(aAnyNotNullNotNullNull)
b.superAsIs(aAnyNotNullNullNotNull)
b.superAsIs(aAnyNotNullNullNull)
b.superNotNull(aAnyNotNullNotNullNotNull)
b.superNotNull(aAnyNotNullNotNullNull)
b.superNotNull(aAnyNotNullNullNotNull)
b.superNotNull(aAnyNotNullNullNull)
// TODO: Bound for the first argument in "superNullable" contradicts to declared nullability of the parameter
// Do we need to ignore such arguments' nullability?
b.superNullable(aAnyNotNullNotNullNotNull)
b.superNullable(aAnyNotNullNotNullNull)
b.superNullable(aAnyNotNullNullNotNull)
b.superNullable(aAnyNotNullNullNull)
b.extendsAsIs(aNotNullNotNullNotNull)
b.extendsAsIs(aNotNullNotNullNull)
b.extendsAsIs(aNotNullNullNotNull)
b.extendsAsIs(aNotNullNullNull)
b.extendsNotNull(aNotNullNotNullNotNull)
// TODO: NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS should be reported
b.extendsNotNull(aNotNullNotNullNull)
// TODO: NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS should be reported
b.extendsNotNull(aNotNullNullNotNull)
// TODO: NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS should be reported
b.extendsNotNull(aNotNullNullNull)
b.extendsNullable(aNotNullNotNullNotNull)
b.extendsNullable(aNotNullNotNullNull)
b.extendsNullable(aNotNullNullNotNull)
b.extendsNullable(aNotNullNullNull)
b.noBounds(aNotNullNotNullNotNull)
b.noBounds(aNotNullNotNullNull)
b.noBounds(aNotNullNullNotNull)
b.noBounds(aNotNullNullNull)
}
@@ -0,0 +1,24 @@
package
public fun main(/*0*/ aNotNullNotNullNotNull: A<kotlin.String, kotlin.String, kotlin.String>, /*1*/ aNotNullNotNullNull: A<kotlin.String, kotlin.String, kotlin.String?>, /*2*/ aNotNullNullNotNull: A<kotlin.String, kotlin.String?, kotlin.String>, /*3*/ aNotNullNullNull: A<kotlin.String, kotlin.String?, kotlin.String?>, /*4*/ aAnyNotNullNotNullNotNull: A<kotlin.Any, kotlin.Any, kotlin.Any>, /*5*/ aAnyNotNullNotNullNull: A<kotlin.Any, kotlin.Any, kotlin.Any?>, /*6*/ aAnyNotNullNullNotNull: A<kotlin.Any, kotlin.Any?, kotlin.Any>, /*7*/ aAnyNotNullNullNull: A<kotlin.Any, kotlin.Any?, kotlin.Any?>, /*8*/ b: B): kotlin.Unit
public open class A</*0*/ T : @jspecify.annotations.NotNull kotlin.Any!, /*1*/ E : @jspecify.annotations.Nullable kotlin.Any!, /*2*/ F : @jspecify.annotations.UnknownNullness kotlin.Any!> {
public constructor A</*0*/ T : @jspecify.annotations.NotNull kotlin.Any!, /*1*/ E : @jspecify.annotations.Nullable kotlin.Any!, /*2*/ F : @jspecify.annotations.UnknownNullness kotlin.Any!>()
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
}
public open class B {
public constructor B()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open fun extendsAsIs(/*0*/ a: A<out kotlin.CharSequence!, out kotlin.CharSequence!, out kotlin.CharSequence!>!): kotlin.Unit
public open fun extendsNotNull(/*0*/ a: A<out @jspecify.annotations.NotNull kotlin.CharSequence!, out @jspecify.annotations.NotNull kotlin.CharSequence!, out @jspecify.annotations.NotNull kotlin.CharSequence!>!): kotlin.Unit
public open fun extendsNullable(/*0*/ a: A<out @jspecify.annotations.Nullable kotlin.CharSequence!, out @jspecify.annotations.Nullable kotlin.CharSequence!, out @jspecify.annotations.Nullable kotlin.CharSequence!>!): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open fun noBounds(/*0*/ a: A<*, *, *>!): kotlin.Unit
public open fun superAsIs(/*0*/ a: A<in kotlin.CharSequence!, in kotlin.CharSequence!, in kotlin.CharSequence!>!): kotlin.Unit
public open fun superNotNull(/*0*/ a: A<in @jspecify.annotations.NotNull kotlin.CharSequence!, in @jspecify.annotations.NotNull kotlin.CharSequence!, in @jspecify.annotations.NotNull kotlin.CharSequence!>!): kotlin.Unit
public open fun superNullable(/*0*/ a: A<in @jspecify.annotations.Nullable kotlin.CharSequence!, in @jspecify.annotations.Nullable kotlin.CharSequence!, in @jspecify.annotations.Nullable kotlin.CharSequence!>!): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,46 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// CODE_ANALYSIS_STATE warn
// FILE: A.java
import jspecify.annotations.*;
@DefaultNotNull
public class A {
public String defaultField = "";
@Nullable public String field = null;
public String everythingNotNullable(String x) { return ""; }
@DefaultNullable
public String everythingNullable(String x) { return ""; }
@DefaultNullnessUnknown
public String everythingUnknown(String x) { return ""; }
@DefaultNullable
public String mixed(@NotNull String x) { return ""; }
}
// FILE: main.kt
fun main(a: A) {
a.everythingNotNullable(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)<!UNNECESSARY_SAFE_CALL!>?.<!>length
a.everythingNotNullable(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>).length
a.everythingNotNullable("").length
<!RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>a.everythingNullable(null)<!>.length
a.everythingNullable(null)?.length
a.everythingUnknown(null).length
a.everythingUnknown(null)?.length
<!RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>a.mixed(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)<!>.length
a.mixed(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)?.length
a.mixed("")?.length
a.defaultField<!UNNECESSARY_SAFE_CALL!>?.<!>length
a.defaultField.length
a.field?.length
<!RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>a.field<!>.length
}
@@ -0,0 +1,16 @@
package
public fun main(/*0*/ a: A): kotlin.Unit
@jspecify.annotations.DefaultNotNull public open class A {
public constructor A()
public final var defaultField: kotlin.String!
@jspecify.annotations.Nullable public final var field: kotlin.String!
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open fun everythingNotNullable(/*0*/ x: kotlin.String!): kotlin.String!
@jspecify.annotations.DefaultNullable public open fun everythingNullable(/*0*/ x: kotlin.String!): kotlin.String!
@jspecify.annotations.DefaultNullnessUnknown public open fun everythingUnknown(/*0*/ x: kotlin.String!): kotlin.String!
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
@jspecify.annotations.DefaultNullable public open fun mixed(/*0*/ @jspecify.annotations.NotNull x: kotlin.String!): kotlin.String!
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,50 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// CODE_ANALYSIS_STATE warn
// FILE: A.java
import jspecify.annotations.*;
public class A<T extends @Nullable Object> {
public void foo(T t) {}
public <E extends @Nullable Object> void bar(E e) {}
}
// FILE: B.java
import jspecify.annotations.*;
@DefaultNullable
public class B<T> {
public void foo(T t) {}
public <E> void bar(E e) {}
}
// FILE: main.kt
fun main(a1: A<Any?>, a2: A<String>, b1: B<Any?>, b2: B<String>) {
a1.foo(null)
a1.bar<String?>(null)
// TODO: NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS should be reported
a1.bar<String>(null)
a1.bar<String>("")
// TODO: NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS should be reported
a2.foo(null)
a2.bar<String?>(null)
// TODO: NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS should be reported
a2.bar<String>(null)
a2.bar<String>("")
b1.foo(null)
b1.bar<String?>(null)
// TODO: NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS should be reported
b1.bar<String>(null)
b1.bar<String>("")
// TODO: NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS should be reported
b2.foo(null)
b2.bar<String?>(null)
// TODO: NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS should be reported
b2.bar<String>(null)
b2.bar<String>("")
}
@@ -0,0 +1,21 @@
package
public fun main(/*0*/ a1: A<kotlin.Any?>, /*1*/ a2: A<kotlin.String>, /*2*/ b1: B<kotlin.Any?>, /*3*/ b2: B<kotlin.String>): kotlin.Unit
public open class A</*0*/ T : @jspecify.annotations.Nullable kotlin.Any!> {
public constructor A</*0*/ T : @jspecify.annotations.Nullable kotlin.Any!>()
public open fun </*0*/ E : @jspecify.annotations.Nullable kotlin.Any!> bar(/*0*/ e: E!): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open fun foo(/*0*/ t: T!): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@jspecify.annotations.DefaultNullable public open class B</*0*/ T : kotlin.Any!> {
public constructor B</*0*/ T : kotlin.Any!>()
public open fun </*0*/ E : kotlin.Any!> bar(/*0*/ e: E!): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open fun foo(/*0*/ t: T!): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,34 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// CODE_ANALYSIS_STATE warn
// FILE: A.java
import jspecify.annotations.*;
public class A {
@Nullable public String field = null;
@Nullable
public String foo(@NotNull String x, @UnknownNullness CharSequence y) {
return "";
}
@NotNull
public String bar() {
return "";
}
}
// FILE: main.kt
fun main(a: A) {
a.foo("", null)?.length
<!RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>a.foo("", null)<!>.length
<!RECEIVER_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
<!RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>a.field<!>.length
}
@@ -0,0 +1,13 @@
package
public fun main(/*0*/ a: A): kotlin.Unit
public open class A {
public constructor A()
@jspecify.annotations.Nullable public final var field: kotlin.String!
@jspecify.annotations.NotNull public open fun bar(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
@jspecify.annotations.Nullable public open fun foo(/*0*/ @jspecify.annotations.NotNull x: kotlin.String!, /*1*/ @jspecify.annotations.UnknownNullness 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,68 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// CODE_ANALYSIS_STATE warn
// FILE: A.java
import jspecify.annotations.*;
public class A<T extends @NotNull Object, E extends @Nullable Object, F extends @UnknownNullness Object> {
}
// FILE: B.java
import jspecify.annotations.*;
@DefaultNullable
public class B {
public void bar(A<String, String, String> a) {}
}
// FILE: C.java
import jspecify.annotations.*;
@DefaultNotNull
public class C {
public void bar(A<String, String, String> a) {}
}
// FILE: D.java
import jspecify.annotations.*;
@DefaultUnknownNullness
public class D {
public void bar(A<String, String, String> a) {}
}
// FILE: main.kt
fun main(
aNotNullNotNullNotNull: A<String, String, String>,
aNotNullNotNullNull: A<String, String, String?>,
aNotNullNullNotNull: A<String, String?, String>,
aNotNullNullNull: A<String, String?, String?>,
b: B, c: C, d: D
) {
// TODO: NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS should be reported
b.bar(aNotNullNotNullNotNull)
// TODO: NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS should be reported
b.bar(aNotNullNotNullNull)
// TODO: NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS should be reported
b.bar(aNotNullNullNotNull)
b.bar(aNotNullNullNull)
c.bar(aNotNullNotNullNotNull)
// TODO: NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS should be reported
c.bar(aNotNullNotNullNull)
// TODO: NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS should be reported
c.bar(aNotNullNullNotNull)
// TODO: NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS should be reported
c.bar(aNotNullNullNull)
// TODO: NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS should be reported
d.bar(aNotNullNotNullNotNull)
// TODO: NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS should be reported
d.bar(aNotNullNotNullNull)
d.bar(aNotNullNullNotNull)
d.bar(aNotNullNullNull)
}
@@ -0,0 +1,34 @@
package
public fun main(/*0*/ aNotNullNotNullNotNull: A<kotlin.String, kotlin.String, kotlin.String>, /*1*/ aNotNullNotNullNull: A<kotlin.String, kotlin.String, kotlin.String?>, /*2*/ aNotNullNullNotNull: A<kotlin.String, kotlin.String?, kotlin.String>, /*3*/ aNotNullNullNull: A<kotlin.String, kotlin.String?, kotlin.String?>, /*4*/ b: B, /*5*/ c: C, /*6*/ d: D): kotlin.Unit
public open class A</*0*/ T : @jspecify.annotations.NotNull kotlin.Any!, /*1*/ E : @jspecify.annotations.Nullable kotlin.Any!, /*2*/ F : @jspecify.annotations.UnknownNullness kotlin.Any!> {
public constructor A</*0*/ T : @jspecify.annotations.NotNull kotlin.Any!, /*1*/ E : @jspecify.annotations.Nullable kotlin.Any!, /*2*/ F : @jspecify.annotations.UnknownNullness kotlin.Any!>()
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
}
@jspecify.annotations.DefaultNullable public open class B {
public constructor B()
public open fun bar(/*0*/ a: A<kotlin.String!, kotlin.String!, kotlin.String!>!): kotlin.Unit
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
}
@jspecify.annotations.DefaultNotNull public open class C {
public constructor C()
public open fun bar(/*0*/ a: A<kotlin.String!, kotlin.String!, kotlin.String!>!): kotlin.Unit
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
}
@DefaultUnknownNullness /* annotation class not found */ public open class D {
public constructor D()
public open fun bar(/*0*/ a: A<kotlin.String!, kotlin.String!, kotlin.String!>!): kotlin.Unit
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,49 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// CODE_ANALYSIS_STATE warn
// FILE: A.java
import jspecify.annotations.*;
public class A<T extends @NotNull Object> {
public void foo(T t) {}
public <E extends @NotNull Object> void bar(E e) {}
}
// FILE: B.java
import jspecify.annotations.*;
@DefaultNotNull
public class B<T> {
public void foo(T t) {}
public <E> void bar(E e) {}
}
// FILE: main.kt
// TODO: UPPER_BOUND_VIOLATED_WARNING should be reported
fun main(a1: A<Any?>, a2: A<String>, b1: B<Any?>, b2: B<String>) {
// TODO: NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS should be reported
a1.foo(null)
// TODO: UPPER_BOUND_VIOLATED_WARNING should be reported
a1.bar<String?>(null)
a1.bar<String>("")
// TODO: NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS should be reported
a2.foo(null)
// TODO: UPPER_BOUND_VIOLATED_WARNING should be reported
a2.bar<String?>(null)
a2.bar<String>("")
// TODO: NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS should be reported
b1.foo(null)
// TODO: UPPER_BOUND_VIOLATED_WARNING should be reported
b1.bar<String?>(null)
b1.bar<String>("")
// TODO: NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS should be reported
b2.foo(null)
// TODO: UPPER_BOUND_VIOLATED_WARNING should be reported
b2.bar<String?>(null)
b2.bar<String>("")
}
@@ -0,0 +1,21 @@
package
public fun main(/*0*/ a1: A<kotlin.Any?>, /*1*/ a2: A<kotlin.String>, /*2*/ b1: B<kotlin.Any?>, /*3*/ b2: B<kotlin.String>): kotlin.Unit
public open class A</*0*/ T : @jspecify.annotations.NotNull kotlin.Any!> {
public constructor A</*0*/ T : @jspecify.annotations.NotNull kotlin.Any!>()
public open fun </*0*/ E : @jspecify.annotations.NotNull kotlin.Any!> bar(/*0*/ e: E!): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open fun foo(/*0*/ t: T!): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@jspecify.annotations.DefaultNotNull public open class B</*0*/ T : kotlin.Any!> {
public constructor B</*0*/ T : kotlin.Any!>()
public open fun </*0*/ E : kotlin.Any!> bar(/*0*/ e: E!): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open fun foo(/*0*/ t: T!): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,30 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// CODE_ANALYSIS_STATE warn
// FILE: A.java
import codeanalysis.annotations.*;
public class A<T> {
public void foo(T t) {}
@DefaultNotNull
public void bar(String s, T t) {} // t should not become not nullable
}
// FILE: main.kt
fun main(a1: A<Int>, a2: A<Int?>) {
a1.foo(null)
a1.foo(1)
a2.foo(null)
a2.foo(1)
a1.bar(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>, null)
a1.bar("", null)
a1.bar("", 1)
a2.bar(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>, null)
a2.bar("", null)
a2.bar("", 1)
}
@@ -0,0 +1,12 @@
package
public fun main(/*0*/ a1: A<kotlin.Int>, /*1*/ a2: A<kotlin.Int?>): kotlin.Unit
public open class A</*0*/ T : kotlin.Any!> {
public constructor A</*0*/ T : kotlin.Any!>()
@codeanalysis.annotations.DefaultNotNull public open fun bar(/*0*/ s: kotlin.String!, /*1*/ t: T!): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open fun foo(/*0*/ t: T!): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,42 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// CODE_ANALYSIS_STATE warn
// FILE: A.java
import jspecify.annotations.*;
public class A<T extends @NotNull Object, E extends @Nullable Object, F extends @UnknownNullness Object> {
}
// FILE: B.java
import jspecify.annotations.*;
public class B {
@DefaultNotNull
public void noBoundsNotNull(A<?, ?, ?> a) {}
@DefaultNullable
public void noBoundsNullable(A<?, ?, ?> a) {}
}
// FILE: main.kt
fun main(
aNotNullNotNullNotNull: A<String, String, String>,
aNotNullNotNullNull: A<String, String, String?>,
aNotNullNullNotNull: A<String, String?, String>,
aNotNullNullNull: A<String, String?, String?>,
b: B
) {
b.noBoundsNotNull(aNotNullNotNullNotNull)
// TODO: NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS should be reported
b.noBoundsNotNull(aNotNullNotNullNull)
// TODO: NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS should be reported
b.noBoundsNotNull(aNotNullNullNotNull)
// TODO: NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS should be reported
b.noBoundsNotNull(aNotNullNullNull)
b.noBoundsNullable(aNotNullNotNullNotNull)
b.noBoundsNullable(aNotNullNotNullNull)
b.noBoundsNullable(aNotNullNullNotNull)
b.noBoundsNullable(aNotNullNullNull)
}
@@ -0,0 +1,19 @@
package
public fun main(/*0*/ aNotNullNotNullNotNull: A<kotlin.String, kotlin.String, kotlin.String>, /*1*/ aNotNullNotNullNull: A<kotlin.String, kotlin.String, kotlin.String?>, /*2*/ aNotNullNullNotNull: A<kotlin.String, kotlin.String?, kotlin.String>, /*3*/ aNotNullNullNull: A<kotlin.String, kotlin.String?, kotlin.String?>, /*4*/ b: B): kotlin.Unit
public open class A</*0*/ T : @jspecify.annotations.NotNull kotlin.Any!, /*1*/ E : @jspecify.annotations.Nullable kotlin.Any!, /*2*/ F : @jspecify.annotations.UnknownNullness kotlin.Any!> {
public constructor A</*0*/ T : @jspecify.annotations.NotNull kotlin.Any!, /*1*/ E : @jspecify.annotations.Nullable kotlin.Any!, /*2*/ F : @jspecify.annotations.UnknownNullness kotlin.Any!>()
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
}
public open class B {
public constructor B()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
@jspecify.annotations.DefaultNotNull public open fun noBoundsNotNull(/*0*/ a: A<*, *, *>!): kotlin.Unit
@jspecify.annotations.DefaultNullable public open fun noBoundsNullable(/*0*/ a: A<*, *, *>!): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -18,10 +18,8 @@ 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.JavaTypeEnhancementState
import org.jetbrains.kotlin.utils.ReportLevel
import java.io.File
@@ -33,6 +31,7 @@ abstract class AbstractForeignAnnotationsTest : AbstractDiagnosticsTest() {
private val JSR305_GLOBAL_DIRECTIVE = "JSR305_GLOBAL_REPORT"
private val JSR305_MIGRATION_DIRECTIVE = "JSR305_MIGRATION_REPORT"
private val JSR305_SPECIAL_DIRECTIVE = "JSR305_SPECIAL_REPORT"
private val CODE_ANALYSIS_STATE_SPECIAL_DIRECTIVE = "CODE_ANALYSIS_STATE"
override fun getExtraClasspath(): List<File> {
val foreignAnnotations = createJarWithForeignAnnotations()
@@ -78,11 +77,14 @@ abstract class AbstractForeignAnnotationsTest : AbstractDiagnosticsTest() {
name to state
}.toMap()
val codeAnalysisReportLevel = module.getDirectiveValue(CODE_ANALYSIS_STATE_SPECIAL_DIRECTIVE) ?: ReportLevel.STRICT
return mapOf(
JvmAnalysisFlags.javaTypeEnhancementState to JavaTypeEnhancementState(
globalState,
migrationState,
userAnnotationsState
userAnnotationsState,
jspecifyReportLevel = codeAnalysisReportLevel
)
)
}
@@ -60,10 +60,68 @@ public class ForeignJava8AnnotationsNoAnnotationInClasspathTestGenerated extends
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/annotatedWildcards.kt");
}
@TestMetadata("ignoreAnnotations.kt")
public void testIgnoreAnnotations() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/ignoreAnnotations.kt");
}
@TestMetadata("wildcardsWithDefault.kt")
public void testWildcardsWithDefault() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/wildcardsWithDefault.kt");
}
@TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Warnings extends AbstractForeignJava8AnnotationsNoAnnotationInClasspathTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInWarnings() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@TestMetadata("annotatedWildcards.kt")
public void testAnnotatedWildcards() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/annotatedWildcards.kt");
}
@TestMetadata("defaults.kt")
public void testDefaults() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/defaults.kt");
}
@TestMetadata("nonPlatformTypeParameter.kt")
public void testNonPlatformTypeParameter() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/nonPlatformTypeParameter.kt");
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/simple.kt");
}
@TestMetadata("typeArgumentsFromParameterBounds.kt")
public void testTypeArgumentsFromParameterBounds() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/typeArgumentsFromParameterBounds.kt");
}
@TestMetadata("typeParameterBounds.kt")
public void testTypeParameterBounds() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/typeParameterBounds.kt");
}
@TestMetadata("unknownNullnessTypeParameter.kt")
public void testUnknownNullnessTypeParameter() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/unknownNullnessTypeParameter.kt");
}
@TestMetadata("wildcardsWithDefault.kt")
public void testWildcardsWithDefault() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/wildcardsWithDefault.kt");
}
}
}
@TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/jspecify")
@@ -60,10 +60,68 @@ public class ForeignJava8AnnotationsNoAnnotationInClasspathWithPsiClassReadingTe
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/annotatedWildcards.kt");
}
@TestMetadata("ignoreAnnotations.kt")
public void testIgnoreAnnotations() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/ignoreAnnotations.kt");
}
@TestMetadata("wildcardsWithDefault.kt")
public void testWildcardsWithDefault() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/wildcardsWithDefault.kt");
}
@TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Warnings extends AbstractForeignJava8AnnotationsNoAnnotationInClasspathWithPsiClassReadingTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInWarnings() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@TestMetadata("annotatedWildcards.kt")
public void testAnnotatedWildcards() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/annotatedWildcards.kt");
}
@TestMetadata("defaults.kt")
public void testDefaults() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/defaults.kt");
}
@TestMetadata("nonPlatformTypeParameter.kt")
public void testNonPlatformTypeParameter() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/nonPlatformTypeParameter.kt");
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/simple.kt");
}
@TestMetadata("typeArgumentsFromParameterBounds.kt")
public void testTypeArgumentsFromParameterBounds() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/typeArgumentsFromParameterBounds.kt");
}
@TestMetadata("typeParameterBounds.kt")
public void testTypeParameterBounds() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/typeParameterBounds.kt");
}
@TestMetadata("unknownNullnessTypeParameter.kt")
public void testUnknownNullnessTypeParameter() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/unknownNullnessTypeParameter.kt");
}
@TestMetadata("wildcardsWithDefault.kt")
public void testWildcardsWithDefault() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/wildcardsWithDefault.kt");
}
}
}
@TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/jspecify")
@@ -60,10 +60,68 @@ public class ForeignJava8AnnotationsTestGenerated extends AbstractForeignJava8An
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/annotatedWildcards.kt");
}
@TestMetadata("ignoreAnnotations.kt")
public void testIgnoreAnnotations() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/ignoreAnnotations.kt");
}
@TestMetadata("wildcardsWithDefault.kt")
public void testWildcardsWithDefault() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/wildcardsWithDefault.kt");
}
@TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Warnings extends AbstractForeignJava8AnnotationsTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInWarnings() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@TestMetadata("annotatedWildcards.kt")
public void testAnnotatedWildcards() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/annotatedWildcards.kt");
}
@TestMetadata("defaults.kt")
public void testDefaults() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/defaults.kt");
}
@TestMetadata("nonPlatformTypeParameter.kt")
public void testNonPlatformTypeParameter() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/nonPlatformTypeParameter.kt");
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/simple.kt");
}
@TestMetadata("typeArgumentsFromParameterBounds.kt")
public void testTypeArgumentsFromParameterBounds() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/typeArgumentsFromParameterBounds.kt");
}
@TestMetadata("typeParameterBounds.kt")
public void testTypeParameterBounds() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/typeParameterBounds.kt");
}
@TestMetadata("unknownNullnessTypeParameter.kt")
public void testUnknownNullnessTypeParameter() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/unknownNullnessTypeParameter.kt");
}
@TestMetadata("wildcardsWithDefault.kt")
public void testWildcardsWithDefault() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/wildcardsWithDefault.kt");
}
}
}
@TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/jspecify")
@@ -60,10 +60,68 @@ public class JavacForeignJava8AnnotationsTestGenerated extends AbstractJavacFore
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/annotatedWildcards.kt");
}
@TestMetadata("ignoreAnnotations.kt")
public void testIgnoreAnnotations() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/ignoreAnnotations.kt");
}
@TestMetadata("wildcardsWithDefault.kt")
public void testWildcardsWithDefault() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/wildcardsWithDefault.kt");
}
@TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Warnings extends AbstractJavacForeignJava8AnnotationsTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInWarnings() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@TestMetadata("annotatedWildcards.kt")
public void testAnnotatedWildcards() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/annotatedWildcards.kt");
}
@TestMetadata("defaults.kt")
public void testDefaults() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/defaults.kt");
}
@TestMetadata("nonPlatformTypeParameter.kt")
public void testNonPlatformTypeParameter() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/nonPlatformTypeParameter.kt");
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/simple.kt");
}
@TestMetadata("typeArgumentsFromParameterBounds.kt")
public void testTypeArgumentsFromParameterBounds() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/typeArgumentsFromParameterBounds.kt");
}
@TestMetadata("typeParameterBounds.kt")
public void testTypeParameterBounds() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/typeParameterBounds.kt");
}
@TestMetadata("unknownNullnessTypeParameter.kt")
public void testUnknownNullnessTypeParameter() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/unknownNullnessTypeParameter.kt");
}
@TestMetadata("wildcardsWithDefault.kt")
public void testWildcardsWithDefault() throws Exception {
runTest("compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/wildcardsWithDefault.kt");
}
}
}
@TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/jspecify")
@@ -115,6 +115,26 @@ public class CliTestGenerated extends AbstractCliTest {
runTest("compiler/testData/cli/jvm/classpath.args");
}
@TestMetadata("codeanalysisDefault.args")
public void testCodeanalysisDefault() throws Exception {
runTest("compiler/testData/cli/jvm/codeanalysisDefault.args");
}
@TestMetadata("codeanalysisIgnore.args")
public void testCodeanalysisIgnore() throws Exception {
runTest("compiler/testData/cli/jvm/codeanalysisIgnore.args");
}
@TestMetadata("codeanalysisStrict.args")
public void testCodeanalysisStrict() throws Exception {
runTest("compiler/testData/cli/jvm/codeanalysisStrict.args");
}
@TestMetadata("codeanalysisWarn.args")
public void testCodeanalysisWarn() throws Exception {
runTest("compiler/testData/cli/jvm/codeanalysisWarn.args");
}
@TestMetadata("compatqualDefault.args")
public void testCompatqualDefault() throws Exception {
runTest("compiler/testData/cli/jvm/compatqualDefault.args");
@@ -31,18 +31,7 @@ val DEFAULT_JSPECIFY_APPLICABILITY = listOf(
AnnotationQualifierApplicabilityType.TYPE_USE
)
val BUILT_IN_TYPE_QUALIFIER_DEFAULT_ANNOTATIONS = mapOf(
FqName("javax.annotation.ParametersAreNullableByDefault") to
JavaDefaultQualifiers(
NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE),
listOf(AnnotationQualifierApplicabilityType.VALUE_PARAMETER)
),
FqName("javax.annotation.ParametersAreNonnullByDefault") to
JavaDefaultQualifiers(
NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL),
listOf(AnnotationQualifierApplicabilityType.VALUE_PARAMETER)
),
val CODE_ANALYSIS_DEFAULT_ANNOTATIONS = mapOf(
JSPECIFY_DEFAULT_NULLABLE to JavaDefaultQualifiers(
NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE),
DEFAULT_JSPECIFY_APPLICABILITY
@@ -58,4 +47,17 @@ val BUILT_IN_TYPE_QUALIFIER_DEFAULT_ANNOTATIONS = mapOf(
)
)
val BUILT_IN_TYPE_QUALIFIER_DEFAULT_ANNOTATIONS = mapOf(
FqName("javax.annotation.ParametersAreNullableByDefault") to
JavaDefaultQualifiers(
NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE),
listOf(AnnotationQualifierApplicabilityType.VALUE_PARAMETER)
),
FqName("javax.annotation.ParametersAreNonnullByDefault") to
JavaDefaultQualifiers(
NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL),
listOf(AnnotationQualifierApplicabilityType.VALUE_PARAMETER)
)
) + CODE_ANALYSIS_DEFAULT_ANNOTATIONS
val BUILT_IN_TYPE_QUALIFIER_FQ_NAMES = setOf(JAVAX_NONNULL_ANNOTATION, JAVAX_CHECKFORNULL_ANNOTATION)
@@ -79,18 +79,26 @@ class AnnotationTypeQualifierResolver(storageManager: StorageManager, private va
}
fun resolveQualifierBuiltInDefaultAnnotation(annotationDescriptor: AnnotationDescriptor): JavaDefaultQualifiers? {
if (javaTypeEnhancementState.disabledJsr305) {
if (javaTypeEnhancementState.disabledDefaultAnnotations) {
return null
}
return BUILT_IN_TYPE_QUALIFIER_DEFAULT_ANNOTATIONS[annotationDescriptor.fqName]?.let { qualifierForDefaultingAnnotation ->
val state = resolveJsr305AnnotationState(annotationDescriptor).takeIf { it != ReportLevel.IGNORE } ?: return null
val state = resolveDefaultAnnotationState(annotationDescriptor).takeIf { it != ReportLevel.IGNORE } ?: return null
return qualifierForDefaultingAnnotation.copy(
nullabilityQualifier = qualifierForDefaultingAnnotation.nullabilityQualifier.copy(isForWarningOnly = state.isWarning)
)
}
}
private fun resolveDefaultAnnotationState(annotationDescriptor: AnnotationDescriptor): ReportLevel {
if (annotationDescriptor.fqName in CODE_ANALYSIS_DEFAULT_ANNOTATIONS) {
return javaTypeEnhancementState.jspecifyReportLevel
}
return resolveJsr305AnnotationState(annotationDescriptor)
}
fun resolveTypeQualifierDefaultAnnotation(annotationDescriptor: AnnotationDescriptor): TypeQualifierWithApplicability? {
if (javaTypeEnhancementState.disabledJsr305) {
return null
@@ -156,8 +164,6 @@ class AnnotationTypeQualifierResolver(storageManager: StorageManager, private va
)
else -> emptyList()
}
val disabled: Boolean = javaTypeEnhancementState.disabledJsr305
}
private val ClassDescriptor.isAnnotatedWithTypeQualifier: Boolean
@@ -41,6 +41,7 @@ import org.jetbrains.kotlin.resolve.sam.SamConversionResolver
import org.jetbrains.kotlin.serialization.deserialization.ErrorReporter
import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker
import org.jetbrains.kotlin.utils.JavaTypeEnhancementState
import java.util.*
class JavaResolverComponents(
@@ -64,7 +65,8 @@ class JavaResolverComponents(
val signatureEnhancement: SignatureEnhancement,
val javaClassesTracker: JavaClassesTracker,
val settings: JavaResolverSettings,
val kotlinTypeChecker: NewKotlinTypeChecker
val kotlinTypeChecker: NewKotlinTypeChecker,
val javaTypeEnhancementState: JavaTypeEnhancementState
) {
fun replace(
javaResolverCache: JavaResolverCache = this.javaResolverCache
@@ -74,7 +76,8 @@ class JavaResolverComponents(
javaPropertyInitializerEvaluator, samConversionResolver, sourceElementFactory,
moduleClassResolver, packagePartProvider, supertypeLoopChecker, lookupTracker, module, reflectionTypes,
annotationTypeQualifierResolver, signatureEnhancement, javaClassesTracker, settings,
kotlinTypeChecker
kotlinTypeChecker,
javaTypeEnhancementState
)
}
@@ -130,7 +133,7 @@ fun LazyJavaResolverContext.child(
fun LazyJavaResolverContext.computeNewDefaultTypeQualifiers(
additionalAnnotations: Annotations
): JavaTypeQualifiersByElementType? {
if (components.annotationTypeQualifierResolver.disabled) return defaultTypeQualifiers
if (components.javaTypeEnhancementState.disabledDefaultAnnotations) return defaultTypeQualifiers
val defaultQualifiers =
additionalAnnotations.mapNotNull(this::extractDefaultNullabilityQualifier)
@@ -56,7 +56,7 @@ class LazyJavaPackageFragment(
override val annotations =
// Do not resolve package annotations if JSR-305 is disabled
if (c.components.annotationTypeQualifierResolver.disabled) Annotations.EMPTY
if (c.components.javaTypeEnhancementState.disabledDefaultAnnotations) Annotations.EMPTY
else c.resolveAnnotations(jPackage)
internal fun getSubPackageFqNames(): List<FqName> = subPackages()
@@ -41,6 +41,7 @@ import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
import org.jetbrains.kotlin.utils.JavaTypeEnhancementState
import org.jetbrains.kotlin.utils.ReportLevel
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
@@ -102,11 +103,16 @@ class SignatureEnhancement(
private fun jspecifyMigrationStatus(
annotationFqName: FqName
): NullabilityQualifierWithMigrationStatus? = when (annotationFqName) {
JSPECIFY_NOT_NULL -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL)
JSPECIFY_NULLABLE -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE)
JSPECIFY_NULLNESS_UNKNOWN -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.FORCE_FLEXIBILITY)
else -> null
): NullabilityQualifierWithMigrationStatus? {
if (javaTypeEnhancementState.jspecifyReportLevel == ReportLevel.IGNORE) return null
val isForWarningOnly = javaTypeEnhancementState.jspecifyReportLevel == ReportLevel.WARN
return when (annotationFqName) {
JSPECIFY_NOT_NULL -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL, isForWarningOnly)
JSPECIFY_NULLABLE -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE, isForWarningOnly)
JSPECIFY_NULLNESS_UNKNOWN ->
NullabilityQualifierWithMigrationStatus(NullabilityQualifier.FORCE_FLEXIBILITY, isForWarningOnly)
else -> null
}
}
private fun commonMigrationStatus(
@@ -111,6 +111,7 @@ fun makeLazyJavaPackageFragmentFromClassLoaderProvider(
packagePartProvider: PackagePartProvider = PackagePartProvider.Empty
): LazyJavaPackageFragmentProvider {
val annotationTypeQualifierResolver = AnnotationTypeQualifierResolver(storageManager, JavaTypeEnhancementState.DISABLED_JSR_305)
val javaTypeEnhancementState = JavaTypeEnhancementState.DISABLED_JSR_305
val javaResolverComponents = JavaResolverComponents(
storageManager, ReflectJavaClassFinder(classLoader), reflectKotlinClassFinder, deserializedDescriptorResolver,
SignaturePropagator.DO_NOTHING, RuntimeErrorReporter, JavaResolverCache.EMPTY,
@@ -118,7 +119,7 @@ fun makeLazyJavaPackageFragmentFromClassLoaderProvider(
singleModuleClassResolver, packagePartProvider, SupertypeLoopChecker.EMPTY, LookupTracker.DO_NOTHING, module,
ReflectionTypes(module, notFoundClasses), annotationTypeQualifierResolver,
SignatureEnhancement(annotationTypeQualifierResolver, JavaTypeEnhancementState.DISABLED_JSR_305, JavaTypeEnhancement(JavaResolverSettings.Default)),
JavaClassesTracker.Default, JavaResolverSettings.Default, NewKotlinTypeChecker.Default
JavaClassesTracker.Default, JavaResolverSettings.Default, NewKotlinTypeChecker.Default, javaTypeEnhancementState
)
return LazyJavaPackageFragmentProvider(javaResolverComponents)
@@ -34,7 +34,8 @@ class JavaTypeEnhancementState(
val globalJsr305Level: ReportLevel,
val migrationLevelForJsr305: ReportLevel?,
val userDefinedLevelForSpecificJsr305Annotation: Map<String, ReportLevel>,
val enableCompatqualCheckerFrameworkAnnotations: Boolean = COMPATQUAL_CHECKER_FRAMEWORK_ANNOTATIONS_SUPPORT_DEFAULT_VALUE
val enableCompatqualCheckerFrameworkAnnotations: Boolean = COMPATQUAL_CHECKER_FRAMEWORK_ANNOTATIONS_SUPPORT_DEFAULT_VALUE,
val jspecifyReportLevel: ReportLevel = DEFAULT_REPORT_LEVEL_FOR_CODE_ANALYSIS
) {
val description: Array<String> by lazy {
val result = mutableListOf<String>()
@@ -49,11 +50,19 @@ class JavaTypeEnhancementState(
result.toTypedArray()
}
val disabledJsr305: Boolean get() = this === DISABLED_JSR_305
val disabledJsr305: Boolean =
globalJsr305Level == ReportLevel.IGNORE &&
migrationLevelForJsr305 == ReportLevel.IGNORE &&
userDefinedLevelForSpecificJsr305Annotation.isEmpty()
val disabledDefaultAnnotations = disabledJsr305 || jspecifyReportLevel == ReportLevel.IGNORE
companion object {
const val COMPATQUAL_CHECKER_FRAMEWORK_ANNOTATIONS_SUPPORT_DEFAULT_VALUE = true
@JvmField
val DEFAULT_REPORT_LEVEL_FOR_CODE_ANALYSIS = ReportLevel.WARN
@JvmField
val DEFAULT: JavaTypeEnhancementState = JavaTypeEnhancementState(ReportLevel.WARN, null, emptyMap())
@@ -79,7 +79,8 @@ object IDELanguageSettingsProvider : LanguageSettingsProvider {
result = JavaTypeEnhancementStateParser(MessageCollector.NONE).parse(
compilerArguments.jsr305,
compilerArguments.supportCompatqualCheckerFrameworkAnnotations
compilerArguments.supportCompatqualCheckerFrameworkAnnotations,
compilerArguments.jspecifyAnnotations
)
}