[FIR] Implement warnings for java nullability type mismatch on override
#KT-56989
This commit is contained in:
committed by
Space Team
parent
a6fdeeb7df
commit
2df1e9dde6
+8
@@ -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),
|
||||
|
||||
+6
@@ -3495,6 +3495,12 @@ sealed interface KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
override val diagnosticClass get() = JvmInlineWithoutValueClass::class
|
||||
}
|
||||
|
||||
interface WrongNullabilityForJavaOverride : KtFirDiagnostic<PsiElement> {
|
||||
override val diagnosticClass get() = WrongNullabilityForJavaOverride::class
|
||||
val override: KtCallableSymbol
|
||||
val base: KtCallableSymbol
|
||||
}
|
||||
|
||||
interface JavaTypeMismatch : KtFirDiagnostic<KtExpression> {
|
||||
override val diagnosticClass get() = JavaTypeMismatch::class
|
||||
val expectedType: KtType
|
||||
|
||||
+7
@@ -4217,6 +4217,13 @@ internal class JvmInlineWithoutValueClassImpl(
|
||||
token: KtLifetimeToken,
|
||||
) : KtAbstractFirDiagnostic<PsiElement>(firDiagnostic, token), KtFirDiagnostic.JvmInlineWithoutValueClass
|
||||
|
||||
internal class WrongNullabilityForJavaOverrideImpl(
|
||||
override val override: KtCallableSymbol,
|
||||
override val base: KtCallableSymbol,
|
||||
firDiagnostic: KtPsiDiagnostic,
|
||||
token: KtLifetimeToken,
|
||||
) : KtAbstractFirDiagnostic<PsiElement>(firDiagnostic, token), KtFirDiagnostic.WrongNullabilityForJavaOverride
|
||||
|
||||
internal class JavaTypeMismatchImpl(
|
||||
override val expectedType: KtType,
|
||||
override val actualType: KtType,
|
||||
|
||||
+5
@@ -39,6 +39,11 @@ object JVM_DIAGNOSTICS_LIST : DiagnosticList("FirJvmErrors") {
|
||||
|
||||
val VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION by error<PsiElement>()
|
||||
val JVM_INLINE_WITHOUT_VALUE_CLASS by error<PsiElement>()
|
||||
|
||||
val WRONG_NULLABILITY_FOR_JAVA_OVERRIDE by warning<PsiElement>(PositioningStrategy.OVERRIDE_MODIFIER) {
|
||||
parameter<FirCallableSymbol<*>>("override")
|
||||
parameter<FirCallableSymbol<*>>("base")
|
||||
}
|
||||
}
|
||||
|
||||
val TYPES by object : DiagnosticGroup("Types") {
|
||||
|
||||
+1
@@ -41,6 +41,7 @@ object FirJvmErrors {
|
||||
val FUNCTION_DELEGATE_MEMBER_NAME_CLASH by error0<PsiElement>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||
val VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION by error0<PsiElement>()
|
||||
val JVM_INLINE_WITHOUT_VALUE_CLASS by error0<PsiElement>()
|
||||
val WRONG_NULLABILITY_FOR_JAVA_OVERRIDE by warning2<PsiElement, FirCallableSymbol<*>, FirCallableSymbol<*>>(SourceElementPositioningStrategies.OVERRIDE_MODIFIER)
|
||||
|
||||
// Types
|
||||
val JAVA_TYPE_MISMATCH by error2<KtExpression, ConeKotlinType, ConeKotlinType>()
|
||||
|
||||
+9
@@ -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.")
|
||||
|
||||
+2
-1
@@ -23,7 +23,8 @@ object JvmDeclarationCheckers : DeclarationCheckers() {
|
||||
|
||||
override val classCheckers: Set<FirClassChecker>
|
||||
get() = setOf(
|
||||
FirStrictfpApplicabilityChecker
|
||||
FirStrictfpApplicabilityChecker,
|
||||
FirOverrideJavaNullabilityWarningChecker,
|
||||
)
|
||||
|
||||
override val regularClassCheckers: Set<FirRegularClassChecker>
|
||||
|
||||
+163
@@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
+53
-51
@@ -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<FirCallableSymbol<*>>,
|
||||
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<*>>,
|
||||
): FirCallableSymbol<*>? {
|
||||
@@ -185,40 +221,6 @@ object FirOverrideChecker : FirClassChecker() {
|
||||
}
|
||||
}
|
||||
|
||||
// See [OverrideResolver#isReturnTypeOkForOverride]
|
||||
private fun FirCallableSymbol<*>.checkReturnType(
|
||||
overriddenSymbols: List<FirCallableSymbol<*>>,
|
||||
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,
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
+3
-3
@@ -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
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+23
-9
@@ -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() {
|
||||
<!WRONG_NULLABILITY_FOR_JAVA_OVERRIDE!>override<!> fun everythingNotNullable(x: Foo): Foo? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun explicitlyNullnessUnspecified(x: Foo): Foo? {
|
||||
<!WRONG_NULLABILITY_FOR_JAVA_OVERRIDE!>override<!> fun explicitlyNullnessUnspecified(x: Foo): Foo? {
|
||||
return null
|
||||
}
|
||||
|
||||
<!WRONG_NULLABILITY_FOR_JAVA_OVERRIDE!>override<!> fun intermediateNotNull(): Foo? {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
class WrongParameter : BaseClass() {
|
||||
override fun everythingNotNullable(x: Foo?): Foo {
|
||||
class WrongParameter : IntermediateClass() {
|
||||
<!WRONG_NULLABILITY_FOR_JAVA_OVERRIDE!>override<!> fun everythingNotNullable(x: Foo?): Foo {
|
||||
return FOO
|
||||
}
|
||||
|
||||
override fun everythingNullable(x: Foo): Foo? {
|
||||
<!WRONG_NULLABILITY_FOR_JAVA_OVERRIDE!>override<!> fun everythingNullable(x: Foo): Foo? {
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -69,11 +83,11 @@ class WrongParameter : BaseClass() {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun mixed(x: Foo?): Foo? {
|
||||
<!WRONG_NULLABILITY_FOR_JAVA_OVERRIDE!>override<!> fun mixed(x: Foo?): Foo? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun explicitlyNullnessUnspecified(x: Foo?): Foo {
|
||||
return FOO
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+17
-3
@@ -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() {
|
||||
<!WRONG_NULLABILITY_FOR_JAVA_OVERRIDE!>override<!> fun everythingNotNullable(x: Foo): Foo? {
|
||||
return null
|
||||
}
|
||||
@@ -54,9 +64,13 @@ class WrongReturnTypes : BaseClass() {
|
||||
<!WRONG_NULLABILITY_FOR_JAVA_OVERRIDE!>override<!> fun explicitlyNullnessUnspecified(x: Foo): Foo? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun intermediateNotNull(): Foo? {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
class WrongParameter : BaseClass() {
|
||||
class WrongParameter : IntermediateClass() {
|
||||
<!WRONG_NULLABILITY_FOR_JAVA_OVERRIDE!>override<!> fun everythingNotNullable(x: Foo?): Foo {
|
||||
return FOO
|
||||
}
|
||||
|
||||
+23
-3
@@ -12,9 +12,12 @@ private val FOO: FOO.`<no name provided>`
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
-79
@@ -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
|
||||
}
|
||||
}
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// JSPECIFY_STATE: warn
|
||||
|
||||
// FILE: Foo.java
|
||||
|
||||
Reference in New Issue
Block a user