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
|
||||
|
||||
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 migration: ReportLevel? = null
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
+15
-4
@@ -16,13 +16,10 @@
|
||||
|
||||
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.config.AnalysisFlag
|
||||
import org.jetbrains.kotlin.config.JVMConstructorCallNormalizationMode
|
||||
import org.jetbrains.kotlin.config.JvmTarget
|
||||
import org.jetbrains.kotlin.utils.Jsr305State
|
||||
import org.jetbrains.kotlin.utils.ReportLevel
|
||||
|
||||
class K2JVMCompilerArguments : CommonCompilerArguments() {
|
||||
companion object {
|
||||
@@ -191,6 +188,17 @@ class K2JVMCompilerArguments : CommonCompilerArguments() {
|
||||
)
|
||||
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(
|
||||
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"
|
||||
@@ -202,7 +210,10 @@ class K2JVMCompilerArguments : CommonCompilerArguments() {
|
||||
|
||||
override fun configureAnalysisFlags(collector: MessageCollector): MutableMap<AnalysisFlag<*>, Any> {
|
||||
val result = super.configureAnalysisFlags(collector)
|
||||
result[AnalysisFlag.jsr305] = Jsr305Parser(collector).parse(jsr305)
|
||||
result[AnalysisFlag.jsr305] = Jsr305Parser(collector).parse(
|
||||
jsr305,
|
||||
supportCompatqualCheckerFrameworkAnnotations
|
||||
)
|
||||
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
|
||||
-Xstrict-java-nullability-assertions
|
||||
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-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
|
||||
|
||||
@@ -99,6 +99,30 @@ public class CliTestGenerated extends AbstractCliTest {
|
||||
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")
|
||||
public void testConflictingOverloads() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/conflictingOverloads.args");
|
||||
|
||||
@@ -24,7 +24,6 @@ val NULLABLE_ANNOTATIONS = listOf(
|
||||
FqName("com.android.annotations.Nullable"),
|
||||
FqName("org.eclipse.jdt.annotation.Nullable"),
|
||||
FqName("org.checkerframework.checker.nullness.qual.Nullable"),
|
||||
FqName("org.checkerframework.checker.nullness.compatqual.NullableDecl"),
|
||||
FqName("javax.annotation.Nullable"),
|
||||
FqName("javax.annotation.CheckForNull"),
|
||||
FqName("edu.umd.cs.findbugs.annotations.CheckForNull"),
|
||||
@@ -43,11 +42,13 @@ val NOT_NULL_ANNOTATIONS = listOf(
|
||||
FqName("com.android.annotations.NonNull"),
|
||||
FqName("org.eclipse.jdt.annotation.NonNull"),
|
||||
FqName("org.checkerframework.checker.nullness.qual.NonNull"),
|
||||
FqName("org.checkerframework.checker.nullness.compatqual.NonNullDecl"),
|
||||
FqName("lombok.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(
|
||||
JvmAnnotationNames.JETBRAINS_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.platform.JavaToKotlinClassMap
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.firstArgumentValue
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.asFlexibleType
|
||||
import org.jetbrains.kotlin.types.*
|
||||
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.unwrapEnhancement
|
||||
import org.jetbrains.kotlin.utils.Jsr305State
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
@@ -46,7 +43,10 @@ data class NullabilityQualifierWithMigrationStatus(
|
||||
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? {
|
||||
val enumEntryDescriptor = firstArgumentValue()
|
||||
@@ -81,10 +81,16 @@ class SignatureEnhancement(private val annotationTypeQualifierResolver: Annotati
|
||||
): NullabilityQualifierWithMigrationStatus? {
|
||||
val annotationFqName = annotationDescriptor.fqName ?: return null
|
||||
|
||||
return when (annotationFqName) {
|
||||
in NULLABLE_ANNOTATIONS -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE)
|
||||
in NOT_NULL_ANNOTATIONS -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL)
|
||||
JAVAX_NONNULL_ANNOTATION -> annotationDescriptor.extractNullabilityTypeFromArgument()
|
||||
return when {
|
||||
annotationFqName in NULLABLE_ANNOTATIONS -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE)
|
||||
annotationFqName in NOT_NULL_ANNOTATIONS -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL)
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -68,7 +68,7 @@ class RuntimeModuleData private constructor(
|
||||
runtimePackagePartProvider, SupertypeLoopChecker.EMPTY, LookupTracker.DO_NOTHING, module,
|
||||
ReflectionTypes(module, notFoundClasses),
|
||||
annotationTypeQualifierResolver,
|
||||
SignatureEnhancement(annotationTypeQualifierResolver),
|
||||
SignatureEnhancement(annotationTypeQualifierResolver, Jsr305State.DISABLED),
|
||||
JavaClassesTracker.Default
|
||||
)
|
||||
|
||||
|
||||
@@ -33,7 +33,8 @@ enum class ReportLevel(val description: String) {
|
||||
data class Jsr305State(
|
||||
val global: 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 result = mutableListOf<String>()
|
||||
@@ -51,6 +52,8 @@ data class Jsr305State(
|
||||
val disabled: Boolean get() = this === DISABLED
|
||||
|
||||
companion object {
|
||||
const val COMPATQUAL_CHECKER_FRAMEWORK_ANNOTATIONS_SUPPORT_DEFAULT_VALUE = true
|
||||
|
||||
@JvmField
|
||||
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 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)
|
||||
}
|
||||
return map
|
||||
|
||||
Reference in New Issue
Block a user