Add -Xsupport-compatqual-checker-framework-annotations flag
It's implemented through Jsr305State while it's not related to jsr-305 becasue currently it's the most convenient way to introduce the flag. Probably, it's worth renaming Jsr305State to something more abstract like NullabilityAnnotationsConfiguration #KT-21982 Fixed
This commit is contained in:
+20
-2
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.utils.Jsr305State
|
|||||||
import org.jetbrains.kotlin.utils.ReportLevel
|
import org.jetbrains.kotlin.utils.ReportLevel
|
||||||
|
|
||||||
class Jsr305Parser(private val collector: MessageCollector) {
|
class Jsr305Parser(private val collector: MessageCollector) {
|
||||||
fun parse(value: Array<String>?): Jsr305State {
|
fun parse(value: Array<String>?, supportCompatqualCheckerFrameworkAnnotations: String?): Jsr305State {
|
||||||
var global: ReportLevel? = null
|
var global: ReportLevel? = null
|
||||||
var migration: ReportLevel? = null
|
var migration: ReportLevel? = null
|
||||||
val userDefined = mutableMapOf<String, ReportLevel>()
|
val userDefined = mutableMapOf<String, ReportLevel>()
|
||||||
@@ -70,7 +70,25 @@ class Jsr305Parser(private val collector: MessageCollector) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val state = Jsr305State(global ?: ReportLevel.WARN, migration, userDefined)
|
val enableCompatqualCheckerFrameworkAnnotations = when (supportCompatqualCheckerFrameworkAnnotations) {
|
||||||
|
"enable" -> true
|
||||||
|
"disable" -> false
|
||||||
|
null -> null
|
||||||
|
else -> {
|
||||||
|
collector.report(
|
||||||
|
CompilerMessageSeverity.ERROR,
|
||||||
|
"Unrecognized -Xsupport-compatqual-checker-framework-annotations option: $supportCompatqualCheckerFrameworkAnnotations. Possible values are 'enable'/'disable'"
|
||||||
|
)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val state = Jsr305State(
|
||||||
|
global ?: ReportLevel.WARN, migration, userDefined,
|
||||||
|
enableCompatqualCheckerFrameworkAnnotations =
|
||||||
|
enableCompatqualCheckerFrameworkAnnotations
|
||||||
|
?: Jsr305State.COMPATQUAL_CHECKER_FRAMEWORK_ANNOTATIONS_SUPPORT_DEFAULT_VALUE
|
||||||
|
)
|
||||||
return if (state == Jsr305State.DISABLED) Jsr305State.DISABLED else state
|
return if (state == Jsr305State.DISABLED) Jsr305State.DISABLED else state
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+15
-4
@@ -16,13 +16,10 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.cli.common.arguments
|
package org.jetbrains.kotlin.cli.common.arguments
|
||||||
|
|
||||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
|
|
||||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||||
import org.jetbrains.kotlin.config.AnalysisFlag
|
import org.jetbrains.kotlin.config.AnalysisFlag
|
||||||
import org.jetbrains.kotlin.config.JVMConstructorCallNormalizationMode
|
import org.jetbrains.kotlin.config.JVMConstructorCallNormalizationMode
|
||||||
import org.jetbrains.kotlin.config.JvmTarget
|
import org.jetbrains.kotlin.config.JvmTarget
|
||||||
import org.jetbrains.kotlin.utils.Jsr305State
|
|
||||||
import org.jetbrains.kotlin.utils.ReportLevel
|
|
||||||
|
|
||||||
class K2JVMCompilerArguments : CommonCompilerArguments() {
|
class K2JVMCompilerArguments : CommonCompilerArguments() {
|
||||||
companion object {
|
companion object {
|
||||||
@@ -191,6 +188,17 @@ class K2JVMCompilerArguments : CommonCompilerArguments() {
|
|||||||
)
|
)
|
||||||
var jsr305: Array<String>? by FreezableVar(null)
|
var jsr305: Array<String>? by FreezableVar(null)
|
||||||
|
|
||||||
|
@Argument(
|
||||||
|
value = "-Xsupport-compatqual-checker-framework-annotations",
|
||||||
|
valueDescription = "enable|disable",
|
||||||
|
description =
|
||||||
|
"""
|
||||||
|
Specify behavior for Checker Framework compatqual annotations (NullableDecl/NonNullDecl).
|
||||||
|
Default value is 'enable'
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
var supportCompatqualCheckerFrameworkAnnotations: String? by FreezableVar(null)
|
||||||
|
|
||||||
@Argument(
|
@Argument(
|
||||||
value = "-Xno-exception-on-explicit-equals-for-boxed-null",
|
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"
|
description = "Do not throw NPE on explicit 'equals' call for null receiver of platform boxed primitive type"
|
||||||
@@ -202,7 +210,10 @@ class K2JVMCompilerArguments : CommonCompilerArguments() {
|
|||||||
|
|
||||||
override fun configureAnalysisFlags(collector: MessageCollector): MutableMap<AnalysisFlag<*>, Any> {
|
override fun configureAnalysisFlags(collector: MessageCollector): MutableMap<AnalysisFlag<*>, Any> {
|
||||||
val result = super.configureAnalysisFlags(collector)
|
val result = super.configureAnalysisFlags(collector)
|
||||||
result[AnalysisFlag.jsr305] = Jsr305Parser(collector).parse(jsr305)
|
result[AnalysisFlag.jsr305] = Jsr305Parser(collector).parse(
|
||||||
|
jsr305,
|
||||||
|
supportCompatqualCheckerFrameworkAnnotations
|
||||||
|
)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
public class A {
|
||||||
|
public void foo(@org.checkerframework.checker.nullness.compatqual.NonNullDecl String x) {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
$TESTDATA_DIR$/compatqualUsage.kt
|
||||||
|
$TESTDATA_DIR$/compatqual
|
||||||
|
$FOREIGN_ANNOTATIONS_DIR$
|
||||||
|
-d
|
||||||
|
$TEMP_DIR$
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
compiler/testData/cli/jvm/compatqualUsage.kt:2:11: error: null can not be a value of a non-null type String
|
||||||
|
a.foo(null)
|
||||||
|
^
|
||||||
|
COMPILATION_ERROR
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
-Xsupport-compatqual-checker-framework-annotations=disable
|
||||||
|
$TESTDATA_DIR$/compatqualUsage.kt
|
||||||
|
$TESTDATA_DIR$/compatqual
|
||||||
|
$FOREIGN_ANNOTATIONS_DIR$
|
||||||
|
-d
|
||||||
|
$TEMP_DIR$
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
OK
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
-Xsupport-compatqual-checker-framework-annotations=enable
|
||||||
|
$TESTDATA_DIR$/compatqualUsage.kt
|
||||||
|
$TESTDATA_DIR$/compatqual
|
||||||
|
$FOREIGN_ANNOTATIONS_DIR$
|
||||||
|
-d
|
||||||
|
$TEMP_DIR$
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
compiler/testData/cli/jvm/compatqualUsage.kt:2:11: error: null can not be a value of a non-null type String
|
||||||
|
a.foo(null)
|
||||||
|
^
|
||||||
|
COMPILATION_ERROR
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fun bar(a: A) {
|
||||||
|
a.foo(null)
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
-Xsupport-compatqual-checker-framework-annotations=true
|
||||||
|
$TESTDATA_DIR$/compatqualUsage.kt
|
||||||
|
$TESTDATA_DIR$/compatqual
|
||||||
|
$FOREIGN_ANNOTATIONS_DIR$
|
||||||
|
-d
|
||||||
|
$TEMP_DIR$
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
error: unrecognized -Xsupport-compatqual-checker-framework-annotations option: true. Possible values are 'enable'/'disable'
|
||||||
|
COMPILATION_ERROR
|
||||||
+5
@@ -35,6 +35,11 @@ where advanced options include:
|
|||||||
-Xskip-runtime-version-check Allow Kotlin runtime libraries of incompatible versions in the classpath
|
-Xskip-runtime-version-check Allow Kotlin runtime libraries of incompatible versions in the classpath
|
||||||
-Xstrict-java-nullability-assertions
|
-Xstrict-java-nullability-assertions
|
||||||
Generate nullability assertions for non-null Java expressions
|
Generate nullability assertions for non-null Java expressions
|
||||||
|
-Xsupport-compatqual-checker-framework-annotations=enable|disable
|
||||||
|
|
||||||
|
Specify behavior for Checker Framework compatqual annotations (NullableDecl/NonNullDecl).
|
||||||
|
Default value is 'enable'
|
||||||
|
|
||||||
-Xuse-javac Use javac for Java source and class files analysis
|
-Xuse-javac Use javac for Java source and class files analysis
|
||||||
-Xuse-old-class-files-reading Use old class files reading implementation (may slow down the build and should be used in case of problems with the new implementation)
|
-Xuse-old-class-files-reading Use old class files reading implementation (may slow down the build and should be used in case of problems with the new implementation)
|
||||||
-Xallow-kotlin-package Allow compiling code in package 'kotlin' and allow not requiring kotlin.stdlib in module-info
|
-Xallow-kotlin-package Allow compiling code in package 'kotlin' and allow not requiring kotlin.stdlib in module-info
|
||||||
|
|||||||
@@ -99,6 +99,30 @@ public class CliTestGenerated extends AbstractCliTest {
|
|||||||
doJvmTest(fileName);
|
doJvmTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compatqualDefault.args")
|
||||||
|
public void testCompatqualDefault() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/compatqualDefault.args");
|
||||||
|
doJvmTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compatqualDisable.args")
|
||||||
|
public void testCompatqualDisable() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/compatqualDisable.args");
|
||||||
|
doJvmTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compatqualEnable.args")
|
||||||
|
public void testCompatqualEnable() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/compatqualEnable.args");
|
||||||
|
doJvmTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compatqualWrong.args")
|
||||||
|
public void testCompatqualWrong() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/compatqualWrong.args");
|
||||||
|
doJvmTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("conflictingOverloads.args")
|
@TestMetadata("conflictingOverloads.args")
|
||||||
public void testConflictingOverloads() throws Exception {
|
public void testConflictingOverloads() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/conflictingOverloads.args");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/conflictingOverloads.args");
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ val NULLABLE_ANNOTATIONS = listOf(
|
|||||||
FqName("com.android.annotations.Nullable"),
|
FqName("com.android.annotations.Nullable"),
|
||||||
FqName("org.eclipse.jdt.annotation.Nullable"),
|
FqName("org.eclipse.jdt.annotation.Nullable"),
|
||||||
FqName("org.checkerframework.checker.nullness.qual.Nullable"),
|
FqName("org.checkerframework.checker.nullness.qual.Nullable"),
|
||||||
FqName("org.checkerframework.checker.nullness.compatqual.NullableDecl"),
|
|
||||||
FqName("javax.annotation.Nullable"),
|
FqName("javax.annotation.Nullable"),
|
||||||
FqName("javax.annotation.CheckForNull"),
|
FqName("javax.annotation.CheckForNull"),
|
||||||
FqName("edu.umd.cs.findbugs.annotations.CheckForNull"),
|
FqName("edu.umd.cs.findbugs.annotations.CheckForNull"),
|
||||||
@@ -43,11 +42,13 @@ val NOT_NULL_ANNOTATIONS = listOf(
|
|||||||
FqName("com.android.annotations.NonNull"),
|
FqName("com.android.annotations.NonNull"),
|
||||||
FqName("org.eclipse.jdt.annotation.NonNull"),
|
FqName("org.eclipse.jdt.annotation.NonNull"),
|
||||||
FqName("org.checkerframework.checker.nullness.qual.NonNull"),
|
FqName("org.checkerframework.checker.nullness.qual.NonNull"),
|
||||||
FqName("org.checkerframework.checker.nullness.compatqual.NonNullDecl"),
|
|
||||||
FqName("lombok.NonNull"),
|
FqName("lombok.NonNull"),
|
||||||
FqName("io.reactivex.annotations.NonNull")
|
FqName("io.reactivex.annotations.NonNull")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val COMPATQUAL_NULLABLE_ANNOTATION = FqName("org.checkerframework.checker.nullness.compatqual.NullableDecl")
|
||||||
|
val COMPATQUAL_NONNULL_ANNOTATION = FqName("org.checkerframework.checker.nullness.compatqual.NonNullDecl")
|
||||||
|
|
||||||
val READ_ONLY_ANNOTATIONS = listOf(
|
val READ_ONLY_ANNOTATIONS = listOf(
|
||||||
JvmAnnotationNames.JETBRAINS_READONLY_ANNOTATION,
|
JvmAnnotationNames.JETBRAINS_READONLY_ANNOTATION,
|
||||||
JvmAnnotationNames.READONLY_ANNOTATION
|
JvmAnnotationNames.READONLY_ANNOTATION
|
||||||
|
|||||||
+16
-10
@@ -31,13 +31,10 @@ import org.jetbrains.kotlin.load.kotlin.computeJvmDescriptor
|
|||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
|
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.firstArgumentValue
|
import org.jetbrains.kotlin.resolve.descriptorUtil.firstArgumentValue
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.*
|
||||||
import org.jetbrains.kotlin.types.TypeUtils
|
|
||||||
import org.jetbrains.kotlin.types.asFlexibleType
|
|
||||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||||
import org.jetbrains.kotlin.types.isFlexible
|
|
||||||
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
|
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
|
||||||
import org.jetbrains.kotlin.types.unwrapEnhancement
|
import org.jetbrains.kotlin.utils.Jsr305State
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
@@ -46,7 +43,10 @@ data class NullabilityQualifierWithMigrationStatus(
|
|||||||
val isForWarningOnly: Boolean = false
|
val isForWarningOnly: Boolean = false
|
||||||
)
|
)
|
||||||
|
|
||||||
class SignatureEnhancement(private val annotationTypeQualifierResolver: AnnotationTypeQualifierResolver) {
|
class SignatureEnhancement(
|
||||||
|
private val annotationTypeQualifierResolver: AnnotationTypeQualifierResolver,
|
||||||
|
private val jsr305State: Jsr305State
|
||||||
|
) {
|
||||||
|
|
||||||
private fun AnnotationDescriptor.extractNullabilityTypeFromArgument(): NullabilityQualifierWithMigrationStatus? {
|
private fun AnnotationDescriptor.extractNullabilityTypeFromArgument(): NullabilityQualifierWithMigrationStatus? {
|
||||||
val enumEntryDescriptor = firstArgumentValue()
|
val enumEntryDescriptor = firstArgumentValue()
|
||||||
@@ -81,10 +81,16 @@ class SignatureEnhancement(private val annotationTypeQualifierResolver: Annotati
|
|||||||
): NullabilityQualifierWithMigrationStatus? {
|
): NullabilityQualifierWithMigrationStatus? {
|
||||||
val annotationFqName = annotationDescriptor.fqName ?: return null
|
val annotationFqName = annotationDescriptor.fqName ?: return null
|
||||||
|
|
||||||
return when (annotationFqName) {
|
return when {
|
||||||
in NULLABLE_ANNOTATIONS -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE)
|
annotationFqName in NULLABLE_ANNOTATIONS -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE)
|
||||||
in NOT_NULL_ANNOTATIONS -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL)
|
annotationFqName in NOT_NULL_ANNOTATIONS -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL)
|
||||||
JAVAX_NONNULL_ANNOTATION -> annotationDescriptor.extractNullabilityTypeFromArgument()
|
annotationFqName == JAVAX_NONNULL_ANNOTATION -> annotationDescriptor.extractNullabilityTypeFromArgument()
|
||||||
|
|
||||||
|
annotationFqName == COMPATQUAL_NULLABLE_ANNOTATION && jsr305State.enableCompatqualCheckerFrameworkAnnotations ->
|
||||||
|
NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE)
|
||||||
|
|
||||||
|
annotationFqName == COMPATQUAL_NONNULL_ANNOTATION && jsr305State.enableCompatqualCheckerFrameworkAnnotations ->
|
||||||
|
NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL)
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -68,7 +68,7 @@ class RuntimeModuleData private constructor(
|
|||||||
runtimePackagePartProvider, SupertypeLoopChecker.EMPTY, LookupTracker.DO_NOTHING, module,
|
runtimePackagePartProvider, SupertypeLoopChecker.EMPTY, LookupTracker.DO_NOTHING, module,
|
||||||
ReflectionTypes(module, notFoundClasses),
|
ReflectionTypes(module, notFoundClasses),
|
||||||
annotationTypeQualifierResolver,
|
annotationTypeQualifierResolver,
|
||||||
SignatureEnhancement(annotationTypeQualifierResolver),
|
SignatureEnhancement(annotationTypeQualifierResolver, Jsr305State.DISABLED),
|
||||||
JavaClassesTracker.Default
|
JavaClassesTracker.Default
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,8 @@ enum class ReportLevel(val description: String) {
|
|||||||
data class Jsr305State(
|
data class Jsr305State(
|
||||||
val global: ReportLevel,
|
val global: ReportLevel,
|
||||||
val migration: ReportLevel?,
|
val migration: ReportLevel?,
|
||||||
val user: Map<String, ReportLevel>
|
val user: Map<String, ReportLevel>,
|
||||||
|
val enableCompatqualCheckerFrameworkAnnotations: Boolean = COMPATQUAL_CHECKER_FRAMEWORK_ANNOTATIONS_SUPPORT_DEFAULT_VALUE
|
||||||
) {
|
) {
|
||||||
val description: Array<String> by lazy {
|
val description: Array<String> by lazy {
|
||||||
val result = mutableListOf<String>()
|
val result = mutableListOf<String>()
|
||||||
@@ -51,6 +52,8 @@ data class Jsr305State(
|
|||||||
val disabled: Boolean get() = this === DISABLED
|
val disabled: Boolean get() = this === DISABLED
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
const val COMPATQUAL_CHECKER_FRAMEWORK_ANNOTATIONS_SUPPORT_DEFAULT_VALUE = true
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
val DEFAULT: Jsr305State = Jsr305State(ReportLevel.WARN, null, emptyMap())
|
val DEFAULT: Jsr305State = Jsr305State(ReportLevel.WARN, null, emptyMap())
|
||||||
|
|
||||||
|
|||||||
+4
-1
@@ -47,7 +47,10 @@ object IDELanguageSettingsProvider : LanguageSettingsProvider {
|
|||||||
val settings = KotlinFacetSettingsProvider.getInstance(project).getSettings(module) ?: continue
|
val settings = KotlinFacetSettingsProvider.getInstance(project).getSettings(module) ?: continue
|
||||||
val compilerArguments = settings.mergedCompilerArguments as? K2JVMCompilerArguments ?: continue
|
val compilerArguments = settings.mergedCompilerArguments as? K2JVMCompilerArguments ?: continue
|
||||||
|
|
||||||
val jsr305State = Jsr305Parser(MessageCollector.NONE).parse(compilerArguments.jsr305)
|
val jsr305State = Jsr305Parser(MessageCollector.NONE).parse(
|
||||||
|
compilerArguments.jsr305,
|
||||||
|
compilerArguments.supportCompatqualCheckerFrameworkAnnotations
|
||||||
|
)
|
||||||
map.put(AnalysisFlag.jsr305, jsr305State)
|
map.put(AnalysisFlag.jsr305, jsr305State)
|
||||||
}
|
}
|
||||||
return map
|
return map
|
||||||
|
|||||||
Reference in New Issue
Block a user