diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/JavaTypeEnhancementStateParser.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/JavaTypeEnhancementStateParser.kt index 0f9800cf3c3..f2b6ce1b292 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/JavaTypeEnhancementStateParser.kt +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/JavaTypeEnhancementStateParser.kt @@ -23,7 +23,9 @@ import org.jetbrains.kotlin.utils.ReportLevel class JavaTypeEnhancementStateParser(private val collector: MessageCollector) { fun parse( - jsr305Args: Array?, supportCompatqualCheckerFrameworkAnnotations: String? + jsr305Args: Array?, + 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?, diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt index 2c9742d16e8..2e8a38ba78a 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt @@ -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 { diff --git a/compiler/testData/cli/jvm/codeanalysis/A.java b/compiler/testData/cli/jvm/codeanalysis/A.java new file mode 100644 index 00000000000..5ca1e304e92 --- /dev/null +++ b/compiler/testData/cli/jvm/codeanalysis/A.java @@ -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; } +} diff --git a/compiler/testData/cli/jvm/codeanalysisDefault.args b/compiler/testData/cli/jvm/codeanalysisDefault.args new file mode 100644 index 00000000000..0664e0e7874 --- /dev/null +++ b/compiler/testData/cli/jvm/codeanalysisDefault.args @@ -0,0 +1,5 @@ +$TESTDATA_DIR$/jspecifyUsage.kt +$TESTDATA_DIR$/jspecify +$FOREIGN_ANNOTATIONS_DIR$ +-d +$TEMP_DIR$ diff --git a/compiler/testData/cli/jvm/codeanalysisDefault.out b/compiler/testData/cli/jvm/codeanalysisDefault.out new file mode 100644 index 00000000000..bf21be97ece --- /dev/null +++ b/compiler/testData/cli/jvm/codeanalysisDefault.out @@ -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 diff --git a/compiler/testData/cli/jvm/codeanalysisIgnore.args b/compiler/testData/cli/jvm/codeanalysisIgnore.args new file mode 100644 index 00000000000..b796c76ceaf --- /dev/null +++ b/compiler/testData/cli/jvm/codeanalysisIgnore.args @@ -0,0 +1,6 @@ +-Xcodeanalysis-annotations=ignore +$TESTDATA_DIR$/codeanalysisUsage.kt +$TESTDATA_DIR$/codeanalysis +$FOREIGN_ANNOTATIONS_DIR$ +-d +$TEMP_DIR$ diff --git a/compiler/testData/cli/jvm/codeanalysisIgnore.out b/compiler/testData/cli/jvm/codeanalysisIgnore.out new file mode 100644 index 00000000000..d86bac9de59 --- /dev/null +++ b/compiler/testData/cli/jvm/codeanalysisIgnore.out @@ -0,0 +1 @@ +OK diff --git a/compiler/testData/cli/jvm/codeanalysisStrict.args b/compiler/testData/cli/jvm/codeanalysisStrict.args new file mode 100644 index 00000000000..24e6c7a50ce --- /dev/null +++ b/compiler/testData/cli/jvm/codeanalysisStrict.args @@ -0,0 +1,6 @@ +-Xcodeanalysis-annotations=strict +$TESTDATA_DIR$/codeanalysisUsage.kt +$TESTDATA_DIR$/codeanalysis +$FOREIGN_ANNOTATIONS_DIR$ +-d +$TEMP_DIR$ diff --git a/compiler/testData/cli/jvm/codeanalysisStrict.out b/compiler/testData/cli/jvm/codeanalysisStrict.out new file mode 100644 index 00000000000..2a911ebf791 --- /dev/null +++ b/compiler/testData/cli/jvm/codeanalysisStrict.out @@ -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 diff --git a/compiler/testData/cli/jvm/codeanalysisUsage.kt b/compiler/testData/cli/jvm/codeanalysisUsage.kt new file mode 100644 index 00000000000..4d3573ac204 --- /dev/null +++ b/compiler/testData/cli/jvm/codeanalysisUsage.kt @@ -0,0 +1,4 @@ +fun bar(a: A) { + a.foo(null) + a.bar().hashCode() +} diff --git a/compiler/testData/cli/jvm/codeanalysisWarn.args b/compiler/testData/cli/jvm/codeanalysisWarn.args new file mode 100644 index 00000000000..23d2c264f70 --- /dev/null +++ b/compiler/testData/cli/jvm/codeanalysisWarn.args @@ -0,0 +1,6 @@ +-Xjspecify-annotations=warn +$TESTDATA_DIR$/codeanalysisUsage.kt +$TESTDATA_DIR$/codeanalysis +$FOREIGN_ANNOTATIONS_DIR$ +-d +$TEMP_DIR$ diff --git a/compiler/testData/cli/jvm/codeanalysisWarn.out b/compiler/testData/cli/jvm/codeanalysisWarn.out new file mode 100644 index 00000000000..7c2a6d77f6e --- /dev/null +++ b/compiler/testData/cli/jvm/codeanalysisWarn.out @@ -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 diff --git a/compiler/testData/cli/jvm/extraHelp.out b/compiler/testData/cli/jvm/extraHelp.out index c7c4bd7ea09..7e451fd000f 100644 --- a/compiler/testData/cli/jvm/extraHelp.out +++ b/compiler/testData/cli/jvm/extraHelp.out @@ -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 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), diff --git a/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/ignoreAnnotations.kt b/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/ignoreAnnotations.kt new file mode 100644 index 00000000000..2c0c9be935c --- /dev/null +++ b/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/ignoreAnnotations.kt @@ -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 +} diff --git a/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/ignoreAnnotations.txt b/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/ignoreAnnotations.txt new file mode 100644 index 00000000000..009faf943f9 --- /dev/null +++ b/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/ignoreAnnotations.txt @@ -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 +} diff --git a/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/annotatedWildcards.kt b/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/annotatedWildcards.kt new file mode 100644 index 00000000000..ae6562fb736 --- /dev/null +++ b/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/annotatedWildcards.kt @@ -0,0 +1,81 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER +// CODE_ANALYSIS_STATE warn +// FILE: A.java + +import jspecify.annotations.*; + +public class A { +} + +// FILE: B.java + +import jspecify.annotations.*; + +public class B { + public void superAsIs(A a) {} + public void superNotNull(A a) {} + public void superNullable(A a) {} + + public void extendsAsIs(A a) {} + public void extendsNotNull(A a) {} + public void extendsNullable(A a) {} + + public void noBounds(A a) {} +} + +// FILE: main.kt + +fun main( + aNotNullNotNullNotNull: A, + aNotNullNotNullNull: A, + aNotNullNullNotNull: A, + aNotNullNullNull: A, + + aAnyNotNullNotNullNotNull: A, + aAnyNotNullNotNullNull: A, + aAnyNotNullNullNotNull: A, + aAnyNotNullNullNull: A, + 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) +} diff --git a/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/annotatedWildcards.txt b/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/annotatedWildcards.txt new file mode 100644 index 00000000000..301fb427728 --- /dev/null +++ b/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/annotatedWildcards.txt @@ -0,0 +1,24 @@ +package + +public fun main(/*0*/ aNotNullNotNullNotNull: A, /*1*/ aNotNullNotNullNull: A, /*2*/ aNotNullNullNotNull: A, /*3*/ aNotNullNullNull: A, /*4*/ aAnyNotNullNotNullNotNull: A, /*5*/ aAnyNotNullNotNullNull: A, /*6*/ aAnyNotNullNullNotNull: A, /*7*/ aAnyNotNullNullNull: A, /*8*/ b: B): 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 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!): kotlin.Unit + public open fun extendsNotNull(/*0*/ a: A!): kotlin.Unit + public open fun extendsNullable(/*0*/ a: A!): 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!): kotlin.Unit + public open fun superNotNull(/*0*/ a: A!): kotlin.Unit + public open fun superNullable(/*0*/ a: A!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/defaults.kt b/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/defaults.kt new file mode 100644 index 00000000000..98a8bd5e8e1 --- /dev/null +++ b/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/defaults.kt @@ -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(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 + + a.mixed(null).length + a.mixed(null)?.length + a.mixed("")?.length + + a.defaultField?.length + a.defaultField.length + + a.field?.length + a.field.length +} diff --git a/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/defaults.txt b/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/defaults.txt new file mode 100644 index 00000000000..de6f9f8712d --- /dev/null +++ b/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/defaults.txt @@ -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 +} diff --git a/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/nonPlatformTypeParameter.kt b/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/nonPlatformTypeParameter.kt new file mode 100644 index 00000000000..5af1a774f0b --- /dev/null +++ b/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/nonPlatformTypeParameter.kt @@ -0,0 +1,50 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER +// CODE_ANALYSIS_STATE warn +// FILE: A.java + +import jspecify.annotations.*; + +public class A { + public void foo(T t) {} + public void bar(E e) {} +} + +// FILE: B.java + +import jspecify.annotations.*; + +@DefaultNullable +public class B { + public void foo(T t) {} + public void bar(E e) {} +} + +// FILE: main.kt + +fun main(a1: A, a2: A, b1: B, b2: B) { + a1.foo(null) + a1.bar(null) + // TODO: NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS should be reported + a1.bar(null) + a1.bar("") + + // TODO: NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS should be reported + a2.foo(null) + a2.bar(null) + // TODO: NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS should be reported + a2.bar(null) + a2.bar("") + + b1.foo(null) + b1.bar(null) + // TODO: NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS should be reported + b1.bar(null) + b1.bar("") + + // TODO: NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS should be reported + b2.foo(null) + b2.bar(null) + // TODO: NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS should be reported + b2.bar(null) + b2.bar("") +} diff --git a/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/nonPlatformTypeParameter.txt b/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/nonPlatformTypeParameter.txt new file mode 100644 index 00000000000..b33c1d298c9 --- /dev/null +++ b/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/nonPlatformTypeParameter.txt @@ -0,0 +1,21 @@ +package + +public fun main(/*0*/ a1: A, /*1*/ a2: A, /*2*/ b1: B, /*3*/ b2: B): kotlin.Unit + +public open class A { + public constructor A() + public open fun 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 { + public constructor B() + public open fun 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 +} diff --git a/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/simple.kt b/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/simple.kt new file mode 100644 index 00000000000..34a07d2dc68 --- /dev/null +++ b/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/simple.kt @@ -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 + a.foo("", null).length + a.foo(null, "").length + + a.bar().length + a.bar()!!.length + + a.field?.length + a.field.length +} diff --git a/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/simple.txt b/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/simple.txt new file mode 100644 index 00000000000..40ee2890e21 --- /dev/null +++ b/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/simple.txt @@ -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 +} diff --git a/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/typeArgumentsFromParameterBounds.kt b/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/typeArgumentsFromParameterBounds.kt new file mode 100644 index 00000000000..af756d2a776 --- /dev/null +++ b/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/typeArgumentsFromParameterBounds.kt @@ -0,0 +1,68 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER +// CODE_ANALYSIS_STATE warn +// FILE: A.java + +import jspecify.annotations.*; + +public class A { +} + +// FILE: B.java + +import jspecify.annotations.*; + +@DefaultNullable +public class B { + public void bar(A a) {} +} + +// FILE: C.java + +import jspecify.annotations.*; + +@DefaultNotNull +public class C { + public void bar(A a) {} +} + +// FILE: D.java + +import jspecify.annotations.*; + +@DefaultUnknownNullness +public class D { + public void bar(A a) {} +} + +// FILE: main.kt + +fun main( + aNotNullNotNullNotNull: A, + aNotNullNotNullNull: A, + aNotNullNullNotNull: A, + aNotNullNullNull: A, + 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) +} diff --git a/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/typeArgumentsFromParameterBounds.txt b/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/typeArgumentsFromParameterBounds.txt new file mode 100644 index 00000000000..9bbb7a9cdd1 --- /dev/null +++ b/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/typeArgumentsFromParameterBounds.txt @@ -0,0 +1,34 @@ +package + +public fun main(/*0*/ aNotNullNotNullNotNull: A, /*1*/ aNotNullNotNullNull: A, /*2*/ aNotNullNullNotNull: A, /*3*/ aNotNullNullNull: A, /*4*/ b: B, /*5*/ c: C, /*6*/ d: D): 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 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.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.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.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 +} diff --git a/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/typeParameterBounds.kt b/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/typeParameterBounds.kt new file mode 100644 index 00000000000..c7dbd329a0e --- /dev/null +++ b/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/typeParameterBounds.kt @@ -0,0 +1,49 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER +// CODE_ANALYSIS_STATE warn +// FILE: A.java + +import jspecify.annotations.*; + +public class A { + public void foo(T t) {} + public void bar(E e) {} +} + +// FILE: B.java + +import jspecify.annotations.*; + +@DefaultNotNull +public class B { + public void foo(T t) {} + public void bar(E e) {} +} + +// FILE: main.kt + +// TODO: UPPER_BOUND_VIOLATED_WARNING should be reported +fun main(a1: A, a2: A, b1: B, b2: B) { + // TODO: NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS should be reported + a1.foo(null) + // TODO: UPPER_BOUND_VIOLATED_WARNING should be reported + a1.bar(null) + a1.bar("") + + // TODO: NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS should be reported + a2.foo(null) + // TODO: UPPER_BOUND_VIOLATED_WARNING should be reported + a2.bar(null) + a2.bar("") + + // TODO: NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS should be reported + b1.foo(null) + // TODO: UPPER_BOUND_VIOLATED_WARNING should be reported + b1.bar(null) + b1.bar("") + + // TODO: NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS should be reported + b2.foo(null) + // TODO: UPPER_BOUND_VIOLATED_WARNING should be reported + b2.bar(null) + b2.bar("") +} diff --git a/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/typeParameterBounds.txt b/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/typeParameterBounds.txt new file mode 100644 index 00000000000..a48a2b051a7 --- /dev/null +++ b/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/typeParameterBounds.txt @@ -0,0 +1,21 @@ +package + +public fun main(/*0*/ a1: A, /*1*/ a2: A, /*2*/ b1: B, /*3*/ b2: B): kotlin.Unit + +public open class A { + public constructor A() + public open fun 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 { + public constructor B() + public open fun 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 +} diff --git a/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/unknownNullnessTypeParameter.kt b/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/unknownNullnessTypeParameter.kt new file mode 100644 index 00000000000..912bf12cbf8 --- /dev/null +++ b/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/unknownNullnessTypeParameter.kt @@ -0,0 +1,30 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER +// CODE_ANALYSIS_STATE warn +// FILE: A.java + +import codeanalysis.annotations.*; + +public class A { + 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, a2: A) { + a1.foo(null) + a1.foo(1) + + a2.foo(null) + a2.foo(1) + + a1.bar(null, null) + a1.bar("", null) + a1.bar("", 1) + + a2.bar(null, null) + a2.bar("", null) + a2.bar("", 1) +} diff --git a/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/unknownNullnessTypeParameter.txt b/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/unknownNullnessTypeParameter.txt new file mode 100644 index 00000000000..2fb2c0fda7c --- /dev/null +++ b/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/unknownNullnessTypeParameter.txt @@ -0,0 +1,12 @@ +package + +public fun main(/*0*/ a1: A, /*1*/ a2: A): kotlin.Unit + +public open class A { + public constructor A() + @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 +} diff --git a/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/wildcardsWithDefault.kt b/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/wildcardsWithDefault.kt new file mode 100644 index 00000000000..2af615f735e --- /dev/null +++ b/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/wildcardsWithDefault.kt @@ -0,0 +1,42 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER +// CODE_ANALYSIS_STATE warn +// FILE: A.java + +import jspecify.annotations.*; + +public class A { +} + +// 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, + aNotNullNotNullNull: A, + aNotNullNullNotNull: A, + aNotNullNullNull: A, + 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) +} diff --git a/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/wildcardsWithDefault.txt b/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/wildcardsWithDefault.txt new file mode 100644 index 00000000000..0954456b442 --- /dev/null +++ b/compiler/testData/foreignAnnotationsJava8/tests/codeanalysis/warnings/wildcardsWithDefault.txt @@ -0,0 +1,19 @@ +package + +public fun main(/*0*/ aNotNullNotNullNotNull: A, /*1*/ aNotNullNotNullNull: A, /*2*/ aNotNullNullNotNull: A, /*3*/ aNotNullNullNull: A, /*4*/ b: B): 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 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 +} diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/checkers/AbstractForeignAnnotationsTest.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/checkers/AbstractForeignAnnotationsTest.kt index cfd5dd53512..cf719b9a0bb 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/checkers/AbstractForeignAnnotationsTest.kt +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/checkers/AbstractForeignAnnotationsTest.kt @@ -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 { 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 ) ) } diff --git a/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/ForeignJava8AnnotationsNoAnnotationInClasspathTestGenerated.java b/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/ForeignJava8AnnotationsNoAnnotationInClasspathTestGenerated.java index ce5956267bd..9983a196179 100644 --- a/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/ForeignJava8AnnotationsNoAnnotationInClasspathTestGenerated.java +++ b/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/ForeignJava8AnnotationsNoAnnotationInClasspathTestGenerated.java @@ -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") diff --git a/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/ForeignJava8AnnotationsNoAnnotationInClasspathWithPsiClassReadingTestGenerated.java b/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/ForeignJava8AnnotationsNoAnnotationInClasspathWithPsiClassReadingTestGenerated.java index b29dc5154d8..561b178f9ab 100644 --- a/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/ForeignJava8AnnotationsNoAnnotationInClasspathWithPsiClassReadingTestGenerated.java +++ b/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/ForeignJava8AnnotationsNoAnnotationInClasspathWithPsiClassReadingTestGenerated.java @@ -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") diff --git a/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/ForeignJava8AnnotationsTestGenerated.java b/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/ForeignJava8AnnotationsTestGenerated.java index ae3d22c9826..ae84bed6985 100644 --- a/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/ForeignJava8AnnotationsTestGenerated.java +++ b/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/ForeignJava8AnnotationsTestGenerated.java @@ -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") diff --git a/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/javac/JavacForeignJava8AnnotationsTestGenerated.java b/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/javac/JavacForeignJava8AnnotationsTestGenerated.java index 409336684e5..78f98186eb4 100644 --- a/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/javac/JavacForeignJava8AnnotationsTestGenerated.java +++ b/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/javac/JavacForeignJava8AnnotationsTestGenerated.java @@ -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") diff --git a/compiler/tests/org/jetbrains/kotlin/cli/CliTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/cli/CliTestGenerated.java index 7388b2e5dfa..1c8ccff3b36 100644 --- a/compiler/tests/org/jetbrains/kotlin/cli/CliTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/cli/CliTestGenerated.java @@ -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"); diff --git a/core/compiler.common.jvm/src/org/jetbrains/kotlin/load/java/AnnotationQualifiersFqNames.kt b/core/compiler.common.jvm/src/org/jetbrains/kotlin/load/java/AnnotationQualifiersFqNames.kt index f228f165fd0..5945dfb866e 100644 --- a/core/compiler.common.jvm/src/org/jetbrains/kotlin/load/java/AnnotationQualifiersFqNames.kt +++ b/core/compiler.common.jvm/src/org/jetbrains/kotlin/load/java/AnnotationQualifiersFqNames.kt @@ -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) diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/AnnotationTypeQualifierResolver.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/AnnotationTypeQualifierResolver.kt index 7a9bd95e993..47d7cddedab 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/AnnotationTypeQualifierResolver.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/AnnotationTypeQualifierResolver.kt @@ -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 diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/context.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/context.kt index 948091b2a9b..f4ed45af85a 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/context.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/context.kt @@ -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) diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaPackageFragment.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaPackageFragment.kt index 2e0d80d2c39..9087cd69d3b 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaPackageFragment.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaPackageFragment.kt @@ -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 = subPackages() diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/typeEnhancement/signatureEnhancement.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/typeEnhancement/signatureEnhancement.kt index ccf5f93bb3f..2da581ef364 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/typeEnhancement/signatureEnhancement.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/typeEnhancement/signatureEnhancement.kt @@ -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( diff --git a/core/descriptors.runtime/src/org/jetbrains/kotlin/descriptors/runtime/components/RuntimeModuleData.kt b/core/descriptors.runtime/src/org/jetbrains/kotlin/descriptors/runtime/components/RuntimeModuleData.kt index b333e3df3df..2d976a2ede2 100644 --- a/core/descriptors.runtime/src/org/jetbrains/kotlin/descriptors/runtime/components/RuntimeModuleData.kt +++ b/core/descriptors.runtime/src/org/jetbrains/kotlin/descriptors/runtime/components/RuntimeModuleData.kt @@ -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) diff --git a/core/util.runtime/src/org/jetbrains/kotlin/utils/JavaTypeEnhancementState.kt b/core/util.runtime/src/org/jetbrains/kotlin/utils/JavaTypeEnhancementState.kt index adc1ac25dc4..1b4d7376aa1 100644 --- a/core/util.runtime/src/org/jetbrains/kotlin/utils/JavaTypeEnhancementState.kt +++ b/core/util.runtime/src/org/jetbrains/kotlin/utils/JavaTypeEnhancementState.kt @@ -34,7 +34,8 @@ class JavaTypeEnhancementState( val globalJsr305Level: ReportLevel, val migrationLevelForJsr305: ReportLevel?, val userDefinedLevelForSpecificJsr305Annotation: Map, - 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 by lazy { val result = mutableListOf() @@ -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()) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/compiler/IDELanguageSettingsProvider.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/compiler/IDELanguageSettingsProvider.kt index 7886d5e8e7b..525c74181f2 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/compiler/IDELanguageSettingsProvider.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/compiler/IDELanguageSettingsProvider.kt @@ -79,7 +79,8 @@ object IDELanguageSettingsProvider : LanguageSettingsProvider { result = JavaTypeEnhancementStateParser(MessageCollector.NONE).parse( compilerArguments.jsr305, - compilerArguments.supportCompatqualCheckerFrameworkAnnotations + compilerArguments.supportCompatqualCheckerFrameworkAnnotations, + compilerArguments.jspecifyAnnotations ) }