[FIR] Implement warnings for java nullability type mismatch

#KT-56989
This commit is contained in:
Kirill Rakhman
2023-09-20 15:34:48 +02:00
committed by Space Team
parent 1ecbc094ec
commit a6fdeeb7df
158 changed files with 741 additions and 2021 deletions
@@ -5033,6 +5033,22 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirJvmErrors.RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS) { firDiagnostic ->
ReceiverNullabilityMismatchBasedOnJavaAnnotationsImpl(
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.b),
firDiagnostic as KtPsiDiagnostic,
token,
)
}
add(FirJvmErrors.NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS) { firDiagnostic ->
NullabilityMismatchBasedOnJavaAnnotationsImpl(
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.b),
firDiagnostic as KtPsiDiagnostic,
token,
)
}
add(FirJvmErrors.UPPER_BOUND_CANNOT_BE_ARRAY) { firDiagnostic ->
UpperBoundCannotBeArrayImpl(
firDiagnostic as KtPsiDiagnostic,
@@ -3501,6 +3501,18 @@ sealed interface KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
val actualType: KtType
}
interface ReceiverNullabilityMismatchBasedOnJavaAnnotations : KtFirDiagnostic<PsiElement> {
override val diagnosticClass get() = ReceiverNullabilityMismatchBasedOnJavaAnnotations::class
val actualType: KtType
val expectedType: KtType
}
interface NullabilityMismatchBasedOnJavaAnnotations : KtFirDiagnostic<PsiElement> {
override val diagnosticClass get() = NullabilityMismatchBasedOnJavaAnnotations::class
val actualType: KtType
val expectedType: KtType
}
interface UpperBoundCannotBeArray : KtFirDiagnostic<PsiElement> {
override val diagnosticClass get() = UpperBoundCannotBeArray::class
}
@@ -4224,6 +4224,20 @@ internal class JavaTypeMismatchImpl(
token: KtLifetimeToken,
) : KtAbstractFirDiagnostic<KtExpression>(firDiagnostic, token), KtFirDiagnostic.JavaTypeMismatch
internal class ReceiverNullabilityMismatchBasedOnJavaAnnotationsImpl(
override val actualType: KtType,
override val expectedType: KtType,
firDiagnostic: KtPsiDiagnostic,
token: KtLifetimeToken,
) : KtAbstractFirDiagnostic<PsiElement>(firDiagnostic, token), KtFirDiagnostic.ReceiverNullabilityMismatchBasedOnJavaAnnotations
internal class NullabilityMismatchBasedOnJavaAnnotationsImpl(
override val actualType: KtType,
override val expectedType: KtType,
firDiagnostic: KtPsiDiagnostic,
token: KtLifetimeToken,
) : KtAbstractFirDiagnostic<PsiElement>(firDiagnostic, token), KtFirDiagnostic.NullabilityMismatchBasedOnJavaAnnotations
internal class UpperBoundCannotBeArrayImpl(
firDiagnostic: KtPsiDiagnostic,
token: KtLifetimeToken,
@@ -216,6 +216,12 @@ public class FirPsiOldFrontendForeignAnnotationsCompiledJavaTestGenerated extend
runTest("compiler/testData/diagnostics/foreignAnnotationsTests/tests/jsr305/nullabilityWarnings/elvis.kt");
}
@Test
@TestMetadata("expressionBodiedFunction.kt")
public void testExpressionBodiedFunction() throws Exception {
runTest("compiler/testData/diagnostics/foreignAnnotationsTests/tests/jsr305/nullabilityWarnings/expressionBodiedFunction.kt");
}
@Test
@TestMetadata("localInference.kt")
public void testLocalInference() throws Exception {
@@ -274,6 +274,12 @@ public class FirPsiOldFrontendForeignAnnotationsCompiledJavaWithPsiClassReadingT
runTest("compiler/testData/diagnostics/foreignAnnotationsTests/tests/jsr305/nullabilityWarnings/elvis.kt");
}
@Test
@TestMetadata("expressionBodiedFunction.kt")
public void testExpressionBodiedFunction() throws Exception {
runTest("compiler/testData/diagnostics/foreignAnnotationsTests/tests/jsr305/nullabilityWarnings/expressionBodiedFunction.kt");
}
@Test
@TestMetadata("localInference.kt")
public void testLocalInference() throws Exception {
@@ -274,6 +274,12 @@ public class FirPsiOldFrontendForeignAnnotationsSourceJavaTestGenerated extends
runTest("compiler/testData/diagnostics/foreignAnnotationsTests/tests/jsr305/nullabilityWarnings/elvis.kt");
}
@Test
@TestMetadata("expressionBodiedFunction.kt")
public void testExpressionBodiedFunction() throws Exception {
runTest("compiler/testData/diagnostics/foreignAnnotationsTests/tests/jsr305/nullabilityWarnings/expressionBodiedFunction.kt");
}
@Test
@TestMetadata("localInference.kt")
public void testLocalInference() throws Exception {
@@ -9,6 +9,7 @@ import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.config.LanguageFeature.*
import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.DiagnosticList
import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.PositioningStrategy
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.name.ClassId
@@ -45,6 +46,15 @@ object JVM_DIAGNOSTICS_LIST : DiagnosticList("FirJvmErrors") {
parameter<ConeKotlinType>("expectedType")
parameter<ConeKotlinType>("actualType")
}
val RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS by warning<PsiElement> {
parameter<ConeKotlinType>("actualType")
parameter<ConeKotlinType>("expectedType")
}
val NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS by warning<PsiElement> {
parameter<ConeKotlinType>("actualType")
parameter<ConeKotlinType>("expectedType")
}
}
val TYPE_PARAMETERS by object : DiagnosticGroup("Type parameters") {
@@ -44,6 +44,8 @@ object FirJvmErrors {
// Types
val JAVA_TYPE_MISMATCH by error2<KtExpression, ConeKotlinType, ConeKotlinType>()
val RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS by warning2<PsiElement, ConeKotlinType, ConeKotlinType>()
val NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS by warning2<PsiElement, ConeKotlinType, ConeKotlinType>()
// Type parameters
val UPPER_BOUND_CANNOT_BE_ARRAY by error0<PsiElement>()
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.fir.analysis.diagnostics.jvm
import org.jetbrains.kotlin.diagnostics.KtDiagnosticFactoryToRendererMap
import org.jetbrains.kotlin.diagnostics.KtDiagnosticRenderers.NOT_RENDERED
import org.jetbrains.kotlin.diagnostics.KtDiagnosticRenderers.TO_STRING
import org.jetbrains.kotlin.diagnostics.rendering.BaseDiagnosticRendererFactory
import org.jetbrains.kotlin.diagnostics.rendering.CommonRenderers.STRING
@@ -52,6 +53,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.NON_DATA_C
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.NON_FINAL_JVM_RECORD
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.NON_SOURCE_REPEATED_ANNOTATION
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.NO_REFLECTION_IN_CLASS_PATH
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.OVERLOADS_ABSTRACT
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.OVERLOADS_ANNOTATION_CLASS_CONSTRUCTOR
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.OVERLOADS_INTERFACE
@@ -60,6 +62,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.OVERLOADS_
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.OVERLOADS_WITHOUT_DEFAULT_ARGUMENTS
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.OVERRIDE_CANNOT_BE_STATIC
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.REDUNDANT_REPEATABLE_ANNOTATION
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.REPEATABLE_ANNOTATION_HAS_NESTED_CLASS_NAMED_CONTAINER
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.REPEATABLE_CONTAINER_HAS_NON_DEFAULT_PARAMETER
@@ -82,6 +85,20 @@ object FirJvmErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
override val MAP = KtDiagnosticFactoryToRendererMap("FIR").also { map ->
map.put(JAVA_TYPE_MISMATCH, "Java type mismatch: expected ''{0}'' but found ''{1}''. Use explicit cast.", RENDER_TYPE, RENDER_TYPE)
map.put(
NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS,
"Java type mismatch: inferred type is ''{1}'', but ''{0}'' was expected.",
RENDER_TYPE,
RENDER_TYPE
)
map.put(
RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS,
"Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type ''{0}''.",
RENDER_TYPE,
NOT_RENDERED
)
map.put(UPPER_BOUND_CANNOT_BE_ARRAY, "Upper bound of type parameter cannot be an array.")
map.put(STRICTFP_ON_CLASS, "'@Strictfp' annotation on classes is not yet supported.")
map.put(SYNCHRONIZED_ON_ABSTRACT, "'@Synchronized' annotation cannot be used on abstract functions.")
@@ -38,12 +38,14 @@ object JvmDeclarationCheckers : DeclarationCheckers() {
get() = setOf(
FirJvmFieldApplicabilityChecker,
FirJvmSyntheticApplicabilityChecker,
FirPropertyJavaNullabilityWarningChecker,
)
override val functionCheckers: Set<FirFunctionChecker>
get() = setOf(
FirSynchronizedAnnotationChecker,
FirOverloadsChecker,
FirFunctionJavaNullabilityWarningChecker,
)
override val typeParameterCheckers: Set<FirTypeParameterChecker>
@@ -55,4 +57,9 @@ object JvmDeclarationCheckers : DeclarationCheckers() {
get() = setOf(
FirInlineBodySimpleFunctionChecker,
)
override val valueParameterCheckers: Set<FirValueParameterChecker>
get() = setOf(
FirValueParameterJavaNullabilityWarningChecker
)
}
@@ -19,6 +19,7 @@ object JvmExpressionCheckers : ExpressionCheckers() {
get() = setOf(
FirInterfaceDefaultMethodCallChecker,
FirJavaSamInterfaceConstructorReferenceChecker,
FirQualifiedAccessJavaNullabilityWarningChecker,
)
override val callableReferenceAccessCheckers: Set<FirCallableReferenceAccessChecker>
@@ -41,4 +42,29 @@ object JvmExpressionCheckers : ExpressionCheckers() {
FirJvmPackageNameAnnotationsChecker,
FirJvmSerializableLambdaChecker,
)
override val loopExpressionCheckers: Set<FirLoopExpressionChecker>
get() = setOf(
FirLoopConditionJavaNullabilityWarningChecker,
)
override val whenExpressionCheckers: Set<FirWhenExpressionChecker>
get() = setOf(
FirWhenConditionJavaNullabilityWarningChecker,
)
override val logicExpressionCheckers: Set<FirLogicExpressionChecker>
get() = setOf(
FirLogicExpressionTypeJavaNullabilityWarningChecker,
)
override val throwExpressionCheckers: Set<FirThrowExpressionChecker>
get() = setOf(
FirThrowJavaNullabilityWarningChecker,
)
override val variableAssignmentCheckers: Set<FirVariableAssignmentChecker>
get() = setOf(
FirAssignmentJavaNullabilityWarningChecker,
)
}
@@ -0,0 +1,59 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.analysis.jvm.checkers.declaration
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirFunctionChecker
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirPropertyChecker
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirValueParameterChecker
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.hasExplicitReturnType
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors
import org.jetbrains.kotlin.fir.analysis.jvm.checkers.expression.checkExpressionForEnhancedTypeMismatch
import org.jetbrains.kotlin.fir.declarations.FirFunction
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
import org.jetbrains.kotlin.fir.expressions.FirReturnExpression
import org.jetbrains.kotlin.fir.expressions.impl.FirSingleExpressionBlock
import org.jetbrains.kotlin.fir.types.coneType
object FirPropertyJavaNullabilityWarningChecker : FirPropertyChecker() {
override fun check(declaration: FirProperty, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration.symbol.hasExplicitReturnType) {
declaration.initializer?.checkExpressionForEnhancedTypeMismatch(
declaration.returnTypeRef.coneType,
reporter,
context,
FirJvmErrors.NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS,
)
}
}
}
object FirFunctionJavaNullabilityWarningChecker : FirFunctionChecker() {
override fun check(declaration: FirFunction, context: CheckerContext, reporter: DiagnosticReporter) {
val body = declaration.body
if (body is FirSingleExpressionBlock && declaration.symbol.hasExplicitReturnType) {
(body.statement as? FirReturnExpression)?.result?.checkExpressionForEnhancedTypeMismatch(
declaration.returnTypeRef.coneType,
reporter,
context,
FirJvmErrors.NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS,
)
}
}
}
object FirValueParameterJavaNullabilityWarningChecker : FirValueParameterChecker() {
override fun check(declaration: FirValueParameter, context: CheckerContext, reporter: DiagnosticReporter) {
declaration.defaultValue?.checkExpressionForEnhancedTypeMismatch(
declaration.returnTypeRef.coneType,
reporter,
context,
FirJvmErrors.NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS,
)
}
}
@@ -0,0 +1,190 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.analysis.jvm.checkers.expression
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.diagnostics.KtDiagnosticFactory2
import org.jetbrains.kotlin.diagnostics.reportOn
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.expression.*
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.impl.FirElseIfTrueCondition
import org.jetbrains.kotlin.fir.java.enhancement.EnhancedForWarningConeSubstitutor
import org.jetbrains.kotlin.fir.resolve.FirSamResolver
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutorByMap
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.types.*
import java.util.*
// TODO reimplement using AdditionalTypeChecker KT-62864
object FirQualifiedAccessJavaNullabilityWarningChecker : FirQualifiedAccessExpressionChecker() {
override fun check(expression: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) {
val symbol = expression.toResolvedCallableSymbol() ?: return
val substitutor = buildSubstitutor(expression, symbol, context.session)
expression.dispatchReceiver?.checkExpressionForEnhancedTypeMismatch(
expectedType = symbol.dispatchReceiverType,
reporter,
context,
FirJvmErrors.RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS
)
val receiverType = symbol.receiverParameter?.typeRef?.coneType
expression.extensionReceiver?.checkExpressionForEnhancedTypeMismatch(
expectedType = receiverType?.let(substitutor::substituteOrSelf),
reporter,
context,
FirJvmErrors.RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS
)
for ((contextArgument, contextParameter) in expression.contextReceiverArguments.zip(symbol.resolvedContextReceivers)) {
contextArgument.checkExpressionForEnhancedTypeMismatch(
expectedType = substitutor.substituteOrSelf(contextParameter.typeRef.coneType),
reporter,
context,
FirJvmErrors.NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS
)
}
if (expression is FirFunctionCall) {
expression.resolvedArgumentMapping?.forEach { (argument, parameter) ->
argument.checkExpressionForEnhancedTypeMismatch(
expectedType = substitutor.substituteOrSelf(parameter.returnTypeRef.coneType),
reporter,
context,
FirJvmErrors.NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS
)
}
}
}
private fun buildSubstitutor(
expression: FirQualifiedAccessExpression,
symbol: FirCallableSymbol<*>,
session: FirSession,
): ConeSubstitutor {
if (expression.typeArguments.isEmpty()) return ConeSubstitutor.Empty
val substitutionMap = buildMap {
for ((parameter, argument) in symbol.typeParameterSymbols.zip(expression.typeArguments)) {
if (argument is FirTypeProjectionWithVariance) {
put(parameter, argument.typeRef.coneType)
}
}
}
return ConeSubstitutorByMap(substitutionMap, session)
}
}
object FirThrowJavaNullabilityWarningChecker : FirThrowExpressionChecker() {
override fun check(expression: FirThrowExpression, context: CheckerContext, reporter: DiagnosticReporter) {
expression.exception.checkExpressionForEnhancedTypeMismatch(
expectedType = context.session.builtinTypes.throwableType.coneType,
reporter,
context,
FirJvmErrors.NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS
)
}
}
object FirAssignmentJavaNullabilityWarningChecker : FirVariableAssignmentChecker() {
override fun check(expression: FirVariableAssignment, context: CheckerContext, reporter: DiagnosticReporter) {
expression.rValue.checkExpressionForEnhancedTypeMismatch(
expectedType = expression.lValue.resolvedType,
reporter,
context,
FirJvmErrors.NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS,
)
}
}
object FirLogicExpressionTypeJavaNullabilityWarningChecker : FirLogicExpressionChecker() {
override fun check(expression: FirBinaryLogicExpression, context: CheckerContext, reporter: DiagnosticReporter) {
expression.leftOperand.checkConditionForEnhancedTypeMismatch(context, reporter)
expression.rightOperand.checkConditionForEnhancedTypeMismatch(context, reporter)
}
}
object FirLoopConditionJavaNullabilityWarningChecker : FirLoopExpressionChecker() {
override fun check(expression: FirLoop, context: CheckerContext, reporter: DiagnosticReporter) {
if (expression is FirErrorLoop) return
val condition = expression.condition
condition.checkConditionForEnhancedTypeMismatch(context, reporter)
}
}
object FirWhenConditionJavaNullabilityWarningChecker : FirWhenExpressionChecker() {
override fun check(expression: FirWhenExpression, context: CheckerContext, reporter: DiagnosticReporter) {
for (branch in expression.branches) {
val condition = branch.condition
if (condition is FirElseIfTrueCondition) continue
condition.checkConditionForEnhancedTypeMismatch(context, reporter)
}
}
}
private fun FirExpression.checkConditionForEnhancedTypeMismatch(context: CheckerContext, reporter: DiagnosticReporter) {
checkExpressionForEnhancedTypeMismatch(
context.session.builtinTypes.booleanType.type,
reporter,
context,
FirJvmErrors.NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS
)
}
internal fun FirExpression.checkExpressionForEnhancedTypeMismatch(
expectedType: ConeKotlinType?,
reporter: DiagnosticReporter,
context: CheckerContext,
factory: KtDiagnosticFactory2<ConeKotlinType, ConeKotlinType>,
) {
if (expectedType == null) return
val actualType = resolvedType
val (actualTypeForComparison, expectedTypeForComparison) = getEnhancedTypesForComparison(actualType, expectedType, context)
?: return
if (!actualTypeForComparison.isSubtypeOf(context.session.typeContext, expectedTypeForComparison)) {
reporter.reportOn(source, factory, actualTypeForComparison, expectedTypeForComparison, context)
}
}
private fun getEnhancedTypesForComparison(
actualType: ConeKotlinType?,
expectedType: ConeKotlinType?,
context: CheckerContext,
): Pair<ConeKotlinType, ConeKotlinType>? {
if (actualType == null || expectedType == null) return null
if (actualType is ConeErrorType || expectedType is ConeErrorType) return null
val substitutor = EnhancedForWarningConeSubstitutor(context.session.typeContext)
val enhancedActualType = substitutor.substituteOrNull(actualType)
val enhancedExpectedType = substitutor.substituteOrNull(expectedType)
// No enhancement on either side, nothing to check.
if (enhancedActualType == null && enhancedExpectedType == null) return null
val actualTypeForComparison = enhancedActualType ?: actualType
val expectedTypeForComparison = enhancedExpectedType ?: expectedType
val expectedTypeAsFunctionTypeIfSam = if (
actualTypeForComparison.isSomeFunctionType(context.session) &&
!expectedTypeForComparison.isSomeFunctionType(context.session)
) {
// TODO remove after KT-62847
val samResolver = FirSamResolver(context.session, context.scopeSession)
samResolver.getFunctionTypeForPossibleSamType(expectedTypeForComparison) ?: expectedTypeForComparison
} else {
expectedTypeForComparison
}
return actualTypeForComparison to expectedTypeAsFunctionTypeIfSam
}
@@ -5,10 +5,9 @@
package org.jetbrains.kotlin.fir.java.enhancement
import org.jetbrains.kotlin.fir.types.ConeAttributeWithConeType
import org.jetbrains.kotlin.fir.types.ConeAttributes
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.renderForDebugging
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
import org.jetbrains.kotlin.fir.resolve.substitution.AbstractConeSubstitutor
import org.jetbrains.kotlin.fir.types.*
import kotlin.reflect.KClass
class EnhancedTypeForWarningAttribute(
@@ -31,4 +30,37 @@ class EnhancedTypeForWarningAttribute(
val ConeAttributes.enhancedTypeForWarning: EnhancedTypeForWarningAttribute? by ConeAttributes.attributeAccessor<EnhancedTypeForWarningAttribute>()
val ConeKotlinType.enhancedTypeForWarning: ConeKotlinType?
get() = attributes.enhancedTypeForWarning?.coneType
get() = attributes.enhancedTypeForWarning?.coneType
/**
* Substitutor that substitutes types with their [ConeKotlinType.enhancedTypeForWarning] recursively.
*/
class EnhancedForWarningConeSubstitutor(typeContext: ConeTypeContext) : AbstractConeSubstitutor(typeContext) {
override fun substituteType(type: ConeKotlinType): ConeKotlinType? {
// The attribute is usually taken from the lower bound of flexible types.
// However, if the type has flexible mutability, we don't want to accidentally enhance the mutability to the lower bound.
if (type is ConeFlexibleType && type.hasFlexibleMutability()) {
val lowerSubstituted = substituteOrNull(type.lowerBound)
return if (lowerSubstituted is ConeSimpleKotlinType) {
ConeFlexibleType(
lowerBound = lowerSubstituted,
upperBound = substituteOrNull(type.upperBound) as? ConeSimpleKotlinType ?: type.upperBound
)
} else {
null
}
}
// If the top-level type can be enhanced, this will only enhance the top-level type but not its arguments: Foo<Bar!>! -> Foo<Bar!>?
// Otherwise, it will enhance recursively until the first possible enhancement.
val enhancedTopLevel = type.enhancedTypeForWarning
// This will also enhance type arguments if the top-level type was enhanced, otherwise it will continue enhancing recursively.
return enhancedTopLevel?.let(::substituteOrSelf)
}
private fun ConeFlexibleType.hasFlexibleMutability(): Boolean {
return JavaToKotlinClassMap.isMutable(lowerBound.classId) && JavaToKotlinClassMap.isReadOnly(upperBound.classId)
}
}
+6
View File
@@ -1 +1,7 @@
compiler/testData/cli/jvm/jspecifyUsage.kt:2:11: warning: Java type mismatch: inferred type is 'kotlin/String', but 'kotlin/Nothing?' was expected.
a.foo(null)
^
compiler/testData/cli/jvm/jspecifyUsage.kt:3:5: warning: only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type 'kotlin/String?'.
a.bar().hashCode()
^
OK
+3
View File
@@ -1,2 +1,5 @@
warning: argument -Xjsr305-annotations is deprecated. Please use -Xjsr305 instead
compiler/testData/cli/jvm/jsr305Usage.kt:2:11: warning: Java type mismatch: inferred type is 'kotlin/String', but 'kotlin/Nothing?' was expected.
a.foo(null)
^
OK
@@ -1 +1,7 @@
compiler/testData/cli/jvm/jsr305Migration.kt:2:19: warning: Java type mismatch: inferred type is 'kotlin/String', but 'kotlin/Nothing?' was expected.
annotated.foo(null)
^
compiler/testData/cli/jvm/jsr305Migration.kt:4:5: warning: only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type 'kotlin/String?'.
annotated.nullable().length
^
OK
+6
View File
@@ -1 +1,7 @@
compiler/testData/cli/jvm/jsr305Migration.kt:2:19: warning: Java type mismatch: inferred type is 'kotlin/String', but 'kotlin/Nothing?' was expected.
annotated.foo(null)
^
compiler/testData/cli/jvm/jsr305Migration.kt:4:5: warning: only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type 'kotlin/String?'.
annotated.nullable().length
^
OK
+9
View File
@@ -1 +1,10 @@
compiler/testData/cli/jvm/jsr305Migration.kt:2:19: warning: Java type mismatch: inferred type is 'kotlin/String', but 'kotlin/Nothing?' was expected.
annotated.foo(null)
^
compiler/testData/cli/jvm/jsr305Migration.kt:3:19: warning: Java type mismatch: inferred type is 'kotlin/String', but 'kotlin/Nothing?' was expected.
annotated.bar(null)
^
compiler/testData/cli/jvm/jsr305Migration.kt:4:5: warning: only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type 'kotlin/String?'.
annotated.nullable().length
^
OK
+3
View File
@@ -1 +1,4 @@
compiler/testData/cli/jvm/jsr305Usage.kt:2:11: warning: Java type mismatch: inferred type is 'kotlin/String', but 'kotlin/Nothing?' was expected.
a.foo(null)
^
OK
+3
View File
@@ -1 +1,4 @@
compiler/testData/cli/jvm/jsr305Usage.kt:2:11: warning: Java type mismatch: inferred type is 'kotlin/String', but 'kotlin/Nothing?' was expected.
a.foo(null)
^
OK
@@ -1,25 +0,0 @@
// JSPECIFY_STATE: warn
// ALLOW_KOTLIN_PACKAGE
// FILE: sandbox/module-info.java
import org.jspecify.annotations.NullMarked;
@NullMarked
module sandbox {
requires java9_annotations;
exports test;
}
// FILE: sandbox/test/Test.java
package test;
public class Test {
public void foo(Integer x) {}
}
// FILE: main.kt
import test.Test
fun main(x: Test) {
x.foo(null)
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// JSPECIFY_STATE: warn
// ALLOW_KOTLIN_PACKAGE
@@ -1,28 +0,0 @@
// JSPECIFY_STATE: warn
// ALLOW_KOTLIN_PACKAGE
// FILE: sandbox/test/module-info.java
import org.jspecify.annotations.NullMarked;
@NullMarked
module sandbox {
requires java9_annotations;
exports test;
}
// FILE: sandbox/test/Test.java
package test;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class Test {
public void foo(Integer x) {}
}
// FILE: main.kt
import test.Test
fun main(x: Test) {
x.foo(null)
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// JSPECIFY_STATE: warn
// ALLOW_KOTLIN_PACKAGE
@@ -1,31 +0,0 @@
// JSPECIFY_STATE: warn
// ALLOW_KOTLIN_PACKAGE
// FILE: sandbox/module-info.java
import org.jspecify.annotations.NullMarked;
@NullMarked
module sandbox {
requires java9_annotations;
exports test;
}
// FILE: sandbox/test/package-info.java
@NullMarked
package test;
import org.jspecify.annotations.NullMarked;
// FILE: sandbox/test/Test.java
package test;
public class Test {
public void foo(Integer x) {}
}
// FILE: main.kt
import test.Test
fun main(x: Test) {
x.foo(null)
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// JSPECIFY_STATE: warn
// ALLOW_KOTLIN_PACKAGE
@@ -1,30 +0,0 @@
// JSPECIFY_STATE: warn
// ALLOW_KOTLIN_PACKAGE
// MODULE: module1
// FILE: module1/module-info.java
module module1 {
}
// MODULE: module2(module1)
// FILE: module2/module-info.java
import org.jspecify.annotations.NullMarked;
@NullMarked
module module2 {
requires java9_annotations;
requires module1;
exports test2;
}
// FILE: module2/test2/Test.java
package test2;
public class Test {
public void foo(Integer x) {}
}
// FILE: main.kt
fun main(y: test2.Test) {
y.foo(null)
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// JSPECIFY_STATE: warn
// ALLOW_KOTLIN_PACKAGE
@@ -1,25 +0,0 @@
// JSPECIFY_STATE: warn
// ALLOW_KOTLIN_PACKAGE
// FILE: my.sand.box/module-info.java
import org.jspecify.annotations.NullMarked;
@NullMarked
open module my.sand.box {
requires java9_annotations;
exports my.test;
}
// FILE: my.sand.box/my/test/Test.java
package my.test;
public class Test {
public void foo(Integer x) {}
}
// FILE: main.kt
import my.test.Test
fun main(x: Test) {
x.foo(null)
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// JSPECIFY_STATE: warn
// ALLOW_KOTLIN_PACKAGE
@@ -1,45 +0,0 @@
// JSPECIFY_STATE: warn
// ALLOW_KOTLIN_PACKAGE
// MODULE: module1
// FILE: module1/module-info.java
import org.jspecify.annotations.NullMarked;
@NullMarked
module module1 {
requires java9_annotations;
exports test1;
}
// FILE: module1/test1/Test1.java
package test1;
public class Test1 {
public void foo(Integer x) {}
}
// MODULE: module2(module1)
// FILE: module2/module-info.java
module module2 {
requires module1;
exports test2;
}
// FILE: module2/test2/Test2.java
package test2;
import test1.Test1;
public class Test2 extends Test1 {
public void foo2(Integer x) {}
}
// FILE: main.kt
import test1.Test1
import test2.Test2
fun main(x: Test1, y: Test2) {
x.foo(null)
y.foo(null)
y.foo2(null)
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// JSPECIFY_STATE: warn
// ALLOW_KOTLIN_PACKAGE
@@ -35,9 +35,9 @@ public class Test {
import test.Test
fun main(x: Test) {
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int..kotlin.Int?!")!>x.Test3().foo(null)<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int..kotlin.Int?!")!>x.Test3().Test5().foo(null)<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int..kotlin.Int?!")!>x.Test3().foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int..kotlin.Int?!")!>x.Test3().Test5().foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int..kotlin.Int?!")!>Test.Test2().foo(null)<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int..kotlin.Int?!")!>Test.Test2().Test5().foo(null)<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int..kotlin.Int?!")!>Test.Test2().foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int..kotlin.Int?!")!>Test.Test2().Test5().foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)<!>
}
@@ -1,39 +0,0 @@
// JSPECIFY_STATE: warn
// ALLOW_KOTLIN_PACKAGE
// MODULE: module1
// FILE: module1/module-info.java
import org.jspecify.annotations.NullMarked;
@NullMarked
module module1 {
requires java9_annotations;
exports test1;
}
// FILE: module1/test1/Test.java
package test1;
public class Test {
public void foo(Integer x) {}
}
// MODULE: module2(module1)
// FILE: module2/module-info.java
module module2 {
requires module1;
exports test2;
}
// FILE: module2/test2/Test.java
package test2;
public class Test {
public void foo(Integer x) {}
}
// FILE: main.kt
fun main(x: test1.Test, y: test2.Test) {
x.foo(null)
y.foo(null)
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// JSPECIFY_STATE: warn
// ALLOW_KOTLIN_PACKAGE
@@ -1,25 +0,0 @@
// JSPECIFY_STATE: warn
// ALLOW_KOTLIN_PACKAGE
// FILE: sandbox/module-info.java
import org.jspecify.nullness.NullMarked;
@NullMarked
module sandbox {
requires java9_annotations;
exports test;
}
// FILE: sandbox/test/Test.java
package test;
public class Test {
public void foo(Integer x) {}
}
// FILE: main.kt
import test.Test
fun main(x: Test) {
x.foo(null)
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// JSPECIFY_STATE: warn
// ALLOW_KOTLIN_PACKAGE
@@ -1,28 +0,0 @@
// JSPECIFY_STATE: warn
// ALLOW_KOTLIN_PACKAGE
// FILE: sandbox/test/module-info.java
import org.jspecify.nullness.NullMarked;
@NullMarked
module sandbox {
requires java9_annotations;
exports test;
}
// FILE: sandbox/test/Test.java
package test;
import org.jspecify.nullness.NullMarked;
@NullMarked
public class Test {
public void foo(Integer x) {}
}
// FILE: main.kt
import test.Test
fun main(x: Test) {
x.foo(null)
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// JSPECIFY_STATE: warn
// ALLOW_KOTLIN_PACKAGE
@@ -1,31 +0,0 @@
// JSPECIFY_STATE: warn
// ALLOW_KOTLIN_PACKAGE
// FILE: sandbox/module-info.java
import org.jspecify.nullness.NullMarked;
@NullMarked
module sandbox {
requires java9_annotations;
exports test;
}
// FILE: sandbox/test/package-info.java
@NullMarked
package test;
import org.jspecify.nullness.NullMarked;
// FILE: sandbox/test/Test.java
package test;
public class Test {
public void foo(Integer x) {}
}
// FILE: main.kt
import test.Test
fun main(x: Test) {
x.foo(null)
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// JSPECIFY_STATE: warn
// ALLOW_KOTLIN_PACKAGE
@@ -1,30 +0,0 @@
// JSPECIFY_STATE: warn
// ALLOW_KOTLIN_PACKAGE
// MODULE: module1
// FILE: module1/module-info.java
module module1 {
}
// MODULE: module2(module1)
// FILE: module2/module-info.java
import org.jspecify.nullness.NullMarked;
@NullMarked
module module2 {
requires java9_annotations;
requires module1;
exports test2;
}
// FILE: module2/test2/Test.java
package test2;
public class Test {
public void foo(Integer x) {}
}
// FILE: main.kt
fun main(y: test2.Test) {
y.foo(null)
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// JSPECIFY_STATE: warn
// ALLOW_KOTLIN_PACKAGE
@@ -1,25 +0,0 @@
// JSPECIFY_STATE: warn
// ALLOW_KOTLIN_PACKAGE
// FILE: my.sand.box/module-info.java
import org.jspecify.nullness.NullMarked;
@NullMarked
open module my.sand.box {
requires java9_annotations;
exports my.test;
}
// FILE: my.sand.box/my/test/Test.java
package my.test;
public class Test {
public void foo(Integer x) {}
}
// FILE: main.kt
import my.test.Test
fun main(x: Test) {
x.foo(null)
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// JSPECIFY_STATE: warn
// ALLOW_KOTLIN_PACKAGE
@@ -1,45 +0,0 @@
// JSPECIFY_STATE: warn
// ALLOW_KOTLIN_PACKAGE
// MODULE: module1
// FILE: module1/module-info.java
import org.jspecify.nullness.NullMarked;
@NullMarked
module module1 {
requires java9_annotations;
exports test1;
}
// FILE: module1/test1/Test1.java
package test1;
public class Test1 {
public void foo(Integer x) {}
}
// MODULE: module2(module1)
// FILE: module2/module-info.java
module module2 {
requires module1;
exports test2;
}
// FILE: module2/test2/Test2.java
package test2;
import test1.Test1;
public class Test2 extends Test1 {
public void foo2(Integer x) {}
}
// FILE: main.kt
import test1.Test1
import test2.Test2
fun main(x: Test1, y: Test2) {
x.foo(null)
y.foo(null)
y.foo2(null)
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// JSPECIFY_STATE: warn
// ALLOW_KOTLIN_PACKAGE
@@ -35,9 +35,9 @@ public class Test {
import test.Test
fun main(x: Test) {
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int..kotlin.Int?!")!>x.Test3().foo(null)<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int..kotlin.Int?!")!>x.Test3().Test5().foo(null)<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int..kotlin.Int?!")!>x.Test3().foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int..kotlin.Int?!")!>x.Test3().Test5().foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int..kotlin.Int?!")!>Test.Test2().foo(null)<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int..kotlin.Int?!")!>Test.Test2().Test5().foo(null)<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int..kotlin.Int?!")!>Test.Test2().foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int..kotlin.Int?!")!>Test.Test2().Test5().foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)<!>
}
@@ -1,39 +0,0 @@
// JSPECIFY_STATE: warn
// ALLOW_KOTLIN_PACKAGE
// MODULE: module1
// FILE: module1/module-info.java
import org.jspecify.nullness.NullMarked;
@NullMarked
module module1 {
requires java9_annotations;
exports test1;
}
// FILE: module1/test1/Test.java
package test1;
public class Test {
public void foo(Integer x) {}
}
// MODULE: module2(module1)
// FILE: module2/module-info.java
module module2 {
requires module1;
exports test2;
}
// FILE: module2/test2/Test.java
package test2;
public class Test {
public void foo(Integer x) {}
}
// FILE: main.kt
fun main(x: test1.Test, y: test2.Test) {
x.foo(null)
y.foo(null)
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// JSPECIFY_STATE: warn
// ALLOW_KOTLIN_PACKAGE
@@ -13,17 +13,21 @@ public class Test {}
// FILE: main.kt
fun main(a1: NullnessUnspecifiedTypeParameter<Any>, a2: NullnessUnspecifiedTypeParameter<Any?>, x: Test): Unit {
a1.foo(null)
// jspecify_nullness_mismatch
a1.foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)
a1.foo(1)
a2.foo(null)
a2.foo(1)
a1.bar(null, null)
a1.bar(x, null)
// jspecify_nullness_mismatch, jspecify_nullness_mismatch
a1.bar(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>, <!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)
// jspecify_nullness_mismatch
a1.bar(x, <!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)
a1.bar(x, 1)
a2.bar(null, null)
// jspecify_nullness_mismatch
a2.bar(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>, null)
a2.bar(x, null)
a2.bar(x, 1)
}
}
@@ -1,80 +0,0 @@
// JSPECIFY_STATE: warn
// MUTE_FOR_PSI_CLASS_FILES_READING
// FILE: AnnotatedBoundsOfWildcard.java
import org.jspecify.annotations.*;
@NullMarked
public class AnnotatedBoundsOfWildcard {
public void superAsIs(Test<? super Base, ? super @Nullable Base, ? super @NullnessUnspecified Base> a) {}
public void superNotNull(Test<? super Base, ? super Base, ? super Base> a) {}
public void superNullable(Test<? super @Nullable Base, ? super @Nullable Base, ? super @Nullable Base> a) {}
public void extendsAsIs(Test<? extends Base, ? extends @Nullable Base, ? extends @NullnessUnspecified Base> a) {}
public void extendsNotNull(Test<? extends Base, ? extends Base, ? extends Base> a) {}
public void extendsNullable(Test<? extends @Nullable Base, ? extends @Nullable Base, ? extends @Nullable Base> a) {}
public void noBounds(Test<? extends @NullnessUnspecified Object, ? extends @NullnessUnspecified Object, ? extends @NullnessUnspecified Object> a) {}
}
// FILE: Base.java
public class Base {}
// FILE: Derived.java
public class Derived extends Base {}
// FILE: Test.java
import org.jspecify.annotations.*;
@NullMarked
public class Test<T extends Object, E extends @Nullable Object, F extends @NullnessUnspecified Object> { }
// FILE: main.kt
fun main(
aNotNullNotNullNotNull: Test<Derived, Derived, Derived>,
aNotNullNotNullNull: Test<Derived, Derived, Derived?>,
aNotNullNullNotNull: Test<Derived, Derived?, Derived>,
aNotNullNullNull: Test<Derived, Derived?, Derived?>,
aAnyNotNullNotNullNotNull: Test<Any, Any, Any>,
aAnyNotNullNotNullNull: Test<Any, Any, Any?>,
aAnyNotNullNullNotNull: Test<Any, Any?, Any>,
aAnyNotNullNullNull: Test<Any, Any?, Any?>,
b: AnnotatedBoundsOfWildcard
): Unit {
b.superAsIs(aAnyNotNullNotNullNotNull)
b.superAsIs(aAnyNotNullNotNullNull)
b.superAsIs(aAnyNotNullNullNotNull)
b.superAsIs(aAnyNotNullNullNull)
b.superNotNull(aAnyNotNullNotNullNotNull)
b.superNotNull(aAnyNotNullNotNullNull)
b.superNotNull(aAnyNotNullNullNotNull)
b.superNotNull(aAnyNotNullNullNull)
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)
b.extendsNotNull(aNotNullNotNullNull)
b.extendsNotNull(aNotNullNullNotNull)
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)
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// JSPECIFY_STATE: warn
// MUTE_FOR_PSI_CLASS_FILES_READING
@@ -1,45 +0,0 @@
// JSPECIFY_STATE: warn
// FILE: Defaults.java
import org.jspecify.annotations.*;
@NullMarked
public class Defaults {
public Foo defaultField = null;
@Nullable public Foo field = null;
public Foo everythingNotNullable(Foo x) { return null; }
public @Nullable Foo everythingNullable(@Nullable Foo x) { return null; }
public @NullnessUnspecified Foo everythingUnknown(@NullnessUnspecified Foo x) { return null; }
public @Nullable Foo mixed(Foo x) { return null; }
public Foo explicitlyNullnessUnspecified(@NullnessUnspecified Foo x) { return null; }
}
// FILE: Foo.java
public class Foo {
public Object foo() { return null; }
}
// FILE: main.kt
fun main(a: Defaults, x: Foo): Unit {
a.everythingNotNullable(null).foo()
a.everythingNotNullable(x).foo()
a.everythingNullable(null).foo()
a.everythingUnknown(null).foo()
a.mixed(null).foo()
a.mixed(x).foo()
a.explicitlyNullnessUnspecified(x).foo()
a.explicitlyNullnessUnspecified(null).foo()
a.defaultField.foo()
a.field.foo()
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// JSPECIFY_STATE: warn
// FILE: Defaults.java
@@ -1,43 +0,0 @@
// JSPECIFY_STATE: warn
// FILE: IgnoreAnnotations.java
import org.jspecify.annotations.*;
@NullMarked
public class IgnoreAnnotations {
@Nullable public Derived field = null;
@Nullable
public Derived foo(Derived x, @NullnessUnspecified Base y) {
return null;
}
public Derived everythingNotNullable(Derived x) { return null; }
public @Nullable Derived everythingNullable(@Nullable Derived x) { return null; }
public @NullnessUnspecified Derived everythingUnknown(@NullnessUnspecified Derived x) { return null; }
}
// FILE: Base.java
public class Base {
void foo() {}
}
// FILE: Derived.java
public class Derived extends Base { }
// FILE: main.kt
fun main(a: IgnoreAnnotations, x: Derived): Unit {
a.foo(x, null).foo()
a.foo(null, x).foo()
a.field.foo()
a.everythingNotNullable(null).foo()
a.everythingNotNullable(x).foo()
a.everythingNullable(null).foo()
a.everythingUnknown(null).foo()
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// JSPECIFY_STATE: warn
// FILE: IgnoreAnnotations.java
@@ -14,17 +14,21 @@ public class Test {}
// FILE: main.kt
fun main(a1: NullnessUnspecifiedTypeParameter<Any>, a2: NullnessUnspecifiedTypeParameter<Any?>, x: Test): Unit {
a1.foo(null)
// jspecify_nullness_mismatch
a1.foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)
a1.foo(1)
a2.foo(null)
a2.foo(1)
a1.bar(null, null)
a1.bar(x, null)
// jspecify_nullness_mismatch, jspecify_nullness_mismatch
a1.bar(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>, <!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)
// jspecify_nullness_mismatch
a1.bar(x, <!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)
a1.bar(x, 1)
a2.bar(null, null)
// jspecify_nullness_mismatch
a2.bar(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>, null)
a2.bar(x, null)
a2.bar(x, 1)
}
@@ -1,36 +0,0 @@
// JSPECIFY_STATE: warn
// FILE: Simple.java
import org.jspecify.annotations.*;
@NullMarked
public class Simple {
@Nullable public Derived field = null;
@Nullable
public Derived foo(Derived x, @NullnessUnspecified Base y) {
return null;
}
public Derived bar() {
return null;
}
}
// FILE: Base.java
public class Base {}
// FILE: Derived.java
public class Derived extends Base {
void foo() {}
}
// FILE: main.kt
fun main(a: Simple, x: Derived): Unit {
a.foo(x, null).foo()
a.foo(null, x).foo()
a.bar().foo()
a.field.foo()
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// JSPECIFY_STATE: warn
// FILE: Simple.java
@@ -1,45 +0,0 @@
// JSPECIFY_STATE: warn
// MUTE_FOR_PSI_CLASS_FILES_READING
// FILE: TypeArgumentsFromParameterBounds.java
import org.jspecify.annotations.*;
@NullMarked
public class TypeArgumentsFromParameterBounds<T extends Object, E extends @Nullable Object, F extends @NullnessUnspecified Object> {}
// FILE: A.java
import org.jspecify.annotations.*;
@NullMarked
public class A {
public void bar(TypeArgumentsFromParameterBounds<Test, Test, Test> a) {}
}
// FILE: B.java
import org.jspecify.annotations.*;
public class B {
public void bar(TypeArgumentsFromParameterBounds<Test, Test, Test> a) {}
}
// FILE: Test.java
public class Test {}
// FILE: main.kt
fun main(
aNotNullNotNullNotNull: TypeArgumentsFromParameterBounds<Test, Test, Test>,
aNotNullNotNullNull: TypeArgumentsFromParameterBounds<Test, Test, Test?>,
aNotNullNullNotNull: TypeArgumentsFromParameterBounds<Test, Test?, Test>,
aNotNullNullNull: TypeArgumentsFromParameterBounds<Test, Test?, Test?>,
a: A, b: B
): Unit {
a.bar(aNotNullNotNullNotNull)
a.bar(aNotNullNotNullNull)
a.bar(aNotNullNullNotNull)
a.bar(aNotNullNullNull)
b.bar(aNotNullNotNullNotNull)
b.bar(aNotNullNotNullNull)
b.bar(aNotNullNullNotNull)
b.bar(aNotNullNullNull)
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// JSPECIFY_STATE: warn
// MUTE_FOR_PSI_CLASS_FILES_READING
@@ -33,7 +33,8 @@ fun <T : Test> main(a1: A<Any?>, a2: A<Test>, b1: B<Any?>, b2: B<Test>, x: T): U
b1.bar<T?>(null)
b1.bar<T>(x)
b2.foo(null)
// jspecify_nullness_mismatch
b2.foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)
b2.bar<T?>(null)
b2.bar<T>(x)
}
@@ -0,0 +1,17 @@
// JSPECIFY_STATE: warn
// FILE: J1.java
import org.jspecify.annotations.*;
@NullMarked
public interface J1<T extends @Nullable Object> {
T foo();
}
// FILE: J2.java
public interface J2 {
J1<?> bar();
}
// FILE: main.kt
// jspecify_nullness_mismatch
fun baz(j2: J2): Any = <!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>j2.bar().foo()<!> // Any..Any?
@@ -1,4 +1,3 @@
// FIR_IDENTICAL
// JSPECIFY_STATE: warn
// FILE: J1.java
import org.jspecify.annotations.*;
@@ -1,15 +0,0 @@
// JSPECIFY_STATE: warn
// FILE: Foo.java
import org.jspecify.annotations.Nullable;
public class Foo {
public static <T> void gauge(@Nullable T stateObject) {}
}
// FILE: main.kt
fun <T> test(metric: T) {
if (metric is String) {
Foo.gauge(metric)
}
}
@@ -1,3 +1,5 @@
// FIR_IDENTICAL
// DIAGNOSTICS: -DEBUG_INFO_SMARTCAST
// JSPECIFY_STATE: warn
// FILE: Foo.java
@@ -10,6 +12,6 @@ public class Foo {
// FILE: main.kt
fun <T> test(metric: T) {
if (metric is String) {
Foo.gauge(<!DEBUG_INFO_SMARTCAST!>metric<!>)
Foo.gauge(metric)
}
}
@@ -15,7 +15,7 @@ public class Test {}
// jspecify_nullness_mismatch
fun main(a1: NullnessUnspecifiedTypeParameter<Any>, a2: NullnessUnspecifiedTypeParameter<Any?>, x: Test): Unit {
// jspecify_nullness_mismatch
a1.foo(null)
a1.foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)
a1.foo(1)
// jspecify_nullness_mismatch
@@ -23,14 +23,14 @@ fun main(a1: NullnessUnspecifiedTypeParameter<Any>, a2: NullnessUnspecifiedTypeP
a2.foo(1)
// jspecify_nullness_mismatch, jspecify_nullness_mismatch
a1.bar(null, null)
a1.bar(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>, <!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)
// jspecify_nullness_mismatch
a1.bar(x, null)
a1.bar(x, <!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)
a1.bar(x, 1)
// jspecify_nullness_mismatch, jspecify_nullness_mismatch
a2.bar(null, null)
a2.bar(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>, null)
// jspecify_nullness_mismatch
a2.bar(x, null)
a2.bar(x, 1)
}
}
@@ -1,89 +0,0 @@
// JSPECIFY_STATE: warn
// MUTE_FOR_PSI_CLASS_FILES_READING
// FILE: AnnotatedBoundsOfWildcard.java
import org.jspecify.nullness.*;
@NullMarked
public class AnnotatedBoundsOfWildcard {
public void superAsIs(Test<? super Base, ? super @Nullable Base, ? super @NullnessUnspecified Base> a) {}
public void superNotNull(Test<? super Base, ? super Base, ? super Base> a) {}
public void superNullable(Test<? super @Nullable Base, ? super @Nullable Base, ? super @Nullable Base> a) {}
public void extendsAsIs(Test<? extends Base, ? extends @Nullable Base, ? extends @NullnessUnspecified Base> a) {}
public void extendsNotNull(Test<? extends Base, ? extends Base, ? extends Base> a) {}
public void extendsNullable(Test<? extends @Nullable Base, ? extends @Nullable Base, ? extends @Nullable Base> a) {}
public void noBounds(Test<? extends @NullnessUnspecified Object, ? extends @NullnessUnspecified Object, ? extends @NullnessUnspecified Object> a) {}
}
// FILE: Base.java
public class Base {}
// FILE: Derived.java
public class Derived extends Base {}
// FILE: Test.java
import org.jspecify.nullness.*;
@NullMarked
public class Test<T extends Object, E extends @Nullable Object, F extends @NullnessUnspecified Object> { }
// FILE: main.kt
fun main(
aNotNullNotNullNotNull: Test<Derived, Derived, Derived>,
aNotNullNotNullNull: Test<Derived, Derived, Derived?>,
aNotNullNullNotNull: Test<Derived, Derived?, Derived>,
aNotNullNullNull: Test<Derived, Derived?, Derived?>,
aAnyNotNullNotNullNotNull: Test<Any, Any, Any>,
aAnyNotNullNotNullNull: Test<Any, Any, Any?>,
aAnyNotNullNullNotNull: Test<Any, Any?, Any>,
aAnyNotNullNullNull: Test<Any, Any?, Any?>,
b: AnnotatedBoundsOfWildcard
): Unit {
// jspecify_nullness_mismatch
b.superAsIs(aAnyNotNullNotNullNotNull)
// jspecify_nullness_mismatch
b.superAsIs(aAnyNotNullNotNullNull)
b.superAsIs(aAnyNotNullNullNotNull)
b.superAsIs(aAnyNotNullNullNull)
b.superNotNull(aAnyNotNullNotNullNotNull)
b.superNotNull(aAnyNotNullNotNullNull)
b.superNotNull(aAnyNotNullNullNotNull)
b.superNotNull(aAnyNotNullNullNull)
// jspecify_nullness_mismatch
b.superNullable(aAnyNotNullNotNullNotNull)
// jspecify_nullness_mismatch
b.superNullable(aAnyNotNullNotNullNull)
// jspecify_nullness_mismatch
b.superNullable(aAnyNotNullNullNotNull)
// jspecify_nullness_mismatch
b.superNullable(aAnyNotNullNullNull)
b.extendsAsIs(aNotNullNotNullNotNull)
b.extendsAsIs(aNotNullNotNullNull)
b.extendsAsIs(aNotNullNullNotNull)
b.extendsAsIs(aNotNullNullNull)
b.extendsNotNull(aNotNullNotNullNotNull)
// jspecify_nullness_mismatch
b.extendsNotNull(aNotNullNotNullNull)
// jspecify_nullness_mismatch
b.extendsNotNull(aNotNullNullNotNull)
// jspecify_nullness_mismatch
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)
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// JSPECIFY_STATE: warn
// MUTE_FOR_PSI_CLASS_FILES_READING
@@ -1,50 +0,0 @@
// JSPECIFY_STATE: warn
// FILE: Defaults.java
import org.jspecify.nullness.*;
@NullMarked
public class Defaults {
public Foo defaultField = null;
@Nullable public Foo field = null;
public Foo everythingNotNullable(Foo x) { return null; }
public @Nullable Foo everythingNullable(@Nullable Foo x) { return null; }
public @NullnessUnspecified Foo everythingUnknown(@NullnessUnspecified Foo x) { return null; }
public @Nullable Foo mixed(Foo x) { return null; }
public Foo explicitlyNullnessUnspecified(@NullnessUnspecified Foo x) { return null; }
}
// FILE: Foo.java
public class Foo {
public Object foo() { return null; }
}
// FILE: main.kt
fun main(a: Defaults, x: Foo): Unit {
// jspecify_nullness_mismatch
a.everythingNotNullable(null).foo()
a.everythingNotNullable(x).foo()
// jspecify_nullness_mismatch
a.everythingNullable(null).foo()
a.everythingUnknown(null).foo()
// jspecify_nullness_mismatch, jspecify_nullness_mismatch
a.mixed(null).foo()
// jspecify_nullness_mismatch
a.mixed(x).foo()
a.explicitlyNullnessUnspecified(x).foo()
a.explicitlyNullnessUnspecified(null).foo()
a.defaultField.foo()
// jspecify_nullness_mismatch
a.field.foo()
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// JSPECIFY_STATE: warn
// FILE: Defaults.java
@@ -1,48 +0,0 @@
// JSPECIFY_STATE: warn
// FILE: IgnoreAnnotations.java
import org.jspecify.nullness.*;
@NullMarked
public class IgnoreAnnotations {
@Nullable public Derived field = null;
@Nullable
public Derived foo(Derived x, @NullnessUnspecified Base y) {
return null;
}
public Derived everythingNotNullable(Derived x) { return null; }
public @Nullable Derived everythingNullable(@Nullable Derived x) { return null; }
public @NullnessUnspecified Derived everythingUnknown(@NullnessUnspecified Derived x) { return null; }
}
// FILE: Base.java
public class Base {
void foo() {}
}
// FILE: Derived.java
public class Derived extends Base { }
// FILE: main.kt
fun main(a: IgnoreAnnotations, x: Derived): Unit {
// jspecify_nullness_mismatch
a.foo(x, null).foo()
// jspecify_nullness_mismatch, jspecify_nullness_mismatch
a.foo(null, x).foo()
// jspecify_nullness_mismatch
a.field.foo()
// jspecify_nullness_mismatch
a.everythingNotNullable(null).foo()
a.everythingNotNullable(x).foo()
// jspecify_nullness_mismatch
a.everythingNullable(null).foo()
a.everythingUnknown(null).foo()
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// JSPECIFY_STATE: warn
// FILE: IgnoreAnnotations.java
@@ -16,7 +16,7 @@ public class Test {}
// jspecify_nullness_mismatch
fun main(a1: NullnessUnspecifiedTypeParameter<Any>, a2: NullnessUnspecifiedTypeParameter<Any?>, x: Test): Unit {
// jspecify_nullness_mismatch
a1.foo(null)
a1.foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)
a1.foo(1)
// jspecify_nullness_mismatch
@@ -24,13 +24,13 @@ fun main(a1: NullnessUnspecifiedTypeParameter<Any>, a2: NullnessUnspecifiedTypeP
a2.foo(1)
// jspecify_nullness_mismatch, jspecify_nullness_mismatch
a1.bar(null, null)
a1.bar(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>, <!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)
// jspecify_nullness_mismatch
a1.bar(x, null)
a1.bar(x, <!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)
a1.bar(x, 1)
// jspecify_nullness_mismatch, jspecify_nullness_mismatch
a2.bar(null, null)
a2.bar(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>, null)
// jspecify_nullness_mismatch
a2.bar(x, null)
a2.bar(x, 1)
@@ -1,39 +0,0 @@
// JSPECIFY_STATE: warn
// FILE: Simple.java
import org.jspecify.nullness.*;
@NullMarked
public class Simple {
@Nullable public Derived field = null;
@Nullable
public Derived foo(Derived x, @NullnessUnspecified Base y) {
return null;
}
public Derived bar() {
return null;
}
}
// FILE: Base.java
public class Base {}
// FILE: Derived.java
public class Derived extends Base {
void foo() {}
}
// FILE: main.kt
fun main(a: Simple, x: Derived): Unit {
// jspecify_nullness_mismatch
a.foo(x, null).foo()
// jspecify_nullness_mismatch, jspecify_nullness_mismatch
a.foo(null, x).foo()
a.bar().foo()
// jspecify_nullness_mismatch
a.field.foo()
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// JSPECIFY_STATE: warn
// FILE: Simple.java
@@ -1,48 +0,0 @@
// JSPECIFY_STATE: warn
// MUTE_FOR_PSI_CLASS_FILES_READING
// FILE: TypeArgumentsFromParameterBounds.java
import org.jspecify.nullness.*;
@NullMarked
public class TypeArgumentsFromParameterBounds<T extends Object, E extends @Nullable Object, F extends @NullnessUnspecified Object> {}
// FILE: A.java
import org.jspecify.nullness.*;
@NullMarked
public class A {
public void bar(TypeArgumentsFromParameterBounds<Test, Test, Test> a) {}
}
// FILE: B.java
import org.jspecify.nullness.*;
public class B {
public void bar(TypeArgumentsFromParameterBounds<Test, Test, Test> a) {}
}
// FILE: Test.java
public class Test {}
// FILE: main.kt
fun main(
aNotNullNotNullNotNull: TypeArgumentsFromParameterBounds<Test, Test, Test>,
aNotNullNotNullNull: TypeArgumentsFromParameterBounds<Test, Test, Test?>,
aNotNullNullNotNull: TypeArgumentsFromParameterBounds<Test, Test?, Test>,
aNotNullNullNull: TypeArgumentsFromParameterBounds<Test, Test?, Test?>,
a: A, b: B
): Unit {
a.bar(aNotNullNotNullNotNull)
// jspecify_nullness_mismatch
a.bar(aNotNullNotNullNull)
// jspecify_nullness_mismatch
a.bar(aNotNullNullNotNull)
// jspecify_nullness_mismatch
a.bar(aNotNullNullNull)
b.bar(aNotNullNotNullNotNull)
b.bar(aNotNullNotNullNull)
b.bar(aNotNullNullNotNull)
b.bar(aNotNullNullNull)
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// JSPECIFY_STATE: warn
// MUTE_FOR_PSI_CLASS_FILES_READING
@@ -39,7 +39,7 @@ fun <T : Test> main(a1: A<Any?>, a2: A<Test>, b1: B<Any?>, b2: B<Test>, x: T): U
b1.bar<T>(x)
// jspecify_nullness_mismatch
b2.foo(null)
b2.foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)
// jspecify_nullness_mismatch
b2.bar<T?>(null)
b2.bar<T>(x)
@@ -0,0 +1,16 @@
// JSPECIFY_STATE: warn
// FILE: J1.java
import org.jspecify.nullness.*;
@NullMarked
public interface J1<T extends @Nullable Object> {
T foo();
}
// FILE: J2.java
public interface J2 {
J1<?> bar();
}
// FILE: main.kt
fun baz(j2: J2): Any = <!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>j2.bar().foo()<!> // Any..Any?
@@ -1,4 +1,3 @@
// FIR_IDENTICAL
// JSPECIFY_STATE: warn
// FILE: J1.java
import org.jspecify.nullness.*;
@@ -26,21 +26,21 @@ public class A<T> {
// FILE: main.kt
fun main(a: A<String>, a1: A<String?>) {
a.foo("", null)?.length
a.foo("", null).length
a.foo(null, "").length
<!RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>a.foo("", null)<!>.length
<!RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>a.foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>, "")<!>.length
a.bar().length
a.bar()!!.length
a.field?.length
a.field.length
<!RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>a.field<!>.length
a.baz("").length
<!RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>a.baz("")<!>.length
a.baz("")?.length
a.baz(null).length
<!RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>a.baz(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)<!>.length
a1.baz("")!!.length
a1.baz(null)!!.length
a1.baz(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)!!.length
a.baz2("").length
a.baz2("")?.length
@@ -18,7 +18,7 @@ public class ClassWithExternalAnnotatedMembers {
// FILE: usage.kt
fun test() {
val i: Int? = null
ClassWithExternalAnnotatedMembers(i)
ClassWithExternalAnnotatedMembers(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>i<!>)
val s: String? = null
<!NONE_APPLICABLE!>ClassWithExternalAnnotatedMembers<!>(s)
@@ -14,7 +14,7 @@ public class ClassWithExternalAnnotatedMembers {
// FILE: usage.kt
fun test() {
val i: Int? = null
ClassWithExternalAnnotatedMembers(i)
ClassWithExternalAnnotatedMembers(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>i<!>)
val s: String? = null
<!NONE_APPLICABLE!>ClassWithExternalAnnotatedMembers<!>(s)
@@ -22,7 +22,7 @@ fun test() {
val b: Boolean? = null
<!NONE_APPLICABLE!>ClassWithExternalAnnotatedMembers<!>(b)
ClassWithExternalAnnotatedMembers(null)
ClassWithExternalAnnotatedMembers(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)
}
// FILE: annotations.xml
@@ -16,12 +16,12 @@ fun test() {
instance.<!NONE_APPLICABLE!>method<!>(i)
val s: String? = null
instance.method(s)
instance.method(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>s<!>)
val b: Boolean? = null
instance.<!NONE_APPLICABLE!>method<!>(b)
instance.method(null)
instance.method(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)
}
// FILE: annotations.xml
@@ -19,7 +19,7 @@ fun test() {
instance.<!NONE_APPLICABLE!>method<!>(i)
val s: String? = null
instance.method(s)
instance.method(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>s<!>)
val b: Boolean? = null
instance.method(b)
@@ -0,0 +1,15 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// JSR305_GLOBAL_REPORT: warn
// FILE: A.java
public class A {
public static @MyNullable String bar() {
return null;
}
}
// FILE: main.kt
fun foo1(): String = <!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>A.bar()<!>
fun foo2(): String? = A.bar()
fun foo3() = A.bar()
@@ -10,40 +10,40 @@ public class J {
}
// FILE: k.kt
fun test() {
var platformNN = J.staticNN
var platformN = J.staticN
var platformJ = J.staticJ
var platformNN = J.staticNN
var platformN = J.staticN
var platformJ = J.staticJ
fun test() {
+platformNN
+platformN
+<!RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>platformN<!>
+platformJ
++platformNN
++platformN
++<!RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>platformN<!>
++platformJ
platformNN++
platformN++
<!RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>platformN++<!>
platformJ++
1 + platformNN
1 + platformN
1 + <!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>platformN<!>
1 + platformJ
platformNN + 1
platformN + 1
<!RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>platformN<!> + 1
platformJ + 1
1 <!INFIX_MODIFIER_REQUIRED!>plus<!> platformNN
1 <!INFIX_MODIFIER_REQUIRED!>plus<!> platformN
1 <!INFIX_MODIFIER_REQUIRED!>plus<!> <!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>platformN<!>
1 <!INFIX_MODIFIER_REQUIRED!>plus<!> platformJ
platformNN <!INFIX_MODIFIER_REQUIRED!>plus<!> 1
platformN <!INFIX_MODIFIER_REQUIRED!>plus<!> 1
<!RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>platformN<!> <!INFIX_MODIFIER_REQUIRED!>plus<!> 1
platformJ <!INFIX_MODIFIER_REQUIRED!>plus<!> 1
platformNN += 1
platformN += 1
<!RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>platformN<!> += 1
platformJ += 1
}
@@ -10,11 +10,11 @@ public class J {
}
// FILE: k.kt
fun test() {
var platformNN = J.staticNN
var platformN = J.staticN
var platformJ = J.staticJ
var platformNN = J.staticNN
var platformN = J.staticN
var platformJ = J.staticJ
fun test() {
+platformNN
+<!RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>platformN<!>
+platformJ
@@ -1,5 +1,8 @@
package
public var platformJ: kotlin.Int!
public var platformN: kotlin.Int!
public var platformNN: kotlin.Int!
public fun test(): kotlin.Unit
public open class J {
@@ -1,25 +0,0 @@
// JSR305_GLOBAL_REPORT: warn
// FILE: J.java
public class J {
@MyNonnull
public static Integer[] staticNN;
@MyNullable
public static Integer[] staticN;
public static Integer[] staticJ;
}
// FILE: k.kt
fun test() {
val platformNN = J.staticNN
val platformN = J.staticN
val platformJ = J.staticJ
platformNN[0]
platformN[0]
platformJ[0]
platformNN[0] = 1
platformN[0] = 1
platformJ[0] = 1
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// JSR305_GLOBAL_REPORT: warn
// FILE: J.java
@@ -1,24 +0,0 @@
// JSR305_GLOBAL_REPORT: warn
// FILE: J.java
public class J {
@MyNonnull
public static J staticNN;
@MyNullable
public static J staticN;
public static J staticJ;
}
// FILE: k.kt
var v: J = J()
var n: J? = J()
fun test() {
v = J.staticNN
v = J.staticN
v = J.staticJ
n = J.staticNN
n = J.staticN
n = J.staticJ
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// JSR305_GLOBAL_REPORT: warn
// FILE: J.java
@@ -17,26 +17,26 @@ fun test() {
val platformJ = J.staticJ
if (platformNN) {}
if (platformN) {}
if (<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>platformN<!>) {}
if (platformJ) {}
while (platformNN) {}
while (platformN) {}
while (<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>platformN<!>) {}
while (platformJ) {}
do {} while (platformNN)
do {} while (platformN)
do {} while (<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>platformN<!>)
do {} while (platformJ)
platformNN && false
platformN && false
<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>platformN<!> && false
platformJ && false
platformNN || false
platformN || false
<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>platformN<!> || false
platformJ || false
!platformNN
!platformN
!<!RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>platformN<!>
!platformJ
}
@@ -1,29 +0,0 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
// JSR305_GLOBAL_REPORT: warn
// FILE: J.java
public class J {
@MyNonnull
public static J staticNN;
@MyNullable
public static J staticN;
}
// FILE: k.kt
fun test() {
val n = J.staticN
foo(n)
J.staticNN = n
if (n != null) {
foo(n)
J.staticNN = n
}
val x: J? = null
J.staticNN = x
if (x != null) {
J.staticNN = x
}
}
fun foo(j: J) {}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -UNUSED_PARAMETER
// JSR305_GLOBAL_REPORT: warn
@@ -1,22 +0,0 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
// JSR305_GLOBAL_REPORT: warn
// FILE: J.java
public class J {
@MyNonnull
public static J staticNN;
@MyNullable
public static J staticN;
public static J staticJ;
}
// FILE: k.kt
fun test() {
val platformNN = J.staticNN
val platformN = J.staticN
val platformJ = J.staticJ
fun foo(p: J = platformNN, p1: J = platformN, p2: J = platformJ) {}
fun foo1(p: J? = platformNN, p1: J? = platformN, p2: J? = platformJ) {}
}

Some files were not shown because too many files have changed in this diff Show More