diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt index ef2be5302e8..0ae3af72601 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -5025,6 +5025,14 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirJvmErrors.WRONG_NULLABILITY_FOR_JAVA_OVERRIDE) { firDiagnostic -> + WrongNullabilityForJavaOverrideImpl( + firSymbolBuilder.callableBuilder.buildCallableSymbol(firDiagnostic.a), + firSymbolBuilder.callableBuilder.buildCallableSymbol(firDiagnostic.b), + firDiagnostic as KtPsiDiagnostic, + token, + ) + } add(FirJvmErrors.JAVA_TYPE_MISMATCH) { firDiagnostic -> JavaTypeMismatchImpl( firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a), diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt index 2daf50f5196..29427d1db70 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt @@ -3495,6 +3495,12 @@ sealed interface KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = JvmInlineWithoutValueClass::class } + interface WrongNullabilityForJavaOverride : KtFirDiagnostic { + override val diagnosticClass get() = WrongNullabilityForJavaOverride::class + val override: KtCallableSymbol + val base: KtCallableSymbol + } + interface JavaTypeMismatch : KtFirDiagnostic { override val diagnosticClass get() = JavaTypeMismatch::class val expectedType: KtType diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index 7632be8bbd9..baa8a15e9ad 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -4217,6 +4217,13 @@ internal class JvmInlineWithoutValueClassImpl( token: KtLifetimeToken, ) : KtAbstractFirDiagnostic(firDiagnostic, token), KtFirDiagnostic.JvmInlineWithoutValueClass +internal class WrongNullabilityForJavaOverrideImpl( + override val override: KtCallableSymbol, + override val base: KtCallableSymbol, + firDiagnostic: KtPsiDiagnostic, + token: KtLifetimeToken, +) : KtAbstractFirDiagnostic(firDiagnostic, token), KtFirDiagnostic.WrongNullabilityForJavaOverride + internal class JavaTypeMismatchImpl( override val expectedType: KtType, override val actualType: KtType, diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirJvmDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirJvmDiagnosticsList.kt index ea9d77adcdb..679160d51fc 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirJvmDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirJvmDiagnosticsList.kt @@ -39,6 +39,11 @@ object JVM_DIAGNOSTICS_LIST : DiagnosticList("FirJvmErrors") { val VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION by error() val JVM_INLINE_WITHOUT_VALUE_CLASS by error() + + val WRONG_NULLABILITY_FOR_JAVA_OVERRIDE by warning(PositioningStrategy.OVERRIDE_MODIFIER) { + parameter>("override") + parameter>("base") + } } val TYPES by object : DiagnosticGroup("Types") { diff --git a/compiler/fir/checkers/checkers.jvm/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/jvm/FirJvmErrors.kt b/compiler/fir/checkers/checkers.jvm/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/jvm/FirJvmErrors.kt index ee9d0bd5516..a73ca7134e9 100644 --- a/compiler/fir/checkers/checkers.jvm/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/jvm/FirJvmErrors.kt +++ b/compiler/fir/checkers/checkers.jvm/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/jvm/FirJvmErrors.kt @@ -41,6 +41,7 @@ object FirJvmErrors { val FUNCTION_DELEGATE_MEMBER_NAME_CLASH by error0(SourceElementPositioningStrategies.DECLARATION_NAME) val VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION by error0() val JVM_INLINE_WITHOUT_VALUE_CLASS by error0() + val WRONG_NULLABILITY_FOR_JAVA_OVERRIDE by warning2, FirCallableSymbol<*>>(SourceElementPositioningStrategies.OVERRIDE_MODIFIER) // Types val JAVA_TYPE_MISMATCH by error2() diff --git a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/diagnostics/jvm/FirJvmErrorsDefaultMessages.kt b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/diagnostics/jvm/FirJvmErrorsDefaultMessages.kt index f5f93635179..99aa0a4646f 100644 --- a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/diagnostics/jvm/FirJvmErrorsDefaultMessages.kt +++ b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/diagnostics/jvm/FirJvmErrorsDefaultMessages.kt @@ -12,6 +12,7 @@ import org.jetbrains.kotlin.diagnostics.rendering.BaseDiagnosticRendererFactory import org.jetbrains.kotlin.diagnostics.rendering.CommonRenderers.STRING import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.DECLARATION_NAME import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.RENDER_TYPE +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.SYMBOL import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.CONCURRENT_HASH_MAP_CONTAINS_OPERATOR import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.DELEGATION_BY_IN_JVM_RECORD import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.DEPRECATED_JAVA_ANNOTATION @@ -80,6 +81,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.SYNCHRONIZ import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.SYNCHRONIZED_ON_SUSPEND import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.UPPER_BOUND_CANNOT_BE_ARRAY import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION +import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.WRONG_NULLABILITY_FOR_JAVA_OVERRIDE object FirJvmErrorsDefaultMessages : BaseDiagnosticRendererFactory() { @@ -99,6 +101,13 @@ object FirJvmErrorsDefaultMessages : BaseDiagnosticRendererFactory() { NOT_RENDERED ) + map.put( + WRONG_NULLABILITY_FOR_JAVA_OVERRIDE, + "Override ''{0}'' has incorrect nullability in its signature compared to the overridden declaration ''{1}''.", + SYMBOL, + SYMBOL, + ) + 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.") diff --git a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/JvmDeclarationCheckers.kt b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/JvmDeclarationCheckers.kt index 5fa4a34b674..af62209650e 100644 --- a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/JvmDeclarationCheckers.kt +++ b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/JvmDeclarationCheckers.kt @@ -23,7 +23,8 @@ object JvmDeclarationCheckers : DeclarationCheckers() { override val classCheckers: Set get() = setOf( - FirStrictfpApplicabilityChecker + FirStrictfpApplicabilityChecker, + FirOverrideJavaNullabilityWarningChecker, ) override val regularClassCheckers: Set diff --git a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirOverrideJavaNullabilityWarningChecker.kt b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirOverrideJavaNullabilityWarningChecker.kt new file mode 100644 index 00000000000..3b1ea1159de --- /dev/null +++ b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirOverrideJavaNullabilityWarningChecker.kt @@ -0,0 +1,163 @@ +/* + * 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.diagnostics.reportOn +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirAbstractOverrideChecker +import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope +import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors +import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.java.enhancement.EnhancedForWarningConeSubstitutor +import org.jetbrains.kotlin.fir.scopes.firOverrideChecker +import org.jetbrains.kotlin.fir.scopes.getDirectOverriddenFunctions +import org.jetbrains.kotlin.fir.scopes.getDirectOverriddenProperties +import org.jetbrains.kotlin.fir.scopes.impl.FirFakeOverrideGenerator +import org.jetbrains.kotlin.fir.symbols.SymbolInternals +import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase +import org.jetbrains.kotlin.fir.types.coneType +import org.jetbrains.kotlin.fir.types.typeContext +import org.jetbrains.kotlin.utils.addToStdlib.runIf + +object FirOverrideJavaNullabilityWarningChecker : FirAbstractOverrideChecker() { + override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { + val substitutor = EnhancedForWarningConeSubstitutor(context.session.typeContext) + val scope = declaration.unsubstitutedScope(context) + val typeCheckerState = context.session.typeContext.newTypeCheckerState( + errorTypesEqualToAnything = false, + stubTypesEqualToAnything = false + ) + + for (member in declaration.declarations) { + var anyBaseEnhanced = false + + if (member is FirSimpleFunction) { + val enhancedOverrides = scope + .getDirectOverriddenFunctions(member.symbol) + .map { + @OptIn(SymbolInternals::class) + val substitutedBase = it.fir.substituteOrNull(substitutor, context) ?: return@map it + anyBaseEnhanced = true + + if (!context.session.firOverrideChecker.isOverriddenFunction(member, substitutedBase)) { + reporter.reportOn( + member.source, + FirJvmErrors.WRONG_NULLABILITY_FOR_JAVA_OVERRIDE, + member.symbol, + substitutedBase.symbol, + context + ) + } + + substitutedBase.symbol + } + + if (anyBaseEnhanced) { + member.symbol.checkReturnType(enhancedOverrides, typeCheckerState, context)?.let { + reporter.reportOn( + member.source, FirJvmErrors.WRONG_NULLABILITY_FOR_JAVA_OVERRIDE, member.symbol, it, context + ) + } + } + } else if (member is FirProperty) { + val enhancedOverrides = scope + .getDirectOverriddenProperties(member.symbol) + .map { + @OptIn(SymbolInternals::class) + val substitutedBase = it.fir.substituteOrNull(substitutor, context) ?: return@map it + anyBaseEnhanced = true + + if (!context.session.firOverrideChecker.isOverriddenProperty(member, substitutedBase)) { + reporter.reportOn( + member.source, + FirJvmErrors.WRONG_NULLABILITY_FOR_JAVA_OVERRIDE, + member.symbol, + substitutedBase.symbol, + context + ) + } + + substitutedBase.symbol + } + + if (anyBaseEnhanced) { + member.symbol.checkReturnType(enhancedOverrides, typeCheckerState, context)?.let { + reporter.reportOn( + member.source, FirJvmErrors.WRONG_NULLABILITY_FOR_JAVA_OVERRIDE, member.symbol, it, context + ) + } + } + } + } + } +} + +/** + * @see org.jetbrains.kotlin.fir.scopes.impl.FirClassSubstitutionScope.createSubstitutionOverrideFunction + * @see org.jetbrains.kotlin.fir.scopes.impl.FirClassSubstitutionScope.createSubstitutedData + */ +private fun FirSimpleFunction.substituteOrNull( + substitutor: EnhancedForWarningConeSubstitutor, + context: CheckerContext, +): FirSimpleFunction? { + symbol.lazyResolveToPhase(FirResolvePhase.TYPES) + var isEnhanced = false + + val newParameterTypes = valueParameters.map { substitutor.substituteOrNull(it.returnTypeRef.coneType)?.also { isEnhanced = true } } + val newContextReceiverTypes = contextReceivers.map { substitutor.substituteOrNull(it.typeRef.coneType)?.also { isEnhanced = true } } + val newReturnType = substitutor.substituteOrNull(context.returnTypeCalculator.tryCalculateReturnType(this).coneType)?.also { isEnhanced = true } + val newExtensionReceiverType = + receiverParameter?.typeRef?.coneType?.let { substitutor.substituteOrNull(it) }?.also { isEnhanced = true } + + return runIf(isEnhanced) { + FirFakeOverrideGenerator.createCopyForFirFunction( + FirFakeOverrideGenerator.createSymbolForSubstitutionOverride(symbol), + this, + null, + context.session, + FirDeclarationOrigin.Enhancement, + newDispatchReceiverType = null, + newParameterTypes = newParameterTypes, + newReturnType = newReturnType, + newContextReceiverTypes = newContextReceiverTypes, + newReceiverType = newExtensionReceiverType, + ) + } +} + +/** + * @see org.jetbrains.kotlin.fir.scopes.impl.FirClassSubstitutionScope.createSubstitutionOverrideProperty + * @see org.jetbrains.kotlin.fir.scopes.impl.FirClassSubstitutionScope.createSubstitutedData + */ +private fun FirProperty.substituteOrNull( + substitutor: EnhancedForWarningConeSubstitutor, + context: CheckerContext, +): FirProperty? { + if (!isJavaOrEnhancement) return null + symbol.lazyResolveToPhase(FirResolvePhase.TYPES) + var isEnhanced = false + + val newContextReceiverTypes = contextReceivers.map { substitutor.substituteOrNull(it.typeRef.coneType)?.also { isEnhanced = true } } + val newReturnType = substitutor.substituteOrNull(context.returnTypeCalculator.tryCalculateReturnType(this).coneType)?.also { isEnhanced = true } + val newExtensionReceiverType = + receiverParameter?.typeRef?.coneType?.let { substitutor.substituteOrNull(it) }?.also { isEnhanced = true } + + return runIf(isEnhanced) { + FirFakeOverrideGenerator.createCopyForFirProperty( + FirFakeOverrideGenerator.createSymbolForSubstitutionOverride(symbol), + this, + null, + context.session, + FirDeclarationOrigin.Enhancement, + newDispatchReceiverType = null, + newReturnType = newReturnType, + newContextReceiverTypes = newContextReceiverTypes, + newReceiverType = newExtensionReceiverType, + ) + } +} \ No newline at end of file diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirOverrideChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirOverrideChecker.kt index befde8ffd13..f7c844c34da 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirOverrideChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirOverrideChecker.kt @@ -42,23 +42,7 @@ import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.types.AbstractTypeChecker import org.jetbrains.kotlin.types.TypeCheckerState -object FirOverrideChecker : FirClassChecker() { - override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { - val typeCheckerState = context.session.typeContext.newTypeCheckerState( - errorTypesEqualToAnything = false, - stubTypesEqualToAnything = false - ) - - val firTypeScope = declaration.unsubstitutedScope(context) - - for (it in declaration.declarations) { - if (it is FirSimpleFunction || it is FirProperty) { - val callable = it as FirCallableDeclaration - checkMember(callable.symbol, declaration, reporter, typeCheckerState, firTypeScope, context) - } - } - } - +abstract class FirAbstractOverrideChecker : FirClassChecker() { private fun ConeKotlinType.substituteAllTypeParameters( overrideDeclaration: FirCallableSymbol<*>, baseDeclaration: FirCallableSymbol<*>, @@ -84,6 +68,58 @@ object FirOverrideChecker : FirClassChecker() { return substitutorByMap(map, context.session).substituteOrSelf(this) } + // See [OverrideResolver#isReturnTypeOkForOverride] + protected fun FirCallableSymbol<*>.checkReturnType( + overriddenSymbols: List>, + typeCheckerState: TypeCheckerState, + context: CheckerContext, + ): FirCallableSymbol<*>? { + val overridingReturnType = resolvedReturnTypeRef.coneType + + // Don't report *_ON_OVERRIDE diagnostics according to an error return type. That should be reported separately. + if (overridingReturnType is ConeErrorType) { + return null + } + + val bounds = overriddenSymbols.map { context.returnTypeCalculator.tryCalculateReturnType(it).coneType } + + for (it in bounds.indices) { + val overriddenDeclaration = overriddenSymbols[it] + + val overriddenReturnType = bounds[it].substituteAllTypeParameters(this, overriddenDeclaration, context) + + val isReturnTypeOkForOverride = + if (overriddenDeclaration is FirPropertySymbol && overriddenDeclaration.isVar) + AbstractTypeChecker.equalTypes(typeCheckerState, overridingReturnType, overriddenReturnType) + else + AbstractTypeChecker.isSubtypeOf(typeCheckerState, overridingReturnType, overriddenReturnType) + + if (!isReturnTypeOkForOverride) { + return overriddenDeclaration + } + } + + return null + } +} + +object FirOverrideChecker : FirAbstractOverrideChecker() { + override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { + val typeCheckerState = context.session.typeContext.newTypeCheckerState( + errorTypesEqualToAnything = false, + stubTypesEqualToAnything = false + ) + + val firTypeScope = declaration.unsubstitutedScope(context) + + for (it in declaration.declarations) { + if (it is FirSimpleFunction || it is FirProperty) { + val callable = it as FirCallableDeclaration + checkMember(callable.symbol, declaration, reporter, typeCheckerState, firTypeScope, context) + } + } + } + private fun checkModality( overriddenSymbols: List>, ): FirCallableSymbol<*>? { @@ -185,40 +221,6 @@ object FirOverrideChecker : FirClassChecker() { } } - // See [OverrideResolver#isReturnTypeOkForOverride] - private fun FirCallableSymbol<*>.checkReturnType( - overriddenSymbols: List>, - typeCheckerState: TypeCheckerState, - context: CheckerContext, - ): FirCallableSymbol<*>? { - val overridingReturnType = resolvedReturnTypeRef.coneType - - // Don't report *_ON_OVERRIDE diagnostics according to an error return type. That should be reported separately. - if (overridingReturnType is ConeErrorType) { - return null - } - - val bounds = overriddenSymbols.map { context.returnTypeCalculator.tryCalculateReturnType(it).coneType } - - for (it in bounds.indices) { - val overriddenDeclaration = overriddenSymbols[it] - - val overriddenReturnType = bounds[it].substituteAllTypeParameters(this, overriddenDeclaration, context) - - val isReturnTypeOkForOverride = - if (overriddenDeclaration is FirPropertySymbol && overriddenDeclaration.isVar) - AbstractTypeChecker.equalTypes(typeCheckerState, overridingReturnType, overriddenReturnType) - else - AbstractTypeChecker.isSubtypeOf(typeCheckerState, overridingReturnType, overriddenReturnType) - - if (!isReturnTypeOkForOverride) { - return overriddenDeclaration - } - } - - return null - } - @OptIn(SymbolInternals::class) private fun FirFunctionSymbol<*>.checkDefaultValues( reporter: DiagnosticReporter, diff --git a/compiler/testData/cli/jvm/jspecifyWarn.out b/compiler/testData/cli/jvm/jspecifyWarn.out index c9707dafe94..0f9b54c5d8e 100644 --- a/compiler/testData/cli/jvm/jspecifyWarn.out +++ b/compiler/testData/cli/jvm/jspecifyWarn.out @@ -1,7 +1,7 @@ -compiler/testData/cli/jvm/jspecifyUsage.kt:2:11: warning: Java type mismatch: inferred type is 'kotlin/String', but 'kotlin/Nothing?' was expected. +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?'. +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 diff --git a/compiler/testData/cli/jvm/jsr305DeprecatedWarn.out b/compiler/testData/cli/jvm/jsr305DeprecatedWarn.out index e795389f8d5..e19f716a0ef 100644 --- a/compiler/testData/cli/jvm/jsr305DeprecatedWarn.out +++ b/compiler/testData/cli/jvm/jsr305DeprecatedWarn.out @@ -1,5 +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. +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 diff --git a/compiler/testData/cli/jvm/jsr305MigrationFqNameIgnore.out b/compiler/testData/cli/jvm/jsr305MigrationFqNameIgnore.out index f3c58e6f285..2ebcc2c26cd 100644 --- a/compiler/testData/cli/jvm/jsr305MigrationFqNameIgnore.out +++ b/compiler/testData/cli/jvm/jsr305MigrationFqNameIgnore.out @@ -1,7 +1,7 @@ -compiler/testData/cli/jvm/jsr305Migration.kt:2:19: warning: Java type mismatch: inferred type is 'kotlin/String', but 'kotlin/Nothing?' was expected. +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?'. +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 diff --git a/compiler/testData/cli/jvm/jsr305MigrationIgnore.out b/compiler/testData/cli/jvm/jsr305MigrationIgnore.out index f3c58e6f285..2ebcc2c26cd 100644 --- a/compiler/testData/cli/jvm/jsr305MigrationIgnore.out +++ b/compiler/testData/cli/jvm/jsr305MigrationIgnore.out @@ -1,7 +1,7 @@ -compiler/testData/cli/jvm/jsr305Migration.kt:2:19: warning: Java type mismatch: inferred type is 'kotlin/String', but 'kotlin/Nothing?' was expected. +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?'. +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 diff --git a/compiler/testData/cli/jvm/jsr305MigrationWarn.out b/compiler/testData/cli/jvm/jsr305MigrationWarn.out index 0f40d4ac8de..02950901a99 100644 --- a/compiler/testData/cli/jvm/jsr305MigrationWarn.out +++ b/compiler/testData/cli/jvm/jsr305MigrationWarn.out @@ -1,10 +1,10 @@ -compiler/testData/cli/jvm/jsr305Migration.kt:2:19: warning: Java type mismatch: inferred type is 'kotlin/String', but 'kotlin/Nothing?' was expected. +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. +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?'. +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 diff --git a/compiler/testData/cli/jvm/jsr305NoFlag.out b/compiler/testData/cli/jvm/jsr305NoFlag.out index 707ae707a29..7e9c02d1167 100644 --- a/compiler/testData/cli/jvm/jsr305NoFlag.out +++ b/compiler/testData/cli/jvm/jsr305NoFlag.out @@ -1,4 +1,4 @@ -compiler/testData/cli/jvm/jsr305Usage.kt:2:11: warning: Java type mismatch: inferred type is 'kotlin/String', but 'kotlin/Nothing?' was expected. +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 diff --git a/compiler/testData/cli/jvm/jsr305Warn.out b/compiler/testData/cli/jvm/jsr305Warn.out index 707ae707a29..7e9c02d1167 100644 --- a/compiler/testData/cli/jvm/jsr305Warn.out +++ b/compiler/testData/cli/jvm/jsr305Warn.out @@ -1,4 +1,4 @@ -compiler/testData/cli/jvm/jsr305Usage.kt:2:11: warning: Java type mismatch: inferred type is 'kotlin/String', but 'kotlin/Nothing?' was expected. +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 diff --git a/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/OverrideOfAnnotated.fir.kt b/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/OverrideOfAnnotated.fir.kt index bd935e9371e..2f5176ba3c4 100644 --- a/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/OverrideOfAnnotated.fir.kt +++ b/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/OverrideOfAnnotated.fir.kt @@ -17,6 +17,8 @@ public class BaseClass { public @Nullable Foo mixed(Foo x) { return null; } public Foo explicitlyNullnessUnspecified(@NullnessUnspecified Foo x) { return null; } + + public static Foo foo() { return null; } } @@ -24,7 +26,11 @@ public class BaseClass { private val FOO = object : Foo {} -class Correct : BaseClass() { +open class IntermediateClass : BaseClass() { + open fun intermediateNotNull() = BaseClass.foo() +} + +class Correct : IntermediateClass() { override fun everythingNotNullable(x: Foo): Foo { return FOO } @@ -44,24 +50,32 @@ class Correct : BaseClass() { override fun explicitlyNullnessUnspecified(x: Foo): Foo { return FOO } + + override fun intermediateNotNull(): Foo { + return FOO + } } -class WrongReturnTypes : BaseClass() { - override fun everythingNotNullable(x: Foo): Foo? { +class WrongReturnTypes : IntermediateClass() { + override fun everythingNotNullable(x: Foo): Foo? { return null } - override fun explicitlyNullnessUnspecified(x: Foo): Foo? { + override fun explicitlyNullnessUnspecified(x: Foo): Foo? { + return null + } + + override fun intermediateNotNull(): Foo? { return null } } -class WrongParameter : BaseClass() { - override fun everythingNotNullable(x: Foo?): Foo { +class WrongParameter : IntermediateClass() { + override fun everythingNotNullable(x: Foo?): Foo { return FOO } - override fun everythingNullable(x: Foo): Foo? { + override fun everythingNullable(x: Foo): Foo? { return null } @@ -69,11 +83,11 @@ class WrongParameter : BaseClass() { return null } - override fun mixed(x: Foo?): Foo? { + override fun mixed(x: Foo?): Foo? { return null } override fun explicitlyNullnessUnspecified(x: Foo?): Foo { return FOO } -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/OverrideOfAnnotated.kt b/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/OverrideOfAnnotated.kt index 42dad43991e..763b600bd71 100644 --- a/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/OverrideOfAnnotated.kt +++ b/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/OverrideOfAnnotated.kt @@ -17,6 +17,8 @@ public class BaseClass { public @Nullable Foo mixed(Foo x) { return null; } public Foo explicitlyNullnessUnspecified(@NullnessUnspecified Foo x) { return null; } + + public static Foo foo() { return null; } } @@ -24,7 +26,11 @@ public class BaseClass { private val FOO = object : Foo {} -class Correct : BaseClass() { +open class IntermediateClass : BaseClass() { + open fun intermediateNotNull() = BaseClass.foo() +} + +class Correct : IntermediateClass() { override fun everythingNotNullable(x: Foo): Foo { return FOO } @@ -44,9 +50,13 @@ class Correct : BaseClass() { override fun explicitlyNullnessUnspecified(x: Foo): Foo { return FOO } + + override fun intermediateNotNull(): Foo { + return FOO + } } -class WrongReturnTypes : BaseClass() { +class WrongReturnTypes : IntermediateClass() { override fun everythingNotNullable(x: Foo): Foo? { return null } @@ -54,9 +64,13 @@ class WrongReturnTypes : BaseClass() { override fun explicitlyNullnessUnspecified(x: Foo): Foo? { return null } + + override fun intermediateNotNull(): Foo? { + return null + } } -class WrongParameter : BaseClass() { +class WrongParameter : IntermediateClass() { override fun everythingNotNullable(x: Foo?): Foo { return FOO } diff --git a/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/OverrideOfAnnotated.txt b/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/OverrideOfAnnotated.txt index 157f49c0093..ea98baa1665 100644 --- a/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/OverrideOfAnnotated.txt +++ b/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/OverrideOfAnnotated.txt @@ -12,9 +12,12 @@ private val FOO: FOO.`` public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int @org.jspecify.annotations.Nullable public open fun mixed(/*0*/ x: Foo!): @org.jspecify.annotations.Nullable Foo! public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public open fun foo(): Foo! } -public final class Correct : BaseClass { +public final class Correct : IntermediateClass { public constructor Correct() public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ fun everythingNotNullable(/*0*/ x: Foo): Foo @@ -22,6 +25,7 @@ public final class Correct : BaseClass { public open override /*1*/ fun everythingUnknown(/*0*/ x: Foo?): Foo? public open override /*1*/ fun explicitlyNullnessUnspecified(/*0*/ x: Foo): Foo public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ fun intermediateNotNull(): Foo public open override /*1*/ fun mixed(/*0*/ x: Foo): Foo? public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } @@ -32,7 +36,20 @@ public interface Foo { public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } -public final class WrongParameter : BaseClass { +public open class IntermediateClass : BaseClass { + public constructor IntermediateClass() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun everythingNotNullable(/*0*/ x: Foo!): Foo! + @org.jspecify.annotations.Nullable public open override /*1*/ /*fake_override*/ fun everythingNullable(/*0*/ @org.jspecify.annotations.Nullable x: @org.jspecify.annotations.Nullable Foo!): @org.jspecify.annotations.Nullable Foo! + @org.jspecify.annotations.NullnessUnspecified public open override /*1*/ /*fake_override*/ fun everythingUnknown(/*0*/ @org.jspecify.annotations.NullnessUnspecified x: @org.jspecify.annotations.NullnessUnspecified Foo!): @org.jspecify.annotations.NullnessUnspecified Foo! + public open override /*1*/ /*fake_override*/ fun explicitlyNullnessUnspecified(/*0*/ @org.jspecify.annotations.NullnessUnspecified x: @org.jspecify.annotations.NullnessUnspecified Foo!): Foo! + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open fun intermediateNotNull(): Foo! + @org.jspecify.annotations.Nullable public open override /*1*/ /*fake_override*/ fun mixed(/*0*/ x: Foo!): @org.jspecify.annotations.Nullable Foo! + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class WrongParameter : IntermediateClass { public constructor WrongParameter() public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ fun everythingNotNullable(/*0*/ x: Foo?): Foo @@ -40,11 +57,12 @@ public final class WrongParameter : BaseClass { public open override /*1*/ fun everythingUnknown(/*0*/ x: Foo): Foo? public open override /*1*/ fun explicitlyNullnessUnspecified(/*0*/ x: Foo?): Foo public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun intermediateNotNull(): Foo! public open override /*1*/ fun mixed(/*0*/ x: Foo?): Foo? public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } -public final class WrongReturnTypes : BaseClass { +public final class WrongReturnTypes : IntermediateClass { public constructor WrongReturnTypes() public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ fun everythingNotNullable(/*0*/ x: Foo): Foo? @@ -52,6 +70,8 @@ public final class WrongReturnTypes : BaseClass { @org.jspecify.annotations.NullnessUnspecified public open override /*1*/ /*fake_override*/ fun everythingUnknown(/*0*/ @org.jspecify.annotations.NullnessUnspecified x: @org.jspecify.annotations.NullnessUnspecified Foo!): @org.jspecify.annotations.NullnessUnspecified Foo! public open override /*1*/ fun explicitlyNullnessUnspecified(/*0*/ x: Foo): Foo? public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ fun intermediateNotNull(): Foo? @org.jspecify.annotations.Nullable public open override /*1*/ /*fake_override*/ fun mixed(/*0*/ x: Foo!): @org.jspecify.annotations.Nullable Foo! public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } + diff --git a/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecifyOld/warnMode/OverrideOfAnnotated.fir.kt b/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecifyOld/warnMode/OverrideOfAnnotated.fir.kt deleted file mode 100644 index 47c613ef709..00000000000 --- a/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecifyOld/warnMode/OverrideOfAnnotated.fir.kt +++ /dev/null @@ -1,79 +0,0 @@ -// JSPECIFY_STATE: warn - -// FILE: Foo.java -public interface Foo {} -// FILE: BaseClass.java - -import org.jspecify.nullness.*; - -@NullMarked -public class BaseClass { - 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: main.kt - -private val FOO = object : Foo {} - -class Correct : BaseClass() { - override fun everythingNotNullable(x: Foo): Foo { - return FOO - } - - override fun everythingNullable(x: Foo?): Foo? { - return null - } - - override fun everythingUnknown(x: Foo?): Foo? { - return null - } - - override fun mixed(x: Foo): Foo? { - return null - } - - override fun explicitlyNullnessUnspecified(x: Foo): Foo { - return FOO - } -} - -class WrongReturnTypes : BaseClass() { - override fun everythingNotNullable(x: Foo): Foo? { - return null - } - - override fun explicitlyNullnessUnspecified(x: Foo): Foo? { - return null - } -} - -class WrongParameter : BaseClass() { - override fun everythingNotNullable(x: Foo?): Foo { - return FOO - } - - override fun everythingNullable(x: Foo): Foo? { - return null - } - - override fun everythingUnknown(x: Foo): Foo? { - return null - } - - override fun mixed(x: Foo?): Foo? { - return null - } - - override fun explicitlyNullnessUnspecified(x: Foo?): Foo { - return FOO - } -} \ No newline at end of file diff --git a/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecifyOld/warnMode/OverrideOfAnnotated.kt b/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecifyOld/warnMode/OverrideOfAnnotated.kt index 7579f0cedaf..80e01d570bd 100644 --- a/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecifyOld/warnMode/OverrideOfAnnotated.kt +++ b/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecifyOld/warnMode/OverrideOfAnnotated.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // JSPECIFY_STATE: warn // FILE: Foo.java